mirror of
https://github.com/nasa/openmct.git
synced 2024-12-20 13:43:09 +00:00
[Mobile] Merge
Merged with master and resolved conflicts.
This commit is contained in:
commit
cd46dab5c1
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": {
|
||||
"include": [
|
||||
"example/",
|
||||
"platform/"
|
||||
],
|
||||
"includePattern": "(example|platform)/.+\\.js$",
|
||||
"includePattern": "platform/.+\\.js$",
|
||||
"excludePattern": ".+\\Spec\\.js$|lib/.+"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugins": [
|
||||
"plugins/markdown"
|
||||
]
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
"start": "node app.js",
|
||||
"test": "karma start --single-run",
|
||||
"jshint": "jshint platform example || exit 0",
|
||||
"watch": "karma start",
|
||||
"jsdoc": "jsdoc -c jsdoc.json -r -d target/docs/api",
|
||||
"otherdoc": "node docs/gendocs.js --in docs/src --out target/docs",
|
||||
"docs": "npm run jsdoc ; npm run otherdoc"
|
||||
|
@ -21,6 +21,11 @@
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
|
||||
/**
|
||||
* Implements Open MCT Web's About dialog.
|
||||
* @namespace platform/commonUI/about
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
@ -29,35 +34,36 @@ define(
|
||||
/**
|
||||
* The AboutController provides information to populate the
|
||||
* About dialog.
|
||||
* @memberof platform/commonUI/about
|
||||
* @constructor
|
||||
* @param {object[]} versions an array of version extensions;
|
||||
* injected from `versions[]`
|
||||
* @param $window Angular-injected window object
|
||||
*/
|
||||
function AboutController(versions, $window) {
|
||||
return {
|
||||
/**
|
||||
* 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");
|
||||
}
|
||||
};
|
||||
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.
|
||||
* @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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -29,20 +29,22 @@ define(
|
||||
/**
|
||||
* Provides extension-introduced licenses information to the
|
||||
* licenses route.
|
||||
* @memberof platform/commonUI/about
|
||||
* @constructor
|
||||
*/
|
||||
function LicenseController(licenses) {
|
||||
return {
|
||||
/**
|
||||
* Get license information.
|
||||
* @returns {Array} license extensions
|
||||
*/
|
||||
licenses: function () {
|
||||
return licenses;
|
||||
}
|
||||
};
|
||||
this.licenseDefinitions = licenses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get license information.
|
||||
* @returns {Array} license extensions
|
||||
* @memberof platform/commonUI/about.LicenseController#
|
||||
*/
|
||||
LicenseController.prototype.licenses = function () {
|
||||
return this.licenseDefinitions;
|
||||
};
|
||||
|
||||
return LicenseController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -29,21 +29,23 @@ define(
|
||||
/**
|
||||
* The LogoController provides functionality to the application
|
||||
* logo in the bottom-right of the user interface.
|
||||
* @memberof platform/commonUI/about
|
||||
* @constructor
|
||||
* @param {OverlayService} overlayService the overlay service
|
||||
*/
|
||||
function LogoController(overlayService) {
|
||||
return {
|
||||
/**
|
||||
* Display the About dialog.
|
||||
* @memberof LogoController#
|
||||
*/
|
||||
showAboutDialog: function () {
|
||||
overlayService.createOverlay("overlay-about");
|
||||
}
|
||||
};
|
||||
this.overlayService = overlayService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the About dialog.
|
||||
* @memberof LogoController#
|
||||
* @memberof platform/commonUI/about.LogoController#
|
||||
*/
|
||||
LogoController.prototype.showAboutDialog = function () {
|
||||
this.overlayService.createOverlay("overlay-about");
|
||||
};
|
||||
|
||||
return LogoController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -69,8 +69,8 @@
|
||||
{
|
||||
"key": "grid-item",
|
||||
"templateUrl": "templates/items/grid-item.html",
|
||||
"uses": [ "type", "action" ],
|
||||
"gestures": [ "info","menu" ]
|
||||
"uses": [ "type", "action", "location" ],
|
||||
"gestures": [ "info", "menu" ]
|
||||
},
|
||||
{
|
||||
"key": "object-header",
|
||||
@ -93,12 +93,12 @@
|
||||
{
|
||||
"key": "navigationService",
|
||||
"implementation": "navigation/NavigationService.js"
|
||||
},
|
||||
},
|
||||
{
|
||||
"key": "creationService",
|
||||
"implementation": "creation/CreationService.js",
|
||||
"depends": [ "persistenceService", "$q", "$log" ]
|
||||
}
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
|
@ -32,7 +32,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class='item-main abs'>
|
||||
<div class='ui-symbol icon lg abs item-type'>{{type.getGlyph()}}</div>
|
||||
<div class='ui-symbol icon lg item-type'>
|
||||
{{type.getGlyph()}}
|
||||
<span
|
||||
class="ui-symbol icon l-icon-link" title="This object is a link"
|
||||
ng-show="location.isLink()"
|
||||
></span>
|
||||
</div>
|
||||
<div class='ui-symbol icon abs item-open'>}</div>
|
||||
</div>
|
||||
<div class='bottom-bar bar abs'>
|
||||
|
@ -22,7 +22,8 @@
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining BrowseController. Created by vwoeltje on 11/7/14.
|
||||
* This bundle implements Browse mode.
|
||||
* @namespace platform/commonUI/browse
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
@ -39,6 +40,7 @@ define(
|
||||
* which Angular templates first have access to the domain object
|
||||
* hierarchy.
|
||||
*
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function BrowseController($scope, $route, $location, objectService, navigationService, urlService) {
|
||||
@ -202,3 +204,4 @@ define(
|
||||
return BrowseController;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -29,6 +29,7 @@ define(
|
||||
/**
|
||||
* Controller for the `browse-object` representation of a domain
|
||||
* object (the right-hand side of Browse mode.)
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function BrowseObjectController($scope, $location, $route) {
|
||||
@ -71,3 +72,4 @@ define(
|
||||
return BrowseObjectController;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -33,19 +33,29 @@ define(
|
||||
* A left-click on the menu arrow should display a
|
||||
* context menu. This controller launches the context
|
||||
* menu.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function MenuArrowController($scope) {
|
||||
function showMenu(event) {
|
||||
var actionContext = {key: 'menu', domainObject: $scope.domainObject, event: event};
|
||||
$scope.domainObject.getCapability('action').perform(actionContext);
|
||||
}
|
||||
|
||||
return {
|
||||
showMenu: showMenu
|
||||
};
|
||||
this.$scope = $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -34,7 +34,10 @@ define(
|
||||
* domain objects of a specific type. This is the action that
|
||||
* is performed when a user uses the Create menu.
|
||||
*
|
||||
* @memberof platform/commonUI/browse
|
||||
* @implements {Action}
|
||||
* @constructor
|
||||
*
|
||||
* @param {Type} type the type of domain object to create
|
||||
* @param {DomainObject} parent the domain object that should
|
||||
* act as a container for the newly-created object
|
||||
@ -49,78 +52,84 @@ define(
|
||||
* of the newly-created domain object
|
||||
*/
|
||||
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:
|
||||
|
||||
1. Show dialog
|
||||
a. Prepare dialog contents
|
||||
b. Invoke dialogService
|
||||
a. Prepare dialog contents
|
||||
b. Invoke dialogService
|
||||
2. Create new object in persistence service
|
||||
a. Generate UUID
|
||||
b. Store model
|
||||
a. Generate UUID
|
||||
b. Store model
|
||||
3. Mutate destination container
|
||||
a. Get mutation capability
|
||||
b. Add new id to composition
|
||||
a. Get mutation capability
|
||||
b. Add new id to composition
|
||||
4. Persist destination container
|
||||
a. ...use persistence capability.
|
||||
a. ...use persistence capability.
|
||||
*/
|
||||
|
||||
function perform() {
|
||||
// The wizard will handle creating the form model based
|
||||
// on the type...
|
||||
var wizard = new CreateWizard(type, parent, policyService);
|
||||
// The wizard will handle creating the form model based
|
||||
// on the type...
|
||||
var wizard =
|
||||
new CreateWizard(this.type, this.parent, this.policyService),
|
||||
self = this;
|
||||
|
||||
// Create and persist the new object, based on user
|
||||
// input.
|
||||
function persistResult(formValue) {
|
||||
var parent = wizard.getLocation(formValue),
|
||||
newModel = wizard.createModel(formValue);
|
||||
return creationService.createObject(newModel, parent);
|
||||
}
|
||||
|
||||
function doNothing() {
|
||||
// Create cancelled, do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
return dialogService.getUserInput(
|
||||
wizard.getFormStructure(),
|
||||
wizard.getInitialFormValue()
|
||||
).then(persistResult, doNothing);
|
||||
// Create and persist the new object, based on user
|
||||
// input.
|
||||
function persistResult(formValue) {
|
||||
var parent = wizard.getLocation(formValue),
|
||||
newModel = wizard.createModel(formValue);
|
||||
return self.creationService.createObject(newModel, parent);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Create a new object of the given type.
|
||||
* This will prompt for user input first.
|
||||
* @method
|
||||
* @memberof CreateAction
|
||||
*/
|
||||
perform: perform,
|
||||
function doNothing() {
|
||||
// Create cancelled, do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata about this action. This includes fields:
|
||||
* * `name`: Human-readable name
|
||||
* * `key`: Machine-readable identifier ("create")
|
||||
* * `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
|
||||
*/
|
||||
getMetadata: function () {
|
||||
return {
|
||||
key: 'create',
|
||||
glyph: type.getGlyph(),
|
||||
name: type.getName(),
|
||||
type: type.getKey(),
|
||||
description: type.getDescription(),
|
||||
context: context
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
return this.dialogService.getUserInput(
|
||||
wizard.getFormStructure(),
|
||||
wizard.getInitialFormValue()
|
||||
).then(persistResult, doNothing);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Metadata associated with a Create action.
|
||||
* @typedef {ActionMetadata} CreateActionMetadata
|
||||
* @property {string} type the key for the type of domain object
|
||||
* to be created
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get metadata about this action.
|
||||
* @returns {CreateActionMetadata} metadata about this action
|
||||
*/
|
||||
CreateAction.prototype.getMetadata = function () {
|
||||
return this.metadata;
|
||||
};
|
||||
|
||||
return CreateAction;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -33,7 +33,10 @@ define(
|
||||
* The CreateActionProvider is an ActionProvider which introduces
|
||||
* a Create action for each creatable domain object type.
|
||||
*
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
* @implements {ActionService}
|
||||
*
|
||||
* @param {TypeService} typeService the type service, used to discover
|
||||
* available types
|
||||
* @param {DialogService} dialogService the dialog service, used by
|
||||
@ -44,44 +47,41 @@ define(
|
||||
* object creation.
|
||||
*/
|
||||
function CreateActionProvider(typeService, dialogService, creationService, policyService) {
|
||||
return {
|
||||
/**
|
||||
* Get all Create actions which are applicable in the provided
|
||||
* context.
|
||||
* @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
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
this.typeService = typeService;
|
||||
this.dialogService = dialogService;
|
||||
this.creationService = creationService;
|
||||
this.policyService = 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -34,6 +34,7 @@ define(
|
||||
* set of Create actions based on the currently-selected
|
||||
* domain object.
|
||||
*
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function CreateMenuController($scope) {
|
||||
@ -55,4 +56,4 @@ define(
|
||||
|
||||
return CreateMenuController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -21,12 +21,6 @@
|
||||
*****************************************************************************/
|
||||
/*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(
|
||||
function () {
|
||||
'use strict';
|
||||
@ -37,113 +31,118 @@ define(
|
||||
* @param {TypeImpl} type the type of domain object to be created
|
||||
* @param {DomainObject} parent the domain object to serve as
|
||||
* the initial parent for the created object, in the dialog
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
* @memberof module:core/action/create-wizard
|
||||
*/
|
||||
function CreateWizard(type, parent, policyService) {
|
||||
var model = type.getInitialModel(),
|
||||
properties = type.getProperties();
|
||||
this.type = type;
|
||||
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) {
|
||||
var locatingType = locatingObject &&
|
||||
locatingObject.getCapability('type');
|
||||
locatingObject.getCapability('type');
|
||||
return locatingType && policyService.allow(
|
||||
"composition",
|
||||
locatingType,
|
||||
type
|
||||
);
|
||||
"composition",
|
||||
locatingType,
|
||||
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 {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
sections: sections,
|
||||
name: "Create a New " + this.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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -39,15 +39,45 @@ define(
|
||||
* persisting new domain objects. Handles all actual object
|
||||
* mutation and persistence associated with domain object
|
||||
* creation.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
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
|
||||
// constituted as a domain object when loaded back, as all
|
||||
// domain object models are.
|
||||
function doPersist(space, id, model) {
|
||||
return persistenceService.createObject(
|
||||
return self.persistenceService.createObject(
|
||||
space,
|
||||
id,
|
||||
model
|
||||
@ -66,14 +96,14 @@ define(
|
||||
}
|
||||
} else {
|
||||
// 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 $q.when(mutatationResult).then(function (result) {
|
||||
return self.$q.when(mutatationResult).then(function (result) {
|
||||
if (!result) {
|
||||
$log.error("Could not mutate " + parent.getId());
|
||||
self.$log.error("Could not mutate " + parent.getId());
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -93,49 +123,28 @@ define(
|
||||
});
|
||||
}
|
||||
|
||||
// Create a new domain object with the provided model as a
|
||||
// member of the specified parent's composition
|
||||
function createObject(model, parent) {
|
||||
var persistence = parent.getCapability("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) {
|
||||
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) {
|
||||
self.$log.warn(NON_PERSISTENT_WARNING);
|
||||
return self.$q.reject(new Error(NON_PERSISTENT_WARNING));
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
// 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 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);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
return CreationService;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -30,6 +30,7 @@ define(
|
||||
* Controller for the "locator" control, which provides the
|
||||
* user with the ability to select a domain object as the
|
||||
* destination for a newly-created object in the Create menu.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function LocatorController($scope) {
|
||||
@ -79,3 +80,4 @@ define(
|
||||
return LocatorController;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -31,32 +31,34 @@ define(
|
||||
|
||||
/**
|
||||
* The navigate action navigates to a specific domain object.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
*/
|
||||
function NavigateAction(navigationService, $q, context) {
|
||||
var domainObject = context.domainObject;
|
||||
|
||||
function perform() {
|
||||
// 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
|
||||
};
|
||||
this.domainObject = context.domainObject;
|
||||
this.$q = $q;
|
||||
this.navigationService = navigationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* is described in the action context.
|
||||
* @param {ActionContext} context the context in which the action
|
||||
* will be performed
|
||||
* @returns true if applicable
|
||||
* @returns {boolean} true if applicable
|
||||
*/
|
||||
NavigateAction.appliesTo = function (context) {
|
||||
return context.domainObject !== undefined;
|
||||
@ -64,4 +66,4 @@ define(
|
||||
|
||||
return NavigateAction;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -32,68 +32,58 @@ define(
|
||||
/**
|
||||
* The navigation service maintains the application's current
|
||||
* navigation state, and allows listening for changes thereto.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function NavigationService() {
|
||||
var navigated,
|
||||
callbacks = [];
|
||||
this.navigated = undefined;
|
||||
this.callbacks = [];
|
||||
}
|
||||
|
||||
// Getter for current navigation
|
||||
function getNavigation() {
|
||||
return navigated;
|
||||
}
|
||||
/**
|
||||
* Get the current navigation state.
|
||||
* @returns {DomainObject} the object that is navigated-to
|
||||
*/
|
||||
NavigationService.prototype.getNavigation = function () {
|
||||
return this.navigated;
|
||||
};
|
||||
|
||||
// Setter for navigation; invokes callbacks
|
||||
function setNavigation(value) {
|
||||
if (navigated !== value) {
|
||||
navigated = value;
|
||||
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;
|
||||
/**
|
||||
* Set the current navigation state. This will invoke listeners.
|
||||
* @param {DomainObject} domainObject the domain object to navigate to
|
||||
*/
|
||||
NavigationService.prototype.setNavigation = function (value) {
|
||||
if (this.navigated !== value) {
|
||||
this.navigated = value;
|
||||
this.callbacks.forEach(function (callback) {
|
||||
callback(value);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get the current navigation state.
|
||||
*/
|
||||
getNavigation: getNavigation,
|
||||
/**
|
||||
* Set the current navigation state. Thiswill invoke listeners.
|
||||
* @param {DomainObject} value the domain object to navigate
|
||||
* to
|
||||
*/
|
||||
setNavigation: setNavigation,
|
||||
/**
|
||||
* Listen for changes in navigation. The passed callback will
|
||||
* be invoked with the new domain object of navigation when
|
||||
* this changes.
|
||||
* @param {function} callback the callback to invoke when
|
||||
* navigation state changes
|
||||
*/
|
||||
addListener: addListener,
|
||||
/**
|
||||
* Stop listening for changes in navigation state.
|
||||
* @param {function} callback the callback which should
|
||||
* no longer be invoked when navigation state
|
||||
* changes
|
||||
*/
|
||||
removeListener: removeListener
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Listen for changes in navigation. The passed callback will
|
||||
* be invoked with the new domain object of navigation when
|
||||
* this changes.
|
||||
* @param {function} callback the callback to invoke when
|
||||
* navigation state changes
|
||||
*/
|
||||
NavigationService.prototype.addListener = function (callback) {
|
||||
this.callbacks.push(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop listening for changes in navigation state.
|
||||
* @param {function} callback the callback which should
|
||||
* no longer be invoked when navigation state
|
||||
* changes
|
||||
*/
|
||||
NavigationService.prototype.removeListener = function (callback) {
|
||||
this.callbacks = this.callbacks.filter(function (cb) {
|
||||
return cb !== callback;
|
||||
});
|
||||
};
|
||||
|
||||
return NavigationService;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -35,36 +35,32 @@ define(
|
||||
/**
|
||||
* The fullscreen action toggles between fullscreen display
|
||||
* and regular in-window display.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
*/
|
||||
function FullscreenAction(context) {
|
||||
return {
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -33,35 +33,29 @@ define(
|
||||
/**
|
||||
* The new tab action allows a domain object to be opened
|
||||
* into a new browser tab.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
*/
|
||||
function NewTabAction(urlService, $window, context) {
|
||||
// Returns the selected domain object
|
||||
// when using the context menu or the top right button
|
||||
// based on the context and the existance of the object
|
||||
// It is set to object an returned
|
||||
function getSelectedObject() {
|
||||
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");
|
||||
}
|
||||
context = context || {};
|
||||
|
||||
this.urlService = urlService;
|
||||
this.open = function () {
|
||||
$window.open.apply($window, arguments);
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -29,6 +29,7 @@ define(
|
||||
/**
|
||||
* Updates the title of the current window to reflect the name
|
||||
* of the currently navigated-to domain object.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function WindowTitler(navigationService, $rootScope, $document) {
|
||||
@ -49,4 +50,4 @@ define(
|
||||
|
||||
return WindowTitler;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -38,6 +38,7 @@ define(
|
||||
mockMutationCapability,
|
||||
mockPersistenceCapability,
|
||||
mockCompositionCapability,
|
||||
mockContextCapability,
|
||||
mockCapabilities,
|
||||
creationService;
|
||||
|
||||
@ -87,10 +88,15 @@ define(
|
||||
"composition",
|
||||
["invoke"]
|
||||
);
|
||||
mockContextCapability = jasmine.createSpyObj(
|
||||
"context",
|
||||
["getPath"]
|
||||
);
|
||||
mockCapabilities = {
|
||||
mutation: mockMutationCapability,
|
||||
persistence: mockPersistenceCapability,
|
||||
composition: mockCompositionCapability
|
||||
composition: mockCompositionCapability,
|
||||
context: mockContextCapability
|
||||
};
|
||||
|
||||
mockPersistenceService.createObject.andReturn(
|
||||
@ -103,6 +109,7 @@ define(
|
||||
mockParentObject.useCapability.andCallFake(function (key, value) {
|
||||
return mockCapabilities[key].invoke(value);
|
||||
});
|
||||
mockParentObject.getId.andReturn('parentId');
|
||||
|
||||
mockPersistenceCapability.persist.andReturn(
|
||||
mockPromise(true)
|
||||
@ -194,7 +201,16 @@ define(
|
||||
expect(mockLog.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("stores location on new domainObjects", function () {
|
||||
var model = { name: "my model" },
|
||||
objectPromise = creationService.createObject(
|
||||
model,
|
||||
mockParentObject
|
||||
);
|
||||
|
||||
expect(model.location).toBe('parentId');
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -22,7 +22,9 @@
|
||||
/*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(
|
||||
[],
|
||||
@ -32,128 +34,130 @@ define(
|
||||
* The dialog service is responsible for handling window-modal
|
||||
* communication with the user, such as displaying forms for user
|
||||
* input.
|
||||
* @memberof platform/commonUI/dialog
|
||||
* @constructor
|
||||
*/
|
||||
function DialogService(overlayService, $q, $log) {
|
||||
var overlay,
|
||||
dialogVisible = false;
|
||||
|
||||
// Stop showing whatever overlay is currently active
|
||||
// (e.g. because the user hit cancel)
|
||||
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
|
||||
};
|
||||
this.overlayService = overlayService;
|
||||
this.$q = $q;
|
||||
this.$log = $log;
|
||||
this.overlay = undefined;
|
||||
this.dialogVisible = false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -43,57 +43,63 @@ define(
|
||||
* particularly where a multiple-overlay effect is not specifically
|
||||
* desired).
|
||||
*
|
||||
* @memberof platform/commonUI/dialog
|
||||
* @constructor
|
||||
*/
|
||||
function OverlayService($document, $compile, $rootScope) {
|
||||
function createOverlay(key, overlayModel) {
|
||||
// Create a new scope for this overlay
|
||||
var scope = $rootScope.$new(),
|
||||
element;
|
||||
this.$compile = $compile;
|
||||
|
||||
// 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 = $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
|
||||
// Don't include $document and $rootScope directly;
|
||||
// avoids https://docs.angularjs.org/error/ng/cpws
|
||||
this.findBody = function () {
|
||||
return $document.find('body');
|
||||
};
|
||||
this.newScope = function () {
|
||||
return $rootScope.$new();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -29,9 +29,26 @@ define(
|
||||
* The "Cancel" action; the action triggered by clicking Cancel from
|
||||
* Edit Mode. Exits the editing user interface and invokes object
|
||||
* capabilities to persist the changes that have been made.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {Action}
|
||||
*/
|
||||
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;
|
||||
// this is introduced by EditableDomainObject which is
|
||||
@ -56,25 +73,15 @@ define(
|
||||
)));
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Cancel editing.
|
||||
*
|
||||
* @returns {Promise} a promise that will be fulfilled when
|
||||
* cancellation has completed
|
||||
*/
|
||||
perform: function () {
|
||||
return doCancel(getEditorCapability())
|
||||
.then(returnToBrowse);
|
||||
}
|
||||
};
|
||||
}
|
||||
return doCancel(getEditorCapability())
|
||||
.then(returnToBrowse);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this action is applicable in a given context.
|
||||
* This will ensure that a domain object is present in the context,
|
||||
* and that this domain object is in Edit mode.
|
||||
* @returns true if applicable
|
||||
* @returns {boolean} true if applicable
|
||||
*/
|
||||
CancelAction.appliesTo = function (context) {
|
||||
var domainObject = (context || {}).domainObject;
|
||||
@ -84,4 +91,4 @@ define(
|
||||
|
||||
return CancelAction;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -42,7 +42,9 @@ define(
|
||||
* mode (typically triggered by the Edit button.) This will
|
||||
* show the user interface for editing (by way of a change in
|
||||
* route)
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
*/
|
||||
function EditAction($location, navigationService, $log, context) {
|
||||
var domainObject = (context || {}).domainObject;
|
||||
@ -60,17 +62,19 @@ define(
|
||||
return NULL_ACTION;
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Enter edit mode.
|
||||
*/
|
||||
perform: function () {
|
||||
navigationService.setNavigation(domainObject);
|
||||
$location.path("/edit");
|
||||
}
|
||||
};
|
||||
this.domainObject = domainObject;
|
||||
this.$location = $location;
|
||||
this.navigationService = navigationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* for this action to be performed upon.
|
||||
@ -87,4 +91,4 @@ define(
|
||||
|
||||
return EditAction;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -29,42 +29,43 @@ define(
|
||||
|
||||
/**
|
||||
* Add one domain object to another's composition.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {Action}
|
||||
*/
|
||||
function LinkAction(context) {
|
||||
var domainObject = (context || {}).domainObject,
|
||||
selectedObject = (context || {}).selectedObject,
|
||||
selectedId = selectedObject && selectedObject.getId();
|
||||
this.domainObject = (context || {}).domainObject;
|
||||
this.selectedObject = (context || {}).selectedObject;
|
||||
this.selectedId = this.selectedObject && this.selectedObject.getId();
|
||||
}
|
||||
|
||||
LinkAction.prototype.perform = function () {
|
||||
var self = this;
|
||||
|
||||
// Add this domain object's identifier
|
||||
function addId(model) {
|
||||
if (Array.isArray(model.composition) &&
|
||||
model.composition.indexOf(selectedId) < 0) {
|
||||
model.composition.push(selectedId);
|
||||
model.composition.indexOf(self.selectedId) < 0) {
|
||||
model.composition.push(self.selectedId);
|
||||
}
|
||||
}
|
||||
|
||||
// Persist changes to the domain object
|
||||
function doPersist() {
|
||||
var persistence = domainObject.getCapability('persistence');
|
||||
var persistence =
|
||||
self.domainObject.getCapability('persistence');
|
||||
return persistence.persist();
|
||||
}
|
||||
|
||||
// Link these objects
|
||||
function doLink() {
|
||||
return domainObject.useCapability("mutation", addId)
|
||||
return self.domainObject.useCapability("mutation", addId)
|
||||
.then(doPersist);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Perform this action.
|
||||
*/
|
||||
perform: function () {
|
||||
return selectedId && doLink();
|
||||
}
|
||||
};
|
||||
}
|
||||
return this.selectedId && doLink();
|
||||
};
|
||||
|
||||
return LinkAction;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -32,58 +32,58 @@ define(
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Construct an action which will allow an object's metadata to be
|
||||
* edited.
|
||||
* Implements the "Edit Properties" action, which prompts the user
|
||||
* to modify a domain object's properties.
|
||||
*
|
||||
* @param {DialogService} dialogService a service which will show the dialog
|
||||
* @param {DomainObject} object the object to be edited
|
||||
* @param {ActionContext} context the context in which this action is performed
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {Action}
|
||||
* @constructor
|
||||
*/
|
||||
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
|
||||
function doPersist() {
|
||||
var persistence = object.getCapability('persistence');
|
||||
var persistence = domainObject.getCapability('persistence');
|
||||
return persistence && persistence.persist();
|
||||
}
|
||||
|
||||
// Update the domain object model based on user input
|
||||
function updateModel(userInput, dialog) {
|
||||
return object.useCapability('mutation', function (model) {
|
||||
return domainObject.useCapability('mutation', function (model) {
|
||||
dialog.updateModel(model, userInput);
|
||||
});
|
||||
}
|
||||
|
||||
function showDialog(type) {
|
||||
// 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
|
||||
return dialogService.getUserInput(
|
||||
dialog.getFormStructure(),
|
||||
dialog.getInitialFormValue()
|
||||
).then(function (userInput) {
|
||||
// Update the model, if user input was provided
|
||||
return userInput && updateModel(userInput, dialog);
|
||||
}).then(function (result) {
|
||||
return result && doPersist();
|
||||
});
|
||||
// Update the model, if user input was provided
|
||||
return userInput && updateModel(userInput, dialog);
|
||||
}).then(function (result) {
|
||||
return result && doPersist();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
return type && showDialog(type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter this action for applicability against a given context.
|
||||
@ -106,3 +106,4 @@ define(
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
@ -21,12 +21,6 @@
|
||||
*****************************************************************************/
|
||||
/*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(
|
||||
function () {
|
||||
'use strict';
|
||||
@ -37,58 +31,60 @@ define(
|
||||
* @param {TypeImpl} type the type of domain object for which properties
|
||||
* will be specified
|
||||
* @param {DomainObject} the object for which properties will be set
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @memberof module:common/actions/properties-dialog
|
||||
*/
|
||||
function PropertiesDialog(type, model) {
|
||||
var properties = type.getProperties();
|
||||
|
||||
return {
|
||||
/**
|
||||
* 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]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.type = type;
|
||||
this.model = model;
|
||||
this.properties = type.getProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -37,23 +37,37 @@ define(
|
||||
*
|
||||
* @param {DomainObject} object the object to be removed
|
||||
* @param {ActionContext} context the context in which this action is performed
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @memberof module:editor/actions/remove-action
|
||||
* @implements {Action}
|
||||
*/
|
||||
function RemoveAction($q, navigationService, context) {
|
||||
var object = (context || {}).domainObject,
|
||||
this.domainObject = (context || {}).domainObject;
|
||||
this.$q = $q;
|
||||
this.navigationService = navigationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform this action.
|
||||
* @return {Promise} a promise which will be
|
||||
* fulfilled when the action has completed.
|
||||
*/
|
||||
RemoveAction.prototype.perform = function () {
|
||||
var $q = this.$q,
|
||||
navigationService = this.navigationService,
|
||||
domainObject = this.domainObject,
|
||||
ROOT_ID = "ROOT";
|
||||
|
||||
/**
|
||||
/*
|
||||
* Check whether an object ID matches the ID of the object being
|
||||
* removed (used to filter a parent's composition to handle the
|
||||
* removal.)
|
||||
*/
|
||||
function isNotObject(otherObjectId) {
|
||||
return otherObjectId !== object.getId();
|
||||
return otherObjectId !== domainObject.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Mutate a parent object such that it no longer contains the object
|
||||
* which is being removed.
|
||||
*/
|
||||
@ -61,7 +75,7 @@ define(
|
||||
model.composition = model.composition.filter(isNotObject);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Invoke persistence on a domain object. This will be called upon
|
||||
* the removed object's parent (as its composition will have changed.)
|
||||
*/
|
||||
@ -76,10 +90,10 @@ define(
|
||||
// navigate back to parent of removed object.
|
||||
function checkObjectNavigation(object, parentObject) {
|
||||
// Traverse object starts at current location
|
||||
var traverseObject = navigationService.getNavigation();
|
||||
var traverseObject = (navigationService).getNavigation();
|
||||
|
||||
// Stop at ROOT of folder path
|
||||
while(traverseObject.getId() !== ROOT_ID) {
|
||||
while (traverseObject.getId() !== ROOT_ID) {
|
||||
// If traverse object is object being removed
|
||||
// navigate to parent of removed object
|
||||
if (traverseObject.getId() === object.getId()) {
|
||||
@ -90,37 +104,25 @@ define(
|
||||
traverseObject = traverseObject.getCapability('context').getParent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/*
|
||||
* Remove the object from its parent, as identified by its context
|
||||
* capability.
|
||||
* @param {object} domain object being removed contextCapability
|
||||
gotten from the "context" capability of this object
|
||||
*/
|
||||
function removeFromContext(object) {
|
||||
var contextCapability = object.getCapability('context'),
|
||||
parent = contextCapability.getParent();
|
||||
// Navigates through/ascendant if deleting current object
|
||||
checkObjectNavigation(object, parent)
|
||||
$q.when(
|
||||
checkObjectNavigation(object, parent);
|
||||
return $q.when(
|
||||
parent.useCapability('mutation', doMutate)
|
||||
).then(function () {
|
||||
return doPersist(parent);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Perform this action.
|
||||
* @return {module:core/promises.Promise} a promise which will be
|
||||
* fulfilled when the action has completed.
|
||||
*/
|
||||
perform: function () {
|
||||
return $q.when(object)
|
||||
.then(removeFromContext);
|
||||
}
|
||||
};
|
||||
}
|
||||
return $q.when(domainObject)
|
||||
.then(removeFromContext);
|
||||
};
|
||||
|
||||
// Object needs to have a parent for Remove to be applicable
|
||||
RemoveAction.appliesTo = function (context) {
|
||||
@ -138,4 +140,4 @@ define(
|
||||
|
||||
return RemoveAction;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -30,9 +30,27 @@ define(
|
||||
* The "Save" action; the action triggered by clicking Save from
|
||||
* Edit Mode. Exits the editing user interface and invokes object
|
||||
* capabilities to persist the changes that have been made.
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
* @memberof platform/commonUI/edit
|
||||
*/
|
||||
function 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;
|
||||
// this is introduced by EditableDomainObject which is
|
||||
@ -51,18 +69,8 @@ define(
|
||||
));
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Save changes and conclude editing.
|
||||
*
|
||||
* @returns {Promise} a promise that will be fulfilled when
|
||||
* cancellation has completed
|
||||
*/
|
||||
perform: function () {
|
||||
return doSave().then(returnToBrowse);
|
||||
}
|
||||
};
|
||||
}
|
||||
return doSave().then(returnToBrowse);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this action is applicable in a given context.
|
||||
@ -78,4 +86,4 @@ define(
|
||||
|
||||
return SaveAction;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -35,6 +35,9 @@ define(
|
||||
* Meant specifically for use by EditableDomainObject and the
|
||||
* associated cache; the constructor signature is particular
|
||||
* to a pattern used there and may contain unused arguments.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {CompositionCapability}
|
||||
*/
|
||||
return function EditableCompositionCapability(
|
||||
contextCapability,
|
||||
@ -54,4 +57,4 @@ define(
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -35,6 +35,9 @@ define(
|
||||
* Meant specifically for use by EditableDomainObject and the
|
||||
* associated cache; the constructor signature is particular
|
||||
* to a pattern used there and may contain unused arguments.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {ContextCapability}
|
||||
*/
|
||||
return function EditableContextCapability(
|
||||
contextCapability,
|
||||
@ -72,4 +75,4 @@ define(
|
||||
return capability;
|
||||
};
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -35,6 +35,8 @@ define(
|
||||
* Meant specifically for use by EditableDomainObject and the
|
||||
* associated cache; the constructor signature is particular
|
||||
* to a pattern used there and may contain unused arguments.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
*/
|
||||
return function EditableLookupCapability(
|
||||
contextCapability,
|
||||
@ -76,7 +78,7 @@ define(
|
||||
// Wrap a returned value (see above); if it's a promise, wrap
|
||||
// the resolved value.
|
||||
function wrapResult(result) {
|
||||
return result.then ? // promise-like
|
||||
return (result && result.then) ? // promise-like
|
||||
result.then(makeEditable) :
|
||||
makeEditable(result);
|
||||
}
|
||||
@ -105,8 +107,10 @@ define(
|
||||
|
||||
// Wrap a method of this capability
|
||||
function wrapMethod(fn) {
|
||||
capability[fn] =
|
||||
(idempotent ? oneTimeFunction : wrapFunction)(fn);
|
||||
if (typeof capability[fn] === 'function') {
|
||||
capability[fn] =
|
||||
(idempotent ? oneTimeFunction : wrapFunction)(fn);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap all methods; return only editable domain objects.
|
||||
@ -115,4 +119,4 @@ define(
|
||||
return capability;
|
||||
};
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -35,6 +35,9 @@ define(
|
||||
* Meant specifically for use by EditableDomainObject and the
|
||||
* associated cache; the constructor signature is particular
|
||||
* to a pattern used there and may contain unused arguments.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {PersistenceCapability}
|
||||
*/
|
||||
function EditablePersistenceCapability(
|
||||
persistenceCapability,
|
||||
@ -62,4 +65,4 @@ define(
|
||||
|
||||
return EditablePersistenceCapability;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -35,6 +35,9 @@ define(
|
||||
* Meant specifically for use by EditableDomainObject and the
|
||||
* associated cache; the constructor signature is particular
|
||||
* to a pattern used there and may contain unused arguments.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {RelationshipCapability}
|
||||
*/
|
||||
return function EditableRelationshipCapability(
|
||||
relationshipCapability,
|
||||
@ -54,4 +57,4 @@ define(
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -39,27 +39,48 @@ define(
|
||||
* Meant specifically for use by EditableDomainObject and the
|
||||
* associated cache; the constructor signature is particular
|
||||
* to a pattern used there and may contain unused arguments.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
*/
|
||||
return function EditorCapability(
|
||||
function EditorCapability(
|
||||
persistenceCapability,
|
||||
editableObject,
|
||||
domainObject,
|
||||
cache
|
||||
) {
|
||||
this.editableObject = editableObject;
|
||||
this.domainObject = domainObject;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
// Simulate Promise.resolve (or $q.when); the former
|
||||
// causes a delayed reaction from Angular (since it
|
||||
// does not trigger a digest) and the latter is not
|
||||
// readily accessible, since we're a few classes
|
||||
// removed from the layer which gets dependency
|
||||
// injection.
|
||||
function resolvePromise(value) {
|
||||
return (value && value.then) ? value : {
|
||||
then: function (callback) {
|
||||
return resolvePromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
// Simulate Promise.resolve (or $q.when); the former
|
||||
// causes a delayed reaction from Angular (since it
|
||||
// does not trigger a digest) and the latter is not
|
||||
// readily accessible, since we're a few classes
|
||||
// removed from the layer which gets dependency
|
||||
// injection.
|
||||
function resolvePromise(value) {
|
||||
return (value && value.then) ? value : {
|
||||
then: function (callback) {
|
||||
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
|
||||
// with changes made to the copy used for editing.
|
||||
@ -74,39 +95,32 @@ define(
|
||||
return domainObject.getCapability('persistence').persist();
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
};
|
||||
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.
|
||||
* @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.
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function EditActionController($scope) {
|
||||
@ -51,4 +52,4 @@ define(
|
||||
|
||||
return EditActionController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -22,7 +22,8 @@
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining EditController. Created by vwoeltje on 11/14/14.
|
||||
* This bundle implements Edit mode.
|
||||
* @namespace platform/commonUI/edit
|
||||
*/
|
||||
define(
|
||||
["../objects/EditableDomainObject"],
|
||||
@ -33,15 +34,16 @@ define(
|
||||
* Controller which is responsible for populating the scope for
|
||||
* Edit mode; introduces an editable version of the currently
|
||||
* navigated domain object into the scope.
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function EditController($scope, $q, navigationService) {
|
||||
var navigatedObject;
|
||||
var self = this;
|
||||
|
||||
function setNavigation(domainObject) {
|
||||
// Wrap the domain object such that all mutation is
|
||||
// confined to edit mode (until Save)
|
||||
navigatedObject =
|
||||
self.navigatedDomainObject =
|
||||
domainObject && new EditableDomainObject(domainObject, $q);
|
||||
}
|
||||
|
||||
@ -50,33 +52,33 @@ define(
|
||||
$scope.$on("$destroy", function () {
|
||||
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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -28,15 +28,17 @@ define(
|
||||
|
||||
/**
|
||||
* Supports the Library and Elements panes in Edit mode.
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function EditPanesController($scope) {
|
||||
var root;
|
||||
var self = this;
|
||||
|
||||
// Update root object based on represented object
|
||||
function updateRoot(domainObject) {
|
||||
var context = domainObject &&
|
||||
domainObject.getCapability('context'),
|
||||
var root = self.rootDomainObject,
|
||||
context = domainObject &&
|
||||
domainObject.getCapability('context'),
|
||||
newRoot = context && context.getTrueRoot(),
|
||||
oldId = root && root.getId(),
|
||||
newId = newRoot && newRoot.getId();
|
||||
@ -44,25 +46,22 @@ define(
|
||||
// Only update if this has actually changed,
|
||||
// to avoid excessive refreshing.
|
||||
if (oldId !== newId) {
|
||||
root = newRoot;
|
||||
self.rootDomainObject = newRoot;
|
||||
}
|
||||
}
|
||||
|
||||
// Update root when represented object changes
|
||||
$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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -31,6 +31,7 @@ define(
|
||||
* to this attribute will be evaluated during page navigation events
|
||||
* and, if it returns a truthy value, will be used to populate a
|
||||
* prompt to the user to confirm this navigation.
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @param $window the window
|
||||
*/
|
||||
@ -102,4 +103,4 @@ define(
|
||||
return MCTBeforeUnload;
|
||||
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -68,6 +68,9 @@ define(
|
||||
* which need to behave differently in edit mode,
|
||||
* and provides a "working copy" of the object's
|
||||
* model to allow changes to be easily cancelled.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {DomainObject}
|
||||
*/
|
||||
function EditableDomainObject(domainObject, $q) {
|
||||
// The cache will hold all domain objects reached from
|
||||
@ -92,10 +95,10 @@ define(
|
||||
this,
|
||||
delegateArguments
|
||||
),
|
||||
factory = capabilityFactories[name];
|
||||
Factory = capabilityFactories[name];
|
||||
|
||||
return (factory && capability) ?
|
||||
factory(capability, editableObject, domainObject, cache) :
|
||||
return (Factory && capability) ?
|
||||
new Factory(capability, editableObject, domainObject, cache) :
|
||||
capability;
|
||||
};
|
||||
|
||||
@ -109,4 +112,4 @@ define(
|
||||
|
||||
return EditableDomainObject;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -22,7 +22,7 @@
|
||||
/*global define*/
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* 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
|
||||
* 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 the objects used in browse mode (or to persistence) until the user
|
||||
* initiates a Save.
|
||||
*
|
||||
* @module editor/object/editable-domain-object-cache
|
||||
*/
|
||||
define(
|
||||
["./EditableModelCache"],
|
||||
@ -46,107 +44,118 @@ define(
|
||||
* of objects retrieved via composition or context capabilities as
|
||||
* editable domain objects.
|
||||
*
|
||||
* @param {Constructor<EditableDomainObject>} EditableDomainObject a
|
||||
* @param {Constructor<DomainObject>} EditableDomainObject a
|
||||
* constructor function which takes a regular domain object as
|
||||
* an argument, and returns an editable domain object as its
|
||||
* result.
|
||||
* @param $q Angular's $q, for promise handling
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @memberof module:editor/object/editable-domain-object-cache
|
||||
*/
|
||||
function EditableDomainObjectCache(EditableDomainObject, $q) {
|
||||
var cache = new EditableModelCache(),
|
||||
dirty = {},
|
||||
root;
|
||||
|
||||
return {
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
this.cache = new EditableModelCache();
|
||||
this.dirtyObjects = {};
|
||||
this.root = undefined;
|
||||
this.$q = $q;
|
||||
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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -31,33 +31,32 @@ define(
|
||||
* 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
|
||||
* object but may contain changes across many objects.
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function EditableModelCache() {
|
||||
var 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()));
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -30,53 +30,47 @@ define(
|
||||
* Policy controlling when the `edit` and/or `properties` actions
|
||||
* can appear as applicable actions of the `view-control` category
|
||||
* (shown as buttons in the top-right of browse mode.)
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @implements {Policy.<Action, ActionContext>}
|
||||
*/
|
||||
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
|
||||
(views || []).forEach(function (view) {
|
||||
count += (view.editable !== false) ? 1 : 0;
|
||||
});
|
||||
// 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;
|
||||
|
||||
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 {
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
// Like all policies, allow by default.
|
||||
return true;
|
||||
};
|
||||
|
||||
return EditActionPolicy;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -28,30 +28,24 @@ define(
|
||||
|
||||
/**
|
||||
* Policy controlling which views should be visible in Edit mode.
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @implements {Policy.<View, DomainObject>}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -41,14 +41,17 @@ define(
|
||||
* and may be reused for different domain objects and/or
|
||||
* representations resulting from changes there.
|
||||
*
|
||||
* @memberof platform/commonUI/edit
|
||||
* @implements {Representer}
|
||||
* @constructor
|
||||
*/
|
||||
function EditRepresenter($q, $log, scope) {
|
||||
var domainObject,
|
||||
key;
|
||||
var self = this;
|
||||
|
||||
// Mutate and persist a new version of a domain object's model.
|
||||
function doPersist(model) {
|
||||
var domainObject = self.domainObject;
|
||||
|
||||
// First, mutate; then, persist.
|
||||
return $q.when(domainObject.useCapability("mutation", function () {
|
||||
return model;
|
||||
@ -64,7 +67,8 @@ define(
|
||||
// Look up from scope; these will have been populated by
|
||||
// mct-representation.
|
||||
var model = scope.model,
|
||||
configuration = scope.configuration;
|
||||
configuration = scope.configuration,
|
||||
domainObject = self.domainObject;
|
||||
|
||||
// Log the commit message
|
||||
$log.debug([
|
||||
@ -78,50 +82,33 @@ define(
|
||||
if (domainObject && domainObject.hasCapability("persistence")) {
|
||||
// Configurations for specific views are stored by
|
||||
// key in the "configuration" field of the model.
|
||||
if (key && configuration) {
|
||||
if (self.key && configuration) {
|
||||
model.configuration = model.configuration || {};
|
||||
model.configuration[key] = configuration;
|
||||
model.configuration[self.key] = configuration;
|
||||
}
|
||||
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
|
||||
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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -38,125 +38,23 @@ define(
|
||||
*
|
||||
* @param structure toolbar structure, as provided by view definition
|
||||
* @param {Function} commit callback to invoke after changes
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function EditToolbar(structure, commit) {
|
||||
var toolbarStructure = Object.create(structure || {}),
|
||||
toolbarState,
|
||||
selection,
|
||||
properties = [];
|
||||
var self = this;
|
||||
|
||||
// Generate a new key for an item's property
|
||||
function addKey(property) {
|
||||
properties.push(property);
|
||||
return 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);
|
||||
self.properties.push(property);
|
||||
return self.properties.length - 1; // Return index of property
|
||||
}
|
||||
|
||||
// Invoke all functions in selections with the given name
|
||||
function invoke(method, value) {
|
||||
if (method) {
|
||||
// Make the change in the selection
|
||||
selection.forEach(function (selected) {
|
||||
self.selection.forEach(function (selected) {
|
||||
if (typeof selected[method] === 'function') {
|
||||
selected[method](value);
|
||||
}
|
||||
@ -189,73 +87,172 @@ define(
|
||||
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
|
||||
function refreshSectionApplicability(section) {
|
||||
var count = 0;
|
||||
// Show/hide each item
|
||||
(section.items || []).forEach(function (item) {
|
||||
item.hidden = !isApplicable(item);
|
||||
item.hidden = !self.isApplicable(item);
|
||||
count += item.hidden ? 0 : 1;
|
||||
});
|
||||
// Hide this section if there are no applicable items
|
||||
section.hidden = !count;
|
||||
}
|
||||
|
||||
// Show/hide controls if they are applicable
|
||||
function refreshApplicability() {
|
||||
toolbarStructure.sections.forEach(refreshSectionApplicability);
|
||||
// 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.
|
||||
self.selection.forEach(function (selected) {
|
||||
result = (selected[property] !== undefined) ?
|
||||
self.lookupState(property, selected) :
|
||||
result;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Refresh toolbar state to match selection
|
||||
function refreshState() {
|
||||
toolbarState = properties.map(initializeState);
|
||||
}
|
||||
this.selection = s;
|
||||
this.toolbarStructure.sections.forEach(refreshSectionApplicability);
|
||||
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 {
|
||||
/**
|
||||
* Set the current selection. Visisbility of sections
|
||||
* and items in the toolbar will be updated to match this.
|
||||
* @param {Array} s the new selection
|
||||
*/
|
||||
setSelection: function (s) {
|
||||
selection = s;
|
||||
refreshApplicability();
|
||||
refreshState();
|
||||
},
|
||||
/**
|
||||
* Get the structure of the toolbar, as appropriate to
|
||||
* pass to `mct-toolbar`.
|
||||
* @returns the toolbar structure
|
||||
*/
|
||||
getStructure: function () {
|
||||
return toolbarStructure;
|
||||
},
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
getState: function () {
|
||||
return toolbarState;
|
||||
},
|
||||
/**
|
||||
* 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 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
|
||||
*/
|
||||
EditToolbar.prototype.updateState = function (index, value) {
|
||||
var self = this;
|
||||
|
||||
// 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
|
||||
self.selection.forEach(updateProperty);
|
||||
|
||||
// Return whether or not anything changed
|
||||
return changed;
|
||||
}
|
||||
|
||||
return updateProperties(this.properties[index], value);
|
||||
};
|
||||
|
||||
return EditToolbar;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
@ -27,17 +27,21 @@ define(
|
||||
"use strict";
|
||||
|
||||
// No operation
|
||||
function noop() {}
|
||||
var NOOP_REPRESENTER = {
|
||||
represent: function () {},
|
||||
destroy: function () {}
|
||||
};
|
||||
|
||||
/**
|
||||
* The EditToolbarRepresenter populates the toolbar in Edit mode
|
||||
* based on a view's definition.
|
||||
* @param {Scope} scope the Angular scope of the representation
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @implements {Representer}
|
||||
*/
|
||||
function EditToolbarRepresenter(scope, element, attrs) {
|
||||
var toolbar,
|
||||
toolbarObject = {};
|
||||
var self = this;
|
||||
|
||||
// Mark changes as ready to persist
|
||||
function commit(message) {
|
||||
@ -49,31 +53,33 @@ define(
|
||||
// Handle changes to the current selection
|
||||
function updateSelection(selection) {
|
||||
// Only update if there is a toolbar to update
|
||||
if (toolbar) {
|
||||
if (self.toolbar) {
|
||||
// Make sure selection is array-like
|
||||
selection = Array.isArray(selection) ?
|
||||
selection :
|
||||
(selection ? [selection] : []);
|
||||
|
||||
// Update the toolbar's selection
|
||||
toolbar.setSelection(selection);
|
||||
self.toolbar.setSelection(selection);
|
||||
|
||||
// ...and expose its structure/state
|
||||
toolbarObject.structure = toolbar.getStructure();
|
||||
toolbarObject.state = toolbar.getState();
|
||||
self.toolbarObject.structure =
|
||||
self.toolbar.getStructure();
|
||||
self.toolbarObject.state =
|
||||
self.toolbar.getState();
|
||||
}
|
||||
}
|
||||
|
||||
// Get state (to watch it)
|
||||
function getState() {
|
||||
return toolbarObject.state;
|
||||
return self.toolbarObject.state;
|
||||
}
|
||||
|
||||
// Update selection models to match changed toolbar state
|
||||
function updateState(state) {
|
||||
// Update underlying state based on toolbar changes
|
||||
var changed = (state || []).map(function (value, index) {
|
||||
return toolbar.updateState(index, value);
|
||||
return self.toolbar.updateState(index, value);
|
||||
}).reduce(function (a, b) {
|
||||
return a || b;
|
||||
}, false);
|
||||
@ -85,66 +91,73 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize toolbar (expose object to parent scope)
|
||||
function initialize(definition) {
|
||||
// If we have been asked to expose toolbar state...
|
||||
if (attrs.toolbar) {
|
||||
// Initialize toolbar object
|
||||
toolbar = new EditToolbar(definition, commit);
|
||||
// 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() {
|
||||
// Avoid attaching scope to this;
|
||||
// http://errors.angularjs.org/1.2.26/ng/cpws
|
||||
this.setSelection = function (s) {
|
||||
scope.selection = s;
|
||||
};
|
||||
this.clearExposedToolbar = function () {
|
||||
// Clear exposed toolbar state (if any)
|
||||
if (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
|
||||
// to synchronize with it.
|
||||
if (attrs.toolbar) {
|
||||
if (attrs && attrs.toolbar) {
|
||||
// Detect and handle changes to state from the toolbar
|
||||
scope.$watchCollection(getState, updateState);
|
||||
// Watch for changes in the current selection state
|
||||
scope.$watchCollection("selection.all()", updateSelection);
|
||||
// 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -37,110 +37,96 @@ define(
|
||||
* * The selection, for single selected elements within the
|
||||
* view.
|
||||
*
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function EditToolbarSelection() {
|
||||
var selection = [ {} ],
|
||||
selecting = false,
|
||||
selected;
|
||||
this.selection = [{}];
|
||||
this.selecting = false;
|
||||
this.selectedObj = undefined;
|
||||
}
|
||||
|
||||
// Remove the currently-selected object
|
||||
function deselect() {
|
||||
// Nothing to do if we don't have a selected object
|
||||
if (selecting) {
|
||||
// Clear state tracking
|
||||
selecting = false;
|
||||
selected = undefined;
|
||||
/**
|
||||
* Check if an object is currently selected.
|
||||
* @param {*} obj the object to check for selection
|
||||
* @returns {boolean} true if selected, otherwise false
|
||||
*/
|
||||
EditToolbarSelection.prototype.selected = function (obj) {
|
||||
return (obj === this.selectedObj) || (obj === this.selection[0]);
|
||||
};
|
||||
|
||||
// Remove the selection
|
||||
selection.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Select an object.
|
||||
* @param obj the object to select
|
||||
* @returns {boolean} true if selection changed
|
||||
*/
|
||||
EditToolbarSelection.prototype.select = function (obj) {
|
||||
// Proxy is always selected
|
||||
if (obj === this.selection[0]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select an object
|
||||
function select(obj) {
|
||||
// Proxy is always selected
|
||||
if (obj === selection[0]) {
|
||||
return false;
|
||||
}
|
||||
// Clear any existing selection
|
||||
this.deselect();
|
||||
|
||||
// Clear any existing selection
|
||||
deselect();
|
||||
// Note the current selection state
|
||||
this.selectedObj = obj;
|
||||
this.selecting = true;
|
||||
|
||||
// Note the current selection state
|
||||
selected = obj;
|
||||
selecting = true;
|
||||
// Add the selection
|
||||
this.selection.push(obj);
|
||||
};
|
||||
|
||||
// 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) {
|
||||
return (obj === selected) || (obj === selection[0]);
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
EditToolbarSelection.prototype.proxy = function (p) {
|
||||
if (arguments.length > 0) {
|
||||
this.selection[0] = p;
|
||||
}
|
||||
return this.selection[0];
|
||||
};
|
||||
|
||||
// Getter for current selection
|
||||
function get() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
// Getter/setter for view proxy
|
||||
function proxy(p) {
|
||||
if (arguments.length > 0) {
|
||||
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
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get an array containing all selections, including the
|
||||
* selection proxy. It is generally not advisable to
|
||||
* mutate this array directly.
|
||||
* @returns {Array} all selections
|
||||
*/
|
||||
EditToolbarSelection.prototype.all = function () {
|
||||
return this.selection;
|
||||
};
|
||||
|
||||
return EditToolbarSelection;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -112,7 +112,9 @@ define(
|
||||
});
|
||||
|
||||
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[2]);
|
||||
@ -123,7 +125,9 @@ define(
|
||||
});
|
||||
|
||||
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[2]);
|
||||
|
@ -200,7 +200,7 @@
|
||||
{
|
||||
"key": "label",
|
||||
"templateUrl": "templates/label.html",
|
||||
"uses": [ "type" ],
|
||||
"uses": [ "type", "location" ],
|
||||
"gestures": [ "drag", "menu", "info" ]
|
||||
},
|
||||
{
|
||||
|
@ -96,6 +96,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*********************************************** FORM ELEMENTS */
|
||||
/*
|
||||
@mixin invokeMenu($baseColor: $colorBodyFg) {
|
||||
$c: $baseColor;
|
||||
@ -230,27 +231,21 @@
|
||||
line-height: 14px;
|
||||
margin-right: 5px; }
|
||||
/* line 89, ../sass/forms/_elems.scss */
|
||||
.form .form-row .controls input[type="text"] {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin-top: -4px;
|
||||
vertical-align: baseline; }
|
||||
/* line 96, ../sass/forms/_elems.scss */
|
||||
.form .form-row .controls .l-med input[type="text"] {
|
||||
width: 200px; }
|
||||
/* line 100, ../sass/forms/_elems.scss */
|
||||
/* line 93, ../sass/forms/_elems.scss */
|
||||
.form .form-row .controls .l-small input[type="text"] {
|
||||
width: 50px; }
|
||||
/* line 104, ../sass/forms/_elems.scss */
|
||||
/* line 97, ../sass/forms/_elems.scss */
|
||||
.form .form-row .controls .l-numeric input[type="text"] {
|
||||
text-align: right; }
|
||||
/* line 108, ../sass/forms/_elems.scss */
|
||||
/* line 101, ../sass/forms/_elems.scss */
|
||||
.form .form-row .controls .select {
|
||||
margin-right: 5px; }
|
||||
/* line 113, ../sass/forms/_elems.scss */
|
||||
/* line 106, ../sass/forms/_elems.scss */
|
||||
.form .form-row .field-hints {
|
||||
color: #666666; }
|
||||
/* line 117, ../sass/forms/_elems.scss */
|
||||
/* line 110, ../sass/forms/_elems.scss */
|
||||
.form .form-row .selector-list {
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
@ -263,7 +258,7 @@
|
||||
position: relative;
|
||||
height: 150px;
|
||||
overflow: auto; }
|
||||
/* line 128, ../sass/forms/_elems.scss */
|
||||
/* line 121, ../sass/forms/_elems.scss */
|
||||
.form .form-row .selector-list .wrapper {
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
@ -272,24 +267,24 @@
|
||||
bottom: 5px;
|
||||
left: 5px; }
|
||||
|
||||
/* line 142, ../sass/forms/_elems.scss */
|
||||
/* line 135, ../sass/forms/_elems.scss */
|
||||
label.form-control.checkbox input {
|
||||
margin-right: 5px;
|
||||
vertical-align: top; }
|
||||
|
||||
/* line 148, ../sass/forms/_elems.scss */
|
||||
/* line 141, ../sass/forms/_elems.scss */
|
||||
.hint,
|
||||
.s-hint {
|
||||
font-size: 0.9em; }
|
||||
|
||||
/* line 153, ../sass/forms/_elems.scss */
|
||||
/* line 146, ../sass/forms/_elems.scss */
|
||||
.l-result {
|
||||
display: inline-block;
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
position: relative;
|
||||
vertical-align: top; }
|
||||
/* line 160, ../sass/forms/_elems.scss */
|
||||
/* line 153, ../sass/forms/_elems.scss */
|
||||
.l-result div.s-hint {
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
@ -324,18 +319,17 @@ label.form-control.checkbox input {
|
||||
.edit-main textarea {
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-moz-box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
-webkit-box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
-moz-box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
-webkit-box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #cccccc;
|
||||
outline: none;
|
||||
padding: 5px;
|
||||
@ -371,18 +365,17 @@ label.form-control.checkbox input {
|
||||
input[type="text"] {
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-moz-box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
-webkit-box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
-moz-box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
-webkit-box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #cccccc;
|
||||
outline: none;
|
||||
padding: 0 3px; }
|
||||
@ -422,9 +415,9 @@ input[type="text"] {
|
||||
background-image: -moz-linear-gradient(#525252, #454545);
|
||||
background-image: -webkit-linear-gradient(#525252, #454545);
|
||||
background-image: linear-gradient(#525252, #454545);
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
@ -511,18 +504,17 @@ input[type="text"] {
|
||||
.channel-selector .treeview {
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-moz-box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
-webkit-box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
box-shadow: inset rgba(0, 0, 0, 0.5) 0 1px 5px;
|
||||
-moz-box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
-webkit-box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
box-shadow: inset rgba(0, 0, 0, 0.65) 0 1px 4px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #cccccc;
|
||||
outline: none;
|
||||
padding: 0 3px;
|
||||
|
@ -96,6 +96,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*********************************************** FORM ELEMENTS */
|
||||
/*
|
||||
@mixin invokeMenu($baseColor: $colorBodyFg) {
|
||||
$c: $baseColor;
|
||||
@ -163,9 +164,9 @@
|
||||
background-image: -moz-linear-gradient(#5e5e5e, #525252);
|
||||
background-image: -webkit-linear-gradient(#5e5e5e, #525252);
|
||||
background-image: linear-gradient(#5e5e5e, #525252);
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
@ -303,9 +304,9 @@
|
||||
background-image: -moz-linear-gradient(#0ac2ff, #00b4f0);
|
||||
background-image: -webkit-linear-gradient(#0ac2ff, #00b4f0);
|
||||
background-image: linear-gradient(#0ac2ff, #00b4f0);
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -96,6 +96,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*********************************************** FORM ELEMENTS */
|
||||
/*
|
||||
@mixin invokeMenu($baseColor: $colorBodyFg) {
|
||||
$c: $baseColor;
|
||||
@ -151,7 +152,7 @@
|
||||
ul.tree {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
/* line 277, ../sass/_mixins.scss */
|
||||
/* line 309, ../sass/_mixins.scss */
|
||||
ul.tree li {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
@ -171,8 +172,8 @@ ul.tree {
|
||||
transition: background-color 0.25s;
|
||||
display: block;
|
||||
font-size: 0.8em;
|
||||
height: 1.4rem;
|
||||
line-height: 1.4rem;
|
||||
height: 1.5rem;
|
||||
line-height: 1.5rem;
|
||||
margin-bottom: 3px;
|
||||
position: relative; }
|
||||
/* line 39, ../sass/tree/_tree.scss */
|
||||
@ -326,7 +327,7 @@ ul.tree {
|
||||
ul.tree {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
/* line 277, ../sass/_mixins.scss */
|
||||
/* line 309, ../sass/_mixins.scss */
|
||||
ul.tree li {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
|
@ -1,19 +1,59 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "WTD Symbols v2.",
|
||||
"lastOpened": 1435765696898,
|
||||
"created": 1435764071891
|
||||
"name": "WTD Symbols v2.1",
|
||||
"lastOpened": 1439844340068,
|
||||
"created": 1439844318831
|
||||
},
|
||||
"iconSets": [
|
||||
{
|
||||
"selection": [
|
||||
{
|
||||
"order": 77,
|
||||
"id": 83,
|
||||
"prevSize": 32,
|
||||
"code": 58881,
|
||||
"name": "icon-datatable",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 78,
|
||||
"id": 82,
|
||||
"prevSize": 32,
|
||||
"code": 58882,
|
||||
"name": "icon-tabular-scrolling",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 79,
|
||||
"id": 81,
|
||||
"prevSize": 32,
|
||||
"code": 58884,
|
||||
"name": "icon-tabular",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 80,
|
||||
"id": 80,
|
||||
"prevSize": 32,
|
||||
"code": 58885,
|
||||
"name": "icon-calendar",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 81,
|
||||
"id": 78,
|
||||
"prevSize": 32,
|
||||
"code": 58886,
|
||||
"name": "icon-paint-bucket",
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 1,
|
||||
"id": 75,
|
||||
"prevSize": 32,
|
||||
"code": 123,
|
||||
"name": "icon-pointer-left",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 3,
|
||||
@ -21,7 +61,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 125,
|
||||
"name": "icon-pointer-right",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 4,
|
||||
@ -29,7 +69,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 80,
|
||||
"name": "icon-person",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 5,
|
||||
@ -37,7 +77,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 232,
|
||||
"name": "icon-chain-links",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 6,
|
||||
@ -45,7 +85,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 115,
|
||||
"name": "icon-database-in-brackets",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 7,
|
||||
@ -53,7 +93,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 114,
|
||||
"name": "icon-refresh",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 8,
|
||||
@ -61,7 +101,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 108,
|
||||
"name": "icon-lock",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 9,
|
||||
@ -69,7 +109,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 51,
|
||||
"name": "icon-box-with-dashed-lines",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 10,
|
||||
@ -77,7 +117,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 58880,
|
||||
"name": "icon-box-with-arrow-cursor",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 11,
|
||||
@ -85,7 +125,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 65,
|
||||
"name": "icon-activity-mode",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 12,
|
||||
@ -93,7 +133,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 97,
|
||||
"name": "icon-activity",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 13,
|
||||
@ -101,7 +141,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 33,
|
||||
"name": "icon-alert-rect",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 14,
|
||||
@ -109,7 +149,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 58883,
|
||||
"name": "icon-alert-triangle",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 15,
|
||||
@ -117,7 +157,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 238,
|
||||
"name": "icon-arrow-double-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 16,
|
||||
@ -125,7 +165,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 235,
|
||||
"name": "icon-arrow-double-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 2,
|
||||
@ -133,7 +173,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 118,
|
||||
"name": "icon-arrow-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 19,
|
||||
@ -141,7 +181,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 60,
|
||||
"name": "icon-arrow-left",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 20,
|
||||
@ -149,7 +189,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 62,
|
||||
"name": "icon-arrow-right",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 21,
|
||||
@ -157,7 +197,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 236,
|
||||
"name": "icon-arrow-tall-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 22,
|
||||
@ -165,7 +205,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 237,
|
||||
"name": "icon-arrow-tall-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 23,
|
||||
@ -173,7 +213,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 94,
|
||||
"name": "icon-arrow-up",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 24,
|
||||
@ -181,7 +221,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 73,
|
||||
"name": "icon-arrows-out",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 25,
|
||||
@ -189,7 +229,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 58893,
|
||||
"name": "icon-arrows-right-left",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 33,
|
||||
@ -197,7 +237,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 53,
|
||||
"name": "icon-arrows-up-down",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 26,
|
||||
@ -205,7 +245,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 42,
|
||||
"name": "icon-asterisk",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 27,
|
||||
@ -213,7 +253,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 72,
|
||||
"name": "icon-autoflow-tabular",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 28,
|
||||
@ -221,7 +261,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 224,
|
||||
"name": "icon-box-round-corners",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 29,
|
||||
@ -229,7 +269,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 50,
|
||||
"name": "icon-check",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 30,
|
||||
@ -237,7 +277,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 67,
|
||||
"name": "icon-clock",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 31,
|
||||
@ -245,7 +285,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 46,
|
||||
"name": "icon-connectivity",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 32,
|
||||
@ -253,7 +293,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 100,
|
||||
"name": "icon-database-query",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 17,
|
||||
@ -261,7 +301,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 68,
|
||||
"name": "icon-database",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 35,
|
||||
@ -269,7 +309,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 81,
|
||||
"name": "icon-dictionary",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 36,
|
||||
@ -277,7 +317,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 242,
|
||||
"name": "icon-duplicate",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 37,
|
||||
@ -285,7 +325,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 102,
|
||||
"name": "icon-folder-new",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 38,
|
||||
@ -293,7 +333,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 70,
|
||||
"name": "icon-folder",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 39,
|
||||
@ -301,7 +341,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 95,
|
||||
"name": "icon-fullscreen-collapse",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 40,
|
||||
@ -309,7 +349,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 122,
|
||||
"name": "icon-fullscreen-expand",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 41,
|
||||
@ -317,7 +357,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 71,
|
||||
"name": "icon-gear",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 49,
|
||||
@ -325,7 +365,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 227,
|
||||
"name": "icon-image",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 42,
|
||||
@ -333,7 +373,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 225,
|
||||
"name": "icon-layers",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 43,
|
||||
@ -341,7 +381,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 76,
|
||||
"name": "icon-layout",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 44,
|
||||
@ -349,7 +389,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 226,
|
||||
"name": "icon-line-horz",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 75,
|
||||
@ -357,7 +397,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 244,
|
||||
"name": "icon-link",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 46,
|
||||
@ -365,7 +405,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 88,
|
||||
"name": "icon-magnify-in",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 47,
|
||||
@ -373,7 +413,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 89,
|
||||
"name": "icon-magnify-out",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 48,
|
||||
@ -381,7 +421,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 77,
|
||||
"name": "icon-magnify",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 34,
|
||||
@ -389,7 +429,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 109,
|
||||
"name": "icon-menu",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 50,
|
||||
@ -397,7 +437,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 243,
|
||||
"name": "icon-move",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 51,
|
||||
@ -405,7 +445,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 121,
|
||||
"name": "icon-new-window",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 52,
|
||||
@ -413,7 +453,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 111,
|
||||
"name": "icon-object",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 73,
|
||||
@ -421,7 +461,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 63,
|
||||
"name": "icon-object-unknown",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 53,
|
||||
@ -429,7 +469,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 86,
|
||||
"name": "icon-packet",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 54,
|
||||
@ -437,7 +477,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 234,
|
||||
"name": "icon-page",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 55,
|
||||
@ -445,7 +485,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 241,
|
||||
"name": "icon-pause",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 56,
|
||||
@ -453,7 +493,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 112,
|
||||
"name": "icon-pencil",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 65,
|
||||
@ -461,7 +501,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 79,
|
||||
"name": "icon-people",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 57,
|
||||
@ -469,7 +509,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 239,
|
||||
"name": "icon-play",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 58,
|
||||
@ -477,7 +517,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 233,
|
||||
"name": "icon-plot-resource",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 59,
|
||||
@ -485,7 +525,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 43,
|
||||
"name": "icon-plus",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 60,
|
||||
@ -493,7 +533,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 45,
|
||||
"name": "icon-minus",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 61,
|
||||
@ -501,7 +541,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 54,
|
||||
"name": "icon-sine",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 62,
|
||||
@ -509,7 +549,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 228,
|
||||
"name": "icon-T",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 63,
|
||||
@ -517,7 +557,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 116,
|
||||
"name": "icon-telemetry-panel",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 64,
|
||||
@ -525,7 +565,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 84,
|
||||
"name": "icon-telemetry",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 18,
|
||||
@ -533,7 +573,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 246,
|
||||
"name": "icon-thumbs-strip",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 67,
|
||||
@ -541,7 +581,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 83,
|
||||
"name": "icon-timeline",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 68,
|
||||
@ -549,7 +589,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 245,
|
||||
"name": "icon-timer",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 69,
|
||||
@ -557,7 +597,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 90,
|
||||
"name": "icon-trash",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 70,
|
||||
@ -565,7 +605,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 229,
|
||||
"name": "icon-two-parts-both",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 71,
|
||||
@ -573,7 +613,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 231,
|
||||
"name": "icon-two-parts-one-only",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 72,
|
||||
@ -581,7 +621,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 120,
|
||||
"name": "icon-x-heavy",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 66,
|
||||
@ -589,7 +629,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 58946,
|
||||
"name": "icon-x",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
}
|
||||
],
|
||||
"id": 2,
|
||||
@ -604,6 +644,182 @@
|
||||
"height": 1024,
|
||||
"prevSize": 32,
|
||||
"icons": [
|
||||
{
|
||||
"id": 83,
|
||||
"paths": [
|
||||
"M1024 192c0 106.039-229.23 192-512 192s-512-85.961-512-192c0-106.039 229.23-192 512-192s512 85.961 512 192z",
|
||||
"M512 512c-282.8 0-512-86-512-192v512c0 106 229.2 192 512 192s512-86 512-192v-512c0 106-229.2 192-512 192zM896 575v256c-36.6 15.6-79.8 28.8-128 39.4v-256c48.2-10.6 91.4-23.8 128-39.4zM256 614.4v256c-48.2-10.4-91.4-23.8-128-39.4v-256c36.6 15.6 79.8 28.8 128 39.4zM384 890v-256c41 4 83.8 6 128 6s87-2.2 128-6v256c-41 4-83.8 6-128 6s-87-2.2-128-6z"
|
||||
],
|
||||
"attrs": [
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-datatable"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": [
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 82,
|
||||
"paths": [
|
||||
"M64 0c-35.2 0-64 28.8-64 64v192h448v-256h-384z",
|
||||
"M1024 256v-192c0-35.2-28.8-64-64-64h-384v256h448z",
|
||||
"M0 384v192c0 35.2 28.8 64 64 64h384v-256h-448z",
|
||||
"M960 640c35.2 0 64-28.8 64-64v-192h-448v256h384z",
|
||||
"M512 1024l-256-256h512z"
|
||||
],
|
||||
"attrs": [
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-tabular-scrolling"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 81,
|
||||
"paths": [
|
||||
"M0 64v192h448v-256h-384c-35.2 0-64 28.8-64 64z",
|
||||
"M960 0h-384v256h448v-192c0-35.2-28.8-64-64-64z",
|
||||
"M576 384h448v256h-448v-256z",
|
||||
"M0 384h448v256h-448v-256z",
|
||||
"M0 960c0 35.2 28.8 64 64 64h384v-256h-448v192z",
|
||||
"M576 1024h384c35.2 0 64-28.8 64-64v-192h-448v256z"
|
||||
],
|
||||
"attrs": [
|
||||
{
|
||||
"fill": "#000",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "#000",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "#000",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "#000",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "#000",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "#000",
|
||||
"opacity": 1
|
||||
}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-tabular"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 80,
|
||||
"paths": [
|
||||
"M896 0h-768c-70.4 0-128 57.6-128 128v768c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-768c0-70.4-57.6-128-128-128zM640 448h-256v-192h256v192zM384 512h256v192h-256v-192zM320 704h-256v-192h256v192zM320 256v192h-256v-192h256zM128 960c-17 0-33-6.6-45.2-18.8s-18.8-28.2-18.8-45.2v-128h256v192h-192zM384 960v-192h256v192h-256zM960 896c0 17-6.6 33-18.8 45.2s-28.2 18.8-45.2 18.8h-192v-192h256v128zM960 704h-256v-192h256v192zM960 448h-256v-192h256v192z"
|
||||
],
|
||||
"attrs": [
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-calendar"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": [
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 78,
|
||||
"paths": [
|
||||
"M896 640c0 0-130 188-128 256 2 70.6 57.4 128 128 128s126-57.4 128-128c2-68-128-256-128-256z",
|
||||
"M449 129l0.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 640c-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"
|
||||
],
|
||||
"attrs": [
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
},
|
||||
{
|
||||
"fill": "rgb(6,161,75)",
|
||||
"opacity": 1
|
||||
}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon-paint-bucket"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"125525525516161751": [
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 75,
|
||||
"paths": [
|
||||
@ -1767,7 +1983,24 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"invisible": false
|
||||
"invisible": false,
|
||||
"colorThemes": [
|
||||
[
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
[
|
||||
6,
|
||||
161,
|
||||
75,
|
||||
1
|
||||
]
|
||||
]
|
||||
],
|
||||
"colorThemeIdx": 0
|
||||
},
|
||||
{
|
||||
"selection": [
|
||||
@ -14510,7 +14743,8 @@
|
||||
"selector": "class",
|
||||
"classSelector": ".ui-symbol",
|
||||
"showMetrics": true,
|
||||
"showMetadata": true
|
||||
"showMetadata": true,
|
||||
"embed": false
|
||||
},
|
||||
"imagePref": {
|
||||
"prefix": "icon-",
|
Binary file not shown.
@ -6,78 +6,83 @@
|
||||
<font id="wtdsymbols" horiz-adv-x="1024">
|
||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||
<missing-glyph horiz-adv-x="1024" />
|
||||
<glyph unicode=" " d="" horiz-adv-x="512" />
|
||||
<glyph unicode="!" d="M832 960h-640c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM640 128c0-35.2-28.8-64-64-64h-128c-35.2 0-64 28.8-64 64v64c0 35.2 28.8 64 64 64h128c35.2 0 64-28.8 64-64v-64zM696.062 768.494l-48.124-384.988c-4.366-34.928-36.738-63.506-71.938-63.506h-128c-35.2 0-67.572 28.578-71.938 63.506l-48.124 384.988c-4.366 34.928 20.862 63.506 56.062 63.506h256c35.2 0 60.428-28.578 56.062-63.506z" />
|
||||
<glyph unicode="*" d="M1004.166 619.542l-97.522 168.916-330.534-229.414 33.414 400.956h-195.048l33.414-400.956-330.534 229.414-97.522-168.916 363.944-171.542-363.944-171.542 97.522-168.916 330.534 229.414-33.414-400.956h195.048l-33.414 400.956 330.534-229.414 97.522 168.916-363.944 171.542z" />
|
||||
<glyph unicode="+" d="M960 576h-330v320c0 35.2-28.8 64-64 64h-108c-35.2 0-64-28.8-64-64v-320h-330c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h330v-320c0-35.2 28.8-64 64-64h108c35.2 0 64 28.8 64 64v320h330c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64z" />
|
||||
<glyph unicode="-" d="M960 320c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64h-896c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h896z" />
|
||||
<glyph unicode="." d="M704 384c0-70.4-57.6-128-128-128h-128c-70.4 0-128 57.6-128 128v128c0 70.4 57.6 128 128 128h128c70.4 0 128-57.6 128-128v-128zM1024 448l-192 320v-640zM0 448l192 320v-640z" />
|
||||
<glyph unicode="2" d="M1024 960l-640-640-384 384v-384l384-384 640 640z" />
|
||||
<glyph unicode="3" d="M640 704h-256c-70.4 0-128-57.6-128-128v-256c0-70.4 57.6-128 128-128h256c70.4 0 128 57.6 128 128v256c0 70.4-57.6 128-128 128zM0 960h192v-192h-192v192zM256 960h192v-128h-192v128zM576 960h192v-128h-192v128zM256 64h192v-128h-192v128zM576 64h192v-128h-192v128zM0 384h128v-192h-128v192zM0 704h128v-192h-128v192zM896 384h128v-192h-128v192zM896 704h128v-192h-128v192zM832 960h192v-192h-192v192zM0 128h192v-192h-192v192zM832 128h192v-192h-192v192z" />
|
||||
<glyph unicode="5" d="M512 960l512-448h-1024zM0 384l512-448 512 448z" />
|
||||
<glyph unicode="6" d="M1022.294 448c-1.746 7.196-3.476 14.452-5.186 21.786-20.036 85.992-53.302 208.976-98 306.538-22.42 48.938-45.298 86.556-69.946 115.006-48.454 55.93-98.176 67.67-131.356 67.67s-82.902-11.74-131.356-67.672c-24.648-28.45-47.528-66.068-69.948-115.006-44.696-97.558-77.962-220.544-98-306.538-21.646-92.898-46.444-175.138-71.71-237.836-16.308-40.46-30.222-66.358-40.6-82.604-10.378 16.246-24.292 42.142-40.6 82.604-23.272 57.75-46.144 132.088-66.524 216.052h-197.362c1.746-7.196 3.476-14.452 5.186-21.786 20.036-85.992 53.302-208.976 98-306.538 22.42-48.938 45.298-86.556 69.946-115.006 48.454-55.932 98.176-67.672 131.356-67.672s82.902 11.74 131.356 67.672c24.648 28.45 47.528 66.068 69.948 115.006 44.696 97.558 77.962 220.544 98 306.538 21.646 92.898 46.444 175.138 71.71 237.836 16.308 40.46 30.222 66.358 40.6 82.604 10.378-16.246 24.292-42.142 40.6-82.604 23.274-57.748 46.146-132.086 66.526-216.050h197.36z" />
|
||||
<glyph unicode="<" d="M256 448l512-512v1024z" />
|
||||
<glyph unicode=">" d="M768 448l-512 512v-1024z" />
|
||||
<glyph unicode="?" d="M510 962l-512-320v-384l512-320 512 320v384l-512 320zM585.4 100.8c-21.2-20.8-46-30.8-76-30.8-31.2 0-56.2 9.8-76.2 29.6-20 20-29.6 44.8-29.6 76.2 0 30.4 10.2 55.2 31 76.2s45.2 31.2 74.8 31.2c29.6 0 54.2-10.4 75.6-32s31.8-46.4 31.8-76c-0.2-29-10.8-54-31.4-74.4zM638.2 413.4c-23.6-11.8-37.4-22-43.4-32.4-3.6-6.2-6-14.8-7.4-26.8v-41h-161.4v44.2c0 40.2 4.4 69.8 13 88 8 17.2 22.6 30.2 44.8 40l34.8 15.4c32 14.2 48.2 35.2 48.2 62.8 0 16-6 30.4-17.2 41.8-11.2 11.2-25.6 17.2-41.6 17.2-24 0-54.4-10-62.8-57.4l-2.2-12.2h-147l1.4 16.2c4 44.6 17 82.4 38.8 112.2 19.6 27 45.6 48.6 77 64.6s64.6 24 98.2 24c60.6 0 110.2-19.4 151.4-59.6 41.2-40 61.2-88 61.2-147.2 0-70.8-28.8-121.4-85.8-149.8z" />
|
||||
<glyph unicode="A" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
|
||||
<glyph unicode="C" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM768 384h-256c-35.2 0-64 28.8-64 64v384c0 35.2 28.8 64 64 64s64-28.8 64-64v-320h192c35.2 0 64-28.8 64-64s-28.8-64-64-64z" />
|
||||
<glyph unicode="D" d="M1024 768c0-106.039-229.23-192-512-192s-512 85.961-512 192c0 106.039 229.23 192 512 192s512-85.961 512-192zM512 448c-282.77 0-512 85.962-512 192v-512c0-106.038 229.23-192 512-192s512 85.962 512 192v512c0-106.038-229.23-192-512-192z" />
|
||||
<glyph unicode="F" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128z" />
|
||||
<glyph unicode="G" d="M1024 384v128l-140.976 35.244c-8.784 32.922-21.818 64.106-38.504 92.918l74.774 124.622-90.51 90.51-124.622-74.774c-28.812 16.686-59.996 29.72-92.918 38.504l-35.244 140.976h-128l-35.244-140.976c-32.922-8.784-64.106-21.818-92.918-38.504l-124.622 74.774-90.51-90.51 74.774-124.622c-16.686-28.812-29.72-59.996-38.504-92.918l-140.976-35.244v-128l140.976-35.244c8.784-32.922 21.818-64.106 38.504-92.918l-74.774-124.622 90.51-90.51 124.622 74.774c28.812-16.686 59.996-29.72 92.918-38.504l35.244-140.976h128l35.244 140.976c32.922 8.784 64.106 21.818 92.918 38.504l124.622-74.774 90.51 90.51-74.774 124.622c16.686 28.812 29.72 59.996 38.504 92.918l140.976 35.244zM704 448c0-106.038-85.962-192-192-192s-192 85.962-192 192 85.962 192 192 192 192-85.962 192-192z" />
|
||||
<glyph unicode="H" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
|
||||
<glyph unicode="I" d="M0 448l256-256v512zM512 960l-256-256h512zM512-64l256 256h-512zM768 704v-512l256 256z" />
|
||||
<glyph unicode="L" d="M448 960h-256c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h256v1024zM832 960h-256v-577.664h448v385.664c0 105.6-86.4 192-192 192zM576-64h256c105.6 0 192 86.4 192 192v129.664h-448v-321.664z" />
|
||||
<glyph unicode="M" d="M1024 64l-201.662 201.662c47.922 72.498 73.662 157.434 73.662 246.338 0 119.666-46.6 232.168-131.216 316.784s-197.118 131.216-316.784 131.216-232.168-46.6-316.784-131.216-131.216-197.118-131.216-316.784 46.6-232.168 131.216-316.784 197.118-131.216 316.784-131.216c88.904 0 173.84 25.74 246.338 73.662l201.662-201.662 128 128zM448 256c-141.16 0-256 114.842-256 256 0 141.16 114.84 256 256 256 141.158 0 256-114.84 256-256 0-141.158-114.842-256-256-256z" />
|
||||
<glyph unicode="O" d="M704 640h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM256 640h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM832 576h-192c-34.908 0-67.716-9.448-96-25.904 57.278-33.324 96-95.404 96-166.096v-448h384v448c0 105.6-86.4 192-192 192zM384 576h-192c-105.6 0-192-86.4-192-192v-448h576v448c0 105.6-86.4 192-192 192z" />
|
||||
<glyph unicode="P" d="M768 704c0-105.6-86.4-192-192-192h-128c-105.6 0-192 86.4-192 192v64c0 105.6 86.4 192 192 192h128c105.6 0 192-86.4 192-192v-64zM64-64v192c0 140.8 115.2 256 256 256h384c140.8 0 256-115.2 256-256v-192z" />
|
||||
<glyph unicode="Q" d="M832 320c105.6 0 192 86.4 192 192v256c0 105.6-86.4 192-192 192v-320l-128 64-128-64v320h-384c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v192c0-105.6-86.4-192-192-192h-640v192h640z" />
|
||||
<glyph unicode="S" d="M256 704h384v-128h-384v128zM384 512h384v-128h-384v128zM320 320h384v-128h-384v128zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.2c0 0.2 0.2 0.2 0.4 0.4h127.6v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4z" />
|
||||
<glyph unicode="T" d="M718.6 384h-127.2c25-93.4 48.4-144.4 63.6-168.6 15.2 24.2 38.6 75.2 63.6 168.6zM794.2 207.2c-15.4-35.8-31.2-63.2-48.2-84-18.4-22.4-49-49.2-91-49.2s-72.6 26.8-91 49.2c-17 20.6-32.6 48.2-48.2 84-23.6 54.8-42.8 120.4-56.6 176.8h-457.2c31.4-252.6 247-448 508-448s476.6 195.4 508 448h-167.2c-14-56.4-33-122-56.6-176.8zM301.4 512h127.2c-25 93.4-48.4 144.4-63.6 168.6-15.2-24.2-38.6-75.2-63.6-168.6zM274 772.8c18.4 22.4 49 49.2 91 49.2s72.6-26.8 91-49.2c17-20.6 32.6-48.2 48.2-84 23.6-54.8 42.8-120.4 56.6-176.8h457.2c-31.4 252.6-246.8 448-508 448s-476.6-195.4-508-448h167.2c14 56.4 33 122 56.6 176.8 15.6 35.8 31.4 63.2 48.2 84z" />
|
||||
<glyph unicode="V" d="M511.98 960l-511.98-320v-512c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v512l-512.020 320zM512 768l358.4-224-358.4-224-358.4 224 358.4 224z" />
|
||||
<glyph unicode="X" d="M640 576h-128v128h-128v-128h-128v-128h128v-128h128v128h128zM1024 64l-201.662 201.662c47.922 72.498 73.662 157.434 73.662 246.338 0 119.666-46.6 232.168-131.216 316.784s-197.118 131.216-316.784 131.216c-119.666 0-232.168-46.6-316.784-131.216s-131.216-197.118-131.216-316.784c0-119.666 46.6-232.168 131.216-316.784s197.118-131.216 316.784-131.216c88.904 0 173.84 25.74 246.338 73.662l201.662-201.662 128 128zM448 256c-141.16 0-256 114.842-256 256 0 141.16 114.84 256 256 256 141.158 0 256-114.84 256-256 0-141.158-114.842-256-256-256z" />
|
||||
<glyph unicode="Y" d="M256 576h384v-128h-384v128zM1024 64l-201.662 201.662c47.922 72.498 73.662 157.434 73.662 246.338 0 119.666-46.6 232.168-131.216 316.784s-197.118 131.216-316.784 131.216c-119.666 0-232.168-46.6-316.784-131.216s-131.216-197.118-131.216-316.784c0-119.666 46.6-232.168 131.216-316.784s197.118-131.216 316.784-131.216c88.904 0 173.84 25.74 246.338 73.662l201.662-201.662 128 128zM448 256c-141.16 0-256 114.842-256 256 0 141.16 114.84 256 256 256 141.158 0 256-114.84 256-256 0-141.158-114.842-256-256-256z" />
|
||||
<glyph unicode="Z" d="M832 832h-192.36v64c0 35.2-28.8 64-64 64h-128c-35.2 0-64-28.8-64-64v-64h-191.64c-105.6 0-192-72-192-160s0-160 0-160h64v-384c0-105.6 86.4-192 192-192h512c105.6 0 192 86.4 192 192v384h64c0 0 0 72 0 160s-86.4 160-192 160zM320 128h-128v384h128v-384zM576 128h-128v384h128v-384zM832 128h-128v384h128v-384z" />
|
||||
<glyph unicode="^" d="M512 704l-512-512h1024z" />
|
||||
<glyph unicode="_" d="M191.656 128c0.118-0.1 0.244-0.224 0.344-0.344v-191.656h192v192c0 105.6-86.4 192-192 192h-192v-192h191.656zM192 768.344c-0.1-0.118-0.224-0.244-0.344-0.344h-191.656v-192h192c105.6 0 192 86.4 192 192v192h-192v-191.656zM832 576h192v192h-191.656c-0.118 0.1-0.244 0.226-0.344 0.344v191.656h-192v-192c0-105.6 86.4-192 192-192zM832 127.656c0.1 0.118 0.224 0.244 0.344 0.344h191.656v192h-192c-105.6 0-192-86.4-192-192v-192h192v191.656z" />
|
||||
<glyph unicode="a" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
|
||||
<glyph unicode="d" d="M683.52 140.714c-50.782-28.456-109.284-44.714-171.52-44.714-194.094 0-352 157.906-352 352s157.906 352 352 352 352-157.906 352-352c0-62.236-16.258-120.738-44.714-171.52l191.692-191.692c8.516 13.89 13.022 28.354 13.022 43.212v640c0 106.038-229.23 192-512 192s-512-85.962-512-192v-640c0-106.038 229.23-192 512-192 126.11 0 241.548 17.108 330.776 45.46l-159.256 159.254zM352 448c0-88.224 71.776-160 160-160s160 71.776 160 160-71.776 160-160 160-160-71.776-160-160z" />
|
||||
<glyph unicode="f" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128zM704 160h-128v-128h-128v128h-128v128h128v128h128v-128h128v-128z" />
|
||||
<glyph unicode="l" d="M832 576h-32v96c0 158.8-129.2 288-288 288s-288-129.2-288-288v-96h-32c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h640c70.4 0 128 57.6 128 128v384c0 70.4-57.6 128-128 128zM416 672c0 53 43 96 96 96s96-43 96-96v-96h-192v96z" />
|
||||
<glyph unicode="m" d="M0 960h1024v-256h-1024v256zM0 576h1024v-256h-1024v256zM0 192h1024v-256h-1024v256z" />
|
||||
<glyph unicode="o" d="M512-64l512 320v384l-512.020 320-511.98-320v-384l512-320zM512 768l358.4-224-358.4-224-358.4 224 358.4 224z" />
|
||||
<glyph unicode="p" d="M922.344 858.32c-38.612 38.596-81.306 69.232-120.304 86.324-68.848 30.25-104.77 9.078-120.194-6.344l-516.228-516.216-3.136-9.152-162.482-476.932 485.998 165.612 6.73 6.806 509.502 509.506c9.882 9.866 21.768 27.77 21.768 56.578 0.002 50.71-38.996 121.148-101.654 183.818zM237.982 104.34l-69.73 69.728 69.25 203.228 18.498 6.704h64v-128h128v-64l-6.846-18.506-203.172-69.154z" />
|
||||
<glyph unicode="r" d="M1012.8 545.8v391.6l-127.6-127.4c-96.6 96.8-225.2 150-362 150s-265.2-53.2-362-150c-96.8-96.8-150-225.2-150-362s53.2-265.4 150-362c96.8-96.8 225.2-150 362-150s265.4 53.2 362 150l-136.6 136.6c-124.2-124.2-326.4-124.2-450.8 0-124.2 124.2-124.2 326.4 0 450.8 124.2 124.2 326.4 124.2 450.8 0l-127.4-127.4h391.6z" />
|
||||
<glyph unicode="s" d="M768 608c0-53.019-114.615-96-256-96s-256 42.981-256 96c0 53.019 114.615 96 256 96s256-42.981 256-96zM768 288v256c0-53-114.6-96-256-96s-256 43-256 96v-256c0-53 114.6-96 256-96s256 43 256 96zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.4c0 0.2 0.2 0.2 0.4 0.4h127.6v191.8h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4z" />
|
||||
<glyph unicode="t" d="M169.2 512c14 56.4 33 122 56.6 176.8 15.4 35.8 31.2 63.2 48.2 84 18.4 22.4 49 49.2 91 49.2s72.6-26.8 91-49.2c17-20.6 32.6-48.2 48.2-84 23.6-54.8 42.8-120.4 56.6-176.8h461.2v256c0 105.6-86.4 192-192 192h-640c-105.6 0-192-86.4-192-192v-256h171.2zM718.6 384h-127.2c25-93.4 48.4-144.4 63.6-168.6 15.2 24.2 38.6 75.2 63.6 168.6zM301.4 512h127.2c-25 93.4-48.4 144.4-63.6 168.6-15.2-24.2-38.6-75.2-63.6-168.6zM850.8 384c-14-56.4-33-122-56.6-176.8-15.4-35.8-31.2-63.2-48.2-84-18.4-22.4-49-49.2-91-49.2s-72.6 26.8-91 49.2c-17 20.6-32.6 48.2-48.2 84-23.6 54.8-42.8 120.4-56.6 176.8h-461.2v-256c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v256h-171.2z" />
|
||||
<glyph unicode="v" d="M512 192l512 512h-1024z" />
|
||||
<glyph unicode="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="y" d="M448 960v-128h320l-384-384 128-128 384 384v-320h128v576zM576 285.726v-157.382c-0.1-0.118-0.226-0.244-0.344-0.344h-383.312c-0.118 0.1-0.244 0.226-0.344 0.344v383.312c0.1 0.118 0.226 0.244 0.344 0.344h157.382l192 192h-349.726c-105.6 0-192-86.4-192-192v-384c0-105.6 86.4-192 192-192h384c105.6 0 192 86.4 192 192v349.726l-192-192z" />
|
||||
<glyph unicode="z" d="M192.344 128c-0.118 0.1-0.244 0.224-0.344 0.344v191.656h-192v-192c0-105.6 86.4-192 192-192h192v192h-191.656zM192 767.656c0.1 0.118 0.224 0.244 0.344 0.344h191.656v192h-192c-105.6 0-192-86.4-192-192v-192h192v191.656zM832 960h-192v-192h191.656c0.118-0.1 0.244-0.226 0.344-0.344v-191.656h192v192c0 105.6-86.4 192-192 192zM832 128.344c-0.1-0.118-0.224-0.244-0.344-0.344h-191.656v-192h192c105.6 0 192 86.4 192 192v192h-192v-191.656z" />
|
||||
<glyph unicode="{" d="M510-64l-256 512 256 512h-256l-256-512 256-512z" horiz-adv-x="512" />
|
||||
<glyph unicode="}" d="M-2 960l256-512-256-512h256l256 512-256 512z" horiz-adv-x="512" />
|
||||
<glyph unicode="à" d="M1024 128c0-105.6-86.4-192-192-192h-640c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-640z" />
|
||||
<glyph unicode="á" d="M1024 576l-512 384-512-384 512-384zM512 64l-426.666 320-85.334-64 512-384 512 384-85.334 64z" />
|
||||
<glyph unicode="â" d="M64 384c-35.346 0-64 28.654-64 64s28.654 64 64 64h896c35.346 0 64-28.654 64-64s-28.654-64-64-64h-896z" />
|
||||
<glyph unicode="ã" 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 128zM896 64h-768v768h768v-768zM320 704l-128-128v-448h640v320l-128 128-128-128z" />
|
||||
<glyph unicode="ä" d="M0 960v-256h128v64h256v-704h-192v-128h640v128h-192v704h256v-64h128v256z" />
|
||||
<glyph unicode="å" 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 128zM128 832h320v-768h-320v768zM896 64h-320v768h320v-768z" />
|
||||
<glyph unicode="ç" 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 128zM896 64h-320v768h320v-768z" />
|
||||
<glyph unicode="è" d="M958.4 894.4c-43.8 43.8-101 65.6-158.4 65.6s-114.6-21.8-158.4-65.6l-128-128c-74-74-85.4-187-34-273l-12.8-12.8c-35.4 20.8-75 31.4-114.8 31.4-57.4 0-114.6-21.8-158.4-65.6l-128-128c-87.4-87.4-87.4-229.4 0-316.8 43.8-43.8 101-65.6 158.4-65.6s114.6 21.8 158.4 65.6l128 128c74 74 85.4 187 34 273l12.8 12.8c35.2-21 75-31.6 114.6-31.6 57.4 0 114.6 21.8 158.4 65.6l128 128c87.6 87.6 87.6 229.6 0.2 317zM419.8 220.2l-128-128c-18-18.2-42.2-28.2-67.8-28.2s-49.8 10-67.8 28.2c-37.4 37.4-37.4 98.4 0 135.8l128 128c18.2 18.2 42.2 28.2 67.8 28.2 5.6 0 11.2-0.6 16.8-1.4l-55.6-55.6c-10.4-10.4-16.2-24.2-16.2-38.8s5.8-28.6 16.2-38.8c10.4-10.4 24.2-16.2 38.8-16.2s28.6 5.8 38.8 16.2l55.6 55.6c5.4-30.4-3.6-62.2-26.6-85zM867.8 668.2l-128-128c-18-18.2-42.2-28.2-67.8-28.2-5.6 0-11.2 0.6-16.8 1.4l55.6 55.6c10.4 10.4 16.2 24.2 16.2 38.8s-5.8 28.6-16.2 38.8c-10.4 10.4-24.2 16.2-38.8 16.2s-28.6-5.8-38.8-16.2l-55.6-55.6c-5.2 29.8 3.6 61.6 26.6 84.6l128 128c18 18.4 42.2 28.4 67.8 28.4s49.8-10 67.8-28.2c37.6-37.4 37.6-98.2 0-135.6z" />
|
||||
<glyph unicode="é" d="M255.884 256c0.040 0.034 0.082 0.074 0.116 0.116v127.884c0 70.58 57.42 128 128 128h255.884c0.040 0.034 0.082 0.074 0.116 0.116v127.884c0 70.58 57.42 128 128 128h143.658c-93.832 117.038-237.98 192-399.658 192-282.77 0-512-229.23-512-512 0-67.904 13.25-132.704 37.256-192h218.628zM768.116 640c-0.040-0.034-0.082-0.074-0.116-0.116v-127.884c0-70.58-57.42-128-128-128h-255.884c-0.040-0.034-0.082-0.074-0.116-0.116v-127.884c0-70.58-57.42-128-128-128h-143.658c93.832-117.038 237.98-192 399.658-192 282.77 0 512 229.23 512 512 0 67.904-13.25 132.704-37.256 192h-218.628z" />
|
||||
<glyph unicode="ê" d="M702 452c-105.6 0-192 86.4-192 192v320h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v320h-320zM766 580h256l-384 384v-256c0-70.4 57.6-128 128-128z" />
|
||||
<glyph unicode="ë" d="M510 450l512-512h-1024zM510 962l512-512h-1024z" />
|
||||
<glyph unicode="ì" d="M512-64l-512 1024h1024z" />
|
||||
<glyph unicode="í" d="M512 960l512-1024h-1024z" />
|
||||
<glyph unicode="î" d="M510 450l-512 512h1024zM510-62l-512 512h1024z" />
|
||||
<glyph unicode="ï" d="M1024 448l-1024-512v1024z" />
|
||||
<glyph unicode="ñ" d="M126 962h256v-1024h-256v1024zM638 962h256v-1024h-256v1024z" />
|
||||
<glyph unicode="ò" d="M640 704v128c0 70.4-57.6 128-128 128h-384c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h128v139.6c0 134.8 109.6 244.4 244.4 244.4h139.6zM896 576h-384c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h384c70.4 0 128 57.6 128 128v384c0 70.4-57.6 128-128 128z" />
|
||||
<glyph unicode="ó" d="M293.4 448l218.6 218.6 256-256v421.4c0 70.4-57.6 128-128 128h-512c-70.4 0-128-57.6-128-128v-512c0-70.4 57.6-128 128-128h421.4l-256 256zM1024 512h-128v-320l-384 384-128-128 384-384h-320v-128h576z" />
|
||||
<glyph unicode="ô" d="M1024 448l-512 512v-307.2l-512-204.8v-256h512v-256z" />
|
||||
<glyph unicode="õ" d="M638 898c0 35.4-28.6 64-64 64h-128c-35.4 0-64-28.6-64-64s28.6-64 64-64h128c35.4 0 64 28.6 64 64zM510 834c-247.4 0-448-200.6-448-448s200.6-448 448-448 448 200.6 448 448-200.6 448-448 448zM510 386h-336c0 185.2 150.8 336 336 336v-336z" />
|
||||
<glyph unicode="ö" d="M448 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM448 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320z" />
|
||||
<glyph unicode="" d="M832 447.6c0 0.2 0 0.2 0 0.4v320c0 105.6-86.4 192-192 192h-448c-105.6 0-192-86.4-192-192v-320c0-105.6 86.4-192 192-192h263.6l-197.2 445.6 573.6-254zM766.8 300.2l193.8 20.4-576.6 255.4 255.4-576.6 20.4 193.8 257-257.2 107.2 107.2z" />
|
||||
<glyph unicode="" d="M998.208 111.136l-422.702 739.728c-34.928 61.124-92.084 61.124-127.012 0l-422.702-739.728c-34.928-61.126-5.906-111.136 64.494-111.136h843.428c70.4 0 99.422 50.010 64.494 111.136zM512 128c-35.2 0-64 28.8-64 64s28.8 64 64 64 64-28.8 64-64c0-35.2-28.8-64-64-64zM627.448 577.242l-38.898-194.486c-6.902-34.516-41.35-62.756-76.55-62.756s-69.648 28.24-76.552 62.758l-38.898 194.486c-6.902 34.516 16.25 62.756 51.45 62.756h128c35.2 0 58.352-28.24 51.448-62.758z" />
|
||||
<glyph unicode="" d="M1024 448l-448-512v1024zM448 960l-448-512 448-512z" />
|
||||
<glyph unicode="" 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=" " horiz-adv-x="512" d="" />
|
||||
<glyph unicode="!" glyph-name="icon-alert-rect" d="M832 960h-640c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM640 128c0-35.2-28.8-64-64-64h-128c-35.2 0-64 28.8-64 64v64c0 35.2 28.8 64 64 64h128c35.2 0 64-28.8 64-64v-64zM696.062 768.494l-48.124-384.988c-4.366-34.928-36.738-63.506-71.938-63.506h-128c-35.2 0-67.572 28.578-71.938 63.506l-48.124 384.988c-4.366 34.928 20.862 63.506 56.062 63.506h256c35.2 0 60.428-28.578 56.062-63.506z" />
|
||||
<glyph unicode="*" glyph-name="icon-asterisk" d="M1004.166 619.542l-97.522 168.916-330.534-229.414 33.414 400.956h-195.048l33.414-400.956-330.534 229.414-97.522-168.916 363.944-171.542-363.944-171.542 97.522-168.916 330.534 229.414-33.414-400.956h195.048l-33.414 400.956 330.534-229.414 97.522 168.916-363.944 171.542z" />
|
||||
<glyph unicode="+" glyph-name="icon-plus" d="M960 576h-330v320c0 35.2-28.8 64-64 64h-108c-35.2 0-64-28.8-64-64v-320h-330c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h330v-320c0-35.2 28.8-64 64-64h108c35.2 0 64 28.8 64 64v320h330c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64z" />
|
||||
<glyph unicode="-" glyph-name="icon-minus" d="M960 320c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64h-896c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h896z" />
|
||||
<glyph unicode="." glyph-name="icon-connectivity" d="M704 384c0-70.4-57.6-128-128-128h-128c-70.4 0-128 57.6-128 128v128c0 70.4 57.6 128 128 128h128c70.4 0 128-57.6 128-128v-128zM1024 448l-192 320v-640zM0 448l192 320v-640z" />
|
||||
<glyph unicode="2" glyph-name="icon-check" d="M1024 960l-640-640-384 384v-384l384-384 640 640z" />
|
||||
<glyph unicode="3" glyph-name="icon-box-with-dashed-lines" d="M640 704h-256c-70.4 0-128-57.6-128-128v-256c0-70.4 57.6-128 128-128h256c70.4 0 128 57.6 128 128v256c0 70.4-57.6 128-128 128zM0 960h192v-192h-192v192zM256 960h192v-128h-192v128zM576 960h192v-128h-192v128zM256 64h192v-128h-192v128zM576 64h192v-128h-192v128zM0 384h128v-192h-128v192zM0 704h128v-192h-128v192zM896 384h128v-192h-128v192zM896 704h128v-192h-128v192zM832 960h192v-192h-192v192zM0 128h192v-192h-192v192zM832 128h192v-192h-192v192z" />
|
||||
<glyph unicode="5" glyph-name="icon-arrows-up-down" d="M512 960l512-448h-1024zM0 384l512-448 512 448z" />
|
||||
<glyph unicode="6" glyph-name="icon-sine" d="M1022.294 448c-1.746 7.196-3.476 14.452-5.186 21.786-20.036 85.992-53.302 208.976-98 306.538-22.42 48.938-45.298 86.556-69.946 115.006-48.454 55.93-98.176 67.67-131.356 67.67s-82.902-11.74-131.356-67.672c-24.648-28.45-47.528-66.068-69.948-115.006-44.696-97.558-77.962-220.544-98-306.538-21.646-92.898-46.444-175.138-71.71-237.836-16.308-40.46-30.222-66.358-40.6-82.604-10.378 16.246-24.292 42.142-40.6 82.604-23.272 57.75-46.144 132.088-66.524 216.052h-197.362c1.746-7.196 3.476-14.452 5.186-21.786 20.036-85.992 53.302-208.976 98-306.538 22.42-48.938 45.298-86.556 69.946-115.006 48.454-55.932 98.176-67.672 131.356-67.672s82.902 11.74 131.356 67.672c24.648 28.45 47.528 66.068 69.948 115.006 44.696 97.558 77.962 220.544 98 306.538 21.646 92.898 46.444 175.138 71.71 237.836 16.308 40.46 30.222 66.358 40.6 82.604 10.378-16.246 24.292-42.142 40.6-82.604 23.274-57.748 46.146-132.086 66.526-216.050h197.36z" />
|
||||
<glyph unicode="<" glyph-name="icon-arrow-left" d="M256 448l512-512v1024z" />
|
||||
<glyph unicode=">" glyph-name="icon-arrow-right" d="M768 448l-512 512v-1024z" />
|
||||
<glyph unicode="?" glyph-name="icon-object-unknown" d="M510 962l-512-320v-384l512-320 512 320v384l-512 320zM585.4 100.8c-21.2-20.8-46-30.8-76-30.8-31.2 0-56.2 9.8-76.2 29.6-20 20-29.6 44.8-29.6 76.2 0 30.4 10.2 55.2 31 76.2s45.2 31.2 74.8 31.2c29.6 0 54.2-10.4 75.6-32s31.8-46.4 31.8-76c-0.2-29-10.8-54-31.4-74.4zM638.2 413.4c-23.6-11.8-37.4-22-43.4-32.4-3.6-6.2-6-14.8-7.4-26.8v-41h-161.4v44.2c0 40.2 4.4 69.8 13 88 8 17.2 22.6 30.2 44.8 40l34.8 15.4c32 14.2 48.2 35.2 48.2 62.8 0 16-6 30.4-17.2 41.8-11.2 11.2-25.6 17.2-41.6 17.2-24 0-54.4-10-62.8-57.4l-2.2-12.2h-147l1.4 16.2c4 44.6 17 82.4 38.8 112.2 19.6 27 45.6 48.6 77 64.6s64.6 24 98.2 24c60.6 0 110.2-19.4 151.4-59.6 41.2-40 61.2-88 61.2-147.2 0-70.8-28.8-121.4-85.8-149.8z" />
|
||||
<glyph unicode="A" glyph-name="icon-activity-mode" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
|
||||
<glyph unicode="C" glyph-name="icon-clock" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM768 384h-256c-35.2 0-64 28.8-64 64v384c0 35.2 28.8 64 64 64s64-28.8 64-64v-320h192c35.2 0 64-28.8 64-64s-28.8-64-64-64z" />
|
||||
<glyph unicode="D" glyph-name="icon-database" d="M1024 768c0-106.039-229.23-192-512-192s-512 85.961-512 192c0 106.039 229.23 192 512 192s512-85.961 512-192zM512 448c-282.77 0-512 85.962-512 192v-512c0-106.038 229.23-192 512-192s512 85.962 512 192v512c0-106.038-229.23-192-512-192z" />
|
||||
<glyph unicode="F" glyph-name="icon-folder" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128z" />
|
||||
<glyph unicode="G" glyph-name="icon-gear" d="M1024 384v128l-140.976 35.244c-8.784 32.922-21.818 64.106-38.504 92.918l74.774 124.622-90.51 90.51-124.622-74.774c-28.812 16.686-59.996 29.72-92.918 38.504l-35.244 140.976h-128l-35.244-140.976c-32.922-8.784-64.106-21.818-92.918-38.504l-124.622 74.774-90.51-90.51 74.774-124.622c-16.686-28.812-29.72-59.996-38.504-92.918l-140.976-35.244v-128l140.976-35.244c8.784-32.922 21.818-64.106 38.504-92.918l-74.774-124.622 90.51-90.51 124.622 74.774c28.812-16.686 59.996-29.72 92.918-38.504l35.244-140.976h128l35.244 140.976c32.922 8.784 64.106 21.818 92.918 38.504l124.622-74.774 90.51 90.51-74.774 124.622c16.686 28.812 29.72 59.996 38.504 92.918l140.976 35.244zM704 448c0-106.038-85.962-192-192-192s-192 85.962-192 192 85.962 192 192 192 192-85.962 192-192z" />
|
||||
<glyph unicode="H" glyph-name="icon-autoflow-tabular" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
|
||||
<glyph unicode="I" glyph-name="icon-arrows-out" d="M0 448l256-256v512zM512 960l-256-256h512zM512-64l256 256h-512zM768 704v-512l256 256z" />
|
||||
<glyph unicode="L" glyph-name="icon-layout" d="M448 960h-256c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h256v1024zM832 960h-256v-577.664h448v385.664c0 105.6-86.4 192-192 192zM576-64h256c105.6 0 192 86.4 192 192v129.664h-448v-321.664z" />
|
||||
<glyph unicode="M" glyph-name="icon-magnify" d="M1024 64l-201.662 201.662c47.922 72.498 73.662 157.434 73.662 246.338 0 119.666-46.6 232.168-131.216 316.784s-197.118 131.216-316.784 131.216-232.168-46.6-316.784-131.216-131.216-197.118-131.216-316.784 46.6-232.168 131.216-316.784 197.118-131.216 316.784-131.216c88.904 0 173.84 25.74 246.338 73.662l201.662-201.662 128 128zM448 256c-141.16 0-256 114.842-256 256 0 141.16 114.84 256 256 256 141.158 0 256-114.84 256-256 0-141.158-114.842-256-256-256z" />
|
||||
<glyph unicode="O" glyph-name="icon-people" d="M704 640h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM256 640h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM832 576h-192c-34.908 0-67.716-9.448-96-25.904 57.278-33.324 96-95.404 96-166.096v-448h384v448c0 105.6-86.4 192-192 192zM384 576h-192c-105.6 0-192-86.4-192-192v-448h576v448c0 105.6-86.4 192-192 192z" />
|
||||
<glyph unicode="P" glyph-name="icon-person" d="M768 704c0-105.6-86.4-192-192-192h-128c-105.6 0-192 86.4-192 192v64c0 105.6 86.4 192 192 192h128c105.6 0 192-86.4 192-192v-64zM64-64v192c0 140.8 115.2 256 256 256h384c140.8 0 256-115.2 256-256v-192z" />
|
||||
<glyph unicode="Q" glyph-name="icon-dictionary" d="M832 320c105.6 0 192 86.4 192 192v256c0 105.6-86.4 192-192 192v-320l-128 64-128-64v320h-384c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v192c0-105.6-86.4-192-192-192h-640v192h640z" />
|
||||
<glyph unicode="S" glyph-name="icon-timeline" d="M256 704h384v-128h-384v128zM384 512h384v-128h-384v128zM320 320h384v-128h-384v128zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.2c0 0.2 0.2 0.2 0.4 0.4h127.6v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4z" />
|
||||
<glyph unicode="T" glyph-name="icon-telemetry" d="M718.6 384h-127.2c25-93.4 48.4-144.4 63.6-168.6 15.2 24.2 38.6 75.2 63.6 168.6zM794.2 207.2c-15.4-35.8-31.2-63.2-48.2-84-18.4-22.4-49-49.2-91-49.2s-72.6 26.8-91 49.2c-17 20.6-32.6 48.2-48.2 84-23.6 54.8-42.8 120.4-56.6 176.8h-457.2c31.4-252.6 247-448 508-448s476.6 195.4 508 448h-167.2c-14-56.4-33-122-56.6-176.8zM301.4 512h127.2c-25 93.4-48.4 144.4-63.6 168.6-15.2-24.2-38.6-75.2-63.6-168.6zM274 772.8c18.4 22.4 49 49.2 91 49.2s72.6-26.8 91-49.2c17-20.6 32.6-48.2 48.2-84 23.6-54.8 42.8-120.4 56.6-176.8h457.2c-31.4 252.6-246.8 448-508 448s-476.6-195.4-508-448h167.2c14 56.4 33 122 56.6 176.8 15.6 35.8 31.4 63.2 48.2 84z" />
|
||||
<glyph unicode="V" glyph-name="icon-packet" d="M511.98 960l-511.98-320v-512c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v512l-512.020 320zM512 768l358.4-224-358.4-224-358.4 224 358.4 224z" />
|
||||
<glyph unicode="X" glyph-name="icon-magnify-in" d="M640 576h-128v128h-128v-128h-128v-128h128v-128h128v128h128zM1024 64l-201.662 201.662c47.922 72.498 73.662 157.434 73.662 246.338 0 119.666-46.6 232.168-131.216 316.784s-197.118 131.216-316.784 131.216c-119.666 0-232.168-46.6-316.784-131.216s-131.216-197.118-131.216-316.784c0-119.666 46.6-232.168 131.216-316.784s197.118-131.216 316.784-131.216c88.904 0 173.84 25.74 246.338 73.662l201.662-201.662 128 128zM448 256c-141.16 0-256 114.842-256 256 0 141.16 114.84 256 256 256 141.158 0 256-114.84 256-256 0-141.158-114.842-256-256-256z" />
|
||||
<glyph unicode="Y" glyph-name="icon-magnify-out" d="M256 576h384v-128h-384v128zM1024 64l-201.662 201.662c47.922 72.498 73.662 157.434 73.662 246.338 0 119.666-46.6 232.168-131.216 316.784s-197.118 131.216-316.784 131.216c-119.666 0-232.168-46.6-316.784-131.216s-131.216-197.118-131.216-316.784c0-119.666 46.6-232.168 131.216-316.784s197.118-131.216 316.784-131.216c88.904 0 173.84 25.74 246.338 73.662l201.662-201.662 128 128zM448 256c-141.16 0-256 114.842-256 256 0 141.16 114.84 256 256 256 141.158 0 256-114.84 256-256 0-141.158-114.842-256-256-256z" />
|
||||
<glyph unicode="Z" glyph-name="icon-trash" d="M832 832h-192.36v64c0 35.2-28.8 64-64 64h-128c-35.2 0-64-28.8-64-64v-64h-191.64c-105.6 0-192-72-192-160s0-160 0-160h64v-384c0-105.6 86.4-192 192-192h512c105.6 0 192 86.4 192 192v384h64c0 0 0 72 0 160s-86.4 160-192 160zM320 128h-128v384h128v-384zM576 128h-128v384h128v-384zM832 128h-128v384h128v-384z" />
|
||||
<glyph unicode="^" glyph-name="icon-arrow-up" d="M512 704l-512-512h1024z" />
|
||||
<glyph unicode="_" glyph-name="icon-fullscreen-collapse" d="M191.656 128c0.118-0.1 0.244-0.224 0.344-0.344v-191.656h192v192c0 105.6-86.4 192-192 192h-192v-192h191.656zM192 768.344c-0.1-0.118-0.224-0.244-0.344-0.344h-191.656v-192h192c105.6 0 192 86.4 192 192v192h-192v-191.656zM832 576h192v192h-191.656c-0.118 0.1-0.244 0.226-0.344 0.344v191.656h-192v-192c0-105.6 86.4-192 192-192zM832 127.656c0.1 0.118 0.224 0.244 0.344 0.344h191.656v192h-192c-105.6 0-192-86.4-192-192v-192h192v191.656z" />
|
||||
<glyph unicode="a" glyph-name="icon-activity" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
|
||||
<glyph unicode="d" glyph-name="icon-database-query" d="M683.52 140.714c-50.782-28.456-109.284-44.714-171.52-44.714-194.094 0-352 157.906-352 352s157.906 352 352 352 352-157.906 352-352c0-62.236-16.258-120.738-44.714-171.52l191.692-191.692c8.516 13.89 13.022 28.354 13.022 43.212v640c0 106.038-229.23 192-512 192s-512-85.962-512-192v-640c0-106.038 229.23-192 512-192 126.11 0 241.548 17.108 330.776 45.46l-159.256 159.254zM352 448c0-88.224 71.776-160 160-160s160 71.776 160 160-71.776 160-160 160-160-71.776-160-160z" />
|
||||
<glyph unicode="f" glyph-name="icon-folder-new" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128zM704 160h-128v-128h-128v128h-128v128h128v128h128v-128h128v-128z" />
|
||||
<glyph unicode="l" glyph-name="icon-lock" d="M832 576h-32v96c0 158.8-129.2 288-288 288s-288-129.2-288-288v-96h-32c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h640c70.4 0 128 57.6 128 128v384c0 70.4-57.6 128-128 128zM416 672c0 53 43 96 96 96s96-43 96-96v-96h-192v96z" />
|
||||
<glyph unicode="m" glyph-name="icon-menu" d="M0 960h1024v-256h-1024v256zM0 576h1024v-256h-1024v256zM0 192h1024v-256h-1024v256z" />
|
||||
<glyph unicode="o" glyph-name="icon-object" d="M512-64l512 320v384l-512.020 320-511.98-320v-384l512-320zM512 768l358.4-224-358.4-224-358.4 224 358.4 224z" />
|
||||
<glyph unicode="p" glyph-name="icon-pencil" d="M922.344 858.32c-38.612 38.596-81.306 69.232-120.304 86.324-68.848 30.25-104.77 9.078-120.194-6.344l-516.228-516.216-3.136-9.152-162.482-476.932 485.998 165.612 6.73 6.806 509.502 509.506c9.882 9.866 21.768 27.77 21.768 56.578 0.002 50.71-38.996 121.148-101.654 183.818zM237.982 104.34l-69.73 69.728 69.25 203.228 18.498 6.704h64v-128h128v-64l-6.846-18.506-203.172-69.154z" />
|
||||
<glyph unicode="r" glyph-name="icon-refresh" d="M1012.8 545.8v391.6l-127.6-127.4c-96.6 96.8-225.2 150-362 150s-265.2-53.2-362-150c-96.8-96.8-150-225.2-150-362s53.2-265.4 150-362c96.8-96.8 225.2-150 362-150s265.4 53.2 362 150l-136.6 136.6c-124.2-124.2-326.4-124.2-450.8 0-124.2 124.2-124.2 326.4 0 450.8 124.2 124.2 326.4 124.2 450.8 0l-127.4-127.4h391.6z" />
|
||||
<glyph unicode="s" glyph-name="icon-database-in-brackets" d="M768 608c0-53.019-114.615-96-256-96s-256 42.981-256 96c0 53.019 114.615 96 256 96s256-42.981 256-96zM768 288v256c0-53-114.6-96-256-96s-256 43-256 96v-256c0-53 114.6-96 256-96s256 43 256 96zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.4c0 0.2 0.2 0.2 0.4 0.4h127.6v191.8h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4z" />
|
||||
<glyph unicode="t" glyph-name="icon-telemetry-panel" d="M169.2 512c14 56.4 33 122 56.6 176.8 15.4 35.8 31.2 63.2 48.2 84 18.4 22.4 49 49.2 91 49.2s72.6-26.8 91-49.2c17-20.6 32.6-48.2 48.2-84 23.6-54.8 42.8-120.4 56.6-176.8h461.2v256c0 105.6-86.4 192-192 192h-640c-105.6 0-192-86.4-192-192v-256h171.2zM718.6 384h-127.2c25-93.4 48.4-144.4 63.6-168.6 15.2 24.2 38.6 75.2 63.6 168.6zM301.4 512h127.2c-25 93.4-48.4 144.4-63.6 168.6-15.2-24.2-38.6-75.2-63.6-168.6zM850.8 384c-14-56.4-33-122-56.6-176.8-15.4-35.8-31.2-63.2-48.2-84-18.4-22.4-49-49.2-91-49.2s-72.6 26.8-91 49.2c-17 20.6-32.6 48.2-48.2 84-23.6 54.8-42.8 120.4-56.6 176.8h-461.2v-256c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v256h-171.2z" />
|
||||
<glyph unicode="v" glyph-name="icon-arrow-down" d="M512 192l512 512h-1024z" />
|
||||
<glyph unicode="x" glyph-name="icon-x-heavy" 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="y" glyph-name="icon-new-window" d="M448 960v-128h320l-384-384 128-128 384 384v-320h128v576zM576 285.726v-157.382c-0.1-0.118-0.226-0.244-0.344-0.344h-383.312c-0.118 0.1-0.244 0.226-0.344 0.344v383.312c0.1 0.118 0.226 0.244 0.344 0.344h157.382l192 192h-349.726c-105.6 0-192-86.4-192-192v-384c0-105.6 86.4-192 192-192h384c105.6 0 192 86.4 192 192v349.726l-192-192z" />
|
||||
<glyph unicode="z" glyph-name="icon-fullscreen-expand" d="M192.344 128c-0.118 0.1-0.244 0.224-0.344 0.344v191.656h-192v-192c0-105.6 86.4-192 192-192h192v192h-191.656zM192 767.656c0.1 0.118 0.224 0.244 0.344 0.344h191.656v192h-192c-105.6 0-192-86.4-192-192v-192h192v191.656zM832 960h-192v-192h191.656c0.118-0.1 0.244-0.226 0.344-0.344v-191.656h192v192c0 105.6-86.4 192-192 192zM832 128.344c-0.1-0.118-0.224-0.244-0.344-0.344h-191.656v-192h192c105.6 0 192 86.4 192 192v192h-192v-191.656z" />
|
||||
<glyph unicode="{" glyph-name="icon-pointer-left" horiz-adv-x="512" d="M510-64l-256 512 256 512h-256l-256-512 256-512z" />
|
||||
<glyph unicode="}" glyph-name="icon-pointer-right" horiz-adv-x="512" d="M-2 960l256-512-256-512h256l256 512-256 512z" />
|
||||
<glyph unicode="à" glyph-name="icon-box-round-corners" d="M1024 128c0-105.6-86.4-192-192-192h-640c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-640z" />
|
||||
<glyph unicode="á" glyph-name="icon-layers" d="M1024 576l-512 384-512-384 512-384zM512 64l-426.666 320-85.334-64 512-384 512 384-85.334 64z" />
|
||||
<glyph unicode="â" glyph-name="icon-line-horz" d="M64 384c-35.346 0-64 28.654-64 64s28.654 64 64 64h896c35.346 0 64-28.654 64-64s-28.654-64-64-64h-896z" />
|
||||
<glyph unicode="ã" glyph-name="icon-image" 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 128zM896 64h-768v768h768v-768zM320 704l-128-128v-448h640v320l-128 128-128-128z" />
|
||||
<glyph unicode="ä" glyph-name="icon-T" d="M0 960v-256h128v64h256v-704h-192v-128h640v128h-192v704h256v-64h128v256z" />
|
||||
<glyph unicode="å" glyph-name="icon-two-parts-both" 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 128zM128 832h320v-768h-320v768zM896 64h-320v768h320v-768z" />
|
||||
<glyph unicode="ç" glyph-name="icon-two-parts-one-only" 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 128zM896 64h-320v768h320v-768z" />
|
||||
<glyph unicode="è" glyph-name="icon-chain-links" d="M958.4 894.4c-43.8 43.8-101 65.6-158.4 65.6s-114.6-21.8-158.4-65.6l-128-128c-74-74-85.4-187-34-273l-12.8-12.8c-35.4 20.8-75 31.4-114.8 31.4-57.4 0-114.6-21.8-158.4-65.6l-128-128c-87.4-87.4-87.4-229.4 0-316.8 43.8-43.8 101-65.6 158.4-65.6s114.6 21.8 158.4 65.6l128 128c74 74 85.4 187 34 273l12.8 12.8c35.2-21 75-31.6 114.6-31.6 57.4 0 114.6 21.8 158.4 65.6l128 128c87.6 87.6 87.6 229.6 0.2 317zM419.8 220.2l-128-128c-18-18.2-42.2-28.2-67.8-28.2s-49.8 10-67.8 28.2c-37.4 37.4-37.4 98.4 0 135.8l128 128c18.2 18.2 42.2 28.2 67.8 28.2 5.6 0 11.2-0.6 16.8-1.4l-55.6-55.6c-10.4-10.4-16.2-24.2-16.2-38.8s5.8-28.6 16.2-38.8c10.4-10.4 24.2-16.2 38.8-16.2s28.6 5.8 38.8 16.2l55.6 55.6c5.4-30.4-3.6-62.2-26.6-85zM867.8 668.2l-128-128c-18-18.2-42.2-28.2-67.8-28.2-5.6 0-11.2 0.6-16.8 1.4l55.6 55.6c10.4 10.4 16.2 24.2 16.2 38.8s-5.8 28.6-16.2 38.8c-10.4 10.4-24.2 16.2-38.8 16.2s-28.6-5.8-38.8-16.2l-55.6-55.6c-5.2 29.8 3.6 61.6 26.6 84.6l128 128c18 18.4 42.2 28.4 67.8 28.4s49.8-10 67.8-28.2c37.6-37.4 37.6-98.2 0-135.6z" />
|
||||
<glyph unicode="é" glyph-name="icon-plot-resource" d="M255.884 256c0.040 0.034 0.082 0.074 0.116 0.116v127.884c0 70.58 57.42 128 128 128h255.884c0.040 0.034 0.082 0.074 0.116 0.116v127.884c0 70.58 57.42 128 128 128h143.658c-93.832 117.038-237.98 192-399.658 192-282.77 0-512-229.23-512-512 0-67.904 13.25-132.704 37.256-192h218.628zM768.116 640c-0.040-0.034-0.082-0.074-0.116-0.116v-127.884c0-70.58-57.42-128-128-128h-255.884c-0.040-0.034-0.082-0.074-0.116-0.116v-127.884c0-70.58-57.42-128-128-128h-143.658c93.832-117.038 237.98-192 399.658-192 282.77 0 512 229.23 512 512 0 67.904-13.25 132.704-37.256 192h-218.628z" />
|
||||
<glyph unicode="ê" glyph-name="icon-page" d="M702 452c-105.6 0-192 86.4-192 192v320h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v320h-320zM766 580h256l-384 384v-256c0-70.4 57.6-128 128-128z" />
|
||||
<glyph unicode="ë" glyph-name="icon-arrow-double-up" d="M510 450l512-512h-1024zM510 962l512-512h-1024z" />
|
||||
<glyph unicode="ì" glyph-name="icon-arrow-tall-down" d="M512-64l-512 1024h1024z" />
|
||||
<glyph unicode="í" glyph-name="icon-arrow-tall-up" d="M512 960l512-1024h-1024z" />
|
||||
<glyph unicode="î" glyph-name="icon-arrow-double-down" d="M510 450l-512 512h1024zM510-62l-512 512h1024z" />
|
||||
<glyph unicode="ï" glyph-name="icon-play" d="M1024 448l-1024-512v1024z" />
|
||||
<glyph unicode="ñ" glyph-name="icon-pause" d="M126 962h256v-1024h-256v1024zM638 962h256v-1024h-256v1024z" />
|
||||
<glyph unicode="ò" glyph-name="icon-duplicate" d="M640 704v128c0 70.4-57.6 128-128 128h-384c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h128v139.6c0 134.8 109.6 244.4 244.4 244.4h139.6zM896 576h-384c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h384c70.4 0 128 57.6 128 128v384c0 70.4-57.6 128-128 128z" />
|
||||
<glyph unicode="ó" glyph-name="icon-move" d="M293.4 448l218.6 218.6 256-256v421.4c0 70.4-57.6 128-128 128h-512c-70.4 0-128-57.6-128-128v-512c0-70.4 57.6-128 128-128h421.4l-256 256zM1024 512h-128v-320l-384 384-128-128 384-384h-320v-128h576z" />
|
||||
<glyph unicode="ô" glyph-name="icon-link" d="M1024 448l-512 512v-307.2l-512-204.8v-256h512v-256z" />
|
||||
<glyph unicode="õ" glyph-name="icon-timer" d="M638 898c0 35.4-28.6 64-64 64h-128c-35.4 0-64-28.6-64-64s28.6-64 64-64h128c35.4 0 64 28.6 64 64zM510 834c-247.4 0-448-200.6-448-448s200.6-448 448-448 448 200.6 448 448-200.6 448-448 448zM510 386h-336c0 185.2 150.8 336 336 336v-336z" />
|
||||
<glyph unicode="ö" glyph-name="icon-thumbs-strip" d="M448 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM448 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320z" />
|
||||
<glyph unicode="" glyph-name="icon-box-with-arrow-cursor" d="M832 447.6c0 0.2 0 0.2 0 0.4v320c0 105.6-86.4 192-192 192h-448c-105.6 0-192-86.4-192-192v-320c0-105.6 86.4-192 192-192h263.6l-197.2 445.6 573.6-254zM766.8 300.2l193.8 20.4-576.6 255.4 255.4-576.6 20.4 193.8 257-257.2 107.2 107.2z" />
|
||||
<glyph unicode="" glyph-name="icon-datatable" d="M1024 768c0-106.039-229.23-192-512-192s-512 85.961-512 192c0 106.039 229.23 192 512 192s512-85.961 512-192zM512 448c-282.8 0-512 86-512 192v-512c0-106 229.2-192 512-192s512 86 512 192v512c0-106-229.2-192-512-192zM896 385v-256c-36.6-15.6-79.8-28.8-128-39.4v256c48.2 10.6 91.4 23.8 128 39.4zM256 345.6v-256c-48.2 10.4-91.4 23.8-128 39.4v256c36.6-15.6 79.8-28.8 128-39.4zM384 70v256c41-4 83.8-6 128-6s87 2.2 128 6v-256c-41-4-83.8-6-128-6s-87 2.2-128 6z" />
|
||||
<glyph unicode="" glyph-name="icon-tabular-scrolling" d="M64 960c-35.2 0-64-28.8-64-64v-192h448v256h-384zM1024 704v192c0 35.2-28.8 64-64 64h-384v-256h448zM0 576v-192c0-35.2 28.8-64 64-64h384v256h-448zM960 320c35.2 0 64 28.8 64 64v192h-448v-256h384zM512-64l-256 256h512z" />
|
||||
<glyph unicode="" glyph-name="icon-alert-triangle" d="M998.208 111.136l-422.702 739.728c-34.928 61.124-92.084 61.124-127.012 0l-422.702-739.728c-34.928-61.126-5.906-111.136 64.494-111.136h843.428c70.4 0 99.422 50.010 64.494 111.136zM512 128c-35.2 0-64 28.8-64 64s28.8 64 64 64 64-28.8 64-64c0-35.2-28.8-64-64-64zM627.448 577.242l-38.898-194.486c-6.902-34.516-41.35-62.756-76.55-62.756s-69.648 28.24-76.552 62.758l-38.898 194.486c-6.902 34.516 16.25 62.756 51.45 62.756h128c35.2 0 58.352-28.24 51.448-62.758z" />
|
||||
<glyph unicode="" 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-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-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" />
|
||||
</font></defs></svg>
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 26 KiB |
Binary file not shown.
Binary file not shown.
@ -29,7 +29,7 @@ $interiorMargin: 5px;
|
||||
$interiorMarginLg: $interiorMargin * 2;
|
||||
$interiorMarginSm: 3px;
|
||||
$basicCr: 2px;
|
||||
$controlCr: 2px;
|
||||
$controlCr: 3px;
|
||||
$smallCr: 2px;
|
||||
$badgeW: 35px;
|
||||
|
||||
@ -84,6 +84,7 @@ $tabularColorBodyBg: darken($colorBodyBg, 10%);
|
||||
$tabularColorBodyFg: lighten($tabularColorBodyBg, 40%);
|
||||
$tabularColorHeaderBg: lighten($colorBodyBg, 10%);
|
||||
$tabularColorHeaderFg: lighten($tabularColorHeaderBg, 40%);
|
||||
$tabularColorHeaderBorder: $colorBodyBg;
|
||||
|
||||
/************************** RATIOS */
|
||||
$ltGamma: 20%;
|
||||
@ -115,9 +116,9 @@ $colorItemTreeIcon: $colorKey;
|
||||
$colorItemTreeIconHover: lighten($colorItemTreeIcon, 20%);
|
||||
$colorItemTreeVCHover: $colorAlt1;
|
||||
// Tabular
|
||||
$tabularHeaderH: 18px;
|
||||
$tabularHeaderH: 22px; //18px
|
||||
$tabularTdPadLR: $itemPadLR;
|
||||
$tabularTdPadTB: 2px;
|
||||
$tabularTdPadTB: 3px;
|
||||
// Imagery
|
||||
$imageMainControlBarH: 22px;
|
||||
$imageThumbsD: 120px;
|
||||
@ -141,12 +142,11 @@ $reqSymbolM: $interiorMargin * 2;
|
||||
$reqSymbolFontSize: 0.7em;
|
||||
|
||||
/************************** CONTROLS */
|
||||
$controlCr: $basicCr;
|
||||
$controlDisabledOpacity: 0.3;
|
||||
$formLabelW: 20%;
|
||||
$formInputH: 22px;
|
||||
$formRowCtrlsH: 14px;
|
||||
$menuLineH: 1.4rem;
|
||||
$menuLineH: 1.5rem;
|
||||
$scrollbarTrackSize: 10px;
|
||||
$scrollbarTrackColorBg: rgba(#000, 0.4);
|
||||
$btnStdH: 25px;
|
||||
|
@ -50,6 +50,11 @@ input, textarea {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
vertical-align: baseline;
|
||||
padding: 3px 5px !important;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -38,7 +38,6 @@
|
||||
@import "fixed-position";
|
||||
@import "about";
|
||||
@import "text";
|
||||
@import "badges";
|
||||
@import "icons";
|
||||
@import "limits";
|
||||
@import "data-status";
|
||||
@ -54,7 +53,6 @@
|
||||
@import "edit/editor";
|
||||
@import "features/imagery";
|
||||
@import "features/time-display";
|
||||
@import "forms/mixins";
|
||||
@import "forms/elems";
|
||||
@import "forms/validation";
|
||||
@import "forms/text-input";
|
||||
@ -76,5 +74,7 @@
|
||||
@import "properties";
|
||||
@import "autoflow";
|
||||
@import "iframe";
|
||||
@import "messages";
|
||||
@import "initialization";
|
||||
@import "hide-non-functional";
|
||||
@import "views";
|
||||
|
12
platform/commonUI/general/res/sass/_messages.scss
Normal file
12
platform/commonUI/general/res/sass/_messages.scss
Normal file
@ -0,0 +1,12 @@
|
||||
/* Styles for messages */
|
||||
|
||||
.message {
|
||||
&.block {
|
||||
@include border-radius($basicCr);
|
||||
padding: $interiorMarginLg;
|
||||
}
|
||||
&.error {
|
||||
background-color: rgba($colorAlert,0.3);
|
||||
color: lighten($colorAlert, 20%);
|
||||
}
|
||||
}
|
@ -260,6 +260,38 @@
|
||||
@include text-shadow(rgba(black, $sVal) 0 3px 7px);
|
||||
}
|
||||
|
||||
/*********************************************** FORM ELEMENTS */
|
||||
@mixin input-base($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
||||
@include appearance(none);
|
||||
@include border-radius($controlCr);
|
||||
@include box-sizing(border-box);
|
||||
@include box-shadow(inset rgba(black, 0.65) 0 1px 4px);
|
||||
// background: lighten($bg, 20%);
|
||||
background: rgba(#fff, 0.1);
|
||||
border: none;
|
||||
//border-bottom: 1px solid rgba(#fff, 0.1);
|
||||
color: lighten($fg, 20%);
|
||||
outline: none;
|
||||
&.error {
|
||||
background: rgba(red, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin nice-input($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
||||
@include input-base($bg, $fg);
|
||||
padding: 0 $interiorMarginSm;
|
||||
}
|
||||
|
||||
@mixin nice-textarea($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
||||
@include input-base($bg, $fg);
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
|
||||
@mixin subdued-input($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
||||
@include nice-input($bg, $fg);
|
||||
background: lighten($bg, 3%);
|
||||
border-bottom: 1px solid lighten($bg, 10%);
|
||||
}
|
||||
|
||||
/*
|
||||
@mixin invokeMenu($baseColor: $colorBodyFg) {
|
||||
|
21
platform/commonUI/general/res/sass/_views.scss
Normal file
21
platform/commonUI/general/res/sass/_views.scss
Normal file
@ -0,0 +1,21 @@
|
||||
/* Styles for sub-dividing views generically */
|
||||
|
||||
.l-view-section {
|
||||
@include absPosDefault(0);
|
||||
font-size: 0.8rem;
|
||||
h2 {
|
||||
color: #fff;
|
||||
margin-bottom: $interiorMargin;
|
||||
}
|
||||
&.fixed {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
&.scrolling {
|
||||
overflow: auto;
|
||||
}
|
||||
.controls,
|
||||
label,
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
@ -86,13 +86,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
height: $formInputH;
|
||||
line-height: $formInputH;
|
||||
margin-top: -4px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.l-med input[type="text"] {
|
||||
width: 200px;
|
||||
}
|
||||
|
@ -23,11 +23,11 @@
|
||||
@include appearance(none);
|
||||
@include border-radius($controlCr);
|
||||
@include box-sizing(border-box);
|
||||
@include box-shadow(inset rgba(black, 0.5) 0 1px 5px);
|
||||
@include box-shadow(inset rgba(black, 0.65) 0 1px 4px);
|
||||
// background: lighten($bg, 20%);
|
||||
background: rgba(#fff, 0.1);
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(#fff, 0.1);
|
||||
//border-bottom: 1px solid rgba(#fff, 0.1);
|
||||
color: lighten($fg, 20%);
|
||||
outline: none;
|
||||
&.error {
|
||||
|
@ -48,19 +48,15 @@
|
||||
width: 100%;
|
||||
tr {
|
||||
td {
|
||||
//max-width: 150px;
|
||||
padding: 2px 0;
|
||||
vertical-align: top;
|
||||
//white-space: nowrap;
|
||||
//overflow: hidden;
|
||||
//text-overflow: ellipsis;
|
||||
&.label {
|
||||
padding-right: $interiorMargin * 2;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&.value {
|
||||
white-space: nowrap;
|
||||
//width: 90%;
|
||||
//word-wrap: break-word; // Doesn't work in <td>?
|
||||
word-break: break-all;
|
||||
}
|
||||
&.align-wrap {
|
||||
white-space: normal;
|
||||
@ -135,7 +131,9 @@
|
||||
z-index: 2;
|
||||
}
|
||||
&.arw-up .arw.arw-down,
|
||||
&.arw-down .arw.arw-up { display: none; }
|
||||
&.arw-down .arw.arw-up {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
//************************************************* LOOK AND FEEL
|
||||
@ -148,6 +146,7 @@
|
||||
@include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
|
||||
}
|
||||
}
|
||||
|
||||
.s-infobubble {
|
||||
$emFg: darken($colorInfoBubbleFg, 20%);
|
||||
@include border-radius($basicCr);
|
||||
@ -159,18 +158,31 @@
|
||||
color: $emFg;
|
||||
font-weight: bold;
|
||||
}
|
||||
tr {
|
||||
td {
|
||||
border-top: 1px solid darken($colorInfoBubbleBg, 10%);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
&:first-child td {
|
||||
border-top: none;
|
||||
table {
|
||||
tr {
|
||||
td {
|
||||
border: none;
|
||||
border-top: 1px solid darken($colorInfoBubbleBg, 10%) !important;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
&:first-child td {
|
||||
border-top: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:first-child td {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: lighten($emFg, 30%);
|
||||
}
|
||||
|
||||
.value {
|
||||
color: $emFg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.s-thumbsbubble {
|
||||
|
@ -50,6 +50,12 @@
|
||||
margin-top: $d / -1;
|
||||
margin-left: $d / -1;
|
||||
z-index: 2;
|
||||
&.inline {
|
||||
display: inline-block !important;
|
||||
margin-right: $interiorMargin;
|
||||
position: relative !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.l-wait-spinner-holder {
|
||||
@ -80,4 +86,14 @@
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
top: 2px; left: 0;
|
||||
}
|
||||
|
||||
.wait-spinner.sm {
|
||||
$d: 13px;
|
||||
@include wait-spinner(0.25em, $colorKey);
|
||||
height: $d; width: $d;
|
||||
margin-left: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
padding: 0 !important;
|
||||
top: 0; left: 0;
|
||||
}
|
@ -24,13 +24,14 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tabular {
|
||||
.tabular,
|
||||
table {
|
||||
@include box-sizing(border-box);
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
color: #fff;
|
||||
display: table;
|
||||
font-size: 0.75em;
|
||||
font-size: 0.75rem;
|
||||
position: relative;
|
||||
//height: 100%; MOVED
|
||||
width: 100%;
|
||||
@ -41,19 +42,7 @@
|
||||
//table-layout: fixed; MOVED
|
||||
}
|
||||
thead, .thead {
|
||||
//width: calc(100% - 10px); MOVED
|
||||
tr, .tr {
|
||||
height: $tabularHeaderH;
|
||||
}
|
||||
&:before {
|
||||
content: "";
|
||||
display: block;
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: $tabularHeaderH;
|
||||
background: rgba(#fff, 0.15);
|
||||
}
|
||||
border-bottom: 1px solid $tabularColorHeaderBorder;
|
||||
}
|
||||
tbody, .tbody {
|
||||
//@include absPosDefault(0); MOVED
|
||||
@ -72,38 +61,49 @@
|
||||
&:first-child .td {
|
||||
border-top: none;
|
||||
}
|
||||
&.group-header {
|
||||
td, .td {
|
||||
$d: 5%;
|
||||
background-color: darken($tabularColorHeaderBg, $d);
|
||||
color: darken($tabularColorHeaderFg, $d);
|
||||
}
|
||||
}
|
||||
th, .th, td, .td {
|
||||
display: table-cell;
|
||||
}
|
||||
th, .th {
|
||||
border: none;
|
||||
border-left: 1px solid $tabularColorBorder;
|
||||
background-color: $tabularColorHeaderBg;
|
||||
border-left: 1px solid $tabularColorHeaderBorder;
|
||||
color: $tabularColorHeaderFg;
|
||||
padding: 0 $tabularTdPadLR;
|
||||
padding: $tabularTdPadLR $tabularTdPadLR;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle; // This is crucial to hiding f**king 4px height injected by browser by default
|
||||
&:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
&.sort {
|
||||
.icon-sorting:before {
|
||||
display: inline-block;
|
||||
&.sort:after {
|
||||
color: $colorIconLink;
|
||||
font-family: symbolsfont;
|
||||
margin-left: 5px;
|
||||
font-size: 8px;
|
||||
content: "\ed";
|
||||
display: inline-block;
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
&.asc .icon-sorting:before {
|
||||
content: '0';
|
||||
}
|
||||
&.desc .icon-sorting:before {
|
||||
content: '1';
|
||||
&.sort.desc:after {
|
||||
content: "\ec";
|
||||
}
|
||||
}
|
||||
&.sortable {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
td, .td {
|
||||
border-top: 1px solid $tabularColorBorder;
|
||||
min-width: 110px;
|
||||
border-bottom: 1px solid $tabularColorBorder;
|
||||
min-width: 20px;
|
||||
color: $colorTelemFresh;
|
||||
padding: $tabularTdPadTB $tabularTdPadLR;
|
||||
word-wrap: break-word;
|
||||
vertical-align: top;
|
||||
&.numeric {
|
||||
text-align: right;
|
||||
@ -119,9 +119,20 @@
|
||||
}
|
||||
}
|
||||
&.filterable {
|
||||
thead, .thead {
|
||||
tr.s-filters, .tr.s-filters {
|
||||
th, .th {
|
||||
//border-left: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
tbody, .tbody {
|
||||
top: $tabularHeaderH * 2;
|
||||
}
|
||||
input[type="text"] {
|
||||
@include box-sizing(border-box);
|
||||
width: 100%; //50px;
|
||||
}
|
||||
}
|
||||
|
||||
&.fixed-header {
|
||||
@ -133,6 +144,15 @@
|
||||
}
|
||||
thead, .thead {
|
||||
width: calc(100% - 10px);
|
||||
&:before {
|
||||
content: "";
|
||||
display: block;
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: $tabularHeaderH;
|
||||
background: rgba(#fff, 0.15);
|
||||
}
|
||||
}
|
||||
tbody, .tbody {
|
||||
@include absPosDefault(0);
|
||||
|
@ -22,7 +22,13 @@
|
||||
<span class="label s-label">
|
||||
<span class='ui-symbol icon type-icon'>
|
||||
{{type.getGlyph()}}
|
||||
<span class='ui-symbol icon alert hidden'>!</span>
|
||||
<span
|
||||
class='ui-symbol icon l-icon-link'
|
||||
ng-show="location.isLink()"
|
||||
></span>
|
||||
<span class='ui-symbol icon l-icon-alert'></span>
|
||||
</span>
|
||||
<span class='title-label'>
|
||||
{{model.name}}
|
||||
</span>
|
||||
<span class='title-label'>{{model.name}}</span>
|
||||
</span>
|
||||
|
@ -21,8 +21,7 @@
|
||||
-->
|
||||
<span ng-controller="ToggleController as toggle">
|
||||
<span ng-controller="TreeNodeController as treeNode">
|
||||
<span
|
||||
class="tree-item menus-to-left"
|
||||
<span class="tree-item menus-to-left"
|
||||
ng-class="{selected: treeNode.isSelected()}"
|
||||
>
|
||||
<mct-representation
|
||||
@ -44,10 +43,10 @@
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="tree-item-subtree"
|
||||
ng-show="toggle.isActive()"
|
||||
ng-if="model.composition !== undefined"
|
||||
>
|
||||
class="tree-item-subtree"
|
||||
ng-show="toggle.isActive()"
|
||||
ng-if="model.composition !== undefined"
|
||||
>
|
||||
|
||||
<mct-representation key="'subtree'"
|
||||
ng-model="ngModel"
|
||||
|
@ -21,6 +21,11 @@
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* This bundle provides various general-purpose UI elements, including
|
||||
* platform styling.
|
||||
* @namespace platform/commonUI/general
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
@ -29,6 +34,7 @@ define(
|
||||
/**
|
||||
* The StyleSheetLoader adds links to style sheets exposed from
|
||||
* various bundles as extensions of category `stylesheets`.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
* @param {object[]} stylesheets stylesheet extension definitions
|
||||
* @param $document Angular's jqLite-wrapped document element
|
||||
@ -62,4 +68,4 @@ define(
|
||||
|
||||
return StyleSheetLoader;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -42,6 +42,7 @@ define(
|
||||
* * `ungrouped`: All actions which did not have a defined
|
||||
* group.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function ActionGroupController($scope) {
|
||||
@ -102,4 +103,4 @@ define(
|
||||
|
||||
return ActionGroupController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -29,6 +29,7 @@ define(
|
||||
/**
|
||||
* Controller for the bottombar template. Exposes
|
||||
* available indicators (of extension category "indicators")
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function BottomBarController(indicators) {
|
||||
@ -42,20 +43,19 @@ define(
|
||||
};
|
||||
}
|
||||
|
||||
indicators = indicators.map(present);
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get all indicators to display.
|
||||
* @returns {Indicator[]} all indicators
|
||||
* to display in the bottom bar.
|
||||
*/
|
||||
getIndicators: function () {
|
||||
return indicators;
|
||||
}
|
||||
};
|
||||
this.indicators = indicators.map(present);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -31,71 +31,69 @@ define(
|
||||
* menus) where clicking elsewhere in the document while the toggle
|
||||
* is in an active state is intended to dismiss the toggle.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
* @param $scope the scope in which this controller is active
|
||||
* @param $document the document element, injected by Angular
|
||||
*/
|
||||
function ClickAwayController($scope, $document) {
|
||||
var state = false,
|
||||
clickaway;
|
||||
var self = this;
|
||||
|
||||
// Track state, but also attach and detach a listener for
|
||||
// mouseup events on the document.
|
||||
function deactivate() {
|
||||
state = false;
|
||||
$document.off("mouseup", clickaway);
|
||||
}
|
||||
|
||||
function activate() {
|
||||
state = true;
|
||||
$document.on("mouseup", clickaway);
|
||||
}
|
||||
|
||||
function changeState() {
|
||||
if (state) {
|
||||
deactivate();
|
||||
} else {
|
||||
activate();
|
||||
}
|
||||
}
|
||||
this.state = false;
|
||||
this.$scope = $scope;
|
||||
this.$document = $document;
|
||||
|
||||
// Callback used by the document listener. Deactivates;
|
||||
// note also $scope.$apply is invoked to indicate that
|
||||
// the state of this controller has changed.
|
||||
clickaway = function () {
|
||||
deactivate();
|
||||
this.clickaway = function () {
|
||||
self.deactivate();
|
||||
$scope.$apply();
|
||||
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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -33,6 +33,7 @@ define(
|
||||
* Controller for the context menu. Maintains an up-to-date
|
||||
* list of applicable actions (those from category "contextual")
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function ContextMenuController($scope) {
|
||||
@ -49,4 +50,4 @@ define(
|
||||
|
||||
return ContextMenuController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -54,6 +54,7 @@ define(
|
||||
* parameter it received.) Getter-setter functions are never the
|
||||
* target of a scope assignment and so avoid this problem.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
* @param {Scope} $scope the controller's scope
|
||||
*/
|
||||
@ -87,4 +88,4 @@ define(
|
||||
return GetterSetterController;
|
||||
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -30,6 +30,7 @@ define(
|
||||
|
||||
/**
|
||||
* Controller for the domain object selector control.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
* @param {ObjectService} objectService service from which to
|
||||
* read domain objects
|
||||
@ -38,28 +39,17 @@ define(
|
||||
function SelectorController(objectService, $scope) {
|
||||
var treeModel = {},
|
||||
listModel = {},
|
||||
selectedObjects = [],
|
||||
rootObject,
|
||||
previousSelected;
|
||||
previousSelected,
|
||||
self = this;
|
||||
|
||||
// For watch; look at the user's selection in the tree
|
||||
function getTreeSelection() {
|
||||
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
|
||||
function storeRoot(objects) {
|
||||
rootObject = objects[ROOT_ID];
|
||||
self.rootObject = objects[ROOT_ID];
|
||||
}
|
||||
|
||||
// Check that a selection is of the valid type
|
||||
@ -82,7 +72,8 @@ define(
|
||||
function updateSelectedObjects(objects) {
|
||||
// Look up from the
|
||||
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
|
||||
@ -93,64 +84,85 @@ define(
|
||||
$scope.$watch(getTreeSelection, validateTreeSelection);
|
||||
|
||||
// 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
|
||||
objectService.getObjects([ROOT_ID]).then(storeRoot);
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get the root object to show in the left-hand tree.
|
||||
* @returns {DomainObject} the root object
|
||||
*/
|
||||
root: function () {
|
||||
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
|
||||
};
|
||||
this.$scope = $scope;
|
||||
this.selectedObjects = [];
|
||||
|
||||
// Expose tree/list model for use in template directly
|
||||
this.treeModel = treeModel;
|
||||
this.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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -32,59 +32,58 @@ define(
|
||||
/**
|
||||
* Controller for the splitter in Browse mode. Current implementation
|
||||
* uses many hard-coded constants; this could be generalized.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function SplitPaneController() {
|
||||
var current = 200,
|
||||
start = 200,
|
||||
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);
|
||||
}
|
||||
};
|
||||
this.current = 200;
|
||||
this.start = 200;
|
||||
this.assigned = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -30,37 +30,37 @@ define(
|
||||
* A ToggleController is used to activate/deactivate things.
|
||||
* A common usage is for "twistie"
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function ToggleController() {
|
||||
var 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;
|
||||
}
|
||||
};
|
||||
|
||||
this.state = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -48,10 +48,12 @@ define(
|
||||
* node expansion when this tree node's _subtree_ will contain
|
||||
* the navigated object (recursively, this becomes an
|
||||
* expand-to-show-navigated-object behavior.)
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function TreeNodeController($scope, $timeout, agentService) {
|
||||
var selectedObject = ($scope.ngModel || {}).selectedObject,
|
||||
var self = this,
|
||||
selectedObject = ($scope.ngModel || {}).selectedObject,
|
||||
isSelected = false,
|
||||
hasBeenExpanded = false;
|
||||
|
||||
@ -75,32 +77,6 @@ define(
|
||||
((navPath[index] === nodePath[index]) &&
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the selected object in the tree, to be the
|
||||
// currently represented object. If the user is on phone
|
||||
// and in portrait mode, than, hide the tree menu
|
||||
function setObject(ngModel, domainObject) {
|
||||
ngModel.selectedObject = domainObject;
|
||||
if (agentService.getOrientation() === "portrait" &&
|
||||
agentService.isPhone(navigator.userAgent)) {
|
||||
$scope.$emit('select-obj');
|
||||
}
|
||||
}
|
||||
|
||||
function checkMobile() {
|
||||
return agentService.isMobile(navigator.userAgent);
|
||||
}
|
||||
|
||||
// Consider the currently-navigated object and update
|
||||
// parameters which support display.
|
||||
@ -116,7 +92,7 @@ define(
|
||||
|
||||
// Deselect; we will reselect below, iff we are
|
||||
// exactly at the end of the path.
|
||||
isSelected = false;
|
||||
self.isSelectedFlag = false;
|
||||
|
||||
// Expand if necessary (if the navigated object will
|
||||
// be in this node's subtree)
|
||||
@ -135,12 +111,12 @@ define(
|
||||
// at the end of the path, highlight;
|
||||
// otherwise, expand.
|
||||
if (nodePath.length === navPath.length) {
|
||||
isSelected = true;
|
||||
self.isSelectedFlag = true;
|
||||
} else { // node path is shorter: Expand!
|
||||
if ($scope.toggle) {
|
||||
$scope.toggle.setState(true);
|
||||
}
|
||||
trackExpansion();
|
||||
self.trackExpansion();
|
||||
}
|
||||
|
||||
}
|
||||
@ -153,43 +129,69 @@ define(
|
||||
selectedObject = object;
|
||||
checkSelection();
|
||||
}
|
||||
|
||||
|
||||
this.isSelectedFlag = false;
|
||||
this.hasBeenExpandedFlag = false;
|
||||
this.$timeout = $timeout;
|
||||
this.agentService = agentService;
|
||||
this.$scope = $scope;
|
||||
|
||||
// Listen for changes which will effect display parameters
|
||||
$scope.$watch("ngModel.selectedObject", setSelection);
|
||||
$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,
|
||||
|
||||
checkMobile: checkMobile,
|
||||
|
||||
setObject: setObject,
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
// Sets the selected object in the tree, to be the
|
||||
// currently represented object. If the user is on phone
|
||||
// and in portrait mode, than, hide the tree menu
|
||||
TreeNodeController.prototype.setObject = function (ngModel, domainObject) {
|
||||
ngModel.selectedObject = domainObject;
|
||||
if (this.agentService.getOrientation() === "portrait" &&
|
||||
this.agentService.isPhone(navigator.userAgent)) {
|
||||
this.$scope.$emit('select-obj');
|
||||
}
|
||||
};
|
||||
|
||||
TreeNodeController.prototype.checkMobile = function () {
|
||||
return this.agentService.isMobile(navigator.userAgent);
|
||||
};
|
||||
|
||||
return TreeNodeController;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -32,6 +32,7 @@ define(
|
||||
/**
|
||||
* Controller for the view switcher; populates and maintains a list
|
||||
* of applicable views for a represented domain object.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function ViewSwitcherController($scope, $timeout) {
|
||||
@ -71,3 +72,4 @@ define(
|
||||
return ViewSwitcherController;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -39,6 +39,7 @@ define(
|
||||
* plain string attribute, instead of as an Angular
|
||||
* expression.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function MCTContainer(containers) {
|
||||
@ -96,4 +97,4 @@ define(
|
||||
|
||||
return MCTContainer;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -44,6 +44,7 @@ define(
|
||||
* and vertical pixel offset of the current mouse position
|
||||
* relative to the mouse position where dragging began.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*
|
||||
*/
|
||||
@ -157,3 +158,4 @@ define(
|
||||
return MCTDrag;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -49,6 +49,7 @@ define(
|
||||
* This is an Angular expression, and it will be re-evaluated after
|
||||
* each interval.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*
|
||||
*/
|
||||
@ -111,4 +112,4 @@ define(
|
||||
|
||||
return MCTResize;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -37,6 +37,7 @@ define(
|
||||
* This is exposed as two directives in `bundle.json`; the difference
|
||||
* is handled purely by parameterization.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
* @param $parse Angular's $parse
|
||||
* @param {string} property property to manage within the HTML element
|
||||
@ -80,4 +81,4 @@ define(
|
||||
return MCTScroll;
|
||||
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -91,6 +91,7 @@ define(
|
||||
* etc. can be set on that element to control the splitter's
|
||||
* allowable positions.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function MCTSplitPane($parse, $log) {
|
||||
@ -213,3 +214,4 @@ define(
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -39,6 +39,7 @@ define(
|
||||
|
||||
/**
|
||||
* Implements `mct-splitter` directive.
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function MCTSplitter() {
|
||||
@ -88,3 +89,4 @@ define(
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -32,62 +32,56 @@ define(
|
||||
/**
|
||||
* The url service handles calls for url paths
|
||||
* using domain objects.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/general
|
||||
*/
|
||||
function UrlService($location) {
|
||||
// Returns the url for the mode wanted
|
||||
// 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
|
||||
};
|
||||
this.$location = $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -20,6 +20,13 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* This bundle provides support for object inspection (specifically, metadata
|
||||
* show in bubbles on hover.)
|
||||
* @namespace platform/commonUI/inspect
|
||||
*/
|
||||
|
||||
define({
|
||||
BUBBLE_TEMPLATE: "<mct-container key=\"bubble\" " +
|
||||
"bubble-title=\"{{bubbleTitle}}\" " +
|
||||
@ -33,4 +40,4 @@ define({
|
||||
// Max width and margins allowed for bubbles; defined in /platform/commonUI/general/res/sass/_constants.scss
|
||||
BUBBLE_MARGIN_LR: 10,
|
||||
BUBBLE_MAX_WIDTH: 300
|
||||
});
|
||||
});
|
||||
|
@ -30,98 +30,115 @@ define(
|
||||
* The `info` gesture displays domain object metadata in a
|
||||
* bubble on hover.
|
||||
*
|
||||
* @memberof platform/commonUI/inspect
|
||||
* @constructor
|
||||
* @implements {Gesture}
|
||||
* @param $timeout Angular's `$timeout`
|
||||
* @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 {DomainObject} domainObject the domain object for which to
|
||||
* show information
|
||||
*/
|
||||
function InfoGesture($timeout, agentService, infoService, DELAY, element, domainObject) {
|
||||
var dismissBubble,
|
||||
pendingBubble,
|
||||
mousePosition,
|
||||
scopeOff;
|
||||
function InfoGesture($timeout, agentService, infoService, delay, element, domainObject) {
|
||||
var self = this;
|
||||
|
||||
function trackPosition(event) {
|
||||
// Record mouse position, so bubble can be shown at latest
|
||||
// mouse position (not just where the mouse entered)
|
||||
mousePosition = [ event.clientX, event.clientY ];
|
||||
}
|
||||
// Callback functions to preserve the "this" pointer (in the
|
||||
// absence of Function.prototype.bind)
|
||||
this.showBubbleCallback = function (event) {
|
||||
self.showBubble(event);
|
||||
};
|
||||
this.hideBubbleCallback = function (event) {
|
||||
self.hideBubble(event);
|
||||
};
|
||||
this.trackPositionCallback = function (event) {
|
||||
self.trackPosition(event);
|
||||
};
|
||||
|
||||
function hideBubble() {
|
||||
// If a bubble is showing, dismiss it
|
||||
if (dismissBubble) {
|
||||
dismissBubble();
|
||||
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;
|
||||
}
|
||||
// Also make sure we dismiss bubble if representation is destroyed
|
||||
// before the mouse actually leaves it
|
||||
this.scopeOff = element.scope().$on('$destroy', this.hideBubbleCallback);
|
||||
|
||||
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);
|
||||
}
|
||||
this.element = element;
|
||||
this.$timeout = $timeout;
|
||||
this.infoService = infoService;
|
||||
this.delay = delay;
|
||||
this.domainObject = domainObject;
|
||||
|
||||
// Checks if you are on a mobile device, if the device is
|
||||
// not mobile (agentService.isMobile() = false), then
|
||||
// the pendingBubble and therefore hovering is allowed
|
||||
if (!agentService.isMobile(navigator.userAgent)) {
|
||||
// Show bubble (on a timeout) on mouse over
|
||||
element.on('mouseenter', showBubble);
|
||||
element.on('mouseenter', this.showBubbleCallback);
|
||||
}
|
||||
|
||||
// Also make sure we dismiss bubble if representation is destroyed
|
||||
// before the mouse actually leaves it
|
||||
scopeOff = element.scope().$on('$destroy', hideBubble);
|
||||
|
||||
return {
|
||||
/**
|
||||
* Detach any event handlers associated with this gesture.
|
||||
* @memberof InfoGesture
|
||||
* @method
|
||||
*/
|
||||
destroy: function () {
|
||||
// Dismiss any active bubble...
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
@ -31,76 +31,79 @@ define(
|
||||
|
||||
/**
|
||||
* Displays informative content ("info bubbles") for the user.
|
||||
* @memberof platform/commonUI/inspect
|
||||
* @constructor
|
||||
*/
|
||||
function InfoService($compile, $document, $window, $rootScope, agentService) {
|
||||
this.$compile = $compile;
|
||||
this.$document = $document;
|
||||
this.$window = $window;
|
||||
this.$rootScope = $rootScope;
|
||||
this.agentService = agentService;
|
||||
}
|
||||
|
||||
function display(templateKey, title, content, position) {
|
||||
var 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;
|
||||
/**
|
||||
* Display an info bubble at the specified location.
|
||||
* @param {string} templateKey template to place in bubble
|
||||
* @param {string} title title for the bubble
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
scope.bubbleModel = content;
|
||||
scope.bubbleTemplate = templateKey;
|
||||
scope.bubbleLayout = (goUp ? 'arw-btm' : 'arw-top') + ' ' +
|
||||
(goLeft ? 'arw-right' : 'arw-left');
|
||||
scope.bubbleTitle = title;
|
||||
|
||||
// Pass model & container parameters into the scope
|
||||
scope.bubbleModel = content;
|
||||
scope.bubbleTemplate = templateKey;
|
||||
scope.bubbleLayout = (goUp ? 'arw-btm' : 'arw-top') + ' ' +
|
||||
(goLeft ? 'arw-right' : 'arw-left');
|
||||
scope.bubbleTitle = title;
|
||||
// Create the context menu
|
||||
bubble = $compile(BUBBLE_TEMPLATE)(scope);
|
||||
|
||||
// Create the context menu
|
||||
bubble = $compile(BUBBLE_TEMPLATE)(scope);
|
||||
|
||||
// Position the bubble:
|
||||
// Phone: On a phone the bubble is specifically positioned
|
||||
// so that it takes up the width of the screen.
|
||||
// Tablet/Desktop: On other devices with larger screens, the
|
||||
// info bubble positioned as normal (with triangle pointing
|
||||
// to where clicked or pressed)
|
||||
bubble.css('position', 'absolute');
|
||||
if (agentService.isPhone(navigator.userAgent)) {
|
||||
bubble.css('right', '0px');
|
||||
bubble.css('left', '0px');
|
||||
bubble.css('top', 'auto');
|
||||
bubble.css('bottom', '25px');
|
||||
// Position the bubble
|
||||
bubble.css('position', 'absolute');
|
||||
if (this.agentService.isPhone(navigator.userAgent)) {
|
||||
bubble.css('right', '0px');
|
||||
bubble.css('left', '0px');
|
||||
bubble.css('top', 'auto');
|
||||
bubble.css('bottom', '25px');
|
||||
} else {
|
||||
if (goLeft) {
|
||||
bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px');
|
||||
} else {
|
||||
if (goLeft) {
|
||||
bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px');
|
||||
} else {
|
||||
bubble.css('left', position[0] + OFFSET[0] + 'px');
|
||||
}
|
||||
if (goUp) {
|
||||
bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px');
|
||||
} else {
|
||||
bubble.css('top', position[1] + OFFSET[1] + 'px');
|
||||
}
|
||||
bubble.css('left', position[0] + OFFSET[0] + 'px');
|
||||
}
|
||||
if (goUp) {
|
||||
bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px');
|
||||
} else {
|
||||
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 {
|
||||
/**
|
||||
* Display an info bubble at the specified location.
|
||||
* @param {string} templateKey template to place in bubble
|
||||
* @param {string} title title for the bubble
|
||||
* @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
|
||||
};
|
||||
}
|
||||
// Add the menu to the body
|
||||
body.append(bubble);
|
||||
|
||||
// Return a function to dismiss the bubble
|
||||
return function () { bubble.remove(); };
|
||||
};
|
||||
|
||||
return InfoService;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -32,9 +32,11 @@ define(
|
||||
* which capabilities. This supports composition policy (rules
|
||||
* for which objects can contain which other objects) which
|
||||
* sometimes is determined based on the presence of capabilities.
|
||||
* @constructor
|
||||
* @memberof platform/containment
|
||||
*/
|
||||
function CapabilityTable(typeService, capabilityService) {
|
||||
var table = {};
|
||||
var self = this;
|
||||
|
||||
// Build an initial model for a type
|
||||
function buildModel(type) {
|
||||
@ -52,25 +54,26 @@ define(
|
||||
function addToTable(type) {
|
||||
var typeKey = type.getKey();
|
||||
Object.keys(getCapabilities(type)).forEach(function (key) {
|
||||
table[key] = table[key] || {};
|
||||
table[key][typeKey] = true;
|
||||
self.table[key] = self.table[key] || {};
|
||||
self.table[key][typeKey] = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Build the table
|
||||
this.table = {};
|
||||
(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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -34,47 +34,51 @@ define(
|
||||
* since it's delegated to a different policy category.
|
||||
* To avoid a circular dependency, the service is obtained via
|
||||
* Angular's `$injector`.
|
||||
* @constructor
|
||||
* @memberof platform/containment
|
||||
* @implements {Policy.<Action, ActionContext>}
|
||||
*/
|
||||
function ComposeActionPolicy($injector) {
|
||||
var 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;
|
||||
}
|
||||
this.getPolicyService = function () {
|
||||
return $injector.get('policyService');
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -8,21 +8,19 @@ define(
|
||||
/**
|
||||
* Policy allowing composition only for domain object types which
|
||||
* have a composition property.
|
||||
* @constructor
|
||||
* @memberof platform/containment
|
||||
* @implements {Policy.<Type, Type>}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
@ -28,24 +28,20 @@ define(
|
||||
|
||||
/**
|
||||
* Disallow composition changes to objects which are not mutable.
|
||||
* @memberof platform/containment
|
||||
* @constructor
|
||||
* @implements {Policy.<Type, Type>}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
);
|
||||
);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user