Compare commits

...

58 Commits

Author SHA1 Message Date
Henry
a515ccfb61 [Edit Mode] Refactor edit concerns out of browse controllers
Fixed jslint errors

Removed commented code and added line breaks
2016-02-05 10:00:01 -08:00
Henry
560897fe81 [Edit Mode] #627 slightly modified edit representer to detect newly created objects
Added some comments, renamed controller variable in markup

Removed edit references from BrowseController
2016-02-04 16:59:12 -08:00
Henry
e1d20e7275 [Edit Mode] #627 remove edit concerns from browse controller 2016-02-04 16:59:11 -08:00
Henry
9371fcbc4c [Plot] #638 Added a new plot options example bundle and rebased
Fixed jsdoc

Fixed incorrect memberof declaration

Corrected memberof statement
2016-02-04 15:17:07 -08:00
Henry
abf5f22155 [Plots] #638 added onchange handling in order to synchronize forms with domain object model.
Fixed failing test

Added tests

jslint errors

Minor refactoring of layout bundle

revert layout/bundle.json
2016-02-04 14:26:21 -08:00
Charles Hacskaylo
f2903f4030 [Frontend] Final styling on properties form in Inspector
open #638
Added custom radio button control and modified
PlotOptionsController / plotOptionsStructure
accordingly; spacing, borders, etc. are
all as finally intended;
2016-02-04 14:25:02 -08:00
Charles Hacskaylo
371669fbce [Frontend] Mods in progress to form layout
open #638
Major progress on form-row markup and CSS when
in Inspector 'part' context; General fixes cleanups
to custom checkbox/radio CSS;
2016-02-04 14:23:29 -08:00
Charles Hacskaylo
68f3cd087d [Frontend] Mods in progress to form layout
open #638
In progress;
2016-02-04 14:23:29 -08:00
Charles Hacskaylo
115ffe7963 [Frontend] Fixes to scrolling and layout in Inspector
open #638
In progress;
2016-02-04 14:23:29 -08:00
Henry
e3a0cae5fd [Plot] #638 Fleshing out form structures 2016-02-04 14:23:29 -08:00
Charles Hacskaylo
8bb5a47b88 CSS updated to use new e619 character
open #638
2016-02-04 14:23:28 -08:00
Charles Hacskaylo
f1b6d7f749 [Frontend] New custom radio mctControl
open #638
Markup and initial CSS
2016-02-04 14:23:28 -08:00
Henry
6fb6761abf [Plots] #638 New plot display options 2016-02-04 14:23:28 -08:00
Pete Richards
2dd9a16bf3 Merge remote-tracking branch 'open/prod-uisymbols' into open-master 2016-02-02 09:46:15 -08:00
Victor Woeltjen
aebae27391 [Tests] Remove suite.json files
Remove obsolete suite.json files; #482
2016-02-02 09:35:50 -08:00
Charles Hacskaylo
97d0a66684 [Frontend] Added VISTA Topic and Session glyphs to symbols font
open #188
See Google Doc UI Symbols Font Map
for char codes
2016-01-29 17:09:19 -08:00
Victor Woeltjen
2727c9544d Merge remote-tracking branch 'github/master' into open-master 2016-01-28 17:33:45 -08:00
Victor Woeltjen
a35b0c1d7b Remove erroneously committed file
From #474
2016-01-28 17:33:00 -08:00
Victor Woeltjen
7c23f803e8 Merge pull request #477 from nasa/open337
Review and integrate open337
2016-01-27 14:33:37 -08:00
Victor Woeltjen
dbf196e014 Merge remote-tracking branch 'github/master' into open477
Resolve conflicts to complete merge of #477

Conflicts:
	platform/commonUI/general/bundle.json
	platform/commonUI/themes/espresso/res/css/theme-espresso.css
	platform/commonUI/themes/snow/res/css/theme-snow.css
2016-01-27 12:53:46 -08:00
Victor Woeltjen
b5c8ecc85f Merge pull request #475 from nasa/open325b
[Time Conductor] Update validation logic
2016-01-27 12:44:14 -08:00
Victor Woeltjen
9e6da94878 [Time Conductor] Reformat expression in template
...to use less line width, and to exhibit more normal
indentation, per code review feedback from #475
2016-01-22 15:24:27 -08:00
Victor Woeltjen
3a26c864b8 [Time Conductor] Fix comment text
Per code review feedback, #475
2016-01-22 15:22:54 -08:00
Pete Richards
be7827d6f8 Merge remote-tracking branch 'open/open445' into open-master 2016-01-22 11:47:05 -08:00
Henry
b8b5fdcabf [Copy] #497 Removed extraenuous persist call 2016-01-22 11:32:20 -08:00
Victor Woeltjen ★
45276183b9 Merge pull request #496 from nasa/open492
[Documentation] #492 Amended CircleCI configuration to add missing dependency
2016-01-22 09:30:27 -08:00
Henry
3850db268a [Documentation] #492 Added missing dependency for CircleCI 2016-01-21 10:54:49 -08:00
Victor Woeltjen ★
fcae3fd7a9 Merge pull request #487 from nasa/open486
Review and integrate open486
2016-01-19 11:38:50 -08:00
Victor Woeltjen ★
83dd23cd4b Merge pull request #490 from nasa/nem-build-fixes
NEM build fixes
2016-01-19 11:37:25 -08:00
Pete Richards
26c155da3b Merge branch 'open483' into open-master 2016-01-18 14:09:30 -08:00
Pete Richards
db7560c31f [Test] Use PhantomJS to run tests
Switch Karma to use PhantomJS to run tests.  CI machines no longer
need to have Chrome installed.

Implemented after changes to build process due to imperative registration.

https://github.com/nasa/openmctweb/issues/450
2016-01-18 13:57:32 -08:00
Pete Richards
6fc028e112 [Docs] remove dependencies for building docs
Remove depencendies necessary to build docs from package.json and
specify them in the readme.  Due to difficulty managing dependencies
for nomnoml on different platforms, this reduces dependency requirements
to only those needed for building the package.
2016-01-18 13:54:33 -08:00
Charles Hacskaylo
2d44cf78f9 [Frontend] Fixed HTML and CSS for grid-item
open #486
Normalized grid-item to use similar HTML structure
as label template;
Fixed CSS accordingly.
2016-01-15 15:33:10 -08:00
Victor Woeltjen ★
9b6f3bff85 Merge pull request #485 from nasa/open337-filters
[Plot] Use filters to reverse tick labels
2016-01-15 13:30:41 -08:00
Victor Woeltjen
c2207fe7ce [Plot] Use reverse filter for range ticks too 2016-01-15 13:14:33 -08:00
Victor Woeltjen
119429bc42 [Plot] Test reverse filter 2016-01-15 13:13:08 -08:00
Victor Woeltjen
a94e99af70 [Plot] Use reverse filter for plot ticks
...to remove CSS-related reversal from scripts
2016-01-15 13:09:05 -08:00
Victor Woeltjen
96dc055f02 [Plot] Add reverse filter 2016-01-15 13:06:56 -08:00
Victor Woeltjen
a50410f8ed [Plot] Allow filters to be registered
https://github.com/nasa/openmctweb/pull/477/files#r49903975
2016-01-15 13:00:24 -08:00
Victor Woeltjen
0dc715199d [Build] Include examples in build 2016-01-15 11:44:26 -08:00
Victor Woeltjen
aab53c4ae1 [Build] Exclude target from build 2016-01-15 11:41:50 -08:00
Victor Woeltjen
b63812111d [Build] Include bundle.js files
https://github.com/nasa/openmctweb/issues/483
2016-01-15 11:34:58 -08:00
Charles Hacskaylo
442229fd42 Merge branch 'master' of https://github.com/nasa/openmctweb into open445
Conflicts:
	platform/features/plot/res/templates/plot.html
2016-01-13 16:01:02 -08:00
Charles Hacskaylo
a7a707595c [Frontend] Fixes to CSS for Chrome Linux
open #445
Mods and simplifications to wait-spinner classes;
Simplification and cleanup in plot.html to use loading
class instead of hide/show DOM element;
2016-01-13 13:54:00 -08:00
Charles Hacskaylo
8c325eb1b1 [Frontend] Mods to allow plot tick labels to ellipsis to left
open #337
Still fixing code due to circleci fail in pull request;
2016-01-13 10:11:14 -08:00
Charles Hacskaylo
5e628b1a25 [Frontend] Mods to allow plot tick labels to ellipsis to left
open #337
Still fixing code due to circleci fail in pull request;
2016-01-13 10:05:30 -08:00
Charles Hacskaylo
f8114ba6b6 [Frontend] Mods to allow plot tick labels to ellipsis to left
open #337
Fixing code due to circleci fail in pull request;
2016-01-12 18:23:30 -08:00
Charles Hacskaylo
a10f895904 [Frontend] Mods to allow plot tick labels to ellipsis to left
open #337
Fixing code due to circleci fail in pull request;
2016-01-12 18:20:52 -08:00
Charles Hacskaylo
9b59fd7eae [Frontend] Mods to allow plot tick labels to ellipsis to left
open #337
Tick label strings are now reversed in their char order in
PlotTickGenerator.js, then reversed again via CSS in
_plots-main.scss. This forces the browser to clip the label
at the left 'start' side, rather than the end, resulting in
the least significant portion of the label getting clipped.
2016-01-12 18:04:09 -08:00
Victor Woeltjen
9fe026a1f1 [Time Conductor] Decrease minimum outer span 2016-01-11 18:29:42 -08:00
Victor Woeltjen
3b5c1bf2e6 [Time Conductor] Update spec
Verify that validation occurs against state in formModel;
remove obsolete test case for enforcing minimum outer span
2016-01-11 18:28:44 -08:00
Victor Woeltjen
bb993dc94f [Time Conductor] Don't update invalid bounds
Don't enforce minimum time span when bounds are invalid;
https://github.com/nasa/openmctweb/issues/325#issuecomment-170755787
2016-01-11 18:23:32 -08:00
Victor Woeltjen
5beb1de805 [Time Conductor] Display validation errors consistently 2016-01-11 16:56:58 -08:00
Victor Woeltjen
0a012c67dd [Time Conductor] Test additions to TimeRangeController
Add test cases to cover validators added to display
start/end time violations.
2016-01-11 16:41:20 -08:00
Victor Woeltjen
11b71fae68 [Time Conductor] Display invalid state
...when text value can be parsed in a date-time field,
but numeric value violates externally-imposed validation
2016-01-11 15:29:43 -08:00
Victor Woeltjen
e6d0537e5e Revert "[Time Conductor] Validate numeric date-time fields"
This reverts commit 07c407edea.
2016-01-11 15:23:21 -08:00
Victor Woeltjen
99556ed6a5 [Time Conductor] Validate start/end times 2016-01-11 15:18:38 -08:00
Victor Woeltjen
07c407edea [Time Conductor] Validate numeric date-time fields
Allow injection of a validator for numeric values of
the date-time fields, to allow for these to be displayed
as invalid in cases where the text itself may be parsed
but the resulting value is not valid (e.g. when start
is greater than end.)

https://github.com/nasa/openmctweb/issues/325
2016-01-11 15:18:26 -08:00
115 changed files with 3148 additions and 1615 deletions

View File

