mirror of
https://github.com/nasa/openmct.git
synced 2025-05-02 08:43:17 +00:00
[Action] Merge
Merged with master.
This commit is contained in:
commit
e7563ff4e9
298
CONTRIBUTING.md
Normal file
298
CONTRIBUTING.md
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
# Contributing to Open MCT Web
|
||||||
|
|
||||||
|
This document describes the process of contributing to Open MCT Web as well
|
||||||
|
as the standards that will be applied when evaluating contributions.
|
||||||
|
|
||||||
|
Please be aware that additional agreements will be necessary before we can
|
||||||
|
accept changes from external contributors.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
The short version:
|
||||||
|
|
||||||
|
1. Write your contribution.
|
||||||
|
2. Make sure your contribution meets code, test, and commit message
|
||||||
|
standards as described below.
|
||||||
|
3. Submit a pull request from a topic branch back to `master`. Include a check
|
||||||
|
list, as described below. (Optionally, assign this to a specific member
|
||||||
|
for review.)
|
||||||
|
4. Respond to any discussion. When the reviewer decides it's ready, they
|
||||||
|
will merge back `master` and fill out their own check list.
|
||||||
|
|
||||||
|
## Contribution Process
|
||||||
|
|
||||||
|
Open MCT Web uses git for software version control, and for branching and
|
||||||
|
merging. The central repository is at
|
||||||
|
https://github.com/nasa/openmctweb.git.
|
||||||
|
|
||||||
|
### Roles
|
||||||
|
|
||||||
|
References to roles are made throughout this document. These are not intended
|
||||||
|
to reflect titles or long-term job assignments; rather, these are used as
|
||||||
|
descriptors to refer to members of the development team performing tasks in
|
||||||
|
the check-in process. These roles are:
|
||||||
|
|
||||||
|
* _Author_: The individual who has made changes to files in the software
|
||||||
|
repository, and wishes to check these in.
|
||||||
|
* _Reviewer_: The individual who reviews changes to files before they are
|
||||||
|
checked in.
|
||||||
|
* _Integrator_: The individual who performs the task of merging these files.
|
||||||
|
Usually the reviewer.
|
||||||
|
|
||||||
|
### Branching
|
||||||
|
|
||||||
|
Three basic types of branches may be included in the above repository:
|
||||||
|
|
||||||
|
1. Master branch.
|
||||||
|
2. Topic branches.
|
||||||
|
3. Developer branches.
|
||||||
|
|
||||||
|
Branches which do not fit into the above categories may be created and used
|
||||||
|
during the course of development for various reasons, such as large-scale
|
||||||
|
refactoring of code or implementation of complex features which may cause
|
||||||
|
instability. In these exceptional cases it is the responsibility of the
|
||||||
|
developer who initiates the task which motivated this branching to
|
||||||
|
communicate to the team the role of these branches and any associated
|
||||||
|
procedures for the duration of their use.
|
||||||
|
|
||||||
|
#### Master Branch
|
||||||
|
|
||||||
|
The role of the `master` branches is to represent the latest
|
||||||
|
"ready for test" version of the software. Source code on the master
|
||||||
|
branch has undergone peer review, and will undergo regular automated
|
||||||
|
testing with notification on failure. Master branches may be unstable
|
||||||
|
(particularly for recent features), but the intent is for the stability of
|
||||||
|
any features on master branches to be non-decreasing. It is the shared
|
||||||
|
responsibility of authors, reviewers, and integrators to ensure this.
|
||||||
|
|
||||||
|
#### Topic Branches
|
||||||
|
|
||||||
|
Topic branches are used by developers to perform and record work on issues.
|
||||||
|
|
||||||
|
Topic branches need not necessarily be stable, even when pushed to the
|
||||||
|
central repository; in fact, the practice of making incremental commits
|
||||||
|
while working on an issue and pushing these to the central repository is
|
||||||
|
encouraged, to avoid lost work and to share work-in-progress. (Small commits
|
||||||
|
also help isolate changes, which can help in identifying which change
|
||||||
|
introduced a defect, particularly when that defect went unnoticed for some
|
||||||
|
time, e.g. using `git bisect`.)
|
||||||
|
|
||||||
|
Topic branches should be named according to their corresponding issue
|
||||||
|
identifiers, all lower case, without hyphens. (e.g. branch mct9 would refer
|
||||||
|
to issue #9.)
|
||||||
|
|
||||||
|
In some cases, work on an issue may warrant the use of multiple divergent
|
||||||
|
branches; for instance, when a developer wants to try more than one solution
|
||||||
|
and compare them, or when a "dead end" is reached and an initial approach to
|
||||||
|
resolving an issue needs to be abandoned. In these cases, a short suffix
|
||||||
|
should be added to the additional branches; this may be simply a single
|
||||||
|
character (e.g. wtd481b) or, where useful, a descriptive term for what
|
||||||
|
distinguishes the branches (e.g. wtd481verbose). It is the responsibility of
|
||||||
|
the author to communicate which branch is intended to be merged to both the
|
||||||
|
reviewer and the integrator.
|
||||||
|
|
||||||
|
#### Developer Branches
|
||||||
|
|
||||||
|
Developer branches are any branches used for purposes outside of the scope
|
||||||
|
of the above; e.g. to try things out, or maintain a "my latest stuff"
|
||||||
|
branch that is not delayed by the review and integration process. These
|
||||||
|
may be pushed to the central repository, and may follow any naming convention
|
||||||
|
desired so long as the owner of the branch is identifiable, and so long as
|
||||||
|
the name chosen could not be mistaken for a topic or master branch.
|
||||||
|
|
||||||
|
### Merging
|
||||||
|
|
||||||
|
When development is complete on an issue, the first step toward merging it
|
||||||
|
back into the master branch is to file a Pull Request. The contributions
|
||||||
|
should meet code, test, and commit message standards as described below,
|
||||||
|
and the pull request should include a completed author checklist, also
|
||||||
|
as described below. Pull requests may be assigned to specific team
|
||||||
|
members when appropriate (e.g. to draw to a specific person's attention.)
|
||||||
|
|
||||||
|
Code review should take place using discussion features within the pull
|
||||||
|
request. When the reviewer is satisfied, they should add a comment to
|
||||||
|
the pull request containing the reviewer checklist (from below) and complete
|
||||||
|
the merge back to the master branch.
|
||||||
|
|
||||||
|
## Standards
|
||||||
|
|
||||||
|
Contributions to Open MCT Web are expected to meet the following standards.
|
||||||
|
In addition, reviewers should use general discretion before accepting
|
||||||
|
changes.
|
||||||
|
|
||||||
|
### Code Standards
|
||||||
|
|
||||||
|
JavaScript sources in Open MCT Web must satisfy JSLint under its default
|
||||||
|
settings. This is verified by the command line build.
|
||||||
|
|
||||||
|
#### Code Guidelines
|
||||||
|
|
||||||
|
JavaScript sources in Open MCT Web should:
|
||||||
|
|
||||||
|
* Use four spaces for indentation. Tabs should not be used.
|
||||||
|
* Include JSDoc for any exposed API (e.g. public methods, constructors.)
|
||||||
|
* Include non-JSDoc comments as-needed for explaining private variables,
|
||||||
|
methods, or algorithms when they are non-obvious.
|
||||||
|
* Define one public class per script, expressed as a constructor function
|
||||||
|
returned from an AMD-style module.
|
||||||
|
* Follow “Java-like” naming conventions. These includes:
|
||||||
|
* Classes should use camel case, first letter capitalized
|
||||||
|
(e.g. SomeClassName.)
|
||||||
|
* Methods, variables, fields, and function names should use camel case,
|
||||||
|
first letter lower-case (e.g. someVariableName.) Constants
|
||||||
|
(variables or fields which are meant to be declared and initialized
|
||||||
|
statically, and never changed) should use only capital letters, with
|
||||||
|
underscores between words (e.g. SOME_CONSTANT.)
|
||||||
|
* File name should be the name of the exported class, plus a .js extension
|
||||||
|
(e.g. SomeClassName.js)
|
||||||
|
* Avoid anonymous functions, except when functions are short (a few lines)
|
||||||
|
and/or their inclusion makes sense within the flow of the code
|
||||||
|
(e.g. as arguments to a forEach call.)
|
||||||
|
* Avoid deep nesting (especially of functions), except where necessary
|
||||||
|
(e.g. due to closure scope.)
|
||||||
|
* End with a single new-line character.
|
||||||
|
* Expose public methods by declaring them on the class's prototype.
|
||||||
|
* Within a given function's scope, do not mix declarations and imperative
|
||||||
|
code, and present these in the following order:
|
||||||
|
* First, variable declarations and initialization.
|
||||||
|
* Second, function declarations.
|
||||||
|
* Third, imperative statements.
|
||||||
|
* Finally, the returned value.
|
||||||
|
|
||||||
|
Deviations from Open MCT Web code style guidelines require two-party agreement,
|
||||||
|
typically from the author of the change and its reviewer.
|
||||||
|
|
||||||
|
#### Code Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundles should declare themselves as namespaces in whichever source
|
||||||
|
* file is most like the "main point of entry" to the bundle.
|
||||||
|
* @namespace some/bundle
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
['./OtherClass'],
|
||||||
|
function (OtherClass) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summary of how to use this class goes here.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @memberof some/bundle
|
||||||
|
*/
|
||||||
|
function ExampleClass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods which are not intended for external use should
|
||||||
|
// not have JSDoc (or should be marked @private)
|
||||||
|
ExampleClass.prototype.privateMethod = function () {
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summary of this method goes here.
|
||||||
|
* @param {number} n a parameter
|
||||||
|
* @returns {number} a return value
|
||||||
|
*/
|
||||||
|
ExampleClass.prototype.publicMethod = function (n) {
|
||||||
|
return n * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExampleClass;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Standards
|
||||||
|
|
||||||
|
Automated testing shall occur whenever changes are merged into the main
|
||||||
|
development branch and must be confirmed alongside any pull request.
|
||||||
|
|
||||||
|
Automated tests are typically unit 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.
|
||||||
|
|
||||||
|
Examples of useful tests:
|
||||||
|
* Tests which replicate bugs (or their root causes) to verify their
|
||||||
|
resolution.
|
||||||
|
* Tests which reflect details from software specifications.
|
||||||
|
* Tests which exercise edge or corner cases among inputs.
|
||||||
|
* Tests which verify expected interactions with other components in the
|
||||||
|
system.
|
||||||
|
|
||||||
|
During automated testing, code coverage metrics will be reported. Line
|
||||||
|
coverage must remain at or above 80%.
|
||||||
|
|
||||||
|
### Commit Message Standards
|
||||||
|
|
||||||
|
Commit messages should:
|
||||||
|
|
||||||
|
* Contain a one-line subject, followed by one line of white space,
|
||||||
|
followed by one or more descriptive paragraphs, each separated by one
|
||||||
|
 line of white space.
|
||||||
|
* Contain a short (usually one word) reference to the feature or subsystem
|
||||||
|
the commit effects, in square brackets, at the start of the subject line
|
||||||
|
(e.g. `[Documentation] Draft of check-in process`)
|
||||||
|
* Contain a reference to a relevant issue number in the body of the commit.
|
||||||
|
* This is important for traceability; while branch names also provide this,
|
||||||
|
you cannot tell from looking at a commit what branch it was authored on.
|
||||||
|
* Describe the change that was made, and any useful rationale therefore.
|
||||||
|
* Comments in code should explain what things do, commit messages describe
|
||||||
|
how they came to be done that way.
|
||||||
|
* Provide sufficient information for a reviewer to understand the changes
|
||||||
|
made and their relationship to previous code.
|
||||||
|
|
||||||
|
Commit messages should not:
|
||||||
|
|
||||||
|
* Exceed 54 characters in length on the subject line.
|
||||||
|
* Exceed 72 characters in length in the body of the commit.
|
||||||
|
* Except where necessary to maintain the structure of machine-readable or
|
||||||
|
machine-generated text (e.g. error messages)
|
||||||
|
|
||||||
|
See [Contributing to a Project](http://git-scm.com/book/ch5-2.html) from
|
||||||
|
Pro Git by Shawn Chacon and Ben Straub for a bit of the rationale behind
|
||||||
|
these standards.
|
||||||
|
|
||||||
|
## Issue Reporting
|
||||||
|
|
||||||
|
Issues are tracked at https://github.com/nasa/openmctweb/issues
|
||||||
|
|
||||||
|
Issues should include:
|
||||||
|
|
||||||
|
* A short description of the issue encountered.
|
||||||
|
* A longer-form description of the issue encountered. When possible, steps to
|
||||||
|
reproduce the issue.
|
||||||
|
* When possible, a description of the impact of the issue. What use case does
|
||||||
|
it impede?
|
||||||
|
* An assessment of the severity of the issue.
|
||||||
|
|
||||||
|
Issue severity is categorized as follows (in ascending order):
|
||||||
|
|
||||||
|
* _Trivial_: Minimal impact on the usefulness and functionality of the
|
||||||
|
software; a "nice-to-have."
|
||||||
|
* _(Unspecified)_: Major loss of functionality or impairment of use.
|
||||||
|
* _Critical_: Large-scale loss of functionality or impairment of use,
|
||||||
|
such that remaining utility becomes marginal.
|
||||||
|
* _Blocker_: Harmful or otherwise unacceptable behavior. Must fix.
|
||||||
|
|
||||||
|
## Check Lists
|
||||||
|
|
||||||
|
The following check lists should be completed and attached to pull requests
|
||||||
|
when they are filed (author checklist) and when they are merged (reviewer
|
||||||
|
checklist.)
|
||||||
|
|
||||||
|
### Author 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?
|
||||||
|
|
||||||
|
### Reviewer Checklist
|
||||||
|
|
||||||
|
1. Changes appear to address issue?
|
||||||
|
2. Appropriate unit tests included?
|
||||||
|
3. Code style and in-line documentation are appropriate?
|
||||||
|
4. Commit messages meet standards?
|
10
jsdoc.json
10
jsdoc.json
@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"source": {
|
"source": {
|
||||||
"include": [
|
"include": [
|
||||||
"example/",
|
|
||||||
"platform/"
|
"platform/"
|
||||||
],
|
],
|
||||||
"includePattern": "(example|platform)/.+\\.js$",
|
"includePattern": "platform/.+\\.js$",
|
||||||
"excludePattern": ".+\\Spec\\.js$|lib/.+"
|
"excludePattern": ".+\\Spec\\.js$|lib/.+"
|
||||||
}
|
},
|
||||||
}
|
"plugins": [
|
||||||
|
"plugins/markdown"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements Open MCT Web's About dialog.
|
||||||
|
* @namespace platform/commonUI/about
|
||||||
|
*/
|
||||||
define(
|
define(
|
||||||
[],
|
[],
|
||||||
function () {
|
function () {
|
||||||
@ -29,35 +34,36 @@ define(
|
|||||||
/**
|
/**
|
||||||
* The AboutController provides information to populate the
|
* The AboutController provides information to populate the
|
||||||
* About dialog.
|
* About dialog.
|
||||||
|
* @memberof platform/commonUI/about
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {object[]} versions an array of version extensions;
|
* @param {object[]} versions an array of version extensions;
|
||||||
* injected from `versions[]`
|
* injected from `versions[]`
|
||||||
* @param $window Angular-injected window object
|
* @param $window Angular-injected window object
|
||||||
*/
|
*/
|
||||||
function AboutController(versions, $window) {
|
function AboutController(versions, $window) {
|
||||||
return {
|
this.versionDefinitions = versions;
|
||||||
/**
|
this.$window = $window;
|
||||||
* Get version info. This is given as an array of
|
|
||||||
* objects, where each object is intended to appear
|
|
||||||
* as a line-item in the version information listing.
|
|
||||||
* @memberof AboutController#
|
|
||||||
* @returns {object[]} version information
|
|
||||||
*/
|
|
||||||
versions: function () {
|
|
||||||
return versions;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Open a new window (or tab, depending on browser
|
|
||||||
* configuration) containing open source licenses.
|
|
||||||
* @memberof AboutController#
|
|
||||||
*/
|
|
||||||
openLicenses: function () {
|
|
||||||
// Open a new browser window at the licenses route
|
|
||||||
$window.open("#/licenses");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get version info. This is given as an array of
|
||||||
|
* objects, where each object is intended to appear
|
||||||
|
* as a line-item in the version information listing.
|
||||||
|
* @returns {object[]} version information
|
||||||
|
*/
|
||||||
|
AboutController.prototype.versions = function () {
|
||||||
|
return this.versionDefinitions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new window (or tab, depending on browser
|
||||||
|
* configuration) containing open source licenses.
|
||||||
|
*/
|
||||||
|
AboutController.prototype.openLicenses = function () {
|
||||||
|
// Open a new browser window at the licenses route
|
||||||
|
this.$window.open("#/licenses");
|
||||||
|
};
|
||||||
|
|
||||||
return AboutController;
|
return AboutController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -29,20 +29,22 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Provides extension-introduced licenses information to the
|
* Provides extension-introduced licenses information to the
|
||||||
* licenses route.
|
* licenses route.
|
||||||
|
* @memberof platform/commonUI/about
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function LicenseController(licenses) {
|
function LicenseController(licenses) {
|
||||||
return {
|
this.licenseDefinitions = licenses;
|
||||||
/**
|
|
||||||
* Get license information.
|
|
||||||
* @returns {Array} license extensions
|
|
||||||
*/
|
|
||||||
licenses: function () {
|
|
||||||
return licenses;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get license information.
|
||||||
|
* @returns {Array} license extensions
|
||||||
|
* @memberof platform/commonUI/about.LicenseController#
|
||||||
|
*/
|
||||||
|
LicenseController.prototype.licenses = function () {
|
||||||
|
return this.licenseDefinitions;
|
||||||
|
};
|
||||||
|
|
||||||
return LicenseController;
|
return LicenseController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -29,21 +29,23 @@ define(
|
|||||||
/**
|
/**
|
||||||
* The LogoController provides functionality to the application
|
* The LogoController provides functionality to the application
|
||||||
* logo in the bottom-right of the user interface.
|
* logo in the bottom-right of the user interface.
|
||||||
|
* @memberof platform/commonUI/about
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {OverlayService} overlayService the overlay service
|
* @param {OverlayService} overlayService the overlay service
|
||||||
*/
|
*/
|
||||||
function LogoController(overlayService) {
|
function LogoController(overlayService) {
|
||||||
return {
|
this.overlayService = overlayService;
|
||||||
/**
|
|
||||||
* Display the About dialog.
|
|
||||||
* @memberof LogoController#
|
|
||||||
*/
|
|
||||||
showAboutDialog: function () {
|
|
||||||
overlayService.createOverlay("overlay-about");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the About dialog.
|
||||||
|
* @memberof LogoController#
|
||||||
|
* @memberof platform/commonUI/about.LogoController#
|
||||||
|
*/
|
||||||
|
LogoController.prototype.showAboutDialog = function () {
|
||||||
|
this.overlayService.createOverlay("overlay-about");
|
||||||
|
};
|
||||||
|
|
||||||
return LogoController;
|
return LogoController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -28,7 +28,15 @@
|
|||||||
>
|
>
|
||||||
<mct-representation key="'create-button'" mct-object="navigatedObject">
|
<mct-representation key="'create-button'" mct-object="navigatedObject">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
<div class='holder tree-holder abs'>
|
<div class='holder search-holder abs'
|
||||||
|
ng-class="{active: treeModel.search}">
|
||||||
|
<mct-representation key="'search'"
|
||||||
|
mct-object="domainObject"
|
||||||
|
ng-model="treeModel">
|
||||||
|
</mct-representation>
|
||||||
|
</div>
|
||||||
|
<div class='holder tree-holder abs'
|
||||||
|
ng-hide="treeModel.search">
|
||||||
<mct-representation key="'tree'"
|
<mct-representation key="'tree'"
|
||||||
mct-object="domainObject"
|
mct-object="domainObject"
|
||||||
ng-model="treeModel">
|
ng-model="treeModel">
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
/*global define,Promise*/
|
/*global define,Promise*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module defining BrowseController. Created by vwoeltje on 11/7/14.
|
* This bundle implements Browse mode.
|
||||||
|
* @namespace platform/commonUI/browse
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
[],
|
[],
|
||||||
@ -39,6 +40,7 @@ define(
|
|||||||
* which Angular templates first have access to the domain object
|
* which Angular templates first have access to the domain object
|
||||||
* hierarchy.
|
* hierarchy.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function BrowseController($scope, $route, $location, objectService, navigationService, urlService) {
|
function BrowseController($scope, $route, $location, objectService, navigationService, urlService) {
|
||||||
@ -157,3 +159,4 @@ define(
|
|||||||
return BrowseController;
|
return BrowseController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Controller for the `browse-object` representation of a domain
|
* Controller for the `browse-object` representation of a domain
|
||||||
* object (the right-hand side of Browse mode.)
|
* object (the right-hand side of Browse mode.)
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function BrowseObjectController($scope, $location, $route) {
|
function BrowseObjectController($scope, $location, $route) {
|
||||||
@ -71,3 +72,4 @@ define(
|
|||||||
return BrowseObjectController;
|
return BrowseObjectController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -33,19 +33,29 @@ define(
|
|||||||
* A left-click on the menu arrow should display a
|
* A left-click on the menu arrow should display a
|
||||||
* context menu. This controller launches the context
|
* context menu. This controller launches the context
|
||||||
* menu.
|
* menu.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function MenuArrowController($scope) {
|
function MenuArrowController($scope) {
|
||||||
function showMenu(event) {
|
this.$scope = $scope;
|
||||||
var actionContext = {key: 'menu', domainObject: $scope.domainObject, event: event};
|
|
||||||
$scope.domainObject.getCapability('action').perform(actionContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
showMenu: showMenu
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a context menu for the domain object in this scope.
|
||||||
|
*
|
||||||
|
* @param event the browser event which caused this (used to
|
||||||
|
* position the menu)
|
||||||
|
*/
|
||||||
|
MenuArrowController.prototype.showMenu = function (event) {
|
||||||
|
var actionContext = {
|
||||||
|
key: 'menu',
|
||||||
|
domainObject: this.$scope.domainObject,
|
||||||
|
event: event
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$scope.domainObject.getCapability('action').perform(actionContext);
|
||||||
|
};
|
||||||
|
|
||||||
return MenuArrowController;
|
return MenuArrowController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -34,7 +34,10 @@ define(
|
|||||||
* domain objects of a specific type. This is the action that
|
* domain objects of a specific type. This is the action that
|
||||||
* is performed when a user uses the Create menu.
|
* is performed when a user uses the Create menu.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
|
* @implements {Action}
|
||||||
* @constructor
|
* @constructor
|
||||||
|
*
|
||||||
* @param {Type} type the type of domain object to create
|
* @param {Type} type the type of domain object to create
|
||||||
* @param {DomainObject} parent the domain object that should
|
* @param {DomainObject} parent the domain object that should
|
||||||
* act as a container for the newly-created object
|
* act as a container for the newly-created object
|
||||||
@ -49,78 +52,84 @@ define(
|
|||||||
* of the newly-created domain object
|
* of the newly-created domain object
|
||||||
*/
|
*/
|
||||||
function CreateAction(type, parent, context, dialogService, creationService, policyService) {
|
function CreateAction(type, parent, context, dialogService, creationService, policyService) {
|
||||||
|
this.metadata = {
|
||||||
|
key: 'create',
|
||||||
|
glyph: type.getGlyph(),
|
||||||
|
name: type.getName(),
|
||||||
|
type: type.getKey(),
|
||||||
|
description: type.getDescription(),
|
||||||
|
context: context
|
||||||
|
};
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
this.parent = parent;
|
||||||
|
this.policyService = policyService;
|
||||||
|
this.dialogService = dialogService;
|
||||||
|
this.creationService = creationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new object of the given type.
|
||||||
|
* This will prompt for user input first.
|
||||||
|
*/
|
||||||
|
CreateAction.prototype.perform = function () {
|
||||||
/*
|
/*
|
||||||
Overview of steps in object creation:
|
Overview of steps in object creation:
|
||||||
|
|
||||||
1. Show dialog
|
1. Show dialog
|
||||||
a. Prepare dialog contents
|
a. Prepare dialog contents
|
||||||
b. Invoke dialogService
|
b. Invoke dialogService
|
||||||
2. Create new object in persistence service
|
2. Create new object in persistence service
|
||||||
a. Generate UUID
|
a. Generate UUID
|
||||||
b. Store model
|
b. Store model
|
||||||
3. Mutate destination container
|
3. Mutate destination container
|
||||||
a. Get mutation capability
|
a. Get mutation capability
|
||||||
b. Add new id to composition
|
b. Add new id to composition
|
||||||
4. Persist destination container
|
4. Persist destination container
|
||||||
a. ...use persistence capability.
|
a. ...use persistence capability.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function perform() {
|
// The wizard will handle creating the form model based
|
||||||
// The wizard will handle creating the form model based
|
// on the type...
|
||||||
// on the type...
|
var wizard =
|
||||||
var wizard = new CreateWizard(type, parent, policyService);
|
new CreateWizard(this.type, this.parent, this.policyService),
|
||||||
|
self = this;
|
||||||
|
|
||||||
// Create and persist the new object, based on user
|
// Create and persist the new object, based on user
|
||||||
// input.
|
// input.
|
||||||
function persistResult(formValue) {
|
function persistResult(formValue) {
|
||||||
var parent = wizard.getLocation(formValue),
|
var parent = wizard.getLocation(formValue),
|
||||||
newModel = wizard.createModel(formValue);
|
newModel = wizard.createModel(formValue);
|
||||||
return creationService.createObject(newModel, parent);
|
return self.creationService.createObject(newModel, parent);
|
||||||
}
|
|
||||||
|
|
||||||
function doNothing() {
|
|
||||||
// Create cancelled, do nothing
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialogService.getUserInput(
|
|
||||||
wizard.getFormStructure(),
|
|
||||||
wizard.getInitialFormValue()
|
|
||||||
).then(persistResult, doNothing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
function doNothing() {
|
||||||
/**
|
// Create cancelled, do nothing
|
||||||
* Create a new object of the given type.
|
return false;
|
||||||
* This will prompt for user input first.
|
}
|
||||||
* @method
|
|
||||||
* @memberof CreateAction
|
|
||||||
*/
|
|
||||||
perform: perform,
|
|
||||||
|
|
||||||
/**
|
return this.dialogService.getUserInput(
|
||||||
* Get metadata about this action. This includes fields:
|
wizard.getFormStructure(),
|
||||||
* * `name`: Human-readable name
|
wizard.getInitialFormValue()
|
||||||
* * `key`: Machine-readable identifier ("create")
|
).then(persistResult, doNothing);
|
||||||
* * `glyph`: Glyph to use as an icon for this action
|
};
|
||||||
* * `description`: Human-readable description
|
|
||||||
* * `context`: The context in which this action will be performed.
|
|
||||||
*
|
/**
|
||||||
* @return {object} metadata about the create action
|
* Metadata associated with a Create action.
|
||||||
*/
|
* @typedef {ActionMetadata} CreateActionMetadata
|
||||||
getMetadata: function () {
|
* @property {string} type the key for the type of domain object
|
||||||
return {
|
* to be created
|
||||||
key: 'create',
|
*/
|
||||||
glyph: type.getGlyph(),
|
|
||||||
name: type.getName(),
|
/**
|
||||||
type: type.getKey(),
|
* Get metadata about this action.
|
||||||
description: type.getDescription(),
|
* @returns {CreateActionMetadata} metadata about this action
|
||||||
context: context
|
*/
|
||||||
};
|
CreateAction.prototype.getMetadata = function () {
|
||||||
}
|
return this.metadata;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return CreateAction;
|
return CreateAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -33,7 +33,10 @@ define(
|
|||||||
* The CreateActionProvider is an ActionProvider which introduces
|
* The CreateActionProvider is an ActionProvider which introduces
|
||||||
* a Create action for each creatable domain object type.
|
* a Create action for each creatable domain object type.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {ActionService}
|
||||||
|
*
|
||||||
* @param {TypeService} typeService the type service, used to discover
|
* @param {TypeService} typeService the type service, used to discover
|
||||||
* available types
|
* available types
|
||||||
* @param {DialogService} dialogService the dialog service, used by
|
* @param {DialogService} dialogService the dialog service, used by
|
||||||
@ -44,44 +47,41 @@ define(
|
|||||||
* object creation.
|
* object creation.
|
||||||
*/
|
*/
|
||||||
function CreateActionProvider(typeService, dialogService, creationService, policyService) {
|
function CreateActionProvider(typeService, dialogService, creationService, policyService) {
|
||||||
return {
|
this.typeService = typeService;
|
||||||
/**
|
this.dialogService = dialogService;
|
||||||
* Get all Create actions which are applicable in the provided
|
this.creationService = creationService;
|
||||||
* context.
|
this.policyService = policyService;
|
||||||
* @memberof CreateActionProvider
|
|
||||||
* @method
|
|
||||||
* @returns {CreateAction[]}
|
|
||||||
*/
|
|
||||||
getActions: function (actionContext) {
|
|
||||||
var context = actionContext || {},
|
|
||||||
key = context.key,
|
|
||||||
destination = context.domainObject;
|
|
||||||
|
|
||||||
// We only provide Create actions, and we need a
|
|
||||||
// domain object to serve as the container for the
|
|
||||||
// newly-created object (although the user may later
|
|
||||||
// make a different selection)
|
|
||||||
if (key !== 'create' || !destination) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Introduce one create action per type
|
|
||||||
return typeService.listTypes().filter(function (type) {
|
|
||||||
return type.hasFeature("creation");
|
|
||||||
}).map(function (type) {
|
|
||||||
return new CreateAction(
|
|
||||||
type,
|
|
||||||
destination,
|
|
||||||
context,
|
|
||||||
dialogService,
|
|
||||||
creationService,
|
|
||||||
policyService
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreateActionProvider.prototype.getActions = function (actionContext) {
|
||||||
|
var context = actionContext || {},
|
||||||
|
key = context.key,
|
||||||
|
destination = context.domainObject,
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
// We only provide Create actions, and we need a
|
||||||
|
// domain object to serve as the container for the
|
||||||
|
// newly-created object (although the user may later
|
||||||
|
// make a different selection)
|
||||||
|
if (key !== 'create' || !destination) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Introduce one create action per type
|
||||||
|
return this.typeService.listTypes().filter(function (type) {
|
||||||
|
return type.hasFeature("creation");
|
||||||
|
}).map(function (type) {
|
||||||
|
return new CreateAction(
|
||||||
|
type,
|
||||||
|
destination,
|
||||||
|
context,
|
||||||
|
self.dialogService,
|
||||||
|
self.creationService,
|
||||||
|
self.policyService
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return CreateActionProvider;
|
return CreateActionProvider;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -34,6 +34,7 @@ define(
|
|||||||
* set of Create actions based on the currently-selected
|
* set of Create actions based on the currently-selected
|
||||||
* domain object.
|
* domain object.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CreateMenuController($scope) {
|
function CreateMenuController($scope) {
|
||||||
@ -55,4 +56,4 @@ define(
|
|||||||
|
|
||||||
return CreateMenuController;
|
return CreateMenuController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -21,12 +21,6 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the CreateWizard, used by the CreateAction to
|
|
||||||
* populate the form shown in dialog based on the created type.
|
|
||||||
*
|
|
||||||
* @module core/action/create-wizard
|
|
||||||
*/
|
|
||||||
define(
|
define(
|
||||||
function () {
|
function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -37,113 +31,118 @@ define(
|
|||||||
* @param {TypeImpl} type the type of domain object to be created
|
* @param {TypeImpl} type the type of domain object to be created
|
||||||
* @param {DomainObject} parent the domain object to serve as
|
* @param {DomainObject} parent the domain object to serve as
|
||||||
* the initial parent for the created object, in the dialog
|
* the initial parent for the created object, in the dialog
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
* @memberof module:core/action/create-wizard
|
|
||||||
*/
|
*/
|
||||||
function CreateWizard(type, parent, policyService) {
|
function CreateWizard(type, parent, policyService) {
|
||||||
var model = type.getInitialModel(),
|
this.type = type;
|
||||||
properties = type.getProperties();
|
this.model = type.getInitialModel();
|
||||||
|
this.properties = type.getProperties();
|
||||||
|
this.parent = parent;
|
||||||
|
this.policyService = policyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the form model for this wizard; this is a description
|
||||||
|
* that will be rendered to an HTML form. See the
|
||||||
|
* platform/forms bundle
|
||||||
|
*
|
||||||
|
* @return {FormModel} formModel the form model to
|
||||||
|
* show in the create dialog
|
||||||
|
*/
|
||||||
|
CreateWizard.prototype.getFormStructure = function () {
|
||||||
|
var sections = [],
|
||||||
|
type = this.type,
|
||||||
|
policyService = this.policyService;
|
||||||
|
|
||||||
function validateLocation(locatingObject) {
|
function validateLocation(locatingObject) {
|
||||||
var locatingType = locatingObject &&
|
var locatingType = locatingObject &&
|
||||||
locatingObject.getCapability('type');
|
locatingObject.getCapability('type');
|
||||||
return locatingType && policyService.allow(
|
return locatingType && policyService.allow(
|
||||||
"composition",
|
"composition",
|
||||||
locatingType,
|
locatingType,
|
||||||
type
|
type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sections.push({
|
||||||
|
name: "Properties",
|
||||||
|
rows: this.properties.map(function (property, index) {
|
||||||
|
// Property definition is same as form row definition
|
||||||
|
var row = Object.create(property.getDefinition());
|
||||||
|
|
||||||
|
// Use index as the key into the formValue;
|
||||||
|
// this correlates to the indexing provided by
|
||||||
|
// getInitialFormValue
|
||||||
|
row.key = index;
|
||||||
|
|
||||||
|
return row;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure there is always a "save in" section
|
||||||
|
sections.push({ name: 'Location', rows: [{
|
||||||
|
name: "Save In",
|
||||||
|
control: "locator",
|
||||||
|
validate: validateLocation,
|
||||||
|
key: "createParent"
|
||||||
|
}]});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
sections: sections,
|
||||||
* Get the form model for this wizard; this is a description
|
name: "Create a New " + this.type.getName()
|
||||||
* that will be rendered to an HTML form. See the
|
|
||||||
* platform/forms bundle
|
|
||||||
*
|
|
||||||
* @return {FormModel} formModel the form model to
|
|
||||||
* show in the create dialog
|
|
||||||
*/
|
|
||||||
getFormStructure: function () {
|
|
||||||
var sections = [];
|
|
||||||
|
|
||||||
sections.push({
|
|
||||||
name: "Properties",
|
|
||||||
rows: properties.map(function (property, index) {
|
|
||||||
// Property definition is same as form row definition
|
|
||||||
var row = Object.create(property.getDefinition());
|
|
||||||
|
|
||||||
// Use index as the key into the formValue;
|
|
||||||
// this correlates to the indexing provided by
|
|
||||||
// getInitialFormValue
|
|
||||||
row.key = index;
|
|
||||||
|
|
||||||
return row;
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure there is always a "save in" section
|
|
||||||
sections.push({ name: 'Location', rows: [{
|
|
||||||
name: "Save In",
|
|
||||||
control: "locator",
|
|
||||||
validate: validateLocation,
|
|
||||||
key: "createParent"
|
|
||||||
}]});
|
|
||||||
|
|
||||||
return {
|
|
||||||
sections: sections,
|
|
||||||
name: "Create a New " + type.getName()
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the initial value for the form being described.
|
|
||||||
* This will include the values for all properties described
|
|
||||||
* in the structure.
|
|
||||||
*
|
|
||||||
* @returns {object} the initial value of the form
|
|
||||||
*/
|
|
||||||
getInitialFormValue: function () {
|
|
||||||
// Start with initial values for properties
|
|
||||||
var formValue = properties.map(function (property) {
|
|
||||||
return property.getValue(model);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Include the createParent
|
|
||||||
formValue.createParent = parent;
|
|
||||||
|
|
||||||
return formValue;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Based on a populated form, get the domain object which
|
|
||||||
* should be used as a parent for the newly-created object.
|
|
||||||
* @return {DomainObject}
|
|
||||||
*/
|
|
||||||
getLocation: function (formValue) {
|
|
||||||
return formValue.createParent || parent;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Create the domain object model for a newly-created object,
|
|
||||||
* based on user input read from a formModel.
|
|
||||||
* @return {object} the domain object' model
|
|
||||||
*/
|
|
||||||
createModel: function (formValue) {
|
|
||||||
// Clone
|
|
||||||
var newModel = JSON.parse(JSON.stringify(model));
|
|
||||||
|
|
||||||
// Always use the type from the type definition
|
|
||||||
newModel.type = type.getKey();
|
|
||||||
|
|
||||||
// Update all properties
|
|
||||||
properties.forEach(function (property, index) {
|
|
||||||
property.setValue(newModel, formValue[index]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return newModel;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the initial value for the form being described.
|
||||||
|
* This will include the values for all properties described
|
||||||
|
* in the structure.
|
||||||
|
*
|
||||||
|
* @returns {object} the initial value of the form
|
||||||
|
*/
|
||||||
|
CreateWizard.prototype.getInitialFormValue = function () {
|
||||||
|
// Start with initial values for properties
|
||||||
|
var model = this.model,
|
||||||
|
formValue = this.properties.map(function (property) {
|
||||||
|
return property.getValue(model);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
// Include the createParent
|
||||||
|
formValue.createParent = this.parent;
|
||||||
|
|
||||||
|
return formValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on a populated form, get the domain object which
|
||||||
|
* should be used as a parent for the newly-created object.
|
||||||
|
* @return {DomainObject}
|
||||||
|
*/
|
||||||
|
CreateWizard.prototype.getLocation = function (formValue) {
|
||||||
|
return formValue.createParent || this.parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the domain object model for a newly-created object,
|
||||||
|
* based on user input read from a formModel.
|
||||||
|
* @return {object} the domain object model
|
||||||
|
*/
|
||||||
|
CreateWizard.prototype.createModel = function (formValue) {
|
||||||
|
// Clone
|
||||||
|
var newModel = JSON.parse(JSON.stringify(this.model));
|
||||||
|
|
||||||
|
// Always use the type from the type definition
|
||||||
|
newModel.type = this.type.getKey();
|
||||||
|
|
||||||
|
// Update all properties
|
||||||
|
this.properties.forEach(function (property, index) {
|
||||||
|
property.setValue(newModel, formValue[index]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return newModel;
|
||||||
|
};
|
||||||
|
|
||||||
return CreateWizard;
|
return CreateWizard;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -39,15 +39,45 @@ define(
|
|||||||
* persisting new domain objects. Handles all actual object
|
* persisting new domain objects. Handles all actual object
|
||||||
* mutation and persistence associated with domain object
|
* mutation and persistence associated with domain object
|
||||||
* creation.
|
* creation.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CreationService(persistenceService, $q, $log) {
|
function CreationService(persistenceService, $q, $log) {
|
||||||
|
this.persistenceService = persistenceService;
|
||||||
|
this.$q = $q;
|
||||||
|
this.$log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new domain object with the provided model, as
|
||||||
|
* a member of the provided parent domain object's composition.
|
||||||
|
* This parent will additionally determine which persistence
|
||||||
|
* space an object is created within (as it is possible to
|
||||||
|
* have multiple persistence spaces attached.)
|
||||||
|
*
|
||||||
|
* @param {object} model the model for the newly-created
|
||||||
|
* domain object
|
||||||
|
* @param {DomainObject} parent the domain object which
|
||||||
|
* should contain the newly-created domain object
|
||||||
|
* in its composition
|
||||||
|
* @return {Promise} a promise that will resolve when the domain
|
||||||
|
* object has been created
|
||||||
|
*/
|
||||||
|
CreationService.prototype.createObject = function (model, parent) {
|
||||||
|
var persistence = parent.getCapability("persistence"),
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
// Store the location of an object relative to it's parent.
|
||||||
|
function addLocationToModel(modelId, model, parent) {
|
||||||
|
model.location = parent.getId();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
// Persist the new domain object's model; it will be fully
|
// Persist the new domain object's model; it will be fully
|
||||||
// constituted as a domain object when loaded back, as all
|
// constituted as a domain object when loaded back, as all
|
||||||
// domain object models are.
|
// domain object models are.
|
||||||
function doPersist(space, id, model) {
|
function doPersist(space, id, model) {
|
||||||
return persistenceService.createObject(
|
return self.persistenceService.createObject(
|
||||||
space,
|
space,
|
||||||
id,
|
id,
|
||||||
model
|
model
|
||||||
@ -66,14 +96,14 @@ define(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is abnormal; composition should be an array
|
// This is abnormal; composition should be an array
|
||||||
$log.warn(NO_COMPOSITION_WARNING + parent.getId());
|
self.$log.warn(NO_COMPOSITION_WARNING + parent.getId());
|
||||||
return false; // Cancel mutation
|
return false; // Cancel mutation
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return $q.when(mutatationResult).then(function (result) {
|
return self.$q.when(mutatationResult).then(function (result) {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
$log.error("Could not mutate " + parent.getId());
|
self.$log.error("Could not mutate " + parent.getId());
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,56 +123,28 @@ define(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the location of an object relative to it's parent.
|
// We need the parent's persistence capability to determine
|
||||||
function addLocationToModel(modelId, model, parent) {
|
// what space to create the new object's model in.
|
||||||
model.location = parent.getId();
|
if (!persistence) {
|
||||||
return model;
|
self.$log.warn(NON_PERSISTENT_WARNING);
|
||||||
|
return self.$q.reject(new Error(NON_PERSISTENT_WARNING));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new domain object with the provided model as a
|
// We create a new domain object in three sequential steps:
|
||||||
// member of the specified parent's composition
|
// 1. Get a new UUID for the object
|
||||||
function createObject(model, parent) {
|
// 2. Create a model with that ID in the persistence space
|
||||||
var persistence = parent.getCapability("persistence");
|
// 3. Add that ID to
|
||||||
|
return self.$q.when(uuid()).then(function (id) {
|
||||||
|
model = addLocationToModel(id, model, parent);
|
||||||
|
return doPersist(persistence.getSpace(), id, model);
|
||||||
|
}).then(function (id) {
|
||||||
|
return addToComposition(id, parent, persistence);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// We need the parent's persistence capability to determine
|
|
||||||
// what space to create the new object's model in.
|
|
||||||
if (!persistence) {
|
|
||||||
$log.warn(NON_PERSISTENT_WARNING);
|
|
||||||
return $q.reject(new Error(NON_PERSISTENT_WARNING));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We create a new domain object in three sequential steps:
|
|
||||||
// 1. Get a new UUID for the object
|
|
||||||
// 2. Create a model with that ID in the persistence space
|
|
||||||
// 3. Add that ID to
|
|
||||||
return $q.when(
|
|
||||||
uuid()
|
|
||||||
).then(function (id) {
|
|
||||||
model = addLocationToModel(id, model, parent);
|
|
||||||
return doPersist(persistence.getSpace(), id, model);
|
|
||||||
}).then(function (id) {
|
|
||||||
return addToComposition(id, parent, persistence);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Create a new domain object with the provided model, as
|
|
||||||
* a member of the provided parent domain object's composition.
|
|
||||||
* This parent will additionally determine which persistence
|
|
||||||
* space an object is created within (as it is possible to
|
|
||||||
* have multiple persistence spaces attached.)
|
|
||||||
*
|
|
||||||
* @param {object} model the model for the newly-created
|
|
||||||
* domain object
|
|
||||||
* @param {DomainObject} parent the domain object which
|
|
||||||
* should contain the newly-created domain object
|
|
||||||
* in its composition
|
|
||||||
*/
|
|
||||||
createObject: createObject
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreationService;
|
return CreationService;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ define(
|
|||||||
* Controller for the "locator" control, which provides the
|
* Controller for the "locator" control, which provides the
|
||||||
* user with the ability to select a domain object as the
|
* user with the ability to select a domain object as the
|
||||||
* destination for a newly-created object in the Create menu.
|
* destination for a newly-created object in the Create menu.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function LocatorController($scope) {
|
function LocatorController($scope) {
|
||||||
@ -79,3 +80,4 @@ define(
|
|||||||
return LocatorController;
|
return LocatorController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -31,32 +31,34 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The navigate action navigates to a specific domain object.
|
* The navigate action navigates to a specific domain object.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function NavigateAction(navigationService, $q, context) {
|
function NavigateAction(navigationService, $q, context) {
|
||||||
var domainObject = context.domainObject;
|
this.domainObject = context.domainObject;
|
||||||
|
this.$q = $q;
|
||||||
function perform() {
|
this.navigationService = navigationService;
|
||||||
// Set navigation, and wrap like a promise
|
|
||||||
return $q.when(navigationService.setNavigation(domainObject));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Navigate to the object described in the context.
|
|
||||||
* @returns {Promise} a promise that is resolved once the
|
|
||||||
* navigation has been updated
|
|
||||||
*/
|
|
||||||
perform: perform
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the object described in the context.
|
||||||
|
* @returns {Promise} a promise that is resolved once the
|
||||||
|
* navigation has been updated
|
||||||
|
*/
|
||||||
|
NavigateAction.prototype.perform = function () {
|
||||||
|
// Set navigation, and wrap like a promise
|
||||||
|
return this.$q.when(
|
||||||
|
this.navigationService.setNavigation(this.domainObject)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate as an action is only applicable when a domain object
|
* Navigate as an action is only applicable when a domain object
|
||||||
* is described in the action context.
|
* is described in the action context.
|
||||||
* @param {ActionContext} context the context in which the action
|
* @param {ActionContext} context the context in which the action
|
||||||
* will be performed
|
* will be performed
|
||||||
* @returns true if applicable
|
* @returns {boolean} true if applicable
|
||||||
*/
|
*/
|
||||||
NavigateAction.appliesTo = function (context) {
|
NavigateAction.appliesTo = function (context) {
|
||||||
return context.domainObject !== undefined;
|
return context.domainObject !== undefined;
|
||||||
@ -64,4 +66,4 @@ define(
|
|||||||
|
|
||||||
return NavigateAction;
|
return NavigateAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -32,68 +32,58 @@ define(
|
|||||||
/**
|
/**
|
||||||
* The navigation service maintains the application's current
|
* The navigation service maintains the application's current
|
||||||
* navigation state, and allows listening for changes thereto.
|
* navigation state, and allows listening for changes thereto.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function NavigationService() {
|
function NavigationService() {
|
||||||
var navigated,
|
this.navigated = undefined;
|
||||||
callbacks = [];
|
this.callbacks = [];
|
||||||
|
}
|
||||||
|
|
||||||
// Getter for current navigation
|
/**
|
||||||
function getNavigation() {
|
* Get the current navigation state.
|
||||||
return navigated;
|
* @returns {DomainObject} the object that is navigated-to
|
||||||
}
|
*/
|
||||||
|
NavigationService.prototype.getNavigation = function () {
|
||||||
|
return this.navigated;
|
||||||
|
};
|
||||||
|
|
||||||
// Setter for navigation; invokes callbacks
|
/**
|
||||||
function setNavigation(value) {
|
* Set the current navigation state. This will invoke listeners.
|
||||||
if (navigated !== value) {
|
* @param {DomainObject} domainObject the domain object to navigate to
|
||||||
navigated = value;
|
*/
|
||||||
callbacks.forEach(function (callback) {
|
NavigationService.prototype.setNavigation = function (value) {
|
||||||
callback(value);
|
if (this.navigated !== value) {
|
||||||
});
|
this.navigated = value;
|
||||||
}
|
this.callbacks.forEach(function (callback) {
|
||||||
}
|
callback(value);
|
||||||
|
|
||||||
// Adds a callback
|
|
||||||
function addListener(callback) {
|
|
||||||
callbacks.push(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filters out a callback
|
|
||||||
function removeListener(callback) {
|
|
||||||
callbacks = callbacks.filter(function (cb) {
|
|
||||||
return cb !== callback;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
/**
|
||||||
/**
|
* Listen for changes in navigation. The passed callback will
|
||||||
* Get the current navigation state.
|
* be invoked with the new domain object of navigation when
|
||||||
*/
|
* this changes.
|
||||||
getNavigation: getNavigation,
|
* @param {function} callback the callback to invoke when
|
||||||
/**
|
* navigation state changes
|
||||||
* Set the current navigation state. Thiswill invoke listeners.
|
*/
|
||||||
* @param {DomainObject} value the domain object to navigate
|
NavigationService.prototype.addListener = function (callback) {
|
||||||
* to
|
this.callbacks.push(callback);
|
||||||
*/
|
};
|
||||||
setNavigation: setNavigation,
|
|
||||||
/**
|
/**
|
||||||
* Listen for changes in navigation. The passed callback will
|
* Stop listening for changes in navigation state.
|
||||||
* be invoked with the new domain object of navigation when
|
* @param {function} callback the callback which should
|
||||||
* this changes.
|
* no longer be invoked when navigation state
|
||||||
* @param {function} callback the callback to invoke when
|
* changes
|
||||||
* navigation state changes
|
*/
|
||||||
*/
|
NavigationService.prototype.removeListener = function (callback) {
|
||||||
addListener: addListener,
|
this.callbacks = this.callbacks.filter(function (cb) {
|
||||||
/**
|
return cb !== callback;
|
||||||
* Stop listening for changes in navigation state.
|
});
|
||||||
* @param {function} callback the callback which should
|
};
|
||||||
* no longer be invoked when navigation state
|
|
||||||
* changes
|
|
||||||
*/
|
|
||||||
removeListener: removeListener
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return NavigationService;
|
return NavigationService;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,36 +35,32 @@ define(
|
|||||||
/**
|
/**
|
||||||
* The fullscreen action toggles between fullscreen display
|
* The fullscreen action toggles between fullscreen display
|
||||||
* and regular in-window display.
|
* and regular in-window display.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function FullscreenAction(context) {
|
function FullscreenAction(context) {
|
||||||
return {
|
this.context = context;
|
||||||
/**
|
|
||||||
* Toggle full screen state
|
|
||||||
*/
|
|
||||||
perform: function () {
|
|
||||||
screenfull.toggle();
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get metadata about this action, including the
|
|
||||||
* applicable glyph to display.
|
|
||||||
*/
|
|
||||||
getMetadata: function () {
|
|
||||||
// We override getMetadata, because the glyph and
|
|
||||||
// description need to be determined at run-time
|
|
||||||
// based on whether or not we are currently
|
|
||||||
// full screen.
|
|
||||||
var metadata = Object.create(FullscreenAction);
|
|
||||||
metadata.glyph = screenfull.isFullscreen ? "_" : "z";
|
|
||||||
metadata.description = screenfull.isFullscreen ?
|
|
||||||
EXIT_FULLSCREEN : ENTER_FULLSCREEN;
|
|
||||||
metadata.group = "windowing";
|
|
||||||
metadata.context = context;
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FullscreenAction.prototype.perform = function () {
|
||||||
|
screenfull.toggle();
|
||||||
|
};
|
||||||
|
|
||||||
|
FullscreenAction.prototype.getMetadata = function () {
|
||||||
|
// We override getMetadata, because the glyph and
|
||||||
|
// description need to be determined at run-time
|
||||||
|
// based on whether or not we are currently
|
||||||
|
// full screen.
|
||||||
|
var metadata = Object.create(FullscreenAction);
|
||||||
|
metadata.glyph = screenfull.isFullscreen ? "_" : "z";
|
||||||
|
metadata.description = screenfull.isFullscreen ?
|
||||||
|
EXIT_FULLSCREEN : ENTER_FULLSCREEN;
|
||||||
|
metadata.group = "windowing";
|
||||||
|
metadata.context = this.context;
|
||||||
|
return metadata;
|
||||||
|
};
|
||||||
|
|
||||||
return FullscreenAction;
|
return FullscreenAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -33,35 +33,29 @@ define(
|
|||||||
/**
|
/**
|
||||||
* The new tab action allows a domain object to be opened
|
* The new tab action allows a domain object to be opened
|
||||||
* into a new browser tab.
|
* into a new browser tab.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function NewTabAction(urlService, $window, context) {
|
function NewTabAction(urlService, $window, context) {
|
||||||
// Returns the selected domain object
|
context = context || {};
|
||||||
// when using the context menu or the top right button
|
|
||||||
// based on the context and the existance of the object
|
this.urlService = urlService;
|
||||||
// It is set to object an returned
|
this.open = function () {
|
||||||
function getSelectedObject() {
|
$window.open.apply($window, arguments);
|
||||||
var object;
|
|
||||||
if (context.selectedObject) {
|
|
||||||
object = context.selectedObject;
|
|
||||||
} else {
|
|
||||||
object = context.domainObject;
|
|
||||||
}
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
// Performs the open in new tab function
|
|
||||||
// By calling the url service, the mode needed
|
|
||||||
// (browse) and the domainObject is passed in and
|
|
||||||
// the path is returned and opened in a new tab
|
|
||||||
perform: function () {
|
|
||||||
$window.open(urlService.urlForNewTab("browse", getSelectedObject()),
|
|
||||||
"_blank");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Choose the object to be opened into a new tab
|
||||||
|
this.domainObject = context.selectedObject || context.domainObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NewTabAction.prototype.perform = function () {
|
||||||
|
this.open(
|
||||||
|
this.urlService.urlForNewTab("browse", this.domainObject),
|
||||||
|
"_blank"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return NewTabAction;
|
return NewTabAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -29,6 +29,7 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Updates the title of the current window to reflect the name
|
* Updates the title of the current window to reflect the name
|
||||||
* of the currently navigated-to domain object.
|
* of the currently navigated-to domain object.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function WindowTitler(navigationService, $rootScope, $document) {
|
function WindowTitler(navigationService, $rootScope, $document) {
|
||||||
@ -49,4 +50,4 @@ define(
|
|||||||
|
|
||||||
return WindowTitler;
|
return WindowTitler;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module defining DialogService. Created by vwoeltje on 11/10/14.
|
* This bundle implements the dialog service, which can be used to
|
||||||
|
* launch dialogs for user input & notifications.
|
||||||
|
* @namespace platform/commonUI/dialog
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
[],
|
[],
|
||||||
@ -32,128 +34,130 @@ define(
|
|||||||
* The dialog service is responsible for handling window-modal
|
* The dialog service is responsible for handling window-modal
|
||||||
* communication with the user, such as displaying forms for user
|
* communication with the user, such as displaying forms for user
|
||||||
* input.
|
* input.
|
||||||
|
* @memberof platform/commonUI/dialog
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function DialogService(overlayService, $q, $log) {
|
function DialogService(overlayService, $q, $log) {
|
||||||
var overlay,
|
this.overlayService = overlayService;
|
||||||
dialogVisible = false;
|
this.$q = $q;
|
||||||
|
this.$log = $log;
|
||||||
// Stop showing whatever overlay is currently active
|
this.overlay = undefined;
|
||||||
// (e.g. because the user hit cancel)
|
this.dialogVisible = false;
|
||||||
function dismiss() {
|
|
||||||
if (overlay) {
|
|
||||||
overlay.dismiss();
|
|
||||||
}
|
|
||||||
dialogVisible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDialogResponse(key, model, resultGetter) {
|
|
||||||
// We will return this result as a promise, because user
|
|
||||||
// input is asynchronous.
|
|
||||||
var deferred = $q.defer(),
|
|
||||||
overlayModel;
|
|
||||||
|
|
||||||
// Confirm function; this will be passed in to the
|
|
||||||
// overlay-dialog template and associated with a
|
|
||||||
// OK button click
|
|
||||||
function confirm(value) {
|
|
||||||
// Pass along the result
|
|
||||||
deferred.resolve(resultGetter ? resultGetter() : value);
|
|
||||||
|
|
||||||
// Stop showing the dialog
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel function; this will be passed in to the
|
|
||||||
// overlay-dialog template and associated with a
|
|
||||||
// Cancel or X button click
|
|
||||||
function cancel() {
|
|
||||||
deferred.reject();
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add confirm/cancel callbacks
|
|
||||||
model.confirm = confirm;
|
|
||||||
model.cancel = cancel;
|
|
||||||
|
|
||||||
if (dialogVisible) {
|
|
||||||
// Only one dialog should be shown at a time.
|
|
||||||
// The application design should be such that
|
|
||||||
// we never even try to do this.
|
|
||||||
$log.warn([
|
|
||||||
"Dialog already showing; ",
|
|
||||||
"unable to show ",
|
|
||||||
model.name
|
|
||||||
].join(""));
|
|
||||||
deferred.reject();
|
|
||||||
} else {
|
|
||||||
// Add the overlay using the OverlayService, which
|
|
||||||
// will handle actual insertion into the DOM
|
|
||||||
overlay = overlayService.createOverlay(
|
|
||||||
key,
|
|
||||||
model
|
|
||||||
);
|
|
||||||
|
|
||||||
// Track that a dialog is already visible, to
|
|
||||||
// avoid spawning multiple dialogs at once.
|
|
||||||
dialogVisible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUserInput(formModel, value) {
|
|
||||||
var overlayModel = {
|
|
||||||
title: formModel.name,
|
|
||||||
message: formModel.message,
|
|
||||||
structure: formModel,
|
|
||||||
value: value
|
|
||||||
};
|
|
||||||
|
|
||||||
// Provide result from the model
|
|
||||||
function resultGetter() {
|
|
||||||
return overlayModel.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the overlay-dialog
|
|
||||||
return getDialogResponse(
|
|
||||||
"overlay-dialog",
|
|
||||||
overlayModel,
|
|
||||||
resultGetter
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUserChoice(dialogModel) {
|
|
||||||
// Show the overlay-options dialog
|
|
||||||
return getDialogResponse(
|
|
||||||
"overlay-options",
|
|
||||||
{ dialog: dialogModel }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Request user input via a window-modal dialog.
|
|
||||||
*
|
|
||||||
* @param {FormModel} formModel a description of the form
|
|
||||||
* to be shown (see platform/forms)
|
|
||||||
* @param {object} value the initial state of the form
|
|
||||||
* @returns {Promise} a promsie for the form value that the
|
|
||||||
* user has supplied; this may be rejected if
|
|
||||||
* user input cannot be obtained (for instance,
|
|
||||||
* because the user cancelled the dialog)
|
|
||||||
*/
|
|
||||||
getUserInput: getUserInput,
|
|
||||||
/**
|
|
||||||
* Request that the user chooses from a set of options,
|
|
||||||
* which will be shown as buttons.
|
|
||||||
*
|
|
||||||
* @param dialogModel a description of the dialog to show
|
|
||||||
*/
|
|
||||||
getUserChoice: getUserChoice
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop showing whatever overlay is currently active
|
||||||
|
// (e.g. because the user hit cancel)
|
||||||
|
DialogService.prototype.dismiss = function () {
|
||||||
|
var overlay = this.overlay;
|
||||||
|
if (overlay) {
|
||||||
|
overlay.dismiss();
|
||||||
|
}
|
||||||
|
this.dialogVisible = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
DialogService.prototype.getDialogResponse = function (key, model, resultGetter) {
|
||||||
|
// We will return this result as a promise, because user
|
||||||
|
// input is asynchronous.
|
||||||
|
var deferred = this.$q.defer(),
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
// Confirm function; this will be passed in to the
|
||||||
|
// overlay-dialog template and associated with a
|
||||||
|
// OK button click
|
||||||
|
function confirm(value) {
|
||||||
|
// Pass along the result
|
||||||
|
deferred.resolve(resultGetter ? resultGetter() : value);
|
||||||
|
|
||||||
|
// Stop showing the dialog
|
||||||
|
self.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel function; this will be passed in to the
|
||||||
|
// overlay-dialog template and associated with a
|
||||||
|
// Cancel or X button click
|
||||||
|
function cancel() {
|
||||||
|
deferred.reject();
|
||||||
|
self.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add confirm/cancel callbacks
|
||||||
|
model.confirm = confirm;
|
||||||
|
model.cancel = cancel;
|
||||||
|
|
||||||
|
if (this.dialogVisible) {
|
||||||
|
// Only one dialog should be shown at a time.
|
||||||
|
// The application design should be such that
|
||||||
|
// we never even try to do this.
|
||||||
|
this.$log.warn([
|
||||||
|
"Dialog already showing; ",
|
||||||
|
"unable to show ",
|
||||||
|
model.name
|
||||||
|
].join(""));
|
||||||
|
deferred.reject();
|
||||||
|
} else {
|
||||||
|
// Add the overlay using the OverlayService, which
|
||||||
|
// will handle actual insertion into the DOM
|
||||||
|
this.overlay = this.overlayService.createOverlay(
|
||||||
|
key,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
// Track that a dialog is already visible, to
|
||||||
|
// avoid spawning multiple dialogs at once.
|
||||||
|
this.dialogVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request user input via a window-modal dialog.
|
||||||
|
*
|
||||||
|
* @param {FormModel} formModel a description of the form
|
||||||
|
* to be shown (see platform/forms)
|
||||||
|
* @param {object} value the initial state of the form
|
||||||
|
* @returns {Promise} a promise for the form value that the
|
||||||
|
* user has supplied; this may be rejected if
|
||||||
|
* user input cannot be obtained (for instance,
|
||||||
|
* because the user cancelled the dialog)
|
||||||
|
*/
|
||||||
|
DialogService.prototype.getUserInput = function (formModel, value) {
|
||||||
|
var overlayModel = {
|
||||||
|
title: formModel.name,
|
||||||
|
message: formModel.message,
|
||||||
|
structure: formModel,
|
||||||
|
value: value
|
||||||
|
};
|
||||||
|
|
||||||
|
// Provide result from the model
|
||||||
|
function resultGetter() {
|
||||||
|
return overlayModel.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the overlay-dialog
|
||||||
|
return this.getDialogResponse(
|
||||||
|
"overlay-dialog",
|
||||||
|
overlayModel,
|
||||||
|
resultGetter
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request that the user chooses from a set of options,
|
||||||
|
* which will be shown as buttons.
|
||||||
|
*
|
||||||
|
* @param dialogModel a description of the dialog to show
|
||||||
|
* @return {Promise} a promise for the user's choice
|
||||||
|
*/
|
||||||
|
DialogService.prototype.getUserChoice = function (dialogModel) {
|
||||||
|
// Show the overlay-options dialog
|
||||||
|
return this.getDialogResponse(
|
||||||
|
"overlay-options",
|
||||||
|
{ dialog: dialogModel }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return DialogService;
|
return DialogService;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -43,57 +43,63 @@ define(
|
|||||||
* particularly where a multiple-overlay effect is not specifically
|
* particularly where a multiple-overlay effect is not specifically
|
||||||
* desired).
|
* desired).
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/dialog
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function OverlayService($document, $compile, $rootScope) {
|
function OverlayService($document, $compile, $rootScope) {
|
||||||
function createOverlay(key, overlayModel) {
|
this.$compile = $compile;
|
||||||
// Create a new scope for this overlay
|
|
||||||
var scope = $rootScope.$new(),
|
|
||||||
element;
|
|
||||||
|
|
||||||
// Stop showing the overlay; additionally, release the scope
|
// Don't include $document and $rootScope directly;
|
||||||
// that it uses.
|
// avoids https://docs.angularjs.org/error/ng/cpws
|
||||||
function dismiss() {
|
this.findBody = function () {
|
||||||
scope.$destroy();
|
return $document.find('body');
|
||||||
element.remove();
|
};
|
||||||
}
|
this.newScope = function () {
|
||||||
|
return $rootScope.$new();
|
||||||
// If no model is supplied, just fill in a default "cancel"
|
|
||||||
overlayModel = overlayModel || { cancel: dismiss };
|
|
||||||
|
|
||||||
// Populate the scope; will be passed directly to the template
|
|
||||||
scope.overlay = overlayModel;
|
|
||||||
scope.key = key;
|
|
||||||
|
|
||||||
// Create the overlay element and add it to the document's body
|
|
||||||
element = $compile(TEMPLATE)(scope);
|
|
||||||
$document.find('body').prepend(element);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
|
||||||
dismiss: dismiss
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Add a new overlay to the document. This will be
|
|
||||||
* prepended to the document body; the overlay's
|
|
||||||
* template (as pointed to by the `key` argument) is
|
|
||||||
* responsible for having a useful z-order, and for
|
|
||||||
* blocking user interactions if appropriate.
|
|
||||||
*
|
|
||||||
* @param {string} key the symbolic key which identifies
|
|
||||||
* the template of the overlay to be shown
|
|
||||||
* @param {object} overlayModel the model to pass to the
|
|
||||||
* included overlay template (this will be passed
|
|
||||||
* in via ng-model)
|
|
||||||
*/
|
|
||||||
createOverlay: createOverlay
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new overlay to the document. This will be
|
||||||
|
* prepended to the document body; the overlay's
|
||||||
|
* template (as pointed to by the `key` argument) is
|
||||||
|
* responsible for having a useful z-order, and for
|
||||||
|
* blocking user interactions if appropriate.
|
||||||
|
*
|
||||||
|
* @param {string} key the symbolic key which identifies
|
||||||
|
* the template of the overlay to be shown
|
||||||
|
* @param {object} overlayModel the model to pass to the
|
||||||
|
* included overlay template (this will be passed
|
||||||
|
* in via ng-model)
|
||||||
|
*/
|
||||||
|
OverlayService.prototype.createOverlay = function (key, overlayModel) {
|
||||||
|
// Create a new scope for this overlay
|
||||||
|
var scope = this.newScope(),
|
||||||
|
element;
|
||||||
|
|
||||||
|
// Stop showing the overlay; additionally, release the scope
|
||||||
|
// that it uses.
|
||||||
|
function dismiss() {
|
||||||
|
scope.$destroy();
|
||||||
|
element.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no model is supplied, just fill in a default "cancel"
|
||||||
|
overlayModel = overlayModel || { cancel: dismiss };
|
||||||
|
|
||||||
|
// Populate the scope; will be passed directly to the template
|
||||||
|
scope.overlay = overlayModel;
|
||||||
|
scope.key = key;
|
||||||
|
|
||||||
|
// Create the overlay element and add it to the document's body
|
||||||
|
element = this.$compile(TEMPLATE)(scope);
|
||||||
|
this.findBody().prepend(element);
|
||||||
|
|
||||||
|
return {
|
||||||
|
dismiss: dismiss
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return OverlayService;
|
return OverlayService;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -29,9 +29,26 @@ define(
|
|||||||
* The "Cancel" action; the action triggered by clicking Cancel from
|
* The "Cancel" action; the action triggered by clicking Cancel from
|
||||||
* Edit Mode. Exits the editing user interface and invokes object
|
* Edit Mode. Exits the editing user interface and invokes object
|
||||||
* capabilities to persist the changes that have been made.
|
* capabilities to persist the changes that have been made.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function CancelAction($location, urlService, context) {
|
function CancelAction($location, urlService, context) {
|
||||||
var domainObject = context.domainObject;
|
this.domainObject = context.domainObject;
|
||||||
|
this.$location = $location;
|
||||||
|
this.urlService = urlService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel editing.
|
||||||
|
*
|
||||||
|
* @returns {Promise} a promise that will be fulfilled when
|
||||||
|
* cancellation has completed
|
||||||
|
*/
|
||||||
|
CancelAction.prototype.perform = function () {
|
||||||
|
var domainObject = this.domainObject,
|
||||||
|
$location = this.$location,
|
||||||
|
urlService = this.urlService;
|
||||||
|
|
||||||
// Look up the object's "editor.completion" capability;
|
// Look up the object's "editor.completion" capability;
|
||||||
// this is introduced by EditableDomainObject which is
|
// this is introduced by EditableDomainObject which is
|
||||||
@ -56,25 +73,15 @@ define(
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return doCancel(getEditorCapability())
|
||||||
/**
|
.then(returnToBrowse);
|
||||||
* Cancel editing.
|
};
|
||||||
*
|
|
||||||
* @returns {Promise} a promise that will be fulfilled when
|
|
||||||
* cancellation has completed
|
|
||||||
*/
|
|
||||||
perform: function () {
|
|
||||||
return doCancel(getEditorCapability())
|
|
||||||
.then(returnToBrowse);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this action is applicable in a given context.
|
* Check if this action is applicable in a given context.
|
||||||
* This will ensure that a domain object is present in the context,
|
* This will ensure that a domain object is present in the context,
|
||||||
* and that this domain object is in Edit mode.
|
* and that this domain object is in Edit mode.
|
||||||
* @returns true if applicable
|
* @returns {boolean} true if applicable
|
||||||
*/
|
*/
|
||||||
CancelAction.appliesTo = function (context) {
|
CancelAction.appliesTo = function (context) {
|
||||||
var domainObject = (context || {}).domainObject;
|
var domainObject = (context || {}).domainObject;
|
||||||
@ -84,4 +91,4 @@ define(
|
|||||||
|
|
||||||
return CancelAction;
|
return CancelAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -42,7 +42,9 @@ define(
|
|||||||
* mode (typically triggered by the Edit button.) This will
|
* mode (typically triggered by the Edit button.) This will
|
||||||
* show the user interface for editing (by way of a change in
|
* show the user interface for editing (by way of a change in
|
||||||
* route)
|
* route)
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function EditAction($location, navigationService, $log, context) {
|
function EditAction($location, navigationService, $log, context) {
|
||||||
var domainObject = (context || {}).domainObject;
|
var domainObject = (context || {}).domainObject;
|
||||||
@ -60,17 +62,19 @@ define(
|
|||||||
return NULL_ACTION;
|
return NULL_ACTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
this.domainObject = domainObject;
|
||||||
/**
|
this.$location = $location;
|
||||||
* Enter edit mode.
|
this.navigationService = navigationService;
|
||||||
*/
|
|
||||||
perform: function () {
|
|
||||||
navigationService.setNavigation(domainObject);
|
|
||||||
$location.path("/edit");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enter edit mode.
|
||||||
|
*/
|
||||||
|
EditAction.prototype.perform = function () {
|
||||||
|
this.navigationService.setNavigation(this.domainObject);
|
||||||
|
this.$location.path("/edit");
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check for applicability; verify that a domain object is present
|
* Check for applicability; verify that a domain object is present
|
||||||
* for this action to be performed upon.
|
* for this action to be performed upon.
|
||||||
@ -87,4 +91,4 @@ define(
|
|||||||
|
|
||||||
return EditAction;
|
return EditAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -29,42 +29,43 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add one domain object to another's composition.
|
* Add one domain object to another's composition.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function LinkAction(context) {
|
function LinkAction(context) {
|
||||||
var domainObject = (context || {}).domainObject,
|
this.domainObject = (context || {}).domainObject;
|
||||||
selectedObject = (context || {}).selectedObject,
|
this.selectedObject = (context || {}).selectedObject;
|
||||||
selectedId = selectedObject && selectedObject.getId();
|
this.selectedId = this.selectedObject && this.selectedObject.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkAction.prototype.perform = function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
// Add this domain object's identifier
|
// Add this domain object's identifier
|
||||||
function addId(model) {
|
function addId(model) {
|
||||||
if (Array.isArray(model.composition) &&
|
if (Array.isArray(model.composition) &&
|
||||||
model.composition.indexOf(selectedId) < 0) {
|
model.composition.indexOf(self.selectedId) < 0) {
|
||||||
model.composition.push(selectedId);
|
model.composition.push(self.selectedId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist changes to the domain object
|
// Persist changes to the domain object
|
||||||
function doPersist() {
|
function doPersist() {
|
||||||
var persistence = domainObject.getCapability('persistence');
|
var persistence =
|
||||||
|
self.domainObject.getCapability('persistence');
|
||||||
return persistence.persist();
|
return persistence.persist();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link these objects
|
// Link these objects
|
||||||
function doLink() {
|
function doLink() {
|
||||||
return domainObject.useCapability("mutation", addId)
|
return self.domainObject.useCapability("mutation", addId)
|
||||||
.then(doPersist);
|
.then(doPersist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return this.selectedId && doLink();
|
||||||
/**
|
};
|
||||||
* Perform this action.
|
|
||||||
*/
|
|
||||||
perform: function () {
|
|
||||||
return selectedId && doLink();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return LinkAction;
|
return LinkAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -32,58 +32,58 @@ define(
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an action which will allow an object's metadata to be
|
* Implements the "Edit Properties" action, which prompts the user
|
||||||
* edited.
|
* to modify a domain object's properties.
|
||||||
*
|
*
|
||||||
* @param {DialogService} dialogService a service which will show the dialog
|
* @param {DialogService} dialogService a service which will show the dialog
|
||||||
* @param {DomainObject} object the object to be edited
|
* @param {DomainObject} object the object to be edited
|
||||||
* @param {ActionContext} context the context in which this action is performed
|
* @param {ActionContext} context the context in which this action is performed
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {Action}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function PropertiesAction(dialogService, context) {
|
function PropertiesAction(dialogService, context) {
|
||||||
var object = context.domainObject;
|
this.domainObject = (context || {}).domainObject;
|
||||||
|
this.dialogService = dialogService;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertiesAction.prototype.perform = function () {
|
||||||
|
var type = this.domainObject.getCapability('type'),
|
||||||
|
domainObject = this.domainObject,
|
||||||
|
dialogService = this.dialogService;
|
||||||
|
|
||||||
// Persist modifications to this domain object
|
// Persist modifications to this domain object
|
||||||
function doPersist() {
|
function doPersist() {
|
||||||
var persistence = object.getCapability('persistence');
|
var persistence = domainObject.getCapability('persistence');
|
||||||
return persistence && persistence.persist();
|
return persistence && persistence.persist();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the domain object model based on user input
|
// Update the domain object model based on user input
|
||||||
function updateModel(userInput, dialog) {
|
function updateModel(userInput, dialog) {
|
||||||
return object.useCapability('mutation', function (model) {
|
return domainObject.useCapability('mutation', function (model) {
|
||||||
dialog.updateModel(model, userInput);
|
dialog.updateModel(model, userInput);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showDialog(type) {
|
function showDialog(type) {
|
||||||
// Create a dialog object to generate the form structure, etc.
|
// Create a dialog object to generate the form structure, etc.
|
||||||
var dialog = new PropertiesDialog(type, object.getModel());
|
var dialog =
|
||||||
|
new PropertiesDialog(type, domainObject.getModel());
|
||||||
|
|
||||||
// Show the dialog
|
// Show the dialog
|
||||||
return dialogService.getUserInput(
|
return dialogService.getUserInput(
|
||||||
dialog.getFormStructure(),
|
dialog.getFormStructure(),
|
||||||
dialog.getInitialFormValue()
|
dialog.getInitialFormValue()
|
||||||
).then(function (userInput) {
|
).then(function (userInput) {
|
||||||
// Update the model, if user input was provided
|
// Update the model, if user input was provided
|
||||||
return userInput && updateModel(userInput, dialog);
|
return userInput && updateModel(userInput, dialog);
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
return result && doPersist();
|
return result && doPersist();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return type && showDialog(type);
|
||||||
/**
|
};
|
||||||
* Perform this action.
|
|
||||||
* @return {Promise} a promise which will be
|
|
||||||
* fulfilled when the action has completed.
|
|
||||||
*/
|
|
||||||
perform: function () {
|
|
||||||
var type = object.getCapability('type');
|
|
||||||
return type && showDialog(type);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter this action for applicability against a given context.
|
* Filter this action for applicability against a given context.
|
||||||
@ -106,3 +106,4 @@ define(
|
|||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,12 +21,6 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the PropertiesDialog, used by the PropertiesAction to
|
|
||||||
* populate the form shown in dialog based on the created type.
|
|
||||||
*
|
|
||||||
* @module common/actions/properties-dialog
|
|
||||||
*/
|
|
||||||
define(
|
define(
|
||||||
function () {
|
function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -37,58 +31,60 @@ define(
|
|||||||
* @param {TypeImpl} type the type of domain object for which properties
|
* @param {TypeImpl} type the type of domain object for which properties
|
||||||
* will be specified
|
* will be specified
|
||||||
* @param {DomainObject} the object for which properties will be set
|
* @param {DomainObject} the object for which properties will be set
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
* @memberof module:common/actions/properties-dialog
|
|
||||||
*/
|
*/
|
||||||
function PropertiesDialog(type, model) {
|
function PropertiesDialog(type, model) {
|
||||||
var properties = type.getProperties();
|
this.type = type;
|
||||||
|
this.model = model;
|
||||||
return {
|
this.properties = type.getProperties();
|
||||||
/**
|
|
||||||
* Get sections provided by this dialog.
|
|
||||||
* @return {FormStructure} the structure of this form
|
|
||||||
*/
|
|
||||||
getFormStructure: function () {
|
|
||||||
return {
|
|
||||||
name: "Edit " + model.name,
|
|
||||||
sections: [{
|
|
||||||
name: "Properties",
|
|
||||||
rows: properties.map(function (property, index) {
|
|
||||||
// Property definition is same as form row definition
|
|
||||||
var row = Object.create(property.getDefinition());
|
|
||||||
row.key = index;
|
|
||||||
return row;
|
|
||||||
})
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the initial state of the form shown by this dialog
|
|
||||||
* (based on the object model)
|
|
||||||
* @returns {object} initial state of the form
|
|
||||||
*/
|
|
||||||
getInitialFormValue: function () {
|
|
||||||
// Start with initial values for properties
|
|
||||||
// Note that index needs to correlate to row.key
|
|
||||||
// from getFormStructure
|
|
||||||
return properties.map(function (property) {
|
|
||||||
return property.getValue(model);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Update a domain object model based on the value of a form.
|
|
||||||
*/
|
|
||||||
updateModel: function (model, formValue) {
|
|
||||||
// Update all properties
|
|
||||||
properties.forEach(function (property, index) {
|
|
||||||
property.setValue(model, formValue[index]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sections provided by this dialog.
|
||||||
|
* @return {FormStructure} the structure of this form
|
||||||
|
*/
|
||||||
|
PropertiesDialog.prototype.getFormStructure = function () {
|
||||||
|
return {
|
||||||
|
name: "Edit " + this.model.name,
|
||||||
|
sections: [{
|
||||||
|
name: "Properties",
|
||||||
|
rows: this.properties.map(function (property, index) {
|
||||||
|
// Property definition is same as form row definition
|
||||||
|
var row = Object.create(property.getDefinition());
|
||||||
|
row.key = index;
|
||||||
|
return row;
|
||||||
|
})
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the initial state of the form shown by this dialog
|
||||||
|
* (based on the object model)
|
||||||
|
* @returns {object} initial state of the form
|
||||||
|
*/
|
||||||
|
PropertiesDialog.prototype.getInitialFormValue = function () {
|
||||||
|
var model = this.model;
|
||||||
|
|
||||||
|
// Start with initial values for properties
|
||||||
|
// Note that index needs to correlate to row.key
|
||||||
|
// from getFormStructure
|
||||||
|
return this.properties.map(function (property) {
|
||||||
|
return property.getValue(model);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a domain object model based on the value of a form.
|
||||||
|
*/
|
||||||
|
PropertiesDialog.prototype.updateModel = function (model, formValue) {
|
||||||
|
// Update all properties
|
||||||
|
this.properties.forEach(function (property, index) {
|
||||||
|
property.setValue(model, formValue[index]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return PropertiesDialog;
|
return PropertiesDialog;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -57,7 +57,6 @@ define(
|
|||||||
navigationService = this.navigationService,
|
navigationService = this.navigationService,
|
||||||
domainObject = this.domainObject,
|
domainObject = this.domainObject,
|
||||||
ROOT_ID = "ROOT";
|
ROOT_ID = "ROOT";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether an object ID matches the ID of the object being
|
* Check whether an object ID matches the ID of the object being
|
||||||
* removed (used to filter a parent's composition to handle the
|
* removed (used to filter a parent's composition to handle the
|
||||||
|
@ -30,9 +30,27 @@ define(
|
|||||||
* The "Save" action; the action triggered by clicking Save from
|
* The "Save" action; the action triggered by clicking Save from
|
||||||
* Edit Mode. Exits the editing user interface and invokes object
|
* Edit Mode. Exits the editing user interface and invokes object
|
||||||
* capabilities to persist the changes that have been made.
|
* capabilities to persist the changes that have been made.
|
||||||
|
* @constructor
|
||||||
|
* @implements {Action}
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
*/
|
*/
|
||||||
function SaveAction($location, urlService, context) {
|
function SaveAction($location, urlService, context) {
|
||||||
var domainObject = context.domainObject;
|
this.domainObject = (context || {}).domainObject;
|
||||||
|
this.$location = $location;
|
||||||
|
this.urlService = urlService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save changes and conclude editing.
|
||||||
|
*
|
||||||
|
* @returns {Promise} a promise that will be fulfilled when
|
||||||
|
* cancellation has completed
|
||||||
|
* @memberof platform/commonUI/edit.SaveAction#
|
||||||
|
*/
|
||||||
|
SaveAction.prototype.perform = function () {
|
||||||
|
var domainObject = this.domainObject,
|
||||||
|
$location = this.$location,
|
||||||
|
urlService = this.urlService;
|
||||||
|
|
||||||
// Invoke any save behavior introduced by the editor capability;
|
// Invoke any save behavior introduced by the editor capability;
|
||||||
// this is introduced by EditableDomainObject which is
|
// this is introduced by EditableDomainObject which is
|
||||||
@ -51,18 +69,8 @@ define(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return doSave().then(returnToBrowse);
|
||||||
/**
|
};
|
||||||
* Save changes and conclude editing.
|
|
||||||
*
|
|
||||||
* @returns {Promise} a promise that will be fulfilled when
|
|
||||||
* cancellation has completed
|
|
||||||
*/
|
|
||||||
perform: function () {
|
|
||||||
return doSave().then(returnToBrowse);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this action is applicable in a given context.
|
* Check if this action is applicable in a given context.
|
||||||
@ -78,4 +86,4 @@ define(
|
|||||||
|
|
||||||
return SaveAction;
|
return SaveAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,6 +35,9 @@ define(
|
|||||||
* Meant specifically for use by EditableDomainObject and the
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
* associated cache; the constructor signature is particular
|
* associated cache; the constructor signature is particular
|
||||||
* to a pattern used there and may contain unused arguments.
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {CompositionCapability}
|
||||||
*/
|
*/
|
||||||
return function EditableCompositionCapability(
|
return function EditableCompositionCapability(
|
||||||
contextCapability,
|
contextCapability,
|
||||||
@ -54,4 +57,4 @@ define(
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,6 +35,9 @@ define(
|
|||||||
* Meant specifically for use by EditableDomainObject and the
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
* associated cache; the constructor signature is particular
|
* associated cache; the constructor signature is particular
|
||||||
* to a pattern used there and may contain unused arguments.
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {ContextCapability}
|
||||||
*/
|
*/
|
||||||
return function EditableContextCapability(
|
return function EditableContextCapability(
|
||||||
contextCapability,
|
contextCapability,
|
||||||
@ -72,4 +75,4 @@ define(
|
|||||||
return capability;
|
return capability;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,6 +35,8 @@ define(
|
|||||||
* Meant specifically for use by EditableDomainObject and the
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
* associated cache; the constructor signature is particular
|
* associated cache; the constructor signature is particular
|
||||||
* to a pattern used there and may contain unused arguments.
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
*/
|
*/
|
||||||
return function EditableLookupCapability(
|
return function EditableLookupCapability(
|
||||||
contextCapability,
|
contextCapability,
|
||||||
@ -76,7 +78,7 @@ define(
|
|||||||
// Wrap a returned value (see above); if it's a promise, wrap
|
// Wrap a returned value (see above); if it's a promise, wrap
|
||||||
// the resolved value.
|
// the resolved value.
|
||||||
function wrapResult(result) {
|
function wrapResult(result) {
|
||||||
return result.then ? // promise-like
|
return (result && result.then) ? // promise-like
|
||||||
result.then(makeEditable) :
|
result.then(makeEditable) :
|
||||||
makeEditable(result);
|
makeEditable(result);
|
||||||
}
|
}
|
||||||
@ -105,8 +107,10 @@ define(
|
|||||||
|
|
||||||
// Wrap a method of this capability
|
// Wrap a method of this capability
|
||||||
function wrapMethod(fn) {
|
function wrapMethod(fn) {
|
||||||
capability[fn] =
|
if (typeof capability[fn] === 'function') {
|
||||||
(idempotent ? oneTimeFunction : wrapFunction)(fn);
|
capability[fn] =
|
||||||
|
(idempotent ? oneTimeFunction : wrapFunction)(fn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap all methods; return only editable domain objects.
|
// Wrap all methods; return only editable domain objects.
|
||||||
@ -115,4 +119,4 @@ define(
|
|||||||
return capability;
|
return capability;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,6 +35,9 @@ define(
|
|||||||
* Meant specifically for use by EditableDomainObject and the
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
* associated cache; the constructor signature is particular
|
* associated cache; the constructor signature is particular
|
||||||
* to a pattern used there and may contain unused arguments.
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {PersistenceCapability}
|
||||||
*/
|
*/
|
||||||
function EditablePersistenceCapability(
|
function EditablePersistenceCapability(
|
||||||
persistenceCapability,
|
persistenceCapability,
|
||||||
@ -62,4 +65,4 @@ define(
|
|||||||
|
|
||||||
return EditablePersistenceCapability;
|
return EditablePersistenceCapability;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,6 +35,9 @@ define(
|
|||||||
* Meant specifically for use by EditableDomainObject and the
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
* associated cache; the constructor signature is particular
|
* associated cache; the constructor signature is particular
|
||||||
* to a pattern used there and may contain unused arguments.
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {RelationshipCapability}
|
||||||
*/
|
*/
|
||||||
return function EditableRelationshipCapability(
|
return function EditableRelationshipCapability(
|
||||||
relationshipCapability,
|
relationshipCapability,
|
||||||
@ -54,4 +57,4 @@ define(
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -39,27 +39,48 @@ define(
|
|||||||
* Meant specifically for use by EditableDomainObject and the
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
* associated cache; the constructor signature is particular
|
* associated cache; the constructor signature is particular
|
||||||
* to a pattern used there and may contain unused arguments.
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
*/
|
*/
|
||||||
return function EditorCapability(
|
function EditorCapability(
|
||||||
persistenceCapability,
|
persistenceCapability,
|
||||||
editableObject,
|
editableObject,
|
||||||
domainObject,
|
domainObject,
|
||||||
cache
|
cache
|
||||||
) {
|
) {
|
||||||
|
this.editableObject = editableObject;
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
// Simulate Promise.resolve (or $q.when); the former
|
// Simulate Promise.resolve (or $q.when); the former
|
||||||
// causes a delayed reaction from Angular (since it
|
// causes a delayed reaction from Angular (since it
|
||||||
// does not trigger a digest) and the latter is not
|
// does not trigger a digest) and the latter is not
|
||||||
// readily accessible, since we're a few classes
|
// readily accessible, since we're a few classes
|
||||||
// removed from the layer which gets dependency
|
// removed from the layer which gets dependency
|
||||||
// injection.
|
// injection.
|
||||||
function resolvePromise(value) {
|
function resolvePromise(value) {
|
||||||
return (value && value.then) ? value : {
|
return (value && value.then) ? value : {
|
||||||
then: function (callback) {
|
then: function (callback) {
|
||||||
return resolvePromise(callback(value));
|
return resolvePromise(callback(value));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save any changes that have been made to this domain object
|
||||||
|
* (as well as to others that might have been retrieved and
|
||||||
|
* modified during the editing session)
|
||||||
|
* @param {boolean} nonrecursive if true, save only this
|
||||||
|
* object (and not other objects with associated changes)
|
||||||
|
* @returns {Promise} a promise that will be fulfilled after
|
||||||
|
* persistence has completed.
|
||||||
|
* @memberof platform/commonUI/edit.EditorCapability#
|
||||||
|
*/
|
||||||
|
EditorCapability.prototype.save = function (nonrecursive) {
|
||||||
|
var domainObject = this.domainObject,
|
||||||
|
editableObject = this.editableObject,
|
||||||
|
cache = this.cache;
|
||||||
|
|
||||||
// Update the underlying, "real" domain object's model
|
// Update the underlying, "real" domain object's model
|
||||||
// with changes made to the copy used for editing.
|
// with changes made to the copy used for editing.
|
||||||
@ -74,39 +95,32 @@ define(
|
|||||||
return domainObject.getCapability('persistence').persist();
|
return domainObject.getCapability('persistence').persist();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return nonrecursive ?
|
||||||
/**
|
resolvePromise(doMutate()).then(doPersist) :
|
||||||
* Save any changes that have been made to this domain object
|
resolvePromise(cache.saveAll());
|
||||||
* (as well as to others that might have been retrieved and
|
|
||||||
* modified during the editing session)
|
|
||||||
* @param {boolean} nonrecursive if true, save only this
|
|
||||||
* object (and not other objects with associated changes)
|
|
||||||
* @returns {Promise} a promise that will be fulfilled after
|
|
||||||
* persistence has completed.
|
|
||||||
*/
|
|
||||||
save: function (nonrecursive) {
|
|
||||||
return nonrecursive ?
|
|
||||||
resolvePromise(doMutate()).then(doPersist) :
|
|
||||||
resolvePromise(cache.saveAll());
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Cancel editing; Discard any changes that have been made to
|
|
||||||
* this domain object (as well as to others that might have
|
|
||||||
* been retrieved and modified during the editing session)
|
|
||||||
* @returns {Promise} a promise that will be fulfilled after
|
|
||||||
* cancellation has completed.
|
|
||||||
*/
|
|
||||||
cancel: function () {
|
|
||||||
return resolvePromise(undefined);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Check if there are any unsaved changes.
|
|
||||||
* @returns {boolean} true if there are unsaved changes
|
|
||||||
*/
|
|
||||||
dirty: function () {
|
|
||||||
return cache.dirty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel editing; Discard any changes that have been made to
|
||||||
|
* this domain object (as well as to others that might have
|
||||||
|
* been retrieved and modified during the editing session)
|
||||||
|
* @returns {Promise} a promise that will be fulfilled after
|
||||||
|
* cancellation has completed.
|
||||||
|
* @memberof platform/commonUI/edit.EditorCapability#
|
||||||
|
*/
|
||||||
|
EditorCapability.prototype.cancel = function () {
|
||||||
|
return resolvePromise(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there are any unsaved changes.
|
||||||
|
* @returns {boolean} true if there are unsaved changes
|
||||||
|
* @memberof platform/commonUI/edit.EditorCapability#
|
||||||
|
*/
|
||||||
|
EditorCapability.prototype.dirty = function () {
|
||||||
|
return this.cache.dirty();
|
||||||
|
};
|
||||||
|
|
||||||
|
return EditorCapability;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -33,6 +33,7 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller which supplies action instances for Save/Cancel.
|
* Controller which supplies action instances for Save/Cancel.
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditActionController($scope) {
|
function EditActionController($scope) {
|
||||||
@ -51,4 +52,4 @@ define(
|
|||||||
|
|
||||||
return EditActionController;
|
return EditActionController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
/*global define,Promise*/
|
/*global define,Promise*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module defining EditController. Created by vwoeltje on 11/14/14.
|
* This bundle implements Edit mode.
|
||||||
|
* @namespace platform/commonUI/edit
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
["../objects/EditableDomainObject"],
|
["../objects/EditableDomainObject"],
|
||||||
@ -33,15 +34,16 @@ define(
|
|||||||
* Controller which is responsible for populating the scope for
|
* Controller which is responsible for populating the scope for
|
||||||
* Edit mode; introduces an editable version of the currently
|
* Edit mode; introduces an editable version of the currently
|
||||||
* navigated domain object into the scope.
|
* navigated domain object into the scope.
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditController($scope, $q, navigationService) {
|
function EditController($scope, $q, navigationService) {
|
||||||
var navigatedObject;
|
var self = this;
|
||||||
|
|
||||||
function setNavigation(domainObject) {
|
function setNavigation(domainObject) {
|
||||||
// Wrap the domain object such that all mutation is
|
// Wrap the domain object such that all mutation is
|
||||||
// confined to edit mode (until Save)
|
// confined to edit mode (until Save)
|
||||||
navigatedObject =
|
self.navigatedDomainObject =
|
||||||
domainObject && new EditableDomainObject(domainObject, $q);
|
domainObject && new EditableDomainObject(domainObject, $q);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,33 +52,33 @@ define(
|
|||||||
$scope.$on("$destroy", function () {
|
$scope.$on("$destroy", function () {
|
||||||
navigationService.removeListener(setNavigation);
|
navigationService.removeListener(setNavigation);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get the domain object which is navigated-to.
|
|
||||||
* @returns {DomainObject} the domain object that is navigated-to
|
|
||||||
*/
|
|
||||||
navigatedObject: function () {
|
|
||||||
return navigatedObject;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the warning to show if the user attempts to navigate
|
|
||||||
* away from Edit mode while unsaved changes are present.
|
|
||||||
* @returns {string} the warning to show, or undefined if
|
|
||||||
* there are no unsaved changes
|
|
||||||
*/
|
|
||||||
getUnloadWarning: function () {
|
|
||||||
var editorCapability = navigatedObject &&
|
|
||||||
navigatedObject.getCapability("editor"),
|
|
||||||
hasChanges = editorCapability && editorCapability.dirty();
|
|
||||||
|
|
||||||
return hasChanges ?
|
|
||||||
"Unsaved changes will be lost if you leave this page." :
|
|
||||||
undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the domain object which is navigated-to.
|
||||||
|
* @returns {DomainObject} the domain object that is navigated-to
|
||||||
|
*/
|
||||||
|
EditController.prototype.navigatedObject = function () {
|
||||||
|
return this.navigatedDomainObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the warning to show if the user attempts to navigate
|
||||||
|
* away from Edit mode while unsaved changes are present.
|
||||||
|
* @returns {string} the warning to show, or undefined if
|
||||||
|
* there are no unsaved changes
|
||||||
|
*/
|
||||||
|
EditController.prototype.getUnloadWarning = function () {
|
||||||
|
var navigatedObject = this.navigatedDomainObject,
|
||||||
|
editorCapability = navigatedObject &&
|
||||||
|
navigatedObject.getCapability("editor"),
|
||||||
|
hasChanges = editorCapability && editorCapability.dirty();
|
||||||
|
|
||||||
|
return hasChanges ?
|
||||||
|
"Unsaved changes will be lost if you leave this page." :
|
||||||
|
undefined;
|
||||||
|
};
|
||||||
|
|
||||||
return EditController;
|
return EditController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -28,15 +28,17 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Supports the Library and Elements panes in Edit mode.
|
* Supports the Library and Elements panes in Edit mode.
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditPanesController($scope) {
|
function EditPanesController($scope) {
|
||||||
var root;
|
var self = this;
|
||||||
|
|
||||||
// Update root object based on represented object
|
// Update root object based on represented object
|
||||||
function updateRoot(domainObject) {
|
function updateRoot(domainObject) {
|
||||||
var context = domainObject &&
|
var root = self.rootDomainObject,
|
||||||
domainObject.getCapability('context'),
|
context = domainObject &&
|
||||||
|
domainObject.getCapability('context'),
|
||||||
newRoot = context && context.getTrueRoot(),
|
newRoot = context && context.getTrueRoot(),
|
||||||
oldId = root && root.getId(),
|
oldId = root && root.getId(),
|
||||||
newId = newRoot && newRoot.getId();
|
newId = newRoot && newRoot.getId();
|
||||||
@ -44,25 +46,22 @@ define(
|
|||||||
// Only update if this has actually changed,
|
// Only update if this has actually changed,
|
||||||
// to avoid excessive refreshing.
|
// to avoid excessive refreshing.
|
||||||
if (oldId !== newId) {
|
if (oldId !== newId) {
|
||||||
root = newRoot;
|
self.rootDomainObject = newRoot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update root when represented object changes
|
// Update root when represented object changes
|
||||||
$scope.$watch('domainObject', updateRoot);
|
$scope.$watch('domainObject', updateRoot);
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get the root-level domain object, as reported by the
|
|
||||||
* represented domain object.
|
|
||||||
* @returns {DomainObject} the root object
|
|
||||||
*/
|
|
||||||
getRoot: function () {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Get the root-level domain object, as reported by the
|
||||||
|
* represented domain object.
|
||||||
|
* @returns {DomainObject} the root object
|
||||||
|
*/
|
||||||
|
EditPanesController.prototype.getRoot = function () {
|
||||||
|
return this.rootDomainObject;
|
||||||
|
};
|
||||||
|
|
||||||
return EditPanesController;
|
return EditPanesController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -31,6 +31,7 @@ define(
|
|||||||
* to this attribute will be evaluated during page navigation events
|
* to this attribute will be evaluated during page navigation events
|
||||||
* and, if it returns a truthy value, will be used to populate a
|
* and, if it returns a truthy value, will be used to populate a
|
||||||
* prompt to the user to confirm this navigation.
|
* prompt to the user to confirm this navigation.
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param $window the window
|
* @param $window the window
|
||||||
*/
|
*/
|
||||||
@ -102,4 +103,4 @@ define(
|
|||||||
return MCTBeforeUnload;
|
return MCTBeforeUnload;
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -68,6 +68,9 @@ define(
|
|||||||
* which need to behave differently in edit mode,
|
* which need to behave differently in edit mode,
|
||||||
* and provides a "working copy" of the object's
|
* and provides a "working copy" of the object's
|
||||||
* model to allow changes to be easily cancelled.
|
* model to allow changes to be easily cancelled.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {DomainObject}
|
||||||
*/
|
*/
|
||||||
function EditableDomainObject(domainObject, $q) {
|
function EditableDomainObject(domainObject, $q) {
|
||||||
// The cache will hold all domain objects reached from
|
// The cache will hold all domain objects reached from
|
||||||
@ -92,10 +95,10 @@ define(
|
|||||||
this,
|
this,
|
||||||
delegateArguments
|
delegateArguments
|
||||||
),
|
),
|
||||||
factory = capabilityFactories[name];
|
Factory = capabilityFactories[name];
|
||||||
|
|
||||||
return (factory && capability) ?
|
return (Factory && capability) ?
|
||||||
factory(capability, editableObject, domainObject, cache) :
|
new Factory(capability, editableObject, domainObject, cache) :
|
||||||
capability;
|
capability;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -109,4 +112,4 @@ define(
|
|||||||
|
|
||||||
return EditableDomainObject;
|
return EditableDomainObject;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* An editable domain object cache stores domain objects that have been
|
* An editable domain object cache stores domain objects that have been
|
||||||
* made editable, in a group that can be saved all-at-once. This supports
|
* made editable, in a group that can be saved all-at-once. This supports
|
||||||
* Edit mode, which is launched for a specific object but may contain
|
* Edit mode, which is launched for a specific object but may contain
|
||||||
@ -32,8 +32,6 @@
|
|||||||
* to ensure that changes made while in edit mode do not propagate up
|
* to ensure that changes made while in edit mode do not propagate up
|
||||||
* to the objects used in browse mode (or to persistence) until the user
|
* to the objects used in browse mode (or to persistence) until the user
|
||||||
* initiates a Save.
|
* initiates a Save.
|
||||||
*
|
|
||||||
* @module editor/object/editable-domain-object-cache
|
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
["./EditableModelCache"],
|
["./EditableModelCache"],
|
||||||
@ -46,107 +44,118 @@ define(
|
|||||||
* of objects retrieved via composition or context capabilities as
|
* of objects retrieved via composition or context capabilities as
|
||||||
* editable domain objects.
|
* editable domain objects.
|
||||||
*
|
*
|
||||||
* @param {Constructor<EditableDomainObject>} EditableDomainObject a
|
* @param {Constructor<DomainObject>} EditableDomainObject a
|
||||||
* constructor function which takes a regular domain object as
|
* constructor function which takes a regular domain object as
|
||||||
* an argument, and returns an editable domain object as its
|
* an argument, and returns an editable domain object as its
|
||||||
* result.
|
* result.
|
||||||
* @param $q Angular's $q, for promise handling
|
* @param $q Angular's $q, for promise handling
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
* @memberof module:editor/object/editable-domain-object-cache
|
|
||||||
*/
|
*/
|
||||||
function EditableDomainObjectCache(EditableDomainObject, $q) {
|
function EditableDomainObjectCache(EditableDomainObject, $q) {
|
||||||
var cache = new EditableModelCache(),
|
this.cache = new EditableModelCache();
|
||||||
dirty = {},
|
this.dirtyObjects = {};
|
||||||
root;
|
this.root = undefined;
|
||||||
|
this.$q = $q;
|
||||||
return {
|
this.EditableDomainObject = EditableDomainObject;
|
||||||
/**
|
|
||||||
* Wrap this domain object in an editable form, or pull such
|
|
||||||
* an object from the cache if one already exists.
|
|
||||||
*
|
|
||||||
* @param {DomainObject} domainObject the regular domain object
|
|
||||||
* @returns {DomainObject} the domain object in an editable form
|
|
||||||
*/
|
|
||||||
getEditableObject: function (domainObject) {
|
|
||||||
var type = domainObject.getCapability('type');
|
|
||||||
|
|
||||||
// Track the top-level domain object; this will have
|
|
||||||
// some special behavior for its context capability.
|
|
||||||
root = root || domainObject;
|
|
||||||
|
|
||||||
// Avoid double-wrapping (WTD-1017)
|
|
||||||
if (domainObject.hasCapability('editor')) {
|
|
||||||
return domainObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't bother wrapping non-editable objects
|
|
||||||
if (!type || !type.hasFeature('creation')) {
|
|
||||||
return domainObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide an editable form of the object
|
|
||||||
return new EditableDomainObject(
|
|
||||||
domainObject,
|
|
||||||
cache.getCachedModel(domainObject)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Check if a domain object is (effectively) the top-level
|
|
||||||
* object in this editable subgraph.
|
|
||||||
* @returns {boolean} true if it is the root
|
|
||||||
*/
|
|
||||||
isRoot: function (domainObject) {
|
|
||||||
return domainObject === root;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Mark an editable domain object (presumably already cached)
|
|
||||||
* as having received modifications during editing; it should be
|
|
||||||
* included in the bulk save invoked when editing completes.
|
|
||||||
*
|
|
||||||
* @param {DomainObject} domainObject the domain object
|
|
||||||
*/
|
|
||||||
markDirty: function (domainObject) {
|
|
||||||
dirty[domainObject.getId()] = domainObject;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Mark an object (presumably already cached) as having had its
|
|
||||||
* changes saved (and thus no longer needing to be subject to a
|
|
||||||
* save operation.)
|
|
||||||
*
|
|
||||||
* @param {DomainObject} domainObject the domain object
|
|
||||||
*/
|
|
||||||
markClean: function (domainObject) {
|
|
||||||
delete dirty[domainObject.getId()];
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Initiate a save on all objects that have been cached.
|
|
||||||
*/
|
|
||||||
saveAll: function () {
|
|
||||||
// Get a list of all dirty objects
|
|
||||||
var objects = Object.keys(dirty).map(function (k) {
|
|
||||||
return dirty[k];
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clear dirty set, since we're about to save.
|
|
||||||
dirty = {};
|
|
||||||
|
|
||||||
// Most save logic is handled by the "editor.completion"
|
|
||||||
// capability, so that is delegated here.
|
|
||||||
return $q.all(objects.map(function (object) {
|
|
||||||
// Save; pass a nonrecursive flag to avoid looping
|
|
||||||
return object.getCapability('editor').save(true);
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Check if any objects have been marked dirty in this cache.
|
|
||||||
* @returns {boolean} true if objects are dirty
|
|
||||||
*/
|
|
||||||
dirty: function () {
|
|
||||||
return Object.keys(dirty).length > 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap this domain object in an editable form, or pull such
|
||||||
|
* an object from the cache if one already exists.
|
||||||
|
*
|
||||||
|
* @param {DomainObject} domainObject the regular domain object
|
||||||
|
* @returns {DomainObject} the domain object in an editable form
|
||||||
|
*/
|
||||||
|
EditableDomainObjectCache.prototype.getEditableObject = function (domainObject) {
|
||||||
|
var type = domainObject.getCapability('type'),
|
||||||
|
EditableDomainObject = this.EditableDomainObject;
|
||||||
|
|
||||||
|
// Track the top-level domain object; this will have
|
||||||
|
// some special behavior for its context capability.
|
||||||
|
this.root = this.root || domainObject;
|
||||||
|
|
||||||
|
// Avoid double-wrapping (WTD-1017)
|
||||||
|
if (domainObject.hasCapability('editor')) {
|
||||||
|
return domainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't bother wrapping non-editable objects
|
||||||
|
if (!type || !type.hasFeature('creation')) {
|
||||||
|
return domainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide an editable form of the object
|
||||||
|
return new EditableDomainObject(
|
||||||
|
domainObject,
|
||||||
|
this.cache.getCachedModel(domainObject)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a domain object is (effectively) the top-level
|
||||||
|
* object in this editable subgraph.
|
||||||
|
* @returns {boolean} true if it is the root
|
||||||
|
*/
|
||||||
|
EditableDomainObjectCache.prototype.isRoot = function (domainObject) {
|
||||||
|
return domainObject === this.root;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark an editable domain object (presumably already cached)
|
||||||
|
* as having received modifications during editing; it should be
|
||||||
|
* included in the bulk save invoked when editing completes.
|
||||||
|
*
|
||||||
|
* @param {DomainObject} domainObject the domain object
|
||||||
|
* @memberof platform/commonUI/edit.EditableDomainObjectCache#
|
||||||
|
*/
|
||||||
|
EditableDomainObjectCache.prototype.markDirty = function (domainObject) {
|
||||||
|
this.dirtyObjects[domainObject.getId()] = domainObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark an object (presumably already cached) as having had its
|
||||||
|
* changes saved (and thus no longer needing to be subject to a
|
||||||
|
* save operation.)
|
||||||
|
*
|
||||||
|
* @param {DomainObject} domainObject the domain object
|
||||||
|
*/
|
||||||
|
EditableDomainObjectCache.prototype.markClean = function (domainObject) {
|
||||||
|
delete this.dirtyObjects[domainObject.getId()];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate a save on all objects that have been cached.
|
||||||
|
* @return {Promise} A promise which will resolve when all objects are
|
||||||
|
* persisted.
|
||||||
|
*/
|
||||||
|
EditableDomainObjectCache.prototype.saveAll = function () {
|
||||||
|
// Get a list of all dirty objects
|
||||||
|
var dirty = this.dirtyObjects,
|
||||||
|
objects = Object.keys(dirty).map(function (k) {
|
||||||
|
return dirty[k];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clear dirty set, since we're about to save.
|
||||||
|
this.dirtyObjects = {};
|
||||||
|
|
||||||
|
// Most save logic is handled by the "editor.completion"
|
||||||
|
// capability, so that is delegated here.
|
||||||
|
return this.$q.all(objects.map(function (object) {
|
||||||
|
// Save; pass a nonrecursive flag to avoid looping
|
||||||
|
return object.getCapability('editor').save(true);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if any objects have been marked dirty in this cache.
|
||||||
|
* @returns {boolean} true if objects are dirty
|
||||||
|
*/
|
||||||
|
EditableDomainObjectCache.prototype.dirty = function () {
|
||||||
|
return Object.keys(this.dirtyObjects).length > 0;
|
||||||
|
};
|
||||||
|
|
||||||
return EditableDomainObjectCache;
|
return EditableDomainObjectCache;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -31,33 +31,32 @@ define(
|
|||||||
* made editable, to support a group that can be saved all-at-once.
|
* made editable, to support a group that can be saved all-at-once.
|
||||||
* This is useful in Edit mode, which is launched for a specific
|
* This is useful in Edit mode, which is launched for a specific
|
||||||
* object but may contain changes across many objects.
|
* object but may contain changes across many objects.
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditableModelCache() {
|
function EditableModelCache() {
|
||||||
var cache = {};
|
this.cache = {};
|
||||||
|
|
||||||
// Deep-copy a model. Models are JSONifiable, so this can be
|
|
||||||
// done by stringification then destringification
|
|
||||||
function clone(model) {
|
|
||||||
return JSON.parse(JSON.stringify(model));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get this domain object's model from the cache (or
|
|
||||||
* place it in the cache if it isn't in the cache yet)
|
|
||||||
* @returns a clone of the domain object's model
|
|
||||||
*/
|
|
||||||
getCachedModel: function (domainObject) {
|
|
||||||
var id = domainObject.getId();
|
|
||||||
|
|
||||||
return (cache[id] =
|
|
||||||
cache[id] || clone(domainObject.getModel()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deep-copy a model. Models are JSONifiable, so this can be
|
||||||
|
// done by stringification then destringification
|
||||||
|
function clone(model) {
|
||||||
|
return JSON.parse(JSON.stringify(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this domain object's model from the cache (or
|
||||||
|
* place it in the cache if it isn't in the cache yet)
|
||||||
|
* @returns a clone of the domain object's model
|
||||||
|
*/
|
||||||
|
EditableModelCache.prototype.getCachedModel = function (domainObject) {
|
||||||
|
var id = domainObject.getId(),
|
||||||
|
cache = this.cache;
|
||||||
|
|
||||||
|
return (cache[id] =
|
||||||
|
cache[id] || clone(domainObject.getModel()));
|
||||||
|
};
|
||||||
|
|
||||||
return EditableModelCache;
|
return EditableModelCache;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -30,53 +30,47 @@ define(
|
|||||||
* Policy controlling when the `edit` and/or `properties` actions
|
* Policy controlling when the `edit` and/or `properties` actions
|
||||||
* can appear as applicable actions of the `view-control` category
|
* can appear as applicable actions of the `view-control` category
|
||||||
* (shown as buttons in the top-right of browse mode.)
|
* (shown as buttons in the top-right of browse mode.)
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Policy.<Action, ActionContext>}
|
||||||
*/
|
*/
|
||||||
function EditActionPolicy() {
|
function EditActionPolicy() {
|
||||||
// Get a count of views which are not flagged as non-editable.
|
}
|
||||||
function countEditableViews(context) {
|
|
||||||
var domainObject = (context || {}).domainObject,
|
|
||||||
views = domainObject && domainObject.useCapability('view'),
|
|
||||||
count = 0;
|
|
||||||
|
|
||||||
// A view is editable unless explicitly flagged as not
|
// Get a count of views which are not flagged as non-editable.
|
||||||
(views || []).forEach(function (view) {
|
function countEditableViews(context) {
|
||||||
count += (view.editable !== false) ? 1 : 0;
|
var domainObject = (context || {}).domainObject,
|
||||||
});
|
views = domainObject && domainObject.useCapability('view'),
|
||||||
|
count = 0;
|
||||||
|
|
||||||
return count;
|
// A view is editable unless explicitly flagged as not
|
||||||
|
(views || []).forEach(function (view) {
|
||||||
|
count += (view.editable !== false) ? 1 : 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditActionPolicy.prototype.allow = function (action, context) {
|
||||||
|
var key = action.getMetadata().key,
|
||||||
|
category = (context || {}).category;
|
||||||
|
|
||||||
|
// Only worry about actions in the view-control category
|
||||||
|
if (category === 'view-control') {
|
||||||
|
// Restrict 'edit' to cases where there are editable
|
||||||
|
// views (similarly, restrict 'properties' to when
|
||||||
|
// the converse is true)
|
||||||
|
if (key === 'edit') {
|
||||||
|
return countEditableViews(context) > 0;
|
||||||
|
} else if (key === 'properties') {
|
||||||
|
return countEditableViews(context) < 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
// Like all policies, allow by default.
|
||||||
/**
|
return true;
|
||||||
* Check whether or not a given action is allowed by this
|
};
|
||||||
* policy.
|
|
||||||
* @param {Action} action the action
|
|
||||||
* @param context the context
|
|
||||||
* @returns {boolean} true if not disallowed
|
|
||||||
*/
|
|
||||||
allow: function (action, context) {
|
|
||||||
var key = action.getMetadata().key,
|
|
||||||
category = (context || {}).category;
|
|
||||||
|
|
||||||
// Only worry about actions in the view-control category
|
|
||||||
if (category === 'view-control') {
|
|
||||||
// Restrict 'edit' to cases where there are editable
|
|
||||||
// views (similarly, restrict 'properties' to when
|
|
||||||
// the converse is true)
|
|
||||||
if (key === 'edit') {
|
|
||||||
return countEditableViews(context) > 0;
|
|
||||||
} else if (key === 'properties') {
|
|
||||||
return countEditableViews(context) < 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like all policies, allow by default.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return EditActionPolicy;
|
return EditActionPolicy;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -28,30 +28,24 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Policy controlling which views should be visible in Edit mode.
|
* Policy controlling which views should be visible in Edit mode.
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Policy.<View, DomainObject>}
|
||||||
*/
|
*/
|
||||||
function EditableViewPolicy() {
|
function EditableViewPolicy() {
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Check whether or not a given action is allowed by this
|
|
||||||
* policy.
|
|
||||||
* @param {Action} action the action
|
|
||||||
* @param domainObject the domain object which will be viewed
|
|
||||||
* @returns {boolean} true if not disallowed
|
|
||||||
*/
|
|
||||||
allow: function (view, domainObject) {
|
|
||||||
// If a view is flagged as non-editable, only allow it
|
|
||||||
// while we're not in Edit mode.
|
|
||||||
if ((view || {}).editable === false) {
|
|
||||||
return !domainObject.hasCapability('editor');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like all policies, allow by default.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditableViewPolicy.prototype.allow = function (view, domainObject) {
|
||||||
|
// If a view is flagged as non-editable, only allow it
|
||||||
|
// while we're not in Edit mode.
|
||||||
|
if ((view || {}).editable === false) {
|
||||||
|
return !domainObject.hasCapability('editor');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like all policies, allow by default.
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
return EditableViewPolicy;
|
return EditableViewPolicy;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -41,14 +41,17 @@ define(
|
|||||||
* and may be reused for different domain objects and/or
|
* and may be reused for different domain objects and/or
|
||||||
* representations resulting from changes there.
|
* representations resulting from changes there.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {Representer}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditRepresenter($q, $log, scope) {
|
function EditRepresenter($q, $log, scope) {
|
||||||
var domainObject,
|
var self = this;
|
||||||
key;
|
|
||||||
|
|
||||||
// Mutate and persist a new version of a domain object's model.
|
// Mutate and persist a new version of a domain object's model.
|
||||||
function doPersist(model) {
|
function doPersist(model) {
|
||||||
|
var domainObject = self.domainObject;
|
||||||
|
|
||||||
// First, mutate; then, persist.
|
// First, mutate; then, persist.
|
||||||
return $q.when(domainObject.useCapability("mutation", function () {
|
return $q.when(domainObject.useCapability("mutation", function () {
|
||||||
return model;
|
return model;
|
||||||
@ -64,7 +67,8 @@ define(
|
|||||||
// Look up from scope; these will have been populated by
|
// Look up from scope; these will have been populated by
|
||||||
// mct-representation.
|
// mct-representation.
|
||||||
var model = scope.model,
|
var model = scope.model,
|
||||||
configuration = scope.configuration;
|
configuration = scope.configuration,
|
||||||
|
domainObject = self.domainObject;
|
||||||
|
|
||||||
// Log the commit message
|
// Log the commit message
|
||||||
$log.debug([
|
$log.debug([
|
||||||
@ -78,50 +82,33 @@ define(
|
|||||||
if (domainObject && domainObject.hasCapability("persistence")) {
|
if (domainObject && domainObject.hasCapability("persistence")) {
|
||||||
// Configurations for specific views are stored by
|
// Configurations for specific views are stored by
|
||||||
// key in the "configuration" field of the model.
|
// key in the "configuration" field of the model.
|
||||||
if (key && configuration) {
|
if (self.key && configuration) {
|
||||||
model.configuration = model.configuration || {};
|
model.configuration = model.configuration || {};
|
||||||
model.configuration[key] = configuration;
|
model.configuration[self.key] = configuration;
|
||||||
}
|
}
|
||||||
doPersist(model);
|
doPersist(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the destruction of the current representation.
|
|
||||||
function destroy() {
|
|
||||||
// Nothing to clean up
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a specific representation of a specific domain object
|
|
||||||
function represent(representation, representedObject) {
|
|
||||||
// Track the key, to know which view configuration to save to.
|
|
||||||
key = (representation || {}).key;
|
|
||||||
// Track the represented object
|
|
||||||
domainObject = representedObject;
|
|
||||||
// Ensure existing watches are released
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Place the "commit" method in the scope
|
// Place the "commit" method in the scope
|
||||||
scope.commit = commit;
|
scope.commit = commit;
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Set the current representation in use, and the domain
|
|
||||||
* object being represented.
|
|
||||||
*
|
|
||||||
* @param {RepresentationDefinition} representation the
|
|
||||||
* definition of the representation in use
|
|
||||||
* @param {DomainObject} domainObject the domain object
|
|
||||||
* being represented
|
|
||||||
*/
|
|
||||||
represent: represent,
|
|
||||||
/**
|
|
||||||
* Release any resources associated with this representer.
|
|
||||||
*/
|
|
||||||
destroy: destroy
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle a specific representation of a specific domain object
|
||||||
|
EditRepresenter.prototype.represent = function represent(representation, representedObject) {
|
||||||
|
// Track the key, to know which view configuration to save to.
|
||||||
|
this.key = (representation || {}).key;
|
||||||
|
// Track the represented object
|
||||||
|
this.domainObject = representedObject;
|
||||||
|
// Ensure existing watches are released
|
||||||
|
this.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Respond to the destruction of the current representation.
|
||||||
|
EditRepresenter.prototype.destroy = function destroy() {
|
||||||
|
// Nothing to clean up
|
||||||
|
};
|
||||||
|
|
||||||
return EditRepresenter;
|
return EditRepresenter;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -38,125 +38,23 @@ define(
|
|||||||
*
|
*
|
||||||
* @param structure toolbar structure, as provided by view definition
|
* @param structure toolbar structure, as provided by view definition
|
||||||
* @param {Function} commit callback to invoke after changes
|
* @param {Function} commit callback to invoke after changes
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditToolbar(structure, commit) {
|
function EditToolbar(structure, commit) {
|
||||||
var toolbarStructure = Object.create(structure || {}),
|
var self = this;
|
||||||
toolbarState,
|
|
||||||
selection,
|
|
||||||
properties = [];
|
|
||||||
|
|
||||||
// Generate a new key for an item's property
|
// Generate a new key for an item's property
|
||||||
function addKey(property) {
|
function addKey(property) {
|
||||||
properties.push(property);
|
self.properties.push(property);
|
||||||
return properties.length - 1; // Return index of property
|
return self.properties.length - 1; // Return index of property
|
||||||
}
|
|
||||||
|
|
||||||
// Update value for this property in all elements of the
|
|
||||||
// selection which have this property.
|
|
||||||
function updateProperties(property, value) {
|
|
||||||
var changed = false;
|
|
||||||
|
|
||||||
// Update property in a selected element
|
|
||||||
function updateProperty(selected) {
|
|
||||||
// Ignore selected elements which don't have this property
|
|
||||||
if (selected[property] !== undefined) {
|
|
||||||
// Check if this is a setter, or just assignable
|
|
||||||
if (typeof selected[property] === 'function') {
|
|
||||||
changed =
|
|
||||||
changed || (selected[property]() !== value);
|
|
||||||
selected[property](value);
|
|
||||||
} else {
|
|
||||||
changed =
|
|
||||||
changed || (selected[property] !== value);
|
|
||||||
selected[property] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update property in all selected elements
|
|
||||||
selection.forEach(updateProperty);
|
|
||||||
|
|
||||||
// Return whether or not anything changed
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up the current value associated with a property
|
|
||||||
// in selection i
|
|
||||||
function lookupState(property, selected) {
|
|
||||||
var value = selected[property];
|
|
||||||
return (typeof value === 'function') ? value() : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get initial value for a given property
|
|
||||||
function initializeState(property) {
|
|
||||||
var result;
|
|
||||||
// Look through all selections for this property;
|
|
||||||
// values should all match by the time we perform
|
|
||||||
// this lookup anyway.
|
|
||||||
selection.forEach(function (selected) {
|
|
||||||
result = (selected[property] !== undefined) ?
|
|
||||||
lookupState(property, selected) :
|
|
||||||
result;
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if all elements of the selection which have this
|
|
||||||
// property have the same value for this property.
|
|
||||||
function isConsistent(property) {
|
|
||||||
var consistent = true,
|
|
||||||
observed = false,
|
|
||||||
state;
|
|
||||||
|
|
||||||
// Check if a given element of the selection is consistent
|
|
||||||
// with previously-observed elements for this property.
|
|
||||||
function checkConsistency(selected) {
|
|
||||||
var next;
|
|
||||||
// Ignore selections which don't have this property
|
|
||||||
if (selected[property] !== undefined) {
|
|
||||||
// Look up state of this element in the selection
|
|
||||||
next = lookupState(property, selected);
|
|
||||||
// Detect inconsistency
|
|
||||||
if (observed) {
|
|
||||||
consistent = consistent && (next === state);
|
|
||||||
}
|
|
||||||
// Track state for next iteration
|
|
||||||
state = next;
|
|
||||||
observed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through selections
|
|
||||||
selection.forEach(checkConsistency);
|
|
||||||
|
|
||||||
return consistent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to filter out items which are applicable (or not)
|
|
||||||
// to the current selection.
|
|
||||||
function isApplicable(item) {
|
|
||||||
var property = (item || {}).property,
|
|
||||||
method = (item || {}).method,
|
|
||||||
exclusive = !!(item || {}).exclusive;
|
|
||||||
|
|
||||||
// Check if a selected item defines this property
|
|
||||||
function hasProperty(selected) {
|
|
||||||
return (property && (selected[property] !== undefined)) ||
|
|
||||||
(method && (typeof selected[method] === 'function'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return selection.map(hasProperty).reduce(
|
|
||||||
exclusive ? and : or,
|
|
||||||
exclusive
|
|
||||||
) && isConsistent(property);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke all functions in selections with the given name
|
// Invoke all functions in selections with the given name
|
||||||
function invoke(method, value) {
|
function invoke(method, value) {
|
||||||
if (method) {
|
if (method) {
|
||||||
// Make the change in the selection
|
// Make the change in the selection
|
||||||
selection.forEach(function (selected) {
|
self.selection.forEach(function (selected) {
|
||||||
if (typeof selected[method] === 'function') {
|
if (typeof selected[method] === 'function') {
|
||||||
selected[method](value);
|
selected[method](value);
|
||||||
}
|
}
|
||||||
@ -189,73 +87,172 @@ define(
|
|||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.toolbarState = [];
|
||||||
|
this.selection = undefined;
|
||||||
|
this.properties = [];
|
||||||
|
this.toolbarStructure = Object.create(structure || {});
|
||||||
|
this.toolbarStructure.sections =
|
||||||
|
((structure || {}).sections || []).map(convertSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all elements of the selection which have this
|
||||||
|
// property have the same value for this property.
|
||||||
|
EditToolbar.prototype.isConsistent = function (property) {
|
||||||
|
var self = this,
|
||||||
|
consistent = true,
|
||||||
|
observed = false,
|
||||||
|
state;
|
||||||
|
|
||||||
|
// Check if a given element of the selection is consistent
|
||||||
|
// with previously-observed elements for this property.
|
||||||
|
function checkConsistency(selected) {
|
||||||
|
var next;
|
||||||
|
// Ignore selections which don't have this property
|
||||||
|
if (selected[property] !== undefined) {
|
||||||
|
// Look up state of this element in the selection
|
||||||
|
next = self.lookupState(property, selected);
|
||||||
|
// Detect inconsistency
|
||||||
|
if (observed) {
|
||||||
|
consistent = consistent && (next === state);
|
||||||
|
}
|
||||||
|
// Track state for next iteration
|
||||||
|
state = next;
|
||||||
|
observed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through selections
|
||||||
|
self.selection.forEach(checkConsistency);
|
||||||
|
|
||||||
|
return consistent;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used to filter out items which are applicable (or not)
|
||||||
|
// to the current selection.
|
||||||
|
EditToolbar.prototype.isApplicable = function (item) {
|
||||||
|
var property = (item || {}).property,
|
||||||
|
method = (item || {}).method,
|
||||||
|
exclusive = !!(item || {}).exclusive;
|
||||||
|
|
||||||
|
// Check if a selected item defines this property
|
||||||
|
function hasProperty(selected) {
|
||||||
|
return (property && (selected[property] !== undefined)) ||
|
||||||
|
(method && (typeof selected[method] === 'function'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.selection.map(hasProperty).reduce(
|
||||||
|
exclusive ? and : or,
|
||||||
|
exclusive
|
||||||
|
) && this.isConsistent(property);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Look up the current value associated with a property
|
||||||
|
EditToolbar.prototype.lookupState = function (property, selected) {
|
||||||
|
var value = selected[property];
|
||||||
|
return (typeof value === 'function') ? value() : value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current selection. Visibility of sections
|
||||||
|
* and items in the toolbar will be updated to match this.
|
||||||
|
* @param {Array} s the new selection
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.setSelection = function (s) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
// Show/hide controls in this section per applicability
|
// Show/hide controls in this section per applicability
|
||||||
function refreshSectionApplicability(section) {
|
function refreshSectionApplicability(section) {
|
||||||
var count = 0;
|
var count = 0;
|
||||||
// Show/hide each item
|
// Show/hide each item
|
||||||
(section.items || []).forEach(function (item) {
|
(section.items || []).forEach(function (item) {
|
||||||
item.hidden = !isApplicable(item);
|
item.hidden = !self.isApplicable(item);
|
||||||
count += item.hidden ? 0 : 1;
|
count += item.hidden ? 0 : 1;
|
||||||
});
|
});
|
||||||
// Hide this section if there are no applicable items
|
// Hide this section if there are no applicable items
|
||||||
section.hidden = !count;
|
section.hidden = !count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show/hide controls if they are applicable
|
// Get initial value for a given property
|
||||||
function refreshApplicability() {
|
function initializeState(property) {
|
||||||
toolbarStructure.sections.forEach(refreshSectionApplicability);
|
var result;
|
||||||
|
// Look through all selections for this property;
|
||||||
|
// values should all match by the time we perform
|
||||||
|
// this lookup anyway.
|
||||||
|
self.selection.forEach(function (selected) {
|
||||||
|
result = (selected[property] !== undefined) ?
|
||||||
|
self.lookupState(property, selected) :
|
||||||
|
result;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh toolbar state to match selection
|
this.selection = s;
|
||||||
function refreshState() {
|
this.toolbarStructure.sections.forEach(refreshSectionApplicability);
|
||||||
toolbarState = properties.map(initializeState);
|
this.toolbarState = this.properties.map(initializeState);
|
||||||
}
|
};
|
||||||
|
|
||||||
toolbarStructure.sections =
|
/**
|
||||||
((structure || {}).sections || []).map(convertSection);
|
* Get the structure of the toolbar, as appropriate to
|
||||||
|
* pass to `mct-toolbar`.
|
||||||
|
* @returns the toolbar structure
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.getStructure = function () {
|
||||||
|
return this.toolbarStructure;
|
||||||
|
};
|
||||||
|
|
||||||
toolbarState = [];
|
/**
|
||||||
|
* Get the current state of the toolbar, as appropriate
|
||||||
|
* to two-way bind to the state handled by `mct-toolbar`.
|
||||||
|
* @returns {Array} state of the toolbar
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.getState = function () {
|
||||||
|
return this.toolbarState;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
/**
|
||||||
/**
|
* Update state within the current selection.
|
||||||
* Set the current selection. Visisbility of sections
|
* @param {number} index the index of the corresponding
|
||||||
* and items in the toolbar will be updated to match this.
|
* element in the state array
|
||||||
* @param {Array} s the new selection
|
* @param value the new value to convey to the selection
|
||||||
*/
|
*/
|
||||||
setSelection: function (s) {
|
EditToolbar.prototype.updateState = function (index, value) {
|
||||||
selection = s;
|
var self = this;
|
||||||
refreshApplicability();
|
|
||||||
refreshState();
|
// Update value for this property in all elements of the
|
||||||
},
|
// selection which have this property.
|
||||||
/**
|
function updateProperties(property, value) {
|
||||||
* Get the structure of the toolbar, as appropriate to
|
var changed = false;
|
||||||
* pass to `mct-toolbar`.
|
|
||||||
* @returns the toolbar structure
|
// Update property in a selected element
|
||||||
*/
|
function updateProperty(selected) {
|
||||||
getStructure: function () {
|
// Ignore selected elements which don't have this property
|
||||||
return toolbarStructure;
|
if (selected[property] !== undefined) {
|
||||||
},
|
// Check if this is a setter, or just assignable
|
||||||
/**
|
if (typeof selected[property] === 'function') {
|
||||||
* Get the current state of the toolbar, as appropriate
|
changed =
|
||||||
* to two-way bind to the state handled by `mct-toolbar`.
|
changed || (selected[property]() !== value);
|
||||||
* @returns {Array} state of the toolbar
|
selected[property](value);
|
||||||
*/
|
} else {
|
||||||
getState: function () {
|
changed =
|
||||||
return toolbarState;
|
changed || (selected[property] !== value);
|
||||||
},
|
selected[property] = value;
|
||||||
/**
|
}
|
||||||
* Update state within the current selection.
|
}
|
||||||
* @param {number} index the index of the corresponding
|
|
||||||
* element in the state array
|
|
||||||
* @param value the new value to convey to the selection
|
|
||||||
*/
|
|
||||||
updateState: function (index, value) {
|
|
||||||
return updateProperties(properties[index], value);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
// Update property in all selected elements
|
||||||
|
self.selection.forEach(updateProperty);
|
||||||
|
|
||||||
|
// Return whether or not anything changed
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateProperties(this.properties[index], value);
|
||||||
|
};
|
||||||
|
|
||||||
return EditToolbar;
|
return EditToolbar;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,17 +27,21 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// No operation
|
// No operation
|
||||||
function noop() {}
|
var NOOP_REPRESENTER = {
|
||||||
|
represent: function () {},
|
||||||
|
destroy: function () {}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The EditToolbarRepresenter populates the toolbar in Edit mode
|
* The EditToolbarRepresenter populates the toolbar in Edit mode
|
||||||
* based on a view's definition.
|
* based on a view's definition.
|
||||||
* @param {Scope} scope the Angular scope of the representation
|
* @param {Scope} scope the Angular scope of the representation
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Representer}
|
||||||
*/
|
*/
|
||||||
function EditToolbarRepresenter(scope, element, attrs) {
|
function EditToolbarRepresenter(scope, element, attrs) {
|
||||||
var toolbar,
|
var self = this;
|
||||||
toolbarObject = {};
|
|
||||||
|
|
||||||
// Mark changes as ready to persist
|
// Mark changes as ready to persist
|
||||||
function commit(message) {
|
function commit(message) {
|
||||||
@ -49,31 +53,33 @@ define(
|
|||||||
// Handle changes to the current selection
|
// Handle changes to the current selection
|
||||||
function updateSelection(selection) {
|
function updateSelection(selection) {
|
||||||
// Only update if there is a toolbar to update
|
// Only update if there is a toolbar to update
|
||||||
if (toolbar) {
|
if (self.toolbar) {
|
||||||
// Make sure selection is array-like
|
// Make sure selection is array-like
|
||||||
selection = Array.isArray(selection) ?
|
selection = Array.isArray(selection) ?
|
||||||
selection :
|
selection :
|
||||||
(selection ? [selection] : []);
|
(selection ? [selection] : []);
|
||||||
|
|
||||||
// Update the toolbar's selection
|
// Update the toolbar's selection
|
||||||
toolbar.setSelection(selection);
|
self.toolbar.setSelection(selection);
|
||||||
|
|
||||||
// ...and expose its structure/state
|
// ...and expose its structure/state
|
||||||
toolbarObject.structure = toolbar.getStructure();
|
self.toolbarObject.structure =
|
||||||
toolbarObject.state = toolbar.getState();
|
self.toolbar.getStructure();
|
||||||
|
self.toolbarObject.state =
|
||||||
|
self.toolbar.getState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get state (to watch it)
|
// Get state (to watch it)
|
||||||
function getState() {
|
function getState() {
|
||||||
return toolbarObject.state;
|
return self.toolbarObject.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update selection models to match changed toolbar state
|
// Update selection models to match changed toolbar state
|
||||||
function updateState(state) {
|
function updateState(state) {
|
||||||
// Update underlying state based on toolbar changes
|
// Update underlying state based on toolbar changes
|
||||||
var changed = (state || []).map(function (value, index) {
|
var changed = (state || []).map(function (value, index) {
|
||||||
return toolbar.updateState(index, value);
|
return self.toolbar.updateState(index, value);
|
||||||
}).reduce(function (a, b) {
|
}).reduce(function (a, b) {
|
||||||
return a || b;
|
return a || b;
|
||||||
}, false);
|
}, false);
|
||||||
@ -85,66 +91,73 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize toolbar (expose object to parent scope)
|
// Avoid attaching scope to this;
|
||||||
function initialize(definition) {
|
// http://errors.angularjs.org/1.2.26/ng/cpws
|
||||||
// If we have been asked to expose toolbar state...
|
this.setSelection = function (s) {
|
||||||
if (attrs.toolbar) {
|
scope.selection = s;
|
||||||
// Initialize toolbar object
|
};
|
||||||
toolbar = new EditToolbar(definition, commit);
|
this.clearExposedToolbar = function () {
|
||||||
// Ensure toolbar state is exposed
|
|
||||||
scope.$parent[attrs.toolbar] = toolbarObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Represent a domain object using this definition
|
|
||||||
function represent(representation) {
|
|
||||||
// Get the newest toolbar definition from the view
|
|
||||||
var definition = (representation || {}).toolbar || {};
|
|
||||||
// Expose the toolbar object to the parent scope
|
|
||||||
initialize(definition);
|
|
||||||
// Create a selection scope
|
|
||||||
scope.selection = new EditToolbarSelection();
|
|
||||||
// Initialize toolbar to an empty selection
|
|
||||||
updateSelection([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy; remove toolbar object from parent scope
|
|
||||||
function destroy() {
|
|
||||||
// Clear exposed toolbar state (if any)
|
// Clear exposed toolbar state (if any)
|
||||||
if (attrs.toolbar) {
|
if (attrs.toolbar) {
|
||||||
delete scope.$parent[attrs.toolbar];
|
delete scope.$parent[attrs.toolbar];
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
this.exposeToolbar = function () {
|
||||||
|
scope.$parent[self.attrs.toolbar] = self.toolbarObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.commit = commit;
|
||||||
|
this.attrs = attrs;
|
||||||
|
this.updateSelection = updateSelection;
|
||||||
|
this.toolbar = undefined;
|
||||||
|
this.toolbarObject = {};
|
||||||
|
|
||||||
// If this representation exposes a toolbar, set up watches
|
// If this representation exposes a toolbar, set up watches
|
||||||
// to synchronize with it.
|
// to synchronize with it.
|
||||||
if (attrs.toolbar) {
|
if (attrs && attrs.toolbar) {
|
||||||
// Detect and handle changes to state from the toolbar
|
// Detect and handle changes to state from the toolbar
|
||||||
scope.$watchCollection(getState, updateState);
|
scope.$watchCollection(getState, updateState);
|
||||||
// Watch for changes in the current selection state
|
// Watch for changes in the current selection state
|
||||||
scope.$watchCollection("selection.all()", updateSelection);
|
scope.$watchCollection("selection.all()", updateSelection);
|
||||||
// Expose toolbar state under that name
|
// Expose toolbar state under that name
|
||||||
scope.$parent[attrs.toolbar] = toolbarObject;
|
scope.$parent[attrs.toolbar] = this.toolbarObject;
|
||||||
|
} else {
|
||||||
|
// No toolbar declared, so do nothing.
|
||||||
|
return NOOP_REPRESENTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Set the current representation in use, and the domain
|
|
||||||
* object being represented.
|
|
||||||
*
|
|
||||||
* @param {RepresentationDefinition} representation the
|
|
||||||
* definition of the representation in use
|
|
||||||
* @param {DomainObject} domainObject the domain object
|
|
||||||
* being represented
|
|
||||||
*/
|
|
||||||
represent: (attrs || {}).toolbar ? represent : noop,
|
|
||||||
/**
|
|
||||||
* Release any resources associated with this representer.
|
|
||||||
*/
|
|
||||||
destroy: (attrs || {}).toolbar ? destroy : noop
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Represent a domain object using this definition
|
||||||
|
EditToolbarRepresenter.prototype.represent = function (representation) {
|
||||||
|
// Get the newest toolbar definition from the view
|
||||||
|
var definition = (representation || {}).toolbar || {},
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
// Initialize toolbar (expose object to parent scope)
|
||||||
|
function initialize(definition) {
|
||||||
|
// If we have been asked to expose toolbar state...
|
||||||
|
if (self.attrs.toolbar) {
|
||||||
|
// Initialize toolbar object
|
||||||
|
self.toolbar = new EditToolbar(definition, self.commit);
|
||||||
|
// Ensure toolbar state is exposed
|
||||||
|
self.exposeToolbar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose the toolbar object to the parent scope
|
||||||
|
initialize(definition);
|
||||||
|
// Create a selection scope
|
||||||
|
this.setSelection(new EditToolbarSelection());
|
||||||
|
// Initialize toolbar to an empty selection
|
||||||
|
this.updateSelection([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Destroy; remove toolbar object from parent scope
|
||||||
|
EditToolbarRepresenter.prototype.destroy = function () {
|
||||||
|
this.clearExposedToolbar();
|
||||||
|
};
|
||||||
|
|
||||||
return EditToolbarRepresenter;
|
return EditToolbarRepresenter;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -37,110 +37,96 @@ define(
|
|||||||
* * The selection, for single selected elements within the
|
* * The selection, for single selected elements within the
|
||||||
* view.
|
* view.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditToolbarSelection() {
|
function EditToolbarSelection() {
|
||||||
var selection = [ {} ],
|
this.selection = [{}];
|
||||||
selecting = false,
|
this.selecting = false;
|
||||||
selected;
|
this.selectedObj = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the currently-selected object
|
/**
|
||||||
function deselect() {
|
* Check if an object is currently selected.
|
||||||
// Nothing to do if we don't have a selected object
|
* @param {*} obj the object to check for selection
|
||||||
if (selecting) {
|
* @returns {boolean} true if selected, otherwise false
|
||||||
// Clear state tracking
|
*/
|
||||||
selecting = false;
|
EditToolbarSelection.prototype.selected = function (obj) {
|
||||||
selected = undefined;
|
return (obj === this.selectedObj) || (obj === this.selection[0]);
|
||||||
|
};
|
||||||
|
|
||||||
// Remove the selection
|
/**
|
||||||
selection.pop();
|
* Select an object.
|
||||||
|
* @param obj the object to select
|
||||||
return true;
|
* @returns {boolean} true if selection changed
|
||||||
}
|
*/
|
||||||
|
EditToolbarSelection.prototype.select = function (obj) {
|
||||||
|
// Proxy is always selected
|
||||||
|
if (obj === this.selection[0]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select an object
|
// Clear any existing selection
|
||||||
function select(obj) {
|
this.deselect();
|
||||||
// Proxy is always selected
|
|
||||||
if (obj === selection[0]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear any existing selection
|
// Note the current selection state
|
||||||
deselect();
|
this.selectedObj = obj;
|
||||||
|
this.selecting = true;
|
||||||
|
|
||||||
// Note the current selection state
|
// Add the selection
|
||||||
selected = obj;
|
this.selection.push(obj);
|
||||||
selecting = true;
|
};
|
||||||
|
|
||||||
// Add the selection
|
/**
|
||||||
selection.push(obj);
|
* Clear the current selection.
|
||||||
|
* @returns {boolean} true if selection changed
|
||||||
|
*/
|
||||||
|
EditToolbarSelection.prototype.deselect = function () {
|
||||||
|
// Nothing to do if we don't have a selected object
|
||||||
|
if (this.selecting) {
|
||||||
|
// Clear state tracking
|
||||||
|
this.selecting = false;
|
||||||
|
this.selectedObj = undefined;
|
||||||
|
|
||||||
|
// Remove the selection
|
||||||
|
this.selection.pop();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently-selected object.
|
||||||
|
* @returns the currently selected object
|
||||||
|
*/
|
||||||
|
EditToolbarSelection.prototype.get = function () {
|
||||||
|
return this.selectedObj;
|
||||||
|
};
|
||||||
|
|
||||||
// Check if an object is selected
|
/**
|
||||||
function isSelected(obj) {
|
* Get/set the view proxy (for toolbar actions taken upon
|
||||||
return (obj === selected) || (obj === selection[0]);
|
* the view itself.)
|
||||||
|
* @param [proxy] the view proxy (if setting)
|
||||||
|
* @returns the current view proxy
|
||||||
|
*/
|
||||||
|
EditToolbarSelection.prototype.proxy = function (p) {
|
||||||
|
if (arguments.length > 0) {
|
||||||
|
this.selection[0] = p;
|
||||||
}
|
}
|
||||||
|
return this.selection[0];
|
||||||
|
};
|
||||||
|
|
||||||
// Getter for current selection
|
/**
|
||||||
function get() {
|
* Get an array containing all selections, including the
|
||||||
return selected;
|
* selection proxy. It is generally not advisable to
|
||||||
}
|
* mutate this array directly.
|
||||||
|
* @returns {Array} all selections
|
||||||
// Getter/setter for view proxy
|
*/
|
||||||
function proxy(p) {
|
EditToolbarSelection.prototype.all = function () {
|
||||||
if (arguments.length > 0) {
|
return this.selection;
|
||||||
selection[0] = p;
|
};
|
||||||
}
|
|
||||||
return selection[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getter for the full array of selected objects (incl. view proxy)
|
|
||||||
function all() {
|
|
||||||
return selection;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Check if an object is currently selected.
|
|
||||||
* @returns true if selected, otherwise false
|
|
||||||
*/
|
|
||||||
selected: isSelected,
|
|
||||||
/**
|
|
||||||
* Select an object.
|
|
||||||
* @param obj the object to select
|
|
||||||
* @returns {boolean} true if selection changed
|
|
||||||
*/
|
|
||||||
select: select,
|
|
||||||
/**
|
|
||||||
* Clear the current selection.
|
|
||||||
* @returns {boolean} true if selection changed
|
|
||||||
*/
|
|
||||||
deselect: deselect,
|
|
||||||
/**
|
|
||||||
* Get the currently-selected object.
|
|
||||||
* @returns the currently selected object
|
|
||||||
*/
|
|
||||||
get: get,
|
|
||||||
/**
|
|
||||||
* Get/set the view proxy (for toolbar actions taken upon
|
|
||||||
* the view itself.)
|
|
||||||
* @param [proxy] the view proxy (if setting)
|
|
||||||
* @returns the current view proxy
|
|
||||||
*/
|
|
||||||
proxy: proxy,
|
|
||||||
/**
|
|
||||||
* Get an array containing all selections, including the
|
|
||||||
* selection proxy. It is generally not advisable to
|
|
||||||
* mutate this array directly.
|
|
||||||
* @returns {Array} all selections
|
|
||||||
*/
|
|
||||||
all: all
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return EditToolbarSelection;
|
return EditToolbarSelection;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -112,7 +112,9 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("saves objects that have been marked dirty", function () {
|
it("saves objects that have been marked dirty", function () {
|
||||||
var objects = ['a', 'b', 'c'].map(TestObject).map(cache.getEditableObject);
|
var objects = ['a', 'b', 'c'].map(TestObject).map(function (domainObject) {
|
||||||
|
return cache.getEditableObject(domainObject);
|
||||||
|
});
|
||||||
|
|
||||||
cache.markDirty(objects[0]);
|
cache.markDirty(objects[0]);
|
||||||
cache.markDirty(objects[2]);
|
cache.markDirty(objects[2]);
|
||||||
@ -123,7 +125,9 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("does not save objects that have been marked clean", function () {
|
it("does not save objects that have been marked clean", function () {
|
||||||
var objects = ['a', 'b', 'c'].map(TestObject).map(cache.getEditableObject);
|
var objects = ['a', 'b', 'c'].map(TestObject).map(function (domainObject) {
|
||||||
|
return cache.getEditableObject(domainObject);
|
||||||
|
});
|
||||||
|
|
||||||
cache.markDirty(objects[0]);
|
cache.markDirty(objects[0]);
|
||||||
cache.markDirty(objects[2]);
|
cache.markDirty(objects[2]);
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/* CONSTANTS */
|
/* CONSTANTS */
|
||||||
|
/*****************************************************************************
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
@ -92,7 +93,7 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/* line 5, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 5, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||||
html, body, div, span, applet, object, iframe,
|
html, body, div, span, applet, object, iframe,
|
||||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
a, abbr, acronym, address, big, cite, code,
|
a, abbr, acronym, address, big, cite, code,
|
||||||
@ -113,38 +114,38 @@ time, mark, audio, video {
|
|||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
vertical-align: baseline; }
|
vertical-align: baseline; }
|
||||||
|
|
||||||
/* line 22, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 22, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||||
html {
|
html {
|
||||||
line-height: 1; }
|
line-height: 1; }
|
||||||
|
|
||||||
/* line 24, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 24, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||||
ol, ul {
|
ol, ul {
|
||||||
list-style: none; }
|
list-style: none; }
|
||||||
|
|
||||||
/* line 26, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 26, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
border-spacing: 0; }
|
border-spacing: 0; }
|
||||||
|
|
||||||
/* line 28, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 28, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||||
caption, th, td {
|
caption, th, td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
vertical-align: middle; }
|
vertical-align: middle; }
|
||||||
|
|
||||||
/* line 30, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 30, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||||
q, blockquote {
|
q, blockquote {
|
||||||
quotes: none; }
|
quotes: none; }
|
||||||
/* line 103, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 103, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||||
q:before, q:after, blockquote:before, blockquote:after {
|
q:before, q:after, blockquote:before, blockquote:after {
|
||||||
content: "";
|
content: "";
|
||||||
content: none; }
|
content: none; }
|
||||||
|
|
||||||
/* line 32, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 32, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||||
a img {
|
a img {
|
||||||
border: none; }
|
border: none; }
|
||||||
|
|
||||||
/* line 116, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
/* line 116, ../../../../../../../../.gem/ruby/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 {
|
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
|
||||||
display: block; }
|
display: block; }
|
||||||
|
|
||||||
@ -172,11 +173,11 @@ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu,
|
|||||||
/*********************************************** FORM ELEMENTS */
|
/*********************************************** FORM ELEMENTS */
|
||||||
/*
|
/*
|
||||||
@mixin invokeMenu($baseColor: $colorBodyFg) {
|
@mixin invokeMenu($baseColor: $colorBodyFg) {
|
||||||
$c: $baseColor;
|
$c: $baseColor;
|
||||||
color: $c;
|
color: $c;
|
||||||
&:hover {
|
&:hover {
|
||||||
color: lighten($c, $ltGamma);
|
color: lighten($c, $ltGamma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@ -644,44 +645,46 @@ mct-container {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 5px; }
|
bottom: 5px; }
|
||||||
/* line 232, ../sass/user-environ/_layout.scss */
|
/* line 232, ../sass/user-environ/_layout.scss */
|
||||||
|
.pane.treeview.left .search-holder {
|
||||||
|
top: 34px; }
|
||||||
|
/* line 235, ../sass/user-environ/_layout.scss */
|
||||||
.pane.treeview.left .tree-holder {
|
.pane.treeview.left .tree-holder {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
top: 34px;
|
top: 64px; }
|
||||||
padding-right: 5px; }
|
/* line 242, ../sass/user-environ/_layout.scss */
|
||||||
/* line 240, ../sass/user-environ/_layout.scss */
|
|
||||||
.pane.items .object-browse-bar .left.abs, .pane.items .object-browse-bar .btn-menu span.left.l-click-area, .btn-menu .pane.items .object-browse-bar span.left.l-click-area,
|
.pane.items .object-browse-bar .left.abs, .pane.items .object-browse-bar .btn-menu span.left.l-click-area, .btn-menu .pane.items .object-browse-bar span.left.l-click-area,
|
||||||
.pane.items .object-browse-bar .right.abs,
|
.pane.items .object-browse-bar .right.abs,
|
||||||
.pane.items .object-browse-bar .btn-menu span.right.l-click-area,
|
.pane.items .object-browse-bar .btn-menu span.right.l-click-area,
|
||||||
.btn-menu .pane.items .object-browse-bar span.right.l-click-area {
|
.btn-menu .pane.items .object-browse-bar span.right.l-click-area {
|
||||||
top: auto; }
|
top: auto; }
|
||||||
/* line 245, ../sass/user-environ/_layout.scss */
|
/* line 247, ../sass/user-environ/_layout.scss */
|
||||||
.pane.items .object-holder {
|
.pane.items .object-holder {
|
||||||
top: 34px; }
|
top: 34px; }
|
||||||
/* line 249, ../sass/user-environ/_layout.scss */
|
/* line 251, ../sass/user-environ/_layout.scss */
|
||||||
.pane .object-holder {
|
.pane .object-holder {
|
||||||
overflow: auto; }
|
overflow: auto; }
|
||||||
|
|
||||||
/* line 257, ../sass/user-environ/_layout.scss */
|
/* line 259, ../sass/user-environ/_layout.scss */
|
||||||
.split-layout.horizontal > .pane {
|
.split-layout.horizontal > .pane {
|
||||||
margin-top: 5px; }
|
margin-top: 5px; }
|
||||||
/* line 260, ../sass/user-environ/_layout.scss */
|
/* line 262, ../sass/user-environ/_layout.scss */
|
||||||
.split-layout.horizontal > .pane:first-child {
|
.split-layout.horizontal > .pane:first-child {
|
||||||
margin-top: 0; }
|
margin-top: 0; }
|
||||||
/* line 267, ../sass/user-environ/_layout.scss */
|
/* line 269, ../sass/user-environ/_layout.scss */
|
||||||
.split-layout.vertical > .pane {
|
.split-layout.vertical > .pane {
|
||||||
margin-left: 5px; }
|
margin-left: 5px; }
|
||||||
/* line 269, ../sass/user-environ/_layout.scss */
|
/* line 271, ../sass/user-environ/_layout.scss */
|
||||||
.split-layout.vertical > .pane > .holder {
|
.split-layout.vertical > .pane > .holder {
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0; }
|
right: 0; }
|
||||||
/* line 273, ../sass/user-environ/_layout.scss */
|
/* line 275, ../sass/user-environ/_layout.scss */
|
||||||
.split-layout.vertical > .pane:first-child {
|
.split-layout.vertical > .pane:first-child {
|
||||||
margin-left: 0; }
|
margin-left: 0; }
|
||||||
/* line 275, ../sass/user-environ/_layout.scss */
|
/* line 277, ../sass/user-environ/_layout.scss */
|
||||||
.split-layout.vertical > .pane:first-child .holder {
|
.split-layout.vertical > .pane:first-child .holder {
|
||||||
right: 3px; }
|
right: 3px; }
|
||||||
|
|
||||||
/* line 284, ../sass/user-environ/_layout.scss */
|
/* line 286, ../sass/user-environ/_layout.scss */
|
||||||
.vscroll {
|
.vscroll {
|
||||||
overflow-y: auto; }
|
overflow-y: auto; }
|
||||||
|
|
||||||
@ -1049,27 +1052,27 @@ mct-container {
|
|||||||
|
|
||||||
/*.s-limit-upr,
|
/*.s-limit-upr,
|
||||||
.s-limit-lwr {
|
.s-limit-lwr {
|
||||||
$a: 0.5;
|
$a: 0.5;
|
||||||
$l: 30%;
|
$l: 30%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
&:before {
|
&:before {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-family: symbolsfont;
|
font-family: symbolsfont;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
font-style: normal !important;
|
font-style: normal !important;
|
||||||
margin-right: $interiorMarginSm;
|
margin-right: $interiorMarginSm;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.s-limit-upr {
|
.s-limit-upr {
|
||||||
&.s-limit-yellow { @include limit($colorLimitYellow, "\0000ed"); }
|
&.s-limit-yellow { @include limit($colorLimitYellow, "\0000ed"); }
|
||||||
&.s-limit-red { @include limit($colorLimitRed, "\0000eb"); }
|
&.s-limit-red { @include limit($colorLimitRed, "\0000eb"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.s-limit-lwr {
|
.s-limit-lwr {
|
||||||
&.s-limit-yellow { @include limit($colorLimitYellow, "\0000ec"); }
|
&.s-limit-yellow { @include limit($colorLimitYellow, "\0000ec"); }
|
||||||
&.s-limit-red { @include limit($colorLimitRed, "\0000ee"); }
|
&.s-limit-red { @include limit($colorLimitRed, "\0000ee"); }
|
||||||
}*/
|
}*/
|
||||||
/* line 35, ../sass/_limits.scss */
|
/* line 35, ../sass/_limits.scss */
|
||||||
[class*="s-limit"] {
|
[class*="s-limit"] {
|
||||||
@ -1237,29 +1240,32 @@ table {
|
|||||||
table .tr .th:first-child {
|
table .tr .th:first-child {
|
||||||
border-left: none; }
|
border-left: none; }
|
||||||
/* line 85, ../sass/lists/_tabular.scss */
|
/* line 85, ../sass/lists/_tabular.scss */
|
||||||
.tabular tr th.sort .icon-sorting:before, .tabular tr .th.sort .icon-sorting:before, .tabular .tr th.sort .icon-sorting:before, .tabular .tr .th.sort .icon-sorting:before,
|
.tabular tr th.sort.sort:after, .tabular tr .th.sort.sort:after, .tabular .tr th.sort.sort:after, .tabular .tr .th.sort.sort:after,
|
||||||
table tr th.sort .icon-sorting:before,
|
table tr th.sort.sort:after,
|
||||||
table tr .th.sort .icon-sorting:before,
|
table tr .th.sort.sort:after,
|
||||||
table .tr th.sort .icon-sorting:before,
|
table .tr th.sort.sort:after,
|
||||||
table .tr .th.sort .icon-sorting:before {
|
table .tr .th.sort.sort:after {
|
||||||
display: inline-block;
|
color: #49dedb;
|
||||||
font-family: symbolsfont;
|
font-family: symbolsfont;
|
||||||
margin-left: 5px; }
|
font-size: 8px;
|
||||||
/* line 90, ../sass/lists/_tabular.scss */
|
content: "\ed";
|
||||||
.tabular tr th.sort.asc .icon-sorting:before, .tabular tr .th.sort.asc .icon-sorting:before, .tabular .tr th.sort.asc .icon-sorting:before, .tabular .tr .th.sort.asc .icon-sorting:before,
|
display: inline-block;
|
||||||
table tr th.sort.asc .icon-sorting:before,
|
margin-left: 3px; }
|
||||||
table tr .th.sort.asc .icon-sorting:before,
|
|
||||||
table .tr th.sort.asc .icon-sorting:before,
|
|
||||||
table .tr .th.sort.asc .icon-sorting:before {
|
|
||||||
content: '0'; }
|
|
||||||
/* line 93, ../sass/lists/_tabular.scss */
|
/* line 93, ../sass/lists/_tabular.scss */
|
||||||
.tabular tr th.sort.desc .icon-sorting:before, .tabular tr .th.sort.desc .icon-sorting:before, .tabular .tr th.sort.desc .icon-sorting:before, .tabular .tr .th.sort.desc .icon-sorting:before,
|
.tabular tr th.sort.sort.desc:after, .tabular tr .th.sort.sort.desc:after, .tabular .tr th.sort.sort.desc:after, .tabular .tr .th.sort.sort.desc:after,
|
||||||
table tr th.sort.desc .icon-sorting:before,
|
table tr th.sort.sort.desc:after,
|
||||||
table tr .th.sort.desc .icon-sorting:before,
|
table tr .th.sort.sort.desc:after,
|
||||||
table .tr th.sort.desc .icon-sorting:before,
|
table .tr th.sort.sort.desc:after,
|
||||||
table .tr .th.sort.desc .icon-sorting:before {
|
table .tr .th.sort.sort.desc:after {
|
||||||
content: '1'; }
|
content: "\ec"; }
|
||||||
/* line 98, ../sass/lists/_tabular.scss */
|
/* line 97, ../sass/lists/_tabular.scss */
|
||||||
|
.tabular tr th.sortable, .tabular tr .th.sortable, .tabular .tr th.sortable, .tabular .tr .th.sortable,
|
||||||
|
table tr th.sortable,
|
||||||
|
table tr .th.sortable,
|
||||||
|
table .tr th.sortable,
|
||||||
|
table .tr .th.sortable {
|
||||||
|
cursor: pointer; }
|
||||||
|
/* line 101, ../sass/lists/_tabular.scss */
|
||||||
.tabular tr td, .tabular tr .td, .tabular .tr td, .tabular .tr .td,
|
.tabular tr td, .tabular tr .td, .tabular .tr td, .tabular .tr .td,
|
||||||
table tr td,
|
table tr td,
|
||||||
table tr .td,
|
table tr .td,
|
||||||
@ -1271,21 +1277,21 @@ table {
|
|||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
vertical-align: top; }
|
vertical-align: top; }
|
||||||
/* line 105, ../sass/lists/_tabular.scss */
|
/* line 108, ../sass/lists/_tabular.scss */
|
||||||
.tabular tr td.numeric, .tabular tr .td.numeric, .tabular .tr td.numeric, .tabular .tr .td.numeric,
|
.tabular tr td.numeric, .tabular tr .td.numeric, .tabular .tr td.numeric, .tabular .tr .td.numeric,
|
||||||
table tr td.numeric,
|
table tr td.numeric,
|
||||||
table tr .td.numeric,
|
table tr .td.numeric,
|
||||||
table .tr td.numeric,
|
table .tr td.numeric,
|
||||||
table .tr .td.numeric {
|
table .tr .td.numeric {
|
||||||
text-align: right; }
|
text-align: right; }
|
||||||
/* line 108, ../sass/lists/_tabular.scss */
|
/* line 111, ../sass/lists/_tabular.scss */
|
||||||
.tabular tr td.s-cell-type-value, .tabular tr .td.s-cell-type-value, .tabular .tr td.s-cell-type-value, .tabular .tr .td.s-cell-type-value,
|
.tabular tr td.s-cell-type-value, .tabular tr .td.s-cell-type-value, .tabular .tr td.s-cell-type-value, .tabular .tr .td.s-cell-type-value,
|
||||||
table tr td.s-cell-type-value,
|
table tr td.s-cell-type-value,
|
||||||
table tr .td.s-cell-type-value,
|
table tr .td.s-cell-type-value,
|
||||||
table .tr td.s-cell-type-value,
|
table .tr td.s-cell-type-value,
|
||||||
table .tr .td.s-cell-type-value {
|
table .tr .td.s-cell-type-value {
|
||||||
text-align: right; }
|
text-align: right; }
|
||||||
/* line 110, ../sass/lists/_tabular.scss */
|
/* line 113, ../sass/lists/_tabular.scss */
|
||||||
.tabular tr td.s-cell-type-value .l-cell-contents, .tabular tr .td.s-cell-type-value .l-cell-contents, .tabular .tr td.s-cell-type-value .l-cell-contents, .tabular .tr .td.s-cell-type-value .l-cell-contents,
|
.tabular tr td.s-cell-type-value .l-cell-contents, .tabular tr .td.s-cell-type-value .l-cell-contents, .tabular .tr td.s-cell-type-value .l-cell-contents, .tabular .tr .td.s-cell-type-value .l-cell-contents,
|
||||||
table tr td.s-cell-type-value .l-cell-contents,
|
table tr td.s-cell-type-value .l-cell-contents,
|
||||||
table tr .td.s-cell-type-value .l-cell-contents,
|
table tr .td.s-cell-type-value .l-cell-contents,
|
||||||
@ -1296,23 +1302,23 @@ table {
|
|||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px; }
|
padding-right: 5px; }
|
||||||
/* line 126, ../sass/lists/_tabular.scss */
|
/* line 129, ../sass/lists/_tabular.scss */
|
||||||
.tabular.filterable tbody, .tabular.filterable .tbody,
|
.tabular.filterable tbody, .tabular.filterable .tbody,
|
||||||
table.filterable tbody,
|
table.filterable tbody,
|
||||||
table.filterable .tbody {
|
table.filterable .tbody {
|
||||||
top: 44px; }
|
top: 44px; }
|
||||||
/* line 129, ../sass/lists/_tabular.scss */
|
/* line 132, ../sass/lists/_tabular.scss */
|
||||||
.tabular.filterable input[type="text"],
|
.tabular.filterable input[type="text"],
|
||||||
table.filterable input[type="text"] {
|
table.filterable input[type="text"] {
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%; }
|
width: 100%; }
|
||||||
/* line 135, ../sass/lists/_tabular.scss */
|
/* line 138, ../sass/lists/_tabular.scss */
|
||||||
.tabular.fixed-header,
|
.tabular.fixed-header,
|
||||||
table.fixed-header {
|
table.fixed-header {
|
||||||
height: 100%; }
|
height: 100%; }
|
||||||
/* line 137, ../sass/lists/_tabular.scss */
|
/* line 140, ../sass/lists/_tabular.scss */
|
||||||
.tabular.fixed-header thead, .tabular.fixed-header .thead,
|
.tabular.fixed-header thead, .tabular.fixed-header .thead,
|
||||||
.tabular.fixed-header tbody tr, .tabular.fixed-header .tbody .tr,
|
.tabular.fixed-header tbody tr, .tabular.fixed-header .tbody .tr,
|
||||||
table.fixed-header thead,
|
table.fixed-header thead,
|
||||||
@ -1321,12 +1327,12 @@ table {
|
|||||||
table.fixed-header .tbody .tr {
|
table.fixed-header .tbody .tr {
|
||||||
display: table;
|
display: table;
|
||||||
table-layout: fixed; }
|
table-layout: fixed; }
|
||||||
/* line 142, ../sass/lists/_tabular.scss */
|
/* line 145, ../sass/lists/_tabular.scss */
|
||||||
.tabular.fixed-header thead, .tabular.fixed-header .thead,
|
.tabular.fixed-header thead, .tabular.fixed-header .thead,
|
||||||
table.fixed-header thead,
|
table.fixed-header thead,
|
||||||
table.fixed-header .thead {
|
table.fixed-header .thead {
|
||||||
width: calc(100% - 10px); }
|
width: calc(100% - 10px); }
|
||||||
/* line 144, ../sass/lists/_tabular.scss */
|
/* line 147, ../sass/lists/_tabular.scss */
|
||||||
.tabular.fixed-header thead:before, .tabular.fixed-header .thead:before,
|
.tabular.fixed-header thead:before, .tabular.fixed-header .thead:before,
|
||||||
table.fixed-header thead:before,
|
table.fixed-header thead:before,
|
||||||
table.fixed-header .thead:before {
|
table.fixed-header .thead:before {
|
||||||
@ -1337,7 +1343,7 @@ table {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
background: rgba(255, 255, 255, 0.15); }
|
background: rgba(255, 255, 255, 0.15); }
|
||||||
/* line 154, ../sass/lists/_tabular.scss */
|
/* line 157, ../sass/lists/_tabular.scss */
|
||||||
.tabular.fixed-header tbody, .tabular.fixed-header .tbody,
|
.tabular.fixed-header tbody, .tabular.fixed-header .tbody,
|
||||||
table.fixed-header tbody,
|
table.fixed-header tbody,
|
||||||
table.fixed-header .tbody {
|
table.fixed-header .tbody {
|
||||||
@ -1352,7 +1358,7 @@ table {
|
|||||||
top: 22px;
|
top: 22px;
|
||||||
display: block;
|
display: block;
|
||||||
overflow-y: scroll; }
|
overflow-y: scroll; }
|
||||||
/* line 162, ../sass/lists/_tabular.scss */
|
/* line 165, ../sass/lists/_tabular.scss */
|
||||||
.tabular.t-event-messages td, .tabular.t-event-messages .td,
|
.tabular.t-event-messages td, .tabular.t-event-messages .td,
|
||||||
table.t-event-messages td,
|
table.t-event-messages td,
|
||||||
table.t-event-messages .td {
|
table.t-event-messages .td {
|
||||||
@ -1772,11 +1778,11 @@ table {
|
|||||||
/* line 132, ../sass/controls/_buttons.scss */
|
/* line 132, ../sass/controls/_buttons.scss */
|
||||||
.icon-btn.pause-play,
|
.icon-btn.pause-play,
|
||||||
.s-icon-btn.pause-play {
|
.s-icon-btn.pause-play {
|
||||||
/* &.paused {
|
/* &.paused {
|
||||||
.icon {
|
.icon {
|
||||||
@include pulse(500ms);
|
@include pulse(500ms);
|
||||||
}
|
}
|
||||||
}*/ }
|
}*/ }
|
||||||
/* line 138, ../sass/controls/_buttons.scss */
|
/* line 138, ../sass/controls/_buttons.scss */
|
||||||
.icon-btn.pause-play .icon:before,
|
.icon-btn.pause-play .icon:before,
|
||||||
.s-icon-btn.pause-play .icon:before {
|
.s-icon-btn.pause-play .icon:before {
|
||||||
@ -1899,32 +1905,32 @@ a.l-btn span {
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*.control {
|
/*.control {
|
||||||
// UNUSED?
|
// UNUSED?
|
||||||
&.view-control {
|
&.view-control {
|
||||||
.icon {
|
.icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: -1px 5px 1px 2px;
|
margin: -1px 5px 1px 2px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
&.triangle-down {
|
&.triangle-down {
|
||||||
margin: 2px 2px -2px 0px;
|
margin: 2px 2px -2px 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle {
|
.toggle {
|
||||||
@include border-radius(3px);
|
@include border-radius(3px);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 1px 6px 4px 4px;
|
padding: 1px 6px 4px 4px;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(white, 0.1);
|
background: rgba(white, 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
/* line 51, ../sass/controls/_controls.scss */
|
/* line 51, ../sass/controls/_controls.scss */
|
||||||
.accordion {
|
.accordion {
|
||||||
@ -2161,23 +2167,23 @@ label.checkbox.custom {
|
|||||||
border-top: 1px solid #575757;
|
border-top: 1px solid #575757;
|
||||||
color: #999;
|
color: #999;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
/* height: $h;
|
/* height: $h;
|
||||||
line-height: $h;
|
line-height: $h;
|
||||||
&.dropdown {
|
&.dropdown {
|
||||||
padding-left: $p;
|
padding-left: $p;
|
||||||
padding-right: $p;
|
padding-right: $p;
|
||||||
}*/
|
}*/
|
||||||
/* &.context-available {
|
/* &.context-available {
|
||||||
// An element like the invoke-menu triangle;
|
// An element like the invoke-menu triangle;
|
||||||
// Indicates that this element has a dropdown menu available;
|
// Indicates that this element has a dropdown menu available;
|
||||||
// Currently unused
|
// Currently unused
|
||||||
$c: $colorKey;
|
$c: $colorKey;
|
||||||
color: $c;
|
color: $c;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
&:hover {
|
&:hover {
|
||||||
color: lighten($c, 10%);
|
color: lighten($c, 10%);
|
||||||
}
|
}
|
||||||
}*/ }
|
}*/ }
|
||||||
/* line 162, ../sass/_mixins.scss */
|
/* line 162, ../sass/_mixins.scss */
|
||||||
.btn-menu:not(.disabled):hover {
|
.btn-menu:not(.disabled):hover {
|
||||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
|
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
|
||||||
@ -2568,22 +2574,23 @@ label.checkbox.custom {
|
|||||||
color: #d9d9d9;
|
color: #d9d9d9;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
padding: 3px 10px 3px 30px;
|
padding: 3px 10px 3px 30px;
|
||||||
|
position: relative;
|
||||||
white-space: nowrap; }
|
white-space: nowrap; }
|
||||||
/* line 46, ../sass/controls/_menus.scss */
|
/* line 47, ../sass/controls/_menus.scss */
|
||||||
.menu-element .menu ul li:first-child {
|
.menu-element .menu ul li:first-child {
|
||||||
border: none; }
|
border: none; }
|
||||||
/* line 49, ../sass/controls/_menus.scss */
|
/* line 50, ../sass/controls/_menus.scss */
|
||||||
.menu-element .menu ul li:hover {
|
.menu-element .menu ul li:hover {
|
||||||
background: #737373;
|
background: #737373;
|
||||||
color: #fff; }
|
color: #fff; }
|
||||||
/* line 55, ../sass/controls/_menus.scss */
|
/* line 56, ../sass/controls/_menus.scss */
|
||||||
.menu-element .menu ul li:hover .icon {
|
.menu-element .menu ul li:hover .icon {
|
||||||
color: #33ccff; }
|
color: #33ccff; }
|
||||||
/* line 63, ../sass/controls/_menus.scss */
|
/* line 64, ../sass/controls/_menus.scss */
|
||||||
.menu-element .menu ul li .type-icon {
|
.menu-element .menu ul li .type-icon {
|
||||||
left: 10px; }
|
left: 10px; }
|
||||||
/* line 70, ../sass/controls/_menus.scss */
|
/* line 71, ../sass/controls/_menus.scss */
|
||||||
.menu-element .context-menu,
|
.menu-element .context-menu, .menu-element .checkbox-menu,
|
||||||
.menu-element .super-menu {
|
.menu-element .super-menu {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzhjOGM4YyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzgwODA4MCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
|
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzhjOGM4YyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzgwODA4MCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
|
||||||
@ -2606,35 +2613,56 @@ label.checkbox.custom {
|
|||||||
color: #999;
|
color: #999;
|
||||||
display: inline-block; }
|
display: inline-block; }
|
||||||
/* line 170, ../sass/_mixins.scss */
|
/* line 170, ../sass/_mixins.scss */
|
||||||
.menu-element .context-menu.btn-menu .invoke-menu,
|
.menu-element .context-menu.btn-menu .invoke-menu, .menu-element .btn-menu.checkbox-menu .invoke-menu,
|
||||||
.menu-element .super-menu.btn-menu .invoke-menu {
|
.menu-element .super-menu.btn-menu .invoke-menu {
|
||||||
color: #b0b0b0; }
|
color: #b0b0b0; }
|
||||||
/* line 78, ../sass/controls/_menus.scss */
|
/* line 79, ../sass/controls/_menus.scss */
|
||||||
.menu-element .context-menu ul li,
|
.menu-element .context-menu ul li, .menu-element .checkbox-menu ul li,
|
||||||
.menu-element .super-menu ul li {
|
.menu-element .super-menu ul li {
|
||||||
padding-left: 25px; }
|
padding-left: 25px; }
|
||||||
/* line 80, ../sass/controls/_menus.scss */
|
/* line 81, ../sass/controls/_menus.scss */
|
||||||
.menu-element .context-menu ul li a,
|
.menu-element .context-menu ul li a, .menu-element .checkbox-menu ul li a,
|
||||||
.menu-element .super-menu ul li a {
|
.menu-element .super-menu ul li a {
|
||||||
color: white; }
|
color: white; }
|
||||||
/* line 81, ../sass/controls/_menus.scss */
|
/* line 84, ../sass/controls/_menus.scss */
|
||||||
.menu-element .context-menu ul li .icon,
|
.menu-element .context-menu ul li .icon, .menu-element .checkbox-menu ul li .icon,
|
||||||
.menu-element .super-menu ul li .icon {
|
.menu-element .super-menu ul li .icon {
|
||||||
color: #24c8ff; }
|
color: #24c8ff; }
|
||||||
/* line 84, ../sass/controls/_menus.scss */
|
/* line 87, ../sass/controls/_menus.scss */
|
||||||
.menu-element .context-menu ul li .type-icon,
|
.menu-element .context-menu ul li .type-icon, .menu-element .checkbox-menu ul li .type-icon,
|
||||||
.menu-element .super-menu ul li .type-icon {
|
.menu-element .super-menu ul li .type-icon {
|
||||||
left: 5px; }
|
left: 5px; }
|
||||||
/* line 87, ../sass/controls/_menus.scss */
|
/* line 90, ../sass/controls/_menus.scss */
|
||||||
.menu-element .context-menu ul li:hover .icon,
|
.menu-element .context-menu ul li:hover .icon, .menu-element .checkbox-menu ul li:hover .icon,
|
||||||
.menu-element .super-menu ul li:hover .icon {
|
.menu-element .super-menu ul li:hover .icon {
|
||||||
color: #3dcfff; }
|
color: #3dcfff; }
|
||||||
/* line 94, ../sass/controls/_menus.scss */
|
/* line 99, ../sass/controls/_menus.scss */
|
||||||
|
.menu-element .checkbox-menu ul li {
|
||||||
|
padding-left: 50px; }
|
||||||
|
/* line 101, ../sass/controls/_menus.scss */
|
||||||
|
.menu-element .checkbox-menu ul li .checkbox {
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
top: 0.53333rem; }
|
||||||
|
/* line 106, ../sass/controls/_menus.scss */
|
||||||
|
.menu-element .checkbox-menu ul li .checkbox em {
|
||||||
|
height: 0.7rem;
|
||||||
|
width: 0.7rem; }
|
||||||
|
/* line 109, ../sass/controls/_menus.scss */
|
||||||
|
.menu-element .checkbox-menu ul li .checkbox em:before {
|
||||||
|
font-size: 7px !important;
|
||||||
|
height: 0.7rem;
|
||||||
|
width: 0.7rem;
|
||||||
|
line-height: 0.7rem; }
|
||||||
|
/* line 117, ../sass/controls/_menus.scss */
|
||||||
|
.menu-element .checkbox-menu ul li .type-icon {
|
||||||
|
left: 25px; }
|
||||||
|
/* line 123, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu {
|
.menu-element .super-menu {
|
||||||
display: block;
|
display: block;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
height: 480px; }
|
height: 480px; }
|
||||||
/* line 104, ../sass/controls/_menus.scss */
|
/* line 133, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .contents {
|
.menu-element .super-menu .contents {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -2644,12 +2672,12 @@ label.checkbox.custom {
|
|||||||
left: 5px;
|
left: 5px;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto; }
|
height: auto; }
|
||||||
/* line 107, ../sass/controls/_menus.scss */
|
/* line 136, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .pane {
|
.menu-element .super-menu .pane {
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
box-sizing: border-box; }
|
box-sizing: border-box; }
|
||||||
/* line 109, ../sass/controls/_menus.scss */
|
/* line 138, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .pane.left {
|
.menu-element .super-menu .pane.left {
|
||||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -2658,23 +2686,23 @@ label.checkbox.custom {
|
|||||||
width: 50%;
|
width: 50%;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto; }
|
overflow-y: auto; }
|
||||||
/* line 119, ../sass/controls/_menus.scss */
|
/* line 148, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .pane.left ul li {
|
.menu-element .super-menu .pane.left ul li {
|
||||||
-moz-border-radius: 3px;
|
-moz-border-radius: 3px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding-left: 30px;
|
padding-left: 30px;
|
||||||
border-top: none; }
|
border-top: none; }
|
||||||
/* line 126, ../sass/controls/_menus.scss */
|
/* line 155, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .pane.right {
|
.menu-element .super-menu .pane.right {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: 0;
|
right: 0;
|
||||||
padding: 25px;
|
padding: 25px;
|
||||||
width: 50%; }
|
width: 50%; }
|
||||||
/* line 132, ../sass/controls/_menus.scss */
|
/* line 161, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .pane.right .icon {
|
.menu-element .super-menu .pane.right .icon {
|
||||||
color: #fff; }
|
color: #fff; }
|
||||||
/* line 139, ../sass/controls/_menus.scss */
|
/* line 168, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .menu-item-description .desc-area.icon {
|
.menu-element .super-menu .menu-item-description .desc-area.icon {
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 8em;
|
font-size: 8em;
|
||||||
@ -2683,40 +2711,40 @@ label.checkbox.custom {
|
|||||||
line-height: 150px;
|
line-height: 150px;
|
||||||
margin-bottom: 25px;
|
margin-bottom: 25px;
|
||||||
text-align: center; }
|
text-align: center; }
|
||||||
/* line 149, ../sass/controls/_menus.scss */
|
/* line 178, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .menu-item-description .desc-area.title {
|
.menu-element .super-menu .menu-item-description .desc-area.title {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
margin-bottom: 0.5em; }
|
margin-bottom: 0.5em; }
|
||||||
/* line 154, ../sass/controls/_menus.scss */
|
/* line 183, ../sass/controls/_menus.scss */
|
||||||
.menu-element .super-menu .menu-item-description .desc-area.description {
|
.menu-element .super-menu .menu-item-description .desc-area.description {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
line-height: 1.5em; }
|
line-height: 1.5em; }
|
||||||
/* line 163, ../sass/controls/_menus.scss */
|
/* line 192, ../sass/controls/_menus.scss */
|
||||||
.menu-element .context-menu {
|
.menu-element .context-menu, .menu-element .checkbox-menu {
|
||||||
font-size: 0.80rem; }
|
font-size: 0.80rem; }
|
||||||
|
|
||||||
/* line 168, ../sass/controls/_menus.scss */
|
/* line 197, ../sass/controls/_menus.scss */
|
||||||
.context-menu-holder {
|
.context-menu-holder {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
width: 170px;
|
width: 170px;
|
||||||
z-index: 70; }
|
z-index: 70; }
|
||||||
/* line 174, ../sass/controls/_menus.scss */
|
/* line 203, ../sass/controls/_menus.scss */
|
||||||
.context-menu-holder .context-menu-wrapper {
|
.context-menu-holder .context-menu-wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%; }
|
width: 100%; }
|
||||||
/* line 181, ../sass/controls/_menus.scss */
|
/* line 210, ../sass/controls/_menus.scss */
|
||||||
.context-menu-holder.go-left .context-menu {
|
.context-menu-holder.go-left .context-menu, .context-menu-holder.go-left .menu-element .checkbox-menu, .menu-element .context-menu-holder.go-left .checkbox-menu {
|
||||||
right: 0; }
|
right: 0; }
|
||||||
/* line 182, ../sass/controls/_menus.scss */
|
/* line 213, ../sass/controls/_menus.scss */
|
||||||
.context-menu-holder.go-up .context-menu {
|
.context-menu-holder.go-up .context-menu, .context-menu-holder.go-up .menu-element .checkbox-menu, .menu-element .context-menu-holder.go-up .checkbox-menu {
|
||||||
bottom: 0; }
|
bottom: 0; }
|
||||||
|
|
||||||
/* line 185, ../sass/controls/_menus.scss */
|
/* line 218, ../sass/controls/_menus.scss */
|
||||||
.btn-bar.right .menu,
|
.btn-bar.right .menu,
|
||||||
.menus-to-left .menu {
|
.menus-to-left .menu {
|
||||||
left: auto;
|
left: auto;
|
||||||
@ -4429,26 +4457,26 @@ input[type="text"] {
|
|||||||
.l-infobubble-wrapper .l-infobubble table tr td {
|
.l-infobubble-wrapper .l-infobubble table tr td {
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
vertical-align: top; }
|
vertical-align: top; }
|
||||||
/* line 57, ../sass/helpers/_bubbles.scss */
|
/* line 53, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper .l-infobubble table tr td.label {
|
.l-infobubble-wrapper .l-infobubble table tr td.label {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
white-space: nowrap; }
|
white-space: nowrap; }
|
||||||
/* line 61, ../sass/helpers/_bubbles.scss */
|
/* line 57, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper .l-infobubble table tr td.value {
|
.l-infobubble-wrapper .l-infobubble table tr td.value {
|
||||||
white-space: nowrap; }
|
word-break: break-all; }
|
||||||
/* line 65, ../sass/helpers/_bubbles.scss */
|
/* line 61, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper .l-infobubble table tr td.align-wrap {
|
.l-infobubble-wrapper .l-infobubble table tr td.align-wrap {
|
||||||
white-space: normal; }
|
white-space: normal; }
|
||||||
/* line 71, ../sass/helpers/_bubbles.scss */
|
/* line 67, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper .l-infobubble .title {
|
.l-infobubble-wrapper .l-infobubble .title {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin-bottom: 5px; }
|
margin-bottom: 5px; }
|
||||||
/* line 78, ../sass/helpers/_bubbles.scss */
|
/* line 74, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-left {
|
.l-infobubble-wrapper.arw-left {
|
||||||
margin-left: 20px; }
|
margin-left: 20px; }
|
||||||
/* line 80, ../sass/helpers/_bubbles.scss */
|
/* line 76, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-left .l-infobubble::before {
|
.l-infobubble-wrapper.arw-left .l-infobubble::before {
|
||||||
right: 100%;
|
right: 100%;
|
||||||
width: 0;
|
width: 0;
|
||||||
@ -4456,10 +4484,10 @@ input[type="text"] {
|
|||||||
border-top: 6.66667px solid transparent;
|
border-top: 6.66667px solid transparent;
|
||||||
border-bottom: 6.66667px solid transparent;
|
border-bottom: 6.66667px solid transparent;
|
||||||
border-right: 10px solid #ddd; }
|
border-right: 10px solid #ddd; }
|
||||||
/* line 86, ../sass/helpers/_bubbles.scss */
|
/* line 82, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-right {
|
.l-infobubble-wrapper.arw-right {
|
||||||
margin-right: 20px; }
|
margin-right: 20px; }
|
||||||
/* line 88, ../sass/helpers/_bubbles.scss */
|
/* line 84, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-right .l-infobubble::before {
|
.l-infobubble-wrapper.arw-right .l-infobubble::before {
|
||||||
left: 100%;
|
left: 100%;
|
||||||
width: 0;
|
width: 0;
|
||||||
@ -4467,16 +4495,16 @@ input[type="text"] {
|
|||||||
border-top: 6.66667px solid transparent;
|
border-top: 6.66667px solid transparent;
|
||||||
border-bottom: 6.66667px solid transparent;
|
border-bottom: 6.66667px solid transparent;
|
||||||
border-left: 10px solid #ddd; }
|
border-left: 10px solid #ddd; }
|
||||||
/* line 95, ../sass/helpers/_bubbles.scss */
|
/* line 91, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-top .l-infobubble::before {
|
.l-infobubble-wrapper.arw-top .l-infobubble::before {
|
||||||
top: 20px; }
|
top: 20px; }
|
||||||
/* line 101, ../sass/helpers/_bubbles.scss */
|
/* line 97, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-btm .l-infobubble::before {
|
.l-infobubble-wrapper.arw-btm .l-infobubble::before {
|
||||||
bottom: 20px; }
|
bottom: 20px; }
|
||||||
/* line 106, ../sass/helpers/_bubbles.scss */
|
/* line 102, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-down {
|
.l-infobubble-wrapper.arw-down {
|
||||||
margin-bottom: 10px; }
|
margin-bottom: 10px; }
|
||||||
/* line 108, ../sass/helpers/_bubbles.scss */
|
/* line 104, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-down .l-infobubble::before {
|
.l-infobubble-wrapper.arw-down .l-infobubble::before {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
@ -4484,21 +4512,21 @@ input[type="text"] {
|
|||||||
border-left: 5px solid transparent;
|
border-left: 5px solid transparent;
|
||||||
border-right: 5px solid transparent;
|
border-right: 5px solid transparent;
|
||||||
border-top: 7.5px solid #ddd; }
|
border-top: 7.5px solid #ddd; }
|
||||||
/* line 117, ../sass/helpers/_bubbles.scss */
|
/* line 113, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper .arw {
|
.l-infobubble-wrapper .arw {
|
||||||
z-index: 2; }
|
z-index: 2; }
|
||||||
/* line 120, ../sass/helpers/_bubbles.scss */
|
/* line 116, ../sass/helpers/_bubbles.scss */
|
||||||
.l-infobubble-wrapper.arw-up .arw.arw-down, .l-infobubble-wrapper.arw-down .arw.arw-up {
|
.l-infobubble-wrapper.arw-up .arw.arw-down, .l-infobubble-wrapper.arw-down .arw.arw-up {
|
||||||
display: none; }
|
display: none; }
|
||||||
|
|
||||||
/* line 127, ../sass/helpers/_bubbles.scss */
|
/* line 125, ../sass/helpers/_bubbles.scss */
|
||||||
.l-thumbsbubble-wrapper .arw-up {
|
.l-thumbsbubble-wrapper .arw-up {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-left: 6.66667px solid transparent;
|
border-left: 6.66667px solid transparent;
|
||||||
border-right: 6.66667px solid transparent;
|
border-right: 6.66667px solid transparent;
|
||||||
border-bottom: 10px solid #4d4d4d; }
|
border-bottom: 10px solid #4d4d4d; }
|
||||||
/* line 130, ../sass/helpers/_bubbles.scss */
|
/* line 128, ../sass/helpers/_bubbles.scss */
|
||||||
.l-thumbsbubble-wrapper .arw-down {
|
.l-thumbsbubble-wrapper .arw-down {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
@ -4506,7 +4534,7 @@ input[type="text"] {
|
|||||||
border-right: 6.66667px solid transparent;
|
border-right: 6.66667px solid transparent;
|
||||||
border-top: 10px solid #4d4d4d; }
|
border-top: 10px solid #4d4d4d; }
|
||||||
|
|
||||||
/* line 134, ../sass/helpers/_bubbles.scss */
|
/* line 133, ../sass/helpers/_bubbles.scss */
|
||||||
.s-infobubble {
|
.s-infobubble {
|
||||||
-moz-border-radius: 2px;
|
-moz-border-radius: 2px;
|
||||||
-webkit-border-radius: 2px;
|
-webkit-border-radius: 2px;
|
||||||
@ -4517,22 +4545,29 @@ input[type="text"] {
|
|||||||
background: #ddd;
|
background: #ddd;
|
||||||
color: #666;
|
color: #666;
|
||||||
font-size: 0.8rem; }
|
font-size: 0.8rem; }
|
||||||
/* line 141, ../sass/helpers/_bubbles.scss */
|
/* line 140, ../sass/helpers/_bubbles.scss */
|
||||||
.s-infobubble .title {
|
.s-infobubble .title {
|
||||||
color: #333333;
|
color: #333333;
|
||||||
font-weight: bold; }
|
font-weight: bold; }
|
||||||
/* line 146, ../sass/helpers/_bubbles.scss */
|
/* line 146, ../sass/helpers/_bubbles.scss */
|
||||||
.s-infobubble tr td {
|
.s-infobubble table tr td {
|
||||||
border-top: 1px solid #c4c4c4;
|
border: none;
|
||||||
|
border-top: 1px solid #c4c4c4 !important;
|
||||||
font-size: 0.9em; }
|
font-size: 0.9em; }
|
||||||
/* line 150, ../sass/helpers/_bubbles.scss */
|
/* line 152, ../sass/helpers/_bubbles.scss */
|
||||||
.s-infobubble tr:first-child td {
|
.s-infobubble table tr:first-child td {
|
||||||
|
border-top: none !important; }
|
||||||
|
/* line 157, ../sass/helpers/_bubbles.scss */
|
||||||
|
.s-infobubble:first-child td {
|
||||||
border-top: none; }
|
border-top: none; }
|
||||||
/* line 154, ../sass/helpers/_bubbles.scss */
|
/* line 161, ../sass/helpers/_bubbles.scss */
|
||||||
|
.s-infobubble .label {
|
||||||
|
color: gray; }
|
||||||
|
/* line 165, ../sass/helpers/_bubbles.scss */
|
||||||
.s-infobubble .value {
|
.s-infobubble .value {
|
||||||
color: #333333; }
|
color: #333333; }
|
||||||
|
|
||||||
/* line 159, ../sass/helpers/_bubbles.scss */
|
/* line 171, ../sass/helpers/_bubbles.scss */
|
||||||
.s-thumbsbubble {
|
.s-thumbsbubble {
|
||||||
background: #4d4d4d;
|
background: #4d4d4d;
|
||||||
color: #b3b3b3; }
|
color: #b3b3b3; }
|
||||||
|
@ -250,3 +250,248 @@ ul.tree {
|
|||||||
/* line 154, ../sass/tree/_tree.scss */
|
/* line 154, ../sass/tree/_tree.scss */
|
||||||
ul.tree ul.tree {
|
ul.tree ul.tree {
|
||||||
margin-left: 15px; }
|
margin-left: 15px; }
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
/* line 23, ../sass/search/_search.scss */
|
||||||
|
.abs.search-holder {
|
||||||
|
height: 25px;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 5; }
|
||||||
|
/* line 27, ../sass/search/_search.scss */
|
||||||
|
.abs.search-holder.active {
|
||||||
|
height: auto;
|
||||||
|
bottom: 0; }
|
||||||
|
|
||||||
|
/* line 38, ../sass/search/_search.scss */
|
||||||
|
.search {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%; }
|
||||||
|
/* line 49, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar {
|
||||||
|
font-size: 0.8em;
|
||||||
|
position: relative;
|
||||||
|
width: 100%; }
|
||||||
|
/* line 66, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .search-input {
|
||||||
|
height: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0; }
|
||||||
|
/* line 73, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .search-icon,
|
||||||
|
.search .search-bar .clear-icon,
|
||||||
|
.search .search-bar .menu-icon {
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #737373;
|
||||||
|
height: 17px;
|
||||||
|
width: 17px;
|
||||||
|
line-height: 17px;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
top: 4px; }
|
||||||
|
/* line 86, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .clear-icon,
|
||||||
|
.search .search-bar .menu-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color .25s; }
|
||||||
|
/* line 93, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .search-input {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 22px !important;
|
||||||
|
padding-right: 44px !important; }
|
||||||
|
/* line 100, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .search-input input {
|
||||||
|
width: 100%; }
|
||||||
|
/* line 105, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .search-icon {
|
||||||
|
color: #737373;
|
||||||
|
left: 3px;
|
||||||
|
transition: visibility .15s, opacity .15s, color .2s;
|
||||||
|
pointer-events: none; }
|
||||||
|
/* line 125, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .search-input:hover + div.search-icon {
|
||||||
|
color: #a6a6a6; }
|
||||||
|
/* line 129, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .clear-icon {
|
||||||
|
right: 22px;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transition: visibility .15s, opacity .15s, color .2s; }
|
||||||
|
/* line 138, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .clear-icon.content {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1; }
|
||||||
|
/* line 143, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .clear-icon:hover {
|
||||||
|
color: #a6a6a6; }
|
||||||
|
/* line 148, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .menu-icon {
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-right: 4px;
|
||||||
|
right: 4px;
|
||||||
|
text-align: right; }
|
||||||
|
/* line 154, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .menu-icon:hover {
|
||||||
|
color: #a6a6a6; }
|
||||||
|
/* line 159, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .search-menu-holder {
|
||||||
|
float: right;
|
||||||
|
left: -20px;
|
||||||
|
z-index: 1;
|
||||||
|
transition: visibility .05s, opacity .05s; }
|
||||||
|
/* line 169, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .search-menu-holder.off {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0; }
|
||||||
|
/* line 176, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar .menu-icon:hover + div.search-menu-holder {
|
||||||
|
visibility: visible; }
|
||||||
|
/* line 179, ../sass/search/_search.scss */
|
||||||
|
.search .search-bar div.search-menu-holder:hover {
|
||||||
|
visibility: visible; }
|
||||||
|
/* line 184, ../sass/search/_search.scss */
|
||||||
|
.search .active-filter-display {
|
||||||
|
-moz-border-radius: 2px;
|
||||||
|
-webkit-border-radius: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
line-height: 130%;
|
||||||
|
padding: 5px 0;
|
||||||
|
padding-left: 1.4625em;
|
||||||
|
font-size: 0.65em;
|
||||||
|
margin-top: 3px; }
|
||||||
|
/* line 199, ../sass/search/_search.scss */
|
||||||
|
.search .active-filter-display .clear-filters-icon {
|
||||||
|
opacity: 0.4;
|
||||||
|
font-size: 0.8em;
|
||||||
|
position: absolute;
|
||||||
|
left: 1px;
|
||||||
|
cursor: pointer; }
|
||||||
|
/* line 210, ../sass/search/_search.scss */
|
||||||
|
.search .active-filter-display.off {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0; }
|
||||||
|
/* line 220, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll {
|
||||||
|
order: 3;
|
||||||
|
margin-top: 4px;
|
||||||
|
overflow-y: auto;
|
||||||
|
top: auto;
|
||||||
|
height: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
position: relative; }
|
||||||
|
/* line 235, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item {
|
||||||
|
-moz-transition: background-color 0.25s;
|
||||||
|
-o-transition: background-color 0.25s;
|
||||||
|
-webkit-transition: background-color 0.25s;
|
||||||
|
transition: background-color 0.25s;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 2px; }
|
||||||
|
/* line 249, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item .label {
|
||||||
|
margin-left: 6px; }
|
||||||
|
/* line 253, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item .label .title-label {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
left: 29px;
|
||||||
|
right: 5px;
|
||||||
|
font-size: .8em;
|
||||||
|
line-height: 17px;
|
||||||
|
width: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap; }
|
||||||
|
/* line 275, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item.selected {
|
||||||
|
background: #005177;
|
||||||
|
color: #fff; }
|
||||||
|
/* line 279, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item.selected .view-control {
|
||||||
|
color: #0099cc; }
|
||||||
|
/* line 282, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item.selected .label .type-icon {
|
||||||
|
color: #fff; }
|
||||||
|
/* line 287, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item .label .type-icon .l-icon-link {
|
||||||
|
text-shadow: black 0 1px 2px;
|
||||||
|
z-index: 2;
|
||||||
|
color: #49dedb;
|
||||||
|
font-size: 8px;
|
||||||
|
line-height: 8px;
|
||||||
|
height: 8px;
|
||||||
|
width: 8px;
|
||||||
|
margin-left: -25px; }
|
||||||
|
/* line 296, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item:not(.selected):hover {
|
||||||
|
background: #404040;
|
||||||
|
color: #cccccc; }
|
||||||
|
/* line 299, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item:not(.selected):hover .context-trigger {
|
||||||
|
display: block; }
|
||||||
|
/* line 302, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .results .search-result-item:not(.selected):hover .icon {
|
||||||
|
color: #33ccff; }
|
||||||
|
/* line 310, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .load-icon {
|
||||||
|
position: relative; }
|
||||||
|
/* line 312, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .load-icon.loading {
|
||||||
|
pointer-events: none;
|
||||||
|
margin-left: 6px; }
|
||||||
|
/* line 316, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .load-icon.loading .title-label {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: .9em;
|
||||||
|
opacity: 0.5;
|
||||||
|
margin-left: 26px;
|
||||||
|
line-height: 24px; }
|
||||||
|
/* line 326, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .load-icon.loading .wait-spinner {
|
||||||
|
margin-left: 6px; }
|
||||||
|
/* line 331, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .load-icon:not(.loading) {
|
||||||
|
cursor: pointer; }
|
||||||
|
/* line 336, ../sass/search/_search.scss */
|
||||||
|
.search .search-scroll .load-more-button {
|
||||||
|
margin-top: 5px 0;
|
||||||
|
font-size: 0.8em;
|
||||||
|
position: relative;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -45px;
|
||||||
|
text-align: center;
|
||||||
|
width: 90px;
|
||||||
|
white-space: nowrap; }
|
||||||
|
@ -1,19 +1,27 @@
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "WTD Symbols v2.1",
|
"name": "WTD Symbols v2.2",
|
||||||
"lastOpened": 1439844340068,
|
"lastOpened": 1439948744240,
|
||||||
"created": 1439844318831
|
"created": 1439948734037
|
||||||
},
|
},
|
||||||
"iconSets": [
|
"iconSets": [
|
||||||
{
|
{
|
||||||
"selection": [
|
"selection": [
|
||||||
|
{
|
||||||
|
"order": 82,
|
||||||
|
"id": 84,
|
||||||
|
"prevSize": 32,
|
||||||
|
"code": 58887,
|
||||||
|
"name": "icon-x-in-circle",
|
||||||
|
"tempChar": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"order": 77,
|
"order": 77,
|
||||||
"id": 83,
|
"id": 83,
|
||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58881,
|
"code": 58881,
|
||||||
"name": "icon-datatable",
|
"name": "icon-datatable",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 78,
|
"order": 78,
|
||||||
@ -21,7 +29,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58882,
|
"code": 58882,
|
||||||
"name": "icon-tabular-scrolling",
|
"name": "icon-tabular-scrolling",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 79,
|
"order": 79,
|
||||||
@ -29,7 +37,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58884,
|
"code": 58884,
|
||||||
"name": "icon-tabular",
|
"name": "icon-tabular",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 80,
|
"order": 80,
|
||||||
@ -37,7 +45,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58885,
|
"code": 58885,
|
||||||
"name": "icon-calendar",
|
"name": "icon-calendar",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 81,
|
"order": 81,
|
||||||
@ -45,7 +53,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58886,
|
"code": 58886,
|
||||||
"name": "icon-paint-bucket",
|
"name": "icon-paint-bucket",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 1,
|
"order": 1,
|
||||||
@ -53,7 +61,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 123,
|
"code": 123,
|
||||||
"name": "icon-pointer-left",
|
"name": "icon-pointer-left",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 3,
|
"order": 3,
|
||||||
@ -61,7 +69,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 125,
|
"code": 125,
|
||||||
"name": "icon-pointer-right",
|
"name": "icon-pointer-right",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 4,
|
"order": 4,
|
||||||
@ -69,7 +77,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 80,
|
"code": 80,
|
||||||
"name": "icon-person",
|
"name": "icon-person",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 5,
|
"order": 5,
|
||||||
@ -77,7 +85,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 232,
|
"code": 232,
|
||||||
"name": "icon-chain-links",
|
"name": "icon-chain-links",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 6,
|
"order": 6,
|
||||||
@ -85,7 +93,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 115,
|
"code": 115,
|
||||||
"name": "icon-database-in-brackets",
|
"name": "icon-database-in-brackets",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 7,
|
"order": 7,
|
||||||
@ -93,7 +101,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 114,
|
"code": 114,
|
||||||
"name": "icon-refresh",
|
"name": "icon-refresh",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 8,
|
"order": 8,
|
||||||
@ -101,7 +109,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 108,
|
"code": 108,
|
||||||
"name": "icon-lock",
|
"name": "icon-lock",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 9,
|
"order": 9,
|
||||||
@ -109,7 +117,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 51,
|
"code": 51,
|
||||||
"name": "icon-box-with-dashed-lines",
|
"name": "icon-box-with-dashed-lines",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 10,
|
"order": 10,
|
||||||
@ -117,7 +125,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58880,
|
"code": 58880,
|
||||||
"name": "icon-box-with-arrow-cursor",
|
"name": "icon-box-with-arrow-cursor",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 11,
|
"order": 11,
|
||||||
@ -125,7 +133,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 65,
|
"code": 65,
|
||||||
"name": "icon-activity-mode",
|
"name": "icon-activity-mode",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 12,
|
"order": 12,
|
||||||
@ -133,7 +141,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 97,
|
"code": 97,
|
||||||
"name": "icon-activity",
|
"name": "icon-activity",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 13,
|
"order": 13,
|
||||||
@ -141,7 +149,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 33,
|
"code": 33,
|
||||||
"name": "icon-alert-rect",
|
"name": "icon-alert-rect",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 14,
|
"order": 14,
|
||||||
@ -149,7 +157,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58883,
|
"code": 58883,
|
||||||
"name": "icon-alert-triangle",
|
"name": "icon-alert-triangle",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 15,
|
"order": 15,
|
||||||
@ -157,7 +165,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 238,
|
"code": 238,
|
||||||
"name": "icon-arrow-double-down",
|
"name": "icon-arrow-double-down",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 16,
|
"order": 16,
|
||||||
@ -165,7 +173,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 235,
|
"code": 235,
|
||||||
"name": "icon-arrow-double-up",
|
"name": "icon-arrow-double-up",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 2,
|
"order": 2,
|
||||||
@ -173,7 +181,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 118,
|
"code": 118,
|
||||||
"name": "icon-arrow-down",
|
"name": "icon-arrow-down",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 19,
|
"order": 19,
|
||||||
@ -181,7 +189,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 60,
|
"code": 60,
|
||||||
"name": "icon-arrow-left",
|
"name": "icon-arrow-left",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 20,
|
"order": 20,
|
||||||
@ -189,7 +197,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 62,
|
"code": 62,
|
||||||
"name": "icon-arrow-right",
|
"name": "icon-arrow-right",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 21,
|
"order": 21,
|
||||||
@ -197,7 +205,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 236,
|
"code": 236,
|
||||||
"name": "icon-arrow-tall-down",
|
"name": "icon-arrow-tall-down",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 22,
|
"order": 22,
|
||||||
@ -205,7 +213,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 237,
|
"code": 237,
|
||||||
"name": "icon-arrow-tall-up",
|
"name": "icon-arrow-tall-up",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 23,
|
"order": 23,
|
||||||
@ -213,7 +221,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 94,
|
"code": 94,
|
||||||
"name": "icon-arrow-up",
|
"name": "icon-arrow-up",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 24,
|
"order": 24,
|
||||||
@ -221,7 +229,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 73,
|
"code": 73,
|
||||||
"name": "icon-arrows-out",
|
"name": "icon-arrows-out",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 25,
|
"order": 25,
|
||||||
@ -229,7 +237,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58893,
|
"code": 58893,
|
||||||
"name": "icon-arrows-right-left",
|
"name": "icon-arrows-right-left",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 33,
|
"order": 33,
|
||||||
@ -237,7 +245,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 53,
|
"code": 53,
|
||||||
"name": "icon-arrows-up-down",
|
"name": "icon-arrows-up-down",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 26,
|
"order": 26,
|
||||||
@ -245,7 +253,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 42,
|
"code": 42,
|
||||||
"name": "icon-asterisk",
|
"name": "icon-asterisk",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 27,
|
"order": 27,
|
||||||
@ -253,7 +261,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 72,
|
"code": 72,
|
||||||
"name": "icon-autoflow-tabular",
|
"name": "icon-autoflow-tabular",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 28,
|
"order": 28,
|
||||||
@ -261,7 +269,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 224,
|
"code": 224,
|
||||||
"name": "icon-box-round-corners",
|
"name": "icon-box-round-corners",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 29,
|
"order": 29,
|
||||||
@ -269,7 +277,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 50,
|
"code": 50,
|
||||||
"name": "icon-check",
|
"name": "icon-check",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 30,
|
"order": 30,
|
||||||
@ -277,7 +285,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 67,
|
"code": 67,
|
||||||
"name": "icon-clock",
|
"name": "icon-clock",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 31,
|
"order": 31,
|
||||||
@ -285,7 +293,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 46,
|
"code": 46,
|
||||||
"name": "icon-connectivity",
|
"name": "icon-connectivity",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 32,
|
"order": 32,
|
||||||
@ -293,7 +301,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 100,
|
"code": 100,
|
||||||
"name": "icon-database-query",
|
"name": "icon-database-query",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 17,
|
"order": 17,
|
||||||
@ -301,7 +309,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 68,
|
"code": 68,
|
||||||
"name": "icon-database",
|
"name": "icon-database",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 35,
|
"order": 35,
|
||||||
@ -309,7 +317,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 81,
|
"code": 81,
|
||||||
"name": "icon-dictionary",
|
"name": "icon-dictionary",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 36,
|
"order": 36,
|
||||||
@ -317,7 +325,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 242,
|
"code": 242,
|
||||||
"name": "icon-duplicate",
|
"name": "icon-duplicate",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 37,
|
"order": 37,
|
||||||
@ -325,7 +333,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 102,
|
"code": 102,
|
||||||
"name": "icon-folder-new",
|
"name": "icon-folder-new",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 38,
|
"order": 38,
|
||||||
@ -333,7 +341,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 70,
|
"code": 70,
|
||||||
"name": "icon-folder",
|
"name": "icon-folder",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 39,
|
"order": 39,
|
||||||
@ -341,7 +349,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 95,
|
"code": 95,
|
||||||
"name": "icon-fullscreen-collapse",
|
"name": "icon-fullscreen-collapse",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 40,
|
"order": 40,
|
||||||
@ -349,7 +357,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 122,
|
"code": 122,
|
||||||
"name": "icon-fullscreen-expand",
|
"name": "icon-fullscreen-expand",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 41,
|
"order": 41,
|
||||||
@ -357,7 +365,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 71,
|
"code": 71,
|
||||||
"name": "icon-gear",
|
"name": "icon-gear",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 49,
|
"order": 49,
|
||||||
@ -365,7 +373,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 227,
|
"code": 227,
|
||||||
"name": "icon-image",
|
"name": "icon-image",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 42,
|
"order": 42,
|
||||||
@ -373,7 +381,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 225,
|
"code": 225,
|
||||||
"name": "icon-layers",
|
"name": "icon-layers",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 43,
|
"order": 43,
|
||||||
@ -381,7 +389,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 76,
|
"code": 76,
|
||||||
"name": "icon-layout",
|
"name": "icon-layout",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 44,
|
"order": 44,
|
||||||
@ -389,7 +397,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 226,
|
"code": 226,
|
||||||
"name": "icon-line-horz",
|
"name": "icon-line-horz",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 75,
|
"order": 75,
|
||||||
@ -397,7 +405,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 244,
|
"code": 244,
|
||||||
"name": "icon-link",
|
"name": "icon-link",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 46,
|
"order": 46,
|
||||||
@ -405,7 +413,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 88,
|
"code": 88,
|
||||||
"name": "icon-magnify-in",
|
"name": "icon-magnify-in",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 47,
|
"order": 47,
|
||||||
@ -413,7 +421,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 89,
|
"code": 89,
|
||||||
"name": "icon-magnify-out",
|
"name": "icon-magnify-out",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 48,
|
"order": 48,
|
||||||
@ -421,7 +429,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 77,
|
"code": 77,
|
||||||
"name": "icon-magnify",
|
"name": "icon-magnify",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 34,
|
"order": 34,
|
||||||
@ -429,7 +437,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 109,
|
"code": 109,
|
||||||
"name": "icon-menu",
|
"name": "icon-menu",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 50,
|
"order": 50,
|
||||||
@ -437,7 +445,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 243,
|
"code": 243,
|
||||||
"name": "icon-move",
|
"name": "icon-move",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 51,
|
"order": 51,
|
||||||
@ -445,7 +453,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 121,
|
"code": 121,
|
||||||
"name": "icon-new-window",
|
"name": "icon-new-window",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 52,
|
"order": 52,
|
||||||
@ -453,7 +461,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 111,
|
"code": 111,
|
||||||
"name": "icon-object",
|
"name": "icon-object",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 73,
|
"order": 73,
|
||||||
@ -461,7 +469,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 63,
|
"code": 63,
|
||||||
"name": "icon-object-unknown",
|
"name": "icon-object-unknown",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 53,
|
"order": 53,
|
||||||
@ -469,7 +477,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 86,
|
"code": 86,
|
||||||
"name": "icon-packet",
|
"name": "icon-packet",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 54,
|
"order": 54,
|
||||||
@ -477,7 +485,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 234,
|
"code": 234,
|
||||||
"name": "icon-page",
|
"name": "icon-page",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 55,
|
"order": 55,
|
||||||
@ -485,7 +493,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 241,
|
"code": 241,
|
||||||
"name": "icon-pause",
|
"name": "icon-pause",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 56,
|
"order": 56,
|
||||||
@ -493,7 +501,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 112,
|
"code": 112,
|
||||||
"name": "icon-pencil",
|
"name": "icon-pencil",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 65,
|
"order": 65,
|
||||||
@ -501,7 +509,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 79,
|
"code": 79,
|
||||||
"name": "icon-people",
|
"name": "icon-people",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 57,
|
"order": 57,
|
||||||
@ -509,7 +517,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 239,
|
"code": 239,
|
||||||
"name": "icon-play",
|
"name": "icon-play",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 58,
|
"order": 58,
|
||||||
@ -517,7 +525,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 233,
|
"code": 233,
|
||||||
"name": "icon-plot-resource",
|
"name": "icon-plot-resource",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 59,
|
"order": 59,
|
||||||
@ -525,7 +533,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 43,
|
"code": 43,
|
||||||
"name": "icon-plus",
|
"name": "icon-plus",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 60,
|
"order": 60,
|
||||||
@ -533,7 +541,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 45,
|
"code": 45,
|
||||||
"name": "icon-minus",
|
"name": "icon-minus",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 61,
|
"order": 61,
|
||||||
@ -541,7 +549,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 54,
|
"code": 54,
|
||||||
"name": "icon-sine",
|
"name": "icon-sine",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 62,
|
"order": 62,
|
||||||
@ -549,7 +557,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 228,
|
"code": 228,
|
||||||
"name": "icon-T",
|
"name": "icon-T",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 63,
|
"order": 63,
|
||||||
@ -557,7 +565,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 116,
|
"code": 116,
|
||||||
"name": "icon-telemetry-panel",
|
"name": "icon-telemetry-panel",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 64,
|
"order": 64,
|
||||||
@ -565,7 +573,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 84,
|
"code": 84,
|
||||||
"name": "icon-telemetry",
|
"name": "icon-telemetry",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 18,
|
"order": 18,
|
||||||
@ -573,7 +581,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 246,
|
"code": 246,
|
||||||
"name": "icon-thumbs-strip",
|
"name": "icon-thumbs-strip",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 67,
|
"order": 67,
|
||||||
@ -581,7 +589,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 83,
|
"code": 83,
|
||||||
"name": "icon-timeline",
|
"name": "icon-timeline",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 68,
|
"order": 68,
|
||||||
@ -589,7 +597,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 245,
|
"code": 245,
|
||||||
"name": "icon-timer",
|
"name": "icon-timer",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 69,
|
"order": 69,
|
||||||
@ -597,7 +605,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 90,
|
"code": 90,
|
||||||
"name": "icon-trash",
|
"name": "icon-trash",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 70,
|
"order": 70,
|
||||||
@ -605,7 +613,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 229,
|
"code": 229,
|
||||||
"name": "icon-two-parts-both",
|
"name": "icon-two-parts-both",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 71,
|
"order": 71,
|
||||||
@ -613,7 +621,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 231,
|
"code": 231,
|
||||||
"name": "icon-two-parts-one-only",
|
"name": "icon-two-parts-one-only",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 72,
|
"order": 72,
|
||||||
@ -621,7 +629,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 120,
|
"code": 120,
|
||||||
"name": "icon-x-heavy",
|
"name": "icon-x-heavy",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 66,
|
"order": 66,
|
||||||
@ -629,7 +637,7 @@
|
|||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"code": 58946,
|
"code": 58946,
|
||||||
"name": "icon-x",
|
"name": "icon-x",
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"id": 2,
|
"id": 2,
|
||||||
@ -644,6 +652,21 @@
|
|||||||
"height": 1024,
|
"height": 1024,
|
||||||
"prevSize": 32,
|
"prevSize": 32,
|
||||||
"icons": [
|
"icons": [
|
||||||
|
{
|
||||||
|
"id": 84,
|
||||||
|
"paths": [
|
||||||
|
"M512 0c-282.8 0-512 229.2-512 512s229.2 512 512 512 512-229.2 512-512-229.2-512-512-512zM832 704l-128 128-192-192-192 192-128-128 192-192-192-192 128-128 192 192 192-192 128 128-192 192 192 192z"
|
||||||
|
],
|
||||||
|
"attrs": [],
|
||||||
|
"isMulticolor": false,
|
||||||
|
"grid": 0,
|
||||||
|
"tags": [
|
||||||
|
"icon-x-in-circle"
|
||||||
|
],
|
||||||
|
"colorPermutations": {
|
||||||
|
"16161751": []
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 83,
|
"id": 83,
|
||||||
"paths": [
|
"paths": [
|
||||||
@ -666,6 +689,10 @@
|
|||||||
"icon-datatable"
|
"icon-datatable"
|
||||||
],
|
],
|
||||||
"colorPermutations": {
|
"colorPermutations": {
|
||||||
|
"16161751": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
"125525525516161751": [
|
"125525525516161751": [
|
||||||
1,
|
1,
|
||||||
1
|
1
|
||||||
@ -709,6 +736,13 @@
|
|||||||
"icon-tabular-scrolling"
|
"icon-tabular-scrolling"
|
||||||
],
|
],
|
||||||
"colorPermutations": {
|
"colorPermutations": {
|
||||||
|
"16161751": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
"125525525516161751": [
|
"125525525516161751": [
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
@ -760,6 +794,14 @@
|
|||||||
"icon-tabular"
|
"icon-tabular"
|
||||||
],
|
],
|
||||||
"colorPermutations": {
|
"colorPermutations": {
|
||||||
|
"16161751": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
"125525525516161751": [
|
"125525525516161751": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -787,6 +829,9 @@
|
|||||||
"icon-calendar"
|
"icon-calendar"
|
||||||
],
|
],
|
||||||
"colorPermutations": {
|
"colorPermutations": {
|
||||||
|
"16161751": [
|
||||||
|
1
|
||||||
|
],
|
||||||
"125525525516161751": [
|
"125525525516161751": [
|
||||||
1
|
1
|
||||||
]
|
]
|
||||||
@ -814,6 +859,10 @@
|
|||||||
"icon-paint-bucket"
|
"icon-paint-bucket"
|
||||||
],
|
],
|
||||||
"colorPermutations": {
|
"colorPermutations": {
|
||||||
|
"16161751": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
"125525525516161751": [
|
"125525525516161751": [
|
||||||
1,
|
1,
|
||||||
1
|
1
|
||||||
|
Binary file not shown.
@ -83,6 +83,7 @@
|
|||||||
<glyph unicode="" glyph-name="icon-tabular" d="M0 896v-192h448v256h-384c-35.2 0-64-28.8-64-64zM960 960h-384v-256h448v192c0 35.2-28.8 64-64 64zM576 576h448v-256h-448v256zM0 576h448v-256h-448v256zM0 0c0-35.2 28.8-64 64-64h384v256h-448v-192zM576-64h384c35.2 0 64 28.8 64 64v192h-448v-256z" />
|
<glyph unicode="" glyph-name="icon-tabular" d="M0 896v-192h448v256h-384c-35.2 0-64-28.8-64-64zM960 960h-384v-256h448v192c0 35.2-28.8 64-64 64zM576 576h448v-256h-448v256zM0 576h448v-256h-448v256zM0 0c0-35.2 28.8-64 64-64h384v256h-448v-192zM576-64h384c35.2 0 64 28.8 64 64v192h-448v-256z" />
|
||||||
<glyph unicode="" glyph-name="icon-calendar" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM640 512h-256v192h256v-192zM384 448h256v-192h-256v192zM320 256h-256v192h256v-192zM320 704v-192h-256v192h256zM128 0c-17 0-33 6.6-45.2 18.8s-18.8 28.2-18.8 45.2v128h256v-192h-192zM384 0v192h256v-192h-256zM960 64c0-17-6.6-33-18.8-45.2s-28.2-18.8-45.2-18.8h-192v192h256v-128zM960 256h-256v192h256v-192zM960 512h-256v192h256v-192z" />
|
<glyph unicode="" glyph-name="icon-calendar" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM640 512h-256v192h256v-192zM384 448h256v-192h-256v192zM320 256h-256v192h256v-192zM320 704v-192h-256v192h256zM128 0c-17 0-33 6.6-45.2 18.8s-18.8 28.2-18.8 45.2v128h256v-192h-192zM384 0v192h256v-192h-256zM960 64c0-17-6.6-33-18.8-45.2s-28.2-18.8-45.2-18.8h-192v192h256v-128zM960 256h-256v192h256v-192zM960 512h-256v192h256v-192z" />
|
||||||
<glyph unicode="" glyph-name="icon-paint-bucket" d="M896 320c0 0-130-188-128-256 2-70.6 57.4-128 128-128s126 57.4 128 128c2 68-128 256-128 256zM449 831l0.2 64.8c0 35.4-28.4 64-63.8 64.2 0 0-0.2 0-0.2 0-35.2 0-63.8-28.6-64-63.8l-0.6-190.8-294-292.6c-50-50-12.4-215.2 112.4-340s290-162.4 340-112.4l417 423.6-447 447zM384 320c-70.6 0-128 57.4-128 128 0 47.4 25.8 89 64.4 111l-0.4-110.8c0-35.4 28.4-64 63.8-64.2 0 0 0.2 0 0.2 0 35.2 0 63.8 28.6 64 63.8l0.4 110.8c38-22.2 63.6-63.4 63.6-110.6 0-70.6-57.4-128-128-128z" />
|
<glyph unicode="" glyph-name="icon-paint-bucket" d="M896 320c0 0-130-188-128-256 2-70.6 57.4-128 128-128s126 57.4 128 128c2 68-128 256-128 256zM449 831l0.2 64.8c0 35.4-28.4 64-63.8 64.2 0 0-0.2 0-0.2 0-35.2 0-63.8-28.6-64-63.8l-0.6-190.8-294-292.6c-50-50-12.4-215.2 112.4-340s290-162.4 340-112.4l417 423.6-447 447zM384 320c-70.6 0-128 57.4-128 128 0 47.4 25.8 89 64.4 111l-0.4-110.8c0-35.4 28.4-64 63.8-64.2 0 0 0.2 0 0.2 0 35.2 0 63.8 28.6 64 63.8l0.4 110.8c38-22.2 63.6-63.4 63.6-110.6 0-70.6-57.4-128-128-128z" />
|
||||||
|
<glyph unicode="" glyph-name="icon-x-in-circle" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM832 256l-128-128-192 192-192-192-128 128 192 192-192 192 128 128 192-192 192 192 128-128-192-192 192-192z" />
|
||||||
<glyph unicode="" glyph-name="icon-arrows-right-left" d="M1024 448l-448-512v1024zM448 960l-448-512 448-512z" />
|
<glyph unicode="" glyph-name="icon-arrows-right-left" d="M1024 448l-448-512v1024zM448 960l-448-512 448-512z" />
|
||||||
<glyph unicode="" glyph-name="icon-x" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
|
<glyph unicode="" glyph-name="icon-x" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
|
||||||
</font></defs></svg>
|
</font></defs></svg>
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Binary file not shown.
Binary file not shown.
@ -100,6 +100,7 @@ $ueAppLogoW: 105px;
|
|||||||
$ueEditToolBarH: 25px;
|
$ueEditToolBarH: 25px;
|
||||||
$ueBrowseLeftPaneW: 25%;
|
$ueBrowseLeftPaneW: 25%;
|
||||||
$ueEditLeftPaneW: 75%;
|
$ueEditLeftPaneW: 75%;
|
||||||
|
$treeSearchInputBarH: 25px;
|
||||||
// Overlay
|
// Overlay
|
||||||
$ovrTopBarH: 60px;
|
$ovrTopBarH: 60px;
|
||||||
$ovrFooterH: 40px;
|
$ovrFooterH: 40px;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/*****************************************************************************
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
@ -31,6 +32,7 @@
|
|||||||
@import "global";
|
@import "global";
|
||||||
@import "fonts";
|
@import "fonts";
|
||||||
@import "user-environ/layout";
|
@import "user-environ/layout";
|
||||||
|
//@import "search/layout";
|
||||||
@import "fixed-position";
|
@import "fixed-position";
|
||||||
@import "about";
|
@import "about";
|
||||||
@import "text";
|
@import "text";
|
||||||
|
@ -21,15 +21,15 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/******************************************************** MENUS */
|
/******************************************************** MENUS */
|
||||||
.menu-element {
|
.menu-element {
|
||||||
$bg: lighten($colorBodyBg, 5%);
|
$bg: lighten($colorBodyBg, 5%);
|
||||||
$bgHover: lighten($bg, 20%);
|
$bgHover: lighten($bg, 20%);
|
||||||
$iconColor: $colorKey;
|
$iconColor: $colorKey;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
.menu {
|
.menu {
|
||||||
@include border-radius($basicCr);
|
@include border-radius($basicCr);
|
||||||
@include containerSubtle($bg);
|
@include containerSubtle($bg);
|
||||||
@include txtShdwSubtle(0.2);
|
@include txtShdwSubtle(0.2);
|
||||||
display: block; // set to block via jQuery
|
display: block; // set to block via jQuery
|
||||||
padding: $interiorMarginSm 0;
|
padding: $interiorMarginSm 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -37,11 +37,12 @@
|
|||||||
ul {
|
ul {
|
||||||
@include menuUlReset();
|
@include menuUlReset();
|
||||||
li {
|
li {
|
||||||
@include box-sizing(border-box);
|
@include box-sizing(border-box);
|
||||||
border-top: 1px solid lighten($bg, 20%);
|
border-top: 1px solid lighten($bg, 20%);
|
||||||
color: lighten($bg, 60%);
|
color: lighten($bg, 60%);
|
||||||
line-height: $menuLineH;
|
line-height: $menuLineH;
|
||||||
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
|
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
|
||||||
|
position: relative;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
&:first-child {
|
&:first-child {
|
||||||
border: none;
|
border: none;
|
||||||
@ -61,7 +62,7 @@
|
|||||||
// display: block;
|
// display: block;
|
||||||
//}
|
//}
|
||||||
.type-icon {
|
.type-icon {
|
||||||
left: $interiorMargin * 2;
|
left: $interiorMargin * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +78,9 @@
|
|||||||
@include containerSubtle($bg);
|
@include containerSubtle($bg);
|
||||||
ul li {
|
ul li {
|
||||||
padding-left: 25px;
|
padding-left: 25px;
|
||||||
a { color: $fg; }
|
a {
|
||||||
|
color: $fg;
|
||||||
|
}
|
||||||
.icon {
|
.icon {
|
||||||
color: $ic;
|
color: $ic;
|
||||||
}
|
}
|
||||||
@ -90,99 +93,131 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox-menu {
|
||||||
|
// Used in search dropdown in tree
|
||||||
|
@extend .context-menu;
|
||||||
|
ul li {
|
||||||
|
padding-left: 50px;
|
||||||
|
.checkbox {
|
||||||
|
$d: 0.7rem;
|
||||||
|
position: absolute;
|
||||||
|
left: $interiorMargin;
|
||||||
|
top: ($menuLineH - $d) / 1.5;
|
||||||
|
em {
|
||||||
|
height: $d;
|
||||||
|
width: $d;
|
||||||
|
&:before {
|
||||||
|
font-size: 7px !important;// $d/2;
|
||||||
|
height: $d;
|
||||||
|
width: $d;
|
||||||
|
line-height: $d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.type-icon {
|
||||||
|
left: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.super-menu {
|
.super-menu {
|
||||||
$w: 500px;
|
$w: 500px;
|
||||||
$h: $w - 20;
|
$h: $w - 20;
|
||||||
$plw: 50%; //$w * 0.5;
|
$plw: 50%; //$w * 0.5;
|
||||||
$prw: 50%; //$w - $plw;
|
$prw: 50%; //$w - $plw;
|
||||||
$fg: #fff; //lighten($colorBodyFg, 40%);
|
$fg: #fff; //lighten($colorBodyFg, 40%);
|
||||||
$bgHover: $colorKey; //$bg;
|
$bgHover: $colorKey; //$bg;
|
||||||
display: block;
|
display: block;
|
||||||
width: $w;
|
width: $w;
|
||||||
height: $h;
|
height: $h;
|
||||||
.contents {
|
.contents {
|
||||||
@include absPosDefault($interiorMargin);
|
@include absPosDefault($interiorMargin);
|
||||||
}
|
}
|
||||||
.pane {
|
.pane {
|
||||||
@include box-sizing(border-box);
|
@include box-sizing(border-box);
|
||||||
&.left {
|
&.left {
|
||||||
//@include test();
|
//@include test();
|
||||||
border-right: 1px solid rgba(white, 0.2);
|
border-right: 1px solid rgba(white, 0.2);
|
||||||
left: 0;
|
left: 0;
|
||||||
padding-right: $interiorMargin;
|
padding-right: $interiorMargin;
|
||||||
right: auto;
|
right: auto;
|
||||||
width: $plw;
|
width: $plw;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
ul {
|
ul {
|
||||||
li {
|
li {
|
||||||
@include border-radius($controlCr);
|
@include border-radius($controlCr);
|
||||||
padding-left: 30px;
|
padding-left: 30px;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.right {
|
&.right {
|
||||||
//@include test(red);
|
//@include test(red);
|
||||||
left: auto;
|
left: auto;
|
||||||
right: 0;
|
right: 0;
|
||||||
padding: $interiorMargin * 5;
|
padding: $interiorMargin * 5;
|
||||||
width: $prw;
|
width: $prw;
|
||||||
.icon {
|
.icon {
|
||||||
color: $fg;
|
color: $fg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.menu-item-description {
|
.menu-item-description {
|
||||||
.desc-area {
|
.desc-area {
|
||||||
&.icon {
|
&.icon {
|
||||||
$h: 150px;
|
$h: 150px;
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 8em;
|
font-size: 8em;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: $h;
|
height: $h;
|
||||||
line-height: $h;
|
line-height: $h;
|
||||||
margin-bottom: $interiorMargin * 5;
|
margin-bottom: $interiorMargin * 5;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
&.title {
|
&.title {
|
||||||
color: $fg;
|
color: $fg;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
&.description {
|
&.description {
|
||||||
//color: lighten($bg, 30%);
|
//color: lighten($bg, 30%);
|
||||||
color: $fg;
|
color: $fg;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.context-menu {
|
.context-menu {
|
||||||
font-size: 0.80rem;
|
font-size: 0.80rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-menu-holder {
|
.context-menu-holder {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
width: 170px;
|
width: 170px;
|
||||||
z-index: 70;
|
z-index: 70;
|
||||||
.context-menu-wrapper {
|
.context-menu-wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.context-menu {
|
.context-menu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.go-left .context-menu { right: 0; }
|
&.go-left .context-menu {
|
||||||
&.go-up .context-menu { bottom: 0; }
|
right: 0;
|
||||||
|
}
|
||||||
|
&.go-up .context-menu {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-bar.right .menu,
|
.btn-bar.right .menu,
|
||||||
.menus-to-left .menu {
|
.menus-to-left .menu {
|
||||||
left: auto; right: 0; width: auto;
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
@ -48,19 +48,15 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
tr {
|
tr {
|
||||||
td {
|
td {
|
||||||
//max-width: 150px;
|
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
//white-space: nowrap;
|
|
||||||
//overflow: hidden;
|
|
||||||
//text-overflow: ellipsis;
|
|
||||||
&.label {
|
&.label {
|
||||||
padding-right: $interiorMargin * 2;
|
padding-right: $interiorMargin * 2;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
&.value {
|
&.value {
|
||||||
white-space: nowrap;
|
//word-wrap: break-word; // Doesn't work in <td>?
|
||||||
//width: 90%;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
&.align-wrap {
|
&.align-wrap {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
@ -118,7 +114,9 @@
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
&.arw-up .arw.arw-down,
|
&.arw-up .arw.arw-down,
|
||||||
&.arw-down .arw.arw-up { display: none; }
|
&.arw-down .arw.arw-up {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//************************************************* LOOK AND FEEL
|
//************************************************* LOOK AND FEEL
|
||||||
@ -131,6 +129,7 @@
|
|||||||
@include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
|
@include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.s-infobubble {
|
.s-infobubble {
|
||||||
$emFg: darken($colorInfoBubbleFg, 20%);
|
$emFg: darken($colorInfoBubbleFg, 20%);
|
||||||
@include border-radius($basicCr);
|
@include border-radius($basicCr);
|
||||||
@ -142,18 +141,31 @@
|
|||||||
color: $emFg;
|
color: $emFg;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
tr {
|
table {
|
||||||
td {
|
tr {
|
||||||
border-top: 1px solid darken($colorInfoBubbleBg, 10%);
|
td {
|
||||||
font-size: 0.9em;
|
border: none;
|
||||||
}
|
border-top: 1px solid darken($colorInfoBubbleBg, 10%) !important;
|
||||||
&:first-child td {
|
font-size: 0.9em;
|
||||||
border-top: none;
|
}
|
||||||
|
|
||||||
|
&:first-child td {
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&:first-child td {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: lighten($emFg, 30%);
|
||||||
|
}
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
color: $emFg;
|
color: $emFg;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.s-thumbsbubble {
|
.s-thumbsbubble {
|
||||||
|
@ -82,18 +82,21 @@ table {
|
|||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
&.sort {
|
&.sort {
|
||||||
.icon-sorting:before {
|
&.sort:after {
|
||||||
display: inline-block;
|
color: $colorIconLink;
|
||||||
font-family: symbolsfont;
|
font-family: symbolsfont;
|
||||||
margin-left: 5px;
|
font-size: 8px;
|
||||||
|
content: "\ed";
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: $interiorMarginSm;
|
||||||
}
|
}
|
||||||
&.asc .icon-sorting:before {
|
&.sort.desc:after {
|
||||||
content: '0';
|
content: "\ec";
|
||||||
}
|
|
||||||
&.desc .icon-sorting:before {
|
|
||||||
content: '1';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.sortable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td, .td {
|
td, .td {
|
||||||
border-bottom: 1px solid $tabularColorBorder;
|
border-bottom: 1px solid $tabularColorBorder;
|
||||||
|
31
platform/commonUI/general/res/sass/search/_layout.scss
Normal file
31
platform/commonUI/general/res/sass/search/_layout.scss
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
// Overrides some styling in user-environ/_layout.scss
|
||||||
|
.pane {
|
||||||
|
&.treeview.left {
|
||||||
|
.tree-holder {
|
||||||
|
// Want tree holder to start right below the search bar.
|
||||||
|
top: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
347
platform/commonUI/general/res/sass/search/_search.scss
Normal file
347
platform/commonUI/general/res/sass/search/_search.scss
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
.abs.search-holder {
|
||||||
|
//@include test(#990000);
|
||||||
|
height: $treeSearchInputBarH;
|
||||||
|
bottom: 0;
|
||||||
|
&.active {
|
||||||
|
height: auto;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
//top: 23px;
|
||||||
|
|
||||||
|
// Align with the top of the divider bar, below create button
|
||||||
|
//margin-top: 10px; // CH comment out
|
||||||
|
z-index:5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
$iconWidth: 20px;
|
||||||
|
$leftMargin: 6px;
|
||||||
|
$rightPadding: 5px;
|
||||||
|
|
||||||
|
//padding-right: $rightPadding;
|
||||||
|
//@include test();
|
||||||
|
display: flex; //block;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
//$heightAdjust: 4px;
|
||||||
|
$textInputHeight: 19px; // This is equal to the default value, 19px
|
||||||
|
$iconEdgeM: 4px;
|
||||||
|
$iconD: $treeSearchInputBarH - ($iconEdgeM*2);
|
||||||
|
font-size: 0.8em;
|
||||||
|
|
||||||
|
//order: 1;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
//height: $textInputHeight;
|
||||||
|
//margin-top: $heightAdjust;
|
||||||
|
.search-input,
|
||||||
|
.search-icon {
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
height: $treeSearchInputBarH;
|
||||||
|
line-height: $treeSearchInputBarH;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon,
|
||||||
|
.clear-icon,
|
||||||
|
.menu-icon {
|
||||||
|
//@include test(#008800);
|
||||||
|
@include box-sizing(border-box);
|
||||||
|
color: $colorItemFg;
|
||||||
|
height: $iconD; width: $iconD;
|
||||||
|
line-height: $iconD;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
top: $iconEdgeM;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-icon,
|
||||||
|
.menu-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color .25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: $iconD + $interiorMargin !important;
|
||||||
|
padding-right: ($iconD * 2) + ($interiorMargin * 2) !important;
|
||||||
|
|
||||||
|
// Make work for mct-control textfield
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
color: $colorItemFg;
|
||||||
|
left: $interiorMarginSm;
|
||||||
|
transition: visibility .15s, opacity .15s, color .2s;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&.content {
|
||||||
|
// Make icon invisible whenever there is text input
|
||||||
|
//visibility: hidden;
|
||||||
|
//opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make icon invisible when the text input is focused
|
||||||
|
.search-input:focus + div.search-icon {
|
||||||
|
//visibility: hidden;
|
||||||
|
//opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make icon lighten when hovering over search bar
|
||||||
|
.search-input:hover + div.search-icon {
|
||||||
|
color: lighten($colorItemFg, 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-icon {
|
||||||
|
right: $iconD + $interiorMargin;
|
||||||
|
|
||||||
|
// Icon is visible only when there is text input
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
transition: visibility .15s, opacity .15s, color .2s;
|
||||||
|
|
||||||
|
&.content {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: lighten($colorItemFg, 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-right: $iconEdgeM;
|
||||||
|
right: $iconEdgeM;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: lighten($colorItemFg, 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-menu-holder {
|
||||||
|
float: right;
|
||||||
|
//margin-top: $textInputHeight - 2px;
|
||||||
|
//left: -50px;
|
||||||
|
left: -20px;
|
||||||
|
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
transition: visibility .05s, opacity .05s;
|
||||||
|
|
||||||
|
&.off {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hovering reveals menu
|
||||||
|
.menu-icon:hover + div.search-menu-holder {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
div.search-menu-holder:hover {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-filter-display {
|
||||||
|
//order: 2;
|
||||||
|
$s: 0.65em;
|
||||||
|
$p: $interiorMargin;
|
||||||
|
@include border-radius($basicCr);
|
||||||
|
@include box-sizing(border-box);
|
||||||
|
line-height: 130%;
|
||||||
|
padding: $p 0;
|
||||||
|
padding-left: $s * 2.25;
|
||||||
|
font-size: $s;
|
||||||
|
//background-color: rgba(#000, 0.3);
|
||||||
|
//border-radius: $basicCr;
|
||||||
|
margin-top: $interiorMarginSm;
|
||||||
|
|
||||||
|
|
||||||
|
.clear-filters-icon {
|
||||||
|
opacity: 0.4;
|
||||||
|
font-size: 0.8em;
|
||||||
|
position: absolute;
|
||||||
|
left: 1px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transition looks weird when the results list has none
|
||||||
|
//transition: visibility .2s, opacity .2s;
|
||||||
|
|
||||||
|
&.off {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-scroll {
|
||||||
|
order: 3;
|
||||||
|
|
||||||
|
//padding-right: $rightPadding;
|
||||||
|
margin-top: 4px;
|
||||||
|
|
||||||
|
// Adjustable scrolling size
|
||||||
|
overflow-y: auto;
|
||||||
|
top: auto;
|
||||||
|
height: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.results {
|
||||||
|
|
||||||
|
.search-result-item {
|
||||||
|
// Include transitions (for the highlights)
|
||||||
|
@include single-transition(background-color, 0.25s);
|
||||||
|
|
||||||
|
// Space the results from each other
|
||||||
|
margin-bottom: 2px;
|
||||||
|
|
||||||
|
// Make the highlights the right color and shape.
|
||||||
|
// Attempting to match the style in the tree, but
|
||||||
|
// while having these be compact.
|
||||||
|
border-radius: 2px;
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
// Give some padding away from the left side
|
||||||
|
margin-left: $leftMargin;
|
||||||
|
|
||||||
|
.title-label {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
// Give some padding away from the left side
|
||||||
|
left: $leftMargin + 3px + $iconWidth;
|
||||||
|
// and the right side
|
||||||
|
right: $rightPadding;
|
||||||
|
|
||||||
|
// Size and position the text
|
||||||
|
font-size: .8em;
|
||||||
|
line-height: 17px;
|
||||||
|
|
||||||
|
// Hide overflow text
|
||||||
|
width: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change styling when it's selected
|
||||||
|
&.selected {
|
||||||
|
$c: #fff;
|
||||||
|
background: $colorKeySelectedBg;
|
||||||
|
color: $c;
|
||||||
|
.view-control {
|
||||||
|
color: $colorItemTreeIcon;
|
||||||
|
}
|
||||||
|
.label .type-icon {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label .type-icon .l-icon-link {
|
||||||
|
@include txtShdwSubtle(1);
|
||||||
|
z-index: 2;
|
||||||
|
@include ancillaryIcon(8px, $colorIconLink);
|
||||||
|
margin-left: -25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change styling when it's being hovered over
|
||||||
|
&:not(.selected) {
|
||||||
|
&:hover {
|
||||||
|
background: lighten($colorBodyBg, 5%);
|
||||||
|
color: lighten($colorBodyFg, 20%);
|
||||||
|
.context-trigger {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
color: $colorItemTreeIconHover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-icon {
|
||||||
|
position: relative;
|
||||||
|
&.loading {
|
||||||
|
pointer-events: none;
|
||||||
|
margin-left: $leftMargin;
|
||||||
|
|
||||||
|
.title-label {
|
||||||
|
// Text styling
|
||||||
|
font-style: italic;
|
||||||
|
font-size: .9em;
|
||||||
|
opacity: 0.5;
|
||||||
|
|
||||||
|
// Text positioning
|
||||||
|
margin-left: $iconWidth + $leftMargin;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
.wait-spinner {
|
||||||
|
margin-left: $leftMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.loading) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-more-button {
|
||||||
|
margin-top: $interiorMargin 0;
|
||||||
|
font-size: 0.8em;
|
||||||
|
position: relative;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -45px;
|
||||||
|
text-align: center;
|
||||||
|
width: 90px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,4 +27,5 @@
|
|||||||
|
|
||||||
@import "constants";
|
@import "constants";
|
||||||
@import "mixins";
|
@import "mixins";
|
||||||
@import "tree/tree";
|
@import "tree/tree";
|
||||||
|
@import "search/search";
|
@ -229,10 +229,12 @@
|
|||||||
bottom: $interiorMargin;
|
bottom: $interiorMargin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.search-holder {
|
||||||
|
top: $ueTopBarH + $interiorMarginLg;
|
||||||
|
}
|
||||||
.tree-holder {
|
.tree-holder {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
top: $ueTopBarH + $interiorMarginLg;
|
top: $ueTopBarH + $interiorMarginLg + $treeSearchInputBarH + $interiorMargin;
|
||||||
padding-right: $interiorMargin;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.items {
|
&.items {
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This bundle provides various general-purpose UI elements, including
|
||||||
|
* platform styling.
|
||||||
|
* @namespace platform/commonUI/general
|
||||||
|
*/
|
||||||
define(
|
define(
|
||||||
[],
|
[],
|
||||||
function () {
|
function () {
|
||||||
@ -29,6 +34,7 @@ define(
|
|||||||
/**
|
/**
|
||||||
* The StyleSheetLoader adds links to style sheets exposed from
|
* The StyleSheetLoader adds links to style sheets exposed from
|
||||||
* various bundles as extensions of category `stylesheets`.
|
* various bundles as extensions of category `stylesheets`.
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {object[]} stylesheets stylesheet extension definitions
|
* @param {object[]} stylesheets stylesheet extension definitions
|
||||||
* @param $document Angular's jqLite-wrapped document element
|
* @param $document Angular's jqLite-wrapped document element
|
||||||
@ -62,4 +68,4 @@ define(
|
|||||||
|
|
||||||
return StyleSheetLoader;
|
return StyleSheetLoader;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -42,6 +42,7 @@ define(
|
|||||||
* * `ungrouped`: All actions which did not have a defined
|
* * `ungrouped`: All actions which did not have a defined
|
||||||
* group.
|
* group.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ActionGroupController($scope) {
|
function ActionGroupController($scope) {
|
||||||
@ -102,4 +103,4 @@ define(
|
|||||||
|
|
||||||
return ActionGroupController;
|
return ActionGroupController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -29,6 +29,7 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Controller for the bottombar template. Exposes
|
* Controller for the bottombar template. Exposes
|
||||||
* available indicators (of extension category "indicators")
|
* available indicators (of extension category "indicators")
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function BottomBarController(indicators) {
|
function BottomBarController(indicators) {
|
||||||
@ -42,20 +43,19 @@ define(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
indicators = indicators.map(present);
|
this.indicators = indicators.map(present);
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get all indicators to display.
|
|
||||||
* @returns {Indicator[]} all indicators
|
|
||||||
* to display in the bottom bar.
|
|
||||||
*/
|
|
||||||
getIndicators: function () {
|
|
||||||
return indicators;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all indicators to display.
|
||||||
|
* @returns {Indicator[]} all indicators
|
||||||
|
* to display in the bottom bar.
|
||||||
|
* @memberof platform/commonUI/general.BottomBarController#
|
||||||
|
*/
|
||||||
|
BottomBarController.prototype.getIndicators = function () {
|
||||||
|
return this.indicators;
|
||||||
|
};
|
||||||
|
|
||||||
return BottomBarController;
|
return BottomBarController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -31,71 +31,69 @@ define(
|
|||||||
* menus) where clicking elsewhere in the document while the toggle
|
* menus) where clicking elsewhere in the document while the toggle
|
||||||
* is in an active state is intended to dismiss the toggle.
|
* is in an active state is intended to dismiss the toggle.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param $scope the scope in which this controller is active
|
* @param $scope the scope in which this controller is active
|
||||||
* @param $document the document element, injected by Angular
|
* @param $document the document element, injected by Angular
|
||||||
*/
|
*/
|
||||||
function ClickAwayController($scope, $document) {
|
function ClickAwayController($scope, $document) {
|
||||||
var state = false,
|
var self = this;
|
||||||
clickaway;
|
|
||||||
|
|
||||||
// Track state, but also attach and detach a listener for
|
this.state = false;
|
||||||
// mouseup events on the document.
|
this.$scope = $scope;
|
||||||
function deactivate() {
|
this.$document = $document;
|
||||||
state = false;
|
|
||||||
$document.off("mouseup", clickaway);
|
|
||||||
}
|
|
||||||
|
|
||||||
function activate() {
|
|
||||||
state = true;
|
|
||||||
$document.on("mouseup", clickaway);
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeState() {
|
|
||||||
if (state) {
|
|
||||||
deactivate();
|
|
||||||
} else {
|
|
||||||
activate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback used by the document listener. Deactivates;
|
// Callback used by the document listener. Deactivates;
|
||||||
// note also $scope.$apply is invoked to indicate that
|
// note also $scope.$apply is invoked to indicate that
|
||||||
// the state of this controller has changed.
|
// the state of this controller has changed.
|
||||||
clickaway = function () {
|
this.clickaway = function () {
|
||||||
deactivate();
|
self.deactivate();
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get the current state of the toggle.
|
|
||||||
* @return {boolean} true if active
|
|
||||||
*/
|
|
||||||
isActive: function () {
|
|
||||||
return state;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Set a new state for the toggle.
|
|
||||||
* @return {boolean} true to activate
|
|
||||||
*/
|
|
||||||
setState: function (newState) {
|
|
||||||
if (state !== newState) {
|
|
||||||
changeState();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Toggle the current state; activate if it is inactive,
|
|
||||||
* deactivate if it is active.
|
|
||||||
*/
|
|
||||||
toggle: function () {
|
|
||||||
changeState();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track state, but also attach and detach a listener for
|
||||||
|
// mouseup events on the document.
|
||||||
|
ClickAwayController.prototype.deactivate = function () {
|
||||||
|
this.state = false;
|
||||||
|
this.$document.off("mouseup", this.clickaway);
|
||||||
|
};
|
||||||
|
ClickAwayController.prototype.activate = function () {
|
||||||
|
this.state = true;
|
||||||
|
this.$document.on("mouseup", this.clickaway);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current state of the toggle.
|
||||||
|
* @return {boolean} true if active
|
||||||
|
*/
|
||||||
|
ClickAwayController.prototype.isActive =function () {
|
||||||
|
return this.state;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new state for the toggle.
|
||||||
|
* @return {boolean} true to activate
|
||||||
|
*/
|
||||||
|
ClickAwayController.prototype.setState = function (newState) {
|
||||||
|
if (this.state !== newState) {
|
||||||
|
this.toggle();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the current state; activate if it is inactive,
|
||||||
|
* deactivate if it is active.
|
||||||
|
*/
|
||||||
|
ClickAwayController.prototype.toggle = function () {
|
||||||
|
if (this.state) {
|
||||||
|
this.deactivate();
|
||||||
|
} else {
|
||||||
|
this.activate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return ClickAwayController;
|
return ClickAwayController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -33,6 +33,7 @@ define(
|
|||||||
* Controller for the context menu. Maintains an up-to-date
|
* Controller for the context menu. Maintains an up-to-date
|
||||||
* list of applicable actions (those from category "contextual")
|
* list of applicable actions (those from category "contextual")
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ContextMenuController($scope) {
|
function ContextMenuController($scope) {
|
||||||
@ -49,4 +50,4 @@ define(
|
|||||||
|
|
||||||
return ContextMenuController;
|
return ContextMenuController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -54,6 +54,7 @@ define(
|
|||||||
* parameter it received.) Getter-setter functions are never the
|
* parameter it received.) Getter-setter functions are never the
|
||||||
* target of a scope assignment and so avoid this problem.
|
* target of a scope assignment and so avoid this problem.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {Scope} $scope the controller's scope
|
* @param {Scope} $scope the controller's scope
|
||||||
*/
|
*/
|
||||||
@ -87,4 +88,4 @@ define(
|
|||||||
return GetterSetterController;
|
return GetterSetterController;
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -30,6 +30,7 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for the domain object selector control.
|
* Controller for the domain object selector control.
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {ObjectService} objectService service from which to
|
* @param {ObjectService} objectService service from which to
|
||||||
* read domain objects
|
* read domain objects
|
||||||
@ -38,28 +39,17 @@ define(
|
|||||||
function SelectorController(objectService, $scope) {
|
function SelectorController(objectService, $scope) {
|
||||||
var treeModel = {},
|
var treeModel = {},
|
||||||
listModel = {},
|
listModel = {},
|
||||||
selectedObjects = [],
|
previousSelected,
|
||||||
rootObject,
|
self = this;
|
||||||
previousSelected;
|
|
||||||
|
|
||||||
// For watch; look at the user's selection in the tree
|
// For watch; look at the user's selection in the tree
|
||||||
function getTreeSelection() {
|
function getTreeSelection() {
|
||||||
return treeModel.selectedObject;
|
return treeModel.selectedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the value of the field being edited
|
|
||||||
function getField() {
|
|
||||||
return $scope.ngModel[$scope.field] || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the value of the field being edited
|
|
||||||
function setField(value) {
|
|
||||||
$scope.ngModel[$scope.field] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store root object for subsequent exposure to template
|
// Store root object for subsequent exposure to template
|
||||||
function storeRoot(objects) {
|
function storeRoot(objects) {
|
||||||
rootObject = objects[ROOT_ID];
|
self.rootObject = objects[ROOT_ID];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that a selection is of the valid type
|
// Check that a selection is of the valid type
|
||||||
@ -82,7 +72,8 @@ define(
|
|||||||
function updateSelectedObjects(objects) {
|
function updateSelectedObjects(objects) {
|
||||||
// Look up from the
|
// Look up from the
|
||||||
function getObject(id) { return objects[id]; }
|
function getObject(id) { return objects[id]; }
|
||||||
selectedObjects = ids.filter(getObject).map(getObject);
|
self.selectedObjects =
|
||||||
|
ids.filter(getObject).map(getObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up objects by id, then populate right-hand list
|
// Look up objects by id, then populate right-hand list
|
||||||
@ -93,64 +84,85 @@ define(
|
|||||||
$scope.$watch(getTreeSelection, validateTreeSelection);
|
$scope.$watch(getTreeSelection, validateTreeSelection);
|
||||||
|
|
||||||
// Make sure right-hand list matches underlying model
|
// Make sure right-hand list matches underlying model
|
||||||
$scope.$watchCollection(getField, updateList);
|
$scope.$watchCollection(function () {
|
||||||
|
return self.getField();
|
||||||
|
}, updateList);
|
||||||
|
|
||||||
// Look up root object, then store it
|
// Look up root object, then store it
|
||||||
objectService.getObjects([ROOT_ID]).then(storeRoot);
|
objectService.getObjects([ROOT_ID]).then(storeRoot);
|
||||||
|
|
||||||
return {
|
this.$scope = $scope;
|
||||||
/**
|
this.selectedObjects = [];
|
||||||
* Get the root object to show in the left-hand tree.
|
|
||||||
* @returns {DomainObject} the root object
|
// Expose tree/list model for use in template directly
|
||||||
*/
|
this.treeModel = treeModel;
|
||||||
root: function () {
|
this.listModel = listModel;
|
||||||
return rootObject;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Add a domain object to the list of selected objects.
|
|
||||||
* @param {DomainObject} the domain object to select
|
|
||||||
*/
|
|
||||||
select: function (domainObject) {
|
|
||||||
var id = domainObject && domainObject.getId(),
|
|
||||||
list = getField() || [];
|
|
||||||
// Only select if we have a valid id,
|
|
||||||
// and it isn't already selected
|
|
||||||
if (id && list.indexOf(id) === -1) {
|
|
||||||
setField(list.concat([id]));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Remove a domain object from the list of selected objects.
|
|
||||||
* @param {DomainObject} the domain object to select
|
|
||||||
*/
|
|
||||||
deselect: function (domainObject) {
|
|
||||||
var id = domainObject && domainObject.getId(),
|
|
||||||
list = getField() || [];
|
|
||||||
// Only change if this was a valid id,
|
|
||||||
// for an object which was already selected
|
|
||||||
if (id && list.indexOf(id) !== -1) {
|
|
||||||
// Filter it out of the current field
|
|
||||||
setField(list.filter(function (otherId) {
|
|
||||||
return otherId !== id;
|
|
||||||
}));
|
|
||||||
// Clear the current list selection
|
|
||||||
delete listModel.selectedObject;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the currently-selected domain objects.
|
|
||||||
* @returns {DomainObject[]} the current selection
|
|
||||||
*/
|
|
||||||
selected: function () {
|
|
||||||
return selectedObjects;
|
|
||||||
},
|
|
||||||
// Expose tree/list model for use in template directly
|
|
||||||
treeModel: treeModel,
|
|
||||||
listModel: listModel
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Set the value of the field being edited
|
||||||
|
SelectorController.prototype.setField = function (value) {
|
||||||
|
this.$scope.ngModel[this.$scope.field] = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the value of the field being edited
|
||||||
|
SelectorController.prototype.getField = function () {
|
||||||
|
return this.$scope.ngModel[this.$scope.field] || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the root object to show in the left-hand tree.
|
||||||
|
* @returns {DomainObject} the root object
|
||||||
|
*/
|
||||||
|
SelectorController.prototype.root = function () {
|
||||||
|
return this.rootObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a domain object to the list of selected objects.
|
||||||
|
* @param {DomainObject} the domain object to select
|
||||||
|
*/
|
||||||
|
SelectorController.prototype.select = function (domainObject) {
|
||||||
|
var id = domainObject && domainObject.getId(),
|
||||||
|
list = this.getField() || [];
|
||||||
|
// Only select if we have a valid id,
|
||||||
|
// and it isn't already selected
|
||||||
|
if (id && list.indexOf(id) === -1) {
|
||||||
|
this.setField(list.concat([id]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a domain object from the list of selected objects.
|
||||||
|
* @param {DomainObject} the domain object to select
|
||||||
|
*/
|
||||||
|
SelectorController.prototype.deselect = function (domainObject) {
|
||||||
|
var id = domainObject && domainObject.getId(),
|
||||||
|
list = this.getField() || [];
|
||||||
|
// Only change if this was a valid id,
|
||||||
|
// for an object which was already selected
|
||||||
|
if (id && list.indexOf(id) !== -1) {
|
||||||
|
// Filter it out of the current field
|
||||||
|
this.setField(list.filter(function (otherId) {
|
||||||
|
return otherId !== id;
|
||||||
|
}));
|
||||||
|
// Clear the current list selection
|
||||||
|
delete this.listModel.selectedObject;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently-selected domain objects.
|
||||||
|
* @returns {DomainObject[]} the current selection
|
||||||
|
*/
|
||||||
|
SelectorController.prototype.selected = function () {
|
||||||
|
return this.selectedObjects;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return SelectorController;
|
return SelectorController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -32,59 +32,58 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Controller for the splitter in Browse mode. Current implementation
|
* Controller for the splitter in Browse mode. Current implementation
|
||||||
* uses many hard-coded constants; this could be generalized.
|
* uses many hard-coded constants; this could be generalized.
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function SplitPaneController() {
|
function SplitPaneController() {
|
||||||
var current = 200,
|
this.current = 200;
|
||||||
start = 200,
|
this.start = 200;
|
||||||
assigned = false;
|
this.assigned = false;
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get the current position of the splitter, in pixels
|
|
||||||
* from the left edge.
|
|
||||||
* @returns {number} position of the splitter, in pixels
|
|
||||||
*/
|
|
||||||
state: function (defaultState) {
|
|
||||||
// Set the state to the desired default, if we don't have a
|
|
||||||
// "real" current state yet.
|
|
||||||
if (arguments.length > 0 && !assigned) {
|
|
||||||
current = defaultState;
|
|
||||||
assigned = true;
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Begin moving the splitter; this will note the splitter's
|
|
||||||
* current position, which is necessary for correct
|
|
||||||
* interpretation of deltas provided by mct-drag.
|
|
||||||
*/
|
|
||||||
startMove: function () {
|
|
||||||
start = current;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Move the splitter a number of pixels to the right
|
|
||||||
* (negative numbers move the splitter to the left.)
|
|
||||||
* This movement is relative to the position of the
|
|
||||||
* splitter when startMove was last invoked.
|
|
||||||
* @param {number} delta number of pixels to move
|
|
||||||
*/
|
|
||||||
move: function (delta, minimum, maximum) {
|
|
||||||
// Ensure defaults for minimum/maximum
|
|
||||||
maximum = isNaN(maximum) ? DEFAULT_MAXIMUM : maximum;
|
|
||||||
minimum = isNaN(minimum) ? DEFAULT_MINIMUM : minimum;
|
|
||||||
|
|
||||||
// Update current splitter state
|
|
||||||
current = Math.min(
|
|
||||||
maximum,
|
|
||||||
Math.max(minimum, start + delta)
|
|
||||||
);
|
|
||||||
|
|
||||||
//console.log(current + "; minimum: " + minimum + "; max: " + maximum);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current position of the splitter, in pixels
|
||||||
|
* from the left edge.
|
||||||
|
* @returns {number} position of the splitter, in pixels
|
||||||
|
*/
|
||||||
|
SplitPaneController.prototype.state = function (defaultState) {
|
||||||
|
// Set the state to the desired default, if we don't have a
|
||||||
|
// "real" current state yet.
|
||||||
|
if (arguments.length > 0 && !this.assigned) {
|
||||||
|
this.current = defaultState;
|
||||||
|
this.assigned = true;
|
||||||
|
}
|
||||||
|
return this.current;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin moving the splitter; this will note the splitter's
|
||||||
|
* current position, which is necessary for correct
|
||||||
|
* interpretation of deltas provided by mct-drag.
|
||||||
|
*/
|
||||||
|
SplitPaneController.prototype.startMove = function () {
|
||||||
|
this.start = this.current;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the splitter a number of pixels to the right
|
||||||
|
* (negative numbers move the splitter to the left.)
|
||||||
|
* This movement is relative to the position of the
|
||||||
|
* splitter when startMove was last invoked.
|
||||||
|
* @param {number} delta number of pixels to move
|
||||||
|
*/
|
||||||
|
SplitPaneController.prototype.move = function (delta, minimum, maximum) {
|
||||||
|
// Ensure defaults for minimum/maximum
|
||||||
|
maximum = isNaN(maximum) ? DEFAULT_MAXIMUM : maximum;
|
||||||
|
minimum = isNaN(minimum) ? DEFAULT_MINIMUM : minimum;
|
||||||
|
|
||||||
|
// Update current splitter state
|
||||||
|
this.current = Math.min(
|
||||||
|
maximum,
|
||||||
|
Math.max(minimum, this.start + delta)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return SplitPaneController;
|
return SplitPaneController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -30,37 +30,37 @@ define(
|
|||||||
* A ToggleController is used to activate/deactivate things.
|
* A ToggleController is used to activate/deactivate things.
|
||||||
* A common usage is for "twistie"
|
* A common usage is for "twistie"
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ToggleController() {
|
function ToggleController() {
|
||||||
var state = false;
|
this.state = false;
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get the current state of the toggle.
|
|
||||||
* @return {boolean} true if active
|
|
||||||
*/
|
|
||||||
isActive: function () {
|
|
||||||
return state;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Set a new state for the toggle.
|
|
||||||
* @return {boolean} true to activate
|
|
||||||
*/
|
|
||||||
setState: function (newState) {
|
|
||||||
state = newState;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Toggle the current state; activate if it is inactive,
|
|
||||||
* deactivate if it is active.
|
|
||||||
*/
|
|
||||||
toggle: function () {
|
|
||||||
state = !state;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current state of the toggle.
|
||||||
|
* @return {boolean} true if active
|
||||||
|
*/
|
||||||
|
ToggleController.prototype.isActive = function () {
|
||||||
|
return this.state;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new state for the toggle.
|
||||||
|
* @return {boolean} true to activate
|
||||||
|
*/
|
||||||
|
ToggleController.prototype.setState = function (newState) {
|
||||||
|
this.state = newState;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the current state; activate if it is inactive,
|
||||||
|
* deactivate if it is active.
|
||||||
|
*/
|
||||||
|
ToggleController.prototype.toggle = function () {
|
||||||
|
this.state = !this.state;
|
||||||
|
};
|
||||||
|
|
||||||
return ToggleController;
|
return ToggleController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -48,12 +48,12 @@ define(
|
|||||||
* node expansion when this tree node's _subtree_ will contain
|
* node expansion when this tree node's _subtree_ will contain
|
||||||
* the navigated object (recursively, this becomes an
|
* the navigated object (recursively, this becomes an
|
||||||
* expand-to-show-navigated-object behavior.)
|
* expand-to-show-navigated-object behavior.)
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function TreeNodeController($scope, $timeout, $rootScope) {
|
function TreeNodeController($scope, $timeout) {
|
||||||
var selectedObject = ($scope.ngModel || {}).selectedObject,
|
var self = this,
|
||||||
isSelected = false,
|
selectedObject = ($scope.ngModel || {}).selectedObject;
|
||||||
hasBeenExpanded = false;
|
|
||||||
|
|
||||||
// Look up the id for a domain object. A convenience
|
// Look up the id for a domain object. A convenience
|
||||||
// for mapping; additionally does some undefined-checking.
|
// for mapping; additionally does some undefined-checking.
|
||||||
@ -76,17 +76,6 @@ define(
|
|||||||
checkPath(nodePath, navPath, index + 1));
|
checkPath(nodePath, navPath, index + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track that a node has been expanded, either by the
|
|
||||||
// user or automatically to show a selection.
|
|
||||||
function trackExpansion() {
|
|
||||||
if (!hasBeenExpanded) {
|
|
||||||
// Run on a timeout; if a lot of expansion needs to
|
|
||||||
// occur (e.g. if the selection is several nodes deep) we
|
|
||||||
// want this to be spread across multiple digest cycles.
|
|
||||||
$timeout(function () { hasBeenExpanded = true; }, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consider the currently-navigated object and update
|
// Consider the currently-navigated object and update
|
||||||
// parameters which support display.
|
// parameters which support display.
|
||||||
function checkSelection() {
|
function checkSelection() {
|
||||||
@ -101,7 +90,7 @@ define(
|
|||||||
|
|
||||||
// Deselect; we will reselect below, iff we are
|
// Deselect; we will reselect below, iff we are
|
||||||
// exactly at the end of the path.
|
// exactly at the end of the path.
|
||||||
isSelected = false;
|
self.isSelectedFlag = false;
|
||||||
|
|
||||||
// Expand if necessary (if the navigated object will
|
// Expand if necessary (if the navigated object will
|
||||||
// be in this node's subtree)
|
// be in this node's subtree)
|
||||||
@ -120,12 +109,12 @@ define(
|
|||||||
// at the end of the path, highlight;
|
// at the end of the path, highlight;
|
||||||
// otherwise, expand.
|
// otherwise, expand.
|
||||||
if (nodePath.length === navPath.length) {
|
if (nodePath.length === navPath.length) {
|
||||||
isSelected = true;
|
self.isSelectedFlag = true;
|
||||||
} else { // node path is shorter: Expand!
|
} else { // node path is shorter: Expand!
|
||||||
if ($scope.toggle) {
|
if ($scope.toggle) {
|
||||||
$scope.toggle.setState(true);
|
$scope.toggle.setState(true);
|
||||||
}
|
}
|
||||||
trackExpansion();
|
self.trackExpansion();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -138,38 +127,52 @@ define(
|
|||||||
selectedObject = object;
|
selectedObject = object;
|
||||||
checkSelection();
|
checkSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isSelectedFlag = false;
|
||||||
|
this.hasBeenExpandedFlag = false;
|
||||||
|
this.$timeout = $timeout;
|
||||||
|
|
||||||
// Listen for changes which will effect display parameters
|
// Listen for changes which will effect display parameters
|
||||||
$scope.$watch("ngModel.selectedObject", setSelection);
|
$scope.$watch("ngModel.selectedObject", setSelection);
|
||||||
$scope.$watch("domainObject", checkSelection);
|
$scope.$watch("domainObject", checkSelection);
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* This method should be called when a node is expanded
|
|
||||||
* to record that this has occurred, to support one-time
|
|
||||||
* lazy loading of the node's subtree.
|
|
||||||
*/
|
|
||||||
trackExpansion: trackExpansion,
|
|
||||||
/**
|
|
||||||
* Check if this not has ever been expanded.
|
|
||||||
* @returns true if it has been expanded
|
|
||||||
*/
|
|
||||||
hasBeenExpanded: function () {
|
|
||||||
return hasBeenExpanded;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Check whether or not the domain object represented by
|
|
||||||
* this tree node should be highlighted.
|
|
||||||
* An object will be highlighted if it matches
|
|
||||||
* ngModel.selectedObject
|
|
||||||
* @returns true if this should be highlighted
|
|
||||||
*/
|
|
||||||
isSelected: function () {
|
|
||||||
return isSelected;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should be called when a node is expanded
|
||||||
|
* to record that this has occurred, to support one-time
|
||||||
|
* lazy loading of the node's subtree.
|
||||||
|
*/
|
||||||
|
TreeNodeController.prototype.trackExpansion = function () {
|
||||||
|
var self = this;
|
||||||
|
if (!self.hasBeenExpanded()) {
|
||||||
|
// Run on a timeout; if a lot of expansion needs to
|
||||||
|
// occur (e.g. if the selection is several nodes deep) we
|
||||||
|
// want this to be spread across multiple digest cycles.
|
||||||
|
self.$timeout(function () {
|
||||||
|
self.hasBeenExpandedFlag = true;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this not has ever been expanded.
|
||||||
|
* @returns true if it has been expanded
|
||||||
|
*/
|
||||||
|
TreeNodeController.prototype.hasBeenExpanded = function () {
|
||||||
|
return this.hasBeenExpandedFlag;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether or not the domain object represented by
|
||||||
|
* this tree node should be highlighted.
|
||||||
|
* An object will be highlighted if it matches
|
||||||
|
* ngModel.selectedObject
|
||||||
|
* @returns true if this should be highlighted
|
||||||
|
*/
|
||||||
|
TreeNodeController.prototype.isSelected = function () {
|
||||||
|
return this.isSelectedFlag;
|
||||||
|
};
|
||||||
|
|
||||||
return TreeNodeController;
|
return TreeNodeController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -32,6 +32,7 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Controller for the view switcher; populates and maintains a list
|
* Controller for the view switcher; populates and maintains a list
|
||||||
* of applicable views for a represented domain object.
|
* of applicable views for a represented domain object.
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ViewSwitcherController($scope, $timeout) {
|
function ViewSwitcherController($scope, $timeout) {
|
||||||
@ -71,3 +72,4 @@ define(
|
|||||||
return ViewSwitcherController;
|
return ViewSwitcherController;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ define(
|
|||||||
* plain string attribute, instead of as an Angular
|
* plain string attribute, instead of as an Angular
|
||||||
* expression.
|
* expression.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function MCTContainer(containers) {
|
function MCTContainer(containers) {
|
||||||
@ -96,4 +97,4 @@ define(
|
|||||||
|
|
||||||
return MCTContainer;
|
return MCTContainer;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -44,6 +44,7 @@ define(
|
|||||||
* and vertical pixel offset of the current mouse position
|
* and vertical pixel offset of the current mouse position
|
||||||
* relative to the mouse position where dragging began.
|
* relative to the mouse position where dragging began.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -157,3 +158,4 @@ define(
|
|||||||
return MCTDrag;
|
return MCTDrag;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ define(
|
|||||||
* This is an Angular expression, and it will be re-evaluated after
|
* This is an Angular expression, and it will be re-evaluated after
|
||||||
* each interval.
|
* each interval.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -111,4 +112,4 @@ define(
|
|||||||
|
|
||||||
return MCTResize;
|
return MCTResize;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -37,6 +37,7 @@ define(
|
|||||||
* This is exposed as two directives in `bundle.json`; the difference
|
* This is exposed as two directives in `bundle.json`; the difference
|
||||||
* is handled purely by parameterization.
|
* is handled purely by parameterization.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param $parse Angular's $parse
|
* @param $parse Angular's $parse
|
||||||
* @param {string} property property to manage within the HTML element
|
* @param {string} property property to manage within the HTML element
|
||||||
@ -80,4 +81,4 @@ define(
|
|||||||
return MCTScroll;
|
return MCTScroll;
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -91,6 +91,7 @@ define(
|
|||||||
* etc. can be set on that element to control the splitter's
|
* etc. can be set on that element to control the splitter's
|
||||||
* allowable positions.
|
* allowable positions.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function MCTSplitPane($parse, $log) {
|
function MCTSplitPane($parse, $log) {
|
||||||
@ -213,3 +214,4 @@ define(
|
|||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements `mct-splitter` directive.
|
* Implements `mct-splitter` directive.
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function MCTSplitter() {
|
function MCTSplitter() {
|
||||||
@ -88,3 +89,4 @@ define(
|
|||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -32,62 +32,56 @@ define(
|
|||||||
/**
|
/**
|
||||||
* The url service handles calls for url paths
|
* The url service handles calls for url paths
|
||||||
* using domain objects.
|
* using domain objects.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/general
|
||||||
*/
|
*/
|
||||||
function UrlService($location) {
|
function UrlService($location) {
|
||||||
// Returns the url for the mode wanted
|
this.$location = $location;
|
||||||
// and the domainObject passed in. A path
|
|
||||||
// is returned. The view is defaulted to
|
|
||||||
// the current location's (current object's)
|
|
||||||
// view set.
|
|
||||||
function urlForLocation(mode, domainObject) {
|
|
||||||
var context = domainObject &&
|
|
||||||
domainObject.getCapability('context'),
|
|
||||||
objectPath = context ? context.getPath() : [],
|
|
||||||
ids = objectPath.map(function (domainObject) {
|
|
||||||
return domainObject.getId();
|
|
||||||
}),
|
|
||||||
// Parses the path together. Starts with the
|
|
||||||
// default index.html file, then the mode passed
|
|
||||||
// into the service, followed by ids in the url
|
|
||||||
// joined by '/', and lastly the view path from
|
|
||||||
// the current location
|
|
||||||
path = mode + "/" + ids.slice(1).join("/");
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uses the Url for the current location
|
|
||||||
// from the urlForLocation function and
|
|
||||||
// includes the view and the index path
|
|
||||||
function urlForNewTab(mode, domainObject) {
|
|
||||||
var viewPath = "?view=" + $location.search().view,
|
|
||||||
newTabPath =
|
|
||||||
"index.html#" + urlForLocation(mode, domainObject) + viewPath;
|
|
||||||
return newTabPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Returns the Url path for a specific domain object
|
|
||||||
* without the index.html path and the view path
|
|
||||||
* @param {value} value of the browse or edit mode
|
|
||||||
* for the path
|
|
||||||
* @param {DomainObject} value of the domain object
|
|
||||||
* to get the path of
|
|
||||||
*/
|
|
||||||
urlForNewTab: urlForNewTab,
|
|
||||||
/**
|
|
||||||
* Returns the Url path for a specific domain object
|
|
||||||
* including the index.html path and the view path
|
|
||||||
* allowing a new tab to hold the correct characteristics
|
|
||||||
* @param {value} value of the browse or edit mode
|
|
||||||
* for the path
|
|
||||||
* @param {DomainObject} value of the domain object
|
|
||||||
* to get the path of
|
|
||||||
*/
|
|
||||||
urlForLocation: urlForLocation
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Url path for a specific domain object
|
||||||
|
* without the index.html path and the view path
|
||||||
|
* @param {string} mode value of browse or edit mode
|
||||||
|
* for the path
|
||||||
|
* @param {DomainObject} value of the domain object
|
||||||
|
* to get the path of
|
||||||
|
* @returns {string} URL for the domain object
|
||||||
|
*/
|
||||||
|
UrlService.prototype.urlForLocation = function (mode, domainObject) {
|
||||||
|
var context = domainObject &&
|
||||||
|
domainObject.getCapability('context'),
|
||||||
|
objectPath = context ? context.getPath() : [],
|
||||||
|
ids = objectPath.map(function (domainObject) {
|
||||||
|
return domainObject.getId();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Parses the path together. Starts with the
|
||||||
|
// default index.html file, then the mode passed
|
||||||
|
// into the service, followed by ids in the url
|
||||||
|
// joined by '/', and lastly the view path from
|
||||||
|
// the current location
|
||||||
|
return mode + "/" + ids.slice(1).join("/");
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Url path for a specific domain object
|
||||||
|
* including the index.html path and the view path
|
||||||
|
* allowing a new tab to hold the correct characteristics
|
||||||
|
* @param {string} mode value of browse or edit mode
|
||||||
|
* for the path
|
||||||
|
* @param {DomainObject} value of the domain object
|
||||||
|
* to get the path of
|
||||||
|
* @returns {string} URL for the domain object
|
||||||
|
*/
|
||||||
|
UrlService.prototype.urlForNewTab = function (mode, domainObject) {
|
||||||
|
var viewPath = "?view=" + this.$location.search().view,
|
||||||
|
newTabPath =
|
||||||
|
"index.html#" + this.urlForLocation(mode, domainObject) +
|
||||||
|
viewPath;
|
||||||
|
return newTabPath;
|
||||||
|
};
|
||||||
|
|
||||||
return UrlService;
|
return UrlService;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -20,6 +20,13 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This bundle provides support for object inspection (specifically, metadata
|
||||||
|
* show in bubbles on hover.)
|
||||||
|
* @namespace platform/commonUI/inspect
|
||||||
|
*/
|
||||||
|
|
||||||
define({
|
define({
|
||||||
BUBBLE_TEMPLATE: "<mct-container key=\"bubble\" " +
|
BUBBLE_TEMPLATE: "<mct-container key=\"bubble\" " +
|
||||||
"bubble-title=\"{{bubbleTitle}}\" " +
|
"bubble-title=\"{{bubbleTitle}}\" " +
|
||||||
@ -33,4 +40,4 @@ define({
|
|||||||
// Max width and margins allowed for bubbles; defined in /platform/commonUI/general/res/sass/_constants.scss
|
// Max width and margins allowed for bubbles; defined in /platform/commonUI/general/res/sass/_constants.scss
|
||||||
BUBBLE_MARGIN_LR: 10,
|
BUBBLE_MARGIN_LR: 10,
|
||||||
BUBBLE_MAX_WIDTH: 300
|
BUBBLE_MAX_WIDTH: 300
|
||||||
});
|
});
|
||||||
|
@ -30,92 +30,109 @@ define(
|
|||||||
* The `info` gesture displays domain object metadata in a
|
* The `info` gesture displays domain object metadata in a
|
||||||
* bubble on hover.
|
* bubble on hover.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/commonUI/inspect
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Gesture}
|
||||||
* @param $timeout Angular's `$timeout`
|
* @param $timeout Angular's `$timeout`
|
||||||
* @param {InfoService} infoService a service which shows info bubbles
|
* @param {InfoService} infoService a service which shows info bubbles
|
||||||
* @param {number} DELAY delay, in milliseconds, before bubble appears
|
* @param {number} delay delay, in milliseconds, before bubble appears
|
||||||
* @param element jqLite-wrapped DOM element
|
* @param element jqLite-wrapped DOM element
|
||||||
* @param {DomainObject} domainObject the domain object for which to
|
* @param {DomainObject} domainObject the domain object for which to
|
||||||
* show information
|
* show information
|
||||||
*/
|
*/
|
||||||
function InfoGesture($timeout, infoService, DELAY, element, domainObject) {
|
function InfoGesture($timeout, infoService, delay, element, domainObject) {
|
||||||
var dismissBubble,
|
var self = this;
|
||||||
pendingBubble,
|
|
||||||
mousePosition,
|
|
||||||
scopeOff;
|
|
||||||
|
|
||||||
function trackPosition(event) {
|
// Callback functions to preserve the "this" pointer (in the
|
||||||
// Record mouse position, so bubble can be shown at latest
|
// absence of Function.prototype.bind)
|
||||||
// mouse position (not just where the mouse entered)
|
this.showBubbleCallback = function (event) {
|
||||||
mousePosition = [ event.clientX, event.clientY ];
|
self.showBubble(event);
|
||||||
}
|
};
|
||||||
|
this.hideBubbleCallback = function (event) {
|
||||||
function hideBubble() {
|
self.hideBubble(event);
|
||||||
// If a bubble is showing, dismiss it
|
};
|
||||||
if (dismissBubble) {
|
this.trackPositionCallback = function (event) {
|
||||||
dismissBubble();
|
self.trackPosition(event);
|
||||||
element.off('mouseleave', hideBubble);
|
};
|
||||||
dismissBubble = undefined;
|
|
||||||
}
|
|
||||||
// If a bubble will be shown on a timeout, cancel that
|
|
||||||
if (pendingBubble) {
|
|
||||||
$timeout.cancel(pendingBubble);
|
|
||||||
element.off('mousemove', trackPosition);
|
|
||||||
element.off('mouseleave', hideBubble);
|
|
||||||
pendingBubble = undefined;
|
|
||||||
}
|
|
||||||
// Also clear mouse position so we don't have a ton of tiny
|
|
||||||
// arrays allocated while user mouses over things
|
|
||||||
mousePosition = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function showBubble(event) {
|
|
||||||
trackPosition(event);
|
|
||||||
|
|
||||||
// Also need to track position during hover
|
|
||||||
element.on('mousemove', trackPosition);
|
|
||||||
|
|
||||||
// Show the bubble, after a suitable delay (if mouse has
|
|
||||||
// left before this time is up, this will be canceled.)
|
|
||||||
pendingBubble = $timeout(function () {
|
|
||||||
dismissBubble = infoService.display(
|
|
||||||
"info-table",
|
|
||||||
domainObject.getModel().name,
|
|
||||||
domainObject.useCapability('metadata'),
|
|
||||||
mousePosition
|
|
||||||
);
|
|
||||||
element.off('mousemove', trackPosition);
|
|
||||||
pendingBubble = undefined;
|
|
||||||
}, DELAY);
|
|
||||||
|
|
||||||
element.on('mouseleave', hideBubble);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show bubble (on a timeout) on mouse over
|
|
||||||
element.on('mouseenter', showBubble);
|
|
||||||
|
|
||||||
// Also make sure we dismiss bubble if representation is destroyed
|
// Also make sure we dismiss bubble if representation is destroyed
|
||||||
// before the mouse actually leaves it
|
// before the mouse actually leaves it
|
||||||
scopeOff = element.scope().$on('$destroy', hideBubble);
|
this.scopeOff = element.scope().$on('$destroy', this.hideBubbleCallback);
|
||||||
|
|
||||||
return {
|
this.element = element;
|
||||||
/**
|
this.$timeout = $timeout;
|
||||||
* Detach any event handlers associated with this gesture.
|
this.infoService = infoService;
|
||||||
* @memberof InfoGesture
|
this.delay = delay;
|
||||||
* @method
|
this.domainObject = domainObject;
|
||||||
*/
|
|
||||||
destroy: function () {
|
// Show bubble (on a timeout) on mouse over
|
||||||
// Dismiss any active bubble...
|
element.on('mouseenter', this.showBubbleCallback);
|
||||||
hideBubble();
|
|
||||||
// ...and detach listeners
|
|
||||||
element.off('mouseenter', showBubble);
|
|
||||||
scopeOff();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InfoGesture.prototype.trackPosition = function (event) {
|
||||||
|
// Record mouse position, so bubble can be shown at latest
|
||||||
|
// mouse position (not just where the mouse entered)
|
||||||
|
this.mousePosition = [ event.clientX, event.clientY ];
|
||||||
|
};
|
||||||
|
|
||||||
|
InfoGesture.prototype.hideBubble = function () {
|
||||||
|
// If a bubble is showing, dismiss it
|
||||||
|
if (this.dismissBubble) {
|
||||||
|
this.dismissBubble();
|
||||||
|
this.element.off('mouseleave', this.hideBubbleCallback);
|
||||||
|
this.dismissBubble = undefined;
|
||||||
|
}
|
||||||
|
// If a bubble will be shown on a timeout, cancel that
|
||||||
|
if (this.pendingBubble) {
|
||||||
|
this.$timeout.cancel(this.pendingBubble);
|
||||||
|
this.element.off('mousemove', this.trackPositionCallback);
|
||||||
|
this.element.off('mouseleave', this.hideBubbleCallback);
|
||||||
|
this.pendingBubble = undefined;
|
||||||
|
}
|
||||||
|
// Also clear mouse position so we don't have a ton of tiny
|
||||||
|
// arrays allocated while user mouses over things
|
||||||
|
this.mousePosition = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
InfoGesture.prototype.showBubble = function (event) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.trackPosition(event);
|
||||||
|
|
||||||
|
// Also need to track position during hover
|
||||||
|
this.element.on('mousemove', this.trackPositionCallback);
|
||||||
|
|
||||||
|
// Show the bubble, after a suitable delay (if mouse has
|
||||||
|
// left before this time is up, this will be canceled.)
|
||||||
|
this.pendingBubble = this.$timeout(function () {
|
||||||
|
self.dismissBubble = self.infoService.display(
|
||||||
|
"info-table",
|
||||||
|
self.domainObject.getModel().name,
|
||||||
|
self.domainObject.useCapability('metadata'),
|
||||||
|
self.mousePosition
|
||||||
|
);
|
||||||
|
self.element.off('mousemove', self.trackPositionCallback);
|
||||||
|
self.pendingBubble = undefined;
|
||||||
|
}, this.delay);
|
||||||
|
|
||||||
|
this.element.on('mouseleave', this.hideBubbleCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach any event handlers associated with this gesture.
|
||||||
|
* @method
|
||||||
|
*/
|
||||||
|
InfoGesture.prototype.destroy = function () {
|
||||||
|
// Dismiss any active bubble...
|
||||||
|
this.hideBubble();
|
||||||
|
// ...and detach listeners
|
||||||
|
this.element.off('mouseenter', this.showBubbleCallback);
|
||||||
|
this.scopeOff();
|
||||||
|
};
|
||||||
|
|
||||||
return InfoGesture;
|
return InfoGesture;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -31,65 +31,71 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays informative content ("info bubbles") for the user.
|
* Displays informative content ("info bubbles") for the user.
|
||||||
|
* @memberof platform/commonUI/inspect
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function InfoService($compile, $document, $window, $rootScope) {
|
function InfoService($compile, $document, $window, $rootScope) {
|
||||||
|
this.$compile = $compile;
|
||||||
|
this.$document = $document;
|
||||||
|
this.$window = $window;
|
||||||
|
this.$rootScope = $rootScope;
|
||||||
|
}
|
||||||
|
|
||||||
function display(templateKey, title, content, position) {
|
/**
|
||||||
var body = $document.find('body'),
|
* Display an info bubble at the specified location.
|
||||||
scope = $rootScope.$new(),
|
* @param {string} templateKey template to place in bubble
|
||||||
winDim = [$window.innerWidth, $window.innerHeight],
|
* @param {string} title title for the bubble
|
||||||
bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR + InfoConstants.BUBBLE_MAX_WIDTH,
|
* @param {*} content content to pass to the template, via
|
||||||
goLeft = position[0] > (winDim[0] - bubbleSpaceLR),
|
* `ng-model`
|
||||||
goUp = position[1] > (winDim[1] / 2),
|
* @param {number[]} x,y position of the info bubble, in
|
||||||
bubble;
|
* pixel coordinates.
|
||||||
|
* @returns {Function} a function that may be invoked to
|
||||||
|
* dismiss the info bubble
|
||||||
|
*/
|
||||||
|
InfoService.prototype.display = function (templateKey, title, content, position) {
|
||||||
|
var $compile = this.$compile,
|
||||||
|
$document = this.$document,
|
||||||
|
$window = this.$window,
|
||||||
|
$rootScope = this.$rootScope,
|
||||||
|
body = $document.find('body'),
|
||||||
|
scope = $rootScope.$new(),
|
||||||
|
winDim = [$window.innerWidth, $window.innerHeight],
|
||||||
|
bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR + InfoConstants.BUBBLE_MAX_WIDTH,
|
||||||
|
goLeft = position[0] > (winDim[0] - bubbleSpaceLR),
|
||||||
|
goUp = position[1] > (winDim[1] / 2),
|
||||||
|
bubble;
|
||||||
|
|
||||||
// Pass model & container parameters into the scope
|
// Pass model & container parameters into the scope
|
||||||
scope.bubbleModel = content;
|
scope.bubbleModel = content;
|
||||||
scope.bubbleTemplate = templateKey;
|
scope.bubbleTemplate = templateKey;
|
||||||
scope.bubbleLayout = (goUp ? 'arw-btm' : 'arw-top') + ' ' +
|
scope.bubbleLayout = (goUp ? 'arw-btm' : 'arw-top') + ' ' +
|
||||||
(goLeft ? 'arw-right' : 'arw-left');
|
(goLeft ? 'arw-right' : 'arw-left');
|
||||||
scope.bubbleTitle = title;
|
scope.bubbleTitle = title;
|
||||||
|
|
||||||
// Create the context menu
|
// Create the context menu
|
||||||
bubble = $compile(BUBBLE_TEMPLATE)(scope);
|
bubble = $compile(BUBBLE_TEMPLATE)(scope);
|
||||||
|
|
||||||
// Position the bubble
|
// Position the bubble
|
||||||
bubble.css('position', 'absolute');
|
bubble.css('position', 'absolute');
|
||||||
if (goLeft) {
|
if (goLeft) {
|
||||||
bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px');
|
bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px');
|
||||||
} else {
|
} else {
|
||||||
bubble.css('left', position[0] + OFFSET[0] + 'px');
|
bubble.css('left', position[0] + OFFSET[0] + 'px');
|
||||||
}
|
}
|
||||||
if (goUp) {
|
if (goUp) {
|
||||||
bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px');
|
bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px');
|
||||||
} else {
|
} else {
|
||||||
bubble.css('top', position[1] + OFFSET[1] + 'px');
|
bubble.css('top', position[1] + OFFSET[1] + 'px');
|
||||||
}
|
|
||||||
|
|
||||||
// Add the menu to the body
|
|
||||||
body.append(bubble);
|
|
||||||
|
|
||||||
// Return a function to dismiss the bubble
|
|
||||||
return function () { bubble.remove(); };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
// Add the menu to the body
|
||||||
/**
|
body.append(bubble);
|
||||||
* Display an info bubble at the specified location.
|
|
||||||
* @param {string} templateKey template to place in bubble
|
// Return a function to dismiss the bubble
|
||||||
* @param {string} title title for the bubble
|
return function () { bubble.remove(); };
|
||||||
* @param {*} content content to pass to the template, via
|
};
|
||||||
* `ng-model`
|
|
||||||
* @param {number[]} x,y position of the info bubble, in
|
|
||||||
* pixel coordinates.
|
|
||||||
* @returns {Function} a function that may be invoked to
|
|
||||||
* dismiss the info bubble
|
|
||||||
*/
|
|
||||||
display: display
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return InfoService;
|
return InfoService;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -32,9 +32,11 @@ define(
|
|||||||
* which capabilities. This supports composition policy (rules
|
* which capabilities. This supports composition policy (rules
|
||||||
* for which objects can contain which other objects) which
|
* for which objects can contain which other objects) which
|
||||||
* sometimes is determined based on the presence of capabilities.
|
* sometimes is determined based on the presence of capabilities.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/containment
|
||||||
*/
|
*/
|
||||||
function CapabilityTable(typeService, capabilityService) {
|
function CapabilityTable(typeService, capabilityService) {
|
||||||
var table = {};
|
var self = this;
|
||||||
|
|
||||||
// Build an initial model for a type
|
// Build an initial model for a type
|
||||||
function buildModel(type) {
|
function buildModel(type) {
|
||||||
@ -52,25 +54,26 @@ define(
|
|||||||
function addToTable(type) {
|
function addToTable(type) {
|
||||||
var typeKey = type.getKey();
|
var typeKey = type.getKey();
|
||||||
Object.keys(getCapabilities(type)).forEach(function (key) {
|
Object.keys(getCapabilities(type)).forEach(function (key) {
|
||||||
table[key] = table[key] || {};
|
self.table[key] = self.table[key] || {};
|
||||||
table[key][typeKey] = true;
|
self.table[key][typeKey] = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the table
|
// Build the table
|
||||||
|
this.table = {};
|
||||||
(typeService.listTypes() || []).forEach(addToTable);
|
(typeService.listTypes() || []).forEach(addToTable);
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Check if a type is expected to expose a specific
|
|
||||||
* capability.
|
|
||||||
*/
|
|
||||||
hasCapability: function (typeKey, capabilityKey) {
|
|
||||||
return (table[capabilityKey] || {})[typeKey];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a type is expected to expose a specific capability.
|
||||||
|
* @param {string} typeKey the type identifier
|
||||||
|
* @param {string} capabilityKey the capability identifier
|
||||||
|
* @returns {boolean} true if expected to be exposed
|
||||||
|
*/
|
||||||
|
CapabilityTable.prototype.hasCapability = function (typeKey, capabilityKey) {
|
||||||
|
return (this.table[capabilityKey] || {})[typeKey];
|
||||||
|
};
|
||||||
|
|
||||||
return CapabilityTable;
|
return CapabilityTable;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -34,47 +34,51 @@ define(
|
|||||||
* since it's delegated to a different policy category.
|
* since it's delegated to a different policy category.
|
||||||
* To avoid a circular dependency, the service is obtained via
|
* To avoid a circular dependency, the service is obtained via
|
||||||
* Angular's `$injector`.
|
* Angular's `$injector`.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/containment
|
||||||
|
* @implements {Policy.<Action, ActionContext>}
|
||||||
*/
|
*/
|
||||||
function ComposeActionPolicy($injector) {
|
function ComposeActionPolicy($injector) {
|
||||||
var policyService;
|
this.getPolicyService = function () {
|
||||||
|
return $injector.get('policyService');
|
||||||
function allowComposition(containerObject, selectedObject) {
|
|
||||||
// Get the object types involved in the compose action
|
|
||||||
var containerType = containerObject &&
|
|
||||||
containerObject.getCapability('type'),
|
|
||||||
selectedType = selectedObject &&
|
|
||||||
selectedObject.getCapability('type');
|
|
||||||
|
|
||||||
// Get a reference to the policy service if needed...
|
|
||||||
policyService = policyService || $injector.get('policyService');
|
|
||||||
|
|
||||||
// ...and delegate to the composition policy
|
|
||||||
return policyService.allow(
|
|
||||||
'composition',
|
|
||||||
containerType,
|
|
||||||
selectedType
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Check whether or not a compose action should be allowed
|
|
||||||
* in this context.
|
|
||||||
* @returns {boolean} true if it may be allowed
|
|
||||||
*/
|
|
||||||
allow: function (candidate, context) {
|
|
||||||
if (candidate.getMetadata().key === 'compose') {
|
|
||||||
return allowComposition(
|
|
||||||
(context || {}).domainObject,
|
|
||||||
(context || {}).selectedObject
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) {
|
||||||
|
// Get the object types involved in the compose action
|
||||||
|
var containerType = containerObject &&
|
||||||
|
containerObject.getCapability('type'),
|
||||||
|
selectedType = selectedObject &&
|
||||||
|
selectedObject.getCapability('type');
|
||||||
|
|
||||||
|
// Get a reference to the policy service if needed...
|
||||||
|
this.policyService = this.policyService || this.getPolicyService();
|
||||||
|
|
||||||
|
// ...and delegate to the composition policy
|
||||||
|
return this.policyService.allow(
|
||||||
|
'composition',
|
||||||
|
containerType,
|
||||||
|
selectedType
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether or not a compose action should be allowed
|
||||||
|
* in this context.
|
||||||
|
* @returns {boolean} true if it may be allowed
|
||||||
|
* @memberof platform/containment.ComposeActionPolicy#
|
||||||
|
*/
|
||||||
|
ComposeActionPolicy.prototype.allow = function (candidate, context) {
|
||||||
|
if (candidate.getMetadata().key === 'compose') {
|
||||||
|
return this.allowComposition(
|
||||||
|
(context || {}).domainObject,
|
||||||
|
(context || {}).selectedObject
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
return ComposeActionPolicy;
|
return ComposeActionPolicy;
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -8,21 +8,19 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Policy allowing composition only for domain object types which
|
* Policy allowing composition only for domain object types which
|
||||||
* have a composition property.
|
* have a composition property.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/containment
|
||||||
|
* @implements {Policy.<Type, Type>}
|
||||||
*/
|
*/
|
||||||
function CompositionModelPolicy() {
|
function CompositionModelPolicy() {
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Is the type identified by the candidate allowed to
|
|
||||||
* contain the type described by the context?
|
|
||||||
*/
|
|
||||||
allow: function (candidate, context) {
|
|
||||||
return Array.isArray(
|
|
||||||
(candidate.getInitialModel() || {}).composition
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompositionModelPolicy.prototype.allow = function (candidate, context) {
|
||||||
|
return Array.isArray(
|
||||||
|
(candidate.getInitialModel() || {}).composition
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return CompositionModelPolicy;
|
return CompositionModelPolicy;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -28,24 +28,20 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Disallow composition changes to objects which are not mutable.
|
* Disallow composition changes to objects which are not mutable.
|
||||||
|
* @memberof platform/containment
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Policy.<Type, Type>}
|
||||||
*/
|
*/
|
||||||
function CompositionMutabilityPolicy() {
|
function CompositionMutabilityPolicy() {
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Is the type identified by the candidate allowed to
|
|
||||||
* contain the type described by the context?
|
|
||||||
* @param {Type} candidate the type of domain object
|
|
||||||
*/
|
|
||||||
allow: function (candidate) {
|
|
||||||
// Equate creatability with mutability; that is, users
|
|
||||||
// can only modify objects of types they can create, and
|
|
||||||
// vice versa.
|
|
||||||
return candidate.hasFeature('creation');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompositionMutabilityPolicy.prototype.allow = function (candidate) {
|
||||||
|
// Equate creatability with mutability; that is, users
|
||||||
|
// can only modify objects of types they can create, and
|
||||||
|
// vice versa.
|
||||||
|
return candidate.hasFeature('creation');
|
||||||
|
};
|
||||||
|
|
||||||
return CompositionMutabilityPolicy;
|
return CompositionMutabilityPolicy;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This bundle implements "containment" rules, which determine which objects
|
||||||
|
* can be contained within which other objects.
|
||||||
|
* @namespace platform/containment
|
||||||
|
*/
|
||||||
define(
|
define(
|
||||||
['./ContainmentTable'],
|
['./ContainmentTable'],
|
||||||
function (ContainmentTable) {
|
function (ContainmentTable) {
|
||||||
@ -28,30 +33,27 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines composition policy as driven by type metadata.
|
* Defines composition policy as driven by type metadata.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/containment
|
||||||
|
* @implements {Policy.<Type, Type>}
|
||||||
*/
|
*/
|
||||||
function CompositionPolicy($injector) {
|
function CompositionPolicy($injector) {
|
||||||
// We're really just wrapping the containment table and rephrasing
|
// We're really just wrapping the containment table and rephrasing
|
||||||
// it as a policy decision.
|
// it as a policy decision.
|
||||||
var table;
|
var table;
|
||||||
|
|
||||||
function getTable() {
|
this.getTable = function () {
|
||||||
return (table = table || new ContainmentTable(
|
return (table = table || new ContainmentTable(
|
||||||
$injector.get('typeService'),
|
$injector.get('typeService'),
|
||||||
$injector.get('capabilityService')
|
$injector.get('capabilityService')
|
||||||
));
|
));
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Is the type identified by the candidate allowed to
|
|
||||||
* contain the type described by the context?
|
|
||||||
*/
|
|
||||||
allow: function (candidate, context) {
|
|
||||||
return getTable().canContain(candidate, context);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompositionPolicy.prototype.allow = function (candidate, context) {
|
||||||
|
return this.getTable().canContain(candidate, context);
|
||||||
|
};
|
||||||
|
|
||||||
return CompositionPolicy;
|
return CompositionPolicy;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -37,15 +37,13 @@ define(
|
|||||||
* start time (plug-in support means this cannot be determined
|
* start time (plug-in support means this cannot be determined
|
||||||
* prior to that, but we don't want to redo these calculations
|
* prior to that, but we don't want to redo these calculations
|
||||||
* every time policy is checked.)
|
* every time policy is checked.)
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/containment
|
||||||
*/
|
*/
|
||||||
function ContainmentTable(typeService, capabilityService) {
|
function ContainmentTable(typeService, capabilityService) {
|
||||||
var types = typeService.listTypes(),
|
var self = this,
|
||||||
capabilityTable = new CapabilityTable(typeService, capabilityService),
|
types = typeService.listTypes(),
|
||||||
table = {};
|
capabilityTable = new CapabilityTable(typeService, capabilityService);
|
||||||
|
|
||||||
// Check if one type can contain another
|
|
||||||
function canContain(containerType, containedType) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add types which have all these capabilities to the set
|
// Add types which have all these capabilities to the set
|
||||||
// of allowed types
|
// of allowed types
|
||||||
@ -82,38 +80,39 @@ define(
|
|||||||
// Check for defined containment restrictions
|
// Check for defined containment restrictions
|
||||||
if (contains === undefined) {
|
if (contains === undefined) {
|
||||||
// If not, accept anything
|
// If not, accept anything
|
||||||
table[key] = ANY;
|
self.table[key] = ANY;
|
||||||
} else {
|
} else {
|
||||||
// Start with an empty set...
|
// Start with an empty set...
|
||||||
table[key] = {};
|
self.table[key] = {};
|
||||||
// ...cast accepted types to array if necessary...
|
// ...cast accepted types to array if necessary...
|
||||||
contains = Array.isArray(contains) ? contains : [contains];
|
contains = Array.isArray(contains) ? contains : [contains];
|
||||||
// ...and add all containment rules to that set
|
// ...and add all containment rules to that set
|
||||||
contains.forEach(function (c) {
|
contains.forEach(function (c) {
|
||||||
addToSet(table[key], c);
|
addToSet(self.table[key], c);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the table
|
// Build the table
|
||||||
|
this.table = {};
|
||||||
types.forEach(addToTable);
|
types.forEach(addToTable);
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Check if domain objects of one type can contain domain
|
|
||||||
* objects of another type.
|
|
||||||
* @returns {boolean} true if allowable
|
|
||||||
*/
|
|
||||||
canContain: function (containerType, containedType) {
|
|
||||||
var set = table[containerType.getKey()] || {};
|
|
||||||
// Recognize either the symbolic value for "can contain
|
|
||||||
// anything", or lookup the specific type from the set.
|
|
||||||
return (set === ANY) || set[containedType.getKey()];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if domain objects of one type can contain domain
|
||||||
|
* objects of another type.
|
||||||
|
* @param {Type} containerType type of the containing domain object
|
||||||
|
* @param {Type} containedType type of the domain object
|
||||||
|
* to be contained
|
||||||
|
* @returns {boolean} true if allowable
|
||||||
|
*/
|
||||||
|
ContainmentTable.prototype.canContain = function (containerType, containedType) {
|
||||||
|
var set = this.table[containerType.getKey()] || {};
|
||||||
|
// Recognize either the symbolic value for "can contain
|
||||||
|
// anything", or lookup the specific type from the set.
|
||||||
|
return (set === ANY) || set[containedType.getKey()];
|
||||||
|
};
|
||||||
|
|
||||||
return ContainmentTable;
|
return ContainmentTable;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -25,51 +25,102 @@ define(
|
|||||||
function () {
|
function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions are reusable processes/behaviors performed by users within
|
||||||
|
* the system, typically upon domain objects. Actions are commonly
|
||||||
|
* exposed to users as menu items or buttons.
|
||||||
|
*
|
||||||
|
* Actions are usually registered via the `actions` extension
|
||||||
|
* category, or (in advanced cases) via an `actionService`
|
||||||
|
* implementation.
|
||||||
|
*
|
||||||
|
* @interface Action
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the behavior associated with this action. The return type
|
||||||
|
* may vary depending on which action has been performed; in general,
|
||||||
|
* no return value should be expected.
|
||||||
|
*
|
||||||
|
* @method Action#perform
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get metadata associated with this action.
|
||||||
|
*
|
||||||
|
* @method Action#getMetadata
|
||||||
|
* @returns {ActionMetadata}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata associated with an Action. Actions of specific types may
|
||||||
|
* extend this with additional properties.
|
||||||
|
*
|
||||||
|
* @typedef {Object} ActionMetadata
|
||||||
|
* @property {string} key machine-readable identifier for this action
|
||||||
|
* @property {string} name human-readable name for this action
|
||||||
|
* @property {string} description human-readable description
|
||||||
|
* @property {string} glyph character to display as icon
|
||||||
|
* @property {ActionContext} context the context in which the action
|
||||||
|
* will be performed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides actions that can be performed within specific contexts.
|
||||||
|
*
|
||||||
|
* @interface ActionService
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get actions which can be performed within a certain context.
|
||||||
|
*
|
||||||
|
* @method ActionService#getActions
|
||||||
|
* @param {ActionContext} context the context in which the action will
|
||||||
|
* be performed
|
||||||
|
* @return {Action[]} relevant actions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of the context in which an action may occur.
|
||||||
|
*
|
||||||
|
* @typedef ActionContext
|
||||||
|
* @property {DomainObject} [domainObject] the domain object being
|
||||||
|
* acted upon.
|
||||||
|
* @property {DomainObject} [selectedObject] the selection at the
|
||||||
|
* time of action (e.g. the dragged object in a
|
||||||
|
* drag-and-drop operation.)
|
||||||
|
* @property {string} [key] the machine-readable identifier of
|
||||||
|
* the relevant action
|
||||||
|
* @property {string} [category] a string identifying the category
|
||||||
|
* of action being performed
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ActionAggregator makes several actionService
|
* The ActionAggregator makes several actionService
|
||||||
* instances act as those they were one. When requesting
|
* instances act as those they were one. When requesting
|
||||||
* actions for a given context, results from all
|
* actions for a given context, results from all
|
||||||
* services will be assembled and concatenated.
|
* services will be assembled and concatenated.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/core
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {ActionProvider[]} actionProviders an array
|
* @implements {ActionService}
|
||||||
|
* @param {ActionService[]} actionProviders an array
|
||||||
* of action services
|
* of action services
|
||||||
*/
|
*/
|
||||||
function ActionAggregator(actionProviders) {
|
function ActionAggregator(actionProviders) {
|
||||||
|
this.actionProviders = actionProviders;
|
||||||
function getActions(context) {
|
|
||||||
// Get all actions from all providers, reduce down
|
|
||||||
// to one array by concatenation
|
|
||||||
return actionProviders.map(function (provider) {
|
|
||||||
return provider.getActions(context);
|
|
||||||
}).reduce(function (a, b) {
|
|
||||||
return a.concat(b);
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get a list of actions which are valid in a given
|
|
||||||
* context.
|
|
||||||
*
|
|
||||||
* @param {ActionContext} the context in which
|
|
||||||
* the action will occur; this is a
|
|
||||||
* JavaScript object containing key-value
|
|
||||||
* pairs. Typically, this will contain a
|
|
||||||
* field "domainObject" which refers to
|
|
||||||
* the domain object that will be acted
|
|
||||||
* upon, but may contain arbitrary information
|
|
||||||
* recognized by specific providers.
|
|
||||||
* @return {Action[]} an array of actions which
|
|
||||||
* may be performed in the provided context.
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @memberof ActionAggregator
|
|
||||||
*/
|
|
||||||
getActions: getActions
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActionAggregator.prototype.getActions = function (context) {
|
||||||
|
// Get all actions from all providers, reduce down
|
||||||
|
// to one array by concatenation
|
||||||
|
return this.actionProviders.map(function (provider) {
|
||||||
|
return provider.getActions(context);
|
||||||
|
}).reduce(function (a, b) {
|
||||||
|
return a.concat(b);
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
return ActionAggregator;
|
return ActionAggregator;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -45,73 +45,74 @@ define(
|
|||||||
* which the action will be performed (also, the
|
* which the action will be performed (also, the
|
||||||
* action which exposes the capability.)
|
* action which exposes the capability.)
|
||||||
*
|
*
|
||||||
|
* @memberof platform/core
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ActionCapability($q, actionService, domainObject) {
|
function ActionCapability($q, actionService, domainObject) {
|
||||||
|
this.$q = $q;
|
||||||
|
this.actionService = actionService;
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an action. This will find and perform the
|
||||||
|
* first matching action available for the specified
|
||||||
|
* context or key.
|
||||||
|
*
|
||||||
|
* @param {ActionContext|string} context the context in which
|
||||||
|
* to perform the action; this is passed along to
|
||||||
|
* the action service to match against available
|
||||||
|
* actions. The "domainObject" field will automatically
|
||||||
|
* be populated with the domain object that exposed
|
||||||
|
* this capability. If given as a string, this will
|
||||||
|
* be taken as the "key" field to match against
|
||||||
|
* specific actions.
|
||||||
|
* @returns {Promise} the result of the action that was
|
||||||
|
* performed, or undefined if no matching action
|
||||||
|
* was found.
|
||||||
|
* @memberof platform/core.ActionCapability#
|
||||||
|
*/
|
||||||
|
ActionCapability.prototype.getActions = function (context) {
|
||||||
// Get all actions which are valid in this context;
|
// Get all actions which are valid in this context;
|
||||||
// this simply redirects to the action service,
|
// this simply redirects to the action service,
|
||||||
// but additionally adds a domainObject field.
|
// but additionally adds a domainObject field.
|
||||||
function getActions(context) {
|
var baseContext = typeof context === 'string' ?
|
||||||
var baseContext = typeof context === 'string' ?
|
{ key: context } : (context || {}),
|
||||||
{ key: context } :
|
actionContext = Object.create(baseContext);
|
||||||
(context || {}),
|
|
||||||
actionContext = Object.create(baseContext);
|
|
||||||
|
|
||||||
actionContext.domainObject = domainObject;
|
actionContext.domainObject = this.domainObject;
|
||||||
|
|
||||||
return actionService.getActions(actionContext);
|
return this.actionService.getActions(actionContext);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get actions which are available for this domain object,
|
||||||
|
* in this context.
|
||||||
|
*
|
||||||
|
* @param {ActionContext|string} context the context in which
|
||||||
|
* to perform the action; this is passed along to
|
||||||
|
* the action service to match against available
|
||||||
|
* actions. The "domainObject" field will automatically
|
||||||
|
* be populated with the domain object that exposed
|
||||||
|
* this capability. If given as a string, this will
|
||||||
|
* be taken as the "key" field to match against
|
||||||
|
* specific actions.
|
||||||
|
* @returns {Action[]} an array of matching actions
|
||||||
|
* @memberof platform/core.ActionCapability#
|
||||||
|
*/
|
||||||
|
ActionCapability.prototype.perform = function (context) {
|
||||||
// Alias to getActions(context)[0].perform, with a
|
// Alias to getActions(context)[0].perform, with a
|
||||||
// check for empty arrays.
|
// check for empty arrays.
|
||||||
function performAction(context) {
|
var actions = this.getActions(context);
|
||||||
var actions = getActions(context);
|
|
||||||
|
|
||||||
return $q.when(
|
return this.$q.when(
|
||||||
(actions && actions.length > 0) ?
|
(actions && actions.length > 0) ?
|
||||||
actions[0].perform() :
|
actions[0].perform() :
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Perform an action. This will find and perform the
|
|
||||||
* first matching action available for the specified
|
|
||||||
* context or key.
|
|
||||||
*
|
|
||||||
* @param {ActionContext|string} context the context in which
|
|
||||||
* to perform the action; this is passed along to
|
|
||||||
* the action service to match against available
|
|
||||||
* actions. The "domainObject" field will automatically
|
|
||||||
* be populated with the domain object that exposed
|
|
||||||
* this capability. If given as a string, this will
|
|
||||||
* be taken as the "key" field to match against
|
|
||||||
* specific actions.
|
|
||||||
* @returns {Promise} the result of the action that was
|
|
||||||
* performed, or undefined if no matching action
|
|
||||||
* was found.
|
|
||||||
*/
|
|
||||||
perform: performAction,
|
|
||||||
/**
|
|
||||||
* Get actions which are available for this domain object,
|
|
||||||
* in this context.
|
|
||||||
*
|
|
||||||
* @param {ActionContext|string} context the context in which
|
|
||||||
* to perform the action; this is passed along to
|
|
||||||
* the action service to match against available
|
|
||||||
* actions. The "domainObject" field will automatically
|
|
||||||
* be populated with the domain object that exposed
|
|
||||||
* this capability. If given as a string, this will
|
|
||||||
* be taken as the "key" field to match against
|
|
||||||
* specific actions.
|
|
||||||
* @returns {Action[]} an array of matching actions
|
|
||||||
*/
|
|
||||||
getActions: getActions
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ActionCapability;
|
return ActionCapability;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,11 +35,46 @@ define(
|
|||||||
* of actions exposed via extension (specifically, the "actions"
|
* of actions exposed via extension (specifically, the "actions"
|
||||||
* category of extension.)
|
* category of extension.)
|
||||||
*
|
*
|
||||||
|
* @memberof platform/core
|
||||||
|
* @imeplements {ActionService}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ActionProvider(actions) {
|
function ActionProvider(actions) {
|
||||||
var actionsByKey = {},
|
var self = this;
|
||||||
actionsByCategory = {};
|
|
||||||
|
// Build up look-up tables
|
||||||
|
this.actions = actions;
|
||||||
|
this.actionsByKey = {};
|
||||||
|
this.actionsByCategory = {};
|
||||||
|
actions.forEach(function (Action) {
|
||||||
|
// Get an action's category or categories
|
||||||
|
var categories = Action.category || [];
|
||||||
|
|
||||||
|
// Convert to an array if necessary
|
||||||
|
categories = Array.isArray(categories) ?
|
||||||
|
categories : [categories];
|
||||||
|
|
||||||
|
// Store action under all relevant categories
|
||||||
|
categories.forEach(function (category) {
|
||||||
|
self.actionsByCategory[category] =
|
||||||
|
self.actionsByCategory[category] || [];
|
||||||
|
self.actionsByCategory[category].push(Action);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store action by ekey as well
|
||||||
|
if (Action.key) {
|
||||||
|
self.actionsByKey[Action.key] =
|
||||||
|
self.actionsByKey[Action.key] || [];
|
||||||
|
self.actionsByKey[Action.key].push(Action);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionProvider.prototype.getActions = function (actionContext) {
|
||||||
|
var context = (actionContext || {}),
|
||||||
|
category = context.category,
|
||||||
|
key = context.key,
|
||||||
|
candidates;
|
||||||
|
|
||||||
// Instantiate an action; invokes the constructor and
|
// Instantiate an action; invokes the constructor and
|
||||||
// additionally fills in the action's getMetadata method
|
// additionally fills in the action's getMetadata method
|
||||||
@ -70,86 +105,32 @@ define(
|
|||||||
function createIfApplicable(actions, context) {
|
function createIfApplicable(actions, context) {
|
||||||
return (actions || []).filter(function (Action) {
|
return (actions || []).filter(function (Action) {
|
||||||
return Action.appliesTo ?
|
return Action.appliesTo ?
|
||||||
Action.appliesTo(context) : true;
|
Action.appliesTo(context) : true;
|
||||||
}).map(function (Action) {
|
}).map(function (Action) {
|
||||||
return instantiateAction(Action, context);
|
return instantiateAction(Action, context);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get an array of actions that are valid in the supplied context.
|
// Match actions to the provided context by comparing "key"
|
||||||
function getActions(actionContext) {
|
// and/or "category" parameters, if specified.
|
||||||
var context = (actionContext || {}),
|
candidates = this.actions;
|
||||||
category = context.category,
|
if (key) {
|
||||||
key = context.key,
|
candidates = this.actionsByKey[key];
|
||||||
candidates;
|
if (category) {
|
||||||
|
candidates = candidates.filter(function (Action) {
|
||||||
// Match actions to the provided context by comparing "key"
|
return Action.category === category;
|
||||||
// and/or "category" parameters, if specified.
|
});
|
||||||
candidates = actions;
|
|
||||||
if (key) {
|
|
||||||
candidates = actionsByKey[key];
|
|
||||||
if (category) {
|
|
||||||
candidates = candidates.filter(function (Action) {
|
|
||||||
return Action.category === category;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (category) {
|
|
||||||
candidates = actionsByCategory[category];
|
|
||||||
}
|
}
|
||||||
|
} else if (category) {
|
||||||
// Instantiate those remaining actions, with additional
|
candidates = this.actionsByCategory[category];
|
||||||
// filtering per any appliesTo methods defined on those
|
|
||||||
// actions.
|
|
||||||
return createIfApplicable(candidates, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build up look-up tables
|
// Instantiate those remaining actions, with additional
|
||||||
actions.forEach(function (Action) {
|
// filtering per any appliesTo methods defined on those
|
||||||
// Get an action's category or categories
|
// actions.
|
||||||
var categories = Action.category || [];
|
return createIfApplicable(candidates, context);
|
||||||
|
};
|
||||||
// Convert to an array if necessary
|
|
||||||
categories = Array.isArray(categories) ?
|
|
||||||
categories : [categories];
|
|
||||||
|
|
||||||
// Store action under all relevant categories
|
|
||||||
categories.forEach(function (category) {
|
|
||||||
actionsByCategory[category] =
|
|
||||||
actionsByCategory[category] || [];
|
|
||||||
actionsByCategory[category].push(Action);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Store action by ekey as well
|
|
||||||
if (Action.key) {
|
|
||||||
actionsByKey[Action.key] =
|
|
||||||
actionsByKey[Action.key] || [];
|
|
||||||
actionsByKey[Action.key].push(Action);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Get a list of actions which are valid in a given
|
|
||||||
* context.
|
|
||||||
*
|
|
||||||
* @param {ActionContext} the context in which
|
|
||||||
* the action will occur; this is a
|
|
||||||
* JavaScript object containing key-value
|
|
||||||
* pairs. Typically, this will contain a
|
|
||||||
* field "domainObject" which refers to
|
|
||||||
* the domain object that will be acted
|
|
||||||
* upon, but may contain arbitrary information
|
|
||||||
* recognized by specific providers.
|
|
||||||
* @return {Action[]} an array of actions which
|
|
||||||
* may be performed in the provided context.
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @memberof ActionProvider
|
|
||||||
*/
|
|
||||||
getActions: getActions
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ActionProvider;
|
return ActionProvider;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -34,9 +34,21 @@ define(
|
|||||||
* the actions it exposes always emit a log message when they are
|
* the actions it exposes always emit a log message when they are
|
||||||
* performed.
|
* performed.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/core
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {ActionService}
|
||||||
|
* @param $log Angular's logging service
|
||||||
|
* @param {ActionService} actionService the decorated action service
|
||||||
*/
|
*/
|
||||||
function LoggingActionDecorator($log, actionService) {
|
function LoggingActionDecorator($log, actionService) {
|
||||||
|
this.$log = $log;
|
||||||
|
this.actionService = actionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoggingActionDecorator.prototype.getActions = function () {
|
||||||
|
var actionService = this.actionService,
|
||||||
|
$log = this.$log;
|
||||||
|
|
||||||
// Decorate the perform method of the specified action, such that
|
// Decorate the perform method of the specified action, such that
|
||||||
// it emits a log message whenever performed.
|
// it emits a log message whenever performed.
|
||||||
function addLogging(action) {
|
function addLogging(action) {
|
||||||
@ -58,35 +70,12 @@ define(
|
|||||||
return logAction;
|
return logAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return actionService.getActions.apply(
|
||||||
/**
|
actionService,
|
||||||
* Get a list of actions which are valid in a given
|
arguments
|
||||||
* context. These actions will additionally log
|
).map(addLogging);
|
||||||
* themselves when performed.
|
};
|
||||||
*
|
|
||||||
* @param {ActionContext} the context in which
|
|
||||||
* the action will occur; this is a
|
|
||||||
* JavaScript object containing key-value
|
|
||||||
* pairs. Typically, this will contain a
|
|
||||||
* field "domainObject" which refers to
|
|
||||||
* the domain object that will be acted
|
|
||||||
* upon, but may contain arbitrary information
|
|
||||||
* recognized by specific providers.
|
|
||||||
* @return {Action[]} an array of actions which
|
|
||||||
* may be performed in the provided context.
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @memberof LoggingActionDecorator
|
|
||||||
*/
|
|
||||||
getActions: function () {
|
|
||||||
return actionService.getActions.apply(
|
|
||||||
actionService,
|
|
||||||
arguments
|
|
||||||
).map(addLogging);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return LoggingActionDecorator;
|
return LoggingActionDecorator;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -37,68 +37,61 @@ define(
|
|||||||
* require consulting the object service (e.g. to trigger a database
|
* require consulting the object service (e.g. to trigger a database
|
||||||
* query to retrieve the nested object models.)
|
* query to retrieve the nested object models.)
|
||||||
*
|
*
|
||||||
|
* @memberof platform/core
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Capability}
|
||||||
*/
|
*/
|
||||||
function CompositionCapability($injector, domainObject) {
|
function CompositionCapability($injector, domainObject) {
|
||||||
var objectService,
|
|
||||||
lastPromise,
|
|
||||||
lastModified;
|
|
||||||
|
|
||||||
// Get a reference to the object service from $injector
|
// Get a reference to the object service from $injector
|
||||||
function injectObjectService() {
|
this.injectObjectService = function () {
|
||||||
objectService = $injector.get("objectService");
|
this.objectService = $injector.get("objectService");
|
||||||
return objectService;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a reference to the object service (either cached or
|
|
||||||
// from the injector)
|
|
||||||
function getObjectService() {
|
|
||||||
return objectService || injectObjectService();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Promise this domain object's composition (an array of domain
|
|
||||||
// object instances corresponding to ids in its model.)
|
|
||||||
function promiseComposition() {
|
|
||||||
var model = domainObject.getModel(),
|
|
||||||
ids;
|
|
||||||
|
|
||||||
// Then filter out non-existent objects,
|
|
||||||
// and wrap others (such that they expose a
|
|
||||||
// "context" capability)
|
|
||||||
function contextualize(objects) {
|
|
||||||
return ids.filter(function (id) {
|
|
||||||
return objects[id];
|
|
||||||
}).map(function (id) {
|
|
||||||
return new ContextualDomainObject(
|
|
||||||
objects[id],
|
|
||||||
domainObject
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a new request if we haven't made one, or if the
|
|
||||||
// object has been modified.
|
|
||||||
if (!lastPromise || lastModified !== model.modified) {
|
|
||||||
ids = model.composition || [];
|
|
||||||
lastModified = model.modified;
|
|
||||||
// Load from the underlying object service
|
|
||||||
lastPromise = getObjectService().getObjects(ids)
|
|
||||||
.then(contextualize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Request the composition of this object.
|
|
||||||
* @returns {Promise.<DomainObject[]>} a list of all domain
|
|
||||||
* objects which compose this domain object.
|
|
||||||
*/
|
|
||||||
invoke: promiseComposition
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.domainObject = domainObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the composition of this object.
|
||||||
|
* @returns {Promise.<DomainObject[]>} a list of all domain
|
||||||
|
* objects which compose this domain object.
|
||||||
|
*/
|
||||||
|
CompositionCapability.prototype.invoke = function () {
|
||||||
|
var domainObject = this.domainObject,
|
||||||
|
model = domainObject.getModel(),
|
||||||
|
ids;
|
||||||
|
|
||||||
|
// Then filter out non-existent objects,
|
||||||
|
// and wrap others (such that they expose a
|
||||||
|
// "context" capability)
|
||||||
|
function contextualize(objects) {
|
||||||
|
return ids.filter(function (id) {
|
||||||
|
return objects[id];
|
||||||
|
}).map(function (id) {
|
||||||
|
return new ContextualDomainObject(
|
||||||
|
objects[id],
|
||||||
|
domainObject
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lazily acquire object service (avoids cyclical dependency)
|
||||||
|
if (!this.objectService) {
|
||||||
|
this.injectObjectService();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a new request if we haven't made one, or if the
|
||||||
|
// object has been modified.
|
||||||
|
if (!this.lastPromise || this.lastModified !== model.modified) {
|
||||||
|
ids = model.composition || [];
|
||||||
|
this.lastModified = model.modified;
|
||||||
|
// Load from the underlying object service
|
||||||
|
this.lastPromise = this.objectService.getObjects(ids)
|
||||||
|
.then(contextualize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.lastPromise;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to determine whether or not this capability should be exposed
|
* Test to determine whether or not this capability should be exposed
|
||||||
* by a domain object based on its model. Checks for the presence of
|
* by a domain object based on its model. Checks for the presence of
|
||||||
@ -112,4 +105,4 @@ define(
|
|||||||
|
|
||||||
return CompositionCapability;
|
return CompositionCapability;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -36,77 +36,78 @@ define(
|
|||||||
* those whose `composition` capability was used to access this
|
* those whose `composition` capability was used to access this
|
||||||
* object.)
|
* object.)
|
||||||
*
|
*
|
||||||
|
* @memberof platform/core
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Capability}
|
||||||
*/
|
*/
|
||||||
function ContextCapability(parentObject, domainObject) {
|
function ContextCapability(parentObject, domainObject) {
|
||||||
return {
|
this.parentObject = parentObject;
|
||||||
/**
|
this.domainObject = domainObject;
|
||||||
* Get the immediate parent of a domain object.
|
|
||||||
*
|
|
||||||
* A domain object may be contained in multiple places; its
|
|
||||||
* parent (as exposed by this capability) is the domain
|
|
||||||
* object from which this object was accessed, usually
|
|
||||||
* by way of a `composition` capability.
|
|
||||||
*
|
|
||||||
* @returns {DomainObject} the immediate parent of this
|
|
||||||
* domain object.
|
|
||||||
*/
|
|
||||||
getParent: function () {
|
|
||||||
return parentObject;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get an array containing the complete direct ancestry
|
|
||||||
* of this domain object, including the domain object
|
|
||||||
* itself.
|
|
||||||
*
|
|
||||||
* A domain object may be contained in multiple places; its
|
|
||||||
* parent and all ancestors (as exposed by this capability)
|
|
||||||
* serve as a record of how this specific domain object
|
|
||||||
* instance was reached.
|
|
||||||
*
|
|
||||||
* The first element in the returned array is the deepest
|
|
||||||
* ancestor; subsequent elements are progressively more
|
|
||||||
* recent ancestors, with the domain object which exposed
|
|
||||||
* the capability occupying the last element of the array.
|
|
||||||
*
|
|
||||||
* @returns {DomainObject[]} the full composition ancestry
|
|
||||||
* of the domain object which exposed this
|
|
||||||
* capability.
|
|
||||||
*/
|
|
||||||
getPath: function () {
|
|
||||||
var parentPath = [],
|
|
||||||
parentContext;
|
|
||||||
|
|
||||||
if (parentObject) {
|
|
||||||
parentContext = parentObject.getCapability("context");
|
|
||||||
parentPath = parentContext ?
|
|
||||||
parentContext.getPath() :
|
|
||||||
[parentObject];
|
|
||||||
}
|
|
||||||
|
|
||||||
return parentPath.concat([domainObject]);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get the deepest ancestor available for this domain object;
|
|
||||||
* equivalent to `getPath()[0]`.
|
|
||||||
*
|
|
||||||
* See notes on `getPath()` for how ancestry is defined in
|
|
||||||
* the context of this capability.
|
|
||||||
*
|
|
||||||
* @returns {DomainObject} the deepest ancestor of the domain
|
|
||||||
* object which exposed this capability.
|
|
||||||
*/
|
|
||||||
getRoot: function () {
|
|
||||||
var parentContext = parentObject &&
|
|
||||||
parentObject.getCapability('context');
|
|
||||||
|
|
||||||
return parentContext ?
|
|
||||||
parentContext.getRoot() :
|
|
||||||
(parentObject || domainObject);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the immediate parent of a domain object.
|
||||||
|
*
|
||||||
|
* A domain object may be contained in multiple places; its
|
||||||
|
* parent (as exposed by this capability) is the domain
|
||||||
|
* object from which this object was accessed, usually
|
||||||
|
* by way of a `composition` capability.
|
||||||
|
*
|
||||||
|
* @returns {DomainObject} the immediate parent of this
|
||||||
|
* domain object.
|
||||||
|
*/
|
||||||
|
ContextCapability.prototype.getParent = function () {
|
||||||
|
return this.parentObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array containing the complete direct ancestry
|
||||||
|
* of this domain object, including the domain object
|
||||||
|
* itself.
|
||||||
|
*
|
||||||
|
* A domain object may be contained in multiple places; its
|
||||||
|
* parent and all ancestors (as exposed by this capability)
|
||||||
|
* serve as a record of how this specific domain object
|
||||||
|
* instance was reached.
|
||||||
|
*
|
||||||
|
* The first element in the returned array is the deepest
|
||||||
|
* ancestor; subsequent elements are progressively more
|
||||||
|
* recent ancestors, with the domain object which exposed
|
||||||
|
* the capability occupying the last element of the array.
|
||||||
|
*
|
||||||
|
* @returns {DomainObject[]} the full composition ancestry
|
||||||
|
* of the domain object which exposed this
|
||||||
|
* capability.
|
||||||
|
*/
|
||||||
|
ContextCapability.prototype.getPath = function () {
|
||||||
|
var parentObject = this.parentObject,
|
||||||
|
parentContext =
|
||||||
|
parentObject && parentObject.getCapability('context'),
|
||||||
|
parentPath = parentContext ?
|
||||||
|
parentContext.getPath() : [ this.parentObject ];
|
||||||
|
|
||||||
|
return parentPath.concat([this.domainObject]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the deepest ancestor available for this domain object;
|
||||||
|
* equivalent to `getPath()[0]`.
|
||||||
|
*
|
||||||
|
* See notes on `getPath()` for how ancestry is defined in
|
||||||
|
* the context of this capability.
|
||||||
|
*
|
||||||
|
* @returns {DomainObject} the deepest ancestor of the domain
|
||||||
|
* object which exposed this capability.
|
||||||
|
*/
|
||||||
|
ContextCapability.prototype.getRoot = function () {
|
||||||
|
var parentContext = this.parentObject &&
|
||||||
|
this.parentObject.getCapability('context');
|
||||||
|
|
||||||
|
return parentContext ?
|
||||||
|
parentContext.getRoot() :
|
||||||
|
(this.parentObject || this.domainObject);
|
||||||
|
};
|
||||||
|
|
||||||
return ContextCapability;
|
return ContextCapability;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -42,7 +42,9 @@ define(
|
|||||||
* @param {DomainObject} parentObject the domain object from which
|
* @param {DomainObject} parentObject the domain object from which
|
||||||
* the wrapped object was retrieved
|
* the wrapped object was retrieved
|
||||||
*
|
*
|
||||||
|
* @memberof platform/core
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {DomainObject}
|
||||||
*/
|
*/
|
||||||
function ContextualDomainObject(domainObject, parentObject) {
|
function ContextualDomainObject(domainObject, parentObject) {
|
||||||
// Prototypally inherit from the domain object, and
|
// Prototypally inherit from the domain object, and
|
||||||
@ -63,4 +65,4 @@ define(
|
|||||||
|
|
||||||
return ContextualDomainObject;
|
return ContextualDomainObject;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -29,6 +29,19 @@ define(
|
|||||||
function () {
|
function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A capability provides an interface with dealing with some
|
||||||
|
* dynamic behavior associated with a domain object.
|
||||||
|
* @interface Capability
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional; if present, will be used by `DomainObject#useCapability`
|
||||||
|
* to simplify interaction with a specific capability. Parameters
|
||||||
|
* and return values vary depending on capability type.
|
||||||
|
* @method Capability#invoke
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides capabilities based on extension definitions,
|
* Provides capabilities based on extension definitions,
|
||||||
* matched to domain object models.
|
* matched to domain object models.
|
||||||
@ -37,6 +50,7 @@ define(
|
|||||||
* of constructor functions for capabilities, as
|
* of constructor functions for capabilities, as
|
||||||
* exposed by extensions defined at the bundle level.
|
* exposed by extensions defined at the bundle level.
|
||||||
*
|
*
|
||||||
|
* @memberof platform/core
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CoreCapabilityProvider(capabilities, $log) {
|
function CoreCapabilityProvider(capabilities, $log) {
|
||||||
@ -84,6 +98,7 @@ define(
|
|||||||
* @returns {Object.<string,function|Capability>} all
|
* @returns {Object.<string,function|Capability>} all
|
||||||
* capabilities known to be valid for this model, as
|
* capabilities known to be valid for this model, as
|
||||||
* key-value pairs
|
* key-value pairs
|
||||||
|
* @memberof platform/core.CoreCapabilityProvider#
|
||||||
*/
|
*/
|
||||||
getCapabilities: getCapabilities
|
getCapabilities: getCapabilities
|
||||||
};
|
};
|
||||||
@ -92,3 +107,4 @@ define(
|
|||||||
return CoreCapabilityProvider;
|
return CoreCapabilityProvider;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user