Compare commits
185 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08c4302011 | ||
|
|
5f96861c44 | ||
|
|
995d71f901 | ||
|
|
82e4a53472 | ||
|
|
e7a41061c6 | ||
|
|
4848a61e21 | ||
|
|
6302e45c10 | ||
|
|
451157b653 | ||
|
|
f55168d1ac | ||
|
|
c4f99a6cab | ||
|
|
83e77303aa | ||
|
|
6e1cadf338 | ||
|
|
83a9b984e5 | ||
|
|
978df93ffd | ||
|
|
0cfc070f3c | ||
|
|
5ad150a17e | ||
|
|
de88bf94d4 | ||
|
|
19f07aa398 | ||
|
|
46f9b31cff | ||
|
|
e32feb29e2 | ||
|
|
89a93e2966 | ||
|
|
038322e9aa | ||
|
|
6cef663db5 | ||
|
|
b2f5861458 | ||
|
|
f8809ce67f | ||
|
|
3c97eb6014 | ||
|
|
3498b0a50a | ||
|
|
ed7e0d8b0a | ||
|
|
f3828ba516 | ||
|
|
2a48c25453 | ||
|
|
096da0cb94 | ||
|
|
ca8a07e1ae | ||
|
|
c02f965460 | ||
|
|
5f440bb6de | ||
|
|
fc729279ec | ||
|
|
dd0f9ab74e | ||
|
|
d2a4a85e04 | ||
|
|
37890280ae | ||
|
|
a6ceae4045 | ||
|
|
3447e735dc | ||
|
|
989c937ce1 | ||
|
|
e0608ddee0 | ||
|
|
b35224061f | ||
|
|
b25576aed8 | ||
|
|
d5f054e328 | ||
|
|
eb4959cf49 | ||
|
|
cce415fc51 | ||
|
|
00f96c314a | ||
|
|
fefd27162c | ||
|
|
b388c76e45 | ||
|
|
aaeaf3a096 | ||
|
|
57efe4e0d1 | ||
|
|
dd4dbc9326 | ||
|
|
6aa77ff468 | ||
|
|
f8099550bd | ||
|
|
96249e6bcc | ||
|
|
6e391098a3 | ||
|
|
baec0f9719 | ||
|
|
6aab9f4e34 | ||
|
|
1bf73935e4 | ||
|
|
49e51d0a62 | ||
|
|
3e7bc2f37f | ||
|
|
0f56fd2561 | ||
|
|
9f0114eb39 | ||
|
|
4b82893c36 | ||
|
|
734e979c94 | ||
|
|
983973843e | ||
|
|
3b427c31a2 | ||
|
|
cee0ecf0ef | ||
|
|
8e3c5db3bf | ||
|
|
11d8daf3ed | ||
|
|
9953e16415 | ||
|
|
fe600de0f7 | ||
|
|
386f1f20ff | ||
|
|
5e07951892 | ||
|
|
2514e44083 | ||
|
|
20d9c7158e | ||
|
|
d8e319ebf8 | ||
|
|
a39cbbd917 | ||
|
|
8df27a1c05 | ||
|
|
26cf9c14f4 | ||
|
|
03edd26e17 | ||
|
|
571f6d183a | ||
|
|
1292e39c46 | ||
|
|
6fe3f82fb1 | ||
|
|
da8fb99e82 | ||
|
|
c8d77bc2db | ||
|
|
b5e52fce75 | ||
|
|
3afcb52934 | ||
|
|
677b0cffec | ||
|
|
248bc68f0d | ||
|
|
02050fa3ef | ||
|
|
57d23c3696 | ||
|
|
8babfc5ca9 | ||
|
|
271b5d1a73 | ||
|
|
7d4e7a0925 | ||
|
|
92f5d5f190 | ||
|
|
1731b985fc | ||
|
|
bd4590ad9d | ||
|
|
55fc60ec82 | ||
|
|
ab075e9ad8 | ||
|
|
3ac1710d83 | ||
|
|
730878938e | ||
|
|
3fd4304de1 | ||
|
|
db7224486c | ||
|
|
424953c894 | ||
|
|
6d0f3c7faa | ||
|
|
434a52ded3 | ||
|
|
2ec906e2d4 | ||
|
|
ffff13205a | ||
|
|
16efd85dfc | ||
|
|
1ef09ffbdd | ||
|
|
976ecce075 | ||
|
|
87a51a9eb3 | ||
|
|
c84de00e80 | ||
|
|
91997ced01 | ||
|
|
7a4be9e67e | ||
|
|
eb942b0bf7 | ||
|
|
1cf23c7ad6 | ||
|
|
15ec9df538 | ||
|
|
d6e2895666 | ||
|
|
7974ffdda2 | ||
|
|
d5858622ba | ||
|
|
9656e09066 | ||
|
|
096fee8b6d | ||
|
|
0635e7c38e | ||
|
|
845b1dcd6f | ||
|
|
2e959e8503 | ||
|
|
e6c9cbf0cd | ||
|
|
fb0ba0cff9 | ||
|
|
573e5608fc | ||
|
|
37a7c2b1df | ||
|
|
38274728f6 | ||
|
|
49b3d67272 | ||
|
|
400b992ec3 | ||
|
|
32815d8427 | ||
|
|
3e25d17702 | ||
|
|
b5d1118a3f | ||
|
|
5b9e43f8ff | ||
|
|
3ffa6f70aa | ||
|
|
0d07c3c289 | ||
|
|
29fdb6d641 | ||
|
|
39d007470a | ||
|
|
285c8cbd1e | ||
|
|
ef5a26dfcc | ||
|
|
8363302caf | ||
|
|
04ce2f985a | ||
|
|
a14f30c03c | ||
|
|
bd85392b54 | ||
|
|
7c427e0b6e | ||
|
|
6cf8335f31 | ||
|
|
647a1403d0 | ||
|
|
1d9b8f34e2 | ||
|
|
adf119007b | ||
|
|
7114e9b150 | ||
|
|
76c1f5bfe9 | ||
|
|
33f88d30ed | ||
|
|
ffdcbece56 | ||
|
|
44eb723efb | ||
|
|
689f80bb23 | ||
|
|
a2db98d275 | ||
|
|
49b983cd3a | ||
|
|
ad60b9225e | ||
|
|
0c096db8bd | ||
|
|
87684e0945 | ||
|
|
1d13b245f9 | ||
|
|
e31d9decdc | ||
|
|
06436bb876 | ||
|
|
d8f3f0f430 | ||
|
|
177c1874b9 | ||
|
|
eef801f1ae | ||
|
|
d69cf6c6fe | ||
|
|
0a9c162f26 | ||
|
|
942fa46022 | ||
|
|
74aff1b407 | ||
|
|
dbff9e2125 | ||
|
|
bed1556a3a | ||
|
|
822b4ae96f | ||
|
|
99f3b986b6 | ||
|
|
fd4c1ea747 | ||
|
|
944a5a7424 | ||
|
|
dda2c89a58 | ||
|
|
c8cfbf5281 | ||
|
|
9f383ab101 | ||
|
|
7811d50372 |
@@ -291,7 +291,7 @@ checklist.)
|
||||
1. Changes address original issue?
|
||||
2. Unit tests included and/or updated with changes?
|
||||
3. Command line build passes?
|
||||
4. Expect to pass code review?
|
||||
4. Changes have been smoke-tested?
|
||||
|
||||
### Reviewer Checklist
|
||||
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
"platform/features/timeline",
|
||||
"platform/forms",
|
||||
"platform/identity",
|
||||
"platform/persistence/aggregator",
|
||||
"platform/persistence/local",
|
||||
"platform/persistence/queue",
|
||||
"platform/policy",
|
||||
"platform/entanglement",
|
||||
"platform/search",
|
||||
"platform/status",
|
||||
|
||||
"example/imagery",
|
||||
"example/eventGenerator",
|
||||
|
||||
@@ -677,6 +677,40 @@ If the provided capability has no invoke method, the return value here functions
|
||||
as `getCapability` including returning `undefined` if the capability is not
|
||||
exposed.
|
||||
|
||||
### Identifier Syntax
|
||||
|
||||
For most purposes, a domain object identifier can be treated as a purely
|
||||
symbolic string; these are typically generated by Open MCT Web and plug-ins
|
||||
should rarely be concerned with its internal structure.
|
||||
|
||||
A domain object identifier has one or two parts, separated by a colon.
|
||||
|
||||
* If two parts are present, the part before the colon refers to the space
|
||||
in which the domain object resides. This may be a persistence space or
|
||||
a purely symbolic space recognized by a specific model provider. The
|
||||
part after the colon is the key to use when looking up the domain object
|
||||
model within that space.
|
||||
* If only one part is present, the domain object has no space specified,
|
||||
and may presume to reside in the application-configured default space
|
||||
defined by the `PERSISTENCE_SPACE` constant.
|
||||
* Both the key and the space identifier may consist of any combination
|
||||
of alphanumeric characters, underscores, dashes, and periods.
|
||||
|
||||
Some examples:
|
||||
|
||||
* A domain object with the identifier `foo:xyz` would have its model
|
||||
loaded using key `xyz` from persistence space `foo`.
|
||||
* A domain object with the identifier `bar` would have its model loaded
|
||||
using key `bar` from the space identified by the `PERSISTENCE_SPACE`
|
||||
constant.
|
||||
|
||||
```bnf
|
||||
<identifier> ::= <space> ":" <key> | <key>
|
||||
<space> ::= <id char>+
|
||||
<key> ::= <id char>+
|
||||
<id char> ::= <letter> | <digit> | "-" | "." | "_"
|
||||
```
|
||||
|
||||
## Domain Object Actions
|
||||
|
||||
An `Action` is behavior that can be performed upon/using a `DomainObject`. An
|
||||
@@ -907,6 +941,12 @@ look at field (see below) to determine which field in the model should be
|
||||
modified.
|
||||
* `ngRequired`: True if input is required.
|
||||
* `ngPattern`: The pattern to match against (for text entry)
|
||||
* `ngBlur`: A function that may be invoked to evaluate the expression
|
||||
associated with the `ng-blur` attribute associated with the control.
|
||||
* This should be called when the control has lost focus; for controls
|
||||
which simply wrap or augment `input` elements, this should be fired
|
||||
on `blur` events associated with those elements, while more complex
|
||||
custom controls may fire this at the end of more specific interactions.
|
||||
* `options`: The options for this control, as passed from the `options` property
|
||||
of an individual row definition.
|
||||
* `field`: Name of the field in `ngModel` which will hold the value for this
|
||||
@@ -1254,6 +1294,22 @@ object, or the current view proxy.
|
||||
* `all()`: Get an array of all objects in the selection state. Will include
|
||||
either or both of the view proxy and selected object.
|
||||
|
||||
## Workers Category
|
||||
|
||||
The `workers` extension category allows scripts to be run as web workers
|
||||
using the `workerService`.
|
||||
|
||||
An extension of this category has no implementation. The following properties
|
||||
are supported:
|
||||
|
||||
* `key`: A symbolic string used to identify this worker.
|
||||
* `workerUrl`: The path, relative to this bundle's `src` folder, where
|
||||
this worker's source code resides.
|
||||
* `shared`: Optional; a boolean flag which, if true, indicates that this
|
||||
worker should be instantiated as a
|
||||
[`SharedWorker`](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker/SharedWorker).
|
||||
Default value is `false`.
|
||||
|
||||
# Directives
|
||||
|
||||
Open MCT Web defines several Angular directives that are intended for use both
|
||||
@@ -1849,6 +1905,14 @@ the TelemetrySeries itself, in that order.
|
||||
* `getSeries(domainObject)`: Get the latest `TelemetrySeries` (as resulted from
|
||||
a previous `request(...)` call) available for this domain object.
|
||||
|
||||
### Worker Service
|
||||
|
||||
The `workerService` may be used to run web workers defined via the
|
||||
`workers` extension category. It has the following method:
|
||||
|
||||
* `run(key)`: Run the worker identified by the provided `key`. Returns
|
||||
a `Worker` (or `SharedWorker`, if the specified worker is defined
|
||||
as a shared worker); if the `key` is unknown, returns `undefined`.
|
||||
|
||||
# Models
|
||||
Domain object models in Open MCT Web are JavaScript objects describing the
|
||||
@@ -2056,6 +2120,31 @@ objects which has a `relationships` property in their model, whose value is an
|
||||
object containing key-value pairs, where keys are strings identifying
|
||||
relationship types, and values are arrays of domain object identifiers.
|
||||
|
||||
## Status Capability
|
||||
|
||||
The `status` capability provides a way to flag domain objects as possessing
|
||||
certain states, represented as simple strings. These states, in turn, are
|
||||
reflected on `mct-representation` elements as classes (prefixed with
|
||||
`s-status-`.) The `status` capability has the following interface:
|
||||
|
||||
* `get()`: Returns an array of all status strings that currently apply
|
||||
to this object.
|
||||
* `set(status, state)`: Adds or removes a status flag to this domain object.
|
||||
The `status` argument is the string to set; `state` is a boolean
|
||||
indicating whether this status should be included (true) or removed (false).
|
||||
* `listen(callback)`: Listen for changes in status. The provided `callback`
|
||||
will be invoked with an array of all current status strings whenever status
|
||||
changes.
|
||||
|
||||
Plug-ins may add and/or recognize arbitrary status flags. Flags defined
|
||||
and/or supported by the platform are:
|
||||
|
||||
Status | CSS Class | Meaning
|
||||
-----------|--------------------|-----------------------------------
|
||||
`editing` | `s-status-editing` | Domain object is being edited.
|
||||
`pending` | `s-status-pending` | Domain object is partially loaded.
|
||||
|
||||
|
||||
## Telemetry Capability
|
||||
|
||||
The telemetry capability provides a means for accessing telemetry data
|
||||
@@ -2328,6 +2417,11 @@ default paths to reach external services are all correct.
|
||||
|
||||
### Configuration Constants
|
||||
|
||||
The following constants have global significance:
|
||||
* `PERSISTENCE_SPACE`: The space in which domain objects should be persisted
|
||||
(or read from) when not otherwise specified. Typically this will not need
|
||||
to be overridden by other bundles, but persistence adapters may wish to
|
||||
consume this constant in order to provide persistence for that space.
|
||||
|
||||
The following configuration constants are recognized by Open MCT Web bundles:
|
||||
* Common UI elements - `platform/commonUI/general`
|
||||
|
||||
161
docs/src/process/cycle.md
Normal file
161
docs/src/process/cycle.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Development Cycle
|
||||
|
||||
Development of Open MCT Web occurs on an iterative cycle of
|
||||
sprints and releases.
|
||||
|
||||
* A _sprint_ is three weeks in duration, and represents a
|
||||
set of improvements that can be completed and tested by the
|
||||
development team. Software at the end of the sprint is
|
||||
"semi-stable"; it will have undergone reduced testing and may carry
|
||||
defects or usability issues of lower severity, particularly if
|
||||
there are workarounds.
|
||||
* A _release_ occurs every four sprints. Releases are stable, and
|
||||
will have undergone full acceptance testing to ensure that the
|
||||
software behaves correctly and usably.
|
||||
|
||||
## Roles
|
||||
|
||||
The sprint process assumes the presence of a __project manager.__
|
||||
The project manager is responsible for
|
||||
making tactical decisions about what development work will be
|
||||
performed, and for coordinating with stakeholders to arrive at
|
||||
higher-level strategic decisions about desired functionality
|
||||
and characteristics of the software, major external milestones,
|
||||
and so forth.
|
||||
|
||||
In the absence of a dedicated project manager, this role may be rotated
|
||||
among members of the development team on a per-sprint basis.
|
||||
|
||||
Responsibilities of the project manager including:
|
||||
|
||||
* Maintaining (with agreement of stakeholders) a "road map" of work
|
||||
planned for future releases/sprints; this should be higher-level,
|
||||
usually expressed as "themes",
|
||||
with just enough specificity to gauge feasibility of plans,
|
||||
relate work back to milestones, and identify longer-term
|
||||
dependencies.
|
||||
* Determining (with assistance from the rest of the team) which
|
||||
issues to work on in a given sprint and how they shall be
|
||||
assigned.
|
||||
* Pre-planning subsequent sprints to ensure that all members of the
|
||||
team always have a clear direction.
|
||||
* Scheduling and/or ensuring adherence to
|
||||
[process points](#process-points).
|
||||
* Responding to changes within the sprint (shifting priorities,
|
||||
new issues) and re-allocating work for the sprint as needed.
|
||||
|
||||
## Sprint Calendar
|
||||
|
||||
Certain [process points](#process-points) are regularly scheduled in
|
||||
the sprint cycle.
|
||||
|
||||
### Sprints by Release
|
||||
|
||||
Allocation of work among sprints should be planned relative to release
|
||||
goals and milestones. As a general guideline, higher-risk work (large
|
||||
new features which may carry new defects, major refactoring, design
|
||||
changes with uncertain effects on usability) should be allocated to
|
||||
earlier sprints, allowing for time in later sprints to ensure stability.
|
||||
|
||||
| Sprint | Focus |
|
||||
|:------:|:--------------------------------------------------------|
|
||||
| __1__ | Prototyping, design, experimentation. |
|
||||
| __2__ | New features, refinements, enhancements. |
|
||||
| __3__ | Feature completion, low-risk enhancements, bug fixing. |
|
||||
| __4__ | Stability & quality assurance. |
|
||||
|
||||
### Sprints 1-3
|
||||
|
||||
The first three sprints of a release are primarily centered around
|
||||
development work, with regular acceptance testing in the third
|
||||
week. During this third week, the top priority should be passing
|
||||
acceptance testing (e.g. by resolving any blockers found); any
|
||||
resources not needed for this effort should be used to begin work
|
||||
for the subsequent sprint.
|
||||
|
||||
| Week | Mon | Tue | Wed | Thu | Fri |
|
||||
|:-----:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
|
||||
| __1__ | Sprint plan | Tag-up | | | |
|
||||
| __2__ | | Tag-up | | | Code freeze |
|
||||
| __3__ | Per-sprint testing | Triage | | _Per-sprint testing*_ | Ship |
|
||||
|
||||
* If necessary.
|
||||
|
||||
### Sprint 4
|
||||
|
||||
The software must be stable at the end of the fourth sprint; because of
|
||||
this, the fourth sprint is scheduled differently, with a heightened
|
||||
emphasis on testing.
|
||||
|
||||
| Week | Mon | Tue | Wed | Thu | Fri |
|
||||
|-------:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
|
||||
| __1__ | Sprint plan | Tag-up | | | Code freeze |
|
||||
| __2__ | Per-release testing | Triage | | | |
|
||||
| __3__ | _Per-release testing*_ | Triage | | _Per-release testing*_ | Ship |
|
||||
|
||||
* If necessary.
|
||||
|
||||
## Process Points
|
||||
|
||||
* __Sprint plan.__ Project manager allocates issues based on
|
||||
theme(s) for sprint, then reviews with team. Each team member
|
||||
should have roughly two weeks of work allocated (to allow time
|
||||
in the third week for testing of work completed.)
|
||||
* Project manager should also sketch out subsequent sprint so
|
||||
that team may begin work for that sprint during the
|
||||
third week, since testing and blocker resolution is unlikely
|
||||
to require all available resources.
|
||||
* __Tag-up.__ Check in and status update among development team.
|
||||
May amend plan for sprint as-needed.
|
||||
* __Code freeze.__ Any new work from this sprint
|
||||
(features, bug fixes, enhancements) must be integrated by the
|
||||
end of the second week of the sprint. After code freeze
|
||||
(and until the end of the sprint) the only changes that should be
|
||||
merged into the master branch should directly address issues
|
||||
needed to pass acceptance testing.
|
||||
* [__Per-release Testing.__](testing/plan.md#per-release-testing)
|
||||
Structured testing with predefined
|
||||
success criteria. No release should ship without passing
|
||||
acceptance tests. Time is allocated in each sprint for subsequent
|
||||
rounds of acceptance testing if issues are identified during a
|
||||
prior round. Specific details of acceptance testing need to be
|
||||
agreed-upon with relevant stakeholders and delivery recipients,
|
||||
and should be flexible enough to allow changes to plans
|
||||
(e.g. deferring delivery of some feature in order to ensure
|
||||
stability of other features.) Baseline testing includes:
|
||||
* [__Testathon.__](testing/plan.md#user-testing)
|
||||
Multi-user testing, involving as many users as
|
||||
is feasible, plus development team. Open-ended; should verify
|
||||
completed work from this sprint, test exploratorily for
|
||||
regressions, et cetera.
|
||||
* [__Long-Duration Test.__](testing/plan.md#long-duration-testing) A
|
||||
test to verify that the software remains
|
||||
stable after running for longer durations. May include some
|
||||
combination of automated testing and user verification (e.g.
|
||||
checking to verify that software remains subjectively
|
||||
responsive at conclusion of test.)
|
||||
* [__Unit Testing.__](testing/plan.md#unit-testing)
|
||||
Automated testing integrated into the
|
||||
build. (These tests are verified to pass more often than once
|
||||
per sprint, as they run before any merge to master, but still
|
||||
play an important role in per-release testing.)
|
||||
* [__Per-sprint Testing.__](testing/plan.md#per-sprint-testing)
|
||||
Subset of Pre-release Testing
|
||||
which should be performed before shipping at the end of any
|
||||
sprint. Time is allocated for a second round of
|
||||
Pre-release Testing if the first round is not passed.
|
||||
* __Triage.__ Team reviews issues from acceptance testing and uses
|
||||
success criteria to determine whether or not they should block
|
||||
release, then formulates a plan to address these issues before
|
||||
the next round of acceptance testing. Focus here should be on
|
||||
ensuring software passes that testing in order to ship on time;
|
||||
may prefer to disable malfunctioning components and fix them
|
||||
in a subsequent sprint, for example.
|
||||
* __Ship.__ Tag a code snapshot that has passed acceptance
|
||||
testing and deploy that version. (Only true if acceptance
|
||||
testing has passed by this point; if acceptance testing has not
|
||||
been passed, will need to make ad hoc decisions with stakeholders,
|
||||
e.g. "extend the sprint" or "defer shipment until end of next
|
||||
sprint.")
|
||||
|
||||
|
||||
@@ -1,156 +1,13 @@
|
||||
# Development Cycle
|
||||
|
||||
Development of Open MCT Web occurs on an iterative cycle of
|
||||
sprints and releases.
|
||||
|
||||
* A _sprint_ is three weeks in duration, and represents a
|
||||
set of improvements that can be completed and tested by the
|
||||
development team. Software at the end of the sprint is
|
||||
"semi-stable"; it will have undergone reduced testing and may carry
|
||||
defects or usability issues of lower severity, particularly if
|
||||
there are workarounds.
|
||||
* A _release_ occurs every four sprints. Releases are stable, and
|
||||
will have undergone full acceptance testing to ensure that the
|
||||
software behaves correctly and usably.
|
||||
|
||||
## Roles
|
||||
|
||||
The sprint process assumes the presence of a __project manager.__
|
||||
The project manager is responsible for
|
||||
making tactical decisions about what development work will be
|
||||
performed, and for coordinating with stakeholders to arrive at
|
||||
higher-level strategic decisions about desired functionality
|
||||
and characteristics of the software, major external milestones,
|
||||
and so forth.
|
||||
|
||||
In the absence of a dedicated project manager, this role may be rotated
|
||||
among members of the development team on a per-sprint basis.
|
||||
|
||||
Responsibilities of the project manager including:
|
||||
|
||||
* Maintaining (with agreement of stakeholders) a "road map" of work
|
||||
planned for future releases/sprints; this should be higher-level,
|
||||
usually expressed as "themes",
|
||||
with just enough specificity to gauge feasibility of plans,
|
||||
relate work back to milestones, and identify longer-term
|
||||
dependencies.
|
||||
* Determining (with assistance from the rest of the team) which
|
||||
issues to work on in a given sprint and how they shall be
|
||||
assigned.
|
||||
* Pre-planning subsequent sprints to ensure that all members of the
|
||||
team always have a clear direction.
|
||||
* Scheduling and/or ensuring adherence to
|
||||
[process points](#process-points).
|
||||
* Responding to changes within the sprint (shifting priorities,
|
||||
new issues) and re-allocating work for the sprint as needed.
|
||||
|
||||
## Sprint Calendar
|
||||
|
||||
Certain [process points](#process-points) are regularly scheduled in
|
||||
the sprint cycle.
|
||||
|
||||
### Sprints by Release
|
||||
|
||||
Allocation of work among sprints should be planned relative to release
|
||||
goals and milestones. As a general guideline, higher-risk work (large
|
||||
new features which may carry new defects, major refactoring, design
|
||||
changes with uncertain effects on usability) should be allocated to
|
||||
earlier sprints, allowing for time in later sprints to ensure stability.
|
||||
|
||||
| Sprint | Focus |
|
||||
|:------:|:--------------------------------------------------------|
|
||||
| __1__ | Prototyping, design, experimentation. |
|
||||
| __2__ | New features, refinements, enhancements. |
|
||||
| __3__ | Feature completion, low-risk enhancements, bug fixing. |
|
||||
| __4__ | Stability & quality assurance. |
|
||||
|
||||
### Sprints 1-3
|
||||
|
||||
The first three sprints of a release are primarily centered around
|
||||
development work, with regular acceptance testing in the third
|
||||
week. During this third week, the top priority should be passing
|
||||
acceptance testing (e.g. by resolving any blockers found); any
|
||||
resources not needed for this effort should be used to begin work
|
||||
for the subsequent sprint.
|
||||
|
||||
| Week | Mon | Tue | Wed | Thu | Fri |
|
||||
|:-----:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
|
||||
| __1__ | Sprint plan | Tag-up | | | |
|
||||
| __2__ | | Tag-up | | | Code freeze |
|
||||
| __3__ | Sprint acceptance testing | Triage | | _Sprint acceptance testing*_ | Ship |
|
||||
|
||||
* If necessary.
|
||||
|
||||
### Sprint 4
|
||||
|
||||
The software must be stable at the end of the fourth sprint; because of
|
||||
this, the fourth sprint is scheduled differently, with a heightened
|
||||
emphasis on testing.
|
||||
|
||||
| Week | Mon | Tue | Wed | Thu | Fri |
|
||||
|-------:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
|
||||
| __1__ | Sprint plan | Tag-up | | | Code freeze |
|
||||
| __2__ | Acceptance testing | Triage | | | |
|
||||
| __3__ | _Acceptance testing*_ | Triage | | _Acceptance testing*_ | Ship |
|
||||
|
||||
* If necessary.
|
||||
|
||||
## Process Points
|
||||
|
||||
* __Sprint plan.__ Project manager allocates issues based on
|
||||
theme(s) for sprint, then reviews with team. Each team member
|
||||
should have roughly two weeks of work allocated (to allow time
|
||||
in the third week for testing of work completed.)
|
||||
* Project manager should also sketch out subsequent sprint so
|
||||
that team may begin work for that sprint during the
|
||||
third week, since testing and blocker resolution is unlikely
|
||||
to require all available resources.
|
||||
* __Tag-up.__ Check in and status update among development team.
|
||||
May amend plan for sprint as-needed.
|
||||
* __Code freeze.__ Any new work from this sprint
|
||||
(features, bug fixes, enhancements) must be integrated by the
|
||||
end of the second week of the sprint. After code freeze
|
||||
(and until the end of the sprint) the only changes that should be
|
||||
merged into the master branch should directly address issues
|
||||
needed to pass acceptance testing.
|
||||
* __Acceptance Testing.__ Structured testing with predefined
|
||||
success criteria. No release should ship without passing
|
||||
acceptance tests. Time is allocated in each sprint for subsequent
|
||||
rounds of acceptance testing if issues are identified during a
|
||||
prior round. Specific details of acceptance testing need to be
|
||||
agreed-upon with relevant stakeholders and delivery recipients,
|
||||
and should be flexible enough to allow changes to plans
|
||||
(e.g. deferring delivery of some feature in order to ensure
|
||||
stability of other features.) Baseline testing includes:
|
||||
* __Testathon.__ Multi-user testing, involving as many users as
|
||||
is feasible, plus development team. Open-ended; should verify
|
||||
completed work from this sprint, test exploratorily for
|
||||
regressions, et cetera.
|
||||
* __24-Hour Test.__ A test to verify that the software remains
|
||||
stable after running for longer durations. May include some
|
||||
combination of automated testing and user verification (e.g.
|
||||
checking to verify that software remains subjectively
|
||||
responsive at conclusion of test.)
|
||||
* __Automated Testing.__ Automated testing integrated into the
|
||||
build. (These tests are verified to pass more often than once
|
||||
per sprint, as they run before any merge to master, but still
|
||||
play an important role in acceptance testing.)
|
||||
* __Sprint Acceptance Testing.__ Subset of Acceptance Testing
|
||||
which should be performed before shipping at the end of any
|
||||
sprint. Time is allocated for a second round of
|
||||
Sprint Acceptance Testing if the first round is not passed.
|
||||
* __Triage.__ Team reviews issues from acceptance testing and uses
|
||||
success criteria to determine whether or not they should block
|
||||
release, then formulates a plan to address these issues before
|
||||
the next round of acceptance testing. Focus here should be on
|
||||
ensuring software passes that testing in order to ship on time;
|
||||
may prefer to disable malfunctioning components and fix them
|
||||
in a subsequent sprint, for example.
|
||||
* __Ship.__ Tag a code snapshot that has passed acceptance
|
||||
testing and deploy that version. (Only true if acceptance
|
||||
testing has passed by this point; if acceptance testing has not
|
||||
been passed, will need to make ad hoc decisions with stakeholders,
|
||||
e.g. "extend the sprint" or "defer shipment until end of next
|
||||
sprint.")
|
||||
# Development Process
|
||||
|
||||
The process used to develop Open MCT Web is described in the following
|
||||
documents:
|
||||
|
||||
* [Development Cycle](cycle.md): Describes how and when specific
|
||||
process points are repeated during development.
|
||||
* Testing is described in two documents:
|
||||
* The [Test Plan](testing/plan.md) summarizes the approaches used
|
||||
to test Open MCT Web.
|
||||
* The [Test Procedures](testing/procedures.md) document what
|
||||
specific tests are performed to verify correctness, and how
|
||||
they should be carried out.
|
||||
|
||||
127
docs/src/process/testing/plan.md
Normal file
127
docs/src/process/testing/plan.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Test Plan
|
||||
|
||||
## Test Levels
|
||||
|
||||
Testing for Open MCT Web includes:
|
||||
|
||||
* _Smoke testing_: Brief, informal testing to verify that no major issues
|
||||
or regressions are present in the software, or in specific features of
|
||||
the software.
|
||||
* _Unit testing_: Automated verification of the performance of individual
|
||||
software components.
|
||||
* _User testing_: Testing with a representative user base to verify
|
||||
that application behaves usably and as specified.
|
||||
* _Long-duration testing_: Testing which takes place over a long period
|
||||
of time to detect issues which are not readily noticeable during
|
||||
shorter test periods.
|
||||
|
||||
### Smoke Testing
|
||||
|
||||
Manual, non-rigorous testing of the software and/or specific features
|
||||
of interest. Verifies that the software runs and that basic functionality
|
||||
is present.
|
||||
|
||||
### Unit Testing
|
||||
|
||||
Unit tests are automated tests which exercise individual software
|
||||
components. Tests are subject to code review along with the actual
|
||||
implementation, to ensure that tests are applicable and useful.
|
||||
|
||||
Unit tests should meet
|
||||
[test standards](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#test-standards)
|
||||
as described in the contributing guide.
|
||||
|
||||
### User Testing
|
||||
|
||||
User testing is performed at scheduled times involving target users
|
||||
of the software or reasonable representatives, along with members of
|
||||
the development team exercising known use cases. Users test the
|
||||
software directly; the software should be configured as similarly to
|
||||
its planned production configuration as is feasible without introducing
|
||||
other risks (e.g. damage to data in a production instance.)
|
||||
|
||||
User testing will focus on the following activities:
|
||||
|
||||
* Verifying issues resolved since the last test session.
|
||||
* Checking for regressions in areas related to recent changes.
|
||||
* Using major or important features of the software,
|
||||
as determined by the user.
|
||||
* General "trying to break things."
|
||||
|
||||
During user testing, users will
|
||||
[report issues](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
|
||||
as they are encountered.
|
||||
|
||||
Desired outcomes of user testing are:
|
||||
|
||||
* Identified software defects.
|
||||
* Areas for usability improvement.
|
||||
* Feature requests (particularly missed requirements.)
|
||||
* Recorded issue verification.
|
||||
|
||||
### Long-duration Testing
|
||||
|
||||
Long-duration testing occurs over a twenty-four hour period. The
|
||||
software is run in one or more stressing cases representative of expected
|
||||
usage. After twenty-four hours, the software is evaluated for:
|
||||
|
||||
* Performance metrics: Have memory usage or CPU utilization increased
|
||||
during this time period in unexpected or undesirable ways?
|
||||
* Subjective usability: Does the software behave in the same way it did
|
||||
at the start of the test? Is it as responsive?
|
||||
|
||||
Any defects or unexpected behavior identified during testing should be
|
||||
[reported as issues](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
|
||||
and reviewed for severity.
|
||||
|
||||
## Test Performance
|
||||
|
||||
Tests are performed at various levels of frequency.
|
||||
|
||||
* _Per-merge_: Performed before any new changes are integrated into
|
||||
the software.
|
||||
* _Per-sprint_: Performed at the end of every [sprint](../cycle.md).
|
||||
* _Per-release_: Performed at the end of every [release](../cycle.md).
|
||||
|
||||
### Per-merge Testing
|
||||
|
||||
Before changes are merged, the author of the changes must perform:
|
||||
|
||||
* _Smoke testing_ (both generally, and for areas which interact with
|
||||
the new changes.)
|
||||
* _Unit testing_ (as part of the automated build step.)
|
||||
|
||||
Changes are not merged until the author has affirmed that both
|
||||
forms of testing have been performed successfully; this is documented
|
||||
by the [Author Checklist](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#author-checklist).
|
||||
|
||||
### Per-sprint Testing
|
||||
|
||||
Before a sprint is closed, the development team must additionally
|
||||
perform:
|
||||
|
||||
* A relevant subset of [_user testing_](procedures.md#user-test-procedures)
|
||||
identified by the acting [project manager](../cycle.md#roles).
|
||||
* [_Long-duration testing_](procedures.md#long-duration-testng)
|
||||
(specifically, for 24 hours.)
|
||||
|
||||
Issues are reported as a product of both forms of testing.
|
||||
|
||||
A sprint is not closed until both categories have been performed on
|
||||
the latest snapshot of the software, _and_ no issues labelled as
|
||||
["blocker"](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
|
||||
remain open.
|
||||
|
||||
### Per-release Testing
|
||||
|
||||
As [per-sprint testing](#per-sprint-testing), except that _user testing_
|
||||
should cover all test cases, with less focus on changes from the specific
|
||||
sprint or release.
|
||||
|
||||
Per-release testing should also include any acceptance testing steps
|
||||
agreed upon with recipients of the software.
|
||||
|
||||
A release is not closed until both categories have been performed on
|
||||
the latest snapshot of the software, _and_ no issues labelled as
|
||||
["blocker" or "critical"](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
|
||||
remain open.
|
||||
169
docs/src/process/testing/procedures.md
Normal file
169
docs/src/process/testing/procedures.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# Test Procedures
|
||||
|
||||
## Introduction
|
||||
|
||||
This document is intended to be used:
|
||||
|
||||
* By testers, to verify that Open MCT Web behaves as specified.
|
||||
* By the development team, to document new test cases and to provide
|
||||
guidance on how to author these.
|
||||
|
||||
## Writing Procedures
|
||||
|
||||
### Template
|
||||
|
||||
Procedures for individual tests should use the following template,
|
||||
adapted from [https://swehb.nasa.gov/display/7150/SWE-114]().
|
||||
|
||||
Property | Value
|
||||
---------------|---------------------------------------------------------------
|
||||
Test ID |
|
||||
Relevant reqs. |
|
||||
Prerequisites |
|
||||
Test input |
|
||||
Instructions |
|
||||
Expectation |
|
||||
Eval. criteria |
|
||||
|
||||
For multi-line descriptions, use an asterisk or similar indicator to refer
|
||||
to a longer-form description below.
|
||||
|
||||
#### Example Procedure - Edit a Layout
|
||||
|
||||
Property | Value
|
||||
---------------|---------------------------------------------------------------
|
||||
Test ID | MCT-TEST-000X - Edit a layout
|
||||
Relevant reqs. | MCT-EDIT-000Y
|
||||
Prerequisites | Create a layout, as in MCT-TEST-000Z
|
||||
Test input | Domain object database XYZ
|
||||
Instructions | See below *
|
||||
Expectation | Change to editing context †
|
||||
Eval. criteria | Visual inspection
|
||||
|
||||
* Follow the following steps:
|
||||
|
||||
1. Verify that the created layout is currently navigated-to,
|
||||
as in MCT-TEST-00ZZ.
|
||||
2. Click the Edit button, identified by a pencil icon and the text "Edit"
|
||||
displayed on hover.
|
||||
|
||||
† Right-hand viewing area should be surrounded by a dashed
|
||||
blue border when a domain object is being edited.
|
||||
|
||||
### Guidelines
|
||||
|
||||
Test procedures should be written assuming minimal prior knowledge of the
|
||||
application: Non-standard terms should only be used when they are documented
|
||||
in [the glossary](#glossary), and shorthands used for user actions should
|
||||
be accompanied by useful references to test procedures describing those
|
||||
actions (when available) or descriptions in user documentation.
|
||||
|
||||
Test cases should be narrow in scope; if a list of steps is excessively
|
||||
long (or must be written vaguely to be kept short) it should be broken
|
||||
down into multiple tests which reference one another.
|
||||
|
||||
All requirements satisfied by Open MCT Web should be verifiable using
|
||||
one or more test procedures.
|
||||
|
||||
## Glossary
|
||||
|
||||
This section will contain terms used in test procedures. This may link to
|
||||
a common glossary, to avoid replication of content.
|
||||
|
||||
## Procedures
|
||||
|
||||
This section will contain specific test procedures. Presently, procedures
|
||||
are placeholders describing general patterns for setting up and conducting
|
||||
testing.
|
||||
|
||||
### User Testing Setup
|
||||
|
||||
These procedures describes a general pattern for setting up for user
|
||||
testing. Specific deployments should customize this pattern with
|
||||
relevant data and any additional steps necessary.
|
||||
|
||||
Property | Value
|
||||
---------------|---------------------------------------------------------------
|
||||
Test ID | MCT-TEST-SETUP0 - User Testing Setup
|
||||
Relevant reqs. | TBD
|
||||
Prerequisites | Build of relevant components
|
||||
Test input | Exemplary database; exemplary telemetry data set
|
||||
Instructions | See below
|
||||
Expectation | Able to load application in a web browser (Google Chrome)
|
||||
Eval. criteria | Visual inspection
|
||||
|
||||
Instructions:
|
||||
|
||||
1. Start telemetry server.
|
||||
2. Start ElasticSearch.
|
||||
3. Restore database snapshot to ElasticSearch.
|
||||
4. Start telemetry playback.
|
||||
5. Start HTTP server for client sources.
|
||||
|
||||
### User Test Procedures
|
||||
|
||||
Specific user test cases have not yet been authored. In their absence,
|
||||
user testing is conducted by:
|
||||
|
||||
* Reviewing the text of issues from the issue tracker to understand the
|
||||
desired behavior, and exercising this behavior in the running application.
|
||||
(For instance, by following steps to reproduce from the original issue.)
|
||||
* Issues which appear to be resolved should be marked as such with comments
|
||||
on the original issue (e.g. "verified during user testing MM/DD/YYYY".)
|
||||
* Issues which appear not to have been resolved should be reopened with an
|
||||
explanation of what unexpected behavior has been observed.
|
||||
* In cases where an issue appears resolved as-worded but other related
|
||||
undesirable behavior is observed during testing, a new issue should be
|
||||
opened, and linked to from a comment in the original issues.
|
||||
* General usage of new features and/or existing features which have undergone
|
||||
recent changes. Defects or problems with usability should be documented
|
||||
by filing issues in the issue tracker.
|
||||
* Open-ended testing to discover defects, identify usability issues, and
|
||||
generate feature requests.
|
||||
|
||||
### Long-Duration Testing
|
||||
|
||||
The purpose of long-duration testing is to identify performance issues
|
||||
and/or other defects which are sensitive to the amount of time the
|
||||
application is kept running. (Memory leaks, for instance.)
|
||||
|
||||
Property | Value
|
||||
---------------|---------------------------------------------------------------
|
||||
Test ID | MCT-TEST-LDT0 - Long-duration Testing
|
||||
Relevant reqs. | TBD
|
||||
Prerequisites | MCT-TEST-SETUP0
|
||||
Test input | (As for test setup.)
|
||||
Instructions | See "Instructions" below *
|
||||
Expectation | See "Expectations" below †
|
||||
Eval. criteria | Visual inspection
|
||||
|
||||
* Instructions:
|
||||
|
||||
1. Start `top` or a similar tool to measure CPU usage and memory utilization.
|
||||
2. Open several user-created displays (as many as would be realistically
|
||||
opened during actual usage in a stressing case) in some combination of
|
||||
separate tabs and windows (approximately as many tabs-per-window as
|
||||
total windows.)
|
||||
3. Ensure that playback data is set to run continuously for at least 24 hours
|
||||
(e.g. on a loop.)
|
||||
4. Record CPU usage and memory utilization.
|
||||
5. In at least one tab, try some general user interface gestures and make
|
||||
notes about the subjective experience of using the application. (Particularly,
|
||||
the degree of responsiveness.)
|
||||
6. Leave client displays open for 24 hours.
|
||||
7. Record CPU usage and memory utilization again.
|
||||
8. Make additional notes about the subjective experience of using the
|
||||
application (again, particularly responsiveness.)
|
||||
9. Check logs for any unexpected warnings or errors.
|
||||
|
||||
† Expectations:
|
||||
|
||||
* At the end of the test, CPU usage and memory usage should both be similar
|
||||
to their levels at the start of the test.
|
||||
* At the end of the test, subjective usage of the application should not
|
||||
be observably different from the way it was at the start of the test.
|
||||
(In particular, responsiveness should not decrease.)
|
||||
* Logs should not contain any unexpected warnings or errors ("expected"
|
||||
warnings or errors are those that have been documented and prioritized
|
||||
as known issues, or those that are explained by transient conditions
|
||||
external to the software, such as network outages.)
|
||||
@@ -39,8 +39,11 @@ define(
|
||||
start = Date.now();
|
||||
|
||||
function update() {
|
||||
var secs = (Date.now() - start) / 1000;
|
||||
var now = Date.now(),
|
||||
secs = (now - start) / 1000;
|
||||
displayed = Math.round(digests / secs);
|
||||
start = now;
|
||||
digests = 0;
|
||||
}
|
||||
|
||||
function increment() {
|
||||
|
||||
2
example/scratchpad/README.md
Normal file
2
example/scratchpad/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Example of using multiple persistence stores by exposing a root
|
||||
object with a different space prefix.
|
||||
23
example/scratchpad/bundle.json
Normal file
23
example/scratchpad/bundle.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"extensions": {
|
||||
"roots": [
|
||||
{
|
||||
"id": "scratch:root",
|
||||
"model": {
|
||||
"type": "folder",
|
||||
"composition": [],
|
||||
"name": "Scratchpad"
|
||||
},
|
||||
"priority": "preferred"
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"provides": "persistenceService",
|
||||
"type": "provider",
|
||||
"implementation": "ScratchPersistenceProvider.js",
|
||||
"depends": [ "$q" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
79
example/scratchpad/src/ScratchPersistenceProvider.js
Normal file
79
example/scratchpad/src/ScratchPersistenceProvider.js
Normal file
@@ -0,0 +1,79 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define,window*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* The ScratchPersistenceProvider keeps JSON documents in memory
|
||||
* and provides a persistence interface, but changes are lost on reload.
|
||||
* @memberof example/scratchpad
|
||||
* @constructor
|
||||
* @implements {PersistenceService}
|
||||
* @param q Angular's $q, for promises
|
||||
*/
|
||||
function ScratchPersistenceProvider($q) {
|
||||
this.$q = $q;
|
||||
this.table = {};
|
||||
}
|
||||
|
||||
ScratchPersistenceProvider.prototype.listSpaces = function () {
|
||||
return this.$q.when(['scratch']);
|
||||
};
|
||||
|
||||
ScratchPersistenceProvider.prototype.listObjects = function (space) {
|
||||
return this.$q.when(
|
||||
space === 'scratch' ? Object.keys(this.table) : []
|
||||
);
|
||||
};
|
||||
|
||||
ScratchPersistenceProvider.prototype.createObject = function (space, key, value) {
|
||||
if (space === 'scratch') {
|
||||
this.table[key] = JSON.stringify(value);
|
||||
}
|
||||
return this.$q.when(space === 'scratch');
|
||||
};
|
||||
|
||||
ScratchPersistenceProvider.prototype.readObject = function (space, key) {
|
||||
return this.$q.when(
|
||||
(space === 'scratch' && this.table[key]) ?
|
||||
JSON.parse(this.table[key]) : undefined
|
||||
);
|
||||
};
|
||||
|
||||
ScratchPersistenceProvider.prototype.deleteObject = function (space, key, value) {
|
||||
if (space === 'scratch') {
|
||||
delete this.table[key];
|
||||
}
|
||||
return this.$q.when(space === 'scratch');
|
||||
};
|
||||
|
||||
ScratchPersistenceProvider.prototype.updateObject =
|
||||
ScratchPersistenceProvider.prototype.createObject;
|
||||
|
||||
return ScratchPersistenceProvider;
|
||||
}
|
||||
);
|
||||
@@ -102,6 +102,12 @@
|
||||
"implementation": "navigation/NavigationService.js"
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"implementation": "creation/CreationPolicy.js",
|
||||
"category": "creation"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"key": "navigate",
|
||||
|
||||
@@ -69,7 +69,7 @@ define(
|
||||
|
||||
// Introduce one create action per type
|
||||
return this.typeService.listTypes().filter(function (type) {
|
||||
return type.hasFeature("creation");
|
||||
return self.policyService.allow("creation", type);
|
||||
}).map(function (type) {
|
||||
return new CreateAction(
|
||||
type,
|
||||
|
||||
45
platform/commonUI/browse/src/creation/CreationPolicy.js
Normal file
45
platform/commonUI/browse/src/creation/CreationPolicy.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A policy for determining whether objects of a given type can be
|
||||
* created.
|
||||
* @constructor
|
||||
* @implements {Policy}
|
||||
* @memberof platform/commonUI/browse
|
||||
*/
|
||||
function CreationPolicy() {
|
||||
}
|
||||
|
||||
CreationPolicy.prototype.allow = function (type) {
|
||||
return type.hasFeature("creation");
|
||||
};
|
||||
|
||||
return CreationPolicy;
|
||||
}
|
||||
);
|
||||
@@ -33,6 +33,9 @@ define(
|
||||
var mockTypeService,
|
||||
mockDialogService,
|
||||
mockCreationService,
|
||||
mockPolicyService,
|
||||
mockCreationPolicy,
|
||||
mockPolicyMap = {},
|
||||
mockTypes,
|
||||
provider;
|
||||
|
||||
@@ -67,14 +70,32 @@ define(
|
||||
"creationService",
|
||||
[ "createObject" ]
|
||||
);
|
||||
mockPolicyService = jasmine.createSpyObj(
|
||||
"policyService",
|
||||
[ "allow" ]
|
||||
);
|
||||
|
||||
mockTypes = [ "A", "B", "C" ].map(createMockType);
|
||||
|
||||
mockTypes.forEach(function(type){
|
||||
mockPolicyMap[type.getName()] = true;
|
||||
});
|
||||
|
||||
mockCreationPolicy = function(type){
|
||||
return mockPolicyMap[type.getName()];
|
||||
};
|
||||
|
||||
mockPolicyService.allow.andCallFake(function(category, type){
|
||||
return category === "creation" && mockCreationPolicy(type) ? true : false;
|
||||
});
|
||||
|
||||
mockTypeService.listTypes.andReturn(mockTypes);
|
||||
|
||||
provider = new CreateActionProvider(
|
||||
mockTypeService,
|
||||
mockDialogService,
|
||||
mockCreationService
|
||||
mockCreationService,
|
||||
mockPolicyService
|
||||
);
|
||||
});
|
||||
|
||||
@@ -94,15 +115,15 @@ define(
|
||||
|
||||
it("does not expose non-creatable types", function () {
|
||||
// One of the types won't have the creation feature...
|
||||
mockTypes[1].hasFeature.andReturn(false);
|
||||
mockPolicyMap[mockTypes[0].getName()] = false;
|
||||
// ...so it should have been filtered out.
|
||||
expect(provider.getActions({
|
||||
key: "create",
|
||||
domainObject: {}
|
||||
}).length).toEqual(2);
|
||||
// Make sure it was creation which was used to check
|
||||
expect(mockTypes[1].hasFeature)
|
||||
.toHaveBeenCalledWith("creation");
|
||||
expect(mockPolicyService.allow)
|
||||
.toHaveBeenCalledWith("creation", mockTypes[0]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
53
platform/commonUI/browse/test/creation/CreationPolicySpec.js
Normal file
53
platform/commonUI/browse/test/creation/CreationPolicySpec.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/creation/CreationPolicy"],
|
||||
function (CreationPolicy) {
|
||||
"use strict";
|
||||
|
||||
describe("The creation policy", function () {
|
||||
var mockType,
|
||||
policy;
|
||||
|
||||
beforeEach(function () {
|
||||
mockType = jasmine.createSpyObj(
|
||||
'type',
|
||||
['hasFeature']
|
||||
);
|
||||
|
||||
policy = new CreationPolicy();
|
||||
});
|
||||
|
||||
it("allows creation of types with the creation feature", function () {
|
||||
mockType.hasFeature.andReturn(true);
|
||||
expect(policy.allow(mockType)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("disallows creation of types without the creation feature", function () {
|
||||
mockType.hasFeature.andReturn(false);
|
||||
expect(policy.allow(mockType)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -8,6 +8,7 @@
|
||||
"creation/CreateMenuController",
|
||||
"creation/CreateWizard",
|
||||
"creation/CreationService",
|
||||
"creation/CreationPolicy",
|
||||
"creation/LocatorController",
|
||||
"navigation/NavigateAction",
|
||||
"navigation/NavigationService",
|
||||
|
||||
@@ -50,7 +50,7 @@ define(
|
||||
// Simply trigger refresh of in-view objects; do not
|
||||
// write anything to database.
|
||||
persistence.persist = function () {
|
||||
cache.markDirty(editableObject);
|
||||
return cache.markDirty(editableObject);
|
||||
};
|
||||
|
||||
// Delegate refresh to the original object; this avoids refreshing
|
||||
|
||||
@@ -111,6 +111,7 @@ define(
|
||||
*/
|
||||
EditableDomainObjectCache.prototype.markDirty = function (domainObject) {
|
||||
this.dirtyObjects[domainObject.getId()] = domainObject;
|
||||
return this.$q.when(true);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,7 @@ define(
|
||||
mockEditableObject,
|
||||
mockDomainObject,
|
||||
mockCache,
|
||||
mockPromise,
|
||||
capability;
|
||||
|
||||
beforeEach(function () {
|
||||
@@ -50,7 +51,9 @@ define(
|
||||
"cache",
|
||||
[ "markDirty" ]
|
||||
);
|
||||
mockPromise = jasmine.createSpyObj("promise", ["then"]);
|
||||
|
||||
mockCache.markDirty.andReturn(mockPromise);
|
||||
mockDomainObject.getCapability.andReturn(mockPersistence);
|
||||
|
||||
capability = new EditablePersistenceCapability(
|
||||
@@ -84,6 +87,10 @@ define(
|
||||
expect(mockPersistence.refresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns a promise from persist", function () {
|
||||
expect(capability.persist().then).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -19,6 +19,10 @@
|
||||
{
|
||||
"implementation": "StyleSheetLoader.js",
|
||||
"depends": [ "stylesheets[]", "$document", "THEME" ]
|
||||
},
|
||||
{
|
||||
"implementation": "UnsupportedBrowserWarning.js",
|
||||
"depends": [ "notificationService", "agentService" ]
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
@@ -225,10 +229,6 @@
|
||||
"templateUrl": "templates/subtree.html",
|
||||
"uses": [ "composition" ]
|
||||
},
|
||||
{
|
||||
"key": "test",
|
||||
"templateUrl": "templates/test.html"
|
||||
},
|
||||
{
|
||||
"key": "tree-node",
|
||||
"templateUrl": "templates/tree-node.html",
|
||||
|
||||
@@ -35,24 +35,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.l-autoflow-header {
|
||||
bottom: auto;
|
||||
height: $headerH;
|
||||
line-height: $headerH;
|
||||
min-width: $colW;
|
||||
span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
min-width: $colW;
|
||||
.t-last-update {
|
||||
overflow: hidden;
|
||||
}
|
||||
.s-btn.change-column-width {
|
||||
@include trans-prop-nice-fade(500ms);
|
||||
opacity: 0;
|
||||
}
|
||||
.l-filter {
|
||||
margin-left: $interiorMargin;
|
||||
display: block;
|
||||
margin-right: $interiorMargin;
|
||||
input.t-filter-input {
|
||||
width: 100px;
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,4 +126,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.frame {
|
||||
&.child-frame.panel {
|
||||
.autoflow .l-autoflow-header .l-filter {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,6 @@ a.disabled {
|
||||
border-bottom: 1px solid rgba(#fff, 0.3);
|
||||
}
|
||||
|
||||
.outline {
|
||||
@include boxOutline();
|
||||
}
|
||||
|
||||
.test-stripes {
|
||||
@include bgDiagonalStripes();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
margin: 0 0 2px 0; // Needed to avoid dropshadow from being clipped by parent containers
|
||||
}
|
||||
padding: 0 $interiorMargin;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
line-height: $formInputH;
|
||||
select {
|
||||
|
||||
@@ -34,51 +34,31 @@ $mobileTreeItemH: 35px;
|
||||
$mobileTreeItemIndent: 20px;
|
||||
$mobileTreeRightArrowW: 30px;
|
||||
|
||||
/************************** WINDOW DIMENSIONS FOR RWD */
|
||||
$phoMaxW: 514px;
|
||||
$phoMaxH: 740px;
|
||||
|
||||
$tabMinW: 515px;
|
||||
$tabMaxW: 799px;
|
||||
|
||||
$tabMinH: 741px;
|
||||
$tabMaxH: 1024px;
|
||||
|
||||
$compMinW: 800px;
|
||||
$compMinH: 1025px;
|
||||
/************************** DEVICE WIDTHS */
|
||||
// IMPORTANT! Usage assumes that ranges are mutually exclusive and have no gaps
|
||||
$phoMaxW: 767px;
|
||||
$tabMinW: 768px;
|
||||
$tabMaxW: 1024px;
|
||||
$desktopMinW: 1025px;
|
||||
|
||||
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
|
||||
$screenPortrait: "screen and (orientation: portrait)";
|
||||
$screenLandscape: "screen and (orientation: landscape)";
|
||||
$screenPortrait: "(orientation: portrait)";
|
||||
$screenLandscape: "(orientation: landscape)";
|
||||
|
||||
$mobileDevice: "(max-device-width: #{$tabMaxW}) and (max-device-height: #{$tabMaxH})";
|
||||
$mobileDeviceEmu: "(max-device-width: #{$tabMaxH}) and (max-device-height: #{$tabMaxW})";
|
||||
//$mobileDevice: "(max-device-width: #{$tabMaxW})";
|
||||
|
||||
$phonePortraitCheck: "(max-width: #{$phoMaxW}) and (max-height: #{$phoMaxH})";
|
||||
$phoneLandscapeCheck: "(max-height: #{$phoMaxW}) and (max-width: #{$phoMaxH})";
|
||||
|
||||
$tabWidPorCheck: "(min-width: #{$tabMinW}) and (max-width: #{$tabMaxW})";
|
||||
$tabHeiPorCheck: "(min-height: #{$tabMinH}) and (max-height: #{$tabMaxH})";
|
||||
$tabletPortraitCheck: "#{$tabWidPorCheck} and #{$tabHeiPorCheck}";
|
||||
|
||||
$tabWidLanCheck: "(min-height: #{$tabMinW}) and (max-height: #{$tabMaxW})";
|
||||
$tabHeiLanCheck: "(min-width: #{$tabMinH}) and (max-width: #{$tabMaxH})";
|
||||
$tabletLandscapeCheck: "#{$tabWidLanCheck} and #{$tabHeiLanCheck}";
|
||||
|
||||
$desktopPortraitCheck: "(min-device-width: #{$compMinW}) and (min-device-height: #{$compMinH})";
|
||||
$desktopLandscapeCheck: "(min-device-width: #{$compMinH}) and (min-device-height: #{$compMinW})";
|
||||
$phoneCheck: "(max-device-width: #{$phoMaxW})";
|
||||
$tabletCheck: "(min-device-width: #{$tabMinW}) and (max-device-width: #{$tabMaxW})";
|
||||
$desktopCheck: "(min-device-width: #{$desktopMinW}) and (-webkit-min-device-pixel-ratio: 1)";
|
||||
|
||||
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
|
||||
$phonePortrait: "#{$screenPortrait} and #{$phonePortraitCheck} and #{$mobileDevice}";
|
||||
$phoneLandscape: "#{$screenLandscape} and #{$phoneLandscapeCheck} and #{$mobileDevice}";
|
||||
$phoneLandscapeEmu: "#{$screenLandscape} and #{$phoneLandscapeCheck} and #{$mobileDeviceEmu}";
|
||||
$phonePortrait: "only screen and #{$screenPortrait} and #{$phoneCheck}";
|
||||
$phoneLandscape: "only screen and #{$screenLandscape} and #{$phoneCheck}";
|
||||
|
||||
$tabletPortrait: "#{$screenPortrait} and #{$tabletPortraitCheck} and #{$mobileDevice}";
|
||||
$tabletLandscape: "#{$screenLandscape} and #{$tabletLandscapeCheck} and #{$mobileDevice}";
|
||||
$tabletLandscapeEmu: "#{$screenLandscape} and #{$tabletLandscapeCheck} and #{$mobileDeviceEmu}";
|
||||
$tabletPortrait: "only screen and #{$screenPortrait} and #{$tabletCheck}";
|
||||
$tabletLandscape: "only screen and #{$screenLandscape} and #{$tabletCheck}";
|
||||
|
||||
$desktopPortrait: "screen and #{$desktopPortraitCheck}";
|
||||
$desktopLandscape: "screen and #{$desktopLandscapeCheck}";
|
||||
$desktop: "only screen and #{$desktopCheck}";
|
||||
|
||||
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
|
||||
$proporMenuOnly: 90%;
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
// Phones in any orientation
|
||||
@mixin phone {
|
||||
@media #{$phonePortrait},
|
||||
#{$phoneLandscape},
|
||||
#{$phoneLandscapeEmu} {
|
||||
#{$phoneLandscape} {
|
||||
@content
|
||||
}
|
||||
}
|
||||
@@ -40,8 +39,7 @@
|
||||
|
||||
// Phones in landscape orientation
|
||||
@mixin phoneLandscape {
|
||||
@media #{$phoneLandscape},
|
||||
#{$phoneLandscapeEmu} {
|
||||
@media #{$phoneLandscape} {
|
||||
@content
|
||||
}
|
||||
}
|
||||
@@ -49,8 +47,7 @@
|
||||
// Tablets in any orientation
|
||||
@mixin tablet {
|
||||
@media #{$tabletPortrait},
|
||||
#{$tabletLandscape},
|
||||
#{$tabletLandscapeEmu} {
|
||||
#{$tabletLandscape} {
|
||||
@content
|
||||
}
|
||||
}
|
||||
@@ -64,8 +61,7 @@
|
||||
|
||||
// Tablets in landscape orientation
|
||||
@mixin tabletLandscape {
|
||||
@media #{$tabletLandscape},
|
||||
#{$tabletLandscapeEmu} {
|
||||
@media #{$tabletLandscape} {
|
||||
@content
|
||||
}
|
||||
}
|
||||
@@ -74,10 +70,8 @@
|
||||
@mixin phoneandtablet {
|
||||
@media #{$phonePortrait},
|
||||
#{$phoneLandscape},
|
||||
#{$phoneLandscapeEmu},
|
||||
#{$tabletPortrait},
|
||||
#{$tabletLandscape},
|
||||
#{$tabletLandscapeEmu} {
|
||||
#{$tabletLandscape} {
|
||||
@content
|
||||
}
|
||||
}
|
||||
@@ -86,17 +80,14 @@
|
||||
@mixin desktopandtablet {
|
||||
@media #{$tabletPortrait},
|
||||
#{$tabletLandscape},
|
||||
#{$tabletLandscapeEmu},
|
||||
#{$desktopPortrait},
|
||||
#{$desktopLandscape} {
|
||||
#{$desktop} {
|
||||
@content
|
||||
}
|
||||
}
|
||||
|
||||
// Desktop monitors in any orientation
|
||||
@mixin desktop {
|
||||
@media #{$desktopPortrait},
|
||||
#{$desktopLandscape} {
|
||||
@media #{$desktop} {
|
||||
@content
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,9 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
$yBarW: 60px;
|
||||
$yLabelW: auto;
|
||||
$yLabelW: 10px;
|
||||
$xBarH: 32px;
|
||||
$legendH: 20px;
|
||||
//$colorHash: rgba(white, 0.3); // MOVED INTO CONSTANTS
|
||||
//$styleHash: dashed; // MOVED INTO CONSTANTS
|
||||
$swatchD: 8px;
|
||||
$plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBarW); // Top, right, bottom, left
|
||||
|
||||
@@ -36,7 +34,6 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
height: 100%;
|
||||
|
||||
.gl-plot-axis-area {
|
||||
// @include test(green);
|
||||
position: absolute;
|
||||
&.gl-plot-x {
|
||||
top: auto;
|
||||
@@ -59,7 +56,7 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
.gl-plot-coords {
|
||||
@include box-sizing(border-box);
|
||||
@include border-radius($controlCr);
|
||||
background: black; //rgba($colorKey, 0.5);
|
||||
background: black;
|
||||
color: lighten($colorBodyFg, 30%);
|
||||
padding: 2px 5px;
|
||||
position: absolute;
|
||||
@@ -88,11 +85,9 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
|
||||
.gl-plot-label,
|
||||
.l-plot-label {
|
||||
// @include test(yellow);
|
||||
color: $colorPlotLabelFg;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
// text-transform: uppercase;
|
||||
|
||||
&.gl-plot-x-label,
|
||||
&.l-plot-x-label {
|
||||
@@ -117,20 +112,26 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
}
|
||||
}
|
||||
|
||||
.gl-plot-y-options {
|
||||
.gl-plot-x-options,
|
||||
.gl-plot-y-options {
|
||||
$h: 32px;
|
||||
// @include test();
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
left: $yLabelW + $interiorMargin;
|
||||
margin-top: $h / -2;
|
||||
height: auto;
|
||||
min-height: $h;
|
||||
width: $h;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.gl-plot-x-options {
|
||||
top: $interiorMargin;
|
||||
}
|
||||
|
||||
.gl-plot-y-options {
|
||||
@include transform(translateY(-50%));
|
||||
min-width: 150px; // Need this due to enclosure of .select
|
||||
top: 50%;
|
||||
left: $yLabelW + $interiorMargin * 2;
|
||||
}
|
||||
|
||||
.gl-plot-hash {
|
||||
position: absolute;
|
||||
border: 0 $colorPlotHash $stylePlotHash;
|
||||
@@ -214,21 +215,13 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
display: inline-block;
|
||||
height: $swatchD;
|
||||
width: $swatchD;
|
||||
//margin-right: $interiorMarginSm;
|
||||
}
|
||||
&[class*='s-limit'] {
|
||||
.title-label {
|
||||
//color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gl-plot-legend {
|
||||
.plot-legend-item {
|
||||
//@include test();
|
||||
@include border-radius($smallCr);
|
||||
//color: #fff;
|
||||
line-height: 1.5em;
|
||||
padding: 0px $itemPadLR;
|
||||
.plot-color-swatch {
|
||||
@@ -250,7 +243,6 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
|
||||
.gl-plot-tick,
|
||||
.tick-label {
|
||||
// @include test(red);
|
||||
font-size: 0.7rem;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
@@ -277,7 +269,6 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
|
||||
}
|
||||
|
||||
.gl-plot-tick {
|
||||
// @include test(red);
|
||||
&.gl-plot-x-tick-label {
|
||||
top: $interiorMargin;
|
||||
}
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
.splitter-treeview,
|
||||
.holder-treeview-elements {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,6 +305,7 @@
|
||||
.l-inspect,
|
||||
.splitter-inspect {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,29 @@
|
||||
<!--
|
||||
Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT Web includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span class="s-btn"
|
||||
ng-controller="DateTimeFieldController">
|
||||
<input type="text"
|
||||
ng-model="textValue"
|
||||
ng-blur="restoreTextValue(); ngBlur()"
|
||||
ng-class="{ error: textInvalid }">
|
||||
</input>
|
||||
<a class="ui-symbol icon icon-calendar"
|
||||
@@ -11,8 +33,8 @@
|
||||
<mct-popup ng-if="picker.active">
|
||||
<div mct-click-elsewhere="picker.active = false">
|
||||
<mct-control key="'datetime-picker'"
|
||||
ng-model="ngModel"
|
||||
field="field"
|
||||
ng-model="pickerModel"
|
||||
field="'value'"
|
||||
options="{ hours: true }">
|
||||
</mct-control>
|
||||
</div>
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div ng-controller="TimeRangeController">
|
||||
<div class="l-time-range-inputs-holder">
|
||||
<form class="l-time-range-inputs-holder"
|
||||
ng-submit="updateBoundsFromForm()">
|
||||
<span class="l-time-range-inputs-elem ui-symbol type-icon">C</span>
|
||||
<span class="l-time-range-input">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{ format: parameters.format }"
|
||||
ng-model="ngModel.outer"
|
||||
ng-model="formModel"
|
||||
ng-blur="updateBoundsFromForm()"
|
||||
field="'start'"
|
||||
class="time-range-start">
|
||||
</mct-control>
|
||||
@@ -36,12 +38,15 @@
|
||||
<span class="l-time-range-input" ng-controller="ToggleController as t2">
|
||||
<mct-control key="'datetime-field'"
|
||||
structure="{ format: parameters.format }"
|
||||
ng-model="ngModel.outer"
|
||||
ng-model="formModel"
|
||||
ng-blur="updateBoundsFromForm()"
|
||||
field="'end'"
|
||||
class="time-range-end">
|
||||
</mct-control>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<input type="submit" class="hidden">
|
||||
</form>
|
||||
|
||||
<div class="l-time-range-slider-holder">
|
||||
<div class="l-time-range-slider">
|
||||
|
||||
64
platform/commonUI/general/src/UnsupportedBrowserWarning.js
Normal file
64
platform/commonUI/general/src/UnsupportedBrowserWarning.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* This bundle provides various general-purpose UI elements, including
|
||||
* platform styling.
|
||||
* @namespace platform/commonUI/general
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
var WARNING_TITLE = "Unsupported browser",
|
||||
WARNING_DESCRIPTION = [
|
||||
"This software has been developed and tested",
|
||||
"using the latest Google Chrome,",
|
||||
"and may be unstable in other browsers."
|
||||
].join(" "),
|
||||
MOBILE_BROWSER = "Safari",
|
||||
DESKTOP_BROWSER = "Chrome";
|
||||
|
||||
/**
|
||||
* Shows a warning if a user's browser is unsupported.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
* @param {NotificationService} notificationService the notification
|
||||
* service
|
||||
*/
|
||||
function UnsupportedBrowserWarning(notificationService, agentService) {
|
||||
var testToBrowser = agentService.isMobile() ?
|
||||
MOBILE_BROWSER : DESKTOP_BROWSER;
|
||||
|
||||
if (!agentService.isBrowser(testToBrowser)) {
|
||||
notificationService.alert({
|
||||
title: WARNING_TITLE,
|
||||
actionText: WARNING_DESCRIPTION
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return UnsupportedBrowserWarning;
|
||||
}
|
||||
);
|
||||
@@ -53,7 +53,9 @@ define(
|
||||
formatter.parse($scope.textValue) !== value) {
|
||||
$scope.textValue = formatter.format(value);
|
||||
$scope.textInvalid = false;
|
||||
$scope.lastValidValue = $scope.textValue;
|
||||
}
|
||||
$scope.pickerModel = { value: value };
|
||||
}
|
||||
|
||||
function updateFromView(textValue) {
|
||||
@@ -61,6 +63,17 @@ define(
|
||||
if (!$scope.textInvalid) {
|
||||
$scope.ngModel[$scope.field] =
|
||||
formatter.parse(textValue);
|
||||
$scope.lastValidValue = $scope.textValue;
|
||||
}
|
||||
}
|
||||
|
||||
function updateFromPicker(value) {
|
||||
if (value !== $scope.ngModel[$scope.field]) {
|
||||
$scope.ngModel[$scope.field] = value;
|
||||
updateFromModel(value);
|
||||
if ($scope.ngBlur) {
|
||||
$scope.ngBlur();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +82,18 @@ define(
|
||||
updateFromModel($scope.ngModel[$scope.field]);
|
||||
}
|
||||
|
||||
function restoreTextValue() {
|
||||
$scope.textValue = $scope.lastValidValue;
|
||||
updateFromView($scope.textValue);
|
||||
}
|
||||
|
||||
$scope.restoreTextValue = restoreTextValue;
|
||||
|
||||
$scope.picker = { active: false };
|
||||
|
||||
$scope.$watch('structure.format', setFormat);
|
||||
$scope.$watch('ngModel[field]', updateFromModel);
|
||||
$scope.$watch('pickerModel.value', updateFromPicker);
|
||||
$scope.$watch('textValue', updateFromView);
|
||||
|
||||
}
|
||||
|
||||
@@ -175,6 +175,13 @@ define(
|
||||
updateViewFromModel($scope.ngModel);
|
||||
}
|
||||
|
||||
function updateFormModel() {
|
||||
$scope.formModel = {
|
||||
start: (($scope.ngModel || {}).outer || {}).start,
|
||||
end: (($scope.ngModel || {}).outer || {}).end
|
||||
};
|
||||
}
|
||||
|
||||
function updateOuterStart(t) {
|
||||
var ngModel = $scope.ngModel;
|
||||
|
||||
@@ -192,6 +199,7 @@ define(
|
||||
ngModel.inner.end
|
||||
);
|
||||
|
||||
updateFormModel();
|
||||
updateViewForInnerSpanFromModel(ngModel);
|
||||
updateTicks();
|
||||
}
|
||||
@@ -213,6 +221,7 @@ define(
|
||||
ngModel.inner.start
|
||||
);
|
||||
|
||||
updateFormModel();
|
||||
updateViewForInnerSpanFromModel(ngModel);
|
||||
updateTicks();
|
||||
}
|
||||
@@ -223,6 +232,14 @@ define(
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
function updateBoundsFromForm() {
|
||||
$scope.ngModel = $scope.ngModel || {};
|
||||
$scope.ngModel.outer = {
|
||||
start: $scope.formModel.start,
|
||||
end: $scope.formModel.end
|
||||
};
|
||||
}
|
||||
|
||||
$scope.startLeftDrag = startLeftDrag;
|
||||
$scope.startRightDrag = startRightDrag;
|
||||
$scope.startMiddleDrag = startMiddleDrag;
|
||||
@@ -230,10 +247,13 @@ define(
|
||||
$scope.rightDrag = rightDrag;
|
||||
$scope.middleDrag = middleDrag;
|
||||
|
||||
$scope.updateBoundsFromForm = updateBoundsFromForm;
|
||||
|
||||
$scope.ticks = [];
|
||||
|
||||
// Initialize scope to defaults
|
||||
updateViewFromModel($scope.ngModel);
|
||||
updateFormModel();
|
||||
|
||||
$scope.$watchCollection("ngModel", updateViewFromModel);
|
||||
$scope.$watch("spanWidth", updateSpanWidth);
|
||||
|
||||
@@ -204,7 +204,7 @@ define(
|
||||
// And poll for position changes enforced by styles
|
||||
activeInterval = $interval(function () {
|
||||
getSetPosition(getSetPosition());
|
||||
}, POLLING_INTERVAL, false);
|
||||
}, POLLING_INTERVAL, 0, false);
|
||||
|
||||
// ...and stop polling when we're destroyed.
|
||||
$scope.$on('$destroy', function () {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../src/UnsupportedBrowserWarning"],
|
||||
function (UnsupportedBrowserWarning) {
|
||||
"use strict";
|
||||
|
||||
var MOBILE_BROWSER = "Safari",
|
||||
DESKTOP_BROWSER = "Chrome",
|
||||
UNSUPPORTED_BROWSERS = [
|
||||
"Firefox",
|
||||
"IE",
|
||||
"Opera",
|
||||
"Iceweasel"
|
||||
];
|
||||
|
||||
describe("The unsupported browser warning", function () {
|
||||
var mockNotificationService,
|
||||
mockAgentService,
|
||||
testAgent;
|
||||
|
||||
function instantiateWith(browser) {
|
||||
testAgent = "Mozilla/5.0 " + browser + "/12.34.56";
|
||||
return new UnsupportedBrowserWarning(
|
||||
mockNotificationService,
|
||||
mockAgentService
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
testAgent = "chrome";
|
||||
mockNotificationService = jasmine.createSpyObj(
|
||||
"notificationService",
|
||||
[ "alert" ]
|
||||
);
|
||||
mockAgentService = jasmine.createSpyObj(
|
||||
"agentService",
|
||||
[ "isMobile", "isBrowser" ]
|
||||
);
|
||||
mockAgentService.isBrowser.andCallFake(function (substr) {
|
||||
substr = substr.toLowerCase();
|
||||
return testAgent.toLowerCase().indexOf(substr) !== -1;
|
||||
});
|
||||
});
|
||||
|
||||
[ false, true ].forEach(function (isMobile) {
|
||||
var deviceType = isMobile ? "mobile" : "desktop",
|
||||
goodBrowser = isMobile ? MOBILE_BROWSER : DESKTOP_BROWSER,
|
||||
badBrowsers = UNSUPPORTED_BROWSERS.concat([
|
||||
isMobile ? DESKTOP_BROWSER : MOBILE_BROWSER
|
||||
]);
|
||||
|
||||
describe("on " + deviceType + " devices", function () {
|
||||
beforeEach(function () {
|
||||
mockAgentService.isMobile.andReturn(isMobile);
|
||||
});
|
||||
|
||||
it("is not shown for " + goodBrowser, function () {
|
||||
instantiateWith(goodBrowser);
|
||||
expect(mockNotificationService.alert)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
badBrowsers.forEach(function (badBrowser) {
|
||||
it("is shown for " + badBrowser, function () {
|
||||
instantiateWith(badBrowser);
|
||||
expect(mockNotificationService.alert)
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -67,21 +67,13 @@ define(
|
||||
mockScope.ngModel = { testField: 12321 };
|
||||
mockScope.field = "testField";
|
||||
mockScope.structure = { format: "someFormat" };
|
||||
mockScope.ngBlur = jasmine.createSpy('blur');
|
||||
|
||||
controller = new DateTimeFieldController(
|
||||
mockScope,
|
||||
mockFormatService
|
||||
);
|
||||
});
|
||||
|
||||
it("updates models from user-entered text", function () {
|
||||
var newText = "1977-05-25 17:30:00";
|
||||
|
||||
mockScope.textValue = newText;
|
||||
fireWatch("textValue", newText);
|
||||
expect(mockScope.ngModel.testField)
|
||||
.toEqual(mockFormat.parse(newText));
|
||||
expect(mockScope.textInvalid).toBeFalsy();
|
||||
fireWatch("ngModel[field]", mockScope.ngModel.testField);
|
||||
});
|
||||
|
||||
it("updates text from model values", function () {
|
||||
@@ -91,16 +83,55 @@ define(
|
||||
expect(mockScope.textValue).toEqual("1977-05-25 17:30:00");
|
||||
});
|
||||
|
||||
describe("when valid text is entered", function () {
|
||||
var newText;
|
||||
|
||||
beforeEach(function () {
|
||||
newText = "1977-05-25 17:30:00";
|
||||
mockScope.textValue = newText;
|
||||
fireWatch("textValue", newText);
|
||||
});
|
||||
|
||||
it("updates models from user-entered text", function () {
|
||||
expect(mockScope.ngModel.testField)
|
||||
.toEqual(mockFormat.parse(newText));
|
||||
expect(mockScope.textInvalid).toBeFalsy();
|
||||
});
|
||||
|
||||
it("does not indicate a blur event", function () {
|
||||
expect(mockScope.ngBlur).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when a date is chosen via the date picker", function () {
|
||||
var newValue;
|
||||
|
||||
beforeEach(function () {
|
||||
newValue = 12345654321;
|
||||
mockScope.pickerModel.value = newValue;
|
||||
fireWatch("pickerModel.value", newValue);
|
||||
});
|
||||
|
||||
it("updates models", function () {
|
||||
expect(mockScope.ngModel.testField).toEqual(newValue);
|
||||
});
|
||||
|
||||
it("fires a blur event", function () {
|
||||
expect(mockScope.ngBlur).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("exposes toggle state for date-time picker", function () {
|
||||
expect(mockScope.picker.active).toBe(false);
|
||||
});
|
||||
|
||||
describe("when user input is invalid", function () {
|
||||
var newText, oldValue;
|
||||
var newText, oldText, oldValue;
|
||||
|
||||
beforeEach(function () {
|
||||
newText = "Not a date";
|
||||
oldValue = mockScope.ngModel.testField;
|
||||
oldText = mockScope.textValue;
|
||||
mockScope.textValue = newText;
|
||||
fireWatch("textValue", newText);
|
||||
});
|
||||
@@ -116,6 +147,11 @@ define(
|
||||
it("does not modify user input", function () {
|
||||
expect(mockScope.textValue).toEqual(newText);
|
||||
});
|
||||
|
||||
it("restores valid text values on request", function () {
|
||||
mockScope.restoreTextValue();
|
||||
expect(mockScope.textValue).toEqual(oldText);
|
||||
});
|
||||
});
|
||||
|
||||
it("does not modify valid but irregular user input", function () {
|
||||
|
||||
@@ -91,6 +91,39 @@ define(
|
||||
.toHaveBeenCalledWith("ngModel", jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe("when changes are made via form entry", function () {
|
||||
beforeEach(function () {
|
||||
mockScope.ngModel = {
|
||||
outer: { start: DAY * 2, end: DAY * 3 },
|
||||
inner: { start: DAY * 2.25, end: DAY * 2.75 }
|
||||
};
|
||||
mockScope.formModel = {
|
||||
start: DAY * 10000,
|
||||
end: DAY * 11000
|
||||
};
|
||||
// These watches may not exist, but Angular would fire
|
||||
// them if they did.
|
||||
fireWatchCollection("formModel", mockScope.formModel);
|
||||
fireWatch("formModel.start", mockScope.formModel.start);
|
||||
fireWatch("formModel.end", mockScope.formModel.end);
|
||||
});
|
||||
|
||||
it("does not immediately make changes to the model", function () {
|
||||
expect(mockScope.ngModel.outer.start)
|
||||
.not.toEqual(mockScope.formModel.start);
|
||||
expect(mockScope.ngModel.outer.end)
|
||||
.not.toEqual(mockScope.formModel.end);
|
||||
});
|
||||
|
||||
it("updates model bounds on request", function () {
|
||||
mockScope.updateBoundsFromForm();
|
||||
expect(mockScope.ngModel.outer.start)
|
||||
.toEqual(mockScope.formModel.start);
|
||||
expect(mockScope.ngModel.outer.end)
|
||||
.toEqual(mockScope.formModel.end);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when dragged", function () {
|
||||
beforeEach(function () {
|
||||
mockScope.ngModel = {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/directives/MCTSplitPane"],
|
||||
function (MCTSplitPane) {
|
||||
'use strict';
|
||||
|
||||
var JQLITE_METHODS = [
|
||||
'on',
|
||||
'addClass',
|
||||
'children',
|
||||
'eq'
|
||||
];
|
||||
|
||||
describe("The mct-split-pane directive", function () {
|
||||
var mockParse,
|
||||
mockLog,
|
||||
mockInterval,
|
||||
mctSplitPane;
|
||||
|
||||
beforeEach(function () {
|
||||
mockParse = jasmine.createSpy('$parse');
|
||||
mockLog =
|
||||
jasmine.createSpyObj('$log', ['warn', 'info', 'debug']);
|
||||
mockInterval = jasmine.createSpy('$interval');
|
||||
mockInterval.cancel = jasmine.createSpy('mockCancel');
|
||||
mctSplitPane = new MCTSplitPane(
|
||||
mockParse,
|
||||
mockLog,
|
||||
mockInterval
|
||||
);
|
||||
});
|
||||
|
||||
it("is only applicable as an element", function () {
|
||||
expect(mctSplitPane.restrict).toEqual("E");
|
||||
});
|
||||
|
||||
describe("when its controller is applied", function () {
|
||||
var mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockChildren,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope =
|
||||
jasmine.createSpyObj('$scope', ['$apply', '$watch', '$on']);
|
||||
mockElement =
|
||||
jasmine.createSpyObj('element', JQLITE_METHODS);
|
||||
testAttrs = {};
|
||||
mockChildren =
|
||||
jasmine.createSpyObj('children', JQLITE_METHODS);
|
||||
|
||||
mockElement.children.andReturn(mockChildren);
|
||||
mockChildren.eq.andReturn(mockChildren);
|
||||
mockChildren[0] = {};
|
||||
|
||||
controller = mctSplitPane.controller[3](
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs
|
||||
);
|
||||
});
|
||||
|
||||
it("sets an interval which does not trigger digests", function () {
|
||||
expect(mockInterval.mostRecentCall.args[3]).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
@@ -19,8 +19,10 @@
|
||||
"directives/MCTPopup",
|
||||
"directives/MCTResize",
|
||||
"directives/MCTScroll",
|
||||
"directives/MCTSplitPane",
|
||||
"services/Popup",
|
||||
"services/PopupService",
|
||||
"services/UrlService",
|
||||
"StyleSheetLoader"
|
||||
"StyleSheetLoader",
|
||||
"UnsupportedBrowserWarning"
|
||||
]
|
||||
|
||||
@@ -43,6 +43,7 @@ define(
|
||||
var userAgent = $window.navigator.userAgent,
|
||||
matches = userAgent.match(/iPad|iPhone|Android/i) || [];
|
||||
|
||||
this.userAgent = userAgent;
|
||||
this.mobileName = matches[0];
|
||||
this.$window = $window;
|
||||
}
|
||||
@@ -91,6 +92,18 @@ define(
|
||||
return !this.isPortrait();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the user agent matches a certain named device,
|
||||
* as indicated by checking for a case-insensitive substring
|
||||
* match.
|
||||
* @param {string} name the name to check for
|
||||
* @returns {boolean} true if the user agent includes that name
|
||||
*/
|
||||
AgentService.prototype.isBrowser = function (name) {
|
||||
name = name.toLowerCase();
|
||||
return this.userAgent.toLowerCase().indexOf(name) !== -1;
|
||||
};
|
||||
|
||||
return AgentService;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -81,6 +81,13 @@ define(
|
||||
expect(agentService.isPortrait()).toBeTruthy();
|
||||
expect(agentService.isLandscape()).toBeFalsy();
|
||||
});
|
||||
|
||||
it("allows for checking browser type", function () {
|
||||
testWindow.navigator.userAgent = "Chromezilla Safarifox";
|
||||
agentService = new AgentService(testWindow);
|
||||
expect(agentService.isBrowser("Chrome")).toBe(true);
|
||||
expect(agentService.isBrowser("Firefox")).toBe(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/* line 5, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
@@ -41,38 +41,38 @@ time, mark, audio, video {
|
||||
font-size: 100%;
|
||||
vertical-align: baseline; }
|
||||
|
||||
/* line 22, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
html {
|
||||
line-height: 1; }
|
||||
|
||||
/* line 24, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
ol, ul {
|
||||
list-style: none; }
|
||||
|
||||
/* line 26, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0; }
|
||||
|
||||
/* line 28, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
caption, th, td {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
vertical-align: middle; }
|
||||
|
||||
/* line 30, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
q, blockquote {
|
||||
quotes: none; }
|
||||
/* line 103, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
q:before, q:after, blockquote:before, blockquote:after {
|
||||
content: "";
|
||||
content: none; }
|
||||
|
||||
/* line 32, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
a img {
|
||||
border: none; }
|
||||
|
||||
/* line 116, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
|
||||
display: block; }
|
||||
|
||||
@@ -173,7 +173,7 @@ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu,
|
||||
/* REQUIRES /platform/commonUI/general/res/sass/_constants.scss */
|
||||
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
|
||||
/************************** MOBILE TREE MENU DIMENSIONS */
|
||||
/************************** WINDOW DIMENSIONS FOR RWD */
|
||||
/************************** DEVICE WIDTHS */
|
||||
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
|
||||
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
|
||||
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
|
||||
@@ -235,10 +235,6 @@ a.disabled {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.3); }
|
||||
|
||||
/* line 34, ../../../../general/res/sass/_effects.scss */
|
||||
.outline {
|
||||
border: 1px solid #666666; }
|
||||
|
||||
/* line 38, ../../../../general/res/sass/_effects.scss */
|
||||
.test-stripes {
|
||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjEuMCIgeTE9IjEuMCIgeDI9IjAuMCIgeTI9IjAuMCI+PHN0b3Agb2Zmc2V0PSIyNSUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSIyNSUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjMDAwMDAwIiBzdG9wLW9wYWNpdHk9IjAuMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
|
||||
background-size: 100%;
|
||||
@@ -248,7 +244,7 @@ a.disabled {
|
||||
background-repeat: repeat;
|
||||
background-size: 40px 40px; }
|
||||
|
||||
/* line 42, ../../../../general/res/sass/_effects.scss */
|
||||
/* line 38, ../../../../general/res/sass/_effects.scss */
|
||||
.test {
|
||||
background-color: rgba(255, 204, 0, 0.2) !important; }
|
||||
|
||||
@@ -267,7 +263,7 @@ a.disabled {
|
||||
opacity: 0.5; }
|
||||
100% {
|
||||
opacity: 1; } }
|
||||
/* line 69, ../../../../general/res/sass/_effects.scss */
|
||||
/* line 65, ../../../../general/res/sass/_effects.scss */
|
||||
.pulse {
|
||||
-moz-animation-name: pulse;
|
||||
-webkit-animation-name: pulse;
|
||||
@@ -990,7 +986,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 76, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-left .l-infobubble::before {
|
||||
right: 100%; }
|
||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 76, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-left .l-infobubble::before {
|
||||
width: 0;
|
||||
@@ -998,14 +994,14 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
border-top: 6.66667px solid transparent;
|
||||
border-bottom: 6.66667px solid transparent;
|
||||
border-right: 10px solid #ddd; } }
|
||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 88, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-right {
|
||||
margin-right: 20px; } }
|
||||
/* line 95, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-right .l-infobubble::before {
|
||||
left: 100%; }
|
||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 95, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-right .l-infobubble::before {
|
||||
width: 0;
|
||||
@@ -1647,7 +1643,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn.major .icon, .major.s-menu-btn .icon, .s-btn.major .t-item-icon, .major.s-menu-btn .t-item-icon {
|
||||
color: #fff; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn.major:not(.disabled):hover, .major.s-menu-btn:not(.disabled):hover {
|
||||
background: linear-gradient(#1ac6ff, #00bfff); }
|
||||
@@ -1686,7 +1682,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn:not(.major) .icon, .s-menu-btn:not(.major) .icon, .s-btn:not(.major) .t-item-icon, .s-menu-btn:not(.major) .t-item-icon {
|
||||
color: #0099cc; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn:not(.major):not(.disabled):hover, .s-menu-btn:not(.major):not(.disabled):hover {
|
||||
background: linear-gradient(#6b6b6b, #5e5e5e); }
|
||||
@@ -1728,7 +1724,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn.pause-play.paused .icon, .pause-play.paused.s-menu-btn .icon, .s-btn.pause-play.paused .t-item-icon, .pause-play.paused.s-menu-btn .t-item-icon {
|
||||
color: #fff; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn.pause-play.paused:not(.disabled):hover, .pause-play.paused.s-menu-btn:not(.disabled):hover {
|
||||
background: linear-gradient(#fe9815, #f88c01); }
|
||||
@@ -1759,7 +1755,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
.s-btn.show-thumbs .icon:before, .show-thumbs.s-menu-btn .icon:before, .s-btn.show-thumbs .t-item-icon:before, .show-thumbs.s-menu-btn .t-item-icon:before {
|
||||
content: "\000039"; }
|
||||
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 101, ../../../../general/res/sass/controls/_buttons.scss */
|
||||
.mini-tab {
|
||||
-moz-border-radius: 3px;
|
||||
@@ -1829,14 +1825,14 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.mini-tab.collapsed .icon, .mini-tab.collapsed .t-item-icon {
|
||||
color: #0099cc; } }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px) and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 800px) and (min-device-height: 1025px) and (min-device-width: 1025px) and (min-device-height: 800px), screen and (min-device-width: 1025px) and (min-device-height: 800px) and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.mini-tab.collapsed:not(.disabled):hover {
|
||||
background: linear-gradient(#6b6b6b, #5e5e5e); }
|
||||
/* line 304, ../../../../general/res/sass/_mixins.scss */
|
||||
.mini-tab.collapsed:not(.disabled):hover > .icon, .mini-tab.collapsed:not(.disabled):hover > .t-item-icon {
|
||||
color: #33ccff; } }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 138, ../../../../general/res/sass/controls/_buttons.scss */
|
||||
.mini-tab.collapsed:before {
|
||||
opacity: 0; }
|
||||
@@ -1925,7 +1921,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
.mini-tab.anchor-right.collapsed:hover:before {
|
||||
right: 2px; } }
|
||||
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 208, ../../../../general/res/sass/controls/_buttons.scss */
|
||||
.mini-tab-icon {
|
||||
color: #595959;
|
||||
@@ -2314,7 +2310,7 @@ label.checkbox.custom {
|
||||
font-size: 0.7em;
|
||||
flex: 0 0 1;
|
||||
-webkit-flex: 0 0 1; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 240, ../../../../general/res/sass/controls/_controls.scss */
|
||||
.object-header .context-available {
|
||||
-moz-transition-property: opacity;
|
||||
@@ -2657,7 +2653,7 @@ label.checkbox.custom {
|
||||
color: inherit; }
|
||||
|
||||
/******************************************************** BROWSER ELEMENTS */
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 485, ../../../../general/res/sass/controls/_controls.scss */
|
||||
::-webkit-scrollbar {
|
||||
-moz-border-radius: 2px;
|
||||
@@ -3359,7 +3355,7 @@ label.checkbox.custom {
|
||||
/* line 213, ../../../../general/res/sass/controls/_messages.scss */
|
||||
.t-message-single .message-severity-error .type-icon.message-type:before {
|
||||
content: "\21"; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 259, ../../../../general/res/sass/controls/_messages.scss */
|
||||
.t-message-single .l-message,
|
||||
.t-message-single .bottom-bar {
|
||||
@@ -3430,7 +3426,7 @@ label.checkbox.custom {
|
||||
.t-message-list .message-contents .l-message .top-bar,
|
||||
.t-message-list .message-contents .l-message .message-body {
|
||||
margin-bottom: 10px; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 304, ../../../../general/res/sass/controls/_messages.scss */
|
||||
.t-message-list .message-contents .l-message {
|
||||
margin-right: 10px; } }
|
||||
@@ -3682,7 +3678,7 @@ mct-include.l-time-controller {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 25, ../../../../general/res/sass/mobile/controls/_menus.scss */
|
||||
.super-menu {
|
||||
width: 250px;
|
||||
@@ -3956,20 +3952,19 @@ textarea {
|
||||
text-shadow: rgba(0, 0, 0, 0.1) 0 1px 2px;
|
||||
margin: 0 0 2px 0;
|
||||
padding: 0 5px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
line-height: 22px; }
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.select .icon, .select .t-item-icon {
|
||||
color: #0099cc; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.select:not(.disabled):hover {
|
||||
background: linear-gradient(#6b6b6b, #5e5e5e); }
|
||||
/* line 304, ../../../../general/res/sass/_mixins.scss */
|
||||
.select:not(.disabled):hover > .icon, .select:not(.disabled):hover > .t-item-icon {
|
||||
color: #33ccff; } }
|
||||
/* line 31, ../../../../general/res/sass/forms/_selects.scss */
|
||||
/* line 30, ../../../../general/res/sass/forms/_selects.scss */
|
||||
.select select {
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
@@ -3982,10 +3977,10 @@ textarea {
|
||||
border: none !important;
|
||||
padding: 4px 25px 2px 0px;
|
||||
width: 120%; }
|
||||
/* line 40, ../../../../general/res/sass/forms/_selects.scss */
|
||||
/* line 39, ../../../../general/res/sass/forms/_selects.scss */
|
||||
.select select option {
|
||||
margin: 5px 0; }
|
||||
/* line 44, ../../../../general/res/sass/forms/_selects.scss */
|
||||
/* line 43, ../../../../general/res/sass/forms/_selects.scss */
|
||||
.select:after {
|
||||
text-shadow: none;
|
||||
content: '\76';
|
||||
@@ -4473,7 +4468,7 @@ span.req {
|
||||
/* line 138, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane .mini-tab-icon.toggle-pane {
|
||||
z-index: 5; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 138, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane .mini-tab-icon.toggle-pane {
|
||||
top: 10px;
|
||||
@@ -4629,9 +4624,10 @@ span.req {
|
||||
.pane-tree-hidden .tree-holder,
|
||||
.pane-tree-hidden .splitter-treeview,
|
||||
.pane-tree-hidden .holder-treeview-elements {
|
||||
opacity: 0; }
|
||||
opacity: 0;
|
||||
pointer-events: none; }
|
||||
|
||||
/* line 278, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 279, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-tree-showing .tree-holder,
|
||||
.pane-tree-showing .splitter-treeview {
|
||||
-moz-transition-property: opacity;
|
||||
@@ -4651,7 +4647,7 @@ span.req {
|
||||
-webkit-transition-delay: 250ms;
|
||||
transition-delay: 250ms;
|
||||
opacity: 1; }
|
||||
/* line 284, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 285, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-tree-showing .holder-treeview-elements {
|
||||
-moz-transition-property: opacity;
|
||||
-o-transition-property: opacity;
|
||||
@@ -4670,7 +4666,7 @@ span.req {
|
||||
-webkit-transition-delay: 200ms;
|
||||
transition-delay: 200ms; }
|
||||
|
||||
/* line 291, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 292, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-inspect-showing .l-object-and-inspector .l-inspect,
|
||||
.pane-inspect-showing .l-object-and-inspector .splitter-inspect {
|
||||
-moz-transition-property: opacity;
|
||||
@@ -4691,44 +4687,45 @@ span.req {
|
||||
transition-delay: 250ms;
|
||||
opacity: 1; }
|
||||
|
||||
/* line 301, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 302, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-inspect-hidden .l-object-and-inspector .t-inspect {
|
||||
z-index: 1 !important; }
|
||||
/* line 304, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 305, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-inspect-hidden .l-object-and-inspector .l-inspect,
|
||||
.pane-inspect-hidden .l-object-and-inspector .splitter-inspect {
|
||||
opacity: 0; }
|
||||
opacity: 0;
|
||||
pointer-events: none; }
|
||||
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
/* line 312, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 314, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.holder-all {
|
||||
min-width: 600px; }
|
||||
|
||||
/* line 317, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 319, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.split-layout .split-pane-component.pane.treeview.left {
|
||||
min-width: 150px;
|
||||
max-width: 35%;
|
||||
width: 25%; }
|
||||
/* line 322, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 324, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.split-layout .split-pane-component.pane.t-inspect.right {
|
||||
min-width: 200px;
|
||||
max-width: 35%;
|
||||
width: 20%;
|
||||
z-index: 3; }
|
||||
|
||||
/* line 330, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 332, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane.treeview.left .tree-holder {
|
||||
padding-right: 5px; }
|
||||
|
||||
/* line 334, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 336, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-tree-hidden .pane.right.primary-pane {
|
||||
left: 22px !important; }
|
||||
|
||||
/* line 337, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 339, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-inspect-hidden .l-object-and-inspector .pane.left {
|
||||
right: 22px !important; }
|
||||
|
||||
/* line 339, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 341, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane:not(.resizing) {
|
||||
-moz-transition-property: width, left, right;
|
||||
-o-transition-property: width, left, right;
|
||||
@@ -4747,7 +4744,7 @@ span.req {
|
||||
-webkit-transition-delay: 0;
|
||||
transition-delay: 0; }
|
||||
|
||||
/* line 342, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 344, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane.primary-pane .object-browse-bar {
|
||||
min-width: 200px; } }
|
||||
/*****************************************************************************
|
||||
@@ -4771,7 +4768,7 @@ span.req {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 26, ../../../../general/res/sass/mobile/_layout.scss */
|
||||
.browse-wrapper,
|
||||
.pane {
|
||||
@@ -4947,7 +4944,7 @@ span.req {
|
||||
-webkit-transition-delay: 0;
|
||||
transition-delay: 0;
|
||||
opacity: 1; } }
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px) {
|
||||
/* line 146, ../../../../general/res/sass/mobile/_layout.scss */
|
||||
.pane-tree-showing .pane.left.treeview {
|
||||
width: 90% !important; }
|
||||
@@ -4961,7 +4958,7 @@ span.req {
|
||||
/* line 152, ../../../../general/res/sass/mobile/_layout.scss */
|
||||
.pane-tree-showing .pane.right.items .holder-object-and-inspector {
|
||||
opacity: 0; } }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 160, ../../../../general/res/sass/mobile/_layout.scss */
|
||||
.desktop-hide {
|
||||
display: none; } }
|
||||
@@ -5276,7 +5273,7 @@ span.req {
|
||||
margin-left: 50%;
|
||||
white-space: nowrap; }
|
||||
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
|
||||
/* line 5, ../../../../general/res/sass/mobile/search/_search.scss */
|
||||
.search .search-bar .menu-icon {
|
||||
display: none; }
|
||||
@@ -5453,7 +5450,7 @@ span.req {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.overlay .bottom-bar .s-btn:not(.major) .icon, .overlay .bottom-bar .s-menu-btn:not(.major) .icon, .overlay .bottom-bar .s-btn:not(.major) .t-item-icon, .overlay .bottom-bar .s-menu-btn:not(.major) .t-item-icon {
|
||||
color: #fff; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.overlay .bottom-bar .s-btn:not(.major):not(.disabled):hover, .overlay .bottom-bar .s-menu-btn:not(.major):not(.disabled):hover {
|
||||
background: linear-gradient(#a6a6a6, #999999); }
|
||||
@@ -5486,7 +5483,7 @@ span.req {
|
||||
min-height: 225px;
|
||||
height: 225px; }
|
||||
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 3, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
|
||||
.overlay .clk-icon.close {
|
||||
top: 20px;
|
||||
@@ -5504,7 +5501,7 @@ span.req {
|
||||
/* line 17, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
|
||||
.overlay > .holder > .contents .top-bar > .title {
|
||||
margin-right: 1.2em; } }
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
|
||||
/* line 27, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
|
||||
.overlay > .holder {
|
||||
-moz-border-radius: 0;
|
||||
@@ -5575,7 +5572,7 @@ span.req {
|
||||
.t-dialog-sm .overlay > .holder {
|
||||
height: auto;
|
||||
max-height: 100%; } }
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px) {
|
||||
/* line 77, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
|
||||
.overlay > .holder .contents .bottom-bar {
|
||||
text-align: center; } }
|
||||
@@ -5648,7 +5645,7 @@ ul.tree {
|
||||
margin-left: 5px;
|
||||
font-size: 0.75em;
|
||||
width: 10px; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 56, ../../../../general/res/sass/tree/_tree.scss */
|
||||
.tree-item .view-control:hover,
|
||||
.search-result-item .view-control:hover {
|
||||
@@ -5781,7 +5778,7 @@ ul.tree {
|
||||
.tree-item.selected .t-object-label .t-item-icon,
|
||||
.search-result-item.selected .t-object-label .t-item-icon {
|
||||
color: #cccccc; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 136, ../../../../general/res/sass/tree/_tree.scss */
|
||||
.tree-item:not(.selected):hover,
|
||||
.search-result-item:not(.selected):hover {
|
||||
@@ -5833,7 +5830,7 @@ ul.tree {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 27, ../../../../general/res/sass/mobile/_tree.scss */
|
||||
ul.tree ul.tree {
|
||||
margin-left: 20px; }
|
||||
@@ -5924,7 +5921,7 @@ ul.tree {
|
||||
/* line 65, ../../../../general/res/sass/user-environ/_frame.scss */
|
||||
.frame.frame-template .view-switcher {
|
||||
z-index: 10; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 71, ../../../../general/res/sass/user-environ/_frame.scss */
|
||||
.frame.frame-template .view-switcher {
|
||||
opacity: 0; }
|
||||
@@ -6426,7 +6423,7 @@ table {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/* line 31, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 29, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot {
|
||||
color: #999;
|
||||
font-size: 0.7rem;
|
||||
@@ -6434,10 +6431,10 @@ table {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/****************************** Limits and Out-of-Bounds data */ }
|
||||
/* line 38, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 36, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-axis-area {
|
||||
position: absolute; }
|
||||
/* line 41, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 38, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-axis-area.gl-plot-x {
|
||||
top: auto;
|
||||
right: 0;
|
||||
@@ -6446,14 +6443,14 @@ table {
|
||||
height: 32px;
|
||||
width: auto;
|
||||
overflow: hidden; }
|
||||
/* line 50, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 47, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-axis-area.gl-plot-y {
|
||||
top: 25px;
|
||||
right: auto;
|
||||
bottom: 37px;
|
||||
left: 0;
|
||||
width: 60px; }
|
||||
/* line 59, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 56, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-coords {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
@@ -6470,10 +6467,10 @@ table {
|
||||
bottom: auto;
|
||||
left: 70px;
|
||||
z-index: 10; }
|
||||
/* line 71, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 68, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-coords:empty {
|
||||
display: none; }
|
||||
/* line 76, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 73, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-display-area {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
position: absolute;
|
||||
@@ -6483,13 +6480,13 @@ table {
|
||||
left: 60px;
|
||||
cursor: crosshair;
|
||||
border: 1px solid rgba(153, 153, 153, 0.1); }
|
||||
/* line 89, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 86, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-label,
|
||||
.gl-plot .l-plot-label {
|
||||
color: #666666;
|
||||
position: absolute;
|
||||
text-align: center; }
|
||||
/* line 97, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 92, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-label.gl-plot-x-label, .gl-plot .gl-plot-label.l-plot-x-label,
|
||||
.gl-plot .l-plot-label.gl-plot-x-label,
|
||||
.gl-plot .l-plot-label.l-plot-x-label {
|
||||
@@ -6498,7 +6495,7 @@ table {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: auto; }
|
||||
/* line 106, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 101, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-label.gl-plot-y-label, .gl-plot .gl-plot-label.l-plot-y-label,
|
||||
.gl-plot .l-plot-label.gl-plot-y-label,
|
||||
.gl-plot .l-plot-label.l-plot-y-label {
|
||||
@@ -6515,30 +6512,38 @@ table {
|
||||
left: 0;
|
||||
top: 50%;
|
||||
white-space: nowrap; }
|
||||
/* line 120, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 115, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-x-options,
|
||||
.gl-plot .gl-plot-y-options {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
left: auto5px;
|
||||
margin-top: -16px;
|
||||
height: auto;
|
||||
min-height: 32px;
|
||||
width: 32px; }
|
||||
/* line 134, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
z-index: 2; }
|
||||
/* line 124, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-x-options {
|
||||
top: 5px; }
|
||||
/* line 128, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-y-options {
|
||||
-moz-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
min-width: 150px;
|
||||
top: 50%;
|
||||
left: 20px; }
|
||||
/* line 135, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-hash {
|
||||
position: absolute;
|
||||
border: 0 rgba(255, 255, 255, 0.2) dashed; }
|
||||
/* line 137, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 138, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-hash.hash-v {
|
||||
border-right-width: 1px;
|
||||
height: 100%; }
|
||||
/* line 141, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 142, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-hash.hash-h {
|
||||
border-bottom-width: 1px;
|
||||
width: 100%; }
|
||||
/* line 147, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 148, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-legend {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -6548,24 +6553,24 @@ table {
|
||||
height: 20px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto; }
|
||||
/* line 160, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 161, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-limit-bar,
|
||||
.gl-plot .l-oob-data {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: auto; }
|
||||
/* line 168, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 169, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-limit-bar {
|
||||
height: auto;
|
||||
z-index: 0; }
|
||||
/* line 176, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 177, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-limit-bar.s-limit-yellow {
|
||||
background: rgba(255, 170, 0, 0.2); }
|
||||
/* line 177, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 178, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-limit-bar.s-limit-red {
|
||||
background: rgba(255, 0, 0, 0.2); }
|
||||
/* line 180, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 181, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-oob-data {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
@@ -6578,7 +6583,7 @@ table {
|
||||
pointer-events: none;
|
||||
height: 10px;
|
||||
z-index: 1; }
|
||||
/* line 188, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 189, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-oob-data.l-oob-data-up {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
@@ -6587,7 +6592,7 @@ table {
|
||||
background-image: -moz-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
|
||||
background-image: -webkit-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
|
||||
background-image: linear-gradient(0deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
|
||||
/* line 193, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 194, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-oob-data.l-oob-data-dwn {
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
@@ -6597,7 +6602,7 @@ table {
|
||||
background-image: -webkit-linear-gradient(270deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
|
||||
background-image: linear-gradient(180deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
|
||||
|
||||
/* line 203, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 204, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item,
|
||||
.gl-plot-legend .legend-item,
|
||||
.legend .plot-legend-item,
|
||||
@@ -6605,13 +6610,13 @@ table {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 3px; }
|
||||
/* line 208, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 209, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item span,
|
||||
.gl-plot-legend .legend-item span,
|
||||
.legend .plot-legend-item span,
|
||||
.legend .legend-item span {
|
||||
vertical-align: middle; }
|
||||
/* line 211, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 212, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item .plot-color-swatch,
|
||||
.gl-plot-legend .plot-legend-item .color-swatch,
|
||||
.gl-plot-legend .legend-item .plot-color-swatch,
|
||||
@@ -6627,29 +6632,29 @@ table {
|
||||
height: 8px;
|
||||
width: 8px; }
|
||||
|
||||
/* line 228, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 223, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item {
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
line-height: 1.5em;
|
||||
padding: 0px 5px; }
|
||||
/* line 234, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 227, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item .plot-color-swatch {
|
||||
border: 1px solid #333;
|
||||
height: 9px;
|
||||
width: 9px; }
|
||||
|
||||
/* line 242, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 235, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.tick {
|
||||
position: absolute;
|
||||
border: 0 rgba(255, 255, 255, 0.2) solid; }
|
||||
/* line 245, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 238, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.tick.tick-x {
|
||||
border-right-width: 1px;
|
||||
height: 100%; }
|
||||
|
||||
/* line 251, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 244, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick,
|
||||
.tick-label {
|
||||
font-size: 0.7rem;
|
||||
@@ -6657,7 +6662,7 @@ table {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis; }
|
||||
/* line 259, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 251, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick.gl-plot-x-tick-label, .gl-plot-tick.tick-label-x,
|
||||
.tick-label.gl-plot-x-tick-label,
|
||||
.tick-label.tick-label-x {
|
||||
@@ -6668,7 +6673,7 @@ table {
|
||||
width: 20%;
|
||||
margin-left: -10%;
|
||||
text-align: center; }
|
||||
/* line 269, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 261, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick.gl-plot-y-tick-label, .gl-plot-tick.tick-label-y,
|
||||
.tick-label.gl-plot-y-tick-label,
|
||||
.tick-label.tick-label-y {
|
||||
@@ -6678,18 +6683,18 @@ table {
|
||||
margin-bottom: -0.5em;
|
||||
text-align: right; }
|
||||
|
||||
/* line 281, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 272, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick.gl-plot-x-tick-label {
|
||||
top: 5px; }
|
||||
/* line 284, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 275, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick.gl-plot-y-tick-label {
|
||||
right: 5px;
|
||||
left: 5px; }
|
||||
|
||||
/* line 291, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 282, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.tick-label.tick-label-x {
|
||||
top: 0; }
|
||||
/* line 294, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 285, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.tick-label.tick-label-y {
|
||||
right: 0;
|
||||
left: 0; }
|
||||
@@ -6816,7 +6821,7 @@ table {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.items-holder .item.grid-item .icon, .items-holder .item.grid-item .t-item-icon {
|
||||
color: #0099cc; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.items-holder .item.grid-item:not(.disabled):hover {
|
||||
background: linear-gradient(#666666, #595959); }
|
||||
@@ -6947,7 +6952,7 @@ table {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.items-holder .item.grid-item.selected .icon, .items-holder .item.grid-item.selected .t-item-icon {
|
||||
color: #0099cc; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.items-holder .item.grid-item.selected:not(.disabled):hover {
|
||||
background: linear-gradient(#1ac6ff, #00bfff); }
|
||||
@@ -6988,7 +6993,7 @@ table {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
|
||||
.items-holder .item.grid-item {
|
||||
width: 100%; }
|
||||
@@ -7022,7 +7027,7 @@ table {
|
||||
opacity: 1;
|
||||
font-size: 1em;
|
||||
width: auto; } }
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
|
||||
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
|
||||
.items-holder .item.grid-item {
|
||||
height: 50px; }
|
||||
@@ -7042,7 +7047,7 @@ table {
|
||||
/* line 83, ../../../../general/res/sass/mobile/_item.scss */
|
||||
.items-holder .item.grid-item .item-main .item-open {
|
||||
line-height: 50px; } }
|
||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
|
||||
.items-holder .item.grid-item {
|
||||
height: 66px; }
|
||||
@@ -7107,16 +7112,16 @@ table {
|
||||
-webkit-transition-delay: 0;
|
||||
transition-delay: 0;
|
||||
opacity: 1; }
|
||||
/* line 40, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 38, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header {
|
||||
bottom: auto;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
min-width: 225px; }
|
||||
/* line 45, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header span {
|
||||
vertical-align: middle; }
|
||||
/* line 48, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 43, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header .t-last-update {
|
||||
overflow: hidden; }
|
||||
/* line 46, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header .s-btn.change-column-width, .autoflow .l-autoflow-header .change-column-width.s-menu-btn {
|
||||
-moz-transition-property: opacity, background-color, border-color, color;
|
||||
-o-transition-property: opacity, background-color, border-color, color;
|
||||
@@ -7135,19 +7140,20 @@ table {
|
||||
-webkit-transition-delay: 0;
|
||||
transition-delay: 0;
|
||||
opacity: 0; }
|
||||
/* line 52, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 50, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header .l-filter {
|
||||
margin-left: 5px; }
|
||||
/* line 54, ../../../../general/res/sass/_autoflow.scss */
|
||||
display: block;
|
||||
margin-right: 5px; }
|
||||
/* line 53, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header .l-filter input.t-filter-input {
|
||||
width: 100px; }
|
||||
/* line 60, ../../../../general/res/sass/_autoflow.scss */
|
||||
width: 150px; }
|
||||
/* line 59, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items {
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
top: 32px;
|
||||
white-space: nowrap; }
|
||||
/* line 66, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 65, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
@@ -7158,7 +7164,7 @@ table {
|
||||
padding-right: 5px;
|
||||
vertical-align: top;
|
||||
width: 225px; }
|
||||
/* line 76, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 75, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
@@ -7170,37 +7176,37 @@ table {
|
||||
margin-bottom: 1px;
|
||||
margin-top: 1px;
|
||||
position: relative; }
|
||||
/* line 85, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 84, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:first-child {
|
||||
border-top: none; }
|
||||
/* line 88, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 87, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:hover {
|
||||
background: rgba(255, 255, 255, 0.1); }
|
||||
/* line 93, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 92, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.s-stale .l-autoflow-item.l {
|
||||
color: rgba(204, 204, 204, 0.3) !important;
|
||||
font-style: italic; }
|
||||
/* line 94, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 93, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.s-stale .l-autoflow-item.r {
|
||||
color: rgba(204, 204, 204, 0.5) !important;
|
||||
font-style: italic; }
|
||||
/* line 97, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 96, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:not(.s-stale) .l-autoflow-item.r {
|
||||
color: #b3b3b3; }
|
||||
/* line 101, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 100, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.first-in-group {
|
||||
border-top: 1px solid rgba(204, 204, 204, 0.1); }
|
||||
/* line 104, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 103, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item {
|
||||
display: block; }
|
||||
/* line 106, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 105, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item.l {
|
||||
float: none;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: auto; }
|
||||
/* line 113, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 112, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item.r {
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
@@ -7210,11 +7216,15 @@ table {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
text-align: right; }
|
||||
/* line 124, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 123, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col:first-child {
|
||||
border-left: none;
|
||||
padding-left: 0; }
|
||||
|
||||
/* line 133, ../../../../general/res/sass/_autoflow.scss */
|
||||
.frame.child-frame.panel .autoflow .l-autoflow-header .l-filter {
|
||||
display: none; }
|
||||
|
||||
/* line 1, ../../../../general/res/sass/features/_imagery.scss */
|
||||
.l-image-main-wrapper,
|
||||
.l-image-main,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/* line 5, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
@@ -41,38 +41,38 @@ time, mark, audio, video {
|
||||
font-size: 100%;
|
||||
vertical-align: baseline; }
|
||||
|
||||
/* line 22, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
html {
|
||||
line-height: 1; }
|
||||
|
||||
/* line 24, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
ol, ul {
|
||||
list-style: none; }
|
||||
|
||||
/* line 26, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0; }
|
||||
|
||||
/* line 28, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
caption, th, td {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
vertical-align: middle; }
|
||||
|
||||
/* line 30, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
q, blockquote {
|
||||
quotes: none; }
|
||||
/* line 103, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
q:before, q:after, blockquote:before, blockquote:after {
|
||||
content: "";
|
||||
content: none; }
|
||||
|
||||
/* line 32, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
a img {
|
||||
border: none; }
|
||||
|
||||
/* line 116, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
|
||||
display: block; }
|
||||
|
||||
@@ -173,7 +173,7 @@ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu,
|
||||
/* REQUIRES /platform/commonUI/general/res/sass/_constants.scss */
|
||||
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
|
||||
/************************** MOBILE TREE MENU DIMENSIONS */
|
||||
/************************** WINDOW DIMENSIONS FOR RWD */
|
||||
/************************** DEVICE WIDTHS */
|
||||
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
|
||||
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
|
||||
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
|
||||
@@ -235,10 +235,6 @@ a.disabled {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.3); }
|
||||
|
||||
/* line 34, ../../../../general/res/sass/_effects.scss */
|
||||
.outline {
|
||||
border: 1px solid white; }
|
||||
|
||||
/* line 38, ../../../../general/res/sass/_effects.scss */
|
||||
.test-stripes {
|
||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjEuMCIgeTE9IjEuMCIgeDI9IjAuMCIgeTI9IjAuMCI+PHN0b3Agb2Zmc2V0PSIyNSUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSIyNSUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjMDAwMDAwIiBzdG9wLW9wYWNpdHk9IjAuMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
|
||||
background-size: 100%;
|
||||
@@ -248,7 +244,7 @@ a.disabled {
|
||||
background-repeat: repeat;
|
||||
background-size: 40px 40px; }
|
||||
|
||||
/* line 42, ../../../../general/res/sass/_effects.scss */
|
||||
/* line 38, ../../../../general/res/sass/_effects.scss */
|
||||
.test {
|
||||
background-color: rgba(255, 204, 0, 0.2) !important; }
|
||||
|
||||
@@ -267,7 +263,7 @@ a.disabled {
|
||||
opacity: 0.5; }
|
||||
100% {
|
||||
opacity: 1; } }
|
||||
/* line 69, ../../../../general/res/sass/_effects.scss */
|
||||
/* line 65, ../../../../general/res/sass/_effects.scss */
|
||||
.pulse {
|
||||
-moz-animation-name: pulse;
|
||||
-webkit-animation-name: pulse;
|
||||
@@ -990,7 +986,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 76, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-left .l-infobubble::before {
|
||||
right: 100%; }
|
||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 76, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-left .l-infobubble::before {
|
||||
width: 0;
|
||||
@@ -998,14 +994,14 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
border-top: 6.66667px solid transparent;
|
||||
border-bottom: 6.66667px solid transparent;
|
||||
border-right: 10px solid white; } }
|
||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 88, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-right {
|
||||
margin-right: 20px; } }
|
||||
/* line 95, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-right .l-infobubble::before {
|
||||
left: 100%; }
|
||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 95, ../../../../general/res/sass/helpers/_bubbles.scss */
|
||||
.l-infobubble-wrapper.arw-right .l-infobubble::before {
|
||||
width: 0;
|
||||
@@ -1619,7 +1615,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn.major .icon, .major.s-menu-btn .icon, .s-btn.major .t-item-icon, .major.s-menu-btn .t-item-icon {
|
||||
color: #fff; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn.major:not(.disabled):hover, .major.s-menu-btn:not(.disabled):hover {
|
||||
background: deepskyblue; }
|
||||
@@ -1649,7 +1645,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn:not(.major) .icon, .s-menu-btn:not(.major) .icon, .s-btn:not(.major) .t-item-icon, .s-menu-btn:not(.major) .t-item-icon {
|
||||
color: #eee; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn:not(.major):not(.disabled):hover, .s-menu-btn:not(.major):not(.disabled):hover {
|
||||
background: #0099cc; }
|
||||
@@ -1682,7 +1678,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn.pause-play.paused .icon, .pause-play.paused.s-menu-btn .icon, .s-btn.pause-play.paused .t-item-icon, .pause-play.paused.s-menu-btn .t-item-icon {
|
||||
color: #fff; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.s-btn.pause-play.paused:not(.disabled):hover, .pause-play.paused.s-menu-btn:not(.disabled):hover {
|
||||
background: #ffad33; }
|
||||
@@ -1713,7 +1709,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
.s-btn.show-thumbs .icon:before, .show-thumbs.s-menu-btn .icon:before, .s-btn.show-thumbs .t-item-icon:before, .show-thumbs.s-menu-btn .t-item-icon:before {
|
||||
content: "\000039"; }
|
||||
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 101, ../../../../general/res/sass/controls/_buttons.scss */
|
||||
.mini-tab {
|
||||
-moz-border-radius: 4px;
|
||||
@@ -1774,14 +1770,14 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.mini-tab.collapsed .icon, .mini-tab.collapsed .t-item-icon {
|
||||
color: #eee; } }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px) and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 800px) and (min-device-height: 1025px) and (min-device-width: 1025px) and (min-device-height: 800px), screen and (min-device-width: 1025px) and (min-device-height: 800px) and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.mini-tab.collapsed:not(.disabled):hover {
|
||||
background: #0099cc; }
|
||||
/* line 304, ../../../../general/res/sass/_mixins.scss */
|
||||
.mini-tab.collapsed:not(.disabled):hover > .icon, .mini-tab.collapsed:not(.disabled):hover > .t-item-icon {
|
||||
color: white; } }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 138, ../../../../general/res/sass/controls/_buttons.scss */
|
||||
.mini-tab.collapsed:before {
|
||||
opacity: 0; }
|
||||
@@ -1870,7 +1866,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
|
||||
.mini-tab.anchor-right.collapsed:hover:before {
|
||||
right: 2px; } }
|
||||
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 208, ../../../../general/res/sass/controls/_buttons.scss */
|
||||
.mini-tab-icon {
|
||||
color: #d6d6d6;
|
||||
@@ -2259,7 +2255,7 @@ label.checkbox.custom {
|
||||
font-size: 0.7em;
|
||||
flex: 0 0 1;
|
||||
-webkit-flex: 0 0 1; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 240, ../../../../general/res/sass/controls/_controls.scss */
|
||||
.object-header .context-available {
|
||||
-moz-transition-property: opacity;
|
||||
@@ -2602,7 +2598,7 @@ label.checkbox.custom {
|
||||
color: inherit; }
|
||||
|
||||
/******************************************************** BROWSER ELEMENTS */
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 485, ../../../../general/res/sass/controls/_controls.scss */
|
||||
::-webkit-scrollbar {
|
||||
-moz-border-radius: 2px;
|
||||
@@ -3298,7 +3294,7 @@ label.checkbox.custom {
|
||||
/* line 213, ../../../../general/res/sass/controls/_messages.scss */
|
||||
.t-message-single .message-severity-error .type-icon.message-type:before {
|
||||
content: "\21"; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 259, ../../../../general/res/sass/controls/_messages.scss */
|
||||
.t-message-single .l-message,
|
||||
.t-message-single .bottom-bar {
|
||||
@@ -3369,7 +3365,7 @@ label.checkbox.custom {
|
||||
.t-message-list .message-contents .l-message .top-bar,
|
||||
.t-message-list .message-contents .l-message .message-body {
|
||||
margin-bottom: 10px; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 304, ../../../../general/res/sass/controls/_messages.scss */
|
||||
.t-message-list .message-contents .l-message {
|
||||
margin-right: 10px; } }
|
||||
@@ -3621,7 +3617,7 @@ mct-include.l-time-controller {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 25, ../../../../general/res/sass/mobile/controls/_menus.scss */
|
||||
.super-menu {
|
||||
width: 250px;
|
||||
@@ -3885,13 +3881,12 @@ textarea {
|
||||
transition: background, 0.25s;
|
||||
text-shadow: none;
|
||||
padding: 0 5px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
line-height: 22px; }
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.select .icon, .select .t-item-icon {
|
||||
color: #eee; }
|
||||
/* line 31, ../../../../general/res/sass/forms/_selects.scss */
|
||||
/* line 30, ../../../../general/res/sass/forms/_selects.scss */
|
||||
.select select {
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
@@ -3904,10 +3899,10 @@ textarea {
|
||||
border: none !important;
|
||||
padding: 4px 25px 2px 0px;
|
||||
width: 120%; }
|
||||
/* line 40, ../../../../general/res/sass/forms/_selects.scss */
|
||||
/* line 39, ../../../../general/res/sass/forms/_selects.scss */
|
||||
.select select option {
|
||||
margin: 5px 0; }
|
||||
/* line 44, ../../../../general/res/sass/forms/_selects.scss */
|
||||
/* line 43, ../../../../general/res/sass/forms/_selects.scss */
|
||||
.select:after {
|
||||
text-shadow: none;
|
||||
content: '\76';
|
||||
@@ -4395,7 +4390,7 @@ span.req {
|
||||
/* line 138, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane .mini-tab-icon.toggle-pane {
|
||||
z-index: 5; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 138, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane .mini-tab-icon.toggle-pane {
|
||||
top: 10px;
|
||||
@@ -4551,9 +4546,10 @@ span.req {
|
||||
.pane-tree-hidden .tree-holder,
|
||||
.pane-tree-hidden .splitter-treeview,
|
||||
.pane-tree-hidden .holder-treeview-elements {
|
||||
opacity: 0; }
|
||||
opacity: 0;
|
||||
pointer-events: none; }
|
||||
|
||||
/* line 278, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 279, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-tree-showing .tree-holder,
|
||||
.pane-tree-showing .splitter-treeview {
|
||||
-moz-transition-property: opacity;
|
||||
@@ -4573,7 +4569,7 @@ span.req {
|
||||
-webkit-transition-delay: 250ms;
|
||||
transition-delay: 250ms;
|
||||
opacity: 1; }
|
||||
/* line 284, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 285, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-tree-showing .holder-treeview-elements {
|
||||
-moz-transition-property: opacity;
|
||||
-o-transition-property: opacity;
|
||||
@@ -4592,7 +4588,7 @@ span.req {
|
||||
-webkit-transition-delay: 200ms;
|
||||
transition-delay: 200ms; }
|
||||
|
||||
/* line 291, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 292, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-inspect-showing .l-object-and-inspector .l-inspect,
|
||||
.pane-inspect-showing .l-object-and-inspector .splitter-inspect {
|
||||
-moz-transition-property: opacity;
|
||||
@@ -4613,44 +4609,45 @@ span.req {
|
||||
transition-delay: 250ms;
|
||||
opacity: 1; }
|
||||
|
||||
/* line 301, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 302, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-inspect-hidden .l-object-and-inspector .t-inspect {
|
||||
z-index: 1 !important; }
|
||||
/* line 304, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 305, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-inspect-hidden .l-object-and-inspector .l-inspect,
|
||||
.pane-inspect-hidden .l-object-and-inspector .splitter-inspect {
|
||||
opacity: 0; }
|
||||
opacity: 0;
|
||||
pointer-events: none; }
|
||||
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
/* line 312, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 314, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.holder-all {
|
||||
min-width: 600px; }
|
||||
|
||||
/* line 317, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 319, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.split-layout .split-pane-component.pane.treeview.left {
|
||||
min-width: 150px;
|
||||
max-width: 35%;
|
||||
width: 25%; }
|
||||
/* line 322, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 324, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.split-layout .split-pane-component.pane.t-inspect.right {
|
||||
min-width: 200px;
|
||||
max-width: 35%;
|
||||
width: 20%;
|
||||
z-index: 3; }
|
||||
|
||||
/* line 330, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 332, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane.treeview.left .tree-holder {
|
||||
padding-right: 5px; }
|
||||
|
||||
/* line 334, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 336, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-tree-hidden .pane.right.primary-pane {
|
||||
left: 22px !important; }
|
||||
|
||||
/* line 337, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 339, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane-inspect-hidden .l-object-and-inspector .pane.left {
|
||||
right: 22px !important; }
|
||||
|
||||
/* line 339, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 341, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane:not(.resizing) {
|
||||
-moz-transition-property: width, left, right;
|
||||
-o-transition-property: width, left, right;
|
||||
@@ -4669,7 +4666,7 @@ span.req {
|
||||
-webkit-transition-delay: 0;
|
||||
transition-delay: 0; }
|
||||
|
||||
/* line 342, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
/* line 344, ../../../../general/res/sass/user-environ/_layout.scss */
|
||||
.pane.primary-pane .object-browse-bar {
|
||||
min-width: 200px; } }
|
||||
/*****************************************************************************
|
||||
@@ -4693,7 +4690,7 @@ span.req {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 26, ../../../../general/res/sass/mobile/_layout.scss */
|
||||
.browse-wrapper,
|
||||
.pane {
|
||||
@@ -4869,7 +4866,7 @@ span.req {
|
||||
-webkit-transition-delay: 0;
|
||||
transition-delay: 0;
|
||||
opacity: 1; } }
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px) {
|
||||
/* line 146, ../../../../general/res/sass/mobile/_layout.scss */
|
||||
.pane-tree-showing .pane.left.treeview {
|
||||
width: 90% !important; }
|
||||
@@ -4883,7 +4880,7 @@ span.req {
|
||||
/* line 152, ../../../../general/res/sass/mobile/_layout.scss */
|
||||
.pane-tree-showing .pane.right.items .holder-object-and-inspector {
|
||||
opacity: 0; } }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 160, ../../../../general/res/sass/mobile/_layout.scss */
|
||||
.desktop-hide {
|
||||
display: none; } }
|
||||
@@ -5198,7 +5195,7 @@ span.req {
|
||||
margin-left: 50%;
|
||||
white-space: nowrap; }
|
||||
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
|
||||
/* line 5, ../../../../general/res/sass/mobile/search/_search.scss */
|
||||
.search .search-bar .menu-icon {
|
||||
display: none; }
|
||||
@@ -5357,7 +5354,7 @@ span.req {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.overlay .bottom-bar .s-btn:not(.major) .icon, .overlay .bottom-bar .s-menu-btn:not(.major) .icon, .overlay .bottom-bar .s-btn:not(.major) .t-item-icon, .overlay .bottom-bar .s-menu-btn:not(.major) .t-item-icon {
|
||||
color: #fff; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.overlay .bottom-bar .s-btn:not(.major):not(.disabled):hover, .overlay .bottom-bar .s-menu-btn:not(.major):not(.disabled):hover {
|
||||
background: #7d7d7d; }
|
||||
@@ -5390,7 +5387,7 @@ span.req {
|
||||
min-height: 225px;
|
||||
height: 225px; }
|
||||
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 3, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
|
||||
.overlay .clk-icon.close {
|
||||
top: 20px;
|
||||
@@ -5408,7 +5405,7 @@ span.req {
|
||||
/* line 17, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
|
||||
.overlay > .holder > .contents .top-bar > .title {
|
||||
margin-right: 1.2em; } }
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
|
||||
/* line 27, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
|
||||
.overlay > .holder {
|
||||
-moz-border-radius: 0;
|
||||
@@ -5479,7 +5476,7 @@ span.req {
|
||||
.t-dialog-sm .overlay > .holder {
|
||||
height: auto;
|
||||
max-height: 100%; } }
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px) {
|
||||
/* line 77, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
|
||||
.overlay > .holder .contents .bottom-bar {
|
||||
text-align: center; } }
|
||||
@@ -5552,7 +5549,7 @@ ul.tree {
|
||||
margin-left: 5px;
|
||||
font-size: 0.75em;
|
||||
width: 10px; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 56, ../../../../general/res/sass/tree/_tree.scss */
|
||||
.tree-item .view-control:hover,
|
||||
.search-result-item .view-control:hover {
|
||||
@@ -5683,7 +5680,7 @@ ul.tree {
|
||||
.tree-item.selected .t-object-label .t-item-icon,
|
||||
.search-result-item.selected .t-object-label .t-item-icon {
|
||||
color: #fcfcfc; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 136, ../../../../general/res/sass/tree/_tree.scss */
|
||||
.tree-item:not(.selected):hover,
|
||||
.search-result-item:not(.selected):hover {
|
||||
@@ -5735,7 +5732,7 @@ ul.tree {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 27, ../../../../general/res/sass/mobile/_tree.scss */
|
||||
ul.tree ul.tree {
|
||||
margin-left: 20px; }
|
||||
@@ -5826,7 +5823,7 @@ ul.tree {
|
||||
/* line 65, ../../../../general/res/sass/user-environ/_frame.scss */
|
||||
.frame.frame-template .view-switcher {
|
||||
z-index: 10; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 71, ../../../../general/res/sass/user-environ/_frame.scss */
|
||||
.frame.frame-template .view-switcher {
|
||||
opacity: 0; }
|
||||
@@ -6328,7 +6325,7 @@ table {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/* line 31, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 29, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot {
|
||||
color: #666;
|
||||
font-size: 0.7rem;
|
||||
@@ -6336,10 +6333,10 @@ table {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/****************************** Limits and Out-of-Bounds data */ }
|
||||
/* line 38, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 36, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-axis-area {
|
||||
position: absolute; }
|
||||
/* line 41, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 38, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-axis-area.gl-plot-x {
|
||||
top: auto;
|
||||
right: 0;
|
||||
@@ -6348,14 +6345,14 @@ table {
|
||||
height: 32px;
|
||||
width: auto;
|
||||
overflow: hidden; }
|
||||
/* line 50, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 47, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-axis-area.gl-plot-y {
|
||||
top: 25px;
|
||||
right: auto;
|
||||
bottom: 37px;
|
||||
left: 0;
|
||||
width: 60px; }
|
||||
/* line 59, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 56, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-coords {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
@@ -6372,10 +6369,10 @@ table {
|
||||
bottom: auto;
|
||||
left: 70px;
|
||||
z-index: 10; }
|
||||
/* line 71, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 68, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-coords:empty {
|
||||
display: none; }
|
||||
/* line 76, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 73, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-display-area {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
position: absolute;
|
||||
@@ -6385,13 +6382,13 @@ table {
|
||||
left: 60px;
|
||||
cursor: crosshair;
|
||||
border: 1px solid rgba(102, 102, 102, 0.2); }
|
||||
/* line 89, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 86, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-label,
|
||||
.gl-plot .l-plot-label {
|
||||
color: #999999;
|
||||
position: absolute;
|
||||
text-align: center; }
|
||||
/* line 97, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 92, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-label.gl-plot-x-label, .gl-plot .gl-plot-label.l-plot-x-label,
|
||||
.gl-plot .l-plot-label.gl-plot-x-label,
|
||||
.gl-plot .l-plot-label.l-plot-x-label {
|
||||
@@ -6400,7 +6397,7 @@ table {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: auto; }
|
||||
/* line 106, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 101, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-label.gl-plot-y-label, .gl-plot .gl-plot-label.l-plot-y-label,
|
||||
.gl-plot .l-plot-label.gl-plot-y-label,
|
||||
.gl-plot .l-plot-label.l-plot-y-label {
|
||||
@@ -6417,30 +6414,38 @@ table {
|
||||
left: 0;
|
||||
top: 50%;
|
||||
white-space: nowrap; }
|
||||
/* line 120, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 115, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-x-options,
|
||||
.gl-plot .gl-plot-y-options {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
left: auto5px;
|
||||
margin-top: -16px;
|
||||
height: auto;
|
||||
min-height: 32px;
|
||||
width: 32px; }
|
||||
/* line 134, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
z-index: 2; }
|
||||
/* line 124, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-x-options {
|
||||
top: 5px; }
|
||||
/* line 128, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-y-options {
|
||||
-moz-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
min-width: 150px;
|
||||
top: 50%;
|
||||
left: 20px; }
|
||||
/* line 135, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-hash {
|
||||
position: absolute;
|
||||
border: 0 rgba(0, 0, 0, 0.2) dashed; }
|
||||
/* line 137, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 138, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-hash.hash-v {
|
||||
border-right-width: 1px;
|
||||
height: 100%; }
|
||||
/* line 141, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 142, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-hash.hash-h {
|
||||
border-bottom-width: 1px;
|
||||
width: 100%; }
|
||||
/* line 147, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 148, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .gl-plot-legend {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -6450,24 +6455,24 @@ table {
|
||||
height: 20px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto; }
|
||||
/* line 160, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 161, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-limit-bar,
|
||||
.gl-plot .l-oob-data {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: auto; }
|
||||
/* line 168, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 169, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-limit-bar {
|
||||
height: auto;
|
||||
z-index: 0; }
|
||||
/* line 176, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 177, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-limit-bar.s-limit-yellow {
|
||||
background: rgba(255, 170, 0, 0.2); }
|
||||
/* line 177, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 178, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-limit-bar.s-limit-red {
|
||||
background: rgba(255, 0, 0, 0.2); }
|
||||
/* line 180, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 181, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-oob-data {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
@@ -6480,7 +6485,7 @@ table {
|
||||
pointer-events: none;
|
||||
height: 10px;
|
||||
z-index: 1; }
|
||||
/* line 188, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 189, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-oob-data.l-oob-data-up {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
@@ -6489,7 +6494,7 @@ table {
|
||||
background-image: -moz-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
|
||||
background-image: -webkit-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
|
||||
background-image: linear-gradient(0deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
|
||||
/* line 193, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 194, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot .l-oob-data.l-oob-data-dwn {
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
@@ -6499,7 +6504,7 @@ table {
|
||||
background-image: -webkit-linear-gradient(270deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
|
||||
background-image: linear-gradient(180deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
|
||||
|
||||
/* line 203, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 204, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item,
|
||||
.gl-plot-legend .legend-item,
|
||||
.legend .plot-legend-item,
|
||||
@@ -6507,13 +6512,13 @@ table {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 3px; }
|
||||
/* line 208, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 209, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item span,
|
||||
.gl-plot-legend .legend-item span,
|
||||
.legend .plot-legend-item span,
|
||||
.legend .legend-item span {
|
||||
vertical-align: middle; }
|
||||
/* line 211, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 212, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item .plot-color-swatch,
|
||||
.gl-plot-legend .plot-legend-item .color-swatch,
|
||||
.gl-plot-legend .legend-item .plot-color-swatch,
|
||||
@@ -6529,29 +6534,29 @@ table {
|
||||
height: 8px;
|
||||
width: 8px; }
|
||||
|
||||
/* line 228, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 223, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item {
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
line-height: 1.5em;
|
||||
padding: 0px 5px; }
|
||||
/* line 234, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 227, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-legend .plot-legend-item .plot-color-swatch {
|
||||
border: 1px solid #fcfcfc;
|
||||
height: 9px;
|
||||
width: 9px; }
|
||||
|
||||
/* line 242, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 235, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.tick {
|
||||
position: absolute;
|
||||
border: 0 rgba(0, 0, 0, 0.2) solid; }
|
||||
/* line 245, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 238, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.tick.tick-x {
|
||||
border-right-width: 1px;
|
||||
height: 100%; }
|
||||
|
||||
/* line 251, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 244, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick,
|
||||
.tick-label {
|
||||
font-size: 0.7rem;
|
||||
@@ -6559,7 +6564,7 @@ table {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis; }
|
||||
/* line 259, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 251, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick.gl-plot-x-tick-label, .gl-plot-tick.tick-label-x,
|
||||
.tick-label.gl-plot-x-tick-label,
|
||||
.tick-label.tick-label-x {
|
||||
@@ -6570,7 +6575,7 @@ table {
|
||||
width: 20%;
|
||||
margin-left: -10%;
|
||||
text-align: center; }
|
||||
/* line 269, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 261, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick.gl-plot-y-tick-label, .gl-plot-tick.tick-label-y,
|
||||
.tick-label.gl-plot-y-tick-label,
|
||||
.tick-label.tick-label-y {
|
||||
@@ -6580,18 +6585,18 @@ table {
|
||||
margin-bottom: -0.5em;
|
||||
text-align: right; }
|
||||
|
||||
/* line 281, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 272, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick.gl-plot-x-tick-label {
|
||||
top: 5px; }
|
||||
/* line 284, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 275, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.gl-plot-tick.gl-plot-y-tick-label {
|
||||
right: 5px;
|
||||
left: 5px; }
|
||||
|
||||
/* line 291, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 282, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.tick-label.tick-label-x {
|
||||
top: 0; }
|
||||
/* line 294, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
/* line 285, ../../../../general/res/sass/plots/_plots-main.scss */
|
||||
.tick-label.tick-label-y {
|
||||
right: 0;
|
||||
left: 0; }
|
||||
@@ -6709,7 +6714,7 @@ table {
|
||||
/* line 297, ../../../../general/res/sass/_mixins.scss */
|
||||
.items-holder .item.grid-item .icon, .items-holder .item.grid-item .t-item-icon {
|
||||
color: #0099cc; }
|
||||
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
|
||||
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
/* line 302, ../../../../general/res/sass/_mixins.scss */
|
||||
.items-holder .item.grid-item:not(.disabled):hover {
|
||||
background: #d0d0d0; }
|
||||
@@ -6865,7 +6870,7 @@ table {
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
|
||||
.items-holder .item.grid-item {
|
||||
width: 100%; }
|
||||
@@ -6899,7 +6904,7 @@ table {
|
||||
opacity: 1;
|
||||
font-size: 1em;
|
||||
width: auto; } }
|
||||
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
|
||||
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
|
||||
.items-holder .item.grid-item {
|
||||
height: 50px; }
|
||||
@@ -6919,7 +6924,7 @@ table {
|
||||
/* line 83, ../../../../general/res/sass/mobile/_item.scss */
|
||||
.items-holder .item.grid-item .item-main .item-open {
|
||||
line-height: 50px; } }
|
||||
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
|
||||
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
|
||||
.items-holder .item.grid-item {
|
||||
height: 66px; }
|
||||
@@ -6984,16 +6989,16 @@ table {
|
||||
-webkit-transition-delay: 0;
|
||||
transition-delay: 0;
|
||||
opacity: 1; }
|
||||
/* line 40, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 38, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header {
|
||||
bottom: auto;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
min-width: 225px; }
|
||||
/* line 45, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header span {
|
||||
vertical-align: middle; }
|
||||
/* line 48, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 43, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header .t-last-update {
|
||||
overflow: hidden; }
|
||||
/* line 46, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header .s-btn.change-column-width, .autoflow .l-autoflow-header .change-column-width.s-menu-btn {
|
||||
-moz-transition-property: opacity, background-color, border-color, color;
|
||||
-o-transition-property: opacity, background-color, border-color, color;
|
||||
@@ -7012,19 +7017,20 @@ table {
|
||||
-webkit-transition-delay: 0;
|
||||
transition-delay: 0;
|
||||
opacity: 0; }
|
||||
/* line 52, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 50, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header .l-filter {
|
||||
margin-left: 5px; }
|
||||
/* line 54, ../../../../general/res/sass/_autoflow.scss */
|
||||
display: block;
|
||||
margin-right: 5px; }
|
||||
/* line 53, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-header .l-filter input.t-filter-input {
|
||||
width: 100px; }
|
||||
/* line 60, ../../../../general/res/sass/_autoflow.scss */
|
||||
width: 150px; }
|
||||
/* line 59, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items {
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
top: 32px;
|
||||
white-space: nowrap; }
|
||||
/* line 66, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 65, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
@@ -7035,7 +7041,7 @@ table {
|
||||
padding-right: 5px;
|
||||
vertical-align: top;
|
||||
width: 225px; }
|
||||
/* line 76, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 75, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
@@ -7047,37 +7053,37 @@ table {
|
||||
margin-bottom: 1px;
|
||||
margin-top: 1px;
|
||||
position: relative; }
|
||||
/* line 85, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 84, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:first-child {
|
||||
border-top: none; }
|
||||
/* line 88, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 87, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:hover {
|
||||
background: rgba(255, 255, 255, 0.1); }
|
||||
/* line 93, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 92, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.s-stale .l-autoflow-item.l {
|
||||
color: rgba(51, 51, 51, 0.3) !important;
|
||||
font-style: italic; }
|
||||
/* line 94, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 93, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.s-stale .l-autoflow-item.r {
|
||||
color: rgba(51, 51, 51, 0.5) !important;
|
||||
font-style: italic; }
|
||||
/* line 97, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 96, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:not(.s-stale) .l-autoflow-item.r {
|
||||
color: gray; }
|
||||
/* line 101, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 100, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.first-in-group {
|
||||
border-top: 1px solid rgba(153, 153, 153, 0.2); }
|
||||
/* line 104, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 103, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item {
|
||||
display: block; }
|
||||
/* line 106, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 105, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item.l {
|
||||
float: none;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: auto; }
|
||||
/* line 113, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 112, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item.r {
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
@@ -7087,11 +7093,15 @@ table {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
text-align: right; }
|
||||
/* line 124, ../../../../general/res/sass/_autoflow.scss */
|
||||
/* line 123, ../../../../general/res/sass/_autoflow.scss */
|
||||
.autoflow .l-autoflow-items .l-autoflow-col:first-child {
|
||||
border-left: none;
|
||||
padding-left: 0; }
|
||||
|
||||
/* line 133, ../../../../general/res/sass/_autoflow.scss */
|
||||
.frame.child-frame.panel .autoflow .l-autoflow-header .l-filter {
|
||||
display: none; }
|
||||
|
||||
/* line 1, ../../../../general/res/sass/features/_imagery.scss */
|
||||
.l-image-main-wrapper,
|
||||
.l-image-main,
|
||||
|
||||
@@ -72,8 +72,7 @@
|
||||
"persistenceService",
|
||||
"$q",
|
||||
"now",
|
||||
"PERSISTENCE_SPACE",
|
||||
"ADDITIONAL_PERSISTENCE_SPACES"
|
||||
"PERSISTENCE_SPACE"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -115,6 +114,12 @@
|
||||
"type": "provider",
|
||||
"implementation": "views/ViewProvider.js",
|
||||
"depends": [ "views[]", "$log" ]
|
||||
},
|
||||
{
|
||||
"provides": "identifierService",
|
||||
"type": "provider",
|
||||
"implementation": "identifiers/IdentifierProvider.js",
|
||||
"depends": [ "PERSISTENCE_SPACE" ]
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
@@ -183,7 +188,8 @@
|
||||
{
|
||||
"key": "persistence",
|
||||
"implementation": "capabilities/PersistenceCapability.js",
|
||||
"depends": [ "persistenceService", "PERSISTENCE_SPACE" ]
|
||||
"depends": [ "persistenceService", "identifierService",
|
||||
"notificationService", "$q" ]
|
||||
},
|
||||
{
|
||||
"key": "metadata",
|
||||
@@ -202,7 +208,7 @@
|
||||
{
|
||||
"key": "instantiation",
|
||||
"implementation": "capabilities/InstantiationCapability.js",
|
||||
"depends": [ "$injector" ]
|
||||
"depends": [ "$injector", "identifierService" ]
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
@@ -245,11 +251,6 @@
|
||||
{
|
||||
"key": "PERSISTENCE_SPACE",
|
||||
"value": "mct"
|
||||
},
|
||||
{
|
||||
"key": "ADDITIONAL_PERSISTENCE_SPACES",
|
||||
"value": [],
|
||||
"description": "An array of additional persistence spaces to load models from."
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
/*global define,Promise*/
|
||||
|
||||
define(
|
||||
['../objects/DomainObjectImpl', 'uuid'],
|
||||
function (DomainObjectImpl, uuid) {
|
||||
['../objects/DomainObjectImpl'],
|
||||
function (DomainObjectImpl) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@@ -33,9 +33,12 @@ define(
|
||||
* @constructor
|
||||
* @memberof platform/core
|
||||
* @param $injector Angular's `$injector`
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function InstantiationCapability($injector) {
|
||||
function InstantiationCapability($injector, identifierService, domainObject) {
|
||||
this.$injector = $injector;
|
||||
this.identifierService = identifierService;
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,19 +48,26 @@ define(
|
||||
* have been persisted, nor will it have been added to the
|
||||
* composition of the object which exposed this capability.
|
||||
*
|
||||
* @param {object} the model for the new domain object
|
||||
* @returns {DomainObject} the new domain object
|
||||
*/
|
||||
InstantiationCapability.prototype.instantiate = function (model) {
|
||||
var parsedId =
|
||||
this.identifierService.parse(this.domainObject.getId()),
|
||||
space = parsedId.getDefinedSpace(),
|
||||
id = this.identifierService.generate(space);
|
||||
|
||||
// Lazily initialize; instantiate depends on capabilityService,
|
||||
// which depends on all capabilities, including this one.
|
||||
this.instantiateFn = this.instantiateFn ||
|
||||
this.$injector.get("instantiate");
|
||||
return this.instantiateFn(model);
|
||||
|
||||
return this.instantiateFn(model, id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Alias of `create`.
|
||||
* @see {platform/core.CreationCapability#create}
|
||||
* Alias of `instantiate`.
|
||||
* @see {platform/core.CreationCapability#instantiate}
|
||||
*/
|
||||
InstantiationCapability.prototype.invoke =
|
||||
InstantiationCapability.prototype.instantiate;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
/*jslint es5: true */
|
||||
|
||||
|
||||
define(
|
||||
@@ -44,13 +45,21 @@ define(
|
||||
* @constructor
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function PersistenceCapability(persistenceService, space, domainObject) {
|
||||
function PersistenceCapability(
|
||||
persistenceService,
|
||||
identifierService,
|
||||
notificationService,
|
||||
$q,
|
||||
domainObject
|
||||
) {
|
||||
// Cache modified timestamp
|
||||
this.modified = domainObject.getModel().modified;
|
||||
|
||||
this.domainObject = domainObject;
|
||||
this.space = space;
|
||||
this.identifierService = identifierService;
|
||||
this.persistenceService = persistenceService;
|
||||
this.notificationService = notificationService;
|
||||
this.$q = $q;
|
||||
}
|
||||
|
||||
// Utility function for creating promise-like objects which
|
||||
@@ -63,6 +72,51 @@ define(
|
||||
};
|
||||
}
|
||||
|
||||
function getKey(id) {
|
||||
var parts = id.split(":");
|
||||
return parts.length > 1 ? parts.slice(1).join(":") : id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value returned is falsey, and if so returns a
|
||||
* rejected promise
|
||||
*/
|
||||
function rejectIfFalsey(value, $q){
|
||||
if (!value){
|
||||
return $q.reject("Error persisting object");
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
function formatError(error){
|
||||
if (error && error.message) {
|
||||
return error.message;
|
||||
} else if (error && typeof error === "string"){
|
||||
return error;
|
||||
} else {
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a notification message if an error has occurred during
|
||||
* persistence.
|
||||
*/
|
||||
function notifyOnError(error, domainObject, notificationService, $q){
|
||||
var errorMessage = "Unable to persist " + domainObject.getModel().name;
|
||||
if (error) {
|
||||
errorMessage += ": " + formatError(error);
|
||||
}
|
||||
|
||||
notificationService.error({
|
||||
title: "Error persisting " + domainObject.getModel().name,
|
||||
hint: errorMessage || "Unknown error"
|
||||
});
|
||||
|
||||
return $q.reject(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist any changes which have been made to this
|
||||
* domain object's model.
|
||||
@@ -71,7 +125,8 @@ define(
|
||||
* if not.
|
||||
*/
|
||||
PersistenceCapability.prototype.persist = function () {
|
||||
var domainObject = this.domainObject,
|
||||
var self = this,
|
||||
domainObject = this.domainObject,
|
||||
model = domainObject.getModel(),
|
||||
modified = model.modified,
|
||||
persistenceService = this.persistenceService,
|
||||
@@ -87,9 +142,13 @@ define(
|
||||
// ...and persist
|
||||
return persistenceFn.apply(persistenceService, [
|
||||
this.getSpace(),
|
||||
domainObject.getId(),
|
||||
getKey(domainObject.getId()),
|
||||
domainObject.getModel()
|
||||
]);
|
||||
]).then(function(result){
|
||||
return rejectIfFalsey(result, self.$q);
|
||||
}).catch(function(error){
|
||||
return notifyOnError(error, domainObject, self.notificationService, self.$q);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -130,7 +189,8 @@ define(
|
||||
* be used to persist this object
|
||||
*/
|
||||
PersistenceCapability.prototype.getSpace = function () {
|
||||
return this.space;
|
||||
var id = this.domainObject.getId();
|
||||
return this.identifierService.parse(id).getSpace();
|
||||
};
|
||||
|
||||
return PersistenceCapability;
|
||||
|
||||
86
platform/core/src/identifiers/Identifier.js
Normal file
86
platform/core/src/identifiers/Identifier.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
var SEPARATOR = ":";
|
||||
|
||||
/**
|
||||
* Provides an interface for interpreting domain object identifiers;
|
||||
* in particular, parses out persistence space/key pairs associated
|
||||
* with the domain object.
|
||||
*
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @param {string} id the domain object identifier
|
||||
* @param {string} defaultSpace the persistence space to use if
|
||||
* one is not encoded in the identifier
|
||||
*/
|
||||
function Identifier(id, defaultSpace) {
|
||||
var separatorIndex = id.indexOf(SEPARATOR);
|
||||
|
||||
if (separatorIndex > -1) {
|
||||
this.key = id.substring(separatorIndex + 1);
|
||||
this.space = id.substring(0, separatorIndex);
|
||||
this.definedSpace = this.space;
|
||||
} else {
|
||||
this.key = id;
|
||||
this.space = defaultSpace;
|
||||
this.definedSpace = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key under which the identified domain object's model
|
||||
* should be persisted, within its persistence space.
|
||||
* @returns {string} the key within its persistence space
|
||||
*/
|
||||
Identifier.prototype.getKey = function () {
|
||||
return this.key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the space in which the identified domain object's model should
|
||||
* be persisted.
|
||||
* @returns {string} the persistence space
|
||||
*/
|
||||
Identifier.prototype.getSpace = function () {
|
||||
return this.space;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the persistence space, if any, which has been explicitly
|
||||
* encoded in this domain object's identifier. Returns undefined
|
||||
* if no such space has been specified.
|
||||
* @returns {string} the persistence space, or undefined
|
||||
*/
|
||||
Identifier.prototype.getDefinedSpace = function () {
|
||||
return this.definedSpace;
|
||||
};
|
||||
|
||||
return Identifier;
|
||||
}
|
||||
);
|
||||
66
platform/core/src/identifiers/IdentifierProvider.js
Normal file
66
platform/core/src/identifiers/IdentifierProvider.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
["uuid", "./Identifier"],
|
||||
function (uuid, Identifier) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Parses and generates domain object identifiers.
|
||||
* @param {string} defaultSpace the default persistence space
|
||||
* @constructor
|
||||
* @memberof {platform/core}
|
||||
*/
|
||||
function IdentifierProvider(defaultSpace) {
|
||||
this.defaultSpace = defaultSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new domain object identifier. A persistence space
|
||||
* may optionally be included; if not specified, no space will
|
||||
* be encoded into the identifier.
|
||||
* @param {string} [space] the persistence space to encode
|
||||
* in this identifier
|
||||
* @returns {string} a new domain object identifier
|
||||
*/
|
||||
IdentifierProvider.prototype.generate = function (space) {
|
||||
var id = uuid();
|
||||
if (space !== undefined) {
|
||||
id = space + ":" + id;
|
||||
}
|
||||
return id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a domain object identifier to examine its component
|
||||
* parts (e.g. its persistence space.)
|
||||
* @returns {platform/core.Identifier} the parsed identifier
|
||||
*/
|
||||
IdentifierProvider.prototype.parse = function (id) {
|
||||
return new Identifier(id, this.defaultSpace);
|
||||
};
|
||||
|
||||
return IdentifierProvider;
|
||||
}
|
||||
);
|
||||
@@ -33,6 +33,15 @@ define(
|
||||
* A model service which reads domain object models from an external
|
||||
* persistence service.
|
||||
*
|
||||
* Identifiers will be interpreted as follows:
|
||||
* * If no colon is present, the model will be read from the default
|
||||
* persistence space.
|
||||
* * If a colon is present, everything before the first colon will be
|
||||
* taken to refer to the persistence space, and everything after
|
||||
* will be taken to be that model's key within this space. (If
|
||||
* no such space exists within the `persistenceService`, that
|
||||
* identifier will simply be ignored.)
|
||||
*
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @implements {ModelService}
|
||||
@@ -41,39 +50,26 @@ define(
|
||||
* @param $q Angular's $q service, for working with promises
|
||||
* @param {function} now a function which provides the current time
|
||||
* @param {string} space the name of the persistence space(s)
|
||||
* from which models should be retrieved.
|
||||
* @param {string} spaces additional persistence spaces to use
|
||||
* from which models should be retrieved by default
|
||||
*/
|
||||
function PersistedModelProvider(persistenceService, $q, now, space, spaces) {
|
||||
function PersistedModelProvider(persistenceService, $q, now, space) {
|
||||
this.persistenceService = persistenceService;
|
||||
this.$q = $q;
|
||||
this.spaces = [space].concat(spaces || []);
|
||||
this.now = now;
|
||||
}
|
||||
|
||||
// Take the most recently modified model, for cases where
|
||||
// multiple persistence spaces return models.
|
||||
function takeMostRecent(modelA, modelB) {
|
||||
return (!modelB || modelB.modified === undefined) ? modelA :
|
||||
(!modelA || modelA.modified === undefined) ? modelB :
|
||||
modelB.modified > modelA.modified ? modelB :
|
||||
modelA;
|
||||
this.defaultSpace = space;
|
||||
}
|
||||
|
||||
PersistedModelProvider.prototype.getModels = function (ids) {
|
||||
var persistenceService = this.persistenceService,
|
||||
$q = this.$q,
|
||||
spaces = this.spaces,
|
||||
space = this.space,
|
||||
now = this.now;
|
||||
now = this.now,
|
||||
defaultSpace = this.defaultSpace,
|
||||
parsedIds;
|
||||
|
||||
// Load a single object model from any persistence spaces
|
||||
function loadModel(id) {
|
||||
return $q.all(spaces.map(function (space) {
|
||||
return persistenceService.readObject(space, id);
|
||||
})).then(function (models) {
|
||||
return models.reduce(takeMostRecent);
|
||||
});
|
||||
function loadModel(parsedId) {
|
||||
return persistenceService
|
||||
.readObject(parsedId.space, parsedId.key);
|
||||
}
|
||||
|
||||
// Ensure that models read from persistence have some
|
||||
@@ -88,24 +84,43 @@ define(
|
||||
}
|
||||
|
||||
// Package the result as id->model
|
||||
function packageResult(models) {
|
||||
function packageResult(parsedIds, models) {
|
||||
var result = {};
|
||||
ids.forEach(function (id, index) {
|
||||
parsedIds.forEach(function (parsedId, index) {
|
||||
var id = parsedId.id;
|
||||
if (models[index]) {
|
||||
result[id] = addPersistedTimestamp(models[index]);
|
||||
result[id] = models[index];
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Filter out "namespaced" identifiers; these are
|
||||
// not expected to be found in database. See WTD-659.
|
||||
ids = ids.filter(function (id) {
|
||||
return id.indexOf(":") === -1;
|
||||
function loadModels(parsedIds) {
|
||||
return $q.all(parsedIds.map(loadModel))
|
||||
.then(function (models) {
|
||||
return packageResult(
|
||||
parsedIds,
|
||||
models.map(addPersistedTimestamp)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function restrictToSpaces(spaces) {
|
||||
return parsedIds.filter(function (parsedId) {
|
||||
return spaces.indexOf(parsedId.space) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
parsedIds = ids.map(function (id) {
|
||||
var parts = id.split(":");
|
||||
return (parts.length > 1) ?
|
||||
{ id: id, space: parts[0], key: parts.slice(1).join(":") } :
|
||||
{ id: id, space: defaultSpace, key: id };
|
||||
});
|
||||
|
||||
// Give a promise for all persistence lookups...
|
||||
return $q.all(ids.map(loadModel)).then(packageResult);
|
||||
return persistenceService.listSpaces()
|
||||
.then(restrictToSpaces)
|
||||
.then(loadModels);
|
||||
};
|
||||
|
||||
return PersistedModelProvider;
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
/*global define,Promise*/
|
||||
|
||||
define(
|
||||
['../objects/DomainObjectImpl', 'uuid'],
|
||||
function (DomainObjectImpl, uuid) {
|
||||
['../objects/DomainObjectImpl'],
|
||||
function (DomainObjectImpl) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@@ -39,12 +39,15 @@ define(
|
||||
*
|
||||
* @constructor
|
||||
* @memberof platform/core
|
||||
* @param $injector Angular's `$injector`
|
||||
* @param {CapabilityService} capabilityService the service which will
|
||||
* provide instantiated domain objects with their capabilities
|
||||
* @param {IdentifierService} identifierService service to generate
|
||||
* new identifiers
|
||||
*/
|
||||
function Instantiate(capabilityService) {
|
||||
function Instantiate(capabilityService, identifierService) {
|
||||
return function (model, id) {
|
||||
var capabilities = capabilityService.getCapabilities(model);
|
||||
id = id || uuid();
|
||||
id = id || identifierService.generate();
|
||||
return new DomainObjectImpl(id, model, capabilities);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,19 +28,40 @@ define(
|
||||
|
||||
describe("The 'instantiation' capability", function () {
|
||||
var mockInjector,
|
||||
mockIdentifierService,
|
||||
mockInstantiate,
|
||||
mockIdentifier,
|
||||
mockDomainObject,
|
||||
instantiation;
|
||||
|
||||
beforeEach(function () {
|
||||
mockInjector = jasmine.createSpyObj("$injector", ["get"]);
|
||||
mockInstantiate = jasmine.createSpy("instantiate");
|
||||
mockIdentifierService = jasmine.createSpyObj(
|
||||
'identifierService',
|
||||
[ 'parse', 'generate' ]
|
||||
);
|
||||
mockIdentifier = jasmine.createSpyObj(
|
||||
'identifier',
|
||||
[ 'getSpace', 'getKey', 'getDefinedSpace' ]
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
'domainObject',
|
||||
[ 'getId', 'getCapability', 'getModel' ]
|
||||
);
|
||||
|
||||
mockInjector.get.andCallFake(function (key) {
|
||||
return key === 'instantiate' ?
|
||||
mockInstantiate : undefined;
|
||||
});
|
||||
mockIdentifierService.parse.andReturn(mockIdentifier);
|
||||
mockIdentifierService.generate.andReturn("some-id");
|
||||
|
||||
instantiation = new InstantiationCapability(mockInjector);
|
||||
instantiation = new InstantiationCapability(
|
||||
mockInjector,
|
||||
mockIdentifierService,
|
||||
mockDomainObject
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -59,7 +80,8 @@ define(
|
||||
mockInstantiate.andReturn(mockDomainObject);
|
||||
expect(instantiation.instantiate(testModel))
|
||||
.toBe(mockDomainObject);
|
||||
expect(mockInstantiate).toHaveBeenCalledWith(testModel);
|
||||
expect(mockInstantiate)
|
||||
.toHaveBeenCalledWith(testModel, jasmine.any(String));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
/*jslint es5: true */
|
||||
|
||||
/**
|
||||
* PersistenceCapabilitySpec. Created by vwoeltje on 11/6/14.
|
||||
@@ -31,25 +32,56 @@ define(
|
||||
|
||||
describe("The persistence capability", function () {
|
||||
var mockPersistenceService,
|
||||
mockIdentifierService,
|
||||
mockDomainObject,
|
||||
mockIdentifier,
|
||||
mockNofificationService,
|
||||
mockQ,
|
||||
id = "object id",
|
||||
model = { someKey: "some value"},
|
||||
model,
|
||||
SPACE = "some space",
|
||||
persistence;
|
||||
persistence,
|
||||
happyPromise;
|
||||
|
||||
function asPromise(value) {
|
||||
function asPromise(value, doCatch) {
|
||||
return (value || {}).then ? value : {
|
||||
then: function (callback) {
|
||||
return asPromise(callback(value));
|
||||
},
|
||||
catch: function(callback) {
|
||||
//Define a default 'happy' catch, that skips over the
|
||||
// catch callback
|
||||
return doCatch ? asPromise(callback(value)): asPromise(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
happyPromise = asPromise(true);
|
||||
model = { someKey: "some value", name: "domain object"};
|
||||
|
||||
mockPersistenceService = jasmine.createSpyObj(
|
||||
"persistenceService",
|
||||
[ "updateObject", "readObject", "createObject", "deleteObject" ]
|
||||
);
|
||||
|
||||
mockIdentifierService = jasmine.createSpyObj(
|
||||
'identifierService',
|
||||
[ 'parse', 'generate' ]
|
||||
);
|
||||
mockIdentifier = jasmine.createSpyObj(
|
||||
'identifier',
|
||||
[ 'getSpace', 'getKey', 'getDefinedSpace' ]
|
||||
);
|
||||
mockQ = jasmine.createSpyObj(
|
||||
"$q",
|
||||
["reject"]
|
||||
);
|
||||
mockNofificationService = jasmine.createSpyObj(
|
||||
"notificationService",
|
||||
["error"]
|
||||
);
|
||||
|
||||
mockDomainObject = {
|
||||
getId: function () { return id; },
|
||||
getModel: function () { return model; },
|
||||
@@ -61,69 +93,104 @@ define(
|
||||
model = mutator(model) || model;
|
||||
}
|
||||
});
|
||||
mockIdentifierService.parse.andReturn(mockIdentifier);
|
||||
mockIdentifier.getSpace.andReturn(SPACE);
|
||||
persistence = new PersistenceCapability(
|
||||
mockPersistenceService,
|
||||
SPACE,
|
||||
mockIdentifierService,
|
||||
mockNofificationService,
|
||||
mockQ,
|
||||
mockDomainObject
|
||||
);
|
||||
});
|
||||
|
||||
it("creates unpersisted objects with the persistence service", function () {
|
||||
// Verify precondition; no call made during constructor
|
||||
expect(mockPersistenceService.createObject).not.toHaveBeenCalled();
|
||||
describe("successful persistence", function() {
|
||||
beforeEach(function () {
|
||||
mockPersistenceService.updateObject.andReturn(happyPromise);
|
||||
mockPersistenceService.createObject.andReturn(happyPromise);
|
||||
});
|
||||
it("creates unpersisted objects with the persistence service", function () {
|
||||
// Verify precondition; no call made during constructor
|
||||
expect(mockPersistenceService.createObject).not.toHaveBeenCalled();
|
||||
|
||||
persistence.persist();
|
||||
persistence.persist();
|
||||
|
||||
expect(mockPersistenceService.createObject).toHaveBeenCalledWith(
|
||||
SPACE,
|
||||
id,
|
||||
model
|
||||
);
|
||||
expect(mockPersistenceService.createObject).toHaveBeenCalledWith(
|
||||
SPACE,
|
||||
id,
|
||||
model
|
||||
);
|
||||
});
|
||||
|
||||
it("updates previously persisted objects with the persistence service", function () {
|
||||
// Verify precondition; no call made during constructor
|
||||
expect(mockPersistenceService.updateObject).not.toHaveBeenCalled();
|
||||
|
||||
model.persisted = 12321;
|
||||
persistence.persist();
|
||||
|
||||
expect(mockPersistenceService.updateObject).toHaveBeenCalledWith(
|
||||
SPACE,
|
||||
id,
|
||||
model
|
||||
);
|
||||
});
|
||||
|
||||
it("reports which persistence space an object belongs to", function () {
|
||||
expect(persistence.getSpace()).toEqual(SPACE);
|
||||
});
|
||||
|
||||
it("updates persisted timestamp on persistence", function () {
|
||||
model.modified = 12321;
|
||||
persistence.persist();
|
||||
expect(model.persisted).toEqual(12321);
|
||||
});
|
||||
it("refreshes the domain object model from persistence", function () {
|
||||
var refreshModel = {someOtherKey: "some other value"};
|
||||
mockPersistenceService.readObject.andReturn(asPromise(refreshModel));
|
||||
persistence.refresh();
|
||||
expect(model).toEqual(refreshModel);
|
||||
});
|
||||
|
||||
it("does not overwrite unpersisted changes on refresh", function () {
|
||||
var refreshModel = {someOtherKey: "some other value"},
|
||||
mockCallback = jasmine.createSpy();
|
||||
model.modified = 2;
|
||||
model.persisted = 1;
|
||||
mockPersistenceService.readObject.andReturn(asPromise(refreshModel));
|
||||
persistence.refresh().then(mockCallback);
|
||||
expect(model).not.toEqual(refreshModel);
|
||||
// Should have also indicated that no changes were actually made
|
||||
expect(mockCallback).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it("does not trigger error notification on successful" +
|
||||
" persistence", function () {
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).not.toHaveBeenCalled();
|
||||
expect(mockNofificationService.error).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe("unsuccessful persistence", function() {
|
||||
var sadPromise = {
|
||||
then: function(callback){
|
||||
return asPromise(callback(0), true);
|
||||
}
|
||||
};
|
||||
beforeEach(function () {
|
||||
mockPersistenceService.createObject.andReturn(sadPromise);
|
||||
});
|
||||
it("rejects on falsey persistence result", function () {
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("updates previously persisted objects with the persistence service", function () {
|
||||
// Verify precondition; no call made during constructor
|
||||
expect(mockPersistenceService.updateObject).not.toHaveBeenCalled();
|
||||
|
||||
model.persisted = 12321;
|
||||
persistence.persist();
|
||||
|
||||
expect(mockPersistenceService.updateObject).toHaveBeenCalledWith(
|
||||
SPACE,
|
||||
id,
|
||||
model
|
||||
);
|
||||
it("notifies user on persistence failure", function () {
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).toHaveBeenCalled();
|
||||
expect(mockNofificationService.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("reports which persistence space an object belongs to", function () {
|
||||
expect(persistence.getSpace()).toEqual(SPACE);
|
||||
});
|
||||
|
||||
it("updates persisted timestamp on persistence", function () {
|
||||
model.modified = 12321;
|
||||
persistence.persist();
|
||||
expect(model.persisted).toEqual(12321);
|
||||
});
|
||||
|
||||
it("refreshes the domain object model from persistence", function () {
|
||||
var refreshModel = { someOtherKey: "some other value" };
|
||||
mockPersistenceService.readObject.andReturn(asPromise(refreshModel));
|
||||
persistence.refresh();
|
||||
expect(model).toEqual(refreshModel);
|
||||
});
|
||||
|
||||
it("does not overwrite unpersisted changes on refresh", function () {
|
||||
var refreshModel = { someOtherKey: "some other value" },
|
||||
mockCallback = jasmine.createSpy();
|
||||
model.modified = 2;
|
||||
model.persisted = 1;
|
||||
mockPersistenceService.readObject.andReturn(asPromise(refreshModel));
|
||||
persistence.refresh().then(mockCallback);
|
||||
expect(model).not.toEqual(refreshModel);
|
||||
// Should have also indicated that no changes were actually made
|
||||
expect(mockCallback).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
58
platform/core/test/identifiers/IdentifierProviderSpec.js
Normal file
58
platform/core/test/identifiers/IdentifierProviderSpec.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/identifiers/IdentifierProvider"],
|
||||
function (IdentifierProvider) {
|
||||
'use strict';
|
||||
|
||||
describe("IdentifierProvider", function () {
|
||||
var defaultSpace,
|
||||
provider;
|
||||
|
||||
beforeEach(function () {
|
||||
defaultSpace = "some-default-space";
|
||||
provider = new IdentifierProvider(defaultSpace);
|
||||
});
|
||||
|
||||
it("generates unique identifiers", function () {
|
||||
expect(provider.generate())
|
||||
.not.toEqual(provider.generate());
|
||||
});
|
||||
|
||||
it("allows spaces to be specified for generated identifiers", function () {
|
||||
var specificSpace = "some-specific-space",
|
||||
id = provider.generate(specificSpace);
|
||||
expect(id).toEqual(jasmine.any(String));
|
||||
expect(provider.parse(id).getDefinedSpace())
|
||||
.toEqual(specificSpace);
|
||||
});
|
||||
|
||||
it("parses identifiers using the default space", function () {
|
||||
expect(provider.parse("some-unprefixed-id").getSpace())
|
||||
.toEqual(defaultSpace);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
82
platform/core/test/identifiers/IdentifierSpec.js
Normal file
82
platform/core/test/identifiers/IdentifierSpec.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/identifiers/Identifier"],
|
||||
function (Identifier) {
|
||||
'use strict';
|
||||
|
||||
describe("A parsed domain object identifier", function () {
|
||||
var id,
|
||||
defaultSpace,
|
||||
identifier;
|
||||
|
||||
beforeEach(function () {
|
||||
defaultSpace = "someDefaultSpace";
|
||||
});
|
||||
|
||||
describe("when space is encoded", function () {
|
||||
var idSpace, idKey, spacedId;
|
||||
|
||||
beforeEach(function () {
|
||||
idSpace = "a-specific-space";
|
||||
idKey = "a-specific-key";
|
||||
id = idSpace + ":" + idKey;
|
||||
identifier = new Identifier(id, defaultSpace);
|
||||
});
|
||||
|
||||
it("provides the encoded space", function () {
|
||||
expect(identifier.getSpace()).toEqual(idSpace);
|
||||
});
|
||||
|
||||
it("provides the key within that space", function () {
|
||||
expect(identifier.getKey()).toEqual(idKey);
|
||||
});
|
||||
|
||||
it("provides the defined space", function () {
|
||||
expect(identifier.getDefinedSpace()).toEqual(idSpace);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when space is not encoded", function () {
|
||||
beforeEach(function () {
|
||||
id = "a-generic-id";
|
||||
identifier = new Identifier(id, defaultSpace);
|
||||
});
|
||||
|
||||
it("provides the default space", function () {
|
||||
expect(identifier.getSpace()).toEqual(defaultSpace);
|
||||
});
|
||||
|
||||
it("provides the id as the key", function () {
|
||||
expect(identifier.getKey()).toEqual(id);
|
||||
});
|
||||
|
||||
it("provides no defined space", function () {
|
||||
expect(identifier.getDefinedSpace()).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -33,13 +33,12 @@ define(
|
||||
var mockQ,
|
||||
mockPersistenceService,
|
||||
SPACE = "space0",
|
||||
spaces = [ "space1" ],
|
||||
modTimes,
|
||||
mockNow,
|
||||
provider;
|
||||
|
||||
function mockPromise(value) {
|
||||
return {
|
||||
return (value || {}).then ? value : {
|
||||
then: function (callback) {
|
||||
return mockPromise(callback(value));
|
||||
},
|
||||
@@ -78,13 +77,14 @@ define(
|
||||
persisted: 0
|
||||
});
|
||||
});
|
||||
mockPersistenceService.listSpaces
|
||||
.andReturn(mockPromise([SPACE]));
|
||||
|
||||
provider = new PersistedModelProvider(
|
||||
mockPersistenceService,
|
||||
mockQ,
|
||||
mockNow,
|
||||
SPACE,
|
||||
spaces
|
||||
SPACE
|
||||
);
|
||||
});
|
||||
|
||||
@@ -103,25 +103,6 @@ define(
|
||||
});
|
||||
|
||||
|
||||
it("reads object models from multiple spaces", function () {
|
||||
var models;
|
||||
|
||||
modTimes.space1 = {
|
||||
'x': 12321
|
||||
};
|
||||
|
||||
provider.getModels(["a", "x", "zz"]).then(function (m) {
|
||||
models = m;
|
||||
});
|
||||
|
||||
expect(models).toEqual({
|
||||
a: { space: SPACE, id: "a", persisted: 0 },
|
||||
x: { space: 'space1', id: "x", modified: 12321, persisted: 0 },
|
||||
zz: { space: SPACE, id: "zz", persisted: 0 }
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("ensures that persisted timestamps are present", function () {
|
||||
var mockCallback = jasmine.createSpy("callback"),
|
||||
testModels = {
|
||||
|
||||
@@ -29,18 +29,27 @@ define(
|
||||
describe("The 'instantiate' service", function () {
|
||||
|
||||
var mockCapabilityService,
|
||||
mockIdentifierService,
|
||||
mockCapabilityConstructor,
|
||||
mockCapabilityInstance,
|
||||
mockCapabilities,
|
||||
mockIdentifier,
|
||||
idCounter,
|
||||
testModel,
|
||||
instantiate,
|
||||
domainObject;
|
||||
|
||||
beforeEach(function () {
|
||||
idCounter = 0;
|
||||
|
||||
mockCapabilityService = jasmine.createSpyObj(
|
||||
'capabilityService',
|
||||
['getCapabilities']
|
||||
);
|
||||
mockIdentifierService = jasmine.createSpyObj(
|
||||
'identifierService',
|
||||
[ 'parse', 'generate' ]
|
||||
);
|
||||
mockCapabilityConstructor = jasmine.createSpy('capability');
|
||||
mockCapabilityInstance = {};
|
||||
mockCapabilityService.getCapabilities.andReturn({
|
||||
@@ -48,9 +57,17 @@ define(
|
||||
});
|
||||
mockCapabilityConstructor.andReturn(mockCapabilityInstance);
|
||||
|
||||
mockIdentifierService.generate.andCallFake(function (space) {
|
||||
return (space ? (space + ":") : "") +
|
||||
"some-id-" + (idCounter += 1);
|
||||
});
|
||||
|
||||
testModel = { someKey: "some value" };
|
||||
|
||||
instantiate = new Instantiate(mockCapabilityService);
|
||||
instantiate = new Instantiate(
|
||||
mockCapabilityService,
|
||||
mockIdentifierService
|
||||
);
|
||||
domainObject = instantiate(testModel);
|
||||
});
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
"capabilities/PersistenceCapability",
|
||||
"capabilities/RelationshipCapability",
|
||||
|
||||
"identifiers/Identifier",
|
||||
"identifiers/IdentifierProvider",
|
||||
|
||||
"models/ModelAggregator",
|
||||
"models/MissingModelDecorator",
|
||||
"models/PersistedModelProvider",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"glyph": "f",
|
||||
"category": "contextual",
|
||||
"implementation": "actions/MoveAction.js",
|
||||
"depends": ["locationService", "moveService"]
|
||||
"depends": ["policyService", "locationService", "moveService"]
|
||||
},
|
||||
{
|
||||
"key": "copy",
|
||||
@@ -20,7 +20,7 @@
|
||||
"glyph": "+",
|
||||
"category": "contextual",
|
||||
"implementation": "actions/CopyAction.js",
|
||||
"depends": ["$log", "locationService", "copyService",
|
||||
"depends": ["$log", "policyService", "locationService", "copyService",
|
||||
"dialogService", "notificationService"]
|
||||
},
|
||||
{
|
||||
@@ -30,7 +30,7 @@
|
||||
"glyph": "\u00E8",
|
||||
"category": "contextual",
|
||||
"implementation": "actions/LinkAction.js",
|
||||
"depends": ["locationService", "linkService"]
|
||||
"depends": ["policyService", "locationService", "linkService"]
|
||||
},
|
||||
{
|
||||
"key": "follow",
|
||||
@@ -39,6 +39,15 @@
|
||||
"glyph": "\u00F4",
|
||||
"category": "contextual",
|
||||
"implementation": "actions/GoToOriginalAction.js"
|
||||
},
|
||||
{
|
||||
"key": "locate",
|
||||
"name": "Set Primary Location",
|
||||
"description": "Set a domain object's primary location.",
|
||||
"glyph": "",
|
||||
"category": "contextual",
|
||||
"implementation": "actions/SetPrimaryLocationAction.js"
|
||||
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
@@ -54,7 +63,11 @@
|
||||
"depends": ["contextualize", "$q", "$log"]
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
"policies": [
|
||||
{
|
||||
"category": "action",
|
||||
"implementation": "policies/CrossSpacePolicy.js"
|
||||
}
|
||||
],
|
||||
"capabilities": [
|
||||
{
|
||||
@@ -85,8 +98,7 @@
|
||||
"name": "Copy Service",
|
||||
"description": "Provides a service for copying objects",
|
||||
"implementation": "services/CopyService.js",
|
||||
"depends": ["$q", "creationService", "policyService",
|
||||
"persistenceService", "now"]
|
||||
"depends": ["$q", "policyService", "now"]
|
||||
},
|
||||
{
|
||||
"key": "locationService",
|
||||
|
||||
@@ -62,6 +62,8 @@ define(
|
||||
* @constructor
|
||||
* @private
|
||||
* @memberof platform/entanglement
|
||||
* @param {PolicyService} policyService the policy service to use to
|
||||
* verify that variants of this action are allowed
|
||||
* @param {platform/entanglement.LocationService} locationService a
|
||||
* service to request destinations from the user
|
||||
* @param {platform/entanglement.AbstractComposeService} composeService
|
||||
@@ -71,7 +73,14 @@ define(
|
||||
* @param {string} [suffix] a string to display in the dialog title;
|
||||
* default is "to a new location"
|
||||
*/
|
||||
function AbstractComposeAction(locationService, composeService, context, verb, suffix) {
|
||||
function AbstractComposeAction(
|
||||
policyService,
|
||||
locationService,
|
||||
composeService,
|
||||
context,
|
||||
verb,
|
||||
suffix
|
||||
) {
|
||||
if (context.selectedObject) {
|
||||
this.newParent = context.domainObject;
|
||||
this.object = context.selectedObject;
|
||||
@@ -83,16 +92,27 @@ define(
|
||||
.getCapability('context')
|
||||
.getParent();
|
||||
|
||||
this.context = context;
|
||||
this.policyService = policyService;
|
||||
this.locationService = locationService;
|
||||
this.composeService = composeService;
|
||||
this.verb = verb || "Compose";
|
||||
this.suffix = suffix || "to a new location";
|
||||
}
|
||||
|
||||
AbstractComposeAction.prototype.cloneContext = function () {
|
||||
var clone = {}, original = this.context;
|
||||
Object.keys(original).forEach(function (k) {
|
||||
clone[k] = original[k];
|
||||
});
|
||||
return clone;
|
||||
};
|
||||
|
||||
AbstractComposeAction.prototype.perform = function () {
|
||||
var dialogTitle,
|
||||
label,
|
||||
validateLocation,
|
||||
self = this,
|
||||
locationService = this.locationService,
|
||||
composeService = this.composeService,
|
||||
currentParent = this.currentParent,
|
||||
@@ -109,7 +129,11 @@ define(
|
||||
label = this.verb + " To";
|
||||
|
||||
validateLocation = function (newParent) {
|
||||
return composeService.validate(object, newParent);
|
||||
var newContext = self.cloneContext();
|
||||
newContext.selectedObject = object;
|
||||
newContext.domainObject = newParent;
|
||||
return composeService.validate(object, newParent) &&
|
||||
self.policyService.allow("action", self, newContext);
|
||||
};
|
||||
|
||||
return locationService.getLocationFromUser(
|
||||
|
||||
@@ -34,18 +34,34 @@ define(
|
||||
* @constructor
|
||||
* @memberof platform/entanglement
|
||||
*/
|
||||
function CopyAction($log, locationService, copyService, dialogService,
|
||||
notificationService, context) {
|
||||
function CopyAction(
|
||||
$log,
|
||||
policyService,
|
||||
locationService,
|
||||
copyService,
|
||||
dialogService,
|
||||
notificationService,
|
||||
context
|
||||
) {
|
||||
this.dialog = undefined;
|
||||
this.notification = undefined;
|
||||
this.dialogService = dialogService;
|
||||
this.notificationService = notificationService;
|
||||
this.$log = $log;
|
||||
//Extend the behaviour of the Abstract Compose Action
|
||||
AbstractComposeAction.call(this, locationService, copyService,
|
||||
context, "Duplicate", "to a location");
|
||||
AbstractComposeAction.call(
|
||||
this,
|
||||
policyService,
|
||||
locationService,
|
||||
copyService,
|
||||
context,
|
||||
"Duplicate",
|
||||
"to a location"
|
||||
);
|
||||
}
|
||||
|
||||
CopyAction.prototype = Object.create(AbstractComposeAction.prototype);
|
||||
|
||||
/**
|
||||
* Updates user about progress of copy. Should not be invoked by
|
||||
* client code under any circumstances.
|
||||
|
||||
@@ -34,10 +34,10 @@ define(
|
||||
* @constructor
|
||||
* @memberof platform/entanglement
|
||||
*/
|
||||
function LinkAction(locationService, linkService, context) {
|
||||
function LinkAction(policyService, locationService, linkService, context) {
|
||||
AbstractComposeAction.apply(
|
||||
this,
|
||||
[locationService, linkService, context, "Link"]
|
||||
[policyService, locationService, linkService, context, "Link"]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,11 @@ define(
|
||||
* @constructor
|
||||
* @memberof platform/entanglement
|
||||
*/
|
||||
function MoveAction(locationService, moveService, context) {
|
||||
function MoveAction(policyService, locationService, moveService, context) {
|
||||
AbstractComposeAction.apply(
|
||||
this,
|
||||
[locationService, moveService, context, "Move"]
|
||||
[policyService, locationService, moveService, context, "Move"]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
MoveAction.prototype = Object.create(AbstractComposeAction.prototype);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define */
|
||||
define(
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Implements the "Set Primary Location" action, which sets a
|
||||
* location property for objects to match their contextual
|
||||
* location.
|
||||
*
|
||||
* @implements {Action}
|
||||
* @constructor
|
||||
* @private
|
||||
* @memberof platform/entanglement
|
||||
* @param {ActionContext} context the context in which the action
|
||||
* will be performed
|
||||
*/
|
||||
function SetPrimaryLocationAction(context) {
|
||||
this.domainObject = context.domainObject;
|
||||
}
|
||||
|
||||
SetPrimaryLocationAction.prototype.perform = function () {
|
||||
var location = this.domainObject.getCapability('location');
|
||||
return location.setPrimaryLocation(
|
||||
location.getContextualLocation()
|
||||
);
|
||||
};
|
||||
|
||||
SetPrimaryLocationAction.appliesTo = function (context) {
|
||||
var domainObject = context.domainObject;
|
||||
return domainObject && domainObject.hasCapability("location")
|
||||
&& (domainObject.getModel().location === undefined);
|
||||
};
|
||||
|
||||
return SetPrimaryLocationAction;
|
||||
}
|
||||
);
|
||||
|
||||
73
platform/entanglement/src/policies/CrossSpacePolicy.js
Normal file
73
platform/entanglement/src/policies/CrossSpacePolicy.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define */
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
var DISALLOWED_ACTIONS = [
|
||||
"move",
|
||||
"copy"
|
||||
];
|
||||
|
||||
/**
|
||||
* This policy prevents performing move/copy/link actions across
|
||||
* different persistence spaces (e.g. linking to an object in
|
||||
* a private space from an object in a public space.)
|
||||
* @memberof {platform/entanglement}
|
||||
* @constructor
|
||||
* @implements {Policy}
|
||||
*/
|
||||
function CrossSpacePolicy() {
|
||||
}
|
||||
|
||||
function lookupSpace(domainObject) {
|
||||
var persistence = domainObject &&
|
||||
domainObject.getCapability("persistence");
|
||||
return persistence && persistence.getSpace();
|
||||
}
|
||||
|
||||
function isCrossSpace(context) {
|
||||
var domainObject = context.domainObject,
|
||||
selectedObject = context.selectedObject,
|
||||
spaces = [ domainObject, selectedObject ].map(lookupSpace);
|
||||
return selectedObject !== undefined &&
|
||||
domainObject !== undefined &&
|
||||
lookupSpace(domainObject) !== lookupSpace(selectedObject);
|
||||
}
|
||||
|
||||
CrossSpacePolicy.prototype.allow = function (action, context) {
|
||||
var key = action.getMetadata().key;
|
||||
|
||||
if (DISALLOWED_ACTIONS.indexOf(key) !== -1) {
|
||||
return !isCrossSpace(context);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return CrossSpacePolicy;
|
||||
|
||||
}
|
||||
);
|
||||
@@ -38,12 +38,9 @@ define(
|
||||
* @memberof platform/entanglement
|
||||
* @implements {platform/entanglement.AbstractComposeService}
|
||||
*/
|
||||
function CopyService($q, creationService, policyService, persistenceService, now) {
|
||||
function CopyService($q, policyService) {
|
||||
this.$q = $q;
|
||||
this.creationService = creationService;
|
||||
this.policyService = policyService;
|
||||
this.persistenceService = persistenceService;
|
||||
this.now = now;
|
||||
}
|
||||
|
||||
CopyService.prototype.validate = function (object, parentCandidate) {
|
||||
@@ -71,7 +68,7 @@ define(
|
||||
*/
|
||||
CopyService.prototype.perform = function (domainObject, parent) {
|
||||
var $q = this.$q,
|
||||
copyTask = new CopyTask(domainObject, parent, this.persistenceService, this.$q, this.now);
|
||||
copyTask = new CopyTask(domainObject, parent, this.policyService, this.$q);
|
||||
if (this.validate(domainObject, parent)) {
|
||||
return copyTask.perform();
|
||||
} else {
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
/*global define */
|
||||
|
||||
define(
|
||||
["uuid"],
|
||||
function (uuid) {
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
@@ -33,36 +33,51 @@ define(
|
||||
*
|
||||
* @param domainObject The object to copy
|
||||
* @param parent The new location of the cloned object tree
|
||||
* @param persistenceService
|
||||
* @param $q
|
||||
* @param now
|
||||
* @constructor
|
||||
*/
|
||||
function CopyTask (domainObject, parent, persistenceService, $q, now){
|
||||
function CopyTask (domainObject, parent, policyService, $q){
|
||||
this.domainObject = domainObject;
|
||||
this.parent = parent;
|
||||
this.firstClone = undefined;
|
||||
this.$q = $q;
|
||||
this.deferred = undefined;
|
||||
this.persistenceService = persistenceService;
|
||||
this.policyService = policyService;
|
||||
this.persisted = 0;
|
||||
this.now = now;
|
||||
this.clones = [];
|
||||
this.idMap = {};
|
||||
}
|
||||
|
||||
function composeChild(child, parent) {
|
||||
function composeChild(child, parent, setLocation) {
|
||||
//Once copied, associate each cloned
|
||||
// composee with its parent clone
|
||||
child.model.location = parent.id;
|
||||
parent.model.composition = parent.model.composition || [];
|
||||
return parent.model.composition.push(child.id);
|
||||
|
||||
parent.getModel().composition.push(child.getId());
|
||||
|
||||
//If a location is not specified, set it.
|
||||
if (setLocation && child.getModel().location === undefined) {
|
||||
child.getModel().location = parent.getId();
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
function cloneObjectModel(objectModel) {
|
||||
var clone = JSON.parse(JSON.stringify(objectModel));
|
||||
|
||||
delete clone.composition;
|
||||
/**
|
||||
* Reset certain fields.
|
||||
*/
|
||||
//If has a composition, set it to an empty array. Will be
|
||||
// recomposed later with the ids of its cloned children.
|
||||
if (clone.composition) {
|
||||
//Important to set it to an empty array here, otherwise
|
||||
// hasCapability("composition") returns false;
|
||||
clone.composition = [];
|
||||
}
|
||||
delete clone.persisted;
|
||||
delete clone.modified;
|
||||
delete clone.location;
|
||||
|
||||
return clone;
|
||||
}
|
||||
@@ -73,13 +88,10 @@ define(
|
||||
* result in automatic request batching by the browser.
|
||||
*/
|
||||
function persistObjects(self) {
|
||||
|
||||
return self.$q.all(self.clones.map(function(clone){
|
||||
clone.model.persisted = self.now();
|
||||
return self.persistenceService.createObject(clone.persistenceSpace, clone.id, clone.model)
|
||||
.then(function(){
|
||||
self.deferred.notify({phase: "copying", totalObjects: self.clones.length, processed: ++self.persisted});
|
||||
});
|
||||
return clone.getCapability("persistence").persist().then(function(){
|
||||
self.deferred.notify({phase: "copying", totalObjects: self.clones.length, processed: ++self.persisted});
|
||||
});
|
||||
})).then(function(){
|
||||
return self;
|
||||
});
|
||||
@@ -89,19 +101,40 @@ define(
|
||||
* Will add a list of clones to the specified parent's composition
|
||||
*/
|
||||
function addClonesToParent(self) {
|
||||
var parentClone = self.clones[self.clones.length-1];
|
||||
return self.firstClone.getCapability("persistence").persist()
|
||||
.then(function(){self.parent.getCapability("composition").add(self.firstClone.getId());})
|
||||
.then(function(){return self.parent.getCapability("persistence").persist();})
|
||||
.then(function(){return self.firstClone;});
|
||||
}
|
||||
|
||||
if (!self.parent.hasCapability('composition')){
|
||||
return self.$q.reject();
|
||||
/**
|
||||
* Update identifiers in a cloned object model (or part of
|
||||
* a cloned object model) to reflect new identifiers after
|
||||
* copying.
|
||||
* @private
|
||||
*/
|
||||
CopyTask.prototype.rewriteIdentifiers = function (obj, idMap) {
|
||||
function lookupValue(value) {
|
||||
return (typeof value === 'string' && idMap[value]) || value;
|
||||
}
|
||||
|
||||
return self.persistenceService
|
||||
.updateObject(parentClone.persistenceSpace, parentClone.id, parentClone.model)
|
||||
.then(function(){return self.parent.getCapability("composition").add(parentClone.id);})
|
||||
.then(function(){return self.parent.getCapability("persistence").persist();})
|
||||
.then(function(){return parentClone;});
|
||||
// Ensure the clone of the original domainObject is returned
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
obj.forEach(function (value, index) {
|
||||
obj[index] = lookupValue(value);
|
||||
this.rewriteIdentifiers(obj[index], idMap);
|
||||
}, this);
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
Object.keys(obj).forEach(function (key) {
|
||||
var value = obj[key];
|
||||
obj[key] = lookupValue(value);
|
||||
if (idMap[key]) {
|
||||
delete obj[key];
|
||||
obj[idMap[key]] = value;
|
||||
}
|
||||
this.rewriteIdentifiers(value, idMap);
|
||||
}, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an array of objects composed by a parent, clone them, then
|
||||
@@ -110,18 +143,37 @@ define(
|
||||
* @returns {*}
|
||||
*/
|
||||
CopyTask.prototype.copyComposees = function(composees, clonedParent, originalParent){
|
||||
var self = this;
|
||||
var self = this,
|
||||
idMap = {};
|
||||
|
||||
return (composees || []).reduce(function(promise, composee){
|
||||
return (composees || []).reduce(function(promise, originalComposee){
|
||||
//If the composee is composed of other
|
||||
// objects, chain a promise..
|
||||
return promise.then(function(){
|
||||
// ...to recursively copy it (and its children)
|
||||
return self.copy(composee, originalParent).then(function(composee){
|
||||
composeChild(composee, clonedParent);
|
||||
return self.copy(originalComposee, originalParent).then(function(clonedComposee){
|
||||
//Map the original composee's ID to that of its
|
||||
// clone so that we can replace any references to it
|
||||
// in the parent
|
||||
idMap[originalComposee.getId()] = clonedComposee.getId();
|
||||
|
||||
//Compose the child within its parent. Cloned
|
||||
// objects will need to also have their location
|
||||
// set, however linked objects will not.
|
||||
return composeChild(clonedComposee, clonedParent, clonedComposee !== originalComposee);
|
||||
});
|
||||
});}, self.$q.when(undefined)
|
||||
);
|
||||
).then(function(){
|
||||
//Replace any references in the cloned parent to
|
||||
// contained objects that have been composed with the
|
||||
// Ids of the clones
|
||||
self.rewriteIdentifiers(clonedParent.getModel(), idMap);
|
||||
|
||||
//Add the clone to the list of clones that will
|
||||
//be returned by this function
|
||||
self.clones.push(clonedParent);
|
||||
return clonedParent;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -131,29 +183,38 @@ define(
|
||||
* cloning objects, and composing them with their child clones
|
||||
* as it goes
|
||||
* @private
|
||||
* @param originalObject
|
||||
* @param originalParent
|
||||
* @returns {*}
|
||||
* @returns {DomainObject} If the type of the original object allows for
|
||||
* duplication, then a duplicate of the object, otherwise the object
|
||||
* itself (to allow linking to non duplicatable objects).
|
||||
*/
|
||||
CopyTask.prototype.copy = function(originalObject, originalParent) {
|
||||
CopyTask.prototype.copy = function(originalObject) {
|
||||
var self = this,
|
||||
modelClone = {
|
||||
id: uuid(),
|
||||
model: cloneObjectModel(originalObject.getModel()),
|
||||
persistenceSpace: originalParent.hasCapability('persistence') && originalParent.getCapability('persistence').getSpace()
|
||||
};
|
||||
clone;
|
||||
|
||||
return this.$q.when(originalObject.useCapability('composition')).then(function(composees){
|
||||
self.deferred.notify({phase: "preparing"});
|
||||
//Duplicate the object's children, and their children, and
|
||||
// so on down to the leaf nodes of the tree.
|
||||
return self.copyComposees(composees, modelClone, originalObject).then(function (){
|
||||
//Add the clone to the list of clones that will
|
||||
//be returned by this function
|
||||
self.clones.push(modelClone);
|
||||
return modelClone;
|
||||
//Check if the type of the object being copied allows for
|
||||
// creation of new instances. If it does not, then a link to the
|
||||
// original will be created instead.
|
||||
if (this.policyService.allow("creation", originalObject.getCapability("type"))){
|
||||
//create a new clone of the original object. Use the
|
||||
// creation capability of the targetParent to create the
|
||||
// new clone. This will ensure that the correct persistence
|
||||
// space is used.
|
||||
clone = this.parent.useCapability("instantiation", cloneObjectModel(originalObject.getModel()));
|
||||
|
||||
//Iterate through child tree
|
||||
return this.$q.when(originalObject.useCapability('composition')).then(function(composees){
|
||||
self.deferred.notify({phase: "preparing"});
|
||||
//Duplicate the object's children, and their children, and
|
||||
// so on down to the leaf nodes of the tree.
|
||||
//If it is a link, don't both with children
|
||||
return self.copyComposees(composees, clone, originalObject);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
//Creating a link, no need to iterate children
|
||||
return self.$q.when(originalObject);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -172,7 +233,10 @@ define(
|
||||
var self = this;
|
||||
|
||||
return this.copy(self.domainObject, self.parent).then(function(domainObjectClone){
|
||||
domainObjectClone.model.location = self.parent.getId();
|
||||
if (domainObjectClone !== self.domainObject) {
|
||||
domainObjectClone.getModel().location = self.parent.getId();
|
||||
}
|
||||
self.firstClone = domainObjectClone;
|
||||
return self;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -34,6 +34,7 @@ define(
|
||||
describe("Move/copy/link Actions", function () {
|
||||
|
||||
var action,
|
||||
policyService,
|
||||
locationService,
|
||||
locationServicePromise,
|
||||
composeService,
|
||||
@@ -44,6 +45,11 @@ define(
|
||||
newParent;
|
||||
|
||||
beforeEach(function () {
|
||||
policyService = jasmine.createSpyObj(
|
||||
'policyService',
|
||||
[ 'allow' ]
|
||||
);
|
||||
|
||||
selectedObjectContextCapability = jasmine.createSpyObj(
|
||||
'selectedObjectContextCapability',
|
||||
[
|
||||
@@ -87,6 +93,8 @@ define(
|
||||
]
|
||||
);
|
||||
|
||||
policyService.allow.andReturn(true);
|
||||
|
||||
locationService
|
||||
.getLocationFromUser
|
||||
.andReturn(locationServicePromise);
|
||||
@@ -124,6 +132,7 @@ define(
|
||||
};
|
||||
|
||||
action = new AbstractComposeAction(
|
||||
policyService,
|
||||
locationService,
|
||||
composeService,
|
||||
context,
|
||||
@@ -164,6 +173,30 @@ define(
|
||||
expect(composeService.perform)
|
||||
.toHaveBeenCalledWith(selectedObject, newParent);
|
||||
});
|
||||
|
||||
describe("provides a validator which", function () {
|
||||
var validator;
|
||||
|
||||
beforeEach(function () {
|
||||
validator = locationService.getLocationFromUser
|
||||
.mostRecentCall.args[2];
|
||||
composeService.validate.andReturn(true);
|
||||
policyService.allow.andReturn(true);
|
||||
});
|
||||
|
||||
it("is sensitive to policy", function () {
|
||||
expect(validator()).toBe(true);
|
||||
policyService.allow.andReturn(false);
|
||||
expect(validator()).toBe(false);
|
||||
});
|
||||
|
||||
it("is sensitive to service-specific validation", function () {
|
||||
expect(validator()).toBe(true);
|
||||
composeService.validate.andReturn(false);
|
||||
expect(validator()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -175,6 +208,7 @@ define(
|
||||
};
|
||||
|
||||
action = new AbstractComposeAction(
|
||||
policyService,
|
||||
locationService,
|
||||
composeService,
|
||||
context,
|
||||
|
||||
@@ -34,6 +34,7 @@ define(
|
||||
describe("Copy Action", function () {
|
||||
|
||||
var copyAction,
|
||||
policyService,
|
||||
locationService,
|
||||
locationServicePromise,
|
||||
copyService,
|
||||
@@ -50,6 +51,12 @@ define(
|
||||
progress = {phase: "copying", totalObjects: 10, processed: 1};
|
||||
|
||||
beforeEach(function () {
|
||||
policyService = jasmine.createSpyObj(
|
||||
'policyService',
|
||||
[ 'allow' ]
|
||||
);
|
||||
policyService.allow.andReturn(true);
|
||||
|
||||
selectedObjectContextCapability = jasmine.createSpyObj(
|
||||
'selectedObjectContextCapability',
|
||||
[
|
||||
@@ -142,6 +149,7 @@ define(
|
||||
|
||||
copyAction = new CopyAction(
|
||||
mockLog,
|
||||
policyService,
|
||||
locationService,
|
||||
copyService,
|
||||
dialogService,
|
||||
@@ -201,6 +209,7 @@ define(
|
||||
|
||||
copyAction = new CopyAction(
|
||||
mockLog,
|
||||
policyService,
|
||||
locationService,
|
||||
copyService,
|
||||
dialogService,
|
||||
|
||||
@@ -34,6 +34,7 @@ define(
|
||||
describe("Link Action", function () {
|
||||
|
||||
var linkAction,
|
||||
policyService,
|
||||
locationService,
|
||||
locationServicePromise,
|
||||
linkService,
|
||||
@@ -44,6 +45,12 @@ define(
|
||||
newParent;
|
||||
|
||||
beforeEach(function () {
|
||||
policyService = jasmine.createSpyObj(
|
||||
'policyService',
|
||||
[ 'allow' ]
|
||||
);
|
||||
policyService.allow.andReturn(true);
|
||||
|
||||
selectedObjectContextCapability = jasmine.createSpyObj(
|
||||
'selectedObjectContextCapability',
|
||||
[
|
||||
@@ -102,6 +109,7 @@ define(
|
||||
};
|
||||
|
||||
linkAction = new LinkAction(
|
||||
policyService,
|
||||
locationService,
|
||||
linkService,
|
||||
context
|
||||
@@ -152,6 +160,7 @@ define(
|
||||
};
|
||||
|
||||
linkAction = new LinkAction(
|
||||
policyService,
|
||||
locationService,
|
||||
linkService,
|
||||
context
|
||||
|
||||
@@ -34,6 +34,7 @@ define(
|
||||
describe("Move Action", function () {
|
||||
|
||||
var moveAction,
|
||||
policyService,
|
||||
locationService,
|
||||
locationServicePromise,
|
||||
moveService,
|
||||
@@ -44,6 +45,12 @@ define(
|
||||
newParent;
|
||||
|
||||
beforeEach(function () {
|
||||
policyService = jasmine.createSpyObj(
|
||||
'policyService',
|
||||
[ 'allow' ]
|
||||
);
|
||||
policyService.allow.andReturn(true);
|
||||
|
||||
selectedObjectContextCapability = jasmine.createSpyObj(
|
||||
'selectedObjectContextCapability',
|
||||
[
|
||||
@@ -102,6 +109,7 @@ define(
|
||||
};
|
||||
|
||||
moveAction = new MoveAction(
|
||||
policyService,
|
||||
locationService,
|
||||
moveService,
|
||||
context
|
||||
@@ -152,6 +160,7 @@ define(
|
||||
};
|
||||
|
||||
moveAction = new MoveAction(
|
||||
policyService,
|
||||
locationService,
|
||||
moveService,
|
||||
context
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define,describe,beforeEach,it,jasmine,expect */
|
||||
|
||||
define(
|
||||
[
|
||||
'../../src/actions/SetPrimaryLocationAction',
|
||||
'../DomainObjectFactory'
|
||||
],
|
||||
function (SetPrimaryLocation, domainObjectFactory) {
|
||||
'use strict';
|
||||
|
||||
describe("The 'set primary location' action", function () {
|
||||
var testContext,
|
||||
testModel,
|
||||
testId,
|
||||
mockLocationCapability,
|
||||
mockContextCapability;
|
||||
|
||||
beforeEach(function () {
|
||||
testId = "some-id";
|
||||
testModel = { name: "some name" };
|
||||
|
||||
mockLocationCapability = jasmine.createSpyObj(
|
||||
'location',
|
||||
[ 'setPrimaryLocation', 'getContextualLocation' ]
|
||||
);
|
||||
|
||||
mockLocationCapability.getContextualLocation.andReturn(testId);
|
||||
|
||||
testContext = {
|
||||
domainObject: domainObjectFactory({
|
||||
capabilities: {
|
||||
location: mockLocationCapability
|
||||
},
|
||||
model: testModel
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
it("is applicable to objects with no location specified", function () {
|
||||
expect(SetPrimaryLocation.appliesTo(testContext))
|
||||
.toBe(true);
|
||||
testContext.domainObject.getModel.andReturn({
|
||||
location: "something",
|
||||
name: "some name"
|
||||
});
|
||||
expect(SetPrimaryLocation.appliesTo(testContext))
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
it("sets the location contextually when performed", function () {
|
||||
new SetPrimaryLocation(testContext).perform();
|
||||
expect(mockLocationCapability.setPrimaryLocation)
|
||||
.toHaveBeenCalledWith(testId);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
120
platform/entanglement/test/policies/CrossSpacePolicySpec.js
Normal file
120
platform/entanglement/test/policies/CrossSpacePolicySpec.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
|
||||
define(
|
||||
[
|
||||
'../../src/policies/CrossSpacePolicy',
|
||||
'../DomainObjectFactory'
|
||||
],
|
||||
function (CrossSpacePolicy, domainObjectFactory) {
|
||||
"use strict";
|
||||
|
||||
describe("CrossSpacePolicy", function () {
|
||||
var mockAction,
|
||||
testActionMetadata,
|
||||
sameSpaceContext,
|
||||
crossSpaceContext,
|
||||
policy;
|
||||
|
||||
function makeObject(space) {
|
||||
var mockPersistence = jasmine.createSpyObj(
|
||||
'persistence',
|
||||
['getSpace']
|
||||
);
|
||||
mockPersistence.getSpace.andReturn(space);
|
||||
return domainObjectFactory({
|
||||
id: space + ":foo",
|
||||
model: {},
|
||||
capabilities: { persistence: mockPersistence }
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
testActionMetadata = {};
|
||||
|
||||
// Policy should only call passive methods, so
|
||||
// only define those in mocks.
|
||||
mockAction = jasmine.createSpyObj(
|
||||
'action',
|
||||
[ 'getMetadata' ]
|
||||
);
|
||||
mockAction.getMetadata.andReturn(testActionMetadata);
|
||||
|
||||
sameSpaceContext = {
|
||||
domainObject: makeObject('a'),
|
||||
selectedObject: makeObject('a')
|
||||
};
|
||||
crossSpaceContext = {
|
||||
domainObject: makeObject('a'),
|
||||
selectedObject: makeObject('b')
|
||||
};
|
||||
|
||||
policy = new CrossSpacePolicy();
|
||||
});
|
||||
|
||||
['move', 'copy'].forEach(function (key) {
|
||||
describe("for " + key + " actions", function () {
|
||||
beforeEach(function () {
|
||||
testActionMetadata.key = key;
|
||||
});
|
||||
|
||||
it("allows same-space changes", function () {
|
||||
expect(policy.allow(mockAction, sameSpaceContext))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("disallows cross-space changes", function () {
|
||||
expect(policy.allow(mockAction, crossSpaceContext))
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
it("allows actions with no selectedObject", function () {
|
||||
expect(policy.allow(mockAction, {
|
||||
domainObject: makeObject('a')
|
||||
})).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("for other actions", function () {
|
||||
beforeEach(function () {
|
||||
testActionMetadata.key = "some-other-action";
|
||||
});
|
||||
|
||||
it("allows same-space and cross-space changes", function () {
|
||||
expect(policy.allow(mockAction, crossSpaceContext))
|
||||
.toBe(true);
|
||||
expect(policy.allow(mockAction, sameSpaceContext))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("allows actions with no selectedObject", function () {
|
||||
expect(policy.allow(mockAction, {
|
||||
domainObject: makeObject('a')
|
||||
})).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -63,7 +63,6 @@ define(
|
||||
|
||||
beforeEach(function () {
|
||||
copyService = new CopyService(
|
||||
null,
|
||||
null,
|
||||
policyService
|
||||
);
|
||||
@@ -130,47 +129,50 @@ define(
|
||||
creationService,
|
||||
createObjectPromise,
|
||||
copyService,
|
||||
mockPersistenceService,
|
||||
mockNow,
|
||||
object,
|
||||
newParent,
|
||||
copyResult,
|
||||
copyFinished,
|
||||
persistObjectPromise,
|
||||
parentPersistenceCapability,
|
||||
persistenceCapability,
|
||||
instantiationCapability,
|
||||
compositionCapability,
|
||||
locationCapability,
|
||||
resolvedValue;
|
||||
|
||||
beforeEach(function () {
|
||||
creationService = jasmine.createSpyObj(
|
||||
'creationService',
|
||||
['createObject']
|
||||
);
|
||||
createObjectPromise = synchronousPromise(undefined);
|
||||
creationService.createObject.andReturn(createObjectPromise);
|
||||
policyService.allow.andReturn(true);
|
||||
|
||||
mockPersistenceService = jasmine.createSpyObj(
|
||||
'persistenceService',
|
||||
['createObject', 'updateObject']
|
||||
);
|
||||
|
||||
persistObjectPromise = synchronousPromise(undefined);
|
||||
mockPersistenceService.createObject.andReturn(persistObjectPromise);
|
||||
mockPersistenceService.updateObject.andReturn(persistObjectPromise);
|
||||
|
||||
parentPersistenceCapability = jasmine.createSpyObj(
|
||||
"persistence",
|
||||
|
||||
instantiationCapability = jasmine.createSpyObj(
|
||||
"instantiation",
|
||||
[ "invoke" ]
|
||||
);
|
||||
|
||||
persistenceCapability = jasmine.createSpyObj(
|
||||
"persistenceCapability",
|
||||
[ "persist", "getSpace" ]
|
||||
);
|
||||
persistenceCapability.persist.andReturn(persistObjectPromise);
|
||||
|
||||
parentPersistenceCapability.persist.andReturn(persistObjectPromise);
|
||||
parentPersistenceCapability.getSpace.andReturn("testSpace");
|
||||
compositionCapability = jasmine.createSpyObj(
|
||||
'compositionCapability',
|
||||
['invoke', 'add']
|
||||
);
|
||||
|
||||
mockNow = jasmine.createSpyObj("mockNow", ["now"]);
|
||||
mockNow.now.andCallFake(function(){
|
||||
return 1234;
|
||||
});
|
||||
locationCapability = jasmine.createSpyObj(
|
||||
'locationCapability',
|
||||
['isLink']
|
||||
);
|
||||
locationCapability.isLink.andReturn(false);
|
||||
|
||||
mockDeferred = jasmine.createSpyObj('mockDeferred', ['notify', 'resolve']);
|
||||
mockDeferred = jasmine.createSpyObj(
|
||||
'mockDeferred',
|
||||
['notify', 'resolve', 'reject']
|
||||
);
|
||||
mockDeferred.notify.andCallFake(function(notification){});
|
||||
mockDeferred.resolve.andCallFake(function(value){resolvedValue = value;});
|
||||
mockDeferred.promise = {
|
||||
@@ -179,7 +181,11 @@ define(
|
||||
}
|
||||
};
|
||||
|
||||
mockQ = jasmine.createSpyObj('mockQ', ['when', 'all', 'reject', 'defer']);
|
||||
mockQ = jasmine.createSpyObj(
|
||||
'mockQ',
|
||||
['when', 'all', 'reject', 'defer']
|
||||
);
|
||||
mockQ.reject.andReturn(synchronousPromise(undefined));
|
||||
mockQ.when.andCallFake(synchronousPromise);
|
||||
mockQ.all.andCallFake(function (promises) {
|
||||
var result = {};
|
||||
@@ -194,6 +200,8 @@ define(
|
||||
|
||||
describe("on domain object without composition", function () {
|
||||
beforeEach(function () {
|
||||
var objectCopy;
|
||||
|
||||
newParent = domainObjectFactory({
|
||||
name: 'newParent',
|
||||
id: '456',
|
||||
@@ -201,7 +209,9 @@ define(
|
||||
composition: []
|
||||
},
|
||||
capabilities: {
|
||||
persistence: parentPersistenceCapability
|
||||
instantiation: instantiationCapability,
|
||||
persistence: persistenceCapability,
|
||||
composition: compositionCapability
|
||||
}
|
||||
});
|
||||
|
||||
@@ -210,31 +220,46 @@ define(
|
||||
id: 'abc',
|
||||
model: {
|
||||
name: 'some object',
|
||||
location: newParent.id,
|
||||
persisted: mockNow.now()
|
||||
location: '456',
|
||||
someOtherAttribute: 'some other value',
|
||||
embeddedObjectAttribute: {
|
||||
name: 'Some embedded object'
|
||||
}
|
||||
},
|
||||
capabilities: {
|
||||
persistence: persistenceCapability
|
||||
}
|
||||
});
|
||||
|
||||
copyService = new CopyService(mockQ, creationService, policyService, mockPersistenceService, mockNow.now);
|
||||
|
||||
objectCopy = domainObjectFactory({
|
||||
name: 'object',
|
||||
id: 'abc.copy.fdgdfgdf',
|
||||
capabilities: {
|
||||
persistence: persistenceCapability,
|
||||
location: locationCapability
|
||||
}
|
||||
});
|
||||
|
||||
instantiationCapability.invoke.andCallFake(
|
||||
function(model){
|
||||
objectCopy.model = model;
|
||||
return objectCopy;
|
||||
}
|
||||
);
|
||||
|
||||
copyService = new CopyService(mockQ, policyService);
|
||||
copyResult = copyService.perform(object, newParent);
|
||||
copyFinished = jasmine.createSpy('copyFinished');
|
||||
copyResult.then(copyFinished);
|
||||
});
|
||||
|
||||
it("uses persistence service", function () {
|
||||
expect(mockPersistenceService.createObject)
|
||||
.toHaveBeenCalledWith(parentPersistenceCapability.getSpace(), jasmine.any(String), object.getModel());
|
||||
|
||||
expect(persistObjectPromise.then)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
it("uses persistence capability", function () {
|
||||
expect(persistenceCapability.persist)
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("deep clones object model", function () {
|
||||
//var newModel = creationService
|
||||
var newModel = mockPersistenceService
|
||||
.createObject
|
||||
.mostRecentCall
|
||||
.args[2];
|
||||
var newModel = copyFinished.calls[0].args[0].getModel();
|
||||
expect(newModel).toEqual(object.model);
|
||||
expect(newModel).not.toBe(object.model);
|
||||
});
|
||||
@@ -249,27 +274,57 @@ define(
|
||||
describe("on domainObject with composition", function () {
|
||||
var newObject,
|
||||
childObject,
|
||||
compositionCapability,
|
||||
locationCapability,
|
||||
objectClone,
|
||||
childObjectClone,
|
||||
compositionPromise;
|
||||
|
||||
beforeEach(function () {
|
||||
var invocationCount = 0,
|
||||
objectClones;
|
||||
|
||||
instantiationCapability.invoke.andCallFake(
|
||||
function(model){
|
||||
var cloneToReturn = objectClones[invocationCount++];
|
||||
cloneToReturn.model = model;
|
||||
return cloneToReturn;
|
||||
}
|
||||
);
|
||||
|
||||
locationCapability = jasmine.createSpyObj('locationCapability', ['isLink']);
|
||||
locationCapability.isLink.andReturn(true);
|
||||
newParent = domainObjectFactory({
|
||||
name: 'newParent',
|
||||
id: '456',
|
||||
model: {
|
||||
composition: []
|
||||
},
|
||||
capabilities: {
|
||||
instantiation: instantiationCapability,
|
||||
persistence: persistenceCapability,
|
||||
composition: compositionCapability
|
||||
}
|
||||
});
|
||||
|
||||
childObject = domainObjectFactory({
|
||||
name: 'childObject',
|
||||
id: 'def',
|
||||
model: {
|
||||
name: 'a child object'
|
||||
name: 'a child object',
|
||||
location: 'abc'
|
||||
},
|
||||
capabilities: {
|
||||
persistence: persistenceCapability,
|
||||
location: locationCapability
|
||||
}
|
||||
});
|
||||
compositionCapability = jasmine.createSpyObj(
|
||||
'compositionCapability',
|
||||
['invoke', 'add']
|
||||
);
|
||||
|
||||
childObjectClone = domainObjectFactory({
|
||||
name: 'childObject',
|
||||
id: 'def.clone',
|
||||
capabilities: {
|
||||
persistence: persistenceCapability,
|
||||
location: locationCapability
|
||||
}
|
||||
});
|
||||
|
||||
compositionPromise = jasmine.createSpyObj(
|
||||
'compositionPromise',
|
||||
['then']
|
||||
@@ -280,7 +335,7 @@ define(
|
||||
.andReturn(synchronousPromise([childObject]));
|
||||
|
||||
object = domainObjectFactory({
|
||||
name: 'object',
|
||||
name: 'some object',
|
||||
id: 'abc',
|
||||
model: {
|
||||
name: 'some object',
|
||||
@@ -288,36 +343,27 @@ define(
|
||||
location: 'testLocation'
|
||||
},
|
||||
capabilities: {
|
||||
instantiation: instantiationCapability,
|
||||
composition: compositionCapability,
|
||||
location: locationCapability
|
||||
}
|
||||
});
|
||||
newObject = domainObjectFactory({
|
||||
name: 'object',
|
||||
id: 'abc2',
|
||||
model: {
|
||||
name: 'some object',
|
||||
composition: []
|
||||
},
|
||||
capabilities: {
|
||||
composition: compositionCapability
|
||||
}
|
||||
});
|
||||
newParent = domainObjectFactory({
|
||||
name: 'newParent',
|
||||
id: '456',
|
||||
model: {
|
||||
composition: []
|
||||
},
|
||||
capabilities: {
|
||||
composition: compositionCapability,
|
||||
persistence: parentPersistenceCapability
|
||||
location: locationCapability,
|
||||
persistence: persistenceCapability
|
||||
}
|
||||
});
|
||||
|
||||
createObjectPromise = synchronousPromise(newObject);
|
||||
creationService.createObject.andReturn(createObjectPromise);
|
||||
copyService = new CopyService(mockQ, creationService, policyService, mockPersistenceService, mockNow.now);
|
||||
objectClone = domainObjectFactory({
|
||||
name: 'some object',
|
||||
id: 'abc.clone',
|
||||
capabilities: {
|
||||
instantiation: instantiationCapability,
|
||||
composition: compositionCapability,
|
||||
location: locationCapability,
|
||||
persistence: persistenceCapability
|
||||
}
|
||||
});
|
||||
|
||||
objectClones = [objectClone, childObjectClone];
|
||||
|
||||
copyService = new CopyService(mockQ, policyService);
|
||||
});
|
||||
|
||||
describe("the cloning process", function(){
|
||||
@@ -327,10 +373,9 @@ define(
|
||||
copyResult.then(copyFinished);
|
||||
});
|
||||
|
||||
it("copies object and children in a bottom-up" +
|
||||
" fashion", function () {
|
||||
expect(mockPersistenceService.createObject.calls[0].args[2].name).toEqual(childObject.model.name);
|
||||
expect(mockPersistenceService.createObject.calls[1].args[2].name).toEqual(object.model.name);
|
||||
it("returns a promise", function () {
|
||||
expect(copyResult.then).toBeDefined();
|
||||
expect(copyFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns a promise", function () {
|
||||
@@ -338,15 +383,27 @@ define(
|
||||
expect(copyFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clears modified and sets persisted", function () {
|
||||
expect(copyFinished.mostRecentCall.args[0].model.modified).toBeUndefined();
|
||||
expect(copyFinished.mostRecentCall.args[0].model.persisted).toBe(mockNow.now());
|
||||
});
|
||||
|
||||
it ("correctly locates cloned objects", function() {
|
||||
expect(mockPersistenceService.createObject.calls[0].args[2].location).toEqual(mockPersistenceService.createObject.calls[1].args[1]);
|
||||
expect(childObjectClone.getModel().location).toEqual(objectClone.getId());
|
||||
});
|
||||
});
|
||||
describe("when cloning non-creatable objects", function() {
|
||||
beforeEach(function () {
|
||||
policyService.allow.andCallFake(function(category){
|
||||
//Return false for 'creation' policy
|
||||
return category !== 'creation';
|
||||
});
|
||||
|
||||
copyResult = copyService.perform(object, newParent);
|
||||
copyFinished = jasmine.createSpy('copyFinished');
|
||||
copyResult.then(copyFinished);
|
||||
});
|
||||
it ("creates link instead of clone", function() {
|
||||
var copiedObject = copyFinished.calls[0].args[0];
|
||||
expect(copiedObject).toBe(object);
|
||||
expect(compositionCapability.add).toHaveBeenCalledWith(copiedObject.getId());
|
||||
//expect(newParent.getModel().composition).toContain(copiedObject.getId());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -355,20 +412,28 @@ define(
|
||||
object = domainObjectFactory({
|
||||
name: 'object',
|
||||
capabilities: {
|
||||
type: { type: 'object' }
|
||||
type: { type: 'object' },
|
||||
location: locationCapability,
|
||||
persistence: persistenceCapability
|
||||
}
|
||||
});
|
||||
|
||||
newParent = domainObjectFactory({
|
||||
name: 'parentCandidate',
|
||||
capabilities: {
|
||||
type: { type: 'parentCandidate' }
|
||||
type: { type: 'parentCandidate' },
|
||||
instantiation: instantiationCapability,
|
||||
composition: compositionCapability,
|
||||
persistence: persistenceCapability
|
||||
}
|
||||
});
|
||||
|
||||
instantiationCapability.invoke.andReturn(object);
|
||||
});
|
||||
|
||||
it("throws an error", function () {
|
||||
var copyService =
|
||||
new CopyService(mockQ, creationService, policyService, mockPersistenceService, mockNow.now);
|
||||
new CopyService(mockQ, policyService);
|
||||
|
||||
function perform() {
|
||||
copyService.perform(object, newParent);
|
||||
|
||||
277
platform/entanglement/test/services/CopyTaskSpec.js
Normal file
277
platform/entanglement/test/services/CopyTaskSpec.js
Normal file
@@ -0,0 +1,277 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
|
||||
|
||||
define(
|
||||
[
|
||||
'../../src/services/CopyTask',
|
||||
'../DomainObjectFactory'
|
||||
],
|
||||
function (CopyTask, domainObjectFactory) {
|
||||
'use strict';
|
||||
|
||||
var ID_A = "some-string-with-vaguely-uuidish-uniqueness",
|
||||
ID_B = "some-other-similarly-unique-string";
|
||||
|
||||
function synchronousPromise(value) {
|
||||
return (value && value.then) ? value : {
|
||||
then: function (callback) {
|
||||
return synchronousPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("CopyTask", function () {
|
||||
var mockDomainObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockQ,
|
||||
mockDeferred,
|
||||
testModel,
|
||||
mockCallback,
|
||||
counter,
|
||||
cloneIds,
|
||||
task;
|
||||
|
||||
function makeMockCapabilities(childIds) {
|
||||
var mockCapabilities = {
|
||||
persistence: jasmine.createSpyObj(
|
||||
'persistence',
|
||||
['persist']
|
||||
),
|
||||
composition: jasmine.createSpyObj(
|
||||
'composition',
|
||||
['add', 'invoke']
|
||||
),
|
||||
instantiation: jasmine.createSpyObj(
|
||||
'instantiation',
|
||||
['instantiate', 'invoke']
|
||||
)
|
||||
},
|
||||
mockChildren = (childIds || []).map(function (id) {
|
||||
return domainObjectFactory({
|
||||
id: id,
|
||||
capabilities: makeMockCapabilities([]),
|
||||
model: { originalId: id }
|
||||
});
|
||||
});
|
||||
|
||||
mockCapabilities.persistence.persist
|
||||
.andReturn(synchronousPromise(true));
|
||||
mockCapabilities.composition.add.andCallFake(function (obj) {
|
||||
return synchronousPromise(obj);
|
||||
});
|
||||
mockCapabilities.composition.invoke
|
||||
.andReturn(synchronousPromise(mockChildren));
|
||||
mockCapabilities.instantiation.invoke
|
||||
.andCallFake(function (model) {
|
||||
var id = "some-id-" + counter;
|
||||
cloneIds[model.originalId] = id;
|
||||
counter += 1;
|
||||
return domainObjectFactory({
|
||||
id: id,
|
||||
model: model,
|
||||
capabilities: makeMockCapabilities()
|
||||
});
|
||||
});
|
||||
|
||||
return mockCapabilities;
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
counter = 0;
|
||||
cloneIds = {};
|
||||
|
||||
testModel = {
|
||||
composition: [ ID_A, ID_B ],
|
||||
someObj: {},
|
||||
someArr: [ ID_A, ID_B ],
|
||||
objArr: [{"id": ID_A}, {"id": ID_B}],
|
||||
singleElementArr: [ ID_A ]
|
||||
};
|
||||
testModel.someObj[ID_A] = "some value";
|
||||
testModel.someObj.someProperty = ID_B;
|
||||
|
||||
mockDomainObject = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities(testModel.composition),
|
||||
model: testModel
|
||||
});
|
||||
mockParentObject = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities()
|
||||
});
|
||||
mockPolicyService = jasmine.createSpyObj(
|
||||
'policyService',
|
||||
[ 'allow' ]
|
||||
);
|
||||
mockQ = jasmine.createSpyObj('$q', ['when', 'defer', 'all']);
|
||||
mockDeferred = jasmine.createSpyObj(
|
||||
'deferred',
|
||||
[ 'notify', 'resolve', 'reject' ]
|
||||
);
|
||||
|
||||
mockPolicyService.allow.andReturn(true);
|
||||
|
||||
mockQ.when.andCallFake(synchronousPromise);
|
||||
mockQ.defer.andReturn(mockDeferred);
|
||||
mockQ.all.andCallFake(function (promises) {
|
||||
return synchronousPromise(promises.map(function (promise) {
|
||||
var value;
|
||||
promise.then(function (v) { value = v; });
|
||||
return value;
|
||||
}));
|
||||
});
|
||||
|
||||
mockDeferred.resolve.andCallFake(function (value) {
|
||||
mockDeferred.promise = synchronousPromise(value);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("produces models which", function () {
|
||||
var model;
|
||||
|
||||
beforeEach(function () {
|
||||
task = new CopyTask(
|
||||
mockDomainObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockQ
|
||||
);
|
||||
|
||||
task.perform().then(function (clone) {
|
||||
model = clone.getModel();
|
||||
});
|
||||
});
|
||||
|
||||
it("contain rewritten identifiers in arrays", function () {
|
||||
expect(model.someArr)
|
||||
.toEqual(testModel.someArr.map(function (id) {
|
||||
return cloneIds[id];
|
||||
}));
|
||||
});
|
||||
|
||||
it("contain rewritten identifiers in properties", function () {
|
||||
expect(model.someObj.someProperty)
|
||||
.toEqual(cloneIds[testModel.someObj.someProperty]);
|
||||
});
|
||||
|
||||
|
||||
it("contain rewritten identifiers in property names", function () {
|
||||
expect(model.someObj[cloneIds[ID_A]])
|
||||
.toEqual(testModel.someObj[ID_A]);
|
||||
});
|
||||
|
||||
it("contain rewritten identifiers in single-element arrays", function () {
|
||||
expect(model.singleElementArr)
|
||||
.toEqual(testModel.singleElementArr.map(function (id) {
|
||||
return cloneIds[id];
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("copies object trees with multiple references to the" +
|
||||
" same object", function () {
|
||||
var model,
|
||||
mockDomainObjectB,
|
||||
mockComposingObject,
|
||||
composingObjectModel,
|
||||
domainObjectClone,
|
||||
domainObjectBClone;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObjectB = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities(testModel.composition),
|
||||
model: testModel
|
||||
});
|
||||
composingObjectModel = {
|
||||
name: 'mockComposingObject',
|
||||
composition: [mockDomainObject.getId(), mockDomainObjectB.getId()]
|
||||
};
|
||||
mockComposingObject = domainObjectFactory({
|
||||
capabilities: makeMockCapabilities(composingObjectModel.composition),
|
||||
model: composingObjectModel
|
||||
});
|
||||
|
||||
mockComposingObject.capabilities.composition.invoke.andReturn([mockDomainObject, mockDomainObjectB]);
|
||||
task = new CopyTask(
|
||||
mockComposingObject,
|
||||
mockParentObject,
|
||||
mockPolicyService,
|
||||
mockQ
|
||||
);
|
||||
|
||||
task.perform();
|
||||
domainObjectClone = task.clones[2];
|
||||
domainObjectBClone = task.clones[5];
|
||||
});
|
||||
|
||||
/**
|
||||
* mockDomainObject and mockDomainObjectB have the same
|
||||
* model with references to children ID_A and ID_B. Expect
|
||||
* that after duplication the references should differ
|
||||
* because they are each now referencing different child
|
||||
* objects. This tests the issue reported in #428
|
||||
*/
|
||||
it(" and correctly updates child identifiers in models ", function () {
|
||||
var childA_ID = task.clones[0].getId(),
|
||||
childB_ID = task.clones[1].getId(),
|
||||
childC_ID = task.clones[3].getId(),
|
||||
childD_ID = task.clones[4].getId();
|
||||
|
||||
expect(domainObjectClone.model.someArr[0]).toNotBe(domainObjectBClone.model.someArr[0]);
|
||||
expect(domainObjectClone.model.someArr[0]).toBe(childA_ID);
|
||||
expect(domainObjectBClone.model.someArr[0]).toBe(childC_ID);
|
||||
expect(domainObjectClone.model.someArr[1]).toNotBe(domainObjectBClone.model.someArr[1]);
|
||||
expect(domainObjectClone.model.someArr[1]).toBe(childB_ID);
|
||||
expect(domainObjectBClone.model.someArr[1]).toBe(childD_ID);
|
||||
expect(domainObjectClone.model.someObj.someProperty).toNotBe(domainObjectBClone.model.someObj.someProperty);
|
||||
expect(domainObjectClone.model.someObj.someProperty).toBe(childB_ID);
|
||||
expect(domainObjectBClone.model.someObj.someProperty).toBe(childD_ID);
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* This a bug found in testathon when testing issue #428
|
||||
*/
|
||||
it(" and correctly updates child identifiers in object" +
|
||||
" arrays within models ", function () {
|
||||
var childA_ID = task.clones[0].getId(),
|
||||
childB_ID = task.clones[1].getId(),
|
||||
childC_ID = task.clones[3].getId(),
|
||||
childD_ID = task.clones[4].getId();
|
||||
|
||||
expect(domainObjectClone.model.objArr[0].id).not.toBe(ID_A);
|
||||
expect(domainObjectClone.model.objArr[0].id).toBe(childA_ID);
|
||||
expect(domainObjectClone.model.objArr[1].id).not.toBe(ID_B);
|
||||
expect(domainObjectClone.model.objArr[1].id).toBe(childB_ID);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
@@ -4,7 +4,10 @@
|
||||
"actions/GoToOriginalAction",
|
||||
"actions/LinkAction",
|
||||
"actions/MoveAction",
|
||||
"actions/SetPrimaryLocationAction",
|
||||
"policies/CrossSpacePolicy",
|
||||
"services/CopyService",
|
||||
"services/CopyTask",
|
||||
"services/LinkService",
|
||||
"services/MoveService",
|
||||
"services/LocationService",
|
||||
|
||||
@@ -38,7 +38,8 @@ define(
|
||||
* @constructor
|
||||
*/
|
||||
function WorkerService($window, workers) {
|
||||
var workerUrls = {};
|
||||
var workerUrls = {},
|
||||
sharedWorkers = {};
|
||||
|
||||
function addWorker(worker) {
|
||||
var key = worker.key;
|
||||
@@ -48,12 +49,15 @@ define(
|
||||
worker.bundle.sources,
|
||||
worker.scriptUrl
|
||||
].join("/");
|
||||
sharedWorkers[key] = worker.shared;
|
||||
}
|
||||
}
|
||||
|
||||
(workers || []).forEach(addWorker);
|
||||
this.workerUrls = workerUrls;
|
||||
this.sharedWorkers = sharedWorkers;
|
||||
this.Worker = $window.Worker;
|
||||
this.SharedWorker = $window.SharedWorker;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,12 +65,17 @@ define(
|
||||
* that has been registered under the `workers` category
|
||||
* of extension.
|
||||
*
|
||||
* This will return either a Worker or a SharedWorker,
|
||||
* depending on whether a `shared` flag has been specified
|
||||
* on the the extension definition for the referenced worker.
|
||||
*
|
||||
* @param {string} key symbolic identifier for the worker
|
||||
* @returns {Worker} the running Worker
|
||||
* @returns {Worker | SharedWorker} the running Worker
|
||||
*/
|
||||
WorkerService.prototype.run = function (key) {
|
||||
var scriptUrl = this.workerUrls[key],
|
||||
Worker = this.Worker;
|
||||
Worker = this.sharedWorkers[key] ?
|
||||
this.SharedWorker : this.Worker;
|
||||
return scriptUrl && Worker && new Worker(scriptUrl);
|
||||
};
|
||||
|
||||
|
||||
@@ -30,10 +30,14 @@ define(
|
||||
var mockWindow,
|
||||
testWorkers,
|
||||
mockWorker,
|
||||
mockSharedWorker,
|
||||
service;
|
||||
|
||||
beforeEach(function () {
|
||||
mockWindow = jasmine.createSpyObj('$window', ['Worker']);
|
||||
mockWindow = jasmine.createSpyObj(
|
||||
'$window',
|
||||
['Worker', 'SharedWorker']
|
||||
);
|
||||
testWorkers = [
|
||||
{
|
||||
key: 'abc',
|
||||
@@ -49,11 +53,19 @@ define(
|
||||
key: 'xyz',
|
||||
scriptUrl: 'bad.js',
|
||||
bundle: { path: 'bad', sources: 'bad' }
|
||||
},
|
||||
{
|
||||
key: 'a-shared-worker',
|
||||
shared: true,
|
||||
scriptUrl: 'c.js',
|
||||
bundle: { path: 'a', sources: 'b' }
|
||||
}
|
||||
];
|
||||
mockWorker = {};
|
||||
mockSharedWorker = {};
|
||||
|
||||
mockWindow.Worker.andReturn(mockWorker);
|
||||
mockWindow.SharedWorker.andReturn(mockSharedWorker);
|
||||
|
||||
service = new WorkerService(mockWindow, testWorkers);
|
||||
});
|
||||
@@ -68,6 +80,12 @@ define(
|
||||
expect(mockWindow.Worker).toHaveBeenCalledWith('x/y/z.js');
|
||||
});
|
||||
|
||||
it("allows workers to be shared", function () {
|
||||
expect(service.run('a-shared-worker')).toBe(mockSharedWorker);
|
||||
expect(mockWindow.SharedWorker)
|
||||
.toHaveBeenCalledWith('a/b/c.js');
|
||||
});
|
||||
|
||||
it("returns undefined for unknown workers", function () {
|
||||
expect(service.run('def')).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"glyph": "L",
|
||||
"type": "layout",
|
||||
"templateUrl": "templates/layout.html",
|
||||
"uses": [ "composition" ],
|
||||
"uses": [],
|
||||
"gestures": [ "drop" ]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -45,43 +45,8 @@ define(
|
||||
* @param {Scope} $scope the controller's Angular scope
|
||||
*/
|
||||
function LayoutController($scope) {
|
||||
var self = this;
|
||||
|
||||
// Utility function to copy raw positions from configuration,
|
||||
// without writing directly to configuration (to avoid triggering
|
||||
// persistence from watchers during drags).
|
||||
function shallowCopy(obj, keys) {
|
||||
var copy = {};
|
||||
keys.forEach(function (k) {
|
||||
copy[k] = obj[k];
|
||||
});
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Compute panel positions based on the layout's object model
|
||||
function lookupPanels(ids) {
|
||||
var configuration = $scope.configuration || {};
|
||||
|
||||
// ids is read from model.composition and may be undefined;
|
||||
// fall back to an array if that occurs
|
||||
ids = ids || [];
|
||||
|
||||
// Pull panel positions from configuration
|
||||
self.rawPositions =
|
||||
shallowCopy(configuration.panels || {}, ids);
|
||||
|
||||
// Clear prior computed positions
|
||||
self.positions = {};
|
||||
|
||||
// Update width/height that we are tracking
|
||||
self.gridSize =
|
||||
($scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
|
||||
|
||||
// Compute positions and add defaults where needed
|
||||
ids.forEach(function (id, index) {
|
||||
self.populatePosition(id, index);
|
||||
});
|
||||
}
|
||||
var self = this,
|
||||
callbackCount = 0;
|
||||
|
||||
// Update grid size when it changed
|
||||
function updateGridSize(layoutGrid) {
|
||||
@@ -92,7 +57,7 @@ define(
|
||||
// Only update panel positions if this actually changed things
|
||||
if (self.gridSize[0] !== oldSize[0] ||
|
||||
self.gridSize[1] !== oldSize[1]) {
|
||||
lookupPanels(Object.keys(self.positions));
|
||||
self.layoutPanels(Object.keys(self.positions));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +85,8 @@ define(
|
||||
$scope.commit("Dropped a frame.");
|
||||
}
|
||||
// Populate template-facing position for this id
|
||||
self.rawPositions[id] =
|
||||
$scope.configuration.panels[id];
|
||||
self.populatePosition(id);
|
||||
// Layout may contain embedded views which will
|
||||
// listen for drops, so call preventDefault() so
|
||||
@@ -127,6 +94,28 @@ define(
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
//Will fetch fully contextualized composed objects, and populate
|
||||
// scope with them.
|
||||
function refreshComposition() {
|
||||
//Keep a track of how many composition callbacks have been made
|
||||
var thisCount = ++callbackCount;
|
||||
|
||||
$scope.domainObject.useCapability('composition').then(function(composition){
|
||||
var ids;
|
||||
|
||||
//Is this callback for the most recent composition
|
||||
// request? If not, discard it. Prevents race condition
|
||||
if (thisCount === callbackCount){
|
||||
ids = composition.map(function (object) {
|
||||
return object.getId();
|
||||
}) || [];
|
||||
|
||||
$scope.composition = composition;
|
||||
self.layoutPanels(ids);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// End drag; we don't want to put $scope into this
|
||||
// because it triggers "cpws" (copy window or scope)
|
||||
// errors in Angular.
|
||||
@@ -156,8 +145,8 @@ define(
|
||||
// Watch for changes to the grid size in the model
|
||||
$scope.$watch("model.layoutGrid", updateGridSize);
|
||||
|
||||
// Position panes when the model field changes
|
||||
$scope.$watch("model.composition", lookupPanels);
|
||||
// Update composed objects on screen, and position panes
|
||||
$scope.$watchCollection("model.composition", refreshComposition);
|
||||
|
||||
// Position panes where they are dropped
|
||||
$scope.$on("mctDrop", handleDrop);
|
||||
@@ -263,6 +252,43 @@ define(
|
||||
}
|
||||
};
|
||||
|
||||
// Utility function to copy raw positions from configuration,
|
||||
// without writing directly to configuration (to avoid triggering
|
||||
// persistence from watchers during drags).
|
||||
function shallowCopy(obj, keys) {
|
||||
var copy = {};
|
||||
keys.forEach(function (k) {
|
||||
copy[k] = obj[k];
|
||||
});
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute panel positions based on the layout's object model.
|
||||
* Defined as member function to facilitate testing.
|
||||
* @private
|
||||
*/
|
||||
LayoutController.prototype.layoutPanels = function (ids) {
|
||||
var configuration = this.$scope.configuration || {},
|
||||
self = this;
|
||||
|
||||
// Pull panel positions from configuration
|
||||
this.rawPositions =
|
||||
shallowCopy(configuration.panels || {}, ids);
|
||||
|
||||
// Clear prior computed positions
|
||||
this.positions = {};
|
||||
|
||||
// Update width/height that we are tracking
|
||||
this.gridSize =
|
||||
(this.$scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
|
||||
|
||||
// Compute positions and add defaults where needed
|
||||
ids.forEach(function (id, index) {
|
||||
self.populatePosition(id, index);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* End the active drag gesture. This will update the
|
||||
* view configuration.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||
/*global define,describe,it,expect,beforeEach,jasmine,spyOn*/
|
||||
|
||||
define(
|
||||
["../src/LayoutController"],
|
||||
@@ -31,21 +31,44 @@ define(
|
||||
mockEvent,
|
||||
testModel,
|
||||
testConfiguration,
|
||||
controller;
|
||||
controller,
|
||||
mockCompositionCapability,
|
||||
mockComposition,
|
||||
mockCompositionObjects;
|
||||
|
||||
function mockPromise(value){
|
||||
return {
|
||||
then: function (thenFunc) {
|
||||
return mockPromise(thenFunc(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function mockDomainObject(id){
|
||||
return {
|
||||
getId: function() {
|
||||
return id;
|
||||
},
|
||||
useCapability: function() {
|
||||
return mockCompositionCapability;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
[ "$watch", "$on", "commit" ]
|
||||
[ "$watch", "$watchCollection", "$on", "commit" ]
|
||||
);
|
||||
mockEvent = jasmine.createSpyObj(
|
||||
'event',
|
||||
[ 'preventDefault' ]
|
||||
);
|
||||
|
||||
testModel = {
|
||||
composition: [ "a", "b", "c" ]
|
||||
};
|
||||
testModel = {};
|
||||
|
||||
mockComposition = ["a", "b", "c"];
|
||||
mockCompositionObjects = mockComposition.map(mockDomainObject);
|
||||
|
||||
testConfiguration = {
|
||||
panels: {
|
||||
@@ -56,23 +79,62 @@ define(
|
||||
}
|
||||
};
|
||||
|
||||
mockCompositionCapability = mockPromise(mockCompositionObjects);
|
||||
|
||||
mockScope.domainObject = mockDomainObject("mockDomainObject");
|
||||
mockScope.model = testModel;
|
||||
mockScope.configuration = testConfiguration;
|
||||
spyOn(mockScope.domainObject, "useCapability").andCallThrough();
|
||||
|
||||
controller = new LayoutController(mockScope);
|
||||
spyOn(controller, "layoutPanels").andCallThrough();
|
||||
});
|
||||
|
||||
// Model changes will indicate that panel positions
|
||||
// may have changed, for instance.
|
||||
it("watches for changes to composition", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
expect(mockScope.$watchCollection).toHaveBeenCalledWith(
|
||||
"model.composition",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("Retrieves updated composition from composition capability", function () {
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
expect(mockScope.domainObject.useCapability).toHaveBeenCalledWith(
|
||||
"composition"
|
||||
);
|
||||
expect(controller.layoutPanels).toHaveBeenCalledWith(
|
||||
mockComposition
|
||||
);
|
||||
});
|
||||
|
||||
it("Is robust to concurrent changes to composition", function () {
|
||||
var secondMockComposition = ["a", "b", "c", "d"],
|
||||
secondMockCompositionObjects = secondMockComposition.map(mockDomainObject),
|
||||
firstCompositionCB,
|
||||
secondCompositionCB;
|
||||
|
||||
spyOn(mockCompositionCapability, "then");
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
firstCompositionCB = mockCompositionCapability.then.calls[0].args[0];
|
||||
secondCompositionCB = mockCompositionCapability.then.calls[1].args[0];
|
||||
|
||||
//Resolve promises in reverse order
|
||||
secondCompositionCB(secondMockCompositionObjects);
|
||||
firstCompositionCB(mockCompositionObjects);
|
||||
|
||||
//Expect the promise call that was initiated most recently to
|
||||
// be the one used to populate scope, irrespective of order that
|
||||
// it was eventually resolved
|
||||
expect(mockScope.composition).toBe(secondMockCompositionObjects);
|
||||
});
|
||||
|
||||
|
||||
it("provides styles for frames, from configuration", function () {
|
||||
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
expect(controller.getFrameStyle("a")).toEqual({
|
||||
top: "320px",
|
||||
left: "640px",
|
||||
@@ -85,7 +147,7 @@ define(
|
||||
var styleB, styleC;
|
||||
|
||||
// b and c do not have configured positions
|
||||
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
styleB = controller.getFrameStyle("b");
|
||||
styleC = controller.getFrameStyle("c");
|
||||
@@ -102,7 +164,7 @@ define(
|
||||
|
||||
it("allows panels to be dragged", function () {
|
||||
// Populate scope
|
||||
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
// Verify precondtion
|
||||
expect(testConfiguration.panels.b).not.toBeDefined();
|
||||
@@ -121,7 +183,7 @@ define(
|
||||
|
||||
it("invokes commit after drag", function () {
|
||||
// Populate scope
|
||||
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
// Do a drag
|
||||
controller.startDrag("b", [1, 1], [0, 0]);
|
||||
@@ -147,7 +209,6 @@ define(
|
||||
expect(testConfiguration.panels.d).not.toBeDefined();
|
||||
|
||||
// Notify that a drop occurred
|
||||
testModel.composition.push('d');
|
||||
mockScope.$on.mostRecentCall.args[1](
|
||||
mockEvent,
|
||||
'd',
|
||||
@@ -167,7 +228,6 @@ define(
|
||||
mockEvent.defaultPrevented = true;
|
||||
|
||||
// Notify that a drop occurred
|
||||
testModel.composition.push('d');
|
||||
mockScope.$on.mostRecentCall.args[1](
|
||||
mockEvent,
|
||||
'd',
|
||||
@@ -184,7 +244,7 @@ define(
|
||||
|
||||
// White-boxy; we know which watch is which
|
||||
mockScope.$watch.calls[0].args[1](testModel.layoutGrid);
|
||||
mockScope.$watch.calls[1].args[1](testModel.composition);
|
||||
mockScope.$watchCollection.calls[0].args[1](testModel.composition);
|
||||
|
||||
styleB = controller.getFrameStyle("b");
|
||||
|
||||
@@ -201,7 +261,6 @@ define(
|
||||
mockScope.$watch.calls[0].args[1](testModel.layoutGrid);
|
||||
|
||||
// Notify that a drop occurred
|
||||
testModel.composition.push('d');
|
||||
mockScope.$on.mostRecentCall.args[1](
|
||||
mockEvent,
|
||||
'd',
|
||||
@@ -215,6 +274,23 @@ define(
|
||||
expect(parseInt(style.width, 10)).toBeGreaterThan(63);
|
||||
expect(parseInt(style.height, 10)).toBeGreaterThan(31);
|
||||
});
|
||||
|
||||
it("updates positions of existing objects on a drop", function () {
|
||||
var oldStyle;
|
||||
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
oldStyle = controller.getFrameStyle("b");
|
||||
|
||||
expect(oldStyle).toBeDefined();
|
||||
|
||||
// ...drop event...
|
||||
mockScope.$on.mostRecentCall
|
||||
.args[1](mockEvent, 'b', { x: 300, y: 100 });
|
||||
|
||||
expect(controller.getFrameStyle("b"))
|
||||
.not.toEqual(oldStyle);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
ng-show="representation.showControls"
|
||||
ng-if="axes[1].options.length > 0">
|
||||
<div class='form-control shell select'>
|
||||
<select class="form-control input shell select"
|
||||
<select class="form-control input shell"
|
||||
ng-model="axes[1].active"
|
||||
ng-options="option.name for option in axes[1].options">
|
||||
</select>
|
||||
@@ -160,12 +160,11 @@
|
||||
{{axes[0].active.name}}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="gl-plot-x-options gl-plot-local-controls"
|
||||
ng-show="representation.showControls"
|
||||
ng-if="axes[0].options.length > 0">
|
||||
<div class='form-control shell select'>
|
||||
<select class="form-control input shell select"
|
||||
<select class="form-control input shell"
|
||||
ng-model="axes[0].active"
|
||||
ng-options="option.name for option in axes[0].options">
|
||||
</select>
|
||||
|
||||
@@ -146,6 +146,7 @@ define(
|
||||
if (canvas.width !== canvas.offsetWidth ||
|
||||
canvas.height !== canvas.offsetHeight) {
|
||||
doDraw(scope.draw);
|
||||
scope.$apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +182,7 @@ define(
|
||||
canvas.addEventListener("webglcontextlost", fallbackFromWebGL);
|
||||
|
||||
// Check for resize, on a timer
|
||||
activeInterval = $interval(drawIfResized, 1000);
|
||||
activeInterval = $interval(drawIfResized, 1000, 0, false);
|
||||
|
||||
// Watch "draw" for external changes to the set of
|
||||
// things to be drawn.
|
||||
|
||||
@@ -45,8 +45,10 @@ define(
|
||||
jasmine.createSpy("$interval");
|
||||
mockLog =
|
||||
jasmine.createSpyObj("$log", ["warn", "info", "debug"]);
|
||||
mockScope =
|
||||
jasmine.createSpyObj("$scope", ["$watchCollection", "$on"]);
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
["$watchCollection", "$on", "$apply"]
|
||||
);
|
||||
mockElement =
|
||||
jasmine.createSpyObj("element", ["find", "html"]);
|
||||
mockInterval.cancel = jasmine.createSpy("cancelInterval");
|
||||
@@ -152,7 +154,9 @@ define(
|
||||
// Should track canvas size in an interval
|
||||
expect(mockInterval).toHaveBeenCalledWith(
|
||||
jasmine.any(Function),
|
||||
jasmine.any(Number)
|
||||
jasmine.any(Number),
|
||||
0,
|
||||
false
|
||||
);
|
||||
|
||||
// Verify pre-condition
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"properties": [
|
||||
{
|
||||
"name": "Start date/time",
|
||||
"control": "datetime",
|
||||
"control": "timeline-datetime",
|
||||
"required": true,
|
||||
"property": [ "start" ],
|
||||
"options": [ "SET" ]
|
||||
@@ -83,7 +83,7 @@
|
||||
"properties": [
|
||||
{
|
||||
"name": "Start date/time",
|
||||
"control": "datetime",
|
||||
"control": "timeline-datetime",
|
||||
"required": true,
|
||||
"property": [ "start" ],
|
||||
"options": [ "SET" ]
|
||||
@@ -271,7 +271,7 @@
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"key": "datetime",
|
||||
"key": "timeline-datetime",
|
||||
"templateUrl": "templates/controls/datetime.html"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -79,6 +79,9 @@ define(
|
||||
// Used to choose which form control to use
|
||||
key: "=",
|
||||
|
||||
// Allow controls to trigger blur-like events
|
||||
ngBlur: "&",
|
||||
|
||||
// The state of the form value itself
|
||||
ngModel: "=",
|
||||
|
||||
|
||||
12
platform/persistence/aggregator/bundle.json
Normal file
12
platform/persistence/aggregator/bundle.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extensions": {
|
||||
"components": [
|
||||
{
|
||||
"provides": "persistenceService",
|
||||
"type": "aggregator",
|
||||
"depends": [ "$q" ],
|
||||
"implementation": "PersistenceAggregator.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
89
platform/persistence/aggregator/src/PersistenceAggregator.js
Normal file
89
platform/persistence/aggregator/src/PersistenceAggregator.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define,window*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
// Return values to use when a persistence space is unknown,
|
||||
// and there is no appropriate provider to route to.
|
||||
var METHOD_DEFAULTS = {
|
||||
createObject: false,
|
||||
readObject: undefined,
|
||||
listObjects: [],
|
||||
updateObject: false,
|
||||
deleteObject: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Aggregates multiple persistence providers, such that they can be
|
||||
* utilized as if they were a single object. This is achieved by
|
||||
* routing persistence calls to an appropriate provider; the space
|
||||
* specified at call time is matched with the first provider (per
|
||||
* priority order) which reports that it provides persistence for
|
||||
* this space.
|
||||
*
|
||||
* @memberof platform/persistence/aggregator
|
||||
* @constructor
|
||||
* @implements {PersistenceService}
|
||||
* @param $q Angular's $q, for promises
|
||||
* @param {PersistenceService[]} providers the providers to aggregate
|
||||
*/
|
||||
function PersistenceAggregator($q, providers) {
|
||||
var providerMap = {};
|
||||
|
||||
function addToMap(provider) {
|
||||
return provider.listSpaces().then(function (spaces) {
|
||||
spaces.forEach(function (space) {
|
||||
providerMap[space] = providerMap[space] || provider;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.providerMapPromise = $q.all(providers.map(addToMap))
|
||||
.then(function () { return providerMap; });
|
||||
}
|
||||
|
||||
PersistenceAggregator.prototype.listSpaces = function () {
|
||||
return this.providerMapPromise.then(function (map) {
|
||||
return Object.keys(map);
|
||||
});
|
||||
};
|
||||
|
||||
Object.keys(METHOD_DEFAULTS).forEach(function (method) {
|
||||
PersistenceAggregator.prototype[method] = function (space) {
|
||||
var delegateArgs = Array.prototype.slice.apply(arguments, []);
|
||||
return this.providerMapPromise.then(function (map) {
|
||||
var provider = map[space];
|
||||
return provider ?
|
||||
provider[method].apply(provider, delegateArgs) :
|
||||
METHOD_DEFAULTS[method];
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return PersistenceAggregator;
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,103 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
|
||||
define(
|
||||
['../src/PersistenceAggregator'],
|
||||
function (PersistenceAggregator) {
|
||||
'use strict';
|
||||
|
||||
var PERSISTENCE_SERVICE_METHODS = [
|
||||
'listSpaces',
|
||||
'listObjects',
|
||||
'createObject',
|
||||
'readObject',
|
||||
'updateObject',
|
||||
'deleteObject'
|
||||
],
|
||||
WRAPPED_METHODS = PERSISTENCE_SERVICE_METHODS.filter(function (m) {
|
||||
return m !== 'listSpaces';
|
||||
});
|
||||
|
||||
function fakePromise(value) {
|
||||
return (value || {}).then ? value : {
|
||||
then: function (callback) {
|
||||
return fakePromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("PersistenceAggregator", function () {
|
||||
var mockQ,
|
||||
mockProviders,
|
||||
mockCallback,
|
||||
testSpaces,
|
||||
aggregator;
|
||||
|
||||
beforeEach(function () {
|
||||
testSpaces = ['a', 'b', 'c'];
|
||||
mockQ = jasmine.createSpyObj("$q", ['all']);
|
||||
mockProviders = testSpaces.map(function (space) {
|
||||
var mockProvider = jasmine.createSpyObj(
|
||||
'provider-' + space,
|
||||
PERSISTENCE_SERVICE_METHODS
|
||||
);
|
||||
PERSISTENCE_SERVICE_METHODS.forEach(function (m) {
|
||||
mockProvider[m].andReturn(fakePromise(true));
|
||||
});
|
||||
mockProvider.listSpaces.andReturn(fakePromise([space]));
|
||||
return mockProvider;
|
||||
});
|
||||
mockCallback = jasmine.createSpy();
|
||||
|
||||
mockQ.all.andCallFake(function (fakePromises) {
|
||||
var result = [];
|
||||
fakePromises.forEach(function (p) {
|
||||
p.then(function (v) { result.push(v); });
|
||||
});
|
||||
return fakePromise(result);
|
||||
});
|
||||
|
||||
aggregator = new PersistenceAggregator(mockQ, mockProviders);
|
||||
});
|
||||
|
||||
it("exposes spaces for all providers", function () {
|
||||
aggregator.listSpaces().then(mockCallback);
|
||||
expect(mockCallback).toHaveBeenCalledWith(testSpaces);
|
||||
});
|
||||
|
||||
WRAPPED_METHODS.forEach(function (m) {
|
||||
it("redirects " + m + " calls to an appropriate provider", function () {
|
||||
testSpaces.forEach(function (space, index) {
|
||||
var key = 'key-' + space,
|
||||
value = 'val-' + space;
|
||||
expect(aggregator[m](space, key, value))
|
||||
.toEqual(mockProviders[index][m]());
|
||||
expect(mockProviders[index][m])
|
||||
.toHaveBeenCalledWith(space, key, value);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
3
platform/persistence/aggregator/test/suite.json
Normal file
3
platform/persistence/aggregator/test/suite.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"PersistenceAggregator"
|
||||
]
|
||||
@@ -80,7 +80,7 @@ define(
|
||||
|
||||
// Update the indicator initially, and start polling.
|
||||
updateIndicator();
|
||||
$interval(updateIndicator, interval, false);
|
||||
$interval(updateIndicator, interval, 0, false);
|
||||
}
|
||||
|
||||
ElasticIndicator.prototype.getGlyph = function () {
|
||||
|
||||
@@ -55,6 +55,7 @@ define(
|
||||
expect(mockInterval).toHaveBeenCalledWith(
|
||||
jasmine.any(Function),
|
||||
testInterval,
|
||||
0,
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
@@ -68,6 +68,20 @@
|
||||
"agentService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"priority": "mandatory",
|
||||
"implementation": "TemplatePrefetcher.js",
|
||||
"depends": [
|
||||
"templateLinker",
|
||||
"templates[]",
|
||||
"views[]",
|
||||
"representations[]",
|
||||
"controls[]",
|
||||
"containers[]"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ define(
|
||||
toClear = [], // Properties to clear out of scope on change
|
||||
counter = 0,
|
||||
couldRepresent = false,
|
||||
lastId,
|
||||
lastIdPath = [],
|
||||
lastKey,
|
||||
changeTemplate = templateLinker.link($scope, element);
|
||||
|
||||
@@ -143,11 +143,27 @@ define(
|
||||
});
|
||||
}
|
||||
|
||||
function unchanged(canRepresent, id, key) {
|
||||
function unchanged(canRepresent, idPath, key) {
|
||||
return canRepresent &&
|
||||
couldRepresent &&
|
||||
id === lastId &&
|
||||
key === lastKey;
|
||||
key === lastKey &&
|
||||
idPath.length === lastIdPath.length &&
|
||||
idPath.every(function (id, i) {
|
||||
return id === lastIdPath[i];
|
||||
});
|
||||
}
|
||||
|
||||
function getIdPath(domainObject) {
|
||||
if (!domainObject) {
|
||||
return [];
|
||||
}
|
||||
if (!domainObject.hasCapability('context')) {
|
||||
return [domainObject.getId()];
|
||||
}
|
||||
return domainObject.getCapability('context')
|
||||
.getPath().map(function (pathObject) {
|
||||
return pathObject.getId();
|
||||
});
|
||||
}
|
||||
|
||||
// General-purpose refresh mechanism; should set up the scope
|
||||
@@ -159,10 +175,10 @@ define(
|
||||
path = representation && getPath(representation),
|
||||
uses = ((representation || {}).uses || []),
|
||||
canRepresent = !!(path && domainObject),
|
||||
id = domainObject && domainObject.getId(),
|
||||
idPath = getIdPath(domainObject),
|
||||
key = $scope.key;
|
||||
|
||||
if (unchanged(canRepresent, id, key)) {
|
||||
if (unchanged(canRepresent, idPath, key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,7 +206,7 @@ define(
|
||||
|
||||
// To allow simplified change detection next time around
|
||||
couldRepresent = canRepresent;
|
||||
lastId = id;
|
||||
lastIdPath = idPath;
|
||||
lastKey = key;
|
||||
|
||||
// Populate scope with fields associated with the current
|
||||
|
||||
@@ -54,7 +54,6 @@ define(
|
||||
* @param {string} the URL for the template
|
||||
* @returns {Promise.<string>} a promise for the HTML content of
|
||||
* the template
|
||||
* @private
|
||||
*/
|
||||
TemplateLinker.prototype.load = function (templateUrl) {
|
||||
return this.$templateRequest(
|
||||
|
||||
51
platform/representation/src/TemplatePrefetcher.js
Normal file
51
platform/representation/src/TemplatePrefetcher.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise*/
|
||||
|
||||
define(
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Loads all templates when the application is started.
|
||||
* @param {platform/representation.TemplateLinker} templateLinker
|
||||
* the `templateLinker` service, used to load and cache
|
||||
* template extensions
|
||||
* @param {...Array.<{templateUrl: string}>} extensions arrays
|
||||
* of template or template-like extensions
|
||||
*/
|
||||
function TemplatePrefetcher(templateLinker, extensions) {
|
||||
Array.prototype.slice.apply(arguments, [1])
|
||||
.reduce(function (a, b) {
|
||||
return a.concat(b);
|
||||
}, [])
|
||||
.map(function (ext) {
|
||||
return templateLinker.getPath(ext);
|
||||
})
|
||||
.forEach(function (path) {
|
||||
templateLinker.load(path);
|
||||
});
|
||||
}
|
||||
|
||||
return TemplatePrefetcher;
|
||||
}
|
||||
);
|
||||
@@ -247,6 +247,54 @@ define(
|
||||
mockScope.$watch.calls[0].args[1]();
|
||||
expect(mockScope.testCapability).toBeUndefined();
|
||||
});
|
||||
|
||||
it("detects changes among linked instances", function () {
|
||||
var mockContext = jasmine.createSpyObj('context', ['getPath']),
|
||||
mockContext2 = jasmine.createSpyObj('context', ['getPath']),
|
||||
mockLink = jasmine.createSpyObj(
|
||||
'linkedObject',
|
||||
DOMAIN_OBJECT_METHODS
|
||||
),
|
||||
mockParent = jasmine.createSpyObj(
|
||||
'parentObject',
|
||||
DOMAIN_OBJECT_METHODS
|
||||
),
|
||||
callCount;
|
||||
|
||||
mockDomainObject.getCapability.andCallFake(function (c) {
|
||||
return c === 'context' && mockContext;
|
||||
});
|
||||
mockLink.getCapability.andCallFake(function (c) {
|
||||
return c === 'context' && mockContext2;
|
||||
});
|
||||
mockDomainObject.hasCapability.andCallFake(function (c) {
|
||||
return c === 'context';
|
||||
});
|
||||
mockLink.hasCapability.andCallFake(function (c) {
|
||||
return c === 'context';
|
||||
});
|
||||
mockLink.getModel.andReturn({});
|
||||
|
||||
mockContext.getPath.andReturn([mockDomainObject]);
|
||||
mockContext2.getPath.andReturn([mockParent, mockLink]);
|
||||
|
||||
mockLink.getId.andReturn('test-id');
|
||||
mockDomainObject.getId.andReturn('test-id');
|
||||
|
||||
mockParent.getId.andReturn('parent-id');
|
||||
|
||||
mockScope.key = "abc";
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
|
||||
mockScope.$watch.calls[0].args[1]();
|
||||
callCount = mockChangeTemplate.calls.length;
|
||||
|
||||
mockScope.domainObject = mockLink;
|
||||
mockScope.$watch.calls[0].args[1]();
|
||||
|
||||
expect(mockChangeTemplate.calls.length)
|
||||
.toEqual(callCount + 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
76
platform/representation/test/TemplatePrefetcherSpec.js
Normal file
76
platform/representation/test/TemplatePrefetcherSpec.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
|
||||
define(
|
||||
["../src/TemplatePrefetcher"],
|
||||
function (TemplatePrefetcher) {
|
||||
'use strict';
|
||||
|
||||
describe("TemplatePrefetcher", function () {
|
||||
var mockTemplateLinker,
|
||||
testExtensions,
|
||||
testPathPrefix,
|
||||
prefetcher;
|
||||
|
||||
beforeEach(function () {
|
||||
testPathPrefix = "some/path/";
|
||||
|
||||
mockTemplateLinker = jasmine.createSpyObj(
|
||||
'templateLinker',
|
||||
[ 'getPath', 'load' ]
|
||||
);
|
||||
|
||||
mockTemplateLinker.getPath.andCallFake(function (ext) {
|
||||
return testPathPrefix + ext.templateUrl;
|
||||
});
|
||||
|
||||
testExtensions = ['a', 'b', 'c'].map(function (category) {
|
||||
return ['x', 'y', 'z'].map(function (ext) {
|
||||
return {
|
||||
templateUrl: category + '/' + ext + '.html'
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
prefetcher = new TemplatePrefetcher(
|
||||
mockTemplateLinker,
|
||||
testExtensions[0],
|
||||
testExtensions[1],
|
||||
testExtensions[2]
|
||||
);
|
||||
});
|
||||
|
||||
it("loads all templates when run", function () {
|
||||
testExtensions.forEach(function (category) {
|
||||
category.forEach(function (extension) {
|
||||
expect(mockTemplateLinker.load).toHaveBeenCalledWith(
|
||||
mockTemplateLinker.getPath(extension)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -8,5 +8,6 @@
|
||||
"services/DndService",
|
||||
"MCTInclude",
|
||||
"MCTRepresentation",
|
||||
"TemplateLinker"
|
||||
"TemplateLinker",
|
||||
"TemplatePrefetcher"
|
||||
]
|
||||
|
||||
2
platform/status/README.md
Normal file
2
platform/status/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Facilitates tracking states associated with specific domain
|
||||
objects.
|
||||
23
platform/status/bundle.json
Normal file
23
platform/status/bundle.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"extensions": {
|
||||
"representers": [
|
||||
{
|
||||
"implementation": "StatusRepresenter.js"
|
||||
}
|
||||
],
|
||||
"capabilities": [
|
||||
{
|
||||
"key": "status",
|
||||
"implementation": "StatusCapability.js",
|
||||
"depends": [ "statusService" ]
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
{
|
||||
"key": "statusService",
|
||||
"implementation": "StatusService.js",
|
||||
"depends": [ "topic" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user