@@ -99,17 +99,16 @@ Run as `mvn clean install`.
### Building Documentation
Open MCT Web's documentation is generated by an
[npm](https://www.npmjs.com/)-based build:
[npm](https://www.npmjs.com/)-based build. It has additional dependencies that
may not be available on every platform and thus is not covered in the standard
npm install. Ensure your system has [libcairo](http://cairographics.org/)
installed and then run the following commands:
* `npm install` _(only needs to run once)_
* `npm install`
* `npm install canvas nomnoml`
* `npm run docs`
Documentation will be generated in `target/docs`. Note that diagram
generation is dependent on having [Cairo](http://cairographics.org/download/)
installed; see
[node-canvas](https://github.com/Automattic/node-canvas#installation)'s
documentation for help with installation.
Documentation will be generated in `target/docs`.
# Glossary

View File

@@ -2,6 +2,7 @@ deployment:
production:
branch: master
commands:
- npm install canvas nomnoml
- ./build-docs.sh
- git push git@heroku.com:openmctweb-demo.git $CIRCLE_SHA1:refs/heads/master
openmctweb-staging-un:

View File

@@ -0,0 +1,145 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define([
'legacyRegistry',
'../../platform/commonUI/browse/src/InspectorRegion'
], function (
legacyRegistry,
InspectorRegion
) {
"use strict";
/**
* Add a 'plot options' region part to the inspector region for the
* Telemetry Plot type only. {@link InspectorRegion} is a default region
* implementation that is added automatically to all types. In order to
* customize what appears in the inspector region, you can start from a
* blank slate by using Region, or customize the default inspector
* region by using {@link InspectorRegion}.
*/
var plotInspector = new InspectorRegion(),
/**
* Two region parts are defined here. One that appears only in browse
* mode, and one that appears only in edit mode. For not they both point
* to the same representation, but a different key could be used here to
* include a customized representation for edit mode.
*/
plotOptionsBrowsePart = {
name: "plot-options",
title: "Plot Options",
modes: ['browse'],
content: {
key: "plot-options-browse"
}
},
plotOptionsEditPart = {
name: "plot-options",
title: "Plot Options",
modes: ['edit'],
content: {
key: "plot-options-browse"
}
};
/**
* Both parts are added, and policies of type 'region' will determine
* which is shown based on domain object state. A default policy is
* provided which will check the 'modes' attribute of the region part
* definition.
*/
plotInspector.addPart(plotOptionsBrowsePart);
plotInspector.addPart(plotOptionsEditPart);
legacyRegistry.register("example/plotType", {
"name": "Plot Type",
"description": "Example illustrating registration of a new object type",
"extensions": {
"types": [
{
"key": "plot",
"name": "Telemetry Plot",
"glyph": "t",
"description": "A plot for displaying telemetry",
"delegates": [
"telemetry"
],
"features": "creation",
"contains": [
{
"has": "telemetry"
}
],
"model": {
"composition": []
},
"regions": {
"inspector": plotInspector
},
"telemetry": {
"source": "generator",
"domains": [
{
"key": "time",
"name": "Time"
},
{
"key": "yesterday",
"name": "Yesterday"
},
{
"key": "delta",
"name": "Delta",
"format": "example.delta"
}
],
"ranges": [
{
"key": "sin",
"name": "Sine"
},
{
"key": "cos",
"name": "Cosine"
}
]
},
"properties": [
{
"name": "Period",
"control": "textfield",
"cssclass": "l-small l-numeric",
"key": "period",
"required": true,
"property": [
"telemetry",
"period"
],
"pattern": "^\\d*(\\.\\d*)?$"
}
]
}
]
}
});
});

View File

@@ -71,7 +71,7 @@ module.exports = function(config) {
// Specify browsers to run tests in.
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [
'Chrome'
'PhantomJS'
],
// Code coverage reporting.

View File

@@ -71,6 +71,7 @@ define([
'./platform/entanglement/bundle',
'./platform/search/bundle',
'./platform/status/bundle',
'./platform/commonUI/regions/bundle',
'./example/imagery/bundle',
'./example/eventGenerator/bundle',

View File

@@ -7,7 +7,6 @@
"minimist": "^1.1.1"
},
"devDependencies": {
"canvas": "^1.2.7",
"glob": ">= 3.0.0",
"jasmine-core": "^2.3.0",
"jsdoc": "^3.3.2",
@@ -18,13 +17,13 @@
"karma-coverage": "^0.5.3",
"karma-html-reporter": "^0.2.7",
"karma-jasmine": "^0.1.5",
"karma-phantomjs-launcher": "^0.1.4",
"karma-phantomjs-launcher": "^0.2.3",
"karma-requirejs": "^0.2.2",
"lodash": "^3.10.1",
"markdown-toc": "^0.11.7",
"marked": "^0.3.5",
"mkdirp": "^0.5.1",
"nomnoml": "^0.0.3",
"phantomjs": "^1.9.19",
"requirejs": "^2.1.17",
"split": "^1.0.0"
},

View File

@@ -1,5 +0,0 @@
[
"AboutController",
"LicenseController",
"LogoController"
]

View File

@@ -36,6 +36,7 @@ define([
"./src/creation/CreateActionProvider",
"./src/creation/CreationService",
"./src/windowing/WindowTitler",
"./src/TypeRegionDecorator",
'legacyRegistry'
], function (
BrowseController,
@@ -52,6 +53,7 @@ define([
CreateActionProvider,
CreationService,
WindowTitler,
TypeRegionDecorator,
legacyRegistry
) {
"use strict";
@@ -78,7 +80,6 @@ define([
"$scope",
"$route",
"$location",
"$q",
"objectService",
"navigationService",
"urlService"
@@ -192,6 +193,18 @@ define([
"context"
],
"templateUrl": "templates/back-arrow.html"
},
{
"key": "object-properties",
"templateUrl": "templates/browse/object-properties.html"
},
{
"key": "inspector-region",
"templateUrl": "templates/browse/inspector-region.html"
},
{
"key": "view-region",
"templateUrl": "templates/view-region.html"
}
],
"services": [
@@ -280,6 +293,11 @@ define([
"$q",
"$log"
]
},
{
"provides": "typeService",
"type": "decorator",
"implementation": TypeRegionDecorator
}
],
"runs": [

View File

@@ -47,11 +47,6 @@
<div class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
<!-- Toolbar and Save/Cancel buttons -->
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
<mct-toolbar name="mctToolbar"
structure="toolbar.structure"
ng-model="toolbar.state"
class="flex-elem grows">
</mct-toolbar>
<mct-representation key="'edit-action-buttons'"
mct-object="domainObject"
class='flex-elem conclude-editing'>

View File

@@ -63,7 +63,7 @@
<mct-split-pane class='l-object-and-inspector contents abs' anchor='right'>
<div class='split-pane-component t-object pane primary-pane left'>
<mct-representation mct-object="navigatedObject"
key="'browse-object'"
key="'view-region'"
class="abs holder holder-object">
</mct-representation>
</div>
@@ -87,4 +87,3 @@
</div>
<mct-include key="'bottombar'"></mct-include>
</div>

View File

@@ -19,14 +19,12 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div content="jquery-wrapper"
class="abs holder-all edit-mode"
ng-controller="EditController as editMode"
mct-before-unload="editMode.getUnloadWarning()">
<mct-representation key="'edit-object'" mct-object="editMode.navigatedObject()">
</mct-representation>
<mct-include key="'bottombar'"></mct-include>
</div>
<div ng-controller="RegionController as regionController">
<div ng-repeat="part in regions.inspector.parts">
<mct-representation
key="part.content.key"
mct-object="domainObject"
ng-model="ngModel">
</mct-representation>
</div>
</div><!--/ PaneController -->

View File

@@ -0,0 +1,60 @@
<!--
Open MCT Web, Copyright (c) 2014-2015, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT Web is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT Web includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div ng-controller="ObjectInspectorController as controller">
<ul class="flex-elem grows l-inspector-part">
<li>
<em class="t-inspector-part-header">Properties</em>
<div class="inspector-properties"
ng-repeat="data in metadata"
ng-class="{ first:$index === 0 }">
<div class="label">{{ data.name }}</div>
<div class="value">{{ data.value }}</div>
</div>
</li>
<li ng-if="contextutalParents.length > 0">
<em class="t-inspector-part-header" title="The location of this linked object.">Location</em>
<span class="inspector-location"
ng-repeat="parent in contextutalParents"
ng-class="{ last:($index + 1) === contextualParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-model="ngModel"
ng-click="ngModel.selectedObject = parent"
class="location-item">
</mct-representation>
</span>
</li>
<li ng-if="primaryParents.length > 0">
<em class="t-inspector-part-header" title="The location of the original object that this was linked from.">Original Location</em>
<span class="inspector-location"
ng-repeat="parent in primaryParents"
ng-class="{ last:($index + 1) === primaryParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-model="ngModel"
ng-click="ngModel.selectedObject = parent"
class="location-item">
</mct-representation>
</span>
</li>
</ul>
</div><!--/ holder-inspector -->

View File

@@ -27,7 +27,9 @@
<mct-representation class="desktop-hide" key="'info-button'" mct-object="domainObject"></mct-representation>
</div>
<div class='item-main abs lg'>
<span class="t-item-icon" ng-class="{ 'l-icon-link':location.isLink() }">{{type.getGlyph()}}</span>
<span class="t-item-icon" ng-class="{ 'l-icon-link':location.isLink() }">
<span class="t-item-icon-glyph ng-binding">{{type.getGlyph()}}</span>
</span>
<div class='ui-symbol abs item-open'>}</div>
</div>
<div class='bottom-bar bar abs'>

View File

@@ -0,0 +1,30 @@
<!--
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.
-->
<div ng-controller="RegionController as regionController">
<div ng-repeat="part in regions.view.parts">
<mct-representation
key="part.content.key"
mct-object="domainObject"
ng-model="ngModel">
</mct-representation>
</div>
</div><!--/ PaneController -->

View File

@@ -27,10 +27,9 @@
*/
define(
[
'../../../representation/src/gestures/GestureConstants',
'../../edit/src/objects/EditableDomainObject'
'../../../representation/src/gestures/GestureConstants'
],
function (GestureConstants, EditableDomainObject) {
function (GestureConstants) {
"use strict";
var ROOT_ID = "ROOT",
@@ -47,18 +46,11 @@ define(
* @memberof platform/commonUI/browse
* @constructor
*/
function BrowseController($scope, $route, $location, $q, objectService, navigationService, urlService) {
function BrowseController($scope, $route, $location, objectService, navigationService, urlService) {
var path = [ROOT_ID].concat(
($route.current.params.ids || DEFAULT_PATH).split("/")
);
function isDirty(){
var editorCapability = $scope.navigatedObject &&
$scope.navigatedObject.getCapability("editor"),
hasChanges = editorCapability && editorCapability.dirty();
return hasChanges;
}
function updateRoute(domainObject) {
var priorRoute = $route.current,
// Act as if params HADN'T changed to avoid page reload
@@ -75,9 +67,7 @@ define(
// urlService.urlForLocation used to adjust current
// path to new, addressed, path based on
// domainObject
$location.path(urlService.urlForLocation("browse",
domainObject.hasCapability('editor') ?
domainObject.getOriginalObject() : domainObject));
$location.path(urlService.urlForLocation("browse", domainObject));
}
@@ -89,17 +79,15 @@ define(
return;
}
if (isDirty() && !confirm(CONFIRM_MSG)) {
$scope.treeModel.selectedObject = $scope.navigatedObject;
navigationService.setNavigation($scope.navigatedObject);
} else {
if ($scope.navigatedObject && $scope.navigatedObject.hasCapability("editor")){
$scope.navigatedObject.getCapability("editor").cancel();
}
if (navigationService.setNavigation(domainObject)) {
$scope.navigatedObject = domainObject;
$scope.treeModel.selectedObject = domainObject;
navigationService.setNavigation(domainObject);
updateRoute(domainObject);
} else {
//If navigation was unsuccessful (ie. blocked), reset
// the selected object in the tree to the currently
// navigated object
$scope.treeModel.selectedObject = $scope.navigatedObject ;
}
}
@@ -170,18 +158,13 @@ define(
selectedObject: navigationService.getNavigation()
};
$scope.beforeUnloadWarning = function() {
return isDirty() ?
"Unsaved changes will be lost if you leave this page." :
undefined;
};
// Listen for changes in navigation state.
navigationService.addListener(setNavigation);
// Also listen for changes which come from the tree
// Also listen for changes which come from the tree. Changes in
// the tree will trigger a change in browse navigation state.
$scope.$watch("treeModel.selectedObject", setNavigation);
// Clean up when the scope is destroyed
$scope.$on("$destroy", function () {
navigationService.removeListener(setNavigation);
@@ -191,4 +174,3 @@ define(
return BrowseController;
}
);

View File

@@ -22,11 +22,8 @@
/*global define,Promise*/
define(
[
'../../../representation/src/gestures/GestureConstants',
'../../edit/src/objects/EditableDomainObject'
],
function (GestureConstants, EditableDomainObject) {
[],
function () {
"use strict";
/**
@@ -57,10 +54,9 @@ define(
function updateQueryParam(viewKey) {
var unlisten,
priorRoute = $route.current,
isEditMode = $scope.domainObject && $scope.domainObject.hasCapability('editor');
priorRoute = $route.current;
if (viewKey && !isEditMode) {
if (viewKey) {
$location.search('view', viewKey);
unlisten = $scope.$on('$locationChangeSuccess', function () {
// Checks path to make sure /browse/ is at front
@@ -76,10 +72,6 @@ define(
$scope.$watch('domainObject', setViewForDomainObject);
$scope.$watch('representation.selected.key', updateQueryParam);
$scope.cancelEditing = function() {
navigationService.setNavigation($scope.domainObject.getDomainObject());
};
$scope.doAction = function (action){
return $scope[action] && $scope[action]();
};
@@ -89,4 +81,3 @@ define(
return BrowseObjectController;
}
);

View File

@@ -0,0 +1,69 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,window*/
define(
[
'../../regions/src/Region'
],
function (Region) {
"use strict";
/**
* Defines the a default Inspector region. Captured in a class to
* allow for modular extension and customization of regions based on
* the typical case.
* @memberOf platform/commonUI/regions
* @constructor
*/
function InspectorRegion() {
Region.call(this);
this.buildRegion();
}
InspectorRegion.prototype = Object.create(Region.prototype);
InspectorRegion.prototype.constructor = Region;
/**
* @private
*/
InspectorRegion.prototype.buildRegion = function() {
var metadataPart = {
name: 'properties-location',
title: 'Properties and Location',
// Which modes should the region part be visible in? If
// nothing provided here, then assumed that part is visible
// in both. The visibility or otherwise of a region part
// should be decided by a policy. In this case, 'modes' is a
// shortcut that is used by the EditableRegionPolicy.
modes: ['browse', 'edit'],
content: {
key: 'object-properties'
}
};
this.addPart(metadataPart, 0);
};
return InspectorRegion;
}
);

View File

@@ -0,0 +1,92 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,window*/
define(
[
'./InspectorRegion',
'./ViewRegion'
],
function (InspectorRegion, ViewRegion) {
"use strict";
/**
* Adds default browse screen regions to Type definitions. Screen
* regions are sections of the browse and edit view of an object
* that can be customized on a per-type basis. Within
* {@link Region}s are {@link RegionPart}s. Policies can be used to
* decide which parts are visible or not based on object state.
* @memberOf platform/commonUI/regions
* @see {@link Region}, {@link RegionPart}, {@link EditableRegionPolicy}
* @constructor
*/
function TypeRegionDecorator(typeService) {
this.typeService = typeService;
}
/**
* Read Type bundle definition, and add default region definitions
* if none provided.
* @private
* @param type
* @returns {*}
*/
TypeRegionDecorator.prototype.decorateType = function (type) {
var regions = type.getDefinition().regions || {};
regions.inspector = regions.inspector || new InspectorRegion();
regions.view = regions.view || new ViewRegion();
type.getDefinition().regions = regions;
return type;
};
/**
* Override the provider functions in order to return decorated Type
* objects.
* @returns {Array|*}
*/
TypeRegionDecorator.prototype.listTypes = function() {
var self = this,
types = this.typeService.listTypes();
return types.map(function (type) {
return self.decorateType(type);
});
};
/**
* Override the provider function in order to return decorated Type
* objects.
* @param key
*/
TypeRegionDecorator.prototype.getType = function(key) {
var self = this,
type = this.typeService.getType(key);
return self.decorateType(type);
};
return TypeRegionDecorator;
}
);

View File

@@ -0,0 +1,73 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,window*/
define(
[
'../../regions/src/Region'
],
function (Region) {
"use strict";
/**
* Defines the default View region. Captured in a class to
* allow for modular extension and customization of regions based on
* the typical case.
* @memberOf platform/commonUI/regions
* @constructor
*/
function ViewRegion() {
Region.call(this);
this.buildRegion();
}
ViewRegion.prototype = Object.create(Region.prototype);
ViewRegion.prototype.constructor = Region;
/**
* @private
*/
ViewRegion.prototype.buildRegion = function() {
var browseViewPart = {
name: 'browse-view',
title: 'Browse Object View',
modes: ['browse'],
content: {
key: 'browse-object'
}
},
editViewPart = {
name: 'edit-view',
title: 'Edit Object View',
modes: ['edit'],
content: {
key: 'edit-object'
}
};
this.addPart(browseViewPart);
this.addPart(editViewPart);
};
return ViewRegion;
}
);

View File

@@ -37,7 +37,7 @@ define(
*/
function NavigationService() {
this.navigated = undefined;
this.callbacks = [];
this.callbacks = {};
}
/**
@@ -50,26 +50,48 @@ define(
/**
* Set the current navigation state. This will invoke listeners.
* Changing the navigation state will be blocked if any of the
* 'before' navigation state change listeners return 'false'.
* @param {DomainObject} domainObject the domain object to navigate to
*/
NavigationService.prototype.setNavigation = function (value) {
var canNavigate = true;
if (this.navigated !== value) {
this.navigated = value;
this.callbacks.forEach(function (callback) {
callback(value);
});
canNavigate = (this.callbacks.before || [])
.reduce(function (previous, callback) {
//Check whether the callback returned a value of
// 'false' indicating that navigation should not
// continue. All other return values will allow
// navigation to continue
return (callback(value)!==false) && previous;
}, true);
if (canNavigate) {
this.navigated = value;
(this.callbacks.after || []).forEach(function (callback) {
callback(value);
});
}
}
return canNavigate;
};
/**
* Listen for changes in navigation. The passed callback will
* be invoked with the new domain object of navigation when
* this changes.
* this changes. Callbacks can be registered to listen to pre or
* post-navigation events. The event to listen to is specified using
* the event parameter. In the case of pre-navigation events
* returning a false value will prevent the navigation event from
* going ahead.
* @param {function} callback the callback to invoke when
* navigation state changes
* @param {string} [event=after] the navigation event to listen to.
* One of 'before' or 'after'.
*/
NavigationService.prototype.addListener = function (callback) {
this.callbacks.push(callback);
NavigationService.prototype.addListener = function (callback, event) {
event = event || 'after';
this.callbacks[event] = this.callbacks[event] || [];
this.callbacks[event].push(callback);
};
/**
@@ -77,9 +99,12 @@ define(
* @param {function} callback the callback which should
* no longer be invoked when navigation state
* changes
* @param {string} [event=after] the navigation event that the
* callback is registered to. One of 'before' or 'after'.
*/
NavigationService.prototype.removeListener = function (callback) {
this.callbacks = this.callbacks.filter(function (cb) {
NavigationService.prototype.removeListener = function (callback, event) {
event = event || 'after';
this.callbacks[event] = this.callbacks[event].filter(function (cb) {
return cb !== callback;
});
};

View File

@@ -29,8 +29,7 @@ define(
function (BrowseController) {
"use strict";
//TODO: Disabled for NEM Beta
xdescribe("The browse controller", function () {
describe("The browse controller", function () {
var mockScope,
mockRoute,
mockLocation,
@@ -230,7 +229,10 @@ define(
// prior to setting $route.current
mockLocation.path.andReturn("/browse/");
mockNavigationService.setNavigation.andReturn(true);
// Exercise the Angular workaround
mockNavigationService.addListener.mostRecentCall.args[0]();
mockScope.$on.mostRecentCall.args[1]();
expect(mockUnlisten).toHaveBeenCalled();
@@ -241,6 +243,32 @@ define(
);
});
it("after successful navigation event sets the selected tree " +
"object", function () {
mockScope.navigatedObject = mockDomainObject;
mockNavigationService.setNavigation.andReturn(true);
//Simulate a change in selected tree object
mockScope.treeModel = {selectedObject: mockDomainObject};
mockScope.$watch.mostRecentCall.args[1](mockNextObject);
expect(mockScope.treeModel.selectedObject).toBe(mockNextObject);
expect(mockScope.treeModel.selectedObject).not.toBe(mockDomainObject);
});
it("after failed navigation event resets the selected tree" +
" object", function () {
mockScope.navigatedObject = mockDomainObject;
mockNavigationService.setNavigation.andReturn(false);
//Simulate a change in selected tree object
mockScope.treeModel = {selectedObject: mockDomainObject};
mockScope.$watch.mostRecentCall.args[1](mockNextObject);
expect(mockScope.treeModel.selectedObject).not.toBe(mockNextObject);
expect(mockScope.treeModel.selectedObject).toBe(mockDomainObject);
});
});
}
);

View File

@@ -0,0 +1,45 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
/**
* MCTIncudeSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../src/InspectorRegion"],
function (InspectorRegion) {
"use strict";
describe("The inspector region", function () {
var inspectorRegion;
beforeEach(function () {
inspectorRegion = new InspectorRegion();
});
it("creates default region parts", function () {
expect(inspectorRegion.parts.length).toBe(1);
});
});
}
);

View File

@@ -0,0 +1,70 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
/**
* MCTIncudeSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../src/TypeRegionDecorator"],
function (TypeRegionDecorator) {
"use strict";
describe("The type region decorator", function () {
var typeRegionDecorator,
mockTypeService,
mockType,
mockTypeDefinition;
beforeEach(function () {
mockTypeDefinition = {};
mockType = jasmine.createSpyObj('type', [
'getDefinition'
]);
mockType.getDefinition.andReturn(mockTypeDefinition);
mockTypeService = jasmine.createSpyObj('typeService', [
'listTypes',
'getType'
]);
mockTypeService.getType.andReturn(mockType);
mockTypeService.listTypes.andReturn([mockType]);
typeRegionDecorator = new TypeRegionDecorator(mockTypeService);
});
it("decorates individual type definitions with basic inspector" +
" region", function () {
typeRegionDecorator.getType('someType');
expect(mockTypeDefinition.regions).toBeDefined();
});
it("decorates all type definitions with basic inspector" +
" region", function () {
typeRegionDecorator.listTypes();
expect(mockTypeDefinition.regions).toBeDefined();
});
});
}
);

View File

@@ -84,6 +84,24 @@ define(
expect(callback).not.toHaveBeenCalled();
});
it("adds listeners to the 'after' state by default", function(){
expect(navigationService.callbacks.after).toBeUndefined();
navigationService.addListener(function(){});
expect(navigationService.callbacks.after).toBeDefined();
expect(navigationService.callbacks.after.length).toBe(1);
});
it("allows navigationService events to be prevented", function(){
var callback = jasmine.createSpy("callback"),
navigationResult;
callback.andReturn(false);
navigationService.addListener(callback, "before");
navigationResult = navigationService.setNavigation({});
expect(callback).toHaveBeenCalled();
expect(navigationResult).toBe(false);
});
});
}
);
);

View File

@@ -1,18 +0,0 @@
[
"BrowseController",
"BrowseObjectController",
"PaneController",
"MenuArrowController",
"creation/CreateAction",
"creation/CreateActionProvider",
"creation/CreateMenuController",
"creation/CreateWizard",
"creation/CreationService",
"creation/CreationPolicy",
"creation/LocatorController",
"navigation/NavigateAction",
"navigation/NavigationService",
"windowing/FullscreenAction",
"windowing/NewTabAction",
"windowing/WindowTitler"
]

View File

@@ -1,4 +0,0 @@
[
"DialogService",
"OverlayService"
]

View File

@@ -22,10 +22,10 @@
/*global define*/
define([
"./src/controllers/EditController",
"./src/controllers/EditActionController",
"./src/controllers/EditPanesController",
"./src/controllers/ElementsController",
"./src/controllers/EditObjectController",
"./src/directives/MCTBeforeUnload",
"./src/actions/LinkAction",
"./src/actions/EditAction",
@@ -38,10 +38,10 @@ define([
"./src/representers/EditToolbarRepresenter",
'legacyRegistry'
], function (
EditController,
EditActionController,
EditPanesController,
ElementsController,
EditObjectController,
MCTBeforeUnload,
LinkAction,
EditAction,
@@ -58,22 +58,7 @@ define([
legacyRegistry.register("platform/commonUI/edit", {
"extensions": {
"routes": [
{
"when": "/edit",
"templateUrl": "templates/edit.html"
}
],
"controllers": [
{
"key": "EditController",
"implementation": EditController,
"depends": [
"$scope",
"$q",
"navigationService"
]
},
{
"key": "EditActionController",
"implementation": EditActionController,
@@ -94,6 +79,14 @@ define([
"depends": [
"$scope"
]
},
{
"key": "EditObjectController",
"implementation": EditObjectController,
"depends": [
"$scope",
"$location"
]
}
],
"directives": [
@@ -101,7 +94,8 @@ define([
"key": "mctBeforeUnload",
"implementation": MCTBeforeUnload,
"depends": [
"$window"
"$window",
"navigationService"
]
}
],
@@ -197,6 +191,9 @@ define([
"templateUrl": "templates/edit-object.html",
"uses": [
"view"
],
"gestures": [
"drop"
]
},
{

View File

@@ -19,50 +19,51 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<mct-representation key="'topbar-edit'"
mct-object="domainObject"
ng-model="representation">
</mct-representation>
<div class="holder edit-area abs">
<mct-split-pane class='contents abs' anchor='right'>
<div class='split-pane-component pane left edit-main'>
<mct-toolbar name="mctToolbar"
structure="toolbar.structure"
ng-model="toolbar.state">
</mct-toolbar>
<mct-representation key="representation.selected.key"
toolbar="toolbar"
mct-object="representation.selected.key && domainObject"
class="holder abs object-holder work-area">
<div class="abs l-flex-col" ng-controller="EditObjectController as EditObjectController">
<div mct-before-unload="EditObjectController.getUnloadWarning()"
class="holder flex-elem l-flex-row object-browse-bar ">
<div class="items-select left flex-elem l-flex-row grows">
<mct-representation key="'back-arrow'"
mct-object="domainObject"
class="flex-elem l-back"></mct-representation>
<mct-representation key="'object-header'"
mct-object="domainObject"
class="l-flex-row flex-elem grows object-header">
</mct-representation>
</div>
<mct-splitter></mct-splitter>
<div
class='split-pane-component pane right edit-objects menus-to-left'
ng-controller='EditPanesController as editPanes'
>
<mct-split-pane class='contents abs' anchor='bottom'>
<div
class="abs pane top accordion"
ng-controller="ToggleController as toggle"
>
<mct-container key="accordion" label="Library">
<mct-representation key="'tree'"
mct-object="editPanes.getRoot()">
</mct-representation>
</mct-container>
</div>
<mct-splitter></mct-splitter>
<div
class="abs pane bottom accordion"
ng-controller="ToggleController as toggle"
>
<mct-container key="accordion" label="Elements">
<mct-representation key="'edit-elements'" mct-object="domainObject">
</mct-representation>
</mct-container>
</div>
</mct-split-pane>
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
<mct-representation key="'switcher'"
mct-object="domainObject"
ng-model="representation">
</mct-representation>
<!-- Temporarily, on mobile, the action buttons are hidden-->
<mct-representation key="'action-group'"
mct-object="domainObject"
parameters="{ category: 'view-control' }"
class="mobile-hide">
</mct-representation>
</div>
</mct-split-pane>
</div>
<div class="holder l-flex-col flex-elem grows l-object-wrapper">
<div class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
<!-- Toolbar and Save/Cancel buttons -->
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
<mct-toolbar name="mctToolbar"
structure="toolbar.structure"
ng-model="toolbar.state"
class="flex-elem grows">
</mct-toolbar>
<mct-representation key="'edit-action-buttons'"
mct-object="domainObject"
class='flex-elem conclude-editing'>
</mct-representation>
</div>
<mct-representation key="representation.selected.key"
mct-object="representation.selected.key && domainObject"
class="abs flex-elem grows object-holder-main scroll"
toolbar="toolbar">
</mct-representation>
</div><!--/ l-object-wrapper-inner -->
</div>
</div>

View File

@@ -72,13 +72,26 @@ define(
* Enter edit mode.
*/
EditAction.prototype.perform = function () {
var editableObject;
var self = this;
if (!this.domainObject.hasCapability("editor")) {
editableObject = new EditableDomainObject(this.domainObject, this.$q);
editableObject.getCapability('status').set('editing', true);
this.navigationService.setNavigation(editableObject);
//TODO: This is only necessary because the drop gesture is
// wrapping the object itself, need to refactor this later.
// All responsibility for switching into edit mode should be
// in the edit action, and not duplicated in the gesture
this.domainObject = new EditableDomainObject(this.domainObject, this.$q);
}
//this.$location.path("/edit");
this.navigationService.setNavigation(this.domainObject);
this.domainObject.getCapability('status').set('editing', true);
//Register a listener to automatically cancel this edit action
//if the user navigates away from this object.
function cancelEditing(navigatedTo){
if (!navigatedTo || navigatedTo.getId() !== self.domainObject.getId()) {
self.domainObject.getCapability('editor').cancel();
self.navigationService.removeListener(cancelEditing);
}
}
this.navigationService.addListener(cancelEditing);
};
/**

View File

@@ -26,41 +26,44 @@
* @namespace platform/commonUI/edit
*/
define(
["../objects/EditableDomainObject"],
function (EditableDomainObject) {
[],
function () {
"use strict";
/**
* Controller which is responsible for populating the scope for
* Edit mode; introduces an editable version of the currently
* navigated domain object into the scope.
* Edit mode
* @memberof platform/commonUI/edit
* @constructor
*/
function EditController($scope, $q, navigationService) {
var self = this;
function EditObjectController($scope, $location) {
this.scope = $scope;
function setNavigation(domainObject) {
// Wrap the domain object such that all mutation is
// confined to edit mode (until Save)
self.navigatedDomainObject =
domainObject && new EditableDomainObject(domainObject, $q);
var navigatedObject;
function setViewForDomainObject(domainObject) {
var locationViewKey = $location.search().view;
function selectViewIfMatching(view) {
if (view.key === locationViewKey) {
$scope.representation = $scope.representation || {};
$scope.representation.selected = view;
}
}
if (locationViewKey) {
((domainObject && domainObject.useCapability('view')) || [])
.forEach(selectViewIfMatching);
}
navigatedObject = domainObject;
}
setNavigation(navigationService.getNavigation());
navigationService.addListener(setNavigation);
$scope.$on("$destroy", function () {
navigationService.removeListener(setNavigation);
});
}
$scope.$watch('domainObject', setViewForDomainObject);
/**
* Get the domain object which is navigated-to.
* @returns {DomainObject} the domain object that is navigated-to
*/
EditController.prototype.navigatedObject = function () {
return this.navigatedDomainObject;
};
$scope.doAction = function (action){
return $scope[action] && $scope[action]();
};
}
/**
* Get the warning to show if the user attempts to navigate
@@ -68,17 +71,20 @@ define(
* @returns {string} the warning to show, or undefined if
* there are no unsaved changes
*/
EditController.prototype.getUnloadWarning = function () {
var navigatedObject = this.navigatedDomainObject,
EditObjectController.prototype.getUnloadWarning = function () {
var navigatedObject = this.scope.domainObject,
editorCapability = navigatedObject &&
navigatedObject.getCapability("editor"),
hasChanges = editorCapability && editorCapability.dirty();
statusCapability = navigatedObject &&
navigatedObject.getCapability("status"),
hasChanges = statusCapability && statusCapability.get('editing')
&& editorCapability && editorCapability.dirty();
return hasChanges ?
"Unsaved changes will be lost if you leave this page." :
undefined;
};
return EditController;
return EditObjectController;
}
);

View File

@@ -35,7 +35,7 @@ define(
* @constructor
* @param $window the window
*/
function MCTBeforeUnload($window) {
function MCTBeforeUnload($window, navigationService) {
var unloads = [],
oldBeforeUnload = $window.onbeforeunload;
@@ -55,8 +55,23 @@ define(
return scope.$eval(attrs.mctBeforeUnload);
}
function shouldAllowNavigation(){
// Get an unload message (if any)
var warning = unload();
// Prompt the user if there's an unload message
return !warning || $window.confirm(warning);
}
// Show a dialog before allowing a location change
function checkNavigationEvent(event) {
// Return a false value to the navigationService to
// indicate that the navigation event should be prevented
return shouldAllowNavigation();
}
// Stop using this unload expression
function removeUnload() {
navigationService.removeListener(checkNavigationEvent, "before");
unloads = unloads.filter(function (callback) {
return callback !== unload;
});
@@ -67,11 +82,8 @@ define(
// Show a dialog before allowing a location change
function checkLocationChange(event) {
// Get an unload message (if any)
var warning = unload();
// Prompt the user if there's an unload message
if (warning && !$window.confirm(warning)) {
// ...and prevent the route change if it was confirmed
if (!shouldAllowNavigation()) {
// Prevent the route change if it was confirmed
event.preventDefault();
}
}
@@ -90,6 +102,8 @@ define(
// Also handle route changes
scope.$on("$locationChangeStart", checkLocationChange);
navigationService.addListener(checkNavigationEvent, "before");
}
return {

View File

@@ -22,89 +22,72 @@
/*global define,describe,it,expect,beforeEach,jasmine*/
define(
["../../src/controllers/EditController"],
function (EditController) {
["../../src/controllers/EditObjectController"],
function (EditObjectController) {
"use strict";
describe("The Edit mode controller", function () {
var mockScope,
mockQ,
mockNavigationService,
mockObject,
mockType,
mockLocation,
mockStatusCapability,
mockCapabilities,
controller;
// Utility function; look for a $watch on scope and fire it
function fireWatch(expr, value) {
mockScope.$watch.calls.forEach(function (call) {
if (call.args[0] === expr) {
call.args[1](value);
}
});
}
beforeEach(function () {
mockScope = jasmine.createSpyObj(
"$scope",
[ "$on" ]
);
mockQ = jasmine.createSpyObj('$q', ['when', 'all']);
mockNavigationService = jasmine.createSpyObj(
"navigationService",
[ "getNavigation", "addListener", "removeListener" ]
[ "$on", "$watch" ]
);
mockObject = jasmine.createSpyObj(
"domainObject",
[ "getId", "getModel", "getCapability", "hasCapability" ]
[ "getId", "getModel", "getCapability", "hasCapability", "useCapability" ]
);
mockType = jasmine.createSpyObj(
"type",
[ "hasFeature" ]
);
mockStatusCapability = jasmine.createSpyObj('statusCapability',
["get"]
);
mockCapabilities = {
"type" : mockType,
"status": mockStatusCapability
};
mockLocation = jasmine.createSpyObj('$location',
["search"]
);
mockLocation.search.andReturn({"view": "fixed"});
mockNavigationService.getNavigation.andReturn(mockObject);
mockObject.getId.andReturn("test");
mockObject.getModel.andReturn({ name: "Test object" });
mockObject.getCapability.andCallFake(function (key) {
return key === 'type' && mockType;
return mockCapabilities[key];
});
mockType.hasFeature.andReturn(true);
controller = new EditController(
mockScope.domainObject = mockObject;
controller = new EditObjectController(
mockScope,
mockQ,
mockNavigationService
mockLocation
);
});
it("exposes the currently-navigated object", function () {
expect(controller.navigatedObject()).toBeDefined();
expect(controller.navigatedObject().getId()).toEqual("test");
});
it("adds an editor capability to the navigated object", function () {
// Should provide an editor capability...
expect(controller.navigatedObject().getCapability("editor"))
.toBeDefined();
// Shouldn't have been the mock capability we provided
expect(controller.navigatedObject().getCapability("editor"))
.not.toEqual(mockType);
});
it("detaches its navigation listener when destroyed", function () {
var navCallback = mockNavigationService
.addListener.mostRecentCall.args[0];
expect(mockScope.$on).toHaveBeenCalledWith(
"$destroy",
jasmine.any(Function)
);
// Verify precondition
expect(mockNavigationService.removeListener)
.not.toHaveBeenCalled();
// Trigger destroy
mockScope.$on.mostRecentCall.args[1]();
// Listener should have been removed
expect(mockNavigationService.removeListener)
.toHaveBeenCalledWith(navCallback);
});
it("exposes a warning message for unload", function () {
var obj = controller.navigatedObject(),
var obj = mockObject,
mockEditor = jasmine.createSpyObj('editor', ['dirty']);
// Normally, should be undefined
@@ -112,14 +95,32 @@ define(
// Override the object's editor capability, make it look
// like there are unsaved changes.
obj.getCapability = jasmine.createSpy();
obj.getCapability.andReturn(mockEditor);
mockCapabilities.editor = mockEditor;
mockEditor.dirty.andReturn(true);
mockStatusCapability.get.andReturn(true);
// Should have some warning message here now
expect(controller.getUnloadWarning()).toEqual(jasmine.any(String));
});
it("sets the active view from query parameters", function () {
var testViews = [
{ key: 'abc' },
{ key: 'def', someKey: 'some value' },
{ key: 'xyz' }
];
mockObject.useCapability.andCallFake(function (c) {
return (c === 'view') && testViews;
});
mockLocation.search.andReturn({ view: 'def' });
fireWatch('domainObject', mockObject);
expect(mockScope.representation.selected)
.toEqual(testViews[1]);
});
});
}
);

View File

@@ -31,6 +31,7 @@ define(
mockScope,
testAttrs,
mockEvent,
mockNavigationService,
directive;
function fireListener(eventType, value) {
@@ -46,7 +47,8 @@ define(
mockScope = jasmine.createSpyObj("$scope", ['$eval', '$on']);
testAttrs = { mctBeforeUnload: "someExpression" };
mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
directive = new MCTBeforeUnload(mockWindow);
mockNavigationService = jasmine.createSpyObj("navigationService", ["addListener", "removeListener"]);
directive = new MCTBeforeUnload(mockWindow, mockNavigationService);
directive.link(mockScope, {}, testAttrs);
});
@@ -65,6 +67,10 @@ define(
);
});
it("listens for navigation changes", function () {
expect(mockNavigationService.addListener).toHaveBeenCalledWith(jasmine.any(Function), "before");
});
it("listens for its scope's destroy event", function () {
expect(mockScope.$on).toHaveBeenCalledWith(
"$destroy",
@@ -108,9 +114,10 @@ define(
it("cleans up listeners when destroyed", function () {
fireListener("$destroy", mockEvent);
expect(mockWindow.onbeforeunload).toBeUndefined();
expect(mockNavigationService.removeListener).toHaveBeenCalled();
});
});
}
);
);

View File

@@ -33,6 +33,8 @@ define(
testRepresentation,
mockDomainObject,
mockPersistence,
mockStatusCapability,
mockCapabilities,
representer;
function mockPromise(value) {
@@ -57,11 +59,20 @@ define(
]);
mockPersistence =
jasmine.createSpyObj("persistence", ["persist"]);
mockStatusCapability =
jasmine.createSpyObj("statusCapability", ["get", "listen"]);
mockCapabilities = {
"persistence": mockPersistence,
"status": mockStatusCapability
};
mockDomainObject.getModel.andReturn({});
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.useCapability.andReturn(true);
mockDomainObject.getCapability.andReturn(mockPersistence);
mockDomainObject.getCapability.andCallFake(function(capability){
return mockCapabilities[capability];
});
representer = new EditRepresenter(mockQ, mockLog, mockScope);
representer.represent(testRepresentation, mockDomainObject);
@@ -101,4 +112,4 @@ define(
});
}
);
);

View File

@@ -1,28 +0,0 @@
[
"actions/CancelAction",
"actions/EditAction",
"actions/LinkAction",
"actions/PropertiesAction",
"actions/PropertiesDialog",
"actions/RemoveAction",
"actions/SaveAction",
"capabilities/EditableCompositionCapability",
"capabilities/EditableContextCapability",
"capabilities/EditableLookupCapability",
"capabilities/EditablePersistenceCapability",
"capabilities/EditableRelationshipCapability",
"capabilities/EditorCapability",
"controllers/EditActionController",
"controllers/EditController",
"controllers/EditPanesController",
"directives/MCTBeforeUnload",
"objects/EditableDomainObject",
"objects/EditableDomainObjectCache",
"objects/EditableModelCache",
"policies/EditableViewPolicy",
"policies/EditActionPolicy",
"representers/EditRepresenter",
"representers/EditToolbar",
"representers/EditToolbarRepresenter",
"representers/EditToolbarSelection"
]

View File

@@ -1,4 +0,0 @@
[
"FormatProvider",
"UTCTimeFormat"
]

View File

@@ -119,6 +119,12 @@ define([
]
}
],
"filters": [
{
"implementation": "filters/ReverseFilter.js",
"key": "reverse"
}
],
"stylesheets": [
{
"stylesheetUrl": "css/normalize.min.css",

View File

@@ -94,5 +94,7 @@
<glyph unicode="&#xe614;" glyph-name="icon-collapse-pane-right" d="M768 960h256v-1024h-256c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192zM512 640l-512-320v640z" />
<glyph unicode="&#xe615;" glyph-name="icon-eye-open" d="M512 896c-261 0-480.6-195.4-512-448 31.4-252.6 251-448 512-448s480.6 195.4 512 448c-31.4 252.6-251 448-512 448zM768.2 225.4c-71.4-62.8-162.8-97.4-257.6-97.4s-186.2 34.6-257.6 97.4c-66.6 58.6-110.6 137.2-125 222.6 0 0 0 0.2 0 0.2 76.8 154 220.8 257.6 384 257.6s307.2-103.8 384-257.6c0 0 0-0.2 0-0.2-14.4-85.4-61.2-164-127.8-222.6zM512 672c-123.8 0-224-100.2-224-224s100.2-224 224-224 224 100.2 224 224-100.2 224-224 224z" />
<glyph unicode="&#xe616;" glyph-name="icon-eye-open-no-gleam" d="M512 896c-261 0-480.6-195.4-512-448 31.4-252.6 251-448 512-448s480.6 195.4 512 448c-31.4 252.6-251 448-512 448zM768.2 225.4c-71.4-62.8-162.8-97.4-257.6-97.4s-186.2 34.6-257.6 97.4c-66.6 58.6-110.6 137.2-125 222.6 0 0 0 0.2 0 0.2 76.8 154 220.8 257.6 384 257.6s307.2-103.8 384-257.6c0 0 0-0.2 0-0.2-14.4-85.4-61.2-164-127.8-222.6zM512 672c-123.8 0-224-100.2-224-224s100.2-224 224-224 224 100.2 224 224-100.2 224-224 224zM576 416c-53 0-96 43-96 96s43 96 96 96 96-43 96-96c0-53-43-96-96-96z" />
<glyph unicode="&#xe617;" glyph-name="icon-topic" d="M832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.4c0 0.2 0.2 0.2 0.4 0.4h127.6v191.8h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4zM686 576c7.2 0 21-7.4 38.6-25.8 11.8 24.8 26.4 52.2 43.4 79v50c-26.4 16.4-53.8 24.6-82 24.6-37.6 0-74.2-14.8-108.8-44.2 27.4-37.8 49.6-78.6 66.2-113.8 19.4 21.6 34.8 30.2 42.6 30.2zM338 320c-7.2 0-21 7.4-38.6 25.8-11.8-24.8-26.4-52.2-43.4-79v-74.8h82c37.6 0 74.2 14.8 108.8 44.2-27.4 37.8-49.6 78.6-66.2 113.8-19.4-21.4-34.8-30-42.6-30zM768 415.8c-38.2-70.6-72.8-95.8-85-95.8-15 0-64.2 38.4-112 152.8-17.4 41.8-46.6 101.6-85.8 149.4-44.8 54.4-93.2 82-144.2 82-29.2 0-57.6-9-85-27v-196.8c38.2 70.6 72.8 95.8 85 95.8 15 0 64.2-38.4 112-152.8 17.4-41.8 46.6-101.6 85.8-149.4 44.8-54.4 93.2-82 144.2-82 29.2 0 57.6 9 85 27v196.8z" />
<glyph unicode="&#xe618;" glyph-name="icon-session" d="M101.2 672.4c57.2 69.6 118.6 104.8 182.8 104.8s125.6-35.2 182.8-104.8c51.4-62.6 89.8-141.2 112.6-196.2 27.6-65.8 58.8-121 90.6-159.6 10-12 44.2-51.4 69.8-51.4 6.4 0 30.4 3.8 69.8 51.4 31.8 38.6 63.2 93.8 90.6 159.6 23 55 61.2 133.6 112.6 196.2 3.6 4.4 7.2 8.6 10.8 12.8v18.8c0.4 140.8-114.8 256-255.6 256h-512c-140.8 0-256-115.2-256-256v-201c23.4 51.8 57.4 116.4 101.2 169.4zM744 778c54 0 106.4-24.4 156-72.8-31.6-44.6-57.4-92.2-77.6-134.2-33.4 42-61.8 59.4-78.4 59.4-17.4 0-47.8-19.2-83.2-65.8-27 57.6-54 102.4-77.4 136 51 51.2 104.8 77.4 160.6 77.4zM922.8 223.6c-57.2-69.6-118.8-104.8-182.8-104.8s-125.6 35.2-182.8 104.8c-51.4 62.6-89.8 141.2-112.6 196.2-27.6 65.8-58.8 121-90.6 159.6-10 12-44.2 51.4-69.8 51.4-6.4 0-30.4-3.8-69.8-51.4-31.8-38.6-63.2-93.8-90.6-159.6-23-55-61.2-133.6-112.6-196.2-3.6-4.4-7.2-8.6-10.8-12.8v-18.8c0-140.8 115.2-256 256-256h512c140.8 0 256 115.2 256 256v201c-23.8-51.8-57.8-116.4-101.6-169.4zM280 118c-54 0-106.4 24.4-156 72.8 31.6 44.6 57.4 92.2 77.6 134.2 33.4-42 61.8-59.4 78.4-59.4 17.4 0 47.8 19.2 83.2 65.8 27-57.6 54-102.4 77.4-136-51-51.2-104.8-77.4-160.6-77.4z" />
<glyph unicode="&#xe642;" glyph-name="icon-x" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -35,7 +35,6 @@
}
&.icon {
color: $colorKey;
//position: relative;
font-size: inherit;
&.alert {
color: $colorAlert;
@@ -81,14 +80,11 @@
}
.t-item-icon {
// Used in grid-item.html, tree-item, inspector location, more?
// Used in grid-item.html, tree-item, inspector location
@extend .ui-symbol;
@extend .icon;
line-height: normal; // This is Ok for the symbolsfont
position: relative;
.t-item-icon-glyph {
position: absolute;
}
&.l-icon-link {
.t-item-icon-glyph {
&:before {
@@ -103,4 +99,4 @@
}
}
}
}
}

View File

@@ -32,14 +32,16 @@
color: $colorInspectorFg;
line-height: 140%;
.flex-elem.holder:not(:last-child) { margin-bottom: $interiorMargin; }
.flex-elem.holder:not(:last-child) {
margin-bottom: $interiorMargin;
}
.pane-header {
color: pushBack($colorInspectorFg, 20%);
font-size: 0.8rem;
&:before {
color: pushBack($colorInspectorFg, 10%);
content:'\e615'; // e615 Crosshair symbol
content: '\e615'; // e615 Crosshair symbol
display: inline;
font-family: symbolsfont;
margin-right: $interiorMargin;
@@ -56,14 +58,29 @@
}
}
}
ul {
.l-inspector-part {
@include box-sizing(border-box);
padding-right: $interiorMargin;
.form {
margin-left: $treeVCW + $interiorMarginLg;
margin-bottom: $interiorMarginLg;
.form-section {
margin-bottom: 0;
&:not(.first) {
border-top: 1px solid $colorFormLines;
}
.form-row {
@include align-items(center);
border: none;
padding: 0;
}
}
}
}
ul li,
em {
em.t-inspector-part-header {
display: block;
position: relative;
}
@@ -71,8 +88,8 @@
ul li {
margin-bottom: $interiorMarginLg;
}
em {
em.t-inspector-part-header {
@include border-radius($basicCr);
background-color: $colorInspectorSectionHeaderBg;
color: $colorInspectorSectionHeaderFg;
@@ -154,8 +171,16 @@
}
}
mct-representation:not(.s-status-editing) .l-inspect {
.split-pane-component.pane.top {
bottom: 0 !important;
}
}
.s-status-editing .l-inspect {
.location-item { pointer-events: none; }
.location-item {
pointer-events: none;
}
.splitter-inspect-panel,
.split-pane-component.pane.bottom {
opacity: 1;

View File

@@ -44,10 +44,6 @@ mct-representation {
$spinD: 0;
@include spinner($spinBW);
content: "";
display: block;
position: absolute;
left: 50%;
top: 50%;
padding: 30%;
width: $spinD;
height: $spinD;
@@ -64,6 +60,6 @@ mct-representation {
}
}
.selected mct-representation.s-status-pending .t-object-label .t-item-icon:before {
border-color: rgba($colorItemTreeSelectedFg, 0.25);
border-top-color: rgba($colorItemTreeSelectedFg, 1.0);
border-color: rgba($colorItemTreeSelectedFg, 0.25) !important;
border-top-color: rgba($colorItemTreeSelectedFg, 1.0) !important;
}

View File

@@ -83,7 +83,6 @@
.l-control-group {
// Buttons that have a conceptual grouping - internal space between, and a divider between groups.
// @include test();
@include box-sizing(border-box);
border-left: 1px solid $colorInteriorBorder;
display: inline-block;
@@ -109,31 +108,29 @@
font-size: 0.7rem;
}
label.checkbox.custom {
label.checkbox.custom,
label.radio.custom {
$bg: pullForward($colorBodyBg, 10%);
$d: $formRowCtrlsH;
cursor: pointer;
display: inline-block;
line-height: $d;
margin-right: $interiorMargin * 4;
padding-left: $d + $interiorMargin;
position: relative;
vertical-align: middle; // was top
em {
color: $colorBodyFg;
display: inline-block;
height: $d;
min-width: $d;
width: $d;
&:before {
@include border-radius($basicCr * .75);
background: $bg;
@include box-shadow(inset rgba(black, 0.4) 0 1px 2px);
box-sizing: border-box;
content: " ";
content: "";
font-family: 'symbolsfont';
font-size: 0.8em;
font-size: 0.7em;
display: inline-block;
margin-right: $interiorMargin;
height: $d;
width: $d;
left: 0;
@@ -157,11 +154,13 @@ label.checkbox.custom {
&:checked ~ em:before {
background: $colorCheck;
color: lighten($colorCheck, 50%);
content: "2";
}
}
}
label.checkbox.custom input:checked ~ em:before { content: "\32"; }
label.radio.custom input:checked ~ em:before { content: "\e619"; }
.input-labeled {
margin-left: $interiorMargin;
label {
@@ -333,7 +332,7 @@ label.checkbox.custom {
/******************************************************** SLIDERS */
.slider {
$knobH: 100%; //14px;
$knobH: 100%;
.slot {
width: auto;
position: absolute;
@@ -369,7 +368,7 @@ label.checkbox.custom {
background-color: $sliderColorRange;
cursor: ew-resize;
position: absolute;
top: 0; //$tbOffset;
top: 0;
right: auto;
bottom: 0;
left: auto;

View File

@@ -23,7 +23,6 @@
@include border-radius($basicCr);
background: $colorFormSectionHeader;
$c: lighten($colorBodyFg, 20%);
//border-bottom: 1px solid rgba(#fff, 0.3);
color: $c;
font-size: 0.8em;
padding: $formTBPad $formLRPad;
@@ -32,6 +31,7 @@
.form {
color: $colorFormText;
width: 100%;
.form-section {
position: relative;
margin-bottom: $interiorMarginLg * 2;
@@ -60,28 +60,24 @@
>.label {
// Only style this way for immediate children of .form-row; prevents problems when .label is used in .controls section of a form
//@include test(orange, 0.05);
float: left;
min-width: 120px;
order: 1;
position: relative;
white-space: nowrap;
width: $formLabelW;
}
.value {
color: $colorInputFg; //lighten($colorBodyFg, 20%);
color: $colorInputFg;
}
.controls {
float: left;
order: 2;
position: relative;
width: 99.9% - $formLabelW; // Start with less than 100% for Firefox
@include flex(1 1 auto);
.l-composite-control {
// display: inline-block;
&.l-checkbox {
// @include test();
// height: $formRowCtrlsH;
display: inline-block;
line-height: $formRowCtrlsH;
margin-right: 5px;
@@ -115,7 +111,6 @@
$h: 150px;
position: relative;
height: $h;
// max-width: 50%;
>.wrapper {
$p: $interiorMargin;
overflow: auto;
@@ -129,6 +124,37 @@
}
}
.l-controls-first {
.form .form-row {
margin-top: $interiorMarginSm;
>.label,
>.controls {
line-height: inherit;
min-height: inherit;;
}
>.label {
@include flex(1 1 auto);
min-width: 0;
width: auto;
order: 2;
}
>.controls {
@include flex(0 0 auto);
margin-right: $interiorMargin;
order: 1;
}
}
}
.no-validate {
.form .form-row >.label {
padding-right: 0;
&:after {
display: none;
}
}
}
label.form-control.checkbox {
input {
margin-right: $interiorMargin;

View File

@@ -20,62 +20,37 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
@include keyframes(rotation) {
0% { transform: rotate(0deg); }
100% { transform: rotate(359deg); }
100% { @include transform(rotate(360deg)); }
}
@mixin spinner($b: 5px) {
@include keyframes(rotateCentered) {
0% { @include transform(translateX(-50%) translateY(-50%) rotate(0deg)); }
100% { @include transform(translateX(-50%) translateY(-50%) rotate(359deg)); }
}
@include animation-name(rotateCentered);
@include keyframes(rotation-centered) {
0% { @include transform(translate(-50%, -50%) rotate(0deg)); }
100% { @include transform(translate(-50%, -50%) rotate(360deg)); }
}
@mixin spinner($b: 5px, $c: $colorKey) {
@include transform-origin(center);
@include animation-name(rotation-centered);
@include animation-duration(0.5s);
@include animation-iteration-count(infinite);
@include animation-timing-function(linear);
@include transform-origin(center);
border-style: solid;
border-width: $b;
@include border-radius(100%);
}
@mixin wait-spinner2($b: 5px, $c: $colorAlt1) {
@include spinner($b);
@include box-sizing(border-box);
border-color: rgba($c, 0.25);
border-top-color: rgba($c, 1.0);
border-style: solid;
border-width: $b;
display: block;
position: absolute;
height: 0; width: 0;
padding: 7%;
left: 50%; top: 50%;
}
@mixin wait-spinner($b: 5px, $c: $colorAlt1) {
display: block;
position: absolute;
-webkit-animation: rotation .6s infinite linear;
-moz-animation: rotation .6s infinite linear;
-o-animation: rotation .6s infinite linear;
animation: rotation .6s infinite linear;
border-color: rgba($c, 0.25);
border-top-color: rgba($c, 1.0);
border-style: solid;
border-width: $b;
@include border-radius(100%);
}
.t-wait-spinner,
.wait-spinner {
$d: 5%;
@include wait-spinner(0.5em, $colorKey);
top: 50%; left: 50%;
@include spinner(0.5em, $colorKey);
height: auto; width: auto;
padding: $d; // Will size object based on parent container WIDTH
pointer-events: none;
margin-top: $d / -1;
margin-left: $d / -1;
z-index: 2;
&.inline {
display: inline-block !important;
@@ -85,46 +60,15 @@
}
}
.l-wait-spinner-holder {
pointer-events: none;
position: absolute;
&.align-left {
.t-wait-spinner {
left: 0;
margin-left: 0;
}
}
&.full-size {
display: inline-block;
height: 100%; width: 100%;
.t-wait-spinner {
top: 0;
margin-top: 0;
padding: 30%;
}
}
}
.treeview .wait-spinner {
// Only used in subtree.html, which I don't think this is actually being used
$d: 10px;
@include wait-spinner(0.25em, $colorKey);
height: $d; width: $d;
margin: 0 !important;
padding: 0 !important;
top: 2px; left: 0;
}
.wait-spinner.sm {
$d: 13px;
@include wait-spinner(0.25em, $colorKey);
height: $d; width: $d;
margin-left: 0 !important;
margin-top: 0 !important;
padding: 0 !important;
top: 0; left: 0;
}
.loading {
// Can be applied to any block element with height and width
pointer-events: none;
@@ -133,7 +77,8 @@
content: '';
}
&:before {
@include wait-spinner2(5px, $colorLoadingFg);
@include spinner(5px, $colorLoadingFg);
padding: 5%;
z-index: 10;
}
&:after {
@@ -146,5 +91,4 @@
padding: $menuLineH / 4;
border-width: 2px;
}
}

View File

@@ -27,7 +27,6 @@
}
.item {
&.grid-item {
//div { @include test() }
$d: $ueBrowseGridItemLg;
$iconMargin: 40px;
$iconD: ($d - ($iconMargin * 2)) * 0.85;
@@ -53,7 +52,6 @@
}
}
.contents {
//@include test(red);
$m: $interiorMarginLg;
top: $m; right: $m; bottom: $m; left: $m;
}
@@ -83,19 +81,21 @@
.item-main {
$h: $ueBrowseGridItemLg;
$lh: $h * 0.8;
//top: $ueBrowseGridItemTopBarH; bottom: $ueBrowseGridItemBottomBarH; //
line-height: $lh;
z-index: 1;
.item-type,
.t-item-icon {
//@include test();
@include transform(translateX(-50%) translateY(-55%));
position: absolute;
top: 50%; left: 50%;
//height: $iconD; width: $iconD;
font-size: $iconD * 0.95; //6em;
//line-height: normal;
//text-align: center;
font-size: $iconD * 0.95;
&.l-icon-link {
.t-item-icon-glyph {
&:before {
@include transform(scale(0.25));
}
}
}
}
.item-open {
@include trans-prop-nice("opacity", $transTime);

View File

@@ -266,6 +266,8 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
.gl-plot-tick,
.tick-label {
direction: rtl;
unicode-bidi:bidi-override;
font-size: 0.7rem;
position: absolute;
overflow: hidden;

View File

@@ -23,8 +23,13 @@
ng-controller="DateTimeFieldController">
<input type="text"
ng-model="textValue"
ng-change="structure.onchange(ngModel[field])"
ng-blur="restoreTextValue(); ngBlur()"
ng-class="{ error: textInvalid }">
ng-class="{
error: textInvalid ||
(structure.validate &&
!structure.validate(ngModel[field]))
}">
</input>
<a class="ui-symbol icon icon-calendar"
ng-if="structure.format === 'utc' || !structure.format"

View File

@@ -25,7 +25,7 @@
<span class="l-time-range-inputs-elem ui-symbol type-icon">&#x43;</span>
<span class="l-time-range-input">
<mct-control key="'datetime-field'"
structure="{ format: parameters.format }"
structure="{ format: parameters.format, validate: validateStart }"
ng-model="formModel"
ng-blur="updateBoundsFromForm()"
field="'start'"
@@ -37,7 +37,7 @@
<span class="l-time-range-input" ng-controller="ToggleController as t2">
<mct-control key="'datetime-field'"
structure="{ format: parameters.format }"
structure="{ format: parameters.format, validate: validateEnd }"
ng-model="formModel"
ng-blur="updateBoundsFromForm()"
field="'end'"

View File

@@ -19,55 +19,24 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<span class="l-inspect" ng-controller="ObjectInspectorController as controller">
<span class="l-inspect">
<div ng-controller="PaneController as modelPaneEdit">
<mct-split-pane class='abs contents split-layout' anchor='bottom'>
<div class="split-pane-component pane top">
<div class="abs holder holder-inspector l-flex-col">
<div class="pane-header flex-elem">Inspection</div>
<ul class="flex-elem grows vscroll">
<li>
<em>Properties</em>
<div class="inspector-properties"
ng-repeat="data in metadata"
ng-class="{ first:$index === 0 }">
<div class="label">{{ data.name }}</div>
<div class="value">{{ data.value }}</div>
</div>
</li>
<li ng-if="contextutalParents.length > 0">
<em title="The location of this linked object.">Location</em>
<span class="inspector-location"
ng-repeat="parent in contextutalParents"
ng-class="{ last:($index + 1) === contextualParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-model="ngModel"
ng-click="ngModel.selectedObject = parent"
class="location-item">
</mct-representation>
</span>
</li>
<li ng-if="primaryParents.length > 0">
<em title="The location of the original object that this was linked from.">Original Location</em>
<span class="inspector-location"
ng-repeat="parent in primaryParents"
ng-class="{ last:($index + 1) === primaryParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-model="ngModel"
ng-click="ngModel.selectedObject = parent"
class="location-item">
</mct-representation>
</span>
</li>
</ul>
<mct-representation
key="'inspector-region'"
mct-object="domainObject"
ng-model="ngModel"
class="flex-elem grows vscroll l-flex-col">
</mct-representation>
</div><!--/ holder-inspector -->
</div><!--/ split-pane-component -->
<mct-splitter class="splitter-inspect-panel mobile-hide"></mct-splitter>
<div class="split-pane-component pane bottom">
<div class="abs holder holder-elements l-flex-col">
<em class="flex-elem">Elements</em>
<em class="flex-elem t-inspector-part-header">Elements</em>
<mct-representation
key="'edit-elements'"
mct-object="domainObject"

View File

@@ -43,7 +43,7 @@ define(
function TimeRangeController($scope, formatService, defaultFormat, now) {
var tickCount = 2,
innerMinimumSpan = 1000, // 1 second
outerMinimumSpan = 1000 * 60 * 60, // 1 hour
outerMinimumSpan = 1000, // 1 second
initialDragValue,
formatter = formatService.getFormat(defaultFormat);
@@ -185,13 +185,6 @@ define(
function updateOuterStart(t) {
var ngModel = $scope.ngModel;
ngModel.outer.start = t;
ngModel.outer.end = Math.max(
ngModel.outer.start + outerMinimumSpan,
ngModel.outer.end
);
ngModel.inner.start =
Math.max(ngModel.outer.start, ngModel.inner.start);
ngModel.inner.end = Math.max(
@@ -207,13 +200,6 @@ define(
function updateOuterEnd(t) {
var ngModel = $scope.ngModel;
ngModel.outer.end = t;
ngModel.outer.start = Math.min(
ngModel.outer.end - outerMinimumSpan,
ngModel.outer.start
);
ngModel.inner.end =
Math.min(ngModel.outer.end, ngModel.inner.end);
ngModel.inner.start = Math.min(
@@ -233,11 +219,20 @@ define(
}
function updateBoundsFromForm() {
$scope.ngModel = $scope.ngModel || {};
$scope.ngModel.outer = {
start: $scope.formModel.start,
end: $scope.formModel.end
};
var start = $scope.formModel.start,
end = $scope.formModel.end;
if (end >= start + outerMinimumSpan) {
$scope.ngModel = $scope.ngModel || {};
$scope.ngModel.outer = { start: start, end: end };
}
}
function validateStart(startValue) {
return startValue <= $scope.formModel.end - outerMinimumSpan;
}
function validateEnd(endValue) {
return endValue >= $scope.formModel.start + outerMinimumSpan;
}
$scope.startLeftDrag = startLeftDrag;
@@ -249,6 +244,9 @@ define(
$scope.updateBoundsFromForm = updateBoundsFromForm;
$scope.validateStart = validateStart;
$scope.validateEnd = validateEnd;
$scope.ticks = [];
// Initialize scope to defaults

View File

@@ -0,0 +1,44 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(function () {
'use strict';
/**
* Implements the `reverse` filter, which reverses text strings.
* Useful in cases where text should be reversed for presentational
* reasons (e.g. in conjunction with CSS tricks involing text direction),
* allowing such behavior to be handled independently from the controller
* layer.
*
* @constructor
* @memberof platform/commonUI/general
*/
function ReverseFilter() {
return function reverse(value) {
return value && value.toString().split('').reverse().join('');
};
}
return ReverseFilter;
});

View File

@@ -91,6 +91,24 @@ define(
.toHaveBeenCalledWith("ngModel", jasmine.any(Function));
});
it("exposes start time validator", function () {
var testValue = 42000000;
mockScope.formModel = { end: testValue };
expect(mockScope.validateStart(testValue + 1))
.toBe(false);
expect(mockScope.validateStart(testValue - 60 * 60 * 1000 - 1))
.toBe(true);
});
it("exposes end time validator", function () {
var testValue = 42000000;
mockScope.formModel = { start: testValue };
expect(mockScope.validateEnd(testValue - 1))
.toBe(false);
expect(mockScope.validateEnd(testValue + 60 * 60 * 1000 + 1))
.toBe(true);
});
describe("when changes are made via form entry", function () {
beforeEach(function () {
mockScope.ngModel = {
@@ -194,26 +212,6 @@ define(
fireWatchCollection("ngModel", mockScope.ngModel);
});
it("enforces a minimum outer span", function () {
mockScope.ngModel.outer.end =
mockScope.ngModel.outer.start - DAY * 100;
fireWatch(
"ngModel.outer.end",
mockScope.ngModel.outer.end
);
expect(mockScope.ngModel.outer.end)
.toBeGreaterThan(mockScope.ngModel.outer.start);
mockScope.ngModel.outer.start =
mockScope.ngModel.outer.end + DAY * 100;
fireWatch(
"ngModel.outer.start",
mockScope.ngModel.outer.start
);
expect(mockScope.ngModel.outer.end)
.toBeGreaterThan(mockScope.ngModel.outer.start);
});
it("enforces a minimum inner span when outer span changes", function () {
mockScope.ngModel.outer.end =
mockScope.ngModel.outer.start - DAY * 100;

View File

@@ -0,0 +1,45 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
['../../src/filters/ReverseFilter'],
function (ReverseFilter) {
'use strict';
describe("The reverse filter", function () {
var reverse;
beforeEach(function () {
reverse = new ReverseFilter();
});
it("reverses text", function () {
expect(reverse('foo')).toEqual('oof');
});
it("returns undefined for undefined inputs", function () {
expect(reverse(undefined)).toBeUndefined();
});
});
}
);

View File

@@ -20,6 +20,7 @@
"directives/MCTScroll",
"directives/MCTSplitPane",
"directives/MCTSplitter",
"filters/ReverseFilter",
"services/Popup",
"services/PopupService",
"services/UrlService",

View File

@@ -1,5 +0,0 @@
[
"gestures/InfoGesture",
"gestures/InfoButtonGesture",
"services/InfoService"
]

View File

@@ -1,6 +0,0 @@
[
"AgentService",
"DeviceClassifier",
"DeviceMatchers",
"MCTDevice"
]

View File

@@ -1,4 +0,0 @@
[
"NotificationService",
"NotificationIndicatorController"
]

View File

@@ -0,0 +1,55 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define([
'./src/RegionController',
'./src/EditableRegionPolicy',
'legacyRegistry'
], function (
RegionController,
EditableRegionPolicy,
legacyRegistry
) {
"use strict";
legacyRegistry.register("platform/commonUI/regions", {
"extensions": {
"controllers": [
{
"key": "RegionController",
"implementation": RegionController,
"depends": [
"$scope",
"policyService"
]
}
],
"policies": [
{
"category": "region",
"implementation": EditableRegionPolicy
}
]
}
});
});

View File

@@ -0,0 +1,57 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
[],
function () {
"use strict";
/**
* A policy for determining whether a region part should be visible or
* not, based on its editability and the current state of the domain
* object .
* @constructor
* @implements {Policy}
* @memberof platform/commonUI/regions
*/
function EditableRegionPolicy() {
}
EditableRegionPolicy.prototype.allow = function (regionPart, domainObject) {
if (!regionPart.modes){
return true;
}
if (domainObject.getCapability('status').get('editing')){
//If the domain object is in edit mode, only include a part
// if it is marked editable
return regionPart.modes.indexOf('edit') !== -1;
} else {
//If the domain object is not in edit mode, return any parts
// that are not explicitly marked editable
return regionPart.modes.indexOf('browse') !== -1;
}
};
return EditableRegionPolicy;
}
);

View File

@@ -0,0 +1,96 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,window*/
define(
[],
function () {
"use strict";
/**
* @typeDef {object} PartContents
* @property {string} key If the part is defined as a
* representation, the key corresponding to the representation.
* @memberOf platform/commonUI/regions
*/
/**
* @typeDef {object} RegionPart
* @property {string} name A unique name for this region part
* @property {PartContents} content the details of the region part
* being defined
* @property {Array<string>} [modes] the modes that this region part
* should be included in. Options are 'edit' and 'browse'. By
* default, will be included in both. Inclusion of region parts is
* determined by policies of category 'region'. By default, the
* {EditableRegionPolicy} will be applied.
* @memberOf platform/commonUI/regions
*/
/**
* Defines the interface for a screen region. A screen region is a
* section of the browse an edit screens for an object. Regions are
* declared in object type definitions.
* @memberOf platform/commonUI/regions
* @abstract
* @constructor
*/
function Region() {
this.parts = [];
}
/**
* Adds a part to this region.
* @param {RegionPart} part the part to add
* @param {number} [index] the position to insert the part. By default
* will add to the end
*/
Region.prototype.addPart = function (part, index){
if (index) {
this.parts.splice(index, 0, part);
} else {
this.parts.push(part);
}
};
/**
* Removes a part from this region.
* @param {RegionPart | number | strnig} part The region part to
* remove. If a number, will remove the part at that index. If a
* string, will remove the part with the matching name. If an
* object, will attempt to remove that object from the Region
*/
Region.prototype.removePart = function (part){
if (typeof part === 'number') {
this.parts.splice(part, 1);
} else if (typeof part === 'string'){
this.parts = this.parts.filter(function(thisPart) {
return thisPart.name !== part;
});
} else {
this.parts.splice(this.parts.indexOf(part), 1);
}
};
return Region;
}
);

View File

@@ -0,0 +1,61 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
define(
[],
function () {
"use strict";
/**
* The RegionController adds region data for a domain object's type
* to the scope.
*
* @constructor
*/
function RegionController($scope, policyService) {
var domainObject = $scope.domainObject,
typeCapability = domainObject.getCapability('type');
/**
* Filters region parts to only those allowed by region policies
* @param regions
* @returns {{}}
*/
function filterParts(regions) {
//Dupe so we're not modifying the type definition.
var filteredRegions = {};
Object.keys(regions).forEach(function(regionName) {
filteredRegions[regionName] = Object.create(regions[regionName]);
filteredRegions[regionName].parts = (regions[regionName].parts || []).filter(function(part){
return policyService.allow('region', part, domainObject);
});
});
return filteredRegions;
}
$scope.regions = filterParts(typeCapability.getDefinition().regions);
}
return RegionController;
}
);

View File

@@ -0,0 +1,75 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,it,expect,beforeEach,waitsFor,jasmine */
define(
['../src/EditableRegionPolicy'],
function (EditableRegionPolicy) {
"use strict";
describe("The editable region policy ", function () {
var editableRegionPolicy,
mockDomainObject,
mockStatusCapability,
mockBrowseRegionPart = {
modes: 'browse'
},
mockEditRegionPart = {
modes: 'edit'
},
mockAllModesRegionPart = {};
beforeEach(function(){
editableRegionPolicy = new EditableRegionPolicy();
mockStatusCapability = jasmine.createSpyObj("statusCapability", [
"get"
]);
mockDomainObject = jasmine.createSpyObj("domainObject", [
"getCapability"
]);
mockDomainObject.getCapability.andReturn(mockStatusCapability);
});
it("includes only browse region parts for object not in edit mode", function() {
mockStatusCapability.get.andReturn(false);
expect(editableRegionPolicy.allow(mockBrowseRegionPart, mockDomainObject)).toBe(true);
expect(editableRegionPolicy.allow(mockEditRegionPart, mockDomainObject)).toBe(false);
});
it("includes only edit region parts for object in edit mode", function() {
mockStatusCapability.get.andReturn(true);
expect(editableRegionPolicy.allow(mockBrowseRegionPart, mockDomainObject)).toBe(false);
expect(editableRegionPolicy.allow(mockEditRegionPart, mockDomainObject)).toBe(true);
});
it("includes region parts with no mode specification", function() {
mockStatusCapability.get.andReturn(false);
expect(editableRegionPolicy.allow(mockAllModesRegionPart, mockDomainObject)).toBe(true);
mockStatusCapability.get.andReturn(true);
expect(editableRegionPolicy.allow(mockAllModesRegionPart, mockDomainObject)).toBe(true);
});
});
}
);

View File

@@ -0,0 +1,82 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,it,expect,beforeEach,waitsFor,jasmine */
define(
['../src/RegionController'],
function (RegionController) {
"use strict";
describe("The region controller ", function () {
var mockScope,
mockDomainObject,
mockTypeCapability,
mockTypeDefinition,
mockPolicyService,
controller;
beforeEach(function(){
mockTypeDefinition = {
regions:
{
'regionOne': {
'parts': [
{'name': 'Part One'},
{'name': 'Part Two'}
]
}
}
};
mockTypeCapability = jasmine.createSpyObj('typeCapability', [
'getDefinition'
]);
mockTypeCapability.getDefinition.andReturn(mockTypeDefinition);
mockDomainObject = jasmine.createSpyObj('domainObject', [
'getCapability'
]);
mockDomainObject.getCapability.andReturn(mockTypeCapability);
mockPolicyService = jasmine.createSpyObj('policyService', [
'allow'
]);
mockScope = {
domainObject: mockDomainObject
};
});
it("filters out regions disallowed by region policy", function() {
mockPolicyService.allow.andReturn(false);
controller = new RegionController(mockScope, mockPolicyService);
expect(mockScope.regions.regionOne.parts.length).toBe(0);
});
it("does not filter out regions allowed by region policy", function() {
mockPolicyService.allow.andReturn(true);
controller = new RegionController(mockScope, mockPolicyService);
expect(mockScope.regions.regionOne.parts.length).toBe(2);
});
});
}
);

View File

@@ -0,0 +1,107 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,it,expect,beforeEach,waitsFor,jasmine */
define(
['../src/Region'],
function (Region) {
"use strict";
describe("The region class ", function () {
var region,
part2 = {'name': 'part2'};
beforeEach(function(){
region = new Region();
region.parts = [
{name: 'part1'},
{name: 'part3'},
{name: 'part4'}
];
});
it("adding a region part at a specified index adds it in that" +
" position", function() {
region.addPart(part2, 1);
expect(region.parts.length).toBe(4);
expect(region.parts[1]).toBe(part2);
});
it("adding a region part without an index adds it at the end", function() {
var partN = {'name': 'partN'};
region.addPart(partN);
expect(region.parts.length).toBe(4);
expect(region.parts[region.parts.length-1]).toBe(partN);
});
describe("removing a region part", function(){
var partName = "part2";
beforeEach(function(){
region.parts = [
{name: 'part1'},
part2,
{name: 'part3'},
{name: 'part4'}
];
});
it("with a string matches on region part" +
" name", function() {
expect(region.parts.length).toBe(4);
expect(region.parts.indexOf(part2)).toBe(1);
region.removePart(partName);
expect(region.parts.length).toBe(3);
expect(region.parts.indexOf(part2)).toBe(-1);
});
it("with a number removes by index", function() {
expect(region.parts.length).toBe(4);
expect(region.parts.indexOf(part2)).toBe(1);
region.removePart(1);
expect(region.parts.length).toBe(3);
expect(region.parts.indexOf(part2)).toBe(-1);
});
it("with object matches that object", function() {
expect(region.parts.length).toBe(4);
expect(region.parts.indexOf(part2)).toBe(1);
region.removePart(part2);
expect(region.parts.length).toBe(3);
expect(region.parts.indexOf(part2)).toBe(-1);
});
});
});
}
);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
[
"CapabilityTable",
"ComposeActionPolicy",
"CompositionModelPolicy",
"CompositionMutabilityPolicy",
"CompositionPolicy",
"ContainmentTable"
]

View File

@@ -1,46 +0,0 @@
[
"actions/ActionAggregator",
"actions/ActionCapability",
"actions/ActionProvider",
"actions/LoggingActionDecorator",
"capabilities/CompositionCapability",
"capabilities/ContextCapability",
"capabilities/ContextualDomainObject",
"capabilities/CoreCapabilityProvider",
"capabilities/DelegationCapability",
"capabilities/InstantiationCapability",
"capabilities/MetadataCapability",
"capabilities/MutationCapability",
"capabilities/PersistenceCapability",
"capabilities/RelationshipCapability",
"identifiers/Identifier",
"identifiers/IdentifierProvider",
"models/ModelAggregator",
"models/MissingModelDecorator",
"models/PersistedModelProvider",
"models/RootModelProvider",
"models/StaticModelProvider",
"models/CachingModelDecorator",
"objects/DomainObject",
"objects/DomainObjectProvider",
"services/Contextualize",
"services/Instantiate",
"services/Now",
"services/Throttle",
"services/Topic",
"types/MergeModels",
"types/TypeCapability",
"types/TypeImpl",
"types/TypeProperty",
"types/TypePropertyConversion",
"types/TypeProvider",
"views/ViewCapability",
"views/ViewProvider"
]

View File

@@ -101,9 +101,8 @@ define(
* Will add a list of clones to the specified parent's composition
*/
function addClonesToParent(self) {
return self.firstClone.getCapability("persistence").persist()
.then(function(){self.parent.getCapability("composition").add(self.firstClone.getId());})
.then(function(){return self.parent.getCapability("persistence").persist();})
self.parent.getCapability("composition").add(self.firstClone.getId());
return self.parent.getCapability("persistence").persist()
.then(function(){return self.firstClone;});
}

View File

@@ -1,17 +0,0 @@
[
"actions/AbstractComposeAction",
"actions/CopyAction",
"actions/GoToOriginalAction",
"actions/LinkAction",
"actions/MoveAction",
"actions/SetPrimaryLocationAction",
"policies/CrossSpacePolicy",
"services/CopyService",
"services/CopyTask",
"services/LinkService",
"services/MoveService",
"services/LocationService",
"services/LocatingCreationDecorator",
"services/LocatingObjectDecorator",
"capabilities/LocationCapability"
]

View File

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

View File

@@ -1,11 +0,0 @@
[
"actions/AbstractStartTimerAction",
"actions/RestartTimerAction",
"actions/StartTimerAction",
"controllers/ClockController",
"controllers/RefreshingController",
"controllers/TimerController",
"controllers/TimerFormatter",
"indicators/ClockIndicator",
"services/TickerService"
]

View File

@@ -1,6 +0,0 @@
[
"ConductorRepresenter",
"ConductorService",
"ConductorTelemetryDecorator",
"TimeConductor"
]

View File

@@ -1,7 +0,0 @@
[
"DomainColumn",
"EventListController",
"EventListPopulator",
"policies/MessagesViewPolicy",
"RangeColumn"
]

View File

@@ -1,5 +0,0 @@
[
"controllers/ImageryController",
"directives/MCTBackgroundImage",
"policies/ImageryViewPolicy"
]

View File

@@ -1,17 +0,0 @@
[
"FixedController",
"FixedDragHandle",
"FixedProxy",
"LayoutCompositionPolicy",
"LayoutController",
"LayoutDrag",
"elements/AccessorMutator",
"elements/BoxProxy",
"elements/ElementFactory",
"elements/ElementProxies",
"elements/ElementProxy",
"elements/LineProxy",
"elements/ResizeHandle",
"elements/TelemetryProxy",
"elements/TextProxy"
]

View File

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

View File

@@ -25,11 +25,13 @@ define([
"./src/MCTChart",
"./src/PlotController",
"./src/policies/PlotViewPolicy",
"./src/PlotOptionsController",
'legacyRegistry'
], function (
MCTChart,
PlotController,
PlotViewPolicy,
PlotOptionsController,
legacyRegistry
) {
"use strict";
@@ -71,6 +73,14 @@ define([
"throttle",
"PLOT_FIXED_DURATION"
]
},
{
"key": "PlotOptionsController",
"implementation": PlotOptionsController,
"depends": [
"$scope",
"topic"
]
}
],
"constants": [
@@ -86,6 +96,12 @@ define([
"category": "view",
"implementation": PlotViewPolicy
}
],
"representations": [
{
"key": "plot-options-browse",
"templateUrl": "templates/plot-options-browse.html"
}
]
}
});

View File

@@ -0,0 +1,76 @@
<!--
Open MCT Web, Copyright (c) 2014-2015, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT Web is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT Web includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<style>
.l-inspect .l-inspector-part .no-margin .form {
margin-left: 0;
}
.reduced-min-width .form .form-row > .label {
min-width: 80px;
}
</style>
<div ng-controller="PlotOptionsController" class="flex-elem grows l-inspector-part">
<em class="t-inspector-part-header" title="Display properties for this object">Display</em>
<mct-form
ng-model="configuration.plot.xAxis"
structure="xAxisForm"
name="xAxisFormState"
class="flex-elem l-flex-row no-validate no-margin reduced-min-width">
</mct-form>
<mct-form
ng-model="configuration.plot.yAxis"
structure="yAxisForm"
name="yAxisFormState"
class="flex-elem l-flex-row no-validate no-margin reduced-min-width">
</mct-form>
<div class="section-header ng-binding ng-scope">
Plot Series
</div>
<ul class="first flex-elem grows vscroll">
<ul class="tree">
<li ng-repeat="child in children">
<span ng-controller="ToggleController as toggle">
<span ng-controller="TreeNodeController as treeNode">
<span class="tree-item menus-to-left">
<span
class='ui-symbol view-control flex-elem has-children'
ng-class="{ expanded: toggle.isActive() }"
ng-click="toggle.toggle(); treeNode.trackExpansion()">
</span>
<mct-representation
class="rep-object-label"
key="'label'"
mct-object="child">
</mct-representation>
</span>
</span>
<mct-form
ng-class="{hidden: !toggle.isActive()}"
ng-model="configuration.plot.series[child.getId()]"
structure="plotSeriesForm"
name="plotOptionsState"
class="flex-elem l-flex-row l-controls-first no-validate">
</mct-form>
</span>
</li>
</ul>
</ul>
</div>

View File

@@ -47,7 +47,7 @@
<div ng-repeat="tick in subplot.getRangeTicks()"
class="gl-plot-tick gl-plot-y-tick-label"
ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%' }">
{{tick.label}}
{{tick.label | reverse}}
</div>
<div class="gl-plot-y-options gl-plot-local-controls"
ng-if="axes[1].options.length > 1">
@@ -61,7 +61,8 @@
</div>
<div class="gl-plot-display-area"
ng-mouseenter="subplot.isHovering(true);"
ng-mouseleave="subplot.isHovering(false)">
ng-mouseleave="subplot.isHovering(false)"
ng-class="{ loading: plot.isRequestPending() }">
<!-- Out-of-bounds data indicators -->
<!-- ng-show is temporarily hard-coded in next element -->
<div ng-show="false" class="l-oob-data l-oob-data-up"></div>
@@ -118,15 +119,13 @@
</div>
</div>
</div>
<span class="t-wait-spinner loading" ng-show="plot.isRequestPending()">
</span>
</div>
<div ng-if="$last" class="gl-plot-axis-area gl-plot-x">
<div ng-repeat="tick in subplot.getDomainTicks()"
class="gl-plot-tick gl-plot-x-tick-label"
ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)"
ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%' }">
{{tick.label}}
{{tick.label | reverse}}
</div>
<div class="gl-plot-label gl-plot-x-label">
{{axes[0].active.name}}

View File

@@ -0,0 +1,145 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
['./PlotOptionsForm'],
function (PlotOptionsForm) {
"use strict";
/**
* Notes on implementation of plot options
*
* Multiple y-axes will have to be handled with multiple forms as
* they will need to be stored on distinct model object
*
* Likewise plot series options per-child will need to be separate
* forms.
*/
/**
* The LayoutController is responsible for supporting the
* Layout view. It arranges frames according to saved configuration
* and provides methods for updating these based on mouse
* movement.
* @memberof platform/features/plot
* @constructor
* @param {Scope} $scope the controller's Angular scope
*/
function PlotOptionsController($scope, topic) {
var self = this,
domainObject = $scope.domainObject,
composition,
mutationListener,
formListener,
configuration = domainObject.getModel().configuration || {};
this.plotOptionsForm = new PlotOptionsForm(topic);
/*
* Determine whether the changes to the model that triggered a
* mutation event were purely compositional.
*/
function hasCompositionChanged(oldComposition, newComposition){
// Framed slightly strangely, but the boolean logic is
// easier to follow for the unchanged case.
var isUnchanged = oldComposition === newComposition ||
(
oldComposition.length === newComposition.length &&
oldComposition.every( function (currentValue, index) {
return newComposition[index] && currentValue === newComposition[index];
})
);
return !isUnchanged;
}
/*
Default the plot options model
*/
function defaultConfiguration() {
configuration.plot = configuration.plot || {};
configuration.plot.xAxis = configuration.plot.xAxis || {};
configuration.plot.yAxis = configuration.plot.yAxis || {}; // y-axes will be associative array keyed on axis key
configuration.plot.series = configuration.plot.series || {}; // series will be associative array keyed on sub-object id
$scope.configuration = configuration;
}
/*
When a child is added to, or removed from a plot, update the
plot options model
*/
function updateChildren() {
domainObject.useCapability('composition').then(function(children){
$scope.children = children;
composition = domainObject.getModel().composition;
children.forEach(function(child){
configuration.plot.series[child.getId()] = configuration.plot.series[child.getId()] || {};
});
});
}
/*
On changes to the form, update the configuration on the domain
object
*/
function updateConfiguration() {
domainObject.useCapability('mutation', function(model){
model.configuration = model.configuration || {};
model.configuration.plot = configuration.plot;
});
}
/*
Set form structures on scope
*/
$scope.plotSeriesForm = this.plotOptionsForm.plotSeriesForm;
$scope.xAxisForm = this.plotOptionsForm.xAxisForm;
$scope.yAxisForm = this.plotOptionsForm.yAxisForm;
/*
Listen for changes to the domain object and update the object's
children.
*/
mutationListener = domainObject.getCapability('mutation').listen(function(model) {
if (hasCompositionChanged(composition, model.composition)) {
updateChildren();
}
});
formListener = this.plotOptionsForm.listen(updateConfiguration);
defaultConfiguration();
updateChildren();
$scope.$on("$destroy", function() {
//Clean up any listeners on destruction of controller
mutationListener();
formListener();
});
}
return PlotOptionsController;
}
);

View File

@@ -0,0 +1,166 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
[],
function () {
"use strict";
/**
* A class for encapsulating structure and behaviour of the plot
* options form
* @memberOf platform/features/plot
* @param topic
* @constructor
*/
function PlotOptionsForm(topic) {
var self = this;
this.onchangeTopic = topic();
function onchange(value){
self.onchangeTopic.notify(value);
}
/*
Defined below are the form structures for the plot options.
*/
this.xAxisForm = {
'name':'x-axis',
'sections': [{
'name': 'x-axis',
'rows': [
{
'name': 'Domain',
'control': 'select',
'key': 'key',
'onchange': onchange,
'options': [
{'name':'scet', 'value': 'scet'},
{'name':'sclk', 'value': 'sclk'},
{'name':'lst', 'value': 'lst'}
]
}
]
}]};
this.yAxisForm = {
'name':'y-axis',
'sections': [{
// Will need to be repeated for each y-axis, with a
// distinct name for each. Ideally the name of the axis
// itself.
'name': 'y-axis',
'rows': [
{
'name': 'Autoscale',
'control': 'checkbox',
'key': 'autoscale',
'onchange': onchange
},
{
'name': 'Min',
'control': 'textfield',
'key': 'min',
'pattern': '[0-9]',
'onchange': onchange
},
{
'name': 'Max',
'control': 'textfield',
'key': 'max',
'pattern': '[0-9]',
'onchange': onchange
},
{
'name': 'Range',
'control': 'select',
'key': 'key',
'onchange': onchange,
'options': [
{'name':'eu', 'value': 'eu'},
{'name':'dn', 'value': 'dn'},
{'name':'status', 'value': 'status'}
]
}
]
}]
};
this.plotSeriesForm = {
'name':'Series Options',
'sections': [
{
rows: [
{
'name': 'Color',
'control': 'color',
'key': 'color',
'onchange': onchange
}]
},
{
'rows':[
{
'name': 'Markers',
'control': 'checkbox',
'key': 'markers',
'onchange': onchange
}
]
},
{
'rows':[
{
'name': 'No Line',
'control': 'radio',
'key': 'lineType',
'value': 'noLine',
'onchange': onchange
},
{
'name': 'Step Line',
'control': 'radio',
'key': 'lineType',
'value': 'stepLine',
'onchange': onchange
},
{
'name': 'Linear Line',
'control': 'radio',
'key': 'lineType',
'value': 'linearLine',
'onchange': onchange
}
]
}
]
};
}
PlotOptionsForm.prototype.listen = function (callback){
return this.onchangeTopic.listen(callback);
};
return PlotOptionsForm;
}
);

View File

@@ -0,0 +1,161 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,it,expect,beforeEach,jasmine,xit*/
define(
['../src/PlotOptionsController'],
function (PlotOptionsController) {
"use strict";
describe("The Plot Options controller", function () {
var plotOptionsController,
mockTopicFunction,
mockTopicObject,
mockDomainObject,
mockMutationCapability,
mockUseCapabilities,
mockCompositionCapability,
mockComposition,
mockUnlisten,
mockFormUnlisten,
mockChildOne,
mockChildTwo,
model,
mockScope;
beforeEach(function () {
model = {
composition: ['childOne']
};
mockChildOne = jasmine.createSpyObj('domainObject', [
'getId'
]);
mockChildOne.getId.andReturn('childOne');
mockChildTwo = jasmine.createSpyObj('childTwo', [
'getId'
]);
mockChildOne.getId.andReturn('childTwo');
mockCompositionCapability = jasmine.createSpyObj('compositionCapability', [
'then'
]);
mockComposition = [
mockChildOne
];
mockCompositionCapability.then.andCallFake(function (callback){
callback(mockComposition);
});
mockUseCapabilities = jasmine.createSpyObj('useCapabilities', [
'composition',
'mutation'
]);
mockUseCapabilities.composition.andReturn(mockCompositionCapability);
mockMutationCapability = jasmine.createSpyObj('mutationCapability', [
'listen'
]);
mockUnlisten = jasmine.createSpy('unlisten');
mockMutationCapability.listen.andReturn(mockUnlisten);
mockTopicObject = jasmine.createSpyObj('Topic', [
'listen',
'notify'
]);
mockFormUnlisten = jasmine.createSpy('formUnlisten');
mockTopicObject.listen.andReturn(mockFormUnlisten);
mockTopicFunction = function() {
return mockTopicObject;
};
mockDomainObject = jasmine.createSpyObj('domainObject', [
'getModel',
'useCapability',
'getCapability'
]);
mockDomainObject.useCapability.andCallFake(function(capability){
return mockUseCapabilities[capability]();
});
mockDomainObject.getCapability.andReturn(mockMutationCapability);
mockDomainObject.getModel.andReturn(model);
mockScope = jasmine.createSpyObj('scope', [
'$on'
]);
mockScope.domainObject = mockDomainObject;
plotOptionsController = new PlotOptionsController(mockScope, mockTopicFunction);
});
it("sets form definitions on scope", function () {
expect(mockScope.xAxisForm).toBeDefined();
expect(mockScope.yAxisForm).toBeDefined();
expect(mockScope.plotSeriesForm).toBeDefined();
});
it("sets object children on scope", function () {
expect(mockScope.children).toBe(mockComposition);
});
it("on changes in object composition, updates the form", function () {
expect(mockMutationCapability.listen).toHaveBeenCalled();
expect(mockScope.children).toBe(mockComposition);
expect(mockScope.children.length).toBe(1);
mockComposition.push(mockChildTwo);
model.composition.push('childTwo');
mockMutationCapability.listen.mostRecentCall.args[0](model);
expect(mockScope.children).toBe(mockComposition);
expect(mockScope.children.length).toBe(2);
});
it("on changes in form values, updates the object model", function () {
var scopeConfiguration = mockScope.configuration,
model = mockDomainObject.getModel();
scopeConfiguration.plot.xAxis.key = 'lst';
scopeConfiguration.plot.yAxis.autoScale = true;
scopeConfiguration.plot.yAxis.key = 'eu';
expect(mockTopicObject.listen).toHaveBeenCalled();
mockTopicObject.listen.mostRecentCall.args[0]();
expect(mockDomainObject.useCapability).toHaveBeenCalledWith('mutation', jasmine.any(Function));
mockDomainObject.useCapability.mostRecentCall.args[1](model);
expect(model.configuration.plot.xAxis.key).toBe('lst');
expect(model.configuration.plot.yAxis.autoScale).toBe(true);
expect(model.configuration.plot.yAxis.key).toBe('eu');
});
it("cleans up listeners on destruction of the controller", function () {
mockScope.$on.mostRecentCall.args[1]();
expect(mockUnlisten).toHaveBeenCalled();
expect(mockFormUnlisten).toHaveBeenCalled();
});
});
}
);

View File

@@ -0,0 +1,73 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,it,expect,beforeEach,jasmine,xit*/
define(
['../src/PlotOptionsForm'],
function (PlotOptionsForm) {
"use strict";
describe("The Plot Options form", function () {
var plotOptionsForm,
mockTopicFunction,
mockTopicObject,
listener;
beforeEach(function () {
mockTopicObject = jasmine.createSpyObj('Topic', [
'listen',
'notify'
]);
mockTopicFunction = function() {
return mockTopicObject;
};
plotOptionsForm = new PlotOptionsForm(mockTopicFunction);
});
it("defines form specs for x-axis, y-axis, and series data", function () {
expect(plotOptionsForm.xAxisForm).toBeDefined();
expect(plotOptionsForm.xAxisForm.sections).toBeDefined();
expect(plotOptionsForm.xAxisForm.sections[0].rows).toBeDefined();
expect(plotOptionsForm.xAxisForm.sections[0].rows.length).toBeGreaterThan(0);
expect(plotOptionsForm.yAxisForm).toBeDefined();
expect(plotOptionsForm.plotSeriesForm).toBeDefined();
});
it("uses a topic to register listeners and inform them when a" +
" form value changes", function () {
var changedValue = 'changedValue';
expect(plotOptionsForm.xAxisForm.sections[0].rows[0].onchange).toBeDefined();
plotOptionsForm.listen(listener);
expect(mockTopicObject.listen).toHaveBeenCalledWith(listener);
plotOptionsForm.xAxisForm.sections[0].rows[0].onchange(changedValue);
expect(mockTopicObject.notify).toHaveBeenCalledWith(changedValue);
});
});
}
);

View File

@@ -1,26 +0,0 @@
[
"Canvas2DChart",
"GLChart",
"MCTChart",
"PlotController",
"SubPlot",
"SubPlotFactory",
"elements/PlotAxis",
"elements/PlotLimitTracker",
"elements/PlotLine",
"elements/PlotLineBuffer",
"elements/PlotPalette",
"elements/PlotPanZoomStack",
"elements/PlotPanZoomStackGroup",
"elements/PlotPosition",
"elements/PlotPreparer",
"elements/PlotSeriesWindow",
"elements/PlotTelemetryFormatter",
"elements/PlotTickGenerator",
"elements/PlotUpdater",
"modes/PlotModeOptions",
"modes/PlotOverlayMode",
"modes/PlotStackMode",
"policies/PlotViewPolicy"
]

View File

@@ -1,6 +0,0 @@
[
"DomainColumn",
"policies/RTMessagesViewPolicy",
"RangeColumn",
"RTEventListController"
]

View File

@@ -1,7 +0,0 @@
[
"DomainColumn",
"NameColumn",
"RangeColumn",
"ScrollingListController",
"ScrollingListPopulator"
]

View File

@@ -1,50 +0,0 @@
[
"TimelineConstants",
"TimelineFormatter",
"capabilities/ActivityTimespan",
"capabilities/ActivityTimespanCapability",
"capabilities/ActivityUtilization",
"capabilities/CostCapability",
"capabilities/GraphCapability",
"capabilities/CumulativeGraph",
"capabilities/ResourceGraph",
"capabilities/TimelineTimespan",
"capabilities/TimelineTimespanCapability",
"capabilities/TimelineUtilization",
"capabilities/UtilizationCapability",
"controllers/ActivityModeValuesController",
"controllers/TimelineController",
"controllers/TimelineGanttController",
"controllers/TimelineGraphController",
"controllers/TimelineTableController",
"controllers/TimelineTickController",
"controllers/TimelineZoomController",
"controllers/TimelineDateTimeController",
"controllers/drag/TimelineDragHandler",
"controllers/drag/TimelineDragHandleFactory",
"controllers/drag/TimelineDragPopulator",
"controllers/drag/TimelineSnapHandler",
"controllers/drag/TimelineStartHandle",
"controllers/drag/TimelineMoveHandle",
"controllers/drag/TimelineEndHandle",
"controllers/graph/TimelineGraph",
"controllers/graph/TimelineGraphPopulator",
"controllers/graph/TimelineGraphRenderer",
"controllers/swimlane/TimelineColorAssigner",
"controllers/swimlane/TimelineProxy",
"controllers/swimlane/TimelineSwimlane",
"controllers/swimlane/TimelineSwimlaneDecorator",
"controllers/swimlane/TimelineSwimlaneDropHandler",
"controllers/swimlane/TimelineSwimlanePopulator",
"directives/SwimlaneDragConstants",
"directives/MCTSwimlaneDrag",
"directives/MCTSwimlaneDrop",
"services/ObjectLoader"
]

View File

@@ -68,6 +68,10 @@ define([
"key": "checkbox",
"templateUrl": "templates/controls/checkbox.html"
},
{
"key": "radio",
"templateUrl": "templates/controls/radio.html"
},
{
"key": "datetime",
"templateUrl": "templates/controls/datetime.html"

View File

@@ -23,6 +23,7 @@
<input type="checkbox"
name="mctControl"
ng-model="ngModel[field]"
ng-change="structure.onchange(ngModel[field])"
ng-disabled="ngDisabled">
<em></em>
</label>

View File

@@ -0,0 +1,30 @@
<!--
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.
-->
<label class="radio custom no-text">
<input type="radio"
name="mctControl"
ng-model="ngModel[field]"
ng-disabled="ngDisabled"
ng-change="structure.onchange(ngModel[field])"
ng-value="structure.value">
<em></em>
</label>

View File

@@ -24,6 +24,7 @@
ng-model="ngModel[field]"
ng-options="opt.value as opt.name for opt in options"
ng-required="ngRequired"
ng-change="structure.onchange(ngModel[field])"
name="mctControl">
<option value="" ng-show="!ngModel[field]">- Select One -</option>
</select>

View File

@@ -25,6 +25,7 @@
ng-required="ngRequired"
ng-model="ngModel[field]"
ng-pattern="ngPattern"
ng-change="structure.onchange(ngModel[field])"
size="{{structure.size}}"
name="mctControl">
</span>

View File

@@ -19,35 +19,29 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<form name="mctForm" novalidate>
<div class="form">
<form name="mctForm" novalidate class="form">
<span ng-repeat="section in structure.sections">
<div class="section-header" ng-if="section.name">
{{section.name}}
</div>
<div class="form-section">
<div class="form-section" ng-class="{ first:$index < 1 }">
<ng-form name="mctFormInner" ng-repeat="row in section.rows">
<div class="form-row validates"
<div class="form-row validates l-flex-row"
ng-class="{
req: row.required,
valid: mctFormInner.$dirty && mctFormInner.$valid,
invalid: mctFormInner.$dirty && !mctFormInner.$valid,
first: $index < 1
}">
<div class='label' title="{{row.description}}">
<div class='label flex-elem' title="{{row.description}}">
{{row.name}}
<span ng-if="row.description"
class="ui-symbol">
i
</span>
</div>
<div class='controls'>
<div class='controls flex-elem'>
<div class="wrapper" ng-if="row.control">
<mct-control key="row.control"
ng-model="ngModel"
ng-required="row.required"
ng-change="row.onchange"
ng-pattern="getRegExp(row.pattern)"
options="row.options"
structure="row"
@@ -59,6 +53,4 @@
</ng-form>
</div>
</span>
</div>
</form>

View File

@@ -1,9 +0,0 @@
[
"MCTControl",
"MCTForm",
"controllers/ColorController",
"controllers/CompositeController",
"controllers/DateTimeController",
"controllers/DialogButtonController",
"controllers/FormController"
]

View File

@@ -221,6 +221,13 @@ define(
CustomRegistrars.prototype.services =
mapUpon(customRegistrar("service"));
/**
* Register Angular filters.
* @param {Array} extensions the resolved extensions
*/
CustomRegistrars.prototype.filters =
mapUpon(customRegistrar("filter"));
/**
* Register functions which will run after bootstrapping.
* @param {Array} extensions the resolved extensions

View File

@@ -1,17 +0,0 @@
[
"FrameworkInitializer",
"LogLevel",
"bootstrap/ApplicationBootstrapper",
"load/Bundle",
"load/BundleLoader",
"load/Extension",
"register/CustomRegistrars",
"register/ExtensionRegistrar",
"register/ExtensionSorter",
"register/PartialConstructor",
"register/ServiceCompositor",
"resolve/BundleResolver",
"resolve/ExtensionResolver",
"resolve/ImplementationLoader",
"resolve/RequireConfigurator"
]

Some files were not shown because too many files have changed in this diff Show More