diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..5f2fb18d84
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -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?
diff --git a/jsdoc.json b/jsdoc.json
index ed0fddcf31..f913b650d1 100644
--- a/jsdoc.json
+++ b/jsdoc.json
@@ -1,10 +1,12 @@
{
"source": {
"include": [
- "example/",
"platform/"
],
- "includePattern": "(example|platform)/.+\\.js$",
+ "includePattern": "platform/.+\\.js$",
"excludePattern": ".+\\Spec\\.js$|lib/.+"
- }
-}
\ No newline at end of file
+ },
+ "plugins": [
+ "plugins/markdown"
+ ]
+}
diff --git a/platform/commonUI/about/src/AboutController.js b/platform/commonUI/about/src/AboutController.js
index 7fc61c8cc2..dffd9b9471 100644
--- a/platform/commonUI/about/src/AboutController.js
+++ b/platform/commonUI/about/src/AboutController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/about/src/LicenseController.js b/platform/commonUI/about/src/LicenseController.js
index 1d996596aa..740124641f 100644
--- a/platform/commonUI/about/src/LicenseController.js
+++ b/platform/commonUI/about/src/LicenseController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/about/src/LogoController.js b/platform/commonUI/about/src/LogoController.js
index a688e96acf..85909a0552 100644
--- a/platform/commonUI/about/src/LogoController.js
+++ b/platform/commonUI/about/src/LogoController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html
index 3ac082fc59..85aeb38ca2 100644
--- a/platform/commonUI/browse/res/templates/browse.html
+++ b/platform/commonUI/browse/res/templates/browse.html
@@ -28,7 +28,15 @@
>
-
+
+
+
+
+
diff --git a/platform/commonUI/browse/src/BrowseController.js b/platform/commonUI/browse/src/BrowseController.js
index 3ec38057fc..b10e0a598a 100644
--- a/platform/commonUI/browse/src/BrowseController.js
+++ b/platform/commonUI/browse/src/BrowseController.js
@@ -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) {
@@ -157,3 +159,4 @@ define(
return BrowseController;
}
);
+
diff --git a/platform/commonUI/browse/src/BrowseObjectController.js b/platform/commonUI/browse/src/BrowseObjectController.js
index 1826120458..b1af9f29a7 100644
--- a/platform/commonUI/browse/src/BrowseObjectController.js
+++ b/platform/commonUI/browse/src/BrowseObjectController.js
@@ -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;
}
);
+
diff --git a/platform/commonUI/browse/src/MenuArrowController.js b/platform/commonUI/browse/src/MenuArrowController.js
index 86cad25c0e..5c4916e099 100644
--- a/platform/commonUI/browse/src/MenuArrowController.js
+++ b/platform/commonUI/browse/src/MenuArrowController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/creation/CreateAction.js b/platform/commonUI/browse/src/creation/CreateAction.js
index ce0d6d5cd4..984b26cfe5 100644
--- a/platform/commonUI/browse/src/creation/CreateAction.js
+++ b/platform/commonUI/browse/src/creation/CreateAction.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/creation/CreateActionProvider.js b/platform/commonUI/browse/src/creation/CreateActionProvider.js
index dcc98b8e95..4ca2bce59f 100644
--- a/platform/commonUI/browse/src/creation/CreateActionProvider.js
+++ b/platform/commonUI/browse/src/creation/CreateActionProvider.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/creation/CreateMenuController.js b/platform/commonUI/browse/src/creation/CreateMenuController.js
index 2dace415df..624764c2e4 100644
--- a/platform/commonUI/browse/src/creation/CreateMenuController.js
+++ b/platform/commonUI/browse/src/creation/CreateMenuController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/creation/CreateWizard.js b/platform/commonUI/browse/src/creation/CreateWizard.js
index 29fe953e18..4073ed7e90 100644
--- a/platform/commonUI/browse/src/creation/CreateWizard.js
+++ b/platform/commonUI/browse/src/creation/CreateWizard.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/creation/CreationService.js b/platform/commonUI/browse/src/creation/CreationService.js
index 17cc5ce6b3..110a49c216 100644
--- a/platform/commonUI/browse/src/creation/CreationService.js
+++ b/platform/commonUI/browse/src/creation/CreationService.js
@@ -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,56 +123,28 @@ define(
});
}
- // Store the location of an object relative to it's parent.
- function addLocationToModel(modelId, model, parent) {
- model.location = parent.getId();
- return model;
+ // 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));
}
- // 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 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);
+ });
+ };
- // We need the parent's persistence capability to determine
- // what space to create the new object's model in.
- if (!persistence) {
- $log.warn(NON_PERSISTENT_WARNING);
- return $q.reject(new Error(NON_PERSISTENT_WARNING));
- }
- // We create a new domain object in three sequential steps:
- // 1. Get a new UUID for the object
- // 2. Create a model with that ID in the persistence space
- // 3. Add that ID to
- return $q.when(
- uuid()
- ).then(function (id) {
- model = addLocationToModel(id, model, parent);
- return doPersist(persistence.getSpace(), id, model);
- }).then(function (id) {
- return addToComposition(id, parent, persistence);
- });
- }
-
- return {
- /**
- * Create a new domain object with the provided model, as
- * a member of the provided parent domain object's composition.
- * This parent will additionally determine which persistence
- * space an object is created within (as it is possible to
- * have multiple persistence spaces attached.)
- *
- * @param {object} model the model for the newly-created
- * domain object
- * @param {DomainObject} parent the domain object which
- * should contain the newly-created domain object
- * in its composition
- */
- createObject: createObject
- };
- }
return CreationService;
}
);
+
diff --git a/platform/commonUI/browse/src/creation/LocatorController.js b/platform/commonUI/browse/src/creation/LocatorController.js
index c7104956ea..d6335f9bd1 100644
--- a/platform/commonUI/browse/src/creation/LocatorController.js
+++ b/platform/commonUI/browse/src/creation/LocatorController.js
@@ -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;
}
);
+
diff --git a/platform/commonUI/browse/src/navigation/NavigateAction.js b/platform/commonUI/browse/src/navigation/NavigateAction.js
index 779a83044a..7b258afafe 100644
--- a/platform/commonUI/browse/src/navigation/NavigateAction.js
+++ b/platform/commonUI/browse/src/navigation/NavigateAction.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/navigation/NavigationService.js b/platform/commonUI/browse/src/navigation/NavigationService.js
index c8c76857b8..87e5582ef7 100644
--- a/platform/commonUI/browse/src/navigation/NavigationService.js
+++ b/platform/commonUI/browse/src/navigation/NavigationService.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/windowing/FullscreenAction.js b/platform/commonUI/browse/src/windowing/FullscreenAction.js
index efba99520b..82d92fbd40 100644
--- a/platform/commonUI/browse/src/windowing/FullscreenAction.js
+++ b/platform/commonUI/browse/src/windowing/FullscreenAction.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/windowing/NewTabAction.js b/platform/commonUI/browse/src/windowing/NewTabAction.js
index 8616a89711..301c204bbd 100644
--- a/platform/commonUI/browse/src/windowing/NewTabAction.js
+++ b/platform/commonUI/browse/src/windowing/NewTabAction.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/browse/src/windowing/WindowTitler.js b/platform/commonUI/browse/src/windowing/WindowTitler.js
index 9db65e5b0e..4ce448cb1e 100644
--- a/platform/commonUI/browse/src/windowing/WindowTitler.js
+++ b/platform/commonUI/browse/src/windowing/WindowTitler.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/dialog/src/DialogService.js b/platform/commonUI/dialog/src/DialogService.js
index d0c2c83f42..25e8943c06 100644
--- a/platform/commonUI/dialog/src/DialogService.js
+++ b/platform/commonUI/dialog/src/DialogService.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/dialog/src/OverlayService.js b/platform/commonUI/dialog/src/OverlayService.js
index b66bffa7dc..5faba5dcf6 100644
--- a/platform/commonUI/dialog/src/OverlayService.js
+++ b/platform/commonUI/dialog/src/OverlayService.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/actions/CancelAction.js b/platform/commonUI/edit/src/actions/CancelAction.js
index 725f6ee6a7..a9e6effe9f 100644
--- a/platform/commonUI/edit/src/actions/CancelAction.js
+++ b/platform/commonUI/edit/src/actions/CancelAction.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/actions/EditAction.js b/platform/commonUI/edit/src/actions/EditAction.js
index 38260469ae..86a8a75540 100644
--- a/platform/commonUI/edit/src/actions/EditAction.js
+++ b/platform/commonUI/edit/src/actions/EditAction.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/actions/LinkAction.js b/platform/commonUI/edit/src/actions/LinkAction.js
index f7d0087646..74abd2a93c 100644
--- a/platform/commonUI/edit/src/actions/LinkAction.js
+++ b/platform/commonUI/edit/src/actions/LinkAction.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/actions/PropertiesAction.js b/platform/commonUI/edit/src/actions/PropertiesAction.js
index bb37727c0e..1134c23190 100644
--- a/platform/commonUI/edit/src/actions/PropertiesAction.js
+++ b/platform/commonUI/edit/src/actions/PropertiesAction.js
@@ -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(
);
+
diff --git a/platform/commonUI/edit/src/actions/PropertiesDialog.js b/platform/commonUI/edit/src/actions/PropertiesDialog.js
index 8319efc315..97ee1f5c0a 100644
--- a/platform/commonUI/edit/src/actions/PropertiesDialog.js
+++ b/platform/commonUI/edit/src/actions/PropertiesDialog.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/actions/RemoveAction.js b/platform/commonUI/edit/src/actions/RemoveAction.js
index 21c290cd08..fccce69b53 100644
--- a/platform/commonUI/edit/src/actions/RemoveAction.js
+++ b/platform/commonUI/edit/src/actions/RemoveAction.js
@@ -57,7 +57,6 @@ define(
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
diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js
index d5db593742..fa276bba4b 100644
--- a/platform/commonUI/edit/src/actions/SaveAction.js
+++ b/platform/commonUI/edit/src/actions/SaveAction.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js b/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js
index 02276639d2..17dff58c0d 100644
--- a/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js
+++ b/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js
@@ -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(
);
};
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/capabilities/EditableContextCapability.js b/platform/commonUI/edit/src/capabilities/EditableContextCapability.js
index 34ea3ee465..d0df90afc4 100644
--- a/platform/commonUI/edit/src/capabilities/EditableContextCapability.js
+++ b/platform/commonUI/edit/src/capabilities/EditableContextCapability.js
@@ -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;
};
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js b/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js
index 5571072b25..c92495dc3f 100644
--- a/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js
+++ b/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js
@@ -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;
};
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js b/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js
index 5252ef1d44..42b08c72b1 100644
--- a/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js
+++ b/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js b/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js
index f61a54176c..3034301502 100644
--- a/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js
+++ b/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js
@@ -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(
);
};
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/capabilities/EditorCapability.js b/platform/commonUI/edit/src/capabilities/EditorCapability.js
index e59fbcae8c..7094d1142c 100644
--- a/platform/commonUI/edit/src/capabilities/EditorCapability.js
+++ b/platform/commonUI/edit/src/capabilities/EditorCapability.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/controllers/EditActionController.js b/platform/commonUI/edit/src/controllers/EditActionController.js
index 43c173b098..4ea38f9bb5 100644
--- a/platform/commonUI/edit/src/controllers/EditActionController.js
+++ b/platform/commonUI/edit/src/controllers/EditActionController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/controllers/EditController.js b/platform/commonUI/edit/src/controllers/EditController.js
index 34cabd0b0b..eaffe02186 100644
--- a/platform/commonUI/edit/src/controllers/EditController.js
+++ b/platform/commonUI/edit/src/controllers/EditController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/controllers/EditPanesController.js b/platform/commonUI/edit/src/controllers/EditPanesController.js
index 4bfc91002c..7dedc251ec 100644
--- a/platform/commonUI/edit/src/controllers/EditPanesController.js
+++ b/platform/commonUI/edit/src/controllers/EditPanesController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/directives/MCTBeforeUnload.js b/platform/commonUI/edit/src/directives/MCTBeforeUnload.js
index 60e825d1b0..3e7501c788 100644
--- a/platform/commonUI/edit/src/directives/MCTBeforeUnload.js
+++ b/platform/commonUI/edit/src/directives/MCTBeforeUnload.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/objects/EditableDomainObject.js b/platform/commonUI/edit/src/objects/EditableDomainObject.js
index dce39bec87..bbbc0ae512 100644
--- a/platform/commonUI/edit/src/objects/EditableDomainObject.js
+++ b/platform/commonUI/edit/src/objects/EditableDomainObject.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js b/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js
index a13a3e2360..88a154d79b 100644
--- a/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js
+++ b/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js
@@ -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 a
+ * @param {Constructor} 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;
}
);
+
diff --git a/platform/commonUI/edit/src/objects/EditableModelCache.js b/platform/commonUI/edit/src/objects/EditableModelCache.js
index 3652f679f7..30ca3d774a 100644
--- a/platform/commonUI/edit/src/objects/EditableModelCache.js
+++ b/platform/commonUI/edit/src/objects/EditableModelCache.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/policies/EditActionPolicy.js b/platform/commonUI/edit/src/policies/EditActionPolicy.js
index 3c47af43b8..bec2fc423d 100644
--- a/platform/commonUI/edit/src/policies/EditActionPolicy.js
+++ b/platform/commonUI/edit/src/policies/EditActionPolicy.js
@@ -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.}
*/
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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/policies/EditableViewPolicy.js b/platform/commonUI/edit/src/policies/EditableViewPolicy.js
index c93072e861..17194064b0 100644
--- a/platform/commonUI/edit/src/policies/EditableViewPolicy.js
+++ b/platform/commonUI/edit/src/policies/EditableViewPolicy.js
@@ -28,30 +28,24 @@ define(
/**
* Policy controlling which views should be visible in Edit mode.
+ * @memberof platform/commonUI/edit
* @constructor
+ * @implements {Policy.}
*/
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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/representers/EditRepresenter.js b/platform/commonUI/edit/src/representers/EditRepresenter.js
index 96f6da332b..17a0f634b2 100644
--- a/platform/commonUI/edit/src/representers/EditRepresenter.js
+++ b/platform/commonUI/edit/src/representers/EditRepresenter.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/representers/EditToolbar.js b/platform/commonUI/edit/src/representers/EditToolbar.js
index 58dab7497e..367eaf1705 100644
--- a/platform/commonUI/edit/src/representers/EditToolbar.js
+++ b/platform/commonUI/edit/src/representers/EditToolbar.js
@@ -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;
}
);
+
diff --git a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js
index f94ddcd7a8..daf3645b69 100644
--- a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js
+++ b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/representers/EditToolbarSelection.js b/platform/commonUI/edit/src/representers/EditToolbarSelection.js
index d88ad0da1a..318ae935b5 100644
--- a/platform/commonUI/edit/src/representers/EditToolbarSelection.js
+++ b/platform/commonUI/edit/src/representers/EditToolbarSelection.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/test/objects/EditableDomainObjectCacheSpec.js b/platform/commonUI/edit/test/objects/EditableDomainObjectCacheSpec.js
index 39cac56d9f..4eea727e26 100644
--- a/platform/commonUI/edit/test/objects/EditableDomainObjectCacheSpec.js
+++ b/platform/commonUI/edit/test/objects/EditableDomainObjectCacheSpec.js
@@ -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]);
diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css
index b6c9a43edc..20b5dc1bcc 100644
--- a/platform/commonUI/general/res/css/theme-espresso.css
+++ b/platform/commonUI/general/res/css/theme-espresso.css
@@ -71,6 +71,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* CONSTANTS */
+/*****************************************************************************
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
@@ -92,7 +93,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
-/* line 5, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+/* line 5, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
@@ -113,38 +114,38 @@ time, mark, audio, video {
font-size: 100%;
vertical-align: baseline; }
-/* line 22, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+/* line 22, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html {
line-height: 1; }
-/* line 24, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+/* line 24, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
ol, ul {
list-style: none; }
-/* line 26, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+/* line 26, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
table {
border-collapse: collapse;
border-spacing: 0; }
-/* line 28, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+/* line 28, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle; }
-/* line 30, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+/* line 30, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q, blockquote {
quotes: none; }
- /* line 103, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+ /* line 103, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after {
content: "";
content: none; }
-/* line 32, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+/* line 32, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
a img {
border: none; }
-/* line 116, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
+/* line 116, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
display: block; }
@@ -172,11 +173,11 @@ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu,
/*********************************************** FORM ELEMENTS */
/*
@mixin invokeMenu($baseColor: $colorBodyFg) {
- $c: $baseColor;
- color: $c;
- &:hover {
- color: lighten($c, $ltGamma);
- }
+ $c: $baseColor;
+ color: $c;
+ &:hover {
+ color: lighten($c, $ltGamma);
+ }
}
*/
/*****************************************************************************
@@ -644,44 +645,46 @@ mct-container {
position: absolute;
bottom: 5px; }
/* line 232, ../sass/user-environ/_layout.scss */
+ .pane.treeview.left .search-holder {
+ top: 34px; }
+ /* line 235, ../sass/user-environ/_layout.scss */
.pane.treeview.left .tree-holder {
overflow: auto;
- top: 34px;
- padding-right: 5px; }
- /* line 240, ../sass/user-environ/_layout.scss */
+ top: 64px; }
+ /* line 242, ../sass/user-environ/_layout.scss */
.pane.items .object-browse-bar .left.abs, .pane.items .object-browse-bar .btn-menu span.left.l-click-area, .btn-menu .pane.items .object-browse-bar span.left.l-click-area,
.pane.items .object-browse-bar .right.abs,
.pane.items .object-browse-bar .btn-menu span.right.l-click-area,
.btn-menu .pane.items .object-browse-bar span.right.l-click-area {
top: auto; }
- /* line 245, ../sass/user-environ/_layout.scss */
+ /* line 247, ../sass/user-environ/_layout.scss */
.pane.items .object-holder {
top: 34px; }
- /* line 249, ../sass/user-environ/_layout.scss */
+ /* line 251, ../sass/user-environ/_layout.scss */
.pane .object-holder {
overflow: auto; }
-/* line 257, ../sass/user-environ/_layout.scss */
+/* line 259, ../sass/user-environ/_layout.scss */
.split-layout.horizontal > .pane {
margin-top: 5px; }
- /* line 260, ../sass/user-environ/_layout.scss */
+ /* line 262, ../sass/user-environ/_layout.scss */
.split-layout.horizontal > .pane:first-child {
margin-top: 0; }
-/* line 267, ../sass/user-environ/_layout.scss */
+/* line 269, ../sass/user-environ/_layout.scss */
.split-layout.vertical > .pane {
margin-left: 5px; }
- /* line 269, ../sass/user-environ/_layout.scss */
+ /* line 271, ../sass/user-environ/_layout.scss */
.split-layout.vertical > .pane > .holder {
left: 0;
right: 0; }
- /* line 273, ../sass/user-environ/_layout.scss */
+ /* line 275, ../sass/user-environ/_layout.scss */
.split-layout.vertical > .pane:first-child {
margin-left: 0; }
- /* line 275, ../sass/user-environ/_layout.scss */
+ /* line 277, ../sass/user-environ/_layout.scss */
.split-layout.vertical > .pane:first-child .holder {
right: 3px; }
-/* line 284, ../sass/user-environ/_layout.scss */
+/* line 286, ../sass/user-environ/_layout.scss */
.vscroll {
overflow-y: auto; }
@@ -1049,27 +1052,27 @@ mct-container {
/*.s-limit-upr,
.s-limit-lwr {
- $a: 0.5;
- $l: 30%;
- white-space: nowrap;
- &:before {
- display: inline-block;
- font-family: symbolsfont;
- font-size: 0.85em;
- font-style: normal !important;
- margin-right: $interiorMarginSm;
- vertical-align: middle;
- }
+ $a: 0.5;
+ $l: 30%;
+ white-space: nowrap;
+ &:before {
+ display: inline-block;
+ font-family: symbolsfont;
+ font-size: 0.85em;
+ font-style: normal !important;
+ margin-right: $interiorMarginSm;
+ vertical-align: middle;
+ }
}
.s-limit-upr {
- &.s-limit-yellow { @include limit($colorLimitYellow, "\0000ed"); }
- &.s-limit-red { @include limit($colorLimitRed, "\0000eb"); }
+ &.s-limit-yellow { @include limit($colorLimitYellow, "\0000ed"); }
+ &.s-limit-red { @include limit($colorLimitRed, "\0000eb"); }
}
.s-limit-lwr {
- &.s-limit-yellow { @include limit($colorLimitYellow, "\0000ec"); }
- &.s-limit-red { @include limit($colorLimitRed, "\0000ee"); }
+ &.s-limit-yellow { @include limit($colorLimitYellow, "\0000ec"); }
+ &.s-limit-red { @include limit($colorLimitRed, "\0000ee"); }
}*/
/* line 35, ../sass/_limits.scss */
[class*="s-limit"] {
@@ -1237,29 +1240,32 @@ table {
table .tr .th:first-child {
border-left: none; }
/* line 85, ../sass/lists/_tabular.scss */
- .tabular tr th.sort .icon-sorting:before, .tabular tr .th.sort .icon-sorting:before, .tabular .tr th.sort .icon-sorting:before, .tabular .tr .th.sort .icon-sorting:before,
- table tr th.sort .icon-sorting:before,
- table tr .th.sort .icon-sorting:before,
- table .tr th.sort .icon-sorting:before,
- table .tr .th.sort .icon-sorting:before {
- display: inline-block;
+ .tabular tr th.sort.sort:after, .tabular tr .th.sort.sort:after, .tabular .tr th.sort.sort:after, .tabular .tr .th.sort.sort:after,
+ table tr th.sort.sort:after,
+ table tr .th.sort.sort:after,
+ table .tr th.sort.sort:after,
+ table .tr .th.sort.sort:after {
+ color: #49dedb;
font-family: symbolsfont;
- margin-left: 5px; }
- /* line 90, ../sass/lists/_tabular.scss */
- .tabular tr th.sort.asc .icon-sorting:before, .tabular tr .th.sort.asc .icon-sorting:before, .tabular .tr th.sort.asc .icon-sorting:before, .tabular .tr .th.sort.asc .icon-sorting:before,
- table tr th.sort.asc .icon-sorting:before,
- table tr .th.sort.asc .icon-sorting:before,
- table .tr th.sort.asc .icon-sorting:before,
- table .tr .th.sort.asc .icon-sorting:before {
- content: '0'; }
+ font-size: 8px;
+ content: "\ed";
+ display: inline-block;
+ margin-left: 3px; }
/* line 93, ../sass/lists/_tabular.scss */
- .tabular tr th.sort.desc .icon-sorting:before, .tabular tr .th.sort.desc .icon-sorting:before, .tabular .tr th.sort.desc .icon-sorting:before, .tabular .tr .th.sort.desc .icon-sorting:before,
- table tr th.sort.desc .icon-sorting:before,
- table tr .th.sort.desc .icon-sorting:before,
- table .tr th.sort.desc .icon-sorting:before,
- table .tr .th.sort.desc .icon-sorting:before {
- content: '1'; }
- /* line 98, ../sass/lists/_tabular.scss */
+ .tabular tr th.sort.sort.desc:after, .tabular tr .th.sort.sort.desc:after, .tabular .tr th.sort.sort.desc:after, .tabular .tr .th.sort.sort.desc:after,
+ table tr th.sort.sort.desc:after,
+ table tr .th.sort.sort.desc:after,
+ table .tr th.sort.sort.desc:after,
+ table .tr .th.sort.sort.desc:after {
+ content: "\ec"; }
+ /* line 97, ../sass/lists/_tabular.scss */
+ .tabular tr th.sortable, .tabular tr .th.sortable, .tabular .tr th.sortable, .tabular .tr .th.sortable,
+ table tr th.sortable,
+ table tr .th.sortable,
+ table .tr th.sortable,
+ table .tr .th.sortable {
+ cursor: pointer; }
+ /* line 101, ../sass/lists/_tabular.scss */
.tabular tr td, .tabular tr .td, .tabular .tr td, .tabular .tr .td,
table tr td,
table tr .td,
@@ -1271,21 +1277,21 @@ table {
padding: 3px 5px;
word-wrap: break-word;
vertical-align: top; }
- /* line 105, ../sass/lists/_tabular.scss */
+ /* line 108, ../sass/lists/_tabular.scss */
.tabular tr td.numeric, .tabular tr .td.numeric, .tabular .tr td.numeric, .tabular .tr .td.numeric,
table tr td.numeric,
table tr .td.numeric,
table .tr td.numeric,
table .tr .td.numeric {
text-align: right; }
- /* line 108, ../sass/lists/_tabular.scss */
+ /* line 111, ../sass/lists/_tabular.scss */
.tabular tr td.s-cell-type-value, .tabular tr .td.s-cell-type-value, .tabular .tr td.s-cell-type-value, .tabular .tr .td.s-cell-type-value,
table tr td.s-cell-type-value,
table tr .td.s-cell-type-value,
table .tr td.s-cell-type-value,
table .tr .td.s-cell-type-value {
text-align: right; }
- /* line 110, ../sass/lists/_tabular.scss */
+ /* line 113, ../sass/lists/_tabular.scss */
.tabular tr td.s-cell-type-value .l-cell-contents, .tabular tr .td.s-cell-type-value .l-cell-contents, .tabular .tr td.s-cell-type-value .l-cell-contents, .tabular .tr .td.s-cell-type-value .l-cell-contents,
table tr td.s-cell-type-value .l-cell-contents,
table tr .td.s-cell-type-value .l-cell-contents,
@@ -1296,23 +1302,23 @@ table {
border-radius: 2px;
padding-left: 5px;
padding-right: 5px; }
- /* line 126, ../sass/lists/_tabular.scss */
+ /* line 129, ../sass/lists/_tabular.scss */
.tabular.filterable tbody, .tabular.filterable .tbody,
table.filterable tbody,
table.filterable .tbody {
top: 44px; }
- /* line 129, ../sass/lists/_tabular.scss */
+ /* line 132, ../sass/lists/_tabular.scss */
.tabular.filterable input[type="text"],
table.filterable input[type="text"] {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 100%; }
- /* line 135, ../sass/lists/_tabular.scss */
+ /* line 138, ../sass/lists/_tabular.scss */
.tabular.fixed-header,
table.fixed-header {
height: 100%; }
- /* line 137, ../sass/lists/_tabular.scss */
+ /* line 140, ../sass/lists/_tabular.scss */
.tabular.fixed-header thead, .tabular.fixed-header .thead,
.tabular.fixed-header tbody tr, .tabular.fixed-header .tbody .tr,
table.fixed-header thead,
@@ -1321,12 +1327,12 @@ table {
table.fixed-header .tbody .tr {
display: table;
table-layout: fixed; }
- /* line 142, ../sass/lists/_tabular.scss */
+ /* line 145, ../sass/lists/_tabular.scss */
.tabular.fixed-header thead, .tabular.fixed-header .thead,
table.fixed-header thead,
table.fixed-header .thead {
width: calc(100% - 10px); }
- /* line 144, ../sass/lists/_tabular.scss */
+ /* line 147, ../sass/lists/_tabular.scss */
.tabular.fixed-header thead:before, .tabular.fixed-header .thead:before,
table.fixed-header thead:before,
table.fixed-header .thead:before {
@@ -1337,7 +1343,7 @@ table {
width: 100%;
height: 22px;
background: rgba(255, 255, 255, 0.15); }
- /* line 154, ../sass/lists/_tabular.scss */
+ /* line 157, ../sass/lists/_tabular.scss */
.tabular.fixed-header tbody, .tabular.fixed-header .tbody,
table.fixed-header tbody,
table.fixed-header .tbody {
@@ -1352,7 +1358,7 @@ table {
top: 22px;
display: block;
overflow-y: scroll; }
- /* line 162, ../sass/lists/_tabular.scss */
+ /* line 165, ../sass/lists/_tabular.scss */
.tabular.t-event-messages td, .tabular.t-event-messages .td,
table.t-event-messages td,
table.t-event-messages .td {
@@ -1772,11 +1778,11 @@ table {
/* line 132, ../sass/controls/_buttons.scss */
.icon-btn.pause-play,
.s-icon-btn.pause-play {
- /* &.paused {
- .icon {
- @include pulse(500ms);
- }
- }*/ }
+ /* &.paused {
+ .icon {
+ @include pulse(500ms);
+ }
+ }*/ }
/* line 138, ../sass/controls/_buttons.scss */
.icon-btn.pause-play .icon:before,
.s-icon-btn.pause-play .icon:before {
@@ -1899,32 +1905,32 @@ a.l-btn span {
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*.control {
- // UNUSED?
- &.view-control {
- .icon {
- display: inline-block;
- margin: -1px 5px 1px 2px;
- vertical-align: middle;
- &.triangle-down {
- margin: 2px 2px -2px 0px;
- }
- }
+ // UNUSED?
+ &.view-control {
+ .icon {
+ display: inline-block;
+ margin: -1px 5px 1px 2px;
+ vertical-align: middle;
+ &.triangle-down {
+ margin: 2px 2px -2px 0px;
+ }
+ }
- .label {
- display: inline-block;
- font-size: 11px;
- vertical-align: middle;
- }
+ .label {
+ display: inline-block;
+ font-size: 11px;
+ vertical-align: middle;
+ }
- .toggle {
- @include border-radius(3px);
- display: inline-block;
- padding: 1px 6px 4px 4px;
- &:hover {
- background: rgba(white, 0.1);
- }
- }
- }
+ .toggle {
+ @include border-radius(3px);
+ display: inline-block;
+ padding: 1px 6px 4px 4px;
+ &:hover {
+ background: rgba(white, 0.1);
+ }
+ }
+ }
}*/
/* line 51, ../sass/controls/_controls.scss */
.accordion {
@@ -2161,23 +2167,23 @@ label.checkbox.custom {
border-top: 1px solid #575757;
color: #999;
display: inline-block;
- /* height: $h;
- line-height: $h;
- &.dropdown {
- padding-left: $p;
- padding-right: $p;
- }*/
- /* &.context-available {
- // An element like the invoke-menu triangle;
- // Indicates that this element has a dropdown menu available;
- // Currently unused
- $c: $colorKey;
- color: $c;
- padding: 0 5px;
- &:hover {
- color: lighten($c, 10%);
- }
- }*/ }
+ /* height: $h;
+ line-height: $h;
+ &.dropdown {
+ padding-left: $p;
+ padding-right: $p;
+ }*/
+ /* &.context-available {
+ // An element like the invoke-menu triangle;
+ // Indicates that this element has a dropdown menu available;
+ // Currently unused
+ $c: $colorKey;
+ color: $c;
+ padding: 0 5px;
+ &:hover {
+ color: lighten($c, 10%);
+ }
+ }*/ }
/* line 162, ../sass/_mixins.scss */
.btn-menu:not(.disabled):hover {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
@@ -2568,22 +2574,23 @@ label.checkbox.custom {
color: #d9d9d9;
line-height: 1.5rem;
padding: 3px 10px 3px 30px;
+ position: relative;
white-space: nowrap; }
- /* line 46, ../sass/controls/_menus.scss */
+ /* line 47, ../sass/controls/_menus.scss */
.menu-element .menu ul li:first-child {
border: none; }
- /* line 49, ../sass/controls/_menus.scss */
+ /* line 50, ../sass/controls/_menus.scss */
.menu-element .menu ul li:hover {
background: #737373;
color: #fff; }
- /* line 55, ../sass/controls/_menus.scss */
+ /* line 56, ../sass/controls/_menus.scss */
.menu-element .menu ul li:hover .icon {
color: #33ccff; }
- /* line 63, ../sass/controls/_menus.scss */
+ /* line 64, ../sass/controls/_menus.scss */
.menu-element .menu ul li .type-icon {
left: 10px; }
- /* line 70, ../sass/controls/_menus.scss */
- .menu-element .context-menu,
+ /* line 71, ../sass/controls/_menus.scss */
+ .menu-element .context-menu, .menu-element .checkbox-menu,
.menu-element .super-menu {
pointer-events: auto;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzhjOGM4YyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzgwODA4MCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
@@ -2606,35 +2613,56 @@ label.checkbox.custom {
color: #999;
display: inline-block; }
/* line 170, ../sass/_mixins.scss */
- .menu-element .context-menu.btn-menu .invoke-menu,
+ .menu-element .context-menu.btn-menu .invoke-menu, .menu-element .btn-menu.checkbox-menu .invoke-menu,
.menu-element .super-menu.btn-menu .invoke-menu {
color: #b0b0b0; }
- /* line 78, ../sass/controls/_menus.scss */
- .menu-element .context-menu ul li,
+ /* line 79, ../sass/controls/_menus.scss */
+ .menu-element .context-menu ul li, .menu-element .checkbox-menu ul li,
.menu-element .super-menu ul li {
padding-left: 25px; }
- /* line 80, ../sass/controls/_menus.scss */
- .menu-element .context-menu ul li a,
+ /* line 81, ../sass/controls/_menus.scss */
+ .menu-element .context-menu ul li a, .menu-element .checkbox-menu ul li a,
.menu-element .super-menu ul li a {
color: white; }
- /* line 81, ../sass/controls/_menus.scss */
- .menu-element .context-menu ul li .icon,
+ /* line 84, ../sass/controls/_menus.scss */
+ .menu-element .context-menu ul li .icon, .menu-element .checkbox-menu ul li .icon,
.menu-element .super-menu ul li .icon {
color: #24c8ff; }
- /* line 84, ../sass/controls/_menus.scss */
- .menu-element .context-menu ul li .type-icon,
+ /* line 87, ../sass/controls/_menus.scss */
+ .menu-element .context-menu ul li .type-icon, .menu-element .checkbox-menu ul li .type-icon,
.menu-element .super-menu ul li .type-icon {
left: 5px; }
- /* line 87, ../sass/controls/_menus.scss */
- .menu-element .context-menu ul li:hover .icon,
+ /* line 90, ../sass/controls/_menus.scss */
+ .menu-element .context-menu ul li:hover .icon, .menu-element .checkbox-menu ul li:hover .icon,
.menu-element .super-menu ul li:hover .icon {
color: #3dcfff; }
- /* line 94, ../sass/controls/_menus.scss */
+ /* line 99, ../sass/controls/_menus.scss */
+ .menu-element .checkbox-menu ul li {
+ padding-left: 50px; }
+ /* line 101, ../sass/controls/_menus.scss */
+ .menu-element .checkbox-menu ul li .checkbox {
+ position: absolute;
+ left: 5px;
+ top: 0.53333rem; }
+ /* line 106, ../sass/controls/_menus.scss */
+ .menu-element .checkbox-menu ul li .checkbox em {
+ height: 0.7rem;
+ width: 0.7rem; }
+ /* line 109, ../sass/controls/_menus.scss */
+ .menu-element .checkbox-menu ul li .checkbox em:before {
+ font-size: 7px !important;
+ height: 0.7rem;
+ width: 0.7rem;
+ line-height: 0.7rem; }
+ /* line 117, ../sass/controls/_menus.scss */
+ .menu-element .checkbox-menu ul li .type-icon {
+ left: 25px; }
+ /* line 123, ../sass/controls/_menus.scss */
.menu-element .super-menu {
display: block;
width: 500px;
height: 480px; }
- /* line 104, ../sass/controls/_menus.scss */
+ /* line 133, ../sass/controls/_menus.scss */
.menu-element .super-menu .contents {
overflow: hidden;
position: absolute;
@@ -2644,12 +2672,12 @@ label.checkbox.custom {
left: 5px;
width: auto;
height: auto; }
- /* line 107, ../sass/controls/_menus.scss */
+ /* line 136, ../sass/controls/_menus.scss */
.menu-element .super-menu .pane {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box; }
- /* line 109, ../sass/controls/_menus.scss */
+ /* line 138, ../sass/controls/_menus.scss */
.menu-element .super-menu .pane.left {
border-right: 1px solid rgba(255, 255, 255, 0.2);
left: 0;
@@ -2658,23 +2686,23 @@ label.checkbox.custom {
width: 50%;
overflow-x: hidden;
overflow-y: auto; }
- /* line 119, ../sass/controls/_menus.scss */
+ /* line 148, ../sass/controls/_menus.scss */
.menu-element .super-menu .pane.left ul li {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
padding-left: 30px;
border-top: none; }
- /* line 126, ../sass/controls/_menus.scss */
+ /* line 155, ../sass/controls/_menus.scss */
.menu-element .super-menu .pane.right {
left: auto;
right: 0;
padding: 25px;
width: 50%; }
- /* line 132, ../sass/controls/_menus.scss */
+ /* line 161, ../sass/controls/_menus.scss */
.menu-element .super-menu .pane.right .icon {
color: #fff; }
- /* line 139, ../sass/controls/_menus.scss */
+ /* line 168, ../sass/controls/_menus.scss */
.menu-element .super-menu .menu-item-description .desc-area.icon {
position: relative;
font-size: 8em;
@@ -2683,40 +2711,40 @@ label.checkbox.custom {
line-height: 150px;
margin-bottom: 25px;
text-align: center; }
- /* line 149, ../sass/controls/_menus.scss */
+ /* line 178, ../sass/controls/_menus.scss */
.menu-element .super-menu .menu-item-description .desc-area.title {
color: #fff;
font-size: 1.2em;
margin-bottom: 0.5em; }
- /* line 154, ../sass/controls/_menus.scss */
+ /* line 183, ../sass/controls/_menus.scss */
.menu-element .super-menu .menu-item-description .desc-area.description {
color: #fff;
font-size: 0.8em;
line-height: 1.5em; }
- /* line 163, ../sass/controls/_menus.scss */
- .menu-element .context-menu {
+ /* line 192, ../sass/controls/_menus.scss */
+ .menu-element .context-menu, .menu-element .checkbox-menu {
font-size: 0.80rem; }
-/* line 168, ../sass/controls/_menus.scss */
+/* line 197, ../sass/controls/_menus.scss */
.context-menu-holder {
pointer-events: none;
position: absolute;
height: 200px;
width: 170px;
z-index: 70; }
- /* line 174, ../sass/controls/_menus.scss */
+ /* line 203, ../sass/controls/_menus.scss */
.context-menu-holder .context-menu-wrapper {
position: absolute;
height: 100%;
width: 100%; }
- /* line 181, ../sass/controls/_menus.scss */
- .context-menu-holder.go-left .context-menu {
+ /* line 210, ../sass/controls/_menus.scss */
+ .context-menu-holder.go-left .context-menu, .context-menu-holder.go-left .menu-element .checkbox-menu, .menu-element .context-menu-holder.go-left .checkbox-menu {
right: 0; }
- /* line 182, ../sass/controls/_menus.scss */
- .context-menu-holder.go-up .context-menu {
+ /* line 213, ../sass/controls/_menus.scss */
+ .context-menu-holder.go-up .context-menu, .context-menu-holder.go-up .menu-element .checkbox-menu, .menu-element .context-menu-holder.go-up .checkbox-menu {
bottom: 0; }
-/* line 185, ../sass/controls/_menus.scss */
+/* line 218, ../sass/controls/_menus.scss */
.btn-bar.right .menu,
.menus-to-left .menu {
left: auto;
@@ -4429,26 +4457,26 @@ input[type="text"] {
.l-infobubble-wrapper .l-infobubble table tr td {
padding: 2px 0;
vertical-align: top; }
- /* line 57, ../sass/helpers/_bubbles.scss */
+ /* line 53, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble table tr td.label {
padding-right: 10px;
white-space: nowrap; }
- /* line 61, ../sass/helpers/_bubbles.scss */
+ /* line 57, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble table tr td.value {
- white-space: nowrap; }
- /* line 65, ../sass/helpers/_bubbles.scss */
+ word-break: break-all; }
+ /* line 61, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble table tr td.align-wrap {
white-space: normal; }
- /* line 71, ../sass/helpers/_bubbles.scss */
+ /* line 67, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble .title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-bottom: 5px; }
- /* line 78, ../sass/helpers/_bubbles.scss */
+ /* line 74, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-left {
margin-left: 20px; }
- /* line 80, ../sass/helpers/_bubbles.scss */
+ /* line 76, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-left .l-infobubble::before {
right: 100%;
width: 0;
@@ -4456,10 +4484,10 @@ input[type="text"] {
border-top: 6.66667px solid transparent;
border-bottom: 6.66667px solid transparent;
border-right: 10px solid #ddd; }
- /* line 86, ../sass/helpers/_bubbles.scss */
+ /* line 82, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right {
margin-right: 20px; }
- /* line 88, ../sass/helpers/_bubbles.scss */
+ /* line 84, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right .l-infobubble::before {
left: 100%;
width: 0;
@@ -4467,16 +4495,16 @@ input[type="text"] {
border-top: 6.66667px solid transparent;
border-bottom: 6.66667px solid transparent;
border-left: 10px solid #ddd; }
- /* line 95, ../sass/helpers/_bubbles.scss */
+ /* line 91, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-top .l-infobubble::before {
top: 20px; }
- /* line 101, ../sass/helpers/_bubbles.scss */
+ /* line 97, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-btm .l-infobubble::before {
bottom: 20px; }
- /* line 106, ../sass/helpers/_bubbles.scss */
+ /* line 102, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-down {
margin-bottom: 10px; }
- /* line 108, ../sass/helpers/_bubbles.scss */
+ /* line 104, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-down .l-infobubble::before {
left: 50%;
top: 100%;
@@ -4484,21 +4512,21 @@ input[type="text"] {
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 7.5px solid #ddd; }
- /* line 117, ../sass/helpers/_bubbles.scss */
+ /* line 113, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .arw {
z-index: 2; }
- /* line 120, ../sass/helpers/_bubbles.scss */
+ /* line 116, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-up .arw.arw-down, .l-infobubble-wrapper.arw-down .arw.arw-up {
display: none; }
-/* line 127, ../sass/helpers/_bubbles.scss */
+/* line 125, ../sass/helpers/_bubbles.scss */
.l-thumbsbubble-wrapper .arw-up {
width: 0;
height: 0;
border-left: 6.66667px solid transparent;
border-right: 6.66667px solid transparent;
border-bottom: 10px solid #4d4d4d; }
-/* line 130, ../sass/helpers/_bubbles.scss */
+/* line 128, ../sass/helpers/_bubbles.scss */
.l-thumbsbubble-wrapper .arw-down {
width: 0;
height: 0;
@@ -4506,7 +4534,7 @@ input[type="text"] {
border-right: 6.66667px solid transparent;
border-top: 10px solid #4d4d4d; }
-/* line 134, ../sass/helpers/_bubbles.scss */
+/* line 133, ../sass/helpers/_bubbles.scss */
.s-infobubble {
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
@@ -4517,22 +4545,29 @@ input[type="text"] {
background: #ddd;
color: #666;
font-size: 0.8rem; }
- /* line 141, ../sass/helpers/_bubbles.scss */
+ /* line 140, ../sass/helpers/_bubbles.scss */
.s-infobubble .title {
color: #333333;
font-weight: bold; }
/* line 146, ../sass/helpers/_bubbles.scss */
- .s-infobubble tr td {
- border-top: 1px solid #c4c4c4;
+ .s-infobubble table tr td {
+ border: none;
+ border-top: 1px solid #c4c4c4 !important;
font-size: 0.9em; }
- /* line 150, ../sass/helpers/_bubbles.scss */
- .s-infobubble tr:first-child td {
+ /* line 152, ../sass/helpers/_bubbles.scss */
+ .s-infobubble table tr:first-child td {
+ border-top: none !important; }
+ /* line 157, ../sass/helpers/_bubbles.scss */
+ .s-infobubble:first-child td {
border-top: none; }
- /* line 154, ../sass/helpers/_bubbles.scss */
+ /* line 161, ../sass/helpers/_bubbles.scss */
+ .s-infobubble .label {
+ color: gray; }
+ /* line 165, ../sass/helpers/_bubbles.scss */
.s-infobubble .value {
color: #333333; }
-/* line 159, ../sass/helpers/_bubbles.scss */
+/* line 171, ../sass/helpers/_bubbles.scss */
.s-thumbsbubble {
background: #4d4d4d;
color: #b3b3b3; }
diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css
index 8f3ac4871a..93414d5dc1 100644
--- a/platform/commonUI/general/res/css/tree.css
+++ b/platform/commonUI/general/res/css/tree.css
@@ -250,3 +250,248 @@ ul.tree {
/* line 154, ../sass/tree/_tree.scss */
ul.tree ul.tree {
margin-left: 15px; }
+
+/*****************************************************************************
+ * Open MCT Web, Copyright (c) 2014-2015, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT Web is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT Web includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+/* line 23, ../sass/search/_search.scss */
+.abs.search-holder {
+ height: 25px;
+ bottom: 0;
+ z-index: 5; }
+ /* line 27, ../sass/search/_search.scss */
+ .abs.search-holder.active {
+ height: auto;
+ bottom: 0; }
+
+/* line 38, ../sass/search/_search.scss */
+.search {
+ display: flex;
+ flex-direction: column;
+ height: 100%; }
+ /* line 49, ../sass/search/_search.scss */
+ .search .search-bar {
+ font-size: 0.8em;
+ position: relative;
+ width: 100%; }
+ /* line 66, ../sass/search/_search.scss */
+ .search .search-bar .search-input {
+ height: 25px;
+ line-height: 25px;
+ padding-top: 0;
+ padding-bottom: 0; }
+ /* line 73, ../sass/search/_search.scss */
+ .search .search-bar .search-icon,
+ .search .search-bar .clear-icon,
+ .search .search-bar .menu-icon {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ color: #737373;
+ height: 17px;
+ width: 17px;
+ line-height: 17px;
+ position: absolute;
+ text-align: center;
+ top: 4px; }
+ /* line 86, ../sass/search/_search.scss */
+ .search .search-bar .clear-icon,
+ .search .search-bar .menu-icon {
+ cursor: pointer;
+ transition: color .25s; }
+ /* line 93, ../sass/search/_search.scss */
+ .search .search-bar .search-input {
+ position: relative;
+ width: 100%;
+ padding-left: 22px !important;
+ padding-right: 44px !important; }
+ /* line 100, ../sass/search/_search.scss */
+ .search .search-bar .search-input input {
+ width: 100%; }
+ /* line 105, ../sass/search/_search.scss */
+ .search .search-bar .search-icon {
+ color: #737373;
+ left: 3px;
+ transition: visibility .15s, opacity .15s, color .2s;
+ pointer-events: none; }
+ /* line 125, ../sass/search/_search.scss */
+ .search .search-bar .search-input:hover + div.search-icon {
+ color: #a6a6a6; }
+ /* line 129, ../sass/search/_search.scss */
+ .search .search-bar .clear-icon {
+ right: 22px;
+ visibility: hidden;
+ opacity: 0;
+ transition: visibility .15s, opacity .15s, color .2s; }
+ /* line 138, ../sass/search/_search.scss */
+ .search .search-bar .clear-icon.content {
+ visibility: visible;
+ opacity: 1; }
+ /* line 143, ../sass/search/_search.scss */
+ .search .search-bar .clear-icon:hover {
+ color: #a6a6a6; }
+ /* line 148, ../sass/search/_search.scss */
+ .search .search-bar .menu-icon {
+ font-size: 0.8em;
+ padding-right: 4px;
+ right: 4px;
+ text-align: right; }
+ /* line 154, ../sass/search/_search.scss */
+ .search .search-bar .menu-icon:hover {
+ color: #a6a6a6; }
+ /* line 159, ../sass/search/_search.scss */
+ .search .search-bar .search-menu-holder {
+ float: right;
+ left: -20px;
+ z-index: 1;
+ transition: visibility .05s, opacity .05s; }
+ /* line 169, ../sass/search/_search.scss */
+ .search .search-bar .search-menu-holder.off {
+ visibility: hidden;
+ opacity: 0; }
+ /* line 176, ../sass/search/_search.scss */
+ .search .search-bar .menu-icon:hover + div.search-menu-holder {
+ visibility: visible; }
+ /* line 179, ../sass/search/_search.scss */
+ .search .search-bar div.search-menu-holder:hover {
+ visibility: visible; }
+ /* line 184, ../sass/search/_search.scss */
+ .search .active-filter-display {
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+ border-radius: 2px;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ line-height: 130%;
+ padding: 5px 0;
+ padding-left: 1.4625em;
+ font-size: 0.65em;
+ margin-top: 3px; }
+ /* line 199, ../sass/search/_search.scss */
+ .search .active-filter-display .clear-filters-icon {
+ opacity: 0.4;
+ font-size: 0.8em;
+ position: absolute;
+ left: 1px;
+ cursor: pointer; }
+ /* line 210, ../sass/search/_search.scss */
+ .search .active-filter-display.off {
+ visibility: hidden;
+ opacity: 0;
+ height: 0;
+ margin: 0;
+ padding: 0;
+ border: 0; }
+ /* line 220, ../sass/search/_search.scss */
+ .search .search-scroll {
+ order: 3;
+ margin-top: 4px;
+ overflow-y: auto;
+ top: auto;
+ height: auto;
+ max-height: 100%;
+ position: relative; }
+ /* line 235, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item {
+ -moz-transition: background-color 0.25s;
+ -o-transition: background-color 0.25s;
+ -webkit-transition: background-color 0.25s;
+ transition: background-color 0.25s;
+ margin-bottom: 2px;
+ border-radius: 2px;
+ padding-top: 4px;
+ padding-bottom: 2px; }
+ /* line 249, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item .label {
+ margin-left: 6px; }
+ /* line 253, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item .label .title-label {
+ display: inline-block;
+ position: absolute;
+ left: 29px;
+ right: 5px;
+ font-size: .8em;
+ line-height: 17px;
+ width: auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ /* line 275, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item.selected {
+ background: #005177;
+ color: #fff; }
+ /* line 279, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item.selected .view-control {
+ color: #0099cc; }
+ /* line 282, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item.selected .label .type-icon {
+ color: #fff; }
+ /* line 287, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item .label .type-icon .l-icon-link {
+ text-shadow: black 0 1px 2px;
+ z-index: 2;
+ color: #49dedb;
+ font-size: 8px;
+ line-height: 8px;
+ height: 8px;
+ width: 8px;
+ margin-left: -25px; }
+ /* line 296, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item:not(.selected):hover {
+ background: #404040;
+ color: #cccccc; }
+ /* line 299, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item:not(.selected):hover .context-trigger {
+ display: block; }
+ /* line 302, ../sass/search/_search.scss */
+ .search .search-scroll .results .search-result-item:not(.selected):hover .icon {
+ color: #33ccff; }
+ /* line 310, ../sass/search/_search.scss */
+ .search .search-scroll .load-icon {
+ position: relative; }
+ /* line 312, ../sass/search/_search.scss */
+ .search .search-scroll .load-icon.loading {
+ pointer-events: none;
+ margin-left: 6px; }
+ /* line 316, ../sass/search/_search.scss */
+ .search .search-scroll .load-icon.loading .title-label {
+ font-style: italic;
+ font-size: .9em;
+ opacity: 0.5;
+ margin-left: 26px;
+ line-height: 24px; }
+ /* line 326, ../sass/search/_search.scss */
+ .search .search-scroll .load-icon.loading .wait-spinner {
+ margin-left: 6px; }
+ /* line 331, ../sass/search/_search.scss */
+ .search .search-scroll .load-icon:not(.loading) {
+ cursor: pointer; }
+ /* line 336, ../sass/search/_search.scss */
+ .search .search-scroll .load-more-button {
+ margin-top: 5px 0;
+ font-size: 0.8em;
+ position: relative;
+ left: 50%;
+ margin-left: -45px;
+ text-align: center;
+ width: 90px;
+ white-space: nowrap; }
diff --git a/platform/commonUI/general/res/fonts/symbols/icomoon.io-WTD-symbols-project.json b/platform/commonUI/general/res/fonts/symbols/icomoon.io-WTD-symbols-project.json
index 502ce67f79..cd432472af 100644
--- a/platform/commonUI/general/res/fonts/symbols/icomoon.io-WTD-symbols-project.json
+++ b/platform/commonUI/general/res/fonts/symbols/icomoon.io-WTD-symbols-project.json
@@ -1,19 +1,27 @@
{
"metadata": {
- "name": "WTD Symbols v2.1",
- "lastOpened": 1439844340068,
- "created": 1439844318831
+ "name": "WTD Symbols v2.2",
+ "lastOpened": 1439948744240,
+ "created": 1439948734037
},
"iconSets": [
{
"selection": [
+ {
+ "order": 82,
+ "id": 84,
+ "prevSize": 32,
+ "code": 58887,
+ "name": "icon-x-in-circle",
+ "tempChar": ""
+ },
{
"order": 77,
"id": 83,
"prevSize": 32,
"code": 58881,
"name": "icon-datatable",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 78,
@@ -21,7 +29,7 @@
"prevSize": 32,
"code": 58882,
"name": "icon-tabular-scrolling",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 79,
@@ -29,7 +37,7 @@
"prevSize": 32,
"code": 58884,
"name": "icon-tabular",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 80,
@@ -37,7 +45,7 @@
"prevSize": 32,
"code": 58885,
"name": "icon-calendar",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 81,
@@ -45,7 +53,7 @@
"prevSize": 32,
"code": 58886,
"name": "icon-paint-bucket",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 1,
@@ -53,7 +61,7 @@
"prevSize": 32,
"code": 123,
"name": "icon-pointer-left",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 3,
@@ -61,7 +69,7 @@
"prevSize": 32,
"code": 125,
"name": "icon-pointer-right",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 4,
@@ -69,7 +77,7 @@
"prevSize": 32,
"code": 80,
"name": "icon-person",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 5,
@@ -77,7 +85,7 @@
"prevSize": 32,
"code": 232,
"name": "icon-chain-links",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 6,
@@ -85,7 +93,7 @@
"prevSize": 32,
"code": 115,
"name": "icon-database-in-brackets",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 7,
@@ -93,7 +101,7 @@
"prevSize": 32,
"code": 114,
"name": "icon-refresh",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 8,
@@ -101,7 +109,7 @@
"prevSize": 32,
"code": 108,
"name": "icon-lock",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 9,
@@ -109,7 +117,7 @@
"prevSize": 32,
"code": 51,
"name": "icon-box-with-dashed-lines",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 10,
@@ -117,7 +125,7 @@
"prevSize": 32,
"code": 58880,
"name": "icon-box-with-arrow-cursor",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 11,
@@ -125,7 +133,7 @@
"prevSize": 32,
"code": 65,
"name": "icon-activity-mode",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 12,
@@ -133,7 +141,7 @@
"prevSize": 32,
"code": 97,
"name": "icon-activity",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 13,
@@ -141,7 +149,7 @@
"prevSize": 32,
"code": 33,
"name": "icon-alert-rect",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 14,
@@ -149,7 +157,7 @@
"prevSize": 32,
"code": 58883,
"name": "icon-alert-triangle",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 15,
@@ -157,7 +165,7 @@
"prevSize": 32,
"code": 238,
"name": "icon-arrow-double-down",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 16,
@@ -165,7 +173,7 @@
"prevSize": 32,
"code": 235,
"name": "icon-arrow-double-up",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 2,
@@ -173,7 +181,7 @@
"prevSize": 32,
"code": 118,
"name": "icon-arrow-down",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 19,
@@ -181,7 +189,7 @@
"prevSize": 32,
"code": 60,
"name": "icon-arrow-left",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 20,
@@ -189,7 +197,7 @@
"prevSize": 32,
"code": 62,
"name": "icon-arrow-right",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 21,
@@ -197,7 +205,7 @@
"prevSize": 32,
"code": 236,
"name": "icon-arrow-tall-down",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 22,
@@ -205,7 +213,7 @@
"prevSize": 32,
"code": 237,
"name": "icon-arrow-tall-up",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 23,
@@ -213,7 +221,7 @@
"prevSize": 32,
"code": 94,
"name": "icon-arrow-up",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 24,
@@ -221,7 +229,7 @@
"prevSize": 32,
"code": 73,
"name": "icon-arrows-out",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 25,
@@ -229,7 +237,7 @@
"prevSize": 32,
"code": 58893,
"name": "icon-arrows-right-left",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 33,
@@ -237,7 +245,7 @@
"prevSize": 32,
"code": 53,
"name": "icon-arrows-up-down",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 26,
@@ -245,7 +253,7 @@
"prevSize": 32,
"code": 42,
"name": "icon-asterisk",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 27,
@@ -253,7 +261,7 @@
"prevSize": 32,
"code": 72,
"name": "icon-autoflow-tabular",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 28,
@@ -261,7 +269,7 @@
"prevSize": 32,
"code": 224,
"name": "icon-box-round-corners",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 29,
@@ -269,7 +277,7 @@
"prevSize": 32,
"code": 50,
"name": "icon-check",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 30,
@@ -277,7 +285,7 @@
"prevSize": 32,
"code": 67,
"name": "icon-clock",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 31,
@@ -285,7 +293,7 @@
"prevSize": 32,
"code": 46,
"name": "icon-connectivity",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 32,
@@ -293,7 +301,7 @@
"prevSize": 32,
"code": 100,
"name": "icon-database-query",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 17,
@@ -301,7 +309,7 @@
"prevSize": 32,
"code": 68,
"name": "icon-database",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 35,
@@ -309,7 +317,7 @@
"prevSize": 32,
"code": 81,
"name": "icon-dictionary",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 36,
@@ -317,7 +325,7 @@
"prevSize": 32,
"code": 242,
"name": "icon-duplicate",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 37,
@@ -325,7 +333,7 @@
"prevSize": 32,
"code": 102,
"name": "icon-folder-new",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 38,
@@ -333,7 +341,7 @@
"prevSize": 32,
"code": 70,
"name": "icon-folder",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 39,
@@ -341,7 +349,7 @@
"prevSize": 32,
"code": 95,
"name": "icon-fullscreen-collapse",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 40,
@@ -349,7 +357,7 @@
"prevSize": 32,
"code": 122,
"name": "icon-fullscreen-expand",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 41,
@@ -357,7 +365,7 @@
"prevSize": 32,
"code": 71,
"name": "icon-gear",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 49,
@@ -365,7 +373,7 @@
"prevSize": 32,
"code": 227,
"name": "icon-image",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 42,
@@ -373,7 +381,7 @@
"prevSize": 32,
"code": 225,
"name": "icon-layers",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 43,
@@ -381,7 +389,7 @@
"prevSize": 32,
"code": 76,
"name": "icon-layout",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 44,
@@ -389,7 +397,7 @@
"prevSize": 32,
"code": 226,
"name": "icon-line-horz",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 75,
@@ -397,7 +405,7 @@
"prevSize": 32,
"code": 244,
"name": "icon-link",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 46,
@@ -405,7 +413,7 @@
"prevSize": 32,
"code": 88,
"name": "icon-magnify-in",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 47,
@@ -413,7 +421,7 @@
"prevSize": 32,
"code": 89,
"name": "icon-magnify-out",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 48,
@@ -421,7 +429,7 @@
"prevSize": 32,
"code": 77,
"name": "icon-magnify",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 34,
@@ -429,7 +437,7 @@
"prevSize": 32,
"code": 109,
"name": "icon-menu",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 50,
@@ -437,7 +445,7 @@
"prevSize": 32,
"code": 243,
"name": "icon-move",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 51,
@@ -445,7 +453,7 @@
"prevSize": 32,
"code": 121,
"name": "icon-new-window",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 52,
@@ -453,7 +461,7 @@
"prevSize": 32,
"code": 111,
"name": "icon-object",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 73,
@@ -461,7 +469,7 @@
"prevSize": 32,
"code": 63,
"name": "icon-object-unknown",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 53,
@@ -469,7 +477,7 @@
"prevSize": 32,
"code": 86,
"name": "icon-packet",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 54,
@@ -477,7 +485,7 @@
"prevSize": 32,
"code": 234,
"name": "icon-page",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 55,
@@ -485,7 +493,7 @@
"prevSize": 32,
"code": 241,
"name": "icon-pause",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 56,
@@ -493,7 +501,7 @@
"prevSize": 32,
"code": 112,
"name": "icon-pencil",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 65,
@@ -501,7 +509,7 @@
"prevSize": 32,
"code": 79,
"name": "icon-people",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 57,
@@ -509,7 +517,7 @@
"prevSize": 32,
"code": 239,
"name": "icon-play",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 58,
@@ -517,7 +525,7 @@
"prevSize": 32,
"code": 233,
"name": "icon-plot-resource",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 59,
@@ -525,7 +533,7 @@
"prevSize": 32,
"code": 43,
"name": "icon-plus",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 60,
@@ -533,7 +541,7 @@
"prevSize": 32,
"code": 45,
"name": "icon-minus",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 61,
@@ -541,7 +549,7 @@
"prevSize": 32,
"code": 54,
"name": "icon-sine",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 62,
@@ -549,7 +557,7 @@
"prevSize": 32,
"code": 228,
"name": "icon-T",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 63,
@@ -557,7 +565,7 @@
"prevSize": 32,
"code": 116,
"name": "icon-telemetry-panel",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 64,
@@ -565,7 +573,7 @@
"prevSize": 32,
"code": 84,
"name": "icon-telemetry",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 18,
@@ -573,7 +581,7 @@
"prevSize": 32,
"code": 246,
"name": "icon-thumbs-strip",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 67,
@@ -581,7 +589,7 @@
"prevSize": 32,
"code": 83,
"name": "icon-timeline",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 68,
@@ -589,7 +597,7 @@
"prevSize": 32,
"code": 245,
"name": "icon-timer",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 69,
@@ -597,7 +605,7 @@
"prevSize": 32,
"code": 90,
"name": "icon-trash",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 70,
@@ -605,7 +613,7 @@
"prevSize": 32,
"code": 229,
"name": "icon-two-parts-both",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 71,
@@ -613,7 +621,7 @@
"prevSize": 32,
"code": 231,
"name": "icon-two-parts-one-only",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 72,
@@ -621,7 +629,7 @@
"prevSize": 32,
"code": 120,
"name": "icon-x-heavy",
- "tempChar": ""
+ "tempChar": ""
},
{
"order": 66,
@@ -629,7 +637,7 @@
"prevSize": 32,
"code": 58946,
"name": "icon-x",
- "tempChar": ""
+ "tempChar": ""
}
],
"id": 2,
@@ -644,6 +652,21 @@
"height": 1024,
"prevSize": 32,
"icons": [
+ {
+ "id": 84,
+ "paths": [
+ "M512 0c-282.8 0-512 229.2-512 512s229.2 512 512 512 512-229.2 512-512-229.2-512-512-512zM832 704l-128 128-192-192-192 192-128-128 192-192-192-192 128-128 192 192 192-192 128 128-192 192 192 192z"
+ ],
+ "attrs": [],
+ "isMulticolor": false,
+ "grid": 0,
+ "tags": [
+ "icon-x-in-circle"
+ ],
+ "colorPermutations": {
+ "16161751": []
+ }
+ },
{
"id": 83,
"paths": [
@@ -666,6 +689,10 @@
"icon-datatable"
],
"colorPermutations": {
+ "16161751": [
+ 1,
+ 1
+ ],
"125525525516161751": [
1,
1
@@ -709,6 +736,13 @@
"icon-tabular-scrolling"
],
"colorPermutations": {
+ "16161751": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
"125525525516161751": [
1,
1,
@@ -760,6 +794,14 @@
"icon-tabular"
],
"colorPermutations": {
+ "16161751": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
"125525525516161751": [
0,
0,
@@ -787,6 +829,9 @@
"icon-calendar"
],
"colorPermutations": {
+ "16161751": [
+ 1
+ ],
"125525525516161751": [
1
]
@@ -814,6 +859,10 @@
"icon-paint-bucket"
],
"colorPermutations": {
+ "16161751": [
+ 1,
+ 1
+ ],
"125525525516161751": [
1,
1
diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot
index 2f4f938076..3087b1c7a5 100755
Binary files a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot and b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot differ
diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg
index d31a879fc3..6d9fbdd714 100755
--- a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg
+++ b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg
@@ -83,6 +83,7 @@
+
\ No newline at end of file
diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf
index 37af03fa79..a2a5aa3bfd 100755
Binary files a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf and b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf differ
diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff
index c93e44215c..fba91366e9 100755
Binary files a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff and b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff differ
diff --git a/platform/commonUI/general/res/sass/_constants.scss b/platform/commonUI/general/res/sass/_constants.scss
index 22518172da..66a9b08626 100644
--- a/platform/commonUI/general/res/sass/_constants.scss
+++ b/platform/commonUI/general/res/sass/_constants.scss
@@ -100,6 +100,7 @@ $ueAppLogoW: 105px;
$ueEditToolBarH: 25px;
$ueBrowseLeftPaneW: 25%;
$ueEditLeftPaneW: 75%;
+$treeSearchInputBarH: 25px;
// Overlay
$ovrTopBarH: 60px;
$ovrFooterH: 40px;
diff --git a/platform/commonUI/general/res/sass/_main.scss b/platform/commonUI/general/res/sass/_main.scss
index 5866aee700..8144885d27 100644
--- a/platform/commonUI/general/res/sass/_main.scss
+++ b/platform/commonUI/general/res/sass/_main.scss
@@ -1,3 +1,4 @@
+/*****************************************************************************
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
@@ -31,6 +32,7 @@
@import "global";
@import "fonts";
@import "user-environ/layout";
+//@import "search/layout";
@import "fixed-position";
@import "about";
@import "text";
diff --git a/platform/commonUI/general/res/sass/controls/_menus.scss b/platform/commonUI/general/res/sass/controls/_menus.scss
index 59312a46a2..14210198ab 100644
--- a/platform/commonUI/general/res/sass/controls/_menus.scss
+++ b/platform/commonUI/general/res/sass/controls/_menus.scss
@@ -21,15 +21,15 @@
*****************************************************************************/
/******************************************************** MENUS */
.menu-element {
- $bg: lighten($colorBodyBg, 5%);
+ $bg: lighten($colorBodyBg, 5%);
$bgHover: lighten($bg, 20%);
$iconColor: $colorKey;
cursor: pointer;
position: relative;
.menu {
@include border-radius($basicCr);
- @include containerSubtle($bg);
- @include txtShdwSubtle(0.2);
+ @include containerSubtle($bg);
+ @include txtShdwSubtle(0.2);
display: block; // set to block via jQuery
padding: $interiorMarginSm 0;
position: absolute;
@@ -37,11 +37,12 @@
ul {
@include menuUlReset();
li {
- @include box-sizing(border-box);
+ @include box-sizing(border-box);
border-top: 1px solid lighten($bg, 20%);
color: lighten($bg, 60%);
line-height: $menuLineH;
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
+ position: relative;
white-space: nowrap;
&:first-child {
border: none;
@@ -61,7 +62,7 @@
// display: block;
//}
.type-icon {
- left: $interiorMargin * 2;
+ left: $interiorMargin * 2;
}
}
}
@@ -77,7 +78,9 @@
@include containerSubtle($bg);
ul li {
padding-left: 25px;
- a { color: $fg; }
+ a {
+ color: $fg;
+ }
.icon {
color: $ic;
}
@@ -90,99 +93,131 @@
}
}
+ .checkbox-menu {
+ // Used in search dropdown in tree
+ @extend .context-menu;
+ ul li {
+ padding-left: 50px;
+ .checkbox {
+ $d: 0.7rem;
+ position: absolute;
+ left: $interiorMargin;
+ top: ($menuLineH - $d) / 1.5;
+ em {
+ height: $d;
+ width: $d;
+ &:before {
+ font-size: 7px !important;// $d/2;
+ height: $d;
+ width: $d;
+ line-height: $d;
+ }
+ }
+ }
+ .type-icon {
+ left: 25px;
+ }
+ }
+ }
- .super-menu {
- $w: 500px;
- $h: $w - 20;
- $plw: 50%; //$w * 0.5;
- $prw: 50%; //$w - $plw;
- $fg: #fff; //lighten($colorBodyFg, 40%);
- $bgHover: $colorKey; //$bg;
- display: block;
- width: $w;
- height: $h;
- .contents {
- @include absPosDefault($interiorMargin);
- }
- .pane {
- @include box-sizing(border-box);
- &.left {
- //@include test();
- border-right: 1px solid rgba(white, 0.2);
- left: 0;
- padding-right: $interiorMargin;
- right: auto;
- width: $plw;
- overflow-x: hidden;
- overflow-y: auto;
- ul {
- li {
- @include border-radius($controlCr);
- padding-left: 30px;
- border-top: none;
- }
- }
- }
- &.right {
- //@include test(red);
- left: auto;
- right: 0;
- padding: $interiorMargin * 5;
- width: $prw;
- .icon {
- color: $fg;
- }
- }
- }
- .menu-item-description {
- .desc-area {
- &.icon {
- $h: 150px;
- position: relative;
- font-size: 8em;
- left: 0;
- height: $h;
- line-height: $h;
- margin-bottom: $interiorMargin * 5;
- text-align: center;
- }
- &.title {
- color: $fg;
- font-size: 1.2em;
- margin-bottom: 0.5em;
- }
- &.description {
- //color: lighten($bg, 30%);
- color: $fg;
- font-size: 0.8em;
- line-height: 1.5em;
- }
- }
- }
- }
- .context-menu {
- font-size: 0.80rem;
- }
+ .super-menu {
+ $w: 500px;
+ $h: $w - 20;
+ $plw: 50%; //$w * 0.5;
+ $prw: 50%; //$w - $plw;
+ $fg: #fff; //lighten($colorBodyFg, 40%);
+ $bgHover: $colorKey; //$bg;
+ display: block;
+ width: $w;
+ height: $h;
+ .contents {
+ @include absPosDefault($interiorMargin);
+ }
+ .pane {
+ @include box-sizing(border-box);
+ &.left {
+ //@include test();
+ border-right: 1px solid rgba(white, 0.2);
+ left: 0;
+ padding-right: $interiorMargin;
+ right: auto;
+ width: $plw;
+ overflow-x: hidden;
+ overflow-y: auto;
+ ul {
+ li {
+ @include border-radius($controlCr);
+ padding-left: 30px;
+ border-top: none;
+ }
+ }
+ }
+ &.right {
+ //@include test(red);
+ left: auto;
+ right: 0;
+ padding: $interiorMargin * 5;
+ width: $prw;
+ .icon {
+ color: $fg;
+ }
+ }
+ }
+ .menu-item-description {
+ .desc-area {
+ &.icon {
+ $h: 150px;
+ position: relative;
+ font-size: 8em;
+ left: 0;
+ height: $h;
+ line-height: $h;
+ margin-bottom: $interiorMargin * 5;
+ text-align: center;
+ }
+ &.title {
+ color: $fg;
+ font-size: 1.2em;
+ margin-bottom: 0.5em;
+ }
+ &.description {
+ //color: lighten($bg, 30%);
+ color: $fg;
+ font-size: 0.8em;
+ line-height: 1.5em;
+ }
+ }
+ }
+ }
+ .context-menu {
+ font-size: 0.80rem;
+ }
}
.context-menu-holder {
- pointer-events: none;
- position: absolute;
- height: 200px;
- width: 170px;
- z-index: 70;
- .context-menu-wrapper {
- position: absolute;
- height: 100%;
- width: 100%;
- .context-menu {
- }
- }
- &.go-left .context-menu { right: 0; }
- &.go-up .context-menu { bottom: 0; }
+ pointer-events: none;
+ position: absolute;
+ height: 200px;
+ width: 170px;
+ z-index: 70;
+ .context-menu-wrapper {
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ .context-menu {
+ }
+ }
+ &.go-left .context-menu {
+ right: 0;
+ }
+ &.go-up .context-menu {
+ bottom: 0;
+ }
}
.btn-bar.right .menu,
.menus-to-left .menu {
- left: auto; right: 0; width: auto;
+ left: auto;
+ right: 0;
+ width: auto;
}
\ No newline at end of file
diff --git a/platform/commonUI/general/res/sass/helpers/_bubbles.scss b/platform/commonUI/general/res/sass/helpers/_bubbles.scss
index 5b174ba6da..10deec9645 100644
--- a/platform/commonUI/general/res/sass/helpers/_bubbles.scss
+++ b/platform/commonUI/general/res/sass/helpers/_bubbles.scss
@@ -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
?
+ word-break: break-all;
}
&.align-wrap {
white-space: normal;
@@ -118,7 +114,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
@@ -131,6 +129,7 @@
@include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg);
}
}
+
.s-infobubble {
$emFg: darken($colorInfoBubbleFg, 20%);
@include border-radius($basicCr);
@@ -142,18 +141,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 {
diff --git a/platform/commonUI/general/res/sass/lists/_tabular.scss b/platform/commonUI/general/res/sass/lists/_tabular.scss
index 629cac9d1a..0621cad46b 100644
--- a/platform/commonUI/general/res/sass/lists/_tabular.scss
+++ b/platform/commonUI/general/res/sass/lists/_tabular.scss
@@ -82,18 +82,21 @@ table {
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-bottom: 1px solid $tabularColorBorder;
diff --git a/platform/commonUI/general/res/sass/search/_layout.scss b/platform/commonUI/general/res/sass/search/_layout.scss
new file mode 100644
index 0000000000..03612d2d3c
--- /dev/null
+++ b/platform/commonUI/general/res/sass/search/_layout.scss
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * Open MCT Web, Copyright (c) 2014-2015, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT Web is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT Web includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+
+// Overrides some styling in user-environ/_layout.scss
+.pane {
+ &.treeview.left {
+ .tree-holder {
+ // Want tree holder to start right below the search bar.
+ top: 60px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss
new file mode 100644
index 0000000000..ce9286e947
--- /dev/null
+++ b/platform/commonUI/general/res/sass/search/_search.scss
@@ -0,0 +1,347 @@
+/*****************************************************************************
+ * Open MCT Web, Copyright (c) 2014-2015, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT Web is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT Web includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+
+.abs.search-holder {
+ //@include test(#990000);
+ height: $treeSearchInputBarH;
+ bottom: 0;
+ &.active {
+ height: auto;
+ bottom: 0;
+ }
+ //top: 23px;
+
+ // Align with the top of the divider bar, below create button
+ //margin-top: 10px; // CH comment out
+ z-index:5;
+}
+
+.search {
+ $iconWidth: 20px;
+ $leftMargin: 6px;
+ $rightPadding: 5px;
+
+ //padding-right: $rightPadding;
+ //@include test();
+ display: flex; //block;
+ flex-direction: column;
+ height: 100%;
+
+ .search-bar {
+ //$heightAdjust: 4px;
+ $textInputHeight: 19px; // This is equal to the default value, 19px
+ $iconEdgeM: 4px;
+ $iconD: $treeSearchInputBarH - ($iconEdgeM*2);
+ font-size: 0.8em;
+
+ //order: 1;
+
+ position: relative;
+ width: 100%;
+ //height: $textInputHeight;
+ //margin-top: $heightAdjust;
+ .search-input,
+ .search-icon {
+ }
+
+ .search-input {
+ height: $treeSearchInputBarH;
+ line-height: $treeSearchInputBarH;
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ .search-icon,
+ .clear-icon,
+ .menu-icon {
+ //@include test(#008800);
+ @include box-sizing(border-box);
+ color: $colorItemFg;
+ height: $iconD; width: $iconD;
+ line-height: $iconD;
+ position: absolute;
+ text-align: center;
+ top: $iconEdgeM;
+ }
+
+ .clear-icon,
+ .menu-icon {
+ cursor: pointer;
+ transition: color .25s;
+ }
+
+
+ .search-input {
+ position: relative;
+ width: 100%;
+ padding-left: $iconD + $interiorMargin !important;
+ padding-right: ($iconD * 2) + ($interiorMargin * 2) !important;
+
+ // Make work for mct-control textfield
+ input {
+ width: 100%;
+ }
+ }
+
+ .search-icon {
+ color: $colorItemFg;
+ left: $interiorMarginSm;
+ transition: visibility .15s, opacity .15s, color .2s;
+ pointer-events: none;
+
+ &.content {
+ // Make icon invisible whenever there is text input
+ //visibility: hidden;
+ //opacity: 0;
+ }
+ }
+
+ // Make icon invisible when the text input is focused
+ .search-input:focus + div.search-icon {
+ //visibility: hidden;
+ //opacity: 0;
+ }
+
+ // Make icon lighten when hovering over search bar
+ .search-input:hover + div.search-icon {
+ color: lighten($colorItemFg, 20%);
+ }
+
+ .clear-icon {
+ right: $iconD + $interiorMargin;
+
+ // Icon is visible only when there is text input
+ visibility: hidden;
+ opacity: 0;
+
+ transition: visibility .15s, opacity .15s, color .2s;
+
+ &.content {
+ visibility: visible;
+ opacity: 1;
+ }
+
+ &:hover {
+ color: lighten($colorItemFg, 20%);
+ }
+ }
+
+ .menu-icon {
+ font-size: 0.8em;
+ padding-right: $iconEdgeM;
+ right: $iconEdgeM;
+ text-align: right;
+
+ &:hover {
+ color: lighten($colorItemFg, 20%);
+ }
+ }
+
+ .search-menu-holder {
+ float: right;
+ //margin-top: $textInputHeight - 2px;
+ //left: -50px;
+ left: -20px;
+
+ z-index: 1;
+
+ transition: visibility .05s, opacity .05s;
+
+ &.off {
+ visibility: hidden;
+ opacity: 0;
+ }
+ }
+
+ // Hovering reveals menu
+ .menu-icon:hover + div.search-menu-holder {
+ visibility: visible;
+ }
+ div.search-menu-holder:hover {
+ visibility: visible;
+ }
+ }
+
+ .active-filter-display {
+ //order: 2;
+ $s: 0.65em;
+ $p: $interiorMargin;
+ @include border-radius($basicCr);
+ @include box-sizing(border-box);
+ line-height: 130%;
+ padding: $p 0;
+ padding-left: $s * 2.25;
+ font-size: $s;
+ //background-color: rgba(#000, 0.3);
+ //border-radius: $basicCr;
+ margin-top: $interiorMarginSm;
+
+
+ .clear-filters-icon {
+ opacity: 0.4;
+ font-size: 0.8em;
+ position: absolute;
+ left: 1px;
+ cursor: pointer;
+ }
+
+ // Transition looks weird when the results list has none
+ //transition: visibility .2s, opacity .2s;
+
+ &.off {
+ visibility: hidden;
+ opacity: 0;
+ height: 0;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ }
+ }
+
+ .search-scroll {
+ order: 3;
+
+ //padding-right: $rightPadding;
+ margin-top: 4px;
+
+ // Adjustable scrolling size
+ overflow-y: auto;
+ top: auto;
+ height: auto;
+ max-height: 100%;
+ position: relative;
+
+ .results {
+
+ .search-result-item {
+ // Include transitions (for the highlights)
+ @include single-transition(background-color, 0.25s);
+
+ // Space the results from each other
+ margin-bottom: 2px;
+
+ // Make the highlights the right color and shape.
+ // Attempting to match the style in the tree, but
+ // while having these be compact.
+ border-radius: 2px;
+ padding-top: 4px;
+ padding-bottom: 2px;
+
+ .label {
+ // Give some padding away from the left side
+ margin-left: $leftMargin;
+
+ .title-label {
+ display: inline-block;
+ position: absolute;
+
+ // Give some padding away from the left side
+ left: $leftMargin + 3px + $iconWidth;
+ // and the right side
+ right: $rightPadding;
+
+ // Size and position the text
+ font-size: .8em;
+ line-height: 17px;
+
+ // Hide overflow text
+ width: auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+
+ // Change styling when it's selected
+ &.selected {
+ $c: #fff;
+ background: $colorKeySelectedBg;
+ color: $c;
+ .view-control {
+ color: $colorItemTreeIcon;
+ }
+ .label .type-icon {
+ color: #fff;
+ }
+ }
+
+ .label .type-icon .l-icon-link {
+ @include txtShdwSubtle(1);
+ z-index: 2;
+ @include ancillaryIcon(8px, $colorIconLink);
+ margin-left: -25px;
+ }
+
+ // Change styling when it's being hovered over
+ &:not(.selected) {
+ &:hover {
+ background: lighten($colorBodyBg, 5%);
+ color: lighten($colorBodyFg, 20%);
+ .context-trigger {
+ display: block;
+ }
+ .icon {
+ color: $colorItemTreeIconHover;
+ }
+ }
+ }
+ }
+ }
+
+ .load-icon {
+ position: relative;
+ &.loading {
+ pointer-events: none;
+ margin-left: $leftMargin;
+
+ .title-label {
+ // Text styling
+ font-style: italic;
+ font-size: .9em;
+ opacity: 0.5;
+
+ // Text positioning
+ margin-left: $iconWidth + $leftMargin;
+ line-height: 24px;
+ }
+ .wait-spinner {
+ margin-left: $leftMargin;
+ }
+ }
+
+ &:not(.loading) {
+ cursor: pointer;
+ }
+ }
+
+ .load-more-button {
+ margin-top: $interiorMargin 0;
+ font-size: 0.8em;
+ position: relative;
+ left: 50%;
+ margin-left: -45px;
+ text-align: center;
+ width: 90px;
+ white-space: nowrap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/platform/commonUI/general/res/sass/tree.scss b/platform/commonUI/general/res/sass/tree.scss
index b8b2d09124..82b2338f30 100644
--- a/platform/commonUI/general/res/sass/tree.scss
+++ b/platform/commonUI/general/res/sass/tree.scss
@@ -27,4 +27,5 @@
@import "constants";
@import "mixins";
-@import "tree/tree";
\ No newline at end of file
+@import "tree/tree";
+@import "search/search";
\ No newline at end of file
diff --git a/platform/commonUI/general/res/sass/user-environ/_layout.scss b/platform/commonUI/general/res/sass/user-environ/_layout.scss
index a07ed38953..ed56ec3e98 100644
--- a/platform/commonUI/general/res/sass/user-environ/_layout.scss
+++ b/platform/commonUI/general/res/sass/user-environ/_layout.scss
@@ -229,10 +229,12 @@
bottom: $interiorMargin;
}
}
+ .search-holder {
+ top: $ueTopBarH + $interiorMarginLg;
+ }
.tree-holder {
overflow: auto;
- top: $ueTopBarH + $interiorMarginLg;
- padding-right: $interiorMargin;
+ top: $ueTopBarH + $interiorMarginLg + $treeSearchInputBarH + $interiorMargin;
}
}
&.items {
diff --git a/platform/commonUI/general/src/StyleSheetLoader.js b/platform/commonUI/general/src/StyleSheetLoader.js
index 9775288b28..19c0ffc291 100644
--- a/platform/commonUI/general/src/StyleSheetLoader.js
+++ b/platform/commonUI/general/src/StyleSheetLoader.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/ActionGroupController.js b/platform/commonUI/general/src/controllers/ActionGroupController.js
index 1675d2e611..0992b5e967 100644
--- a/platform/commonUI/general/src/controllers/ActionGroupController.js
+++ b/platform/commonUI/general/src/controllers/ActionGroupController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/BottomBarController.js b/platform/commonUI/general/src/controllers/BottomBarController.js
index b33ce0fe7a..d53d76fce6 100644
--- a/platform/commonUI/general/src/controllers/BottomBarController.js
+++ b/platform/commonUI/general/src/controllers/BottomBarController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/ClickAwayController.js b/platform/commonUI/general/src/controllers/ClickAwayController.js
index 75b1d985da..9c7c6f8091 100644
--- a/platform/commonUI/general/src/controllers/ClickAwayController.js
+++ b/platform/commonUI/general/src/controllers/ClickAwayController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/ContextMenuController.js b/platform/commonUI/general/src/controllers/ContextMenuController.js
index 4e1bcd3b8f..dece522682 100644
--- a/platform/commonUI/general/src/controllers/ContextMenuController.js
+++ b/platform/commonUI/general/src/controllers/ContextMenuController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/GetterSetterController.js b/platform/commonUI/general/src/controllers/GetterSetterController.js
index 05d7b2f4ef..3d61c00116 100644
--- a/platform/commonUI/general/src/controllers/GetterSetterController.js
+++ b/platform/commonUI/general/src/controllers/GetterSetterController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/SelectorController.js b/platform/commonUI/general/src/controllers/SelectorController.js
index 5b09f3423a..26fe5f4d62 100644
--- a/platform/commonUI/general/src/controllers/SelectorController.js
+++ b/platform/commonUI/general/src/controllers/SelectorController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/SplitPaneController.js b/platform/commonUI/general/src/controllers/SplitPaneController.js
index c747f2f256..75dfed28d9 100644
--- a/platform/commonUI/general/src/controllers/SplitPaneController.js
+++ b/platform/commonUI/general/src/controllers/SplitPaneController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/ToggleController.js b/platform/commonUI/general/src/controllers/ToggleController.js
index 0d3bd664ca..9d7d493f15 100644
--- a/platform/commonUI/general/src/controllers/ToggleController.js
+++ b/platform/commonUI/general/src/controllers/ToggleController.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/TreeNodeController.js b/platform/commonUI/general/src/controllers/TreeNodeController.js
index 77124bb6e3..1ef72491d8 100644
--- a/platform/commonUI/general/src/controllers/TreeNodeController.js
+++ b/platform/commonUI/general/src/controllers/TreeNodeController.js
@@ -48,12 +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, $rootScope) {
- var selectedObject = ($scope.ngModel || {}).selectedObject,
- isSelected = false,
- hasBeenExpanded = false;
+ function TreeNodeController($scope, $timeout) {
+ var self = this,
+ selectedObject = ($scope.ngModel || {}).selectedObject;
// Look up the id for a domain object. A convenience
// for mapping; additionally does some undefined-checking.
@@ -76,17 +76,6 @@ define(
checkPath(nodePath, navPath, index + 1));
}
- // Track that a node has been expanded, either by the
- // user or automatically to show a selection.
- function trackExpansion() {
- if (!hasBeenExpanded) {
- // Run on a timeout; if a lot of expansion needs to
- // occur (e.g. if the selection is several nodes deep) we
- // want this to be spread across multiple digest cycles.
- $timeout(function () { hasBeenExpanded = true; }, 0);
- }
- }
-
// Consider the currently-navigated object and update
// parameters which support display.
function checkSelection() {
@@ -101,7 +90,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)
@@ -120,12 +109,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();
}
}
@@ -138,38 +127,52 @@ define(
selectedObject = object;
checkSelection();
}
-
+
+ this.isSelectedFlag = false;
+ this.hasBeenExpandedFlag = false;
+ this.$timeout = $timeout;
+
// 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,
- /**
- * Check if this not has ever been expanded.
- * @returns true if it has been expanded
- */
- hasBeenExpanded: function () {
- return hasBeenExpanded;
- },
- /**
- * Check whether or not the domain object represented by
- * this tree node should be highlighted.
- * An object will be highlighted if it matches
- * ngModel.selectedObject
- * @returns true if this should be highlighted
- */
- isSelected: function () {
- return isSelected;
- }
- };
}
+ /**
+ * This method should be called when a node is expanded
+ * to record that this has occurred, to support one-time
+ * lazy loading of the node's subtree.
+ */
+ TreeNodeController.prototype.trackExpansion = function () {
+ var self = this;
+ if (!self.hasBeenExpanded()) {
+ // Run on a timeout; if a lot of expansion needs to
+ // occur (e.g. if the selection is several nodes deep) we
+ // want this to be spread across multiple digest cycles.
+ self.$timeout(function () {
+ self.hasBeenExpandedFlag = true;
+ }, 0);
+ }
+ };
+
+ /**
+ * Check if this not has ever been expanded.
+ * @returns true if it has been expanded
+ */
+ TreeNodeController.prototype.hasBeenExpanded = function () {
+ return this.hasBeenExpandedFlag;
+ };
+
+ /**
+ * Check whether or not the domain object represented by
+ * this tree node should be highlighted.
+ * An object will be highlighted if it matches
+ * ngModel.selectedObject
+ * @returns true if this should be highlighted
+ */
+ TreeNodeController.prototype.isSelected = function () {
+ return this.isSelectedFlag;
+ };
+
return TreeNodeController;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/controllers/ViewSwitcherController.js b/platform/commonUI/general/src/controllers/ViewSwitcherController.js
index 69674013d5..a3ab2e7bc4 100644
--- a/platform/commonUI/general/src/controllers/ViewSwitcherController.js
+++ b/platform/commonUI/general/src/controllers/ViewSwitcherController.js
@@ -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;
}
);
+
diff --git a/platform/commonUI/general/src/directives/MCTContainer.js b/platform/commonUI/general/src/directives/MCTContainer.js
index 00b7b2b21a..f65cf0803d 100644
--- a/platform/commonUI/general/src/directives/MCTContainer.js
+++ b/platform/commonUI/general/src/directives/MCTContainer.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/directives/MCTDrag.js b/platform/commonUI/general/src/directives/MCTDrag.js
index f12aae5c5f..7bccccdf28 100644
--- a/platform/commonUI/general/src/directives/MCTDrag.js
+++ b/platform/commonUI/general/src/directives/MCTDrag.js
@@ -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;
}
);
+
diff --git a/platform/commonUI/general/src/directives/MCTResize.js b/platform/commonUI/general/src/directives/MCTResize.js
index 62ae977271..c78039627a 100644
--- a/platform/commonUI/general/src/directives/MCTResize.js
+++ b/platform/commonUI/general/src/directives/MCTResize.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/directives/MCTScroll.js b/platform/commonUI/general/src/directives/MCTScroll.js
index 3df79f23b2..6b9d480c66 100644
--- a/platform/commonUI/general/src/directives/MCTScroll.js
+++ b/platform/commonUI/general/src/directives/MCTScroll.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/general/src/directives/MCTSplitPane.js b/platform/commonUI/general/src/directives/MCTSplitPane.js
index 8d95ff2b69..688689d79f 100644
--- a/platform/commonUI/general/src/directives/MCTSplitPane.js
+++ b/platform/commonUI/general/src/directives/MCTSplitPane.js
@@ -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(
}
);
+
diff --git a/platform/commonUI/general/src/directives/MCTSplitter.js b/platform/commonUI/general/src/directives/MCTSplitter.js
index 0494830057..5216c69358 100644
--- a/platform/commonUI/general/src/directives/MCTSplitter.js
+++ b/platform/commonUI/general/src/directives/MCTSplitter.js
@@ -39,6 +39,7 @@ define(
/**
* Implements `mct-splitter` directive.
+ * @memberof platform/commonUI/general
* @constructor
*/
function MCTSplitter() {
@@ -88,3 +89,4 @@ define(
}
);
+
diff --git a/platform/commonUI/general/src/services/UrlService.js b/platform/commonUI/general/src/services/UrlService.js
index 4562059d0c..5d57b03ca0 100644
--- a/platform/commonUI/general/src/services/UrlService.js
+++ b/platform/commonUI/general/src/services/UrlService.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/inspect/src/InfoConstants.js b/platform/commonUI/inspect/src/InfoConstants.js
index 5e43a1b618..4927de870f 100644
--- a/platform/commonUI/inspect/src/InfoConstants.js
+++ b/platform/commonUI/inspect/src/InfoConstants.js
@@ -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: " (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
- bubble.css('position', 'absolute');
- 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');
- }
-
- // Add the menu to the body
- body.append(bubble);
-
- // Return a function to dismiss the bubble
- return function () { bubble.remove(); };
+ // Position the bubble
+ bubble.css('position', 'absolute');
+ 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');
}
- 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;
}
);
+
diff --git a/platform/containment/src/CapabilityTable.js b/platform/containment/src/CapabilityTable.js
index db14c0f20f..db89f9e68f 100644
--- a/platform/containment/src/CapabilityTable.js
+++ b/platform/containment/src/CapabilityTable.js
@@ -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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/containment/src/ComposeActionPolicy.js b/platform/containment/src/ComposeActionPolicy.js
index 6d3952b763..3468cd3107 100644
--- a/platform/containment/src/ComposeActionPolicy.js
+++ b/platform/containment/src/ComposeActionPolicy.js
@@ -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.}
*/
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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/containment/src/CompositionModelPolicy.js b/platform/containment/src/CompositionModelPolicy.js
index 74f1200530..d5e5cb5f72 100644
--- a/platform/containment/src/CompositionModelPolicy.js
+++ b/platform/containment/src/CompositionModelPolicy.js
@@ -8,21 +8,19 @@ define(
/**
* Policy allowing composition only for domain object types which
* have a composition property.
+ * @constructor
+ * @memberof platform/containment
+ * @implements {Policy.}
*/
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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/containment/src/CompositionMutabilityPolicy.js b/platform/containment/src/CompositionMutabilityPolicy.js
index 9b3e12eb95..8c5ef6a765 100644
--- a/platform/containment/src/CompositionMutabilityPolicy.js
+++ b/platform/containment/src/CompositionMutabilityPolicy.js
@@ -28,24 +28,20 @@ define(
/**
* Disallow composition changes to objects which are not mutable.
+ * @memberof platform/containment
* @constructor
+ * @implements {Policy.}
*/
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;
}
-);
\ No newline at end of file
+);
diff --git a/platform/containment/src/CompositionPolicy.js b/platform/containment/src/CompositionPolicy.js
index 992fced49f..1f5239ec59 100644
--- a/platform/containment/src/CompositionPolicy.js
+++ b/platform/containment/src/CompositionPolicy.js
@@ -21,6 +21,11 @@
*****************************************************************************/
/*global define*/
+/**
+ * This bundle implements "containment" rules, which determine which objects
+ * can be contained within which other objects.
+ * @namespace platform/containment
+ */
define(
['./ContainmentTable'],
function (ContainmentTable) {
@@ -28,30 +33,27 @@ define(
/**
* Defines composition policy as driven by type metadata.
+ * @constructor
+ * @memberof platform/containment
+ * @implements {Policy.}
*/
function CompositionPolicy($injector) {
// We're really just wrapping the containment table and rephrasing
// it as a policy decision.
var table;
- function getTable() {
+ this.getTable = function () {
return (table = table || new ContainmentTable(
$injector.get('typeService'),
$injector.get('capabilityService')
));
- }
-
- return {
- /**
- * Is the type identified by the candidate allowed to
- * contain the type described by the context?
- */
- allow: function (candidate, context) {
- return getTable().canContain(candidate, context);
- }
};
}
+ CompositionPolicy.prototype.allow = function (candidate, context) {
+ return this.getTable().canContain(candidate, context);
+ };
+
return CompositionPolicy;
}
-);
\ No newline at end of file
+);
diff --git a/platform/containment/src/ContainmentTable.js b/platform/containment/src/ContainmentTable.js
index a3d7ab6ed4..823c782faf 100644
--- a/platform/containment/src/ContainmentTable.js
+++ b/platform/containment/src/ContainmentTable.js
@@ -37,15 +37,13 @@ define(
* start time (plug-in support means this cannot be determined
* prior to that, but we don't want to redo these calculations
* every time policy is checked.)
+ * @constructor
+ * @memberof platform/containment
*/
function ContainmentTable(typeService, capabilityService) {
- var types = typeService.listTypes(),
- capabilityTable = new CapabilityTable(typeService, capabilityService),
- table = {};
-
- // Check if one type can contain another
- function canContain(containerType, containedType) {
- }
+ var self = this,
+ types = typeService.listTypes(),
+ capabilityTable = new CapabilityTable(typeService, capabilityService);
// Add types which have all these capabilities to the set
// of allowed types
@@ -82,38 +80,39 @@ define(
// Check for defined containment restrictions
if (contains === undefined) {
// If not, accept anything
- table[key] = ANY;
+ self.table[key] = ANY;
} else {
// Start with an empty set...
- table[key] = {};
+ self.table[key] = {};
// ...cast accepted types to array if necessary...
contains = Array.isArray(contains) ? contains : [contains];
// ...and add all containment rules to that set
contains.forEach(function (c) {
- addToSet(table[key], c);
+ addToSet(self.table[key], c);
});
}
}
// Build the table
+ this.table = {};
types.forEach(addToTable);
-
- return {
- /**
- * Check if domain objects of one type can contain domain
- * objects of another type.
- * @returns {boolean} true if allowable
- */
- canContain: function (containerType, containedType) {
- var set = table[containerType.getKey()] || {};
- // Recognize either the symbolic value for "can contain
- // anything", or lookup the specific type from the set.
- return (set === ANY) || set[containedType.getKey()];
- }
- };
-
}
+ /**
+ * Check if domain objects of one type can contain domain
+ * objects of another type.
+ * @param {Type} containerType type of the containing domain object
+ * @param {Type} containedType type of the domain object
+ * to be contained
+ * @returns {boolean} true if allowable
+ */
+ ContainmentTable.prototype.canContain = function (containerType, containedType) {
+ var set = this.table[containerType.getKey()] || {};
+ // Recognize either the symbolic value for "can contain
+ // anything", or lookup the specific type from the set.
+ return (set === ANY) || set[containedType.getKey()];
+ };
+
return ContainmentTable;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/actions/ActionAggregator.js b/platform/core/src/actions/ActionAggregator.js
index 4a9288a612..3056ab04e8 100644
--- a/platform/core/src/actions/ActionAggregator.js
+++ b/platform/core/src/actions/ActionAggregator.js
@@ -25,51 +25,102 @@ define(
function () {
"use strict";
+ /**
+ * Actions are reusable processes/behaviors performed by users within
+ * the system, typically upon domain objects. Actions are commonly
+ * exposed to users as menu items or buttons.
+ *
+ * Actions are usually registered via the `actions` extension
+ * category, or (in advanced cases) via an `actionService`
+ * implementation.
+ *
+ * @interface Action
+ */
+
+ /**
+ * Perform the behavior associated with this action. The return type
+ * may vary depending on which action has been performed; in general,
+ * no return value should be expected.
+ *
+ * @method Action#perform
+ */
+
+ /**
+ * Get metadata associated with this action.
+ *
+ * @method Action#getMetadata
+ * @returns {ActionMetadata}
+ */
+
+ /**
+ * Metadata associated with an Action. Actions of specific types may
+ * extend this with additional properties.
+ *
+ * @typedef {Object} ActionMetadata
+ * @property {string} key machine-readable identifier for this action
+ * @property {string} name human-readable name for this action
+ * @property {string} description human-readable description
+ * @property {string} glyph character to display as icon
+ * @property {ActionContext} context the context in which the action
+ * will be performed.
+ */
+
+ /**
+ * Provides actions that can be performed within specific contexts.
+ *
+ * @interface ActionService
+ */
+
+ /**
+ * Get actions which can be performed within a certain context.
+ *
+ * @method ActionService#getActions
+ * @param {ActionContext} context the context in which the action will
+ * be performed
+ * @return {Action[]} relevant actions
+ */
+
+ /**
+ * A description of the context in which an action may occur.
+ *
+ * @typedef ActionContext
+ * @property {DomainObject} [domainObject] the domain object being
+ * acted upon.
+ * @property {DomainObject} [selectedObject] the selection at the
+ * time of action (e.g. the dragged object in a
+ * drag-and-drop operation.)
+ * @property {string} [key] the machine-readable identifier of
+ * the relevant action
+ * @property {string} [category] a string identifying the category
+ * of action being performed
+ */
+
/**
* The ActionAggregator makes several actionService
* instances act as those they were one. When requesting
* actions for a given context, results from all
* services will be assembled and concatenated.
*
+ * @memberof platform/core
* @constructor
- * @param {ActionProvider[]} actionProviders an array
+ * @implements {ActionService}
+ * @param {ActionService[]} actionProviders an array
* of action services
*/
function ActionAggregator(actionProviders) {
-
- function getActions(context) {
- // Get all actions from all providers, reduce down
- // to one array by concatenation
- return actionProviders.map(function (provider) {
- return provider.getActions(context);
- }).reduce(function (a, b) {
- return a.concat(b);
- }, []);
- }
-
- return {
- /**
- * Get a list of actions which are valid in a given
- * context.
- *
- * @param {ActionContext} the context in which
- * the action will occur; this is a
- * JavaScript object containing key-value
- * pairs. Typically, this will contain a
- * field "domainObject" which refers to
- * the domain object that will be acted
- * upon, but may contain arbitrary information
- * recognized by specific providers.
- * @return {Action[]} an array of actions which
- * may be performed in the provided context.
- *
- * @method
- * @memberof ActionAggregator
- */
- getActions: getActions
- };
+ this.actionProviders = actionProviders;
}
+ ActionAggregator.prototype.getActions = function (context) {
+ // Get all actions from all providers, reduce down
+ // to one array by concatenation
+ return this.actionProviders.map(function (provider) {
+ return provider.getActions(context);
+ }).reduce(function (a, b) {
+ return a.concat(b);
+ }, []);
+ };
+
return ActionAggregator;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/actions/ActionCapability.js b/platform/core/src/actions/ActionCapability.js
index 94b0706a0d..2164969a05 100644
--- a/platform/core/src/actions/ActionCapability.js
+++ b/platform/core/src/actions/ActionCapability.js
@@ -45,73 +45,74 @@ define(
* which the action will be performed (also, the
* action which exposes the capability.)
*
+ * @memberof platform/core
* @constructor
*/
function ActionCapability($q, actionService, domainObject) {
+ this.$q = $q;
+ this.actionService = actionService;
+ this.domainObject = domainObject;
+ }
+ /**
+ * Perform an action. This will find and perform the
+ * first matching action available for the specified
+ * context or key.
+ *
+ * @param {ActionContext|string} context the context in which
+ * to perform the action; this is passed along to
+ * the action service to match against available
+ * actions. The "domainObject" field will automatically
+ * be populated with the domain object that exposed
+ * this capability. If given as a string, this will
+ * be taken as the "key" field to match against
+ * specific actions.
+ * @returns {Promise} the result of the action that was
+ * performed, or undefined if no matching action
+ * was found.
+ * @memberof platform/core.ActionCapability#
+ */
+ ActionCapability.prototype.getActions = function (context) {
// Get all actions which are valid in this context;
// this simply redirects to the action service,
// but additionally adds a domainObject field.
- function getActions(context) {
- var baseContext = typeof context === 'string' ?
- { key: context } :
- (context || {}),
- actionContext = Object.create(baseContext);
+ var baseContext = typeof context === 'string' ?
+ { key: context } : (context || {}),
+ actionContext = Object.create(baseContext);
- actionContext.domainObject = domainObject;
+ actionContext.domainObject = this.domainObject;
- return actionService.getActions(actionContext);
- }
+ return this.actionService.getActions(actionContext);
+ };
+ /**
+ * Get actions which are available for this domain object,
+ * in this context.
+ *
+ * @param {ActionContext|string} context the context in which
+ * to perform the action; this is passed along to
+ * the action service to match against available
+ * actions. The "domainObject" field will automatically
+ * be populated with the domain object that exposed
+ * this capability. If given as a string, this will
+ * be taken as the "key" field to match against
+ * specific actions.
+ * @returns {Action[]} an array of matching actions
+ * @memberof platform/core.ActionCapability#
+ */
+ ActionCapability.prototype.perform = function (context) {
// Alias to getActions(context)[0].perform, with a
// check for empty arrays.
- function performAction(context) {
- var actions = getActions(context);
+ var actions = this.getActions(context);
- return $q.when(
- (actions && actions.length > 0) ?
- actions[0].perform() :
- undefined
- );
- }
+ return this.$q.when(
+ (actions && actions.length > 0) ?
+ actions[0].perform() :
+ undefined
+ );
+ };
- return {
- /**
- * Perform an action. This will find and perform the
- * first matching action available for the specified
- * context or key.
- *
- * @param {ActionContext|string} context the context in which
- * to perform the action; this is passed along to
- * the action service to match against available
- * actions. The "domainObject" field will automatically
- * be populated with the domain object that exposed
- * this capability. If given as a string, this will
- * be taken as the "key" field to match against
- * specific actions.
- * @returns {Promise} the result of the action that was
- * performed, or undefined if no matching action
- * was found.
- */
- perform: performAction,
- /**
- * Get actions which are available for this domain object,
- * in this context.
- *
- * @param {ActionContext|string} context the context in which
- * to perform the action; this is passed along to
- * the action service to match against available
- * actions. The "domainObject" field will automatically
- * be populated with the domain object that exposed
- * this capability. If given as a string, this will
- * be taken as the "key" field to match against
- * specific actions.
- * @returns {Action[]} an array of matching actions
- */
- getActions: getActions
- };
- }
return ActionCapability;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/actions/ActionProvider.js b/platform/core/src/actions/ActionProvider.js
index 5937f00fc2..dcb17eb6ce 100644
--- a/platform/core/src/actions/ActionProvider.js
+++ b/platform/core/src/actions/ActionProvider.js
@@ -35,11 +35,46 @@ define(
* of actions exposed via extension (specifically, the "actions"
* category of extension.)
*
+ * @memberof platform/core
+ * @imeplements {ActionService}
* @constructor
*/
function ActionProvider(actions) {
- var actionsByKey = {},
- actionsByCategory = {};
+ var self = this;
+
+ // Build up look-up tables
+ this.actions = actions;
+ this.actionsByKey = {};
+ this.actionsByCategory = {};
+ actions.forEach(function (Action) {
+ // Get an action's category or categories
+ var categories = Action.category || [];
+
+ // Convert to an array if necessary
+ categories = Array.isArray(categories) ?
+ categories : [categories];
+
+ // Store action under all relevant categories
+ categories.forEach(function (category) {
+ self.actionsByCategory[category] =
+ self.actionsByCategory[category] || [];
+ self.actionsByCategory[category].push(Action);
+ });
+
+ // Store action by ekey as well
+ if (Action.key) {
+ self.actionsByKey[Action.key] =
+ self.actionsByKey[Action.key] || [];
+ self.actionsByKey[Action.key].push(Action);
+ }
+ });
+ }
+
+ ActionProvider.prototype.getActions = function (actionContext) {
+ var context = (actionContext || {}),
+ category = context.category,
+ key = context.key,
+ candidates;
// Instantiate an action; invokes the constructor and
// additionally fills in the action's getMetadata method
@@ -70,86 +105,32 @@ define(
function createIfApplicable(actions, context) {
return (actions || []).filter(function (Action) {
return Action.appliesTo ?
- Action.appliesTo(context) : true;
+ Action.appliesTo(context) : true;
}).map(function (Action) {
return instantiateAction(Action, context);
});
}
- // Get an array of actions that are valid in the supplied context.
- function getActions(actionContext) {
- var context = (actionContext || {}),
- category = context.category,
- key = context.key,
- candidates;
-
- // Match actions to the provided context by comparing "key"
- // and/or "category" parameters, if specified.
- candidates = actions;
- if (key) {
- candidates = actionsByKey[key];
- if (category) {
- candidates = candidates.filter(function (Action) {
- return Action.category === category;
- });
- }
- } else if (category) {
- candidates = actionsByCategory[category];
+ // Match actions to the provided context by comparing "key"
+ // and/or "category" parameters, if specified.
+ candidates = this.actions;
+ if (key) {
+ candidates = this.actionsByKey[key];
+ if (category) {
+ candidates = candidates.filter(function (Action) {
+ return Action.category === category;
+ });
}
-
- // Instantiate those remaining actions, with additional
- // filtering per any appliesTo methods defined on those
- // actions.
- return createIfApplicable(candidates, context);
+ } else if (category) {
+ candidates = this.actionsByCategory[category];
}
- // Build up look-up tables
- actions.forEach(function (Action) {
- // Get an action's category or categories
- var categories = Action.category || [];
-
- // Convert to an array if necessary
- categories = Array.isArray(categories) ?
- categories : [categories];
-
- // Store action under all relevant categories
- categories.forEach(function (category) {
- actionsByCategory[category] =
- actionsByCategory[category] || [];
- actionsByCategory[category].push(Action);
- });
-
- // Store action by ekey as well
- if (Action.key) {
- actionsByKey[Action.key] =
- actionsByKey[Action.key] || [];
- actionsByKey[Action.key].push(Action);
- }
- });
-
- return {
- /**
- * Get a list of actions which are valid in a given
- * context.
- *
- * @param {ActionContext} the context in which
- * the action will occur; this is a
- * JavaScript object containing key-value
- * pairs. Typically, this will contain a
- * field "domainObject" which refers to
- * the domain object that will be acted
- * upon, but may contain arbitrary information
- * recognized by specific providers.
- * @return {Action[]} an array of actions which
- * may be performed in the provided context.
- *
- * @method
- * @memberof ActionProvider
- */
- getActions: getActions
- };
- }
+ // Instantiate those remaining actions, with additional
+ // filtering per any appliesTo methods defined on those
+ // actions.
+ return createIfApplicable(candidates, context);
+ };
return ActionProvider;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/actions/LoggingActionDecorator.js b/platform/core/src/actions/LoggingActionDecorator.js
index 3e9652d229..0d6f170261 100644
--- a/platform/core/src/actions/LoggingActionDecorator.js
+++ b/platform/core/src/actions/LoggingActionDecorator.js
@@ -34,9 +34,21 @@ define(
* the actions it exposes always emit a log message when they are
* performed.
*
+ * @memberof platform/core
* @constructor
+ * @implements {ActionService}
+ * @param $log Angular's logging service
+ * @param {ActionService} actionService the decorated action service
*/
function LoggingActionDecorator($log, actionService) {
+ this.$log = $log;
+ this.actionService = actionService;
+ }
+
+ LoggingActionDecorator.prototype.getActions = function () {
+ var actionService = this.actionService,
+ $log = this.$log;
+
// Decorate the perform method of the specified action, such that
// it emits a log message whenever performed.
function addLogging(action) {
@@ -58,35 +70,12 @@ define(
return logAction;
}
- return {
- /**
- * Get a list of actions which are valid in a given
- * context. These actions will additionally log
- * themselves when performed.
- *
- * @param {ActionContext} the context in which
- * the action will occur; this is a
- * JavaScript object containing key-value
- * pairs. Typically, this will contain a
- * field "domainObject" which refers to
- * the domain object that will be acted
- * upon, but may contain arbitrary information
- * recognized by specific providers.
- * @return {Action[]} an array of actions which
- * may be performed in the provided context.
- *
- * @method
- * @memberof LoggingActionDecorator
- */
- getActions: function () {
- return actionService.getActions.apply(
- actionService,
- arguments
- ).map(addLogging);
- }
- };
- }
+ return actionService.getActions.apply(
+ actionService,
+ arguments
+ ).map(addLogging);
+ };
return LoggingActionDecorator;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/capabilities/CompositionCapability.js b/platform/core/src/capabilities/CompositionCapability.js
index 8049d5b3c4..f1b2532040 100644
--- a/platform/core/src/capabilities/CompositionCapability.js
+++ b/platform/core/src/capabilities/CompositionCapability.js
@@ -37,68 +37,61 @@ define(
* require consulting the object service (e.g. to trigger a database
* query to retrieve the nested object models.)
*
+ * @memberof platform/core
* @constructor
+ * @implements {Capability}
*/
function CompositionCapability($injector, domainObject) {
- var objectService,
- lastPromise,
- lastModified;
-
// Get a reference to the object service from $injector
- function injectObjectService() {
- objectService = $injector.get("objectService");
- return objectService;
- }
-
- // Get a reference to the object service (either cached or
- // from the injector)
- function getObjectService() {
- return objectService || injectObjectService();
- }
-
- // Promise this domain object's composition (an array of domain
- // object instances corresponding to ids in its model.)
- function promiseComposition() {
- var model = domainObject.getModel(),
- ids;
-
- // Then filter out non-existent objects,
- // and wrap others (such that they expose a
- // "context" capability)
- function contextualize(objects) {
- return ids.filter(function (id) {
- return objects[id];
- }).map(function (id) {
- return new ContextualDomainObject(
- objects[id],
- domainObject
- );
- });
- }
-
- // Make a new request if we haven't made one, or if the
- // object has been modified.
- if (!lastPromise || lastModified !== model.modified) {
- ids = model.composition || [];
- lastModified = model.modified;
- // Load from the underlying object service
- lastPromise = getObjectService().getObjects(ids)
- .then(contextualize);
- }
-
- return lastPromise;
- }
-
- return {
- /**
- * Request the composition of this object.
- * @returns {Promise.} a list of all domain
- * objects which compose this domain object.
- */
- invoke: promiseComposition
+ this.injectObjectService = function () {
+ this.objectService = $injector.get("objectService");
};
+
+ this.domainObject = domainObject;
}
+ /**
+ * Request the composition of this object.
+ * @returns {Promise.} a list of all domain
+ * objects which compose this domain object.
+ */
+ CompositionCapability.prototype.invoke = function () {
+ var domainObject = this.domainObject,
+ model = domainObject.getModel(),
+ ids;
+
+ // Then filter out non-existent objects,
+ // and wrap others (such that they expose a
+ // "context" capability)
+ function contextualize(objects) {
+ return ids.filter(function (id) {
+ return objects[id];
+ }).map(function (id) {
+ return new ContextualDomainObject(
+ objects[id],
+ domainObject
+ );
+ });
+ }
+
+ // Lazily acquire object service (avoids cyclical dependency)
+ if (!this.objectService) {
+ this.injectObjectService();
+ }
+
+ // Make a new request if we haven't made one, or if the
+ // object has been modified.
+ if (!this.lastPromise || this.lastModified !== model.modified) {
+ ids = model.composition || [];
+ this.lastModified = model.modified;
+ // Load from the underlying object service
+ this.lastPromise = this.objectService.getObjects(ids)
+ .then(contextualize);
+ }
+
+ return this.lastPromise;
+ };
+
/**
* Test to determine whether or not this capability should be exposed
* by a domain object based on its model. Checks for the presence of
@@ -112,4 +105,4 @@ define(
return CompositionCapability;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/capabilities/ContextCapability.js b/platform/core/src/capabilities/ContextCapability.js
index 9eeb00823b..9ffaf4a5bb 100644
--- a/platform/core/src/capabilities/ContextCapability.js
+++ b/platform/core/src/capabilities/ContextCapability.js
@@ -36,77 +36,78 @@ define(
* those whose `composition` capability was used to access this
* object.)
*
+ * @memberof platform/core
* @constructor
+ * @implements {Capability}
*/
function ContextCapability(parentObject, domainObject) {
- return {
- /**
- * Get the immediate parent of a domain object.
- *
- * A domain object may be contained in multiple places; its
- * parent (as exposed by this capability) is the domain
- * object from which this object was accessed, usually
- * by way of a `composition` capability.
- *
- * @returns {DomainObject} the immediate parent of this
- * domain object.
- */
- getParent: function () {
- return parentObject;
- },
- /**
- * Get an array containing the complete direct ancestry
- * of this domain object, including the domain object
- * itself.
- *
- * A domain object may be contained in multiple places; its
- * parent and all ancestors (as exposed by this capability)
- * serve as a record of how this specific domain object
- * instance was reached.
- *
- * The first element in the returned array is the deepest
- * ancestor; subsequent elements are progressively more
- * recent ancestors, with the domain object which exposed
- * the capability occupying the last element of the array.
- *
- * @returns {DomainObject[]} the full composition ancestry
- * of the domain object which exposed this
- * capability.
- */
- getPath: function () {
- var parentPath = [],
- parentContext;
-
- if (parentObject) {
- parentContext = parentObject.getCapability("context");
- parentPath = parentContext ?
- parentContext.getPath() :
- [parentObject];
- }
-
- return parentPath.concat([domainObject]);
- },
- /**
- * Get the deepest ancestor available for this domain object;
- * equivalent to `getPath()[0]`.
- *
- * See notes on `getPath()` for how ancestry is defined in
- * the context of this capability.
- *
- * @returns {DomainObject} the deepest ancestor of the domain
- * object which exposed this capability.
- */
- getRoot: function () {
- var parentContext = parentObject &&
- parentObject.getCapability('context');
-
- return parentContext ?
- parentContext.getRoot() :
- (parentObject || domainObject);
- }
- };
+ this.parentObject = parentObject;
+ this.domainObject = domainObject;
}
+ /**
+ * Get the immediate parent of a domain object.
+ *
+ * A domain object may be contained in multiple places; its
+ * parent (as exposed by this capability) is the domain
+ * object from which this object was accessed, usually
+ * by way of a `composition` capability.
+ *
+ * @returns {DomainObject} the immediate parent of this
+ * domain object.
+ */
+ ContextCapability.prototype.getParent = function () {
+ return this.parentObject;
+ };
+
+ /**
+ * Get an array containing the complete direct ancestry
+ * of this domain object, including the domain object
+ * itself.
+ *
+ * A domain object may be contained in multiple places; its
+ * parent and all ancestors (as exposed by this capability)
+ * serve as a record of how this specific domain object
+ * instance was reached.
+ *
+ * The first element in the returned array is the deepest
+ * ancestor; subsequent elements are progressively more
+ * recent ancestors, with the domain object which exposed
+ * the capability occupying the last element of the array.
+ *
+ * @returns {DomainObject[]} the full composition ancestry
+ * of the domain object which exposed this
+ * capability.
+ */
+ ContextCapability.prototype.getPath = function () {
+ var parentObject = this.parentObject,
+ parentContext =
+ parentObject && parentObject.getCapability('context'),
+ parentPath = parentContext ?
+ parentContext.getPath() : [ this.parentObject ];
+
+ return parentPath.concat([this.domainObject]);
+ };
+
+ /**
+ * Get the deepest ancestor available for this domain object;
+ * equivalent to `getPath()[0]`.
+ *
+ * See notes on `getPath()` for how ancestry is defined in
+ * the context of this capability.
+ *
+ * @returns {DomainObject} the deepest ancestor of the domain
+ * object which exposed this capability.
+ */
+ ContextCapability.prototype.getRoot = function () {
+ var parentContext = this.parentObject &&
+ this.parentObject.getCapability('context');
+
+ return parentContext ?
+ parentContext.getRoot() :
+ (this.parentObject || this.domainObject);
+ };
+
return ContextCapability;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/capabilities/ContextualDomainObject.js b/platform/core/src/capabilities/ContextualDomainObject.js
index 0d042923a0..2955515ead 100644
--- a/platform/core/src/capabilities/ContextualDomainObject.js
+++ b/platform/core/src/capabilities/ContextualDomainObject.js
@@ -42,7 +42,9 @@ define(
* @param {DomainObject} parentObject the domain object from which
* the wrapped object was retrieved
*
+ * @memberof platform/core
* @constructor
+ * @implements {DomainObject}
*/
function ContextualDomainObject(domainObject, parentObject) {
// Prototypally inherit from the domain object, and
@@ -63,4 +65,4 @@ define(
return ContextualDomainObject;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/capabilities/CoreCapabilityProvider.js b/platform/core/src/capabilities/CoreCapabilityProvider.js
index 89660b72ee..7b1ba070d7 100644
--- a/platform/core/src/capabilities/CoreCapabilityProvider.js
+++ b/platform/core/src/capabilities/CoreCapabilityProvider.js
@@ -29,6 +29,19 @@ define(
function () {
"use strict";
+ /**
+ * A capability provides an interface with dealing with some
+ * dynamic behavior associated with a domain object.
+ * @interface Capability
+ */
+
+ /**
+ * Optional; if present, will be used by `DomainObject#useCapability`
+ * to simplify interaction with a specific capability. Parameters
+ * and return values vary depending on capability type.
+ * @method Capability#invoke
+ */
+
/**
* Provides capabilities based on extension definitions,
* matched to domain object models.
@@ -37,6 +50,7 @@ define(
* of constructor functions for capabilities, as
* exposed by extensions defined at the bundle level.
*
+ * @memberof platform/core
* @constructor
*/
function CoreCapabilityProvider(capabilities, $log) {
@@ -84,6 +98,7 @@ define(
* @returns {Object.} all
* capabilities known to be valid for this model, as
* key-value pairs
+ * @memberof platform/core.CoreCapabilityProvider#
*/
getCapabilities: getCapabilities
};
@@ -92,3 +107,4 @@ define(
return CoreCapabilityProvider;
}
);
+
diff --git a/platform/core/src/capabilities/DelegationCapability.js b/platform/core/src/capabilities/DelegationCapability.js
index 452b842452..0c62c05f00 100644
--- a/platform/core/src/capabilities/DelegationCapability.js
+++ b/platform/core/src/capabilities/DelegationCapability.js
@@ -45,12 +45,40 @@ define(
* in the type's definition, which contains an array of names of
* capabilities to be delegated.
*
- * @param domainObject
+ * @param $q Angular's $q, for promises
+ * @param {DomainObject} domainObject the delegating domain object
+ * @memberof platform/core
* @constructor
+ * @implements {Capability}
*/
function DelegationCapability($q, domainObject) {
- var delegateCapabilities = {},
- type = domainObject.getCapability("type");
+ var type = domainObject.getCapability("type"),
+ self = this;
+
+ this.$q = $q;
+ this.delegateCapabilities = {};
+ this.domainObject = domainObject;
+
+ // Generate set for easy lookup of capability delegation
+ if (type && type.getDefinition) {
+ (type.getDefinition().delegates || []).forEach(function (key) {
+ self.delegateCapabilities[key] = true;
+ });
+ }
+ }
+
+
+ /**
+ * Get the domain objects which are intended to be delegated
+ * responsibility for some specific capability.
+ *
+ * @param {string} key the name of the delegated capability
+ * @returns {DomainObject[]} the domain objects to which
+ * responsibility for this capability is delegated.
+ * @memberof platform/core.DelegationCapability#
+ */
+ DelegationCapability.prototype.getDelegates = function (key) {
+ var domainObject = this.domainObject;
function filterObjectsWithCapability(capability) {
return function (objects) {
@@ -64,55 +92,42 @@ define(
return domainObject.useCapability('composition');
}
- function doesDelegate(key) {
- return delegateCapabilities[key] || false;
- }
+ return this.doesDelegateCapability(key) ?
+ promiseChildren().then(
+ filterObjectsWithCapability(key)
+ ) :
+ this.$q.when([]);
+ };
- function getDelegates(capability) {
- return doesDelegate(capability) ?
- promiseChildren().then(
- filterObjectsWithCapability(capability)
- ) :
- $q.when([]);
- }
-
- // Generate set for easy lookup of capability delegation
- if (type && type.getDefinition) {
- (type.getDefinition().delegates || []).forEach(function (key) {
- delegateCapabilities[key] = true;
- });
- }
-
- return {
- /**
- * Invoke this capability; alias of `getDelegates`, used to
- * simplify usage, e.g.:
- *
- * `domainObject.useCapability("delegation", "telemetry")`
- *
- * ...will retrieve all members of a domain object's
- * composition which have a "telemetry" capability.
- *
- * @param {string} the name of the delegated capability
- * @returns {DomainObject[]} the domain objects to which
- * responsibility for this capability is delegated.
- */
- invoke: getDelegates,
- /**
- * Get the domain objects which are intended to be delegated
- * responsibility for some specific capability.
- *
- * @param {string} the name of the delegated capability
- * @returns {DomainObject[]} the domain objects to which
- * responsibility for this capability is delegated.
- */
- getDelegates: getDelegates,
- doesDelegateCapability: doesDelegate
- };
- }
+ /**
+ * Check if the domain object which exposed this capability
+ * wishes to delegate another capability.
+ *
+ * @param {string} key the capability to check for
+ * @returns {boolean} true if the capability is delegated
+ */
+ DelegationCapability.prototype.doesDelegateCapability = function (key) {
+ return !!(this.delegateCapabilities[key]);
+ };
+ /**
+ * Invoke this capability; alias of `getDelegates`, used to
+ * simplify usage, e.g.:
+ *
+ * `domainObject.useCapability("delegation", "telemetry")`
+ *
+ * ...will retrieve all members of a domain object's
+ * composition which have a "telemetry" capability.
+ *
+ * @param {string} the name of the delegated capability
+ * @returns {DomainObject[]} the domain objects to which
+ * responsibility for this capability is delegated.
+ * @memberof platform/core.DelegationCapability#
+ */
+ DelegationCapability.prototype.invoke =
+ DelegationCapability.prototype.getDelegates;
return DelegationCapability;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/capabilities/MetadataCapability.js b/platform/core/src/capabilities/MetadataCapability.js
index 677dab0008..242b35b6dc 100644
--- a/platform/core/src/capabilities/MetadataCapability.js
+++ b/platform/core/src/capabilities/MetadataCapability.js
@@ -25,10 +25,23 @@ define(
* `value` properties describing that domain object (suitable for
* display.)
*
+ * @param {DomainObject} domainObject the domain object whose
+ * metadata is to be exposed
+ * @implements {Capability}
* @constructor
+ * @memberof platform/core
*/
function MetadataCapability(domainObject) {
- var model = domainObject.getModel();
+ this.domainObject = domainObject;
+ }
+
+ /**
+ * Get metadata about this object.
+ * @returns {MetadataProperty[]} metadata about this object
+ */
+ MetadataCapability.prototype.invoke = function () {
+ var domainObject = this.domainObject,
+ model = domainObject.getModel();
function hasDisplayableValue(metadataProperty) {
var t = typeof metadataProperty.value;
@@ -37,8 +50,8 @@ define(
function formatTimestamp(timestamp) {
return typeof timestamp === 'number' ?
- (moment.utc(timestamp).format(TIME_FORMAT) + " UTC") :
- undefined;
+ (moment.utc(timestamp).format(TIME_FORMAT) + " UTC") :
+ undefined;
}
function getProperties() {
@@ -73,20 +86,11 @@ define(
];
}
- function getMetadata() {
- return getProperties().concat(getCommonMetadata())
- .filter(hasDisplayableValue);
- }
-
- return {
- /**
- * Get metadata about this object.
- * @returns {MetadataProperty[]} metadata about this object
- */
- invoke: getMetadata
- };
- }
+ return getProperties().concat(getCommonMetadata())
+ .filter(hasDisplayableValue);
+ };
return MetadataCapability;
}
);
+
diff --git a/platform/core/src/capabilities/MutationCapability.js b/platform/core/src/capabilities/MutationCapability.js
index 4268f7c323..b9f49ca969 100644
--- a/platform/core/src/capabilities/MutationCapability.js
+++ b/platform/core/src/capabilities/MutationCapability.js
@@ -69,97 +69,105 @@ define(
* });
* ```
*
+ * @param {Function} topic a service for creating listeners
+ * @param {Function} now a service to get the current time
* @param {DomainObject} domainObject the domain object
* which will expose this capability
+ * @memberof platform/core
* @constructor
+ * @implements {Capability}
*/
function MutationCapability(topic, now, domainObject) {
- var t = topic(TOPIC_PREFIX + domainObject.getId());
+ this.mutationTopic = topic(TOPIC_PREFIX + domainObject.getId());
+ this.now = now;
+ this.domainObject = domainObject;
+ }
- function mutate(mutator, timestamp) {
- // Get the object's model and clone it, so the
- // mutator function has a temporary copy to work with.
- var model = domainObject.getModel(),
- clone = JSON.parse(JSON.stringify(model)),
- useTimestamp = arguments.length > 1;
+ /**
+ * Modify the domain object's model, using a provided
+ * function. This function will receive a copy of the
+ * domain object's model as an argument; behavior
+ * varies depending on that function's return value:
+ *
+ * * If no value (or undefined) is returned by the mutator,
+ * the state of the model object delivered as the mutator's
+ * argument will become the domain object's new model.
+ * This is useful for writing code that modifies the model
+ * directly.
+ * * If a plain object is returned, that object will be used
+ * as the domain object's new model.
+ * * If boolean `false` is returned, the mutation will be
+ * cancelled.
+ * * If a promise is returned, its resolved value will be
+ * handled as one of the above.
+ *
+ *
+ * @param {Function} mutator the function which will make
+ * changes to the domain object's model.
+ * @param {number} [timestamp] timestamp to record for
+ * this mutation (otherwise, system time will be
+ * used)
+ * @returns {Promise.} a promise for the result
+ * of the mutation; true if changes were made.
+ */
+ MutationCapability.prototype.mutate = function (mutator, timestamp) {
+ // Get the object's model and clone it, so the
+ // mutator function has a temporary copy to work with.
+ var domainObject = this.domainObject,
+ now = this.now,
+ t = this.mutationTopic,
+ model = domainObject.getModel(),
+ clone = JSON.parse(JSON.stringify(model)),
+ useTimestamp = arguments.length > 1;
- // Function to handle copying values to the actual
- function handleMutation(mutationResult) {
- // If mutation result was undefined, just use
- // the clone; this allows the mutator to omit return
- // values and just change the model directly.
- var result = mutationResult || clone;
+ // Function to handle copying values to the actual
+ function handleMutation(mutationResult) {
+ // If mutation result was undefined, just use
+ // the clone; this allows the mutator to omit return
+ // values and just change the model directly.
+ var result = mutationResult || clone;
- // Allow mutators to change their mind by
- // returning false.
- if (mutationResult !== false) {
- // Copy values if result was a different object
- // (either our clone or some other new thing)
- if (model !== result) {
- copyValues(model, result);
- }
- model.modified = useTimestamp ? timestamp : now();
- t.notify(model);
+ // Allow mutators to change their mind by
+ // returning false.
+ if (mutationResult !== false) {
+ // Copy values if result was a different object
+ // (either our clone or some other new thing)
+ if (model !== result) {
+ copyValues(model, result);
}
-
- // Report the result of the mutation
- return mutationResult !== false;
+ model.modified = useTimestamp ? timestamp : now();
+ t.notify(model);
}
- // Invoke the provided mutator, then make changes to
- // the underlying model (if applicable.)
- return fastPromise(mutator(clone)).then(handleMutation);
+ // Report the result of the mutation
+ return mutationResult !== false;
}
- function listen(listener) {
- return t.listen(listener);
- }
+ // Invoke the provided mutator, then make changes to
+ // the underlying model (if applicable.)
+ return fastPromise(mutator(clone)).then(handleMutation);
+ };
- return {
- /**
- * Alias of `mutate`, used to support useCapability.
- */
- invoke: mutate,
- /**
- * Modify the domain object's model, using a provided
- * function. This function will receive a copy of the
- * domain object's model as an argument; behavior
- * varies depending on that function's return value:
- *
- * * If no value (or undefined) is returned by the mutator,
- * the state of the model object delivered as the mutator's
- * argument will become the domain object's new model.
- * This is useful for writing code that modifies the model
- * directly.
- * * If a plain object is returned, that object will be used
- * as the domain object's new model.
- * * If boolean `false` is returned, the mutation will be
- * cancelled.
- * * If a promise is returned, its resolved value will be
- * handled as one of the above.
- *
- *
- * @param {function} mutator the function which will make
- * changes to the domain object's model.
- * @param {number} [timestamp] timestamp to record for
- * this mutation (otherwise, system time will be
- * used)
- * @returns {Promise.} a promise for the result
- * of the mutation; true if changes were made.
- */
- mutate: mutate,
- /**
- * Listen for mutations of this domain object's model.
- * The provided listener will be invoked with the domain
- * object's new model after any changes. To stop listening,
- * invoke the function returned by this method.
- * @param {Function} listener function to call on mutation
- * @returns {Function} a function to stop listening
- */
- listen: listen
- };
- }
+ /**
+ * Listen for mutations of this domain object's model.
+ * The provided listener will be invoked with the domain
+ * object's new model after any changes. To stop listening,
+ * invoke the function returned by this method.
+ * @param {Function} listener function to call on mutation
+ * @returns {Function} a function to stop listening
+ * @memberof platform/core.MutationCapability#
+ */
+ MutationCapability.prototype.listen = function (listener) {
+ return this.mutationTopic.listen(listener);
+ };
+
+ /**
+ * Alias of `mutate`, used to support useCapability.
+ */
+ MutationCapability.prototype.invoke =
+ MutationCapability.prototype.mutate;
return MutationCapability;
}
);
+
diff --git a/platform/core/src/capabilities/PersistenceCapability.js b/platform/core/src/capabilities/PersistenceCapability.js
index 68c3255412..8c7e08e17d 100644
--- a/platform/core/src/capabilities/PersistenceCapability.js
+++ b/platform/core/src/capabilities/PersistenceCapability.js
@@ -33,18 +33,69 @@ define(
*
* @param {PersistenceService} persistenceService the underlying
* provider of persistence capabilities.
- * @param {string} SPACE the name of the persistence space to
+ * @param {string} space the name of the persistence space to
* use (this is an arbitrary string, useful in principle
* for distinguishing different persistence stores from
* one another.)
* @param {DomainObject} the domain object which shall expose
* this capability
*
+ * @memberof platform/core
* @constructor
+ * @implements {Capability}
*/
- function PersistenceCapability(persistenceService, SPACE, domainObject) {
+ function PersistenceCapability(persistenceService, space, domainObject) {
// Cache modified timestamp
- var modified = domainObject.getModel().modified;
+ this.modified = domainObject.getModel().modified;
+
+ this.domainObject = domainObject;
+ this.space = space;
+ this.persistenceService = persistenceService;
+ }
+
+ // Utility function for creating promise-like objects which
+ // resolve synchronously when possible
+ function fastPromise(value) {
+ return (value || {}).then ? value : {
+ then: function (callback) {
+ return fastPromise(callback(value));
+ }
+ };
+ }
+
+ /**
+ * Persist any changes which have been made to this
+ * domain object's model.
+ * @returns {Promise} a promise which will be resolved
+ * if persistence is successful, and rejected
+ * if not.
+ */
+ PersistenceCapability.prototype.persist = function () {
+ var domainObject = this.domainObject,
+ modified = domainObject.getModel().modified;
+
+ // Update persistence timestamp...
+ domainObject.useCapability("mutation", function (model) {
+ model.persisted = modified;
+ }, modified);
+
+ // ...and persist
+ return this.persistenceService.updateObject(
+ this.getSpace(),
+ domainObject.getId(),
+ domainObject.getModel()
+ );
+ };
+
+ /**
+ * Update this domain object to match the latest from
+ * persistence.
+ * @returns {Promise} a promise which will be resolved
+ * when the update is complete
+ */
+ PersistenceCapability.prototype.refresh = function () {
+ var domainObject = this.domainObject,
+ model = domainObject.getModel();
// Update a domain object's model upon refresh
function updateModel(model) {
@@ -54,73 +105,29 @@ define(
}, modified);
}
- // For refresh; update a domain object model, only if there
- // are no unsaved changes.
- function updatePersistenceTimestamp() {
- var modified = domainObject.getModel().modified;
- domainObject.useCapability("mutation", function (model) {
- model.persisted = modified;
- }, modified);
- }
+ // Only update if we don't have unsaved changes
+ return (model.modified === model.persisted) ?
+ this.persistenceService.readObject(
+ this.getSpace(),
+ this.domainObject.getId()
+ ).then(updateModel) :
+ fastPromise(false);
+ };
- // Utility function for creating promise-like objects which
- // resolve synchronously when possible
- function fastPromise(value) {
- return (value || {}).then ? value : {
- then: function (callback) {
- return fastPromise(callback(value));
- }
- };
- }
-
- return {
- /**
- * Persist any changes which have been made to this
- * domain object's model.
- * @returns {Promise} a promise which will be resolved
- * if persistence is successful, and rejected
- * if not.
- */
- persist: function () {
- updatePersistenceTimestamp();
- return persistenceService.updateObject(
- SPACE,
- domainObject.getId(),
- domainObject.getModel()
- );
- },
- /**
- * Update this domain object to match the latest from
- * persistence.
- * @returns {Promise} a promise which will be resolved
- * when the update is complete
- */
- refresh: function () {
- var model = domainObject.getModel();
- // Only update if we don't have unsaved changes
- return (model.modified === model.persisted) ?
- persistenceService.readObject(
- SPACE,
- domainObject.getId()
- ).then(updateModel) :
- fastPromise(false);
- },
- /**
- * Get the space in which this domain object is persisted;
- * this is useful when, for example, decided which space a
- * newly-created domain object should be persisted to (by
- * default, this should be the space of its containing
- * object.)
- *
- * @returns {string} the name of the space which should
- * be used to persist this object
- */
- getSpace: function () {
- return SPACE;
- }
- };
- }
+ /**
+ * Get the space in which this domain object is persisted;
+ * this is useful when, for example, decided which space a
+ * newly-created domain object should be persisted to (by
+ * default, this should be the space of its containing
+ * object.)
+ *
+ * @returns {string} the name of the space which should
+ * be used to persist this object
+ */
+ PersistenceCapability.prototype.getSpace = function () {
+ return this.space;
+ };
return PersistenceCapability;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/capabilities/RelationshipCapability.js b/platform/core/src/capabilities/RelationshipCapability.js
index fc8729a9a1..7eb6d01bb9 100644
--- a/platform/core/src/capabilities/RelationshipCapability.js
+++ b/platform/core/src/capabilities/RelationshipCapability.js
@@ -38,91 +38,82 @@ define(
* which are not intended to appear in the tree, but are instead
* intended only for special, limited usage.
*
+ * @memberof platform/core
* @constructor
+ * @implements {Capability}
*/
function RelationshipCapability($injector, domainObject) {
- var objectService,
- lastPromise = {},
- lastModified;
-
// Get a reference to the object service from $injector
- function injectObjectService() {
- objectService = $injector.get("objectService");
- return objectService;
- }
-
- // Get a reference to the object service (either cached or
- // from the injector)
- function getObjectService() {
- return objectService || injectObjectService();
- }
-
- // Promise this domain object's composition (an array of domain
- // object instances corresponding to ids in its model.)
- function promiseRelationships(key) {
- var model = domainObject.getModel(),
- ids;
-
- // Package objects as an array
- function packageObject(objects) {
- return ids.map(function (id) {
- return objects[id];
- }).filter(function (obj) {
- return obj;
- });
- }
-
- // Clear cached promises if modification has occurred
- if (lastModified !== model.modified) {
- lastPromise = {};
- lastModified = model.modified;
- }
-
- // Make a new request if needed
- if (!lastPromise[key]) {
- ids = (model.relationships || {})[key] || [];
- lastModified = model.modified;
- // Load from the underlying object service
- lastPromise[key] = getObjectService().getObjects(ids)
- .then(packageObject);
- }
-
- return lastPromise[key];
- }
-
- // List types of relationships which this object has
- function listRelationships() {
- var relationships =
- (domainObject.getModel() || {}).relationships || {};
-
- // Check if this key really does expose an array of ids
- // (to filter out malformed relationships)
- function isArray(key) {
- return Array.isArray(relationships[key]);
- }
-
- return Object.keys(relationships).filter(isArray).sort();
- }
-
- return {
- /**
- * List all types of relationships exposed by this
- * object.
- * @returns {string[]} a list of all relationship types
- */
- listRelationships: listRelationships,
- /**
- * Request related objects, with a given relationship type.
- * This will typically require asynchronous lookup, so this
- * returns a promise.
- * @param {string} key the type of relationship
- * @returns {Promise.} a promise for related
- * domain objects
- */
- getRelatedObjects: promiseRelationships
+ this.injectObjectService = function () {
+ this.objectService = $injector.get("objectService");
};
+
+ this.lastPromise = {};
+ this.domainObject = domainObject;
}
+ /**
+ * List all types of relationships exposed by this
+ * object.
+ * @returns {string[]} a list of all relationship types
+ */
+ RelationshipCapability.prototype.listRelationships = function listRelationships() {
+ var relationships =
+ (this.domainObject.getModel() || {}).relationships || {};
+
+ // Check if this key really does expose an array of ids
+ // (to filter out malformed relationships)
+ function isArray(key) {
+ return Array.isArray(relationships[key]);
+ }
+
+ return Object.keys(relationships).filter(isArray).sort();
+ };
+
+ /**
+ * Request related objects, with a given relationship type.
+ * This will typically require asynchronous lookup, so this
+ * returns a promise.
+ * @param {string} key the type of relationship
+ * @returns {Promise.} a promise for related
+ * domain objects
+ */
+ RelationshipCapability.prototype.getRelatedObjects = function (key) {
+ var model = this.domainObject.getModel(),
+ ids;
+
+ // Package objects as an array
+ function packageObject(objects) {
+ return ids.map(function (id) {
+ return objects[id];
+ }).filter(function (obj) {
+ return obj;
+ });
+ }
+
+ // Clear cached promises if modification has occurred
+ if (this.lastModified !== model.modified) {
+ this.lastPromise = {};
+ this.lastModified = model.modified;
+ }
+
+ // Make a new request if needed
+ if (!this.lastPromise[key]) {
+ ids = (model.relationships || {})[key] || [];
+ this.lastModified = model.modified;
+ // Lazily initialize object service now that we need it
+ if (!this.objectService) {
+ this.injectObjectService();
+ }
+ // Load from the underlying object service
+ this.lastPromise[key] = this.objectService.getObjects(ids)
+ .then(packageObject);
+ }
+
+ return this.lastPromise[key];
+ };
+
+
/**
* Test to determine whether or not this capability should be exposed
* by a domain object based on its model. Checks for the presence of
@@ -136,4 +127,4 @@ define(
return RelationshipCapability;
}
-);
\ No newline at end of file
+);
diff --git a/platform/core/src/models/CachingModelDecorator.js b/platform/core/src/models/CachingModelDecorator.js
index d9d4ef6775..a338d6770f 100644
--- a/platform/core/src/models/CachingModelDecorator.js
+++ b/platform/core/src/models/CachingModelDecorator.js
@@ -30,11 +30,32 @@ define(
* The caching model decorator maintains a cache of loaded domain
* object models, and ensures that duplicate models for the same
* object are not provided.
+ * @memberof platform/core
* @constructor
+ * @param {ModelService} modelService this service to decorate
+ * @implements {ModelService}
*/
function CachingModelDecorator(modelService) {
- var cache = {},
- cached = {};
+ this.cache = {};
+ this.cached = {};
+ this.modelService = modelService;
+ }
+
+ // Fast-resolving promise
+ function fastPromise(value) {
+ return (value || {}).then ? value : {
+ then: function (callback) {
+ return fastPromise(callback(value));
+ }
+ };
+ }
+
+ CachingModelDecorator.prototype.getModels = function (ids) {
+ var cache = this.cache,
+ cached = this.cached,
+ neededIds = ids.filter(function notCached(id) {
+ return !cached[id];
+ });
// Update the cached instance of a model to a new value.
// We update in-place to ensure there is only ever one instance
@@ -67,30 +88,12 @@ define(
return oldModel;
}
- // Fast-resolving promise
- function fastPromise(value) {
- return (value || {}).then ? value : {
- then: function (callback) {
- return fastPromise(callback(value));
- }
- };
- }
-
- // Store this model in the cache
- function cacheModel(id, model) {
- cache[id] = cached[id] ? updateModel(id, model) : model;
- cached[id] = true;
- }
-
- // Check if an id is not in cache, for lookup filtering
- function notCached(id) {
- return !cached[id];
- }
-
// Store the provided models in our cache
function cacheAll(models) {
Object.keys(models).forEach(function (id) {
- cacheModel(id, models[id]);
+ cache[id] = cached[id] ?
+ updateModel(id, models[id]) : models[id];
+ cached[id] = true;
});
}
@@ -99,38 +102,17 @@ define(
return cache;
}
- return {
- /**
- * Get models for these specified string identifiers.
- * These will be given as an object containing keys
- * and values, where keys are object identifiers and
- * values are models.
- * This result may contain either a subset or a
- * superset of the total objects.
- *
- * @param {Array} ids the string identifiers for
- * models of interest.
- * @returns {Promise