Compare commits

...

26 Commits

Author SHA1 Message Date
6db1833a45 Merge branch 'topic-core-refactor' into misc-ui-4 2019-01-15 16:42:03 -08:00
6b1e8862ef Tables composition error (#2260)
* Removed debubgging statement

* Change order of mutation events so that composition handlers are working with latest object version.

* Remove suppression of mutation event

* Minor code reformatting
2019-01-15 09:55:22 -08:00
00ce246fc5 Merge pull request #2261 from nasa/object-path-on-drop
Change domain-object event transfer data to domain-object-path
2019-01-15 09:48:32 -08:00
c0c7d96429 Change domain-object event transfer data to domain-object-path 2019-01-14 12:07:31 -08:00
92b2582d0d Preview instead of navigate in edit mode + highlight navigated object (#2252)
* Preview instead of navigate when in edit mode.

* Prevent preview of navigated object

* Removed trailing comma

* Observe navigation from tree items instead of mct-tree

* Cleanup of redundant code

* .is-selected -> .is-navigated-object
2019-01-11 11:21:52 -08:00
4084a1ac86 Drag and drop fixes (#2249)
* Drag-drop edit mode from capture handler. Drag-drop composition from bubble handler. Check composability on drag start

* Show drop hints without being in edit mode.

* Don't serialize objects twice on drag
2019-01-11 11:20:57 -08:00
8b2edaa6fd Toolbar styling, edit colors
- Toolbar now with color bg for better tie-in with edit area visually;
- Edit colors refined for Snow theme, WIP;
2019-01-10 17:35:22 -08:00
8caeed2ce5 Telemetry Table editing styles
- Headers now have hover effects;
2019-01-08 14:42:02 -08:00
03be582b54 List View fixes
- Ellipsizing now works;
- Better icon and text alignment;
2019-01-04 17:56:10 -08:00
1ce84ee56b Styling for selects
- New cleaner styling approach;
- New cSelect and appearanceNone mixins;
- Converted selects in Notebook, plot-options-edit;
2019-01-04 17:06:26 -08:00
cb39ad8500 Merge branch 'topic-core-refactor' into misc-ui-4 2019-01-04 14:39:57 -08:00
cb1a1c2616 R&I Clock timer fixes (#2254)
* Clocks and timers styling WIP

- Markup, new styles;
- Renamed _legacy-plots.scss > _legacy;
- New $colorBodyFgEm constants - theme files all updated;

* Clocks and timers styling complete

* Styles clean up

- Moved legacy styles out of _global into _legacy.scss;
2018-12-24 14:02:37 -08:00
74be02b6de Various improvements
- Tighten up search inputs;
- Fix icon/label spacing regression in c-button--menu;
- Better icon and text alignment in c-button and related;
2018-12-21 23:50:19 -08:00
ce6c1f173e Lad table vue (#2231)
* working telemetry subs

* Styling for LAD table

- Fixed markup;
- Corrected icon, added description;
- Expand c-table styles slightly, moved some definitions into
c-telemetry-table;

* add LADTableSummary

* change function names

* make reviewer requested changes

* add lad table headers in sets

* make column widths fixed

* handle composition remove in sets and tables

* finish updateTimeSystem

* add correct support for limits

* LAD Table and Table Set styling

- Removed fixed table layout;
- Col widths set to 33% for now;
- New c-lad-table class and styling;
- New __group-header class added;
- All themes updated with __group-header style colors;

* make reviewer requested changes

* use lodash findIndex
2018-12-20 13:18:22 -08:00
30a4888363 R&I Misc UI 3 (#2253)
* Limits-related changes; WIP

- Renamed CSS classes: `s-limit-*` > `is-limit--*`;
- Removed load of legacy _status.scss and added new _status.scss file;
- Minor re-org of limit/status constants in theme files;
- Limit colors in theme constants all updated;

* Fixes for s-selected always displaying the move cursor

- Mod s-selected;
- Reinstitute `.is-moveable` class;

* Layout-related cleanup and refinements

- LineView cleaned up;
- Selection, hover, etc. classes for c-frame cleaned up;
- Constant names normalized, theme files updated;

* Fixes for editing plot options

- Color palette now more flexible;
- Styles for color palette button refined;
- c-input--flex added for more flexible inputs;

* Various swatch-related changes

- Swatch refinements, new .c-click-swatch class;
- Added .c-click-icon--major modifier style, applied in markup;

* Local controls class application and behavior cleanup

- Remmoved .has-local-controls from selected markup;
- Refined CSS selector for better hover behavior;

* Misc UI tweaks

- click-icon--major in Notebook;
- .test mixin improved;

* Update _constants-espresso.scss

* Update _constants-maelstrom.scss
2018-12-20 13:17:44 -08:00
b0917a9866 Pending fixes for Grid and List Folder views (#2247)
* fix view names, and persist sort order across list views by persisting in local storage

* use keystring as key

* add openmct namespace to localstorage persisted listview-sort-order to avoid name collision, rename key in composition-loader to objectKeyString
2018-12-20 13:16:23 -08:00
464e5de947 [Display Layout] Add delete button (#2251)
* Add delete button in the toolbar for removing items

* Mutate composition if there are no telemetry objects. Select the parent layout after deleting an item.

* Saving work

* Watch for index in the components and update it in the context.

* Select the parent after a composition is removed.

* Address reviewer's feedback.
- Rename mutatComposition() to removeFromComposition().
- Inline logic for filtering composition
- Use separate branches for each item type in trackItem().

* Address reviewer's requested changes
2018-12-20 13:15:23 -08:00
47a07da17d Merge pull request #2246 from nasa/conditional-edit-button
Conditional edit button
2018-12-20 09:37:43 -08:00
ec4c443299 Misc ui 2 (#2248)
* Create button disabled when editing
* New disabled mixin;
* Tree styling
* Fixed icons for fullscreen toggle button
* Local controls fixed for Imagery and Plots
* Range control styling updated;
* Plot styling, significant mods
* Disclosure controls improved;
* New _legacy-plots.scss file added, no longer loads legacy plot SCSS
files;
* Removed 12px crosshair cursor in legend hover;
* Inspector tree styling in plot options
* Fix z-indexing related to Overlays
2018-12-18 11:07:09 -08:00
3122168b0e Removed unused legacy code 2018-12-13 17:11:39 -08:00
da3af4b3db Merged from TCR 2018-12-13 15:36:13 -08:00
850fa28bf6 Update component locations 2018-12-13 09:45:50 -08:00
270684c5fd Merge pull request #2244 from nasa/component-reorg
Reorganize components, create ObjectFrame
2018-12-13 09:19:40 -08:00
afa1589cb5 Reorganize components, create ObjectFrame 2018-12-13 09:16:42 -08:00
18a94d938f Notebook Snapshot and Annotate (#2240)
Notebook Snapshots and Annotations from new Browse Bar
2018-12-12 18:57:45 -08:00
d026bc2134 Show edit only if view is editable. Rename editable to canEdit 2018-12-12 17:17:49 -08:00
129 changed files with 2764 additions and 2009 deletions

View File

@ -37,25 +37,25 @@ define([
},
LIMITS = {
rh: {
cssClass: "s-limit-upr s-limit-red",
cssClass: "is-limit--upr is-limit--red",
low: RED,
high: Number.POSITIVE_INFINITY,
name: "Red High"
},
rl: {
cssClass: "s-limit-lwr s-limit-red",
cssClass: "is-limit--lwr is-limit--red",
high: -RED,
low: Number.NEGATIVE_INFINITY,
name: "Red Low"
},
yh: {
cssClass: "s-limit-upr s-limit-yellow",
cssClass: "is-limit--upr is-limit--yellow",
low: YELLOW,
high: RED,
name: "Yellow High"
},
yl: {
cssClass: "s-limit-lwr s-limit-yellow",
cssClass: "is-limit--lwr is-limit--yellow",
low: -RED,
high: -YELLOW,
name: "Yellow Low"

View File

@ -79,6 +79,7 @@
openmct.install(openmct.plugins.FolderView());
openmct.install(openmct.plugins.Tabs());
openmct.install(openmct.plugins.FlexibleLayout());
openmct.install(openmct.plugins.LADTable());
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');
openmct.start();

View File

@ -32,7 +32,6 @@ define([
"./src/actions/SaveAndStopEditingAction",
"./src/actions/SaveAsAction",
"./src/actions/CancelAction",
"./src/policies/EditActionPolicy",
"./src/policies/EditPersistableObjectsPolicy",
"./src/representers/EditRepresenter",
"./src/capabilities/EditorCapability",
@ -64,7 +63,6 @@ define([
SaveAndStopEditingAction,
SaveAsAction,
CancelAction,
EditActionPolicy,
EditPersistableObjectsPolicy,
EditRepresenter,
EditorCapability,
@ -225,10 +223,6 @@ define([
}
],
"policies": [
{
"category": "action",
"implementation": EditActionPolicy
},
{
"category": "action",
"implementation": EditPersistableObjectsPolicy,

View File

@ -1,111 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
[],
function () {
/**
* Policy controlling when the `edit` and/or `properties` actions
* can appear as applicable actions of the `view-control` category
* (shown as buttons in the top-right of browse mode.)
* @memberof platform/commonUI/edit
* @constructor
* @implements {Policy.<Action, ActionContext>}
*/
function EditActionPolicy(policyService) {
this.policyService = policyService;
}
/**
* Get a count of views which are not flagged as non-editable.
* @private
*/
EditActionPolicy.prototype.countEditableViews = function (context) {
var domainObject = context.domainObject,
count = 0,
type, views;
if (!domainObject) {
return count;
}
type = domainObject.getCapability('type');
views = domainObject.useCapability('view');
// A view is editable unless explicitly flagged as not
(views || []).forEach(function (view) {
if (isEditable(view) ||
(view.key === 'plot' && type.getKey() === 'telemetry.panel') ||
(view.key === 'table' && type.getKey() === 'table') ||
(view.key === 'rt-table' && type.getKey() === 'rttable')
) {
count++;
}
});
function isEditable(view) {
if (typeof view.editable === Function) {
return view.editable(domainObject.useCapability('adapter'));
} else {
return view.editable === true;
}
}
return count;
};
/**
* Checks whether the domain object is currently being edited. If
* so, the edit action is not applicable.
* @param context
* @returns {*|boolean}
*/
function isEditing(context) {
var domainObject = (context || {}).domainObject;
return domainObject &&
domainObject.hasCapability('editor') &&
domainObject.getCapability('editor').isEditContextRoot();
}
EditActionPolicy.prototype.allow = function (action, context) {
var key = action.getMetadata().key,
category = (context || {}).category;
// Restrict 'edit' to cases where there are editable
// views (similarly, restrict 'properties' to when
// the converse is true), and where the domain object is not
// already being edited.
if (key === 'edit') {
return this.countEditableViews(context) > 0 && !isEditing(context);
} else if (key === 'properties' && category === 'view-control') {
return this.countEditableViews(context) < 1 && !isEditing(context);
}
// Like all policies, allow by default.
return true;
};
return EditActionPolicy;
}
);

View File

@ -1,49 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
[],
function () {
/**
* Policy controlling which views should be visible in Edit mode.
* @memberof platform/commonUI/edit
* @constructor
* @implements {Policy.<View, DomainObject>}
*/
function EditableViewPolicy() {
}
EditableViewPolicy.prototype.allow = function (view, domainObject) {
// If a view is flagged as non-editable, only allow it
// while we're not in Edit mode.
if ((view || {}).editable === false) {
return !(domainObject.hasCapability('editor') && domainObject.getCapability('editor').inEditContext());
}
// Like all policies, allow by default.
return true;
};
return EditableViewPolicy;
}
);

View File

@ -1,138 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
["../../src/policies/EditActionPolicy"],
function (EditActionPolicy) {
describe("The Edit action policy", function () {
var editableView,
nonEditableView,
testViews,
testContext,
mockDomainObject,
mockEditAction,
mockPropertiesAction,
mockTypeCapability,
mockEditorCapability,
capabilities,
plotView,
policy;
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
'domainObject',
[
'useCapability',
'hasCapability',
'getCapability'
]
);
mockEditorCapability = jasmine.createSpyObj('editorCapability', ['isEditContextRoot']);
mockTypeCapability = jasmine.createSpyObj('type', ['getKey']);
capabilities = {
'editor': mockEditorCapability,
'type': mockTypeCapability
};
mockEditAction = jasmine.createSpyObj('edit', ['getMetadata']);
mockPropertiesAction = jasmine.createSpyObj('edit', ['getMetadata']);
mockDomainObject.getCapability.and.callFake(function (capability) {
return capabilities[capability];
});
mockDomainObject.hasCapability.and.callFake(function (capability) {
return !!capabilities[capability];
});
editableView = { editable: true };
nonEditableView = { editable: false };
plotView = { key: "plot", editable: false };
testViews = [];
mockDomainObject.useCapability.and.callFake(function (c) {
// Provide test views, only for the view capability
return c === 'view' && testViews;
});
mockEditAction.getMetadata.and.returnValue({ key: 'edit' });
mockPropertiesAction.getMetadata.and.returnValue({ key: 'properties' });
testContext = {
domainObject: mockDomainObject,
category: 'view-control'
};
policy = new EditActionPolicy();
});
it("allows the edit action when there are editable views", function () {
testViews = [editableView];
expect(policy.allow(mockEditAction, testContext)).toBe(true);
});
it("allows the edit properties action when there are no editable views", function () {
testViews = [nonEditableView, nonEditableView];
expect(policy.allow(mockPropertiesAction, testContext)).toBe(true);
});
it("disallows the edit action when there are no editable views", function () {
testViews = [nonEditableView, nonEditableView];
expect(policy.allow(mockEditAction, testContext)).toBe(false);
});
it("disallows the edit properties action when there are" +
" editable views", function () {
testViews = [editableView];
expect(policy.allow(mockPropertiesAction, testContext)).toBe(false);
});
it("disallows the edit action when object is already being" +
" edited", function () {
testViews = [editableView];
mockEditorCapability.isEditContextRoot.and.returnValue(true);
expect(policy.allow(mockEditAction, testContext)).toBe(false);
});
it("allows editing of panels in plot view", function () {
testViews = [plotView];
mockTypeCapability.getKey.and.returnValue('telemetry.panel');
expect(policy.allow(mockEditAction, testContext)).toBe(true);
});
it("disallows editing of plot view when object not a panel type", function () {
testViews = [plotView];
mockTypeCapability.getKey.and.returnValue('something.else');
expect(policy.allow(mockEditAction, testContext)).toBe(false);
});
it("allows the edit properties outside of the 'view-control' category", function () {
testViews = [nonEditableView];
testContext.category = "something-else";
expect(policy.allow(mockPropertiesAction, testContext)).toBe(true);
});
});
}
);

View File

@ -1,79 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
["../../src/policies/EditableViewPolicy"],
function (EditableViewPolicy) {
describe("The editable view policy", function () {
var mockDomainObject,
testMode,
policy;
beforeEach(function () {
testMode = true; // Act as if we're in Edit mode by default
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['hasCapability', 'getCapability']
);
mockDomainObject.getCapability.and.returnValue({
inEditContext: function () {
return true;
}
});
mockDomainObject.hasCapability.and.callFake(function (c) {
return (c === 'editor') && testMode;
});
policy = new EditableViewPolicy();
});
it("disallows views in edit mode that are flagged as non-editable", function () {
expect(policy.allow({ editable: false }, mockDomainObject))
.toBeFalsy();
});
it("allows views in edit mode that are flagged as editable", function () {
expect(policy.allow({ editable: true }, mockDomainObject))
.toBeTruthy();
});
it("allows any view outside of edit mode", function () {
var testViews = [
{ editable: false },
{ editable: true },
{ someKey: "some value" }
];
testMode = false; // Act as if we're not in Edit mode
testViews.forEach(function (testView) {
expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
});
});
it("treats views with no defined 'editable' property as editable", function () {
expect(policy.allow({ someKey: "some value" }, mockDomainObject))
.toBeTruthy();
});
});
}
);

View File

@ -19,16 +19,14 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="l-time-display l-digital l-clock s-clock" ng-controller="ClockController as clock">
<div class="l-elem-wrapper">
<span class="l-elem timezone">
{{clock.zone()}}
</span>
<span class="l-elem value active">
{{clock.text()}}
</span>
<span class="l-elem ampm">
{{clock.ampm()}}
</span>
<div class="c-clock l-time-display" ng-controller="ClockController as clock">
<div class="c-clock__timezone">
{{clock.zone()}}
</div>
<div class="c-clock__value">
{{clock.text()}}
</div>
<div class="c-clock__ampm">
{{clock.ampm()}}
</div>
</div>

View File

@ -19,21 +19,19 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="l-time-display l-digital l-timer s-timer s-state-{{timer.timerState}}" ng-controller="TimerController as timer">
<div class="l-elem-wrapper l-flex-row">
<div class="l-elem-wrapper l-flex-row controls">
<a ng-click="timer.clickStopButton()"
title="Stop"
class="flex-elem s-icon-button t-btn-stop icon-box"></a>
<a ng-click="timer.clickButton()"
title="{{timer.buttonText()}}"
class="flex-elem s-icon-button t-btn-pauseplay {{timer.buttonCssClass()}}"></a>
</div>
<span class="flex-elem l-value {{timer.signClass()}}">
<span class="value"
ng-class="{ active:timer.text() }">{{timer.text() || "--:--:--"}}
</span>
</span>
<span ng-controller="RefreshingController"></span>
<div class="c-timer is-{{timer.timerState}}" ng-controller="TimerController as timer">
<div class="c-timer__controls">
<button ng-click="timer.clickStopButton()"
ng-hide="timer.timerState == 'stopped'"
title="Reset"
class="c-timer__ctrl-reset c-click-icon c-click-icon--major icon-reset"></button>
<button ng-click="timer.clickButton()"
title="{{timer.buttonText()}}"
class="c-timer__ctrl-pause-play c-click-icon c-click-icon--major {{timer.buttonCssClass()}}"></button>
</div>
<div class="c-timer__direction {{timer.signClass()}}"
ng-hide="!timer.signClass()"></div>
<div class="c-timer__value">{{timer.text() || "--:--:--"}}
</div>
<span class="c-timer__ng-controller u-contents" ng-controller="RefreshingController"></span>
</div>

View File

@ -30,6 +30,7 @@ define([
"./src/controllers/CompositeController",
"./src/controllers/ColorController",
"./src/controllers/DialogButtonController",
"./src/controllers/SnapshotPreviewController",
"./res/templates/controls/autocomplete.html",
"./res/templates/controls/checkbox.html",
"./res/templates/controls/datetime.html",
@ -44,6 +45,7 @@ define([
"./res/templates/controls/dialog.html",
"./res/templates/controls/radio.html",
"./res/templates/controls/file-input.html",
"./res/templates/controls/snap-view.html",
'legacyRegistry'
], function (
MCTForm,
@ -55,6 +57,7 @@ define([
CompositeController,
ColorController,
DialogButtonController,
SnapshotPreviewController,
autocompleteTemplate,
checkboxTemplate,
datetimeTemplate,
@ -69,6 +72,7 @@ define([
dialogTemplate,
radioTemplate,
fileInputTemplate,
snapViewTemplate,
legacyRegistry
) {
@ -153,6 +157,10 @@ define([
{
"key": "file-input",
"template": fileInputTemplate
},
{
"key": "snap-view",
"template": snapViewTemplate
}
],
"controllers": [
@ -186,6 +194,14 @@ define([
"$scope",
"dialogService"
]
},
{
"key": "SnapshotPreviewController",
"implementation": SnapshotPreviewController,
"depends": [
"$scope",
"openmct"
]
}
],
"components": [

View File

@ -1,5 +1,5 @@
<!--
Open MCT, Copyright (c) 2014-2017, United States Government
Open MCT, Copyright (c) 2014-2018, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
@ -19,11 +19,18 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class='form-control select' ng-controller="selectSnapshotController">
<select
ng-model="selectModel"
ng-options="opt.value as opt.name for opt in options"
ng-required="ngRequired"
name="mctControl">
</select>
</div>
<span ng-controller="SnapshotPreviewController"
class='form-control shell'>
<span class='field control {{structure.cssClass}}'>
<image
class="c-ne__embed__snap-thumb"
src="{{imageUrl || structure.src}}"
ng-click="previewImage(imageUrl || structure.src)"
name="mctControl">
</image>
<br>
<a title="Annotate" class="s-button icon-pencil" ng-click="annotateImage(ngModel, field, imageUrl || structure.src)">
<span class="title-label">Annotate</span>
</a>
</span>
</span>

View File

@ -0,0 +1,120 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
[
'painterro'
],
function (Painterro) {
function SnapshotPreviewController($scope, openmct) {
$scope.previewImage = function (imageUrl) {
var image = document.createElement('img');
image.src = imageUrl;
openmct.overlays.overlay(
{
element: image,
size: 'large'
}
);
};
$scope.annotateImage = function (ngModel, field, imageUrl) {
$scope.imageUrl = imageUrl;
var div = document.createElement('div'),
painterroInstance = {},
save = false;
div.id = 'snap-annotation';
openmct.overlays.overlay(
{
element: div,
size: 'large',
buttons: [
{
label: 'Cancel',
callback: function () {
save = false;
painterroInstance.save();
}
},
{
label: 'Save',
callback: function () {
save = true;
painterroInstance.save();
}
}
]
}
);
painterroInstance = Painterro({
id: 'snap-annotation',
activeColor: '#ff0000',
activeColorAlpha: 1.0,
activeFillColor: '#fff',
activeFillColorAlpha: 0.0,
backgroundFillColor: '#000',
backgroundFillColorAlpha: 0.0,
defaultFontSize: 16,
defaultLineWidth: 2,
defaultTool: 'ellipse',
hiddenTools: ['save', 'open', 'close', 'eraser', 'pixelize', 'rotate', 'settings', 'resize'],
translation: {
name: 'en',
strings: {
lineColor: 'Line',
fillColor: 'Fill',
lineWidth: 'Size',
textColor: 'Color',
fontSize: 'Size',
fontStyle: 'Style'
}
},
saveHandler: function (image, done) {
if (save) {
var url = image.asBlob(),
reader = new window.FileReader();
reader.readAsDataURL(url);
reader.onloadend = function () {
$scope.imageUrl = reader.result;
ngModel[field] = reader.result;
};
} else {
ngModel.field = imageUrl;
console.warn('You cancelled the annotation!!!');
}
done(true);
}
}).show(imageUrl);
};
}
return SnapshotPreviewController;
}
);

View File

@ -40,9 +40,10 @@ define([
'../platform/framework/src/Main',
'./styles-new/core.scss',
'./styles-new/notebook.scss',
'./ui/components/layout/Layout.vue',
'./ui/layout/Layout.vue',
'../platform/core/src/objects/DomainObjectImpl',
'../platform/core/src/capabilities/ContextualDomainObject',
'./ui/preview/plugin',
'vue'
], function (
EventEmitter,
@ -67,6 +68,7 @@ define([
Layout,
DomainObjectImpl,
ContextualDomainObject,
PreviewPlugin,
Vue
) {
/**
@ -230,7 +232,7 @@ define([
this.install(this.plugins.Plot());
this.install(this.plugins.TelemetryTable());
this.install(this.plugins.DisplayLayout());
this.install(this.plugins.Preview());
this.install(PreviewPlugin.default());
if (typeof BUILD_CONSTANTS !== 'undefined') {
this.install(buildInfoPlugin(BUILD_CONSTANTS));

View File

@ -58,11 +58,8 @@ define([
handleLegacyMutation = function (legacyObject) {
var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId());
//Don't trigger self
this.eventEmitter.off('mutation', handleMutation);
this.eventEmitter.emit(newStyleObject.identifier.key + ":*", newStyleObject);
this.eventEmitter.on('mutation', handleMutation);
this.eventEmitter.emit('mutation', newStyleObject);
}.bind(this);
this.eventEmitter.on('mutation', handleMutation);

View File

@ -21,7 +21,9 @@ define([
name: legacyView.name,
cssClass: legacyView.cssClass,
description: legacyView.description,
editable: legacyView.editable,
canEdit: function () {
return legacyView.editable === true;
},
canView: function (domainObject) {
if (!domainObject || !domainObject.identifier) {
return false;

View File

@ -28,6 +28,11 @@ export default class Editor extends EventEmitter {
super();
this.editing = false;
this.openmct = openmct;
document.addEventListener('drop', (event) => {
if (!this.isEditing()) {
this.edit();
}
}, {capture: true});
}
/**

View File

@ -46,6 +46,7 @@ define([
function DefaultCompositionProvider(publicAPI, compositionAPI) {
this.publicAPI = publicAPI;
this.listeningTo = {};
this.onMutation = this.onMutation.bind(this);
this.cannotContainDuplicates = this.cannotContainDuplicates.bind(this);
this.cannotContainItself = this.cannotContainItself.bind(this);
@ -208,9 +209,10 @@ define([
if (this.topicListener) {
return;
}
var topic = this.publicAPI.$injector.get('topic');
var mutation = topic('mutation');
this.topicListener = mutation.listen(this.onMutation.bind(this));
this.publicAPI.objects.eventEmitter.on('mutation', this.onMutation);
this.topicListener = () => {
this.publicAPI.objects.eventEmitter.off('mutation', this.onMutation)
};
};
/**
@ -220,7 +222,7 @@ define([
* @private
*/
DefaultCompositionProvider.prototype.onMutation = function (oldDomainObject) {
var id = oldDomainObject.getId();
var id = objectUtils.makeKeyString(oldDomainObject.identifier);
var listeners = this.listeningTo[id];
if (!listeners) {
@ -228,7 +230,7 @@ define([
}
var oldComposition = listeners.composition.map(objectUtils.makeKeyString);
var newComposition = oldDomainObject.getModel().composition.map(objectUtils.makeKeyString);
var newComposition = oldDomainObject.composition.map(objectUtils.makeKeyString);
var added = _.difference(newComposition, oldComposition).map(objectUtils.parseKeyString);
var removed = _.difference(oldComposition, newComposition).map(objectUtils.parseKeyString);

View File

@ -83,18 +83,15 @@ define([
this.object = newObject;
}.bind(this);
this.eventEmitter.on(qualifiedEventName(this.object, '*'), handleRecursiveMutation);
//Emit event specific to property
this.eventEmitter.emit(qualifiedEventName(this.object, path), value);
this.eventEmitter.off(qualifiedEventName(this.object, '*'), handleRecursiveMutation);
//Emit wildcare event
//Emit wildcard event
this.eventEmitter.emit(qualifiedEventName(this.object, '*'), this.object);
//Emit a general "any object" event
this.eventEmitter.emit(ANY_OBJECT_EVENT, this.object);
this.eventEmitter.on(qualifiedEventName(this.object, '*'), handleRecursiveMutation);
//Emit event specific to property
this.eventEmitter.emit(qualifiedEventName(this.object, path), value);
this.eventEmitter.off(qualifiedEventName(this.object, '*'), handleRecursiveMutation);
};
return MutableObject;

View File

@ -1,4 +1,4 @@
import ProgressComponent from '../../ui/components/layout/ProgressBar.vue';
import ProgressComponent from '../../ui/components/ProgressBar.vue';
import Overlay from './Overlay';
import Vue from 'vue';

View File

@ -20,47 +20,48 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'vue',
'../../res/templates/viewSnapshot.html'
'./components/LadTableSet.vue',
'vue'
], function (
Vue,
snapshotOverlayTemplate
LadTableSet,
Vue
) {
function SnapshotOverlay (embedObject, formatTime) {
this.embedObject = embedObject;
function LADTableSetViewProvider(openmct) {
return {
key: 'LadTableSet',
name: 'LAD Table Set',
cssClass: 'icon-tabular-lad-set',
canView: function (domainObject) {
return domainObject.type === 'LadTableSet';
},
view: function (domainObject) {
let component;
this.snapshotOverlayVue = new Vue({
template: snapshotOverlayTemplate,
data: function () {
return {
embed: embedObject
show: function (element) {
component = new Vue({
components: {
LadTableSet: LadTableSet.default
},
provide: {
openmct,
domainObject
},
el: element,
template: '<lad-table-set></lad-table-set>'
});
},
destroy: function (element) {
component.$destroy();
component = undefined;
}
};
},
methods: {
close: this.close.bind(this),
formatTime: formatTime
priority: function () {
return 1;
}
});
this.open();
};
}
SnapshotOverlay.prototype.open = function () {
this.overlay = document.createElement('div');
this.overlay.classList.add('abs');
document.body.appendChild(this.overlay);
this.overlay.appendChild(this.snapshotOverlayVue.$mount().$el);
};
SnapshotOverlay.prototype.close = function (event) {
event.stopPropagation();
this.snapshotOverlayVue.$destroy();
this.overlay.parentNode.removeChild(this.overlay);
};
return SnapshotOverlay;
return LADTableSetViewProvider;
});

View File

@ -0,0 +1,67 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define([
'./components/LadTable.vue',
'vue'
], function (
LadTableComponent,
Vue
) {
function LADTableViewProvider(openmct) {
return {
key: 'LadTable',
name: 'LAD Table',
cssClass: 'icon-tabular-lad',
canView: function (domainObject) {
return domainObject.type === 'LadTable';
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
components: {
LadTableComponent: LadTableComponent.default
},
provide: {
openmct,
domainObject
},
el: element,
template: '<lad-table-component></lad-table-component>'
});
},
destroy: function (element) {
component.$destroy();
component = undefined;
}
};
},
priority: function () {
return 1;
}
};
}
return LADTableViewProvider;
});

View File

@ -0,0 +1,120 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
<template>
<tr>
<td>{{name}}</td>
<td>{{timestamp}}</td>
<td :class="valueClass">
{{value}}
</td>
</tr>
</template>
<style lang="scss">
</style>
<script>
export default {
inject: ['openmct'],
props: ['domainObject'],
data() {
return {
name: this.domainObject.name,
timestamp: '---',
value: '---',
valueClass: ''
}
},
methods: {
updateValues(datum) {
this.timestamp = this.formats[this.timestampKey].format(datum);
this.value = this.formats[this.valueKey].format(datum);
var limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
if (limit) {
this.valueClass = limit.cssClass;
} else {
this.valueClass = '';
}
},
updateName(name){
this.name = name;
},
updateTimeSystem(timeSystem) {
this.value = '---';
this.timestamp = '---';
this.valueClass = '';
this.timestampKey = timeSystem.key;
this.openmct
.telemetry
.request(this.domainObject, {strategy: 'latest'})
.then((array) => this.updateValues(array[array.length - 1]));
}
},
mounted() {
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.limitEvaluator = openmct
.telemetry
.limitEvaluator(this.domainObject);
this.stopWatchingMutation = openmct
.objects
.observe(
this.domainObject,
'*',
this.updateName
);
this.openmct.time.on('timeSystem', this.updateTimeSystem);
this.timestampKey = this.openmct.time.timeSystem().key;
this.valueMetadata = this
.metadata
.valuesForHints(['range'])[0];
this.valueKey = this.valueMetadata.key
this.unsubscribe = this.openmct
.telemetry
.subscribe(this.domainObject, this.updateValues);
this.openmct
.telemetry
.request(this.domainObject, {strategy: 'latest'})
.then((array) => this.updateValues(array[array.length - 1]));
},
destroyed() {
this.stopWatchingMutation();
this.unsubscribe();
this.openmct.off('timeSystem', this.updateTimeSystem);
}
}
</script>

View File

@ -0,0 +1,82 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
<template>
<table class="c-table c-lad-table">
<thead>
<tr>
<th>Name</th>
<th>Timestamp</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<lad-row
v-for="item in items"
:key="item.key"
:domainObject="item.domainObject">
</lad-row>
</tbody>
</table>
</template>
<script>
import lodash from 'lodash';
import LadRow from './LadRow.vue';
export default {
inject: ['openmct', 'domainObject'],
components: {
LadRow
},
data() {
return {
items: []
}
},
methods: {
addItem(domainObject) {
let item = {};
item.domainObject = domainObject;
item.key = this.openmct.objects.makeKeyString(domainObject.identifier);
this.items.push(item);
},
removeItem(identifier) {
let index = _.findIndex(this.items, (item) => this.openmct.objects.makeKeyString(identifier) === item.key);
this.items.splice(index, 1);
}
},
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addItem);
this.composition.on('remove', this.removeItem);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem);
}
}
</script>

View File

@ -0,0 +1,135 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
<template>
<table class="c-table c-lad-table">
<thead>
<tr>
<th>Name</th>
<th>Timestamp</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<template
v-for="primary in primaryTelemetryObjects">
<tr class="c-table__group-header"
:key="primary.key">
<td colspan="10">{{primary.domainObject.name}}</td>
</tr>
<lad-row
v-for="secondary in secondaryTelemetryObjects[primary.key]"
:key="secondary.key"
:domainObject="secondary.domainObject">
</lad-row>
</template>
</tbody>
</table>
</template>
<style lang="scss">
</style>
<script>
import lodash from 'lodash';
import LadRow from './LadRow.vue';
export default {
inject: ['openmct', 'domainObject'],
components: {
LadRow
},
data() {
return {
primaryTelemetryObjects: [],
secondaryTelemetryObjects: {},
compositions: []
}
},
methods: {
addPrimary(domainObject) {
let primary = {};
primary.domainObject = domainObject;
primary.key = this.openmct.objects.makeKeyString(domainObject.identifier);
this.$set(this.secondaryTelemetryObjects, primary.key, []);
this.primaryTelemetryObjects.push(primary);
let composition = openmct.composition.get(primary.domainObject),
addCallback = this.addSecondary(primary),
removeCallback = this.removeSecondary(primary);
composition.on('add', addCallback);
composition.on('remove', removeCallback);
composition.load();
this.compositions.push({composition, addCallback, removeCallback});
},
removePrimary(identifier) {
let index = _.findIndex(this.primaryTelemetryObjects, (primary) => this.openmct.objects.makeKeyString(identifier) === primary.key),
primary = this.primaryTelemetryObjects[index];
this.$set(this.secondaryTelemetryObjects, primary.key, undefined);
this.primaryTelemetryObjects.splice(index,1);
primary = undefined;
},
addSecondary(primary) {
return (domainObject) => {
let secondary = {};
secondary.key = this.openmct.objects.makeKeyString(domainObject.identifier);
secondary.domainObject = domainObject;
let array = this.secondaryTelemetryObjects[primary.key];
array.push(secondary);
this.$set(this.secondaryTelemetryObjects, primary.key, array);
}
},
removeSecondary(primary) {
return (identifier) => {
let array = this.secondaryTelemetryObjects[primary.key],
index = _.findIndex(array, (secondary) => this.openmct.objects.makeKeyString(identifier) === secondary.key);
array.splice(index, 1);
this.$set(this.secondaryTelemetryObjects, primary.key, array);
}
}
},
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addPrimary);
this.composition.on('remove', this.removePrimary);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.addPrimary);
this.composition.off('remove', this.removePrimary);
this.compositions.forEach(c => {
c.composition.off('add', c.addCallback);
c.composition.off('remove', c.removeCallback);
});
}
}
</script>

View File

@ -0,0 +1,56 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define([
'./LADTableViewProvider',
'./LADTableSetViewProvider'
], function (
LADTableViewProvider,
LADTableSetViewProvider
) {
return function plugin() {
return function install(openmct) {
openmct.objectViews.addProvider(new LADTableViewProvider(openmct));
openmct.objectViews.addProvider(new LADTableSetViewProvider(openmct));
openmct.types.addType('LadTable', {
name: "LAD Table",
creatable: true,
description: "A Latest Available Data tabular view in which each row displays the values for one or more contained telemetry objects.",
cssClass: 'icon-tabular-lad',
initialize(domainObject) {
domainObject.composition = [];
}
});
openmct.types.addType('LadTableSet', {
name: "LAD Table Set",
creatable: true,
description: "A Latest Available Data tabular view in which each row displays the values for one or more contained telemetry objects.",
cssClass: 'icon-tabular-lad-set',
initialize(domainObject) {
domainObject.composition = [];
}
});
};
};
});

View File

@ -125,11 +125,41 @@ define([], function () {
let separator = {
control: "separator"
};
let remove = {
control: "button",
domainObject: selectedParent,
icon: "icon-trash",
title: "Delete the selected object",
method: function () {
let removeItem = selection[1].context.removeItem;
let prompt = openmct.overlays.dialog({
iconClass: 'alert',
message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
buttons: [
{
label: 'Ok',
emphasis: 'true',
callback: function () {
removeItem(layoutItem, layoutItemIndex);
prompt.dismiss();
}
},
{
label: 'Cancel',
callback: function () {
prompt.dismiss();
}
}
]
});
}
};
if (layoutItem.type === 'subobject-view') {
if (toolbar.length > 0) {
toolbar.push(separator);
}
toolbar.push({
control: "toggle-button",
domainObject: selectedParent,
@ -147,6 +177,8 @@ define([], function () {
}
]
});
toolbar.push(separator);
toolbar.push(remove);
} else {
const TEXT_SIZE = [9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96];
let fill = {
@ -263,7 +295,9 @@ define([], function () {
x,
y,
height,
width
width,
separator,
remove
];
} else if (layoutItem.type === 'text-view' ) {
let text = {
@ -286,7 +320,9 @@ define([], function () {
height,
width,
separator,
text
text,
separator,
remove
];
} else if (layoutItem.type === 'box-view') {
toolbar = [
@ -296,7 +332,9 @@ define([], function () {
x,
y,
height,
width
width,
separator,
remove
];
} else if (layoutItem.type === 'image-view') {
let url = {
@ -315,7 +353,9 @@ define([], function () {
height,
width,
separator,
url
url,
separator,
remove
];
} else if (layoutItem.type === 'line-view') {
let x2 = {
@ -340,7 +380,9 @@ define([], function () {
x,
y,
x2,
y2
y2,
separator,
remove
];
}
}

View File

@ -75,16 +75,22 @@
};
}
},
watch: {
index(newIndex) {
if (!this.context) {
return;
}
this.context.index = newIndex;
}
},
mounted() {
let context = {
this.context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el,
context,
this.initSelect
);
this.$el, this.context, this.initSelect);
},
destroyed() {
if (this.removeSelectable) {

View File

@ -40,6 +40,7 @@
<component v-for="(item, index) in layoutItems"
:is="item.type"
:item="item"
:key="item.id"
:gridSize="gridSize"
:initSelect="initSelectIndex === index"
:index="index"
@ -76,7 +77,7 @@
.l-shell__main-container {
> .l-layout {
[s-selected] {
border: $browseBorderSelected;
border: $browseSelectedBorder;
}
}
}
@ -176,13 +177,13 @@
this.openmct.objects.mutate(this.internalDomainObject, path, value);
},
handleDrop($event) {
if (!$event.dataTransfer.types.includes('domainobject')) {
if (!$event.dataTransfer.types.includes('openmct/domain-object-path')) {
return;
}
$event.preventDefault();
let domainObject = JSON.parse($event.dataTransfer.getData('domainobject'));
let domainObject = JSON.parse($event.dataTransfer.getData('openmct/domain-object-path'))[0];
let elementRect = this.$el.getBoundingClientRect();
let droppedObjectPosition = [
Math.floor(($event.pageX - elementRect.left) / this.gridSize[0]),
@ -226,6 +227,7 @@
addItem(itemType, ...options) {
let item = getItemDefinition(itemType, this.openmct, this.gridSize, ...options);
item.type = itemType;
item.id = uuid();
this.trackItem(item);
this.layoutItems.push(item);
this.openmct.objects.mutate(this.internalDomainObject, "configuration.items", this.layoutItems);
@ -233,11 +235,46 @@
},
trackItem(item) {
if (item.type === "telemetry-view") {
this.telemetryViewMap[this.openmct.objects.makeKeyString(item.identifier)] = true;
let keyString = this.openmct.objects.makeKeyString(item.identifier);
let count = this.telemetryViewMap[keyString] || 0;
this.telemetryViewMap[keyString] = ++count;
} else if (item.type === "subobject-view") {
this.objectViewMap[this.openmct.objects.makeKeyString(item.identifier)] = true;
}
},
removeItem(item, index) {
this.initSelectIndex = -1;
this.layoutItems.splice(index, 1);
this.mutate("configuration.items", this.layoutItems);
this.untrackItem(item);
this.$el.click();
},
untrackItem(item) {
if (!item.identifier) {
return;
}
let keyString = this.openmct.objects.makeKeyString(item.identifier);
if (item.type === 'telemetry-view') {
let count = --this.telemetryViewMap[keyString];
if (count === 0) {
delete this.telemetryViewMap[keyString];
this.removeFromComposition(keyString);
}
} else if (item.type === 'subobject-view') {
delete this.objectViewMap[keyString];
this.removeFromComposition(keyString);
}
},
removeFromComposition(keyString) {
let composition = _.get(this.internalDomainObject, 'composition');
composition = composition.filter(identifier => {
return this.openmct.objects.makeKeyString(identifier) !== keyString;
});
this.mutate("composition", composition);
},
initializeItems() {
this.telemetryViewMap = {};
this.objectViewMap = {};
@ -254,7 +291,26 @@
}
},
removeChild(identifier) {
// TODO: implement
let keyString = this.openmct.objects.makeKeyString(identifier);
if (this.objectViewMap[keyString]) {
delete this.objectViewMap[keyString];
this.removeFromConfiguration(keyString);
} else if (this.telemetryViewMap[keyString]) {
delete this.telemetryViewMap[keyString];
this.removeFromConfiguration(keyString);
}
},
removeFromConfiguration(keyString) {
let layoutItems = this.layoutItems.filter(item => {
if (!item.identifier) {
return true;
} else {
return this.openmct.objects.makeKeyString(item.identifier) !== keyString;
}
});
this.mutate("configuration.items", layoutItems);
this.$el.click();
}
},
mounted() {

View File

@ -77,13 +77,22 @@
}
}
},
watch: {
index(newIndex) {
if (!this.context) {
return;
}
this.context.index = newIndex;
}
},
mounted() {
let context = {
this.context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
this.$el, this.context, this.initSelect);
},
destroyed() {
if (this.removeSelectable) {

View File

@ -21,7 +21,7 @@
*****************************************************************************/
<template>
<div class="l-layout__frame c-frame has-local-controls"
<div class="l-layout__frame c-frame"
:class="{
'no-frame': !item.hasFrame,
'u-inspectable': inspectable,

View File

@ -21,10 +21,9 @@
*****************************************************************************/
<template>
<div class="l-layout__frame c-frame has-local-controls no-frame"
<div class="l-layout__frame c-frame no-frame"
:style="style">
<svg width="100%"
height="100%">
<svg width="100%" height="100%">
<line v-bind="linePosition"
:stroke="item.stroke"
stroke-width="2">
@ -101,9 +100,6 @@
top: `${top}px`,
width: `${width}px`,
height: `${height}px`,
minWidth: `${width}px`,
minHeight: `${height}px`,
position: 'absolute'
};
},
startHandleClass() {
@ -210,17 +206,22 @@
return dragPosition;
}
},
watch: {
index(newIndex) {
if (!this.context) {
return;
}
this.context.index = newIndex;
}
},
mounted() {
let context = {
this.context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el,
context,
this.initSelect
);
this.$el, this.context, this.initSelect);
},
destroyed() {
if (this.removeSelectable) {

View File

@ -24,90 +24,16 @@
:grid-size="gridSize"
@endDrag="(item, updates) => $emit('endDrag', item, updates)"
@drilledIn="item => $emit('drilledIn', item)">
<div class="u-contents">
<div class="c-so-view__header">
<div class="c-so-view__header__start">
<div class="c-so-view__header__name"
:class="cssClass">
{{ domainObject && domainObject.name }}
</div>
<context-menu-drop-down
:object-path="objectPath">
</context-menu-drop-down>
</div>
<div class="c-so-view__header__end">
<div class="c-button icon-expand local-controls--hidden"></div>
</div>
</div>
<object-view class="c-so-view__object-view"
:object="domainObject"></object-view>
</div>
<object-frame v-if="domainObject"
:domain-object="domainObject"
:object-path="objectPath"
:has-frame="item.hasFrame">
</object-frame>
</layout-frame>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-so-view {
/*************************** HEADER */
&__header {
display: flex;
align-items: center;
&__start,
&__end {
display: flex;
flex: 1 1 auto;
}
&__end {
justify-content: flex-end;
}
&__name {
@include headerFont(1em);
display: flex;
&:before {
margin-right: $interiorMarginSm;
}
}
.no-frame & {
display: none;
}
}
&__name {
@include ellipsize();
@include headerFont(1.2em);
flex: 0 1 auto;
&:before {
// Object type icon
flex: 0 0 auto;
margin-right: $interiorMarginSm;
opacity: 0.5;
}
}
/*************************** OBJECT VIEW */
&__object-view {
flex: 1 1 auto;
overflow: auto;
.c-object-view {
.u-fills-container {
// Expand component types that fill a container
@include abs();
}
}
}
}
</style>
<script>
import ObjectView from '../../../ui/components/layout/ObjectView.vue'
import ContextMenuDropDown from '../../../ui/components/controls/contextMenuDropDown.vue';
import ObjectFrame from '../../../ui/components/ObjectFrame.vue'
import LayoutFrame from './LayoutFrame.vue'
const MINIMUM_FRAME_SIZE = [320, 180],
@ -152,27 +78,33 @@
data() {
return {
domainObject: undefined,
cssClass: undefined,
objectPath: []
}
},
components: {
ObjectView,
ContextMenuDropDown,
ObjectFrame,
LayoutFrame
},
watch: {
index(newIndex) {
if (!this.context) {
return;
}
this.context.index = newIndex;
}
},
methods: {
setObject(domainObject) {
this.domainObject = domainObject;
this.objectPath = [this.domainObject].concat(this.openmct.router.path);
this.cssClass = this.openmct.types.get(this.domainObject.type).definition.cssClass;
let context = {
this.context = {
item: domainObject,
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
this.$el, this.context, this.initSelect);
}
},
mounted() {

View File

@ -160,6 +160,15 @@
domainObject: undefined
}
},
watch: {
index(newIndex) {
if (!this.context) {
return;
}
this.context.index = newIndex;
}
},
methods: {
requestHistoricalData() {
let bounds = this.openmct.time.bounds();
@ -205,13 +214,13 @@
this.requestHistoricalData();
this.subscribeToObject();
let context = {
this.context = {
item: domainObject,
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
this.$el, this.context, this.initSelect);
}
},
mounted() {

View File

@ -82,13 +82,22 @@
};
}
},
watch: {
index(newIndex) {
if (!this.context) {
return;
}
this.context.index = newIndex;
}
},
mounted() {
let context = {
this.context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
this.$el, this.context, this.initSelect);
},
destroyed() {
if (this.removeSelectable) {

View File

@ -33,6 +33,9 @@ export default function () {
canView: function (domainObject) {
return domainObject.type === 'layout';
},
canEdit: function (domainObject) {
return domainObject.type === 'layout';
},
view: function (domainObject) {
let component;
return {
@ -57,7 +60,8 @@ export default function () {
getSelectionContext() {
return {
item: domainObject,
addElement: component && component.$refs.displayLayout.addElement
addElement: component && component.$refs.displayLayout.addElement,
removeItem: component && component.$refs.displayLayout.removeItem
}
},
destroy() {

View File

@ -100,7 +100,7 @@ export default {
},
methods: {
allowDrop(event, index) {
if (event.dataTransfer.getData('domainObject')) {
if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
return true;
}
let frameId = event.dataTransfer.getData('frameid'),
@ -124,9 +124,9 @@ export default {
}
},
moveOrCreateFrame(insertIndex, event) {
if (event.dataTransfer.types.includes('domainobject')) {
if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
// create frame using domain object
let domainObject = JSON.parse(event.dataTransfer.getData('domainObject'));
let domainObject = JSON.parse(event.dataTransfer.getData('openmct/domain-object-path'))[0];
this.$emit(
'create-frame',
this.index,

View File

@ -21,8 +21,7 @@
*****************************************************************************/
<template>
<div v-if="isEditing"
v-show="isValidTarget">
<div v-show="isValidTarget">
<div class="c-drop-hint c-drop-hint--always-show"
:class="{'is-mouse-over': isMouseOver}"
@dragenter="dragenter"
@ -37,8 +36,6 @@
</style>
<script>
import isEditingMixin from '../mixins/isEditing';
export default {
props:{
index: Number,
@ -47,7 +44,6 @@ export default {
required: true
}
},
mixins: [isEditingMixin],
data() {
return {
isMouseOver: false,

View File

@ -27,15 +27,16 @@
}">
<div class="c-frame c-fl-frame__drag-wrapper is-selectable is-moveable"
:class="{'no-frame': noFrame}"
draggable="true"
@dragstart="initDrag"
ref="frame">
<subobject-view
v-if="item.domainObject.identifier"
:item="item">
</subobject-view>
<object-frame
v-if="domainObject"
:domain-object="domainObject"
:object-path="objectPath"
:has-frame="hasFrame">
</object-frame>
<div class="c-fl-frame__size-indicator"
v-if="isEditing"
@ -48,7 +49,7 @@
<script>
import ResizeHandle from './resizeHandle.vue';
import SubobjectView from '../../displayLayout/components/SubobjectView.vue';
import ObjectFrame from '../../../ui/components/ObjectFrame.vue';
import isEditingMixin from '../mixins/isEditing';
export default {
@ -57,26 +58,29 @@ export default {
mixins: [isEditingMixin],
data() {
return {
item: {domainObject: {}}
domainObject: undefined,
objectPath: undefined
}
},
components: {
ResizeHandle,
SubobjectView
ObjectFrame
},
computed: {
noFrame() {
return this.frame.noFrame;
hasFrame() {
return !this.frame.noFrame;
}
},
methods: {
setDomainObject(object) {
this.item.domainObject = object;
console.log('setting object!');
this.domainObject = object;
this.objectPath = [object];
this.setSelection();
},
setSelection() {
let context = {
item: this.item.domainObject,
item: this.domainObject,
addContainer: this.addContainer,
type: 'frame',
frameId: this.frame.id

View File

@ -35,6 +35,9 @@ define([
canView: function (domainObject) {
return domainObject.type === 'flexible-layout';
},
canEdit: function (domainObject) {
return domainObject.type === 'flexible-layout';
},
view: function (domainObject) {
let component;

View File

@ -44,6 +44,7 @@ define([
containers: [new Container.default(50), new Container.default(50)],
rowsLayout: false
};
domainObject.composition = [];
}
});

View File

@ -30,7 +30,7 @@ define([
function FolderGridView(openmct) {
return {
key: 'grid',
name: 'Grid Vue',
name: 'Grid View',
cssClass: 'icon-thumbs-strip',
canView: function (domainObject) {
return domainObject.type === 'folder';

View File

@ -32,7 +32,7 @@ define([
function FolderListView(openmct) {
return {
key: 'list-view',
name: 'List Vue',
name: 'List View',
cssClass: 'icon-list-view',
canView: function (domainObject) {
return domainObject.type === 'folder';

View File

@ -149,8 +149,8 @@
</style>
<script>
import contextMenuGesture from '../../../ui/components/mixins/context-menu-gesture';
import objectLink from '../../../ui/components/mixins/object-link';
import contextMenuGesture from '../../../ui/mixins/context-menu-gesture';
import objectLink from '../../../ui/mixins/object-link';
export default {
mixins: [contextMenuGesture, objectLink],

View File

@ -4,9 +4,8 @@
@click="navigate">
<td class="c-list-item__name">
<a :href="objectLink" ref="objectLink">
<div class="c-list-item__type-icon"
:class="item.type.cssClass"></div>
{{item.model.name}}
<div class="c-list-item__type-icon" :class="item.type.cssClass"></div>
<div class="c-list-item__name-value">{{item.model.name}}</div>
</a>
</td>
<td class="c-list-item__type">{{ item.type.name }}</td>
@ -20,17 +19,24 @@
/******************************* LIST ITEM */
.c-list-item {
&__name {
@include ellipsize();
&__name a {
display: flex;
> * + * { margin-left: $interiorMarginSm; }
}
&__type-icon {
// Have to do it this way instead of using icon-* class, due to need to apply alias to the icon
color: $colorKey;
display: inline-block;
width: 1em;
margin-right:$interiorMarginSm;
}
&__name-value {
@include ellipsize();
}
&.is-alias {
// Object is an alias to an original.
[class*='__type-icon'] {
@ -48,14 +54,13 @@
}
}
}
</style>
<script>
import moment from 'moment';
import contextMenuGesture from '../../../ui/components/mixins/context-menu-gesture';
import objectLink from '../../../ui/components/mixins/object-link';
import contextMenuGesture from '../../../ui/mixins/context-menu-gesture';
import objectLink from '../../../ui/mixins/object-link';
export default {
mixins: [contextMenuGesture, objectLink],

View File

@ -42,7 +42,8 @@
</tr>
</thead>
<tbody>
<list-item v-for="(item,index) in sortedItems"
<list-item v-for="item in sortedItems"
:key="item.objectKeyString"
:item="item"
:object-path="item.objectPath">
</list-item>
@ -77,9 +78,12 @@
td {
$p: floor($interiorMargin * 1.5);
font-size: 1.1em;
@include ellipsize();
line-height: 120%; // Needed for icon alignment
max-width: 0;
padding-top: $p;
padding-bottom: $p;
width: 25%;
&:not(.c-list-item__name) {
color: $colorItemFgDetails;
@ -99,9 +103,20 @@ export default {
mixins: [compositionLoader],
inject: ['domainObject', 'openmct'],
data() {
let sortBy = 'model.name',
ascending = true,
persistedSortOrder = window.localStorage.getItem('openmct-listview-sort-order');
if (persistedSortOrder) {
let parsed = JSON.parse(persistedSortOrder);
sortBy = parsed.sortBy;
ascending = parsed.ascending;
}
return {
sortBy: 'model.name',
ascending: true
sortBy,
ascending
};
},
computed: {
@ -121,6 +136,17 @@ export default {
this.sortBy = field;
this.ascending = defaultDirection;
}
window.localStorage
.setItem(
'openmct-listview-sort-order',
JSON.stringify(
{
sortBy: this.sortBy,
ascending: this.ascending
}
)
);
}
}
}

View File

@ -35,7 +35,8 @@ export default {
model: child,
type: type.definition,
isAlias: this.domainObject.identifier.key !== child.location,
objectPath: [child].concat(openmct.router.path)
objectPath: [child].concat(this.openmct.router.path),
objectKeyString: this.openmct.objects.makeKeyString(child.identifier)
});
},
remove(identifier) {

View File

@ -21,27 +21,9 @@
*****************************************************************************/
define([
"./src/controllers/NotebookController",
"./src/controllers/NewEntryController",
"./src/controllers/SelectSnapshotController",
"./src/actions/NewEntryContextual",
"./src/actions/AnnotateSnapshot",
"./src/directives/MCTSnapshot",
"./res/templates/controls/snapSelect.html",
"./res/templates/controls/embedControl.html",
"./res/templates/annotation.html",
"./res/templates/draggedEntry.html"
"./src/controllers/NotebookController"
], function (
NotebookController,
NewEntryController,
SelectSnapshotController,
newEntryAction,
AnnotateSnapshotAction,
MCTSnapshotDirective,
snapSelectTemplate,
embedControlTemplate,
annotationTemplate,
draggedEntryTemplate
NotebookController
) {
var installed = false;
@ -87,90 +69,6 @@ define([
}
]
}
],
actions: [
{
"key": "notebook-new-entry",
"implementation": newEntryAction,
"name": "New Notebook Entry",
"cssClass": "icon-notebook labeled",
"description": "Add a new Notebook entry",
"category": [
"view-control"
],
"depends": [
"$compile",
"$rootScope",
"dialogService",
"notificationService",
"linkService"
],
"priority": "preferred"
},
{
"key": "annotate-snapshot",
"implementation": AnnotateSnapshotAction,
"name": "Annotate Snapshot",
"cssClass": "icon-pencil labeled",
"description": "Annotate embed's snapshot",
"category": "embed",
"depends": [
"dialogService",
"dndService",
"$rootScope"
]
}
],
controllers: [
{
"key": "NewEntryController",
"implementation": NewEntryController,
"depends": ["$scope",
"$rootScope"
]
},
{
"key": "selectSnapshotController",
"implementation": SelectSnapshotController,
"depends": ["$scope",
"$rootScope"
]
}
],
controls: [
{
"key": "snapshot-select",
"template": snapSelectTemplate
},
{
"key": "embed-control",
"template": embedControlTemplate
}
],
templates: [
{
"key": "annotate-snapshot",
"template": annotationTemplate
}
],
directives: [
{
"key": "mctSnapshot",
"implementation": MCTSnapshotDirective,
"depends": [
"$rootScope",
"$document",
"exportImageService",
"dialogService",
"notificationService"
]
}
],
representations: [
{
"key": "draggedEntry",
"template": draggedEntryTemplate
}
]
}
});

View File

@ -1,2 +0,0 @@
<div class="snap-annotation" id="snap-annotation" ng-controller="ngModel.controller">
</div>

View File

@ -1,51 +0,0 @@
<!--
Open MCT, Copyright (c) 2009-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT 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 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.
-->
<!--
This element appears in the overlay dialog when initiating a new Notebook Entry from a view's Notebook button -->
<div class='form-control'>
<ng-form name="mctControl">
<div class='fields' ng-controller="NewEntryController">
<div class="l-flex-row new-notebook-entry-embed l-entry-embed {{cssClass}}"
ng-class="{ 'has-snapshot' : snapToggle }">
<div class="holder flex-elem snap-thumb"
ng-if="snapToggle">
<img ng-src="{{snapshot.src}}" alt="{{snapshot.modified}}">
</div>
<div class="holder flex-elem embed-info">
<div class="embed-title">{{objectName}}</div>
<div class="embed-date"
ng-if="snapToggle">{{snapshot.modified| date:'yyyy-MM-dd HH:mm:ss'}}</div>
</div>
<div class="holder flex-elem annotate-new"
ng-if="snapToggle">
<a class="s-button flex-elem icon-pencil "
title="Annotate this snapshot"
ng-click="annotateSnapshot()">
<span class="title-label">Annotate</span>
</a>
</div>
</div>
</div>
</ng-form>
</div>

View File

@ -1,38 +0,0 @@
<!--
Open MCT, Copyright (c) 2014-2017, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT 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 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 class="frame snap-frame frame-template t-frame-inner abs t-object-type-{{ representation.selected.key }}">
<div class="abs object-browse-bar l-flex-row">
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
<mct-representation
key="'switcher'"
ng-model="representation"
mct-object="domainObject">
</mct-representation>
</div>
</div>
<div class="abs object-holder" data-entry = "{{parameters.entry}}" data-embed = "{{parameters.embed}}" mct-snapshot ng-if="representation.selected.key">
<mct-representation
key="representation.selected.key"
mct-object="representation.selected.key && domainObject">
</mct-representation>
</div>
</div>

View File

@ -28,7 +28,7 @@
</div>
<div class="c-ne__local-controls--hidden">
<button class="c-click-icon icon-trash"
<button class="c-click-icon c-click-icon--major icon-trash"
title="Delete this entry"
v-on:click="deleteEntry"></button>
</div>

View File

@ -5,21 +5,17 @@
@input="search"
@clear="search">
</search>
<div class="c-notebook__controls">
<div class="select c-notebook__controls__time">
<select v-model="showTime">
<option value="0" selected="selected">Show all</option>
<option value="1">Last hour</option>
<option value="8">Last 8 hours</option>
<option value="24">Last 24 hours</option>
</select>
</div>
<div class="select c-notebook__controls__sort">
<select v-model="sortEntries">
<option value="newest" :selected="sortEntries === 'newest'">Newest first</option>
<option value="oldest" :selected="sortEntries === 'oldest'">Oldest first</option>
</select>
</div>
<div class="c-notebook__controls ">
<select class="c-notebook__controls__time" v-model="showTime">
<option value="0" selected="selected">Show all</option>
<option value="1">Last hour</option>
<option value="8">Last 8 hours</option>
<option value="24">Last 24 hours</option>
</select>
<select class="c-notebook__controls__time" v-model="sortEntries">
<option value="newest" :selected="sortEntries === 'newest'">Newest first</option>
<option value="oldest" :selected="sortEntries === 'oldest'">Oldest first</option>
</select>
</div>
</div>
<div class="c-notebook__drag-area icon-plus"
@ -31,8 +27,9 @@
<div class="c-notebook__entries" ng-mouseover="handleActive()">
<ul>
<notebook-entry
v-for="entry in filteredAndSortedEntries"
v-bind:entry="entry">
v-for="(entry,index) in filteredAndSortedEntries"
:key="entry.key"
:entry="entry">
</notebook-entry>
</ul>
</div>

View File

@ -1,162 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
/**
* Module defining viewSnapshot (Originally NewWindowAction). Created by vwoeltje on 11/18/14.
*/
define(
["painterro", "zepto"],
function (Painterro, $) {
var annotationStruct = {
title: "Annotate Snapshot",
template: "annotate-snapshot",
options: [{
name: "OK",
key: "ok",
description: "save annotation"
},
{
name: "Cancel",
key: "cancel",
description: "cancel editing"
}]
};
function AnnotateSnapshot(dialogService, dndService, $rootScope, context) {
context = context || {};
// Choose the object to be opened into a new tab
this.domainObject = context.selectedObject || context.domainObject;
this.dialogService = dialogService;
this.dndService = dndService;
this.$rootScope = $rootScope;
}
AnnotateSnapshot.prototype.perform = function ($event, snapshot, embedId, entryId) {
var DOMAIN_OBJECT = this.domainObject;
var ROOTSCOPE = this.$rootScope;
var painterro;
var save = false;
var controller = ['$scope', '$timeout', function PainterroController($scope, $timeout) {
$(document.body).find('.l-dialog .outer-holder').addClass('annotation-dialog');
// Timeout is necessary because Painterro uses document.getElementById, and mct-include
// hasn't added the dialog to the DOM yet.
$timeout(function () {
painterro = Painterro({
id: 'snap-annotation',
activeColor: '#ff0000',
activeColorAlpha: 1.0,
activeFillColor: '#fff',
activeFillColorAlpha: 0.0,
backgroundFillColor: '#000',
backgroundFillColorAlpha: 0.0,
defaultFontSize: 16,
defaultLineWidth: 2,
defaultTool: 'ellipse',
hiddenTools: ['save', 'open', 'close', 'eraser', 'pixelize', 'rotate', 'settings', 'resize'],
translation: {
name: 'en',
strings: {
lineColor: 'Line',
fillColor: 'Fill',
lineWidth: 'Size',
textColor: 'Color',
fontSize: 'Size',
fontStyle: 'Style'
}
},
saveHandler: function (image, done) {
if (save) {
if (entryId && embedId) {
var elementPos = DOMAIN_OBJECT.model.entries.map(function (x) {
return x.createdOn;
}).indexOf(entryId);
var entryEmbeds = DOMAIN_OBJECT.model.entries[elementPos].embeds;
var embedPos = entryEmbeds.map(function (x) {
return x.id;
}).indexOf(embedId);
saveSnap(image.asBlob(), embedPos, elementPos, DOMAIN_OBJECT);
}else {
ROOTSCOPE.snapshot = {'src': image.asDataURL('image/png'),
'modified': Date.now()};
}
}
done(true);
}
}).show(snapshot);
});
}];
annotationStruct.model = {'controller': controller};
function saveNotes(param) {
if (param === 'ok') {
save = true;
}else {
save = false;
ROOTSCOPE.snapshot = "annotationCancelled";
}
painterro.save();
}
function rejectNotes() {
save = false;
ROOTSCOPE.snapshot = "annotationCancelled";
painterro.save();
}
function saveSnap(url, embedPos, entryPos, domainObject) {
var snap = false;
if (embedPos !== -1 && entryPos !== -1) {
var reader = new window.FileReader();
reader.readAsDataURL(url);
reader.onloadend = function () {
snap = reader.result;
domainObject.useCapability('mutation', function (model) {
if (model.entries[entryPos]) {
model.entries[entryPos].embeds[embedPos].snapshot = {
'src': snap,
'type': url.type,
'size': url.size,
'modified': Date.now()
};
model.entries[entryPos].embeds[embedPos].id = Date.now();
}
});
};
}
}
this.dialogService.getUserChoice(annotationStruct)
.then(saveNotes, rejectNotes);
};
return AnnotateSnapshot;
}
);

View File

@ -1,204 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
[],
function () {
var SNAPSHOT_TEMPLATE = '<mct-representation key="\'draggedEntry\'"' +
'class="t-rep-frame holder"' +
'mct-object="selObj">' +
'</mct-representation>';
var NEW_TASK_FORM = {
name: "Create a Notebook Entry",
hint: "Please select one Notebook",
sections: [{
rows: [{
name: 'Entry',
key: 'entry',
control: 'textarea',
required: false,
"cssClass": "l-textarea-sm"
},
{
name: 'Embed Type',
key: 'withSnapshot',
control: 'snapshot-select',
"options": [
{
"name": "Link and Snapshot",
"value": true
},
{
"name": "Link only",
"value": false
}
]
},
{
name: 'Embed',
key: 'embedObject',
control: 'embed-control'
},
{
name: 'Save in Notebook',
key: 'saveNotebook',
control: 'locator',
validate: validateLocation
}]
}]
};
function NewEntryContextual($compile, $rootScope, dialogService, notificationService, linkService, context) {
context = context || {};
this.domainObject = context.selectedObject || context.domainObject;
this.dialogService = dialogService;
this.notificationService = notificationService;
this.linkService = linkService;
this.$rootScope = $rootScope;
this.$compile = $compile;
}
function validateLocation(newParentObj) {
return newParentObj.model.type === 'notebook';
}
NewEntryContextual.prototype.perform = function () {
var self = this;
var domainObj = this.domainObject;
var notification = this.notificationService;
var dialogService = this.dialogService;
var rootScope = this.$rootScope;
rootScope.newEntryText = '';
// // Create the overlay element and add it to the document's body
this.$rootScope.selObj = domainObj;
this.$rootScope.selValue = "";
var newScope = rootScope.$new();
newScope.selObj = domainObj;
newScope.selValue = "";
this.$compile(SNAPSHOT_TEMPLATE)(newScope);
this.$rootScope.$watch("snapshot", setSnapshot);
function setSnapshot(value) {
if (value === "annotationCancelled") {
rootScope.snapshot = rootScope.lastValue;
rootScope.lastValue = '';
} else if (value && value !== rootScope.lastValue) {
var overlayModel = {
title: NEW_TASK_FORM.name,
message: NEW_TASK_FORM.message,
structure: NEW_TASK_FORM,
value: {'entry': rootScope.newEntryText || ""}
};
rootScope.currentDialog = overlayModel;
dialogService.getDialogResponse(
"overlay-dialog",
overlayModel,
function () {
return overlayModel.value;
}
).then(addNewEntry);
rootScope.lastValue = value;
}
}
function addNewEntry(options) {
options.selectedModel = options.embedObject.getModel();
options.cssClass = options.embedObject.getCapability('type').typeDef.cssClass;
if (self.$rootScope.snapshot) {
options.snapshot = self.$rootScope.snapshot;
self.$rootScope.snapshot = undefined;
}else {
options.snapshot = undefined;
}
if (!options.withSnapshot) {
options.snapshot = '';
}
createSnap(options);
}
function createSnap(options) {
options.saveNotebook.useCapability('mutation', function (model) {
var entries = model.entries;
var lastEntry = entries[entries.length - 1];
var date = Date.now();
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
model.entries.push({
'id': date,
'createdOn': date,
'text': options.entry,
'embeds': [{'type': options.embedObject.getId(),
'id': '' + date,
'cssClass': options.cssClass,
'name': options.selectedModel.name,
'snapshot': options.snapshot
}]
});
}else {
model.entries[entries.length - 1] = {
'id': date,
'createdOn': date,
'text': options.entry,
'embeds': [{'type': options.embedObject.getId(),
'id': '' + date,
'cssClass': options.cssClass,
'name': options.selectedModel.name,
'snapshot': options.snapshot
}]
};
}
});
notification.info({
title: "Notebook Entry created"
});
}
};
NewEntryContextual.appliesTo = function (context) {
var domainObject = context.domainObject;
if (domainObject) {
if (domainObject.getModel().type === 'notebook') {
// do not allow in context of a notebook
return false;
} else if (domainObject.getModel().type.includes('imagery')) {
// do not allow in the context of an object with imagery
// (because of cross domain issue with snapshot)
return false;
}
}
return true;
};
return NewEntryContextual;
}
);

View File

@ -1,130 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
['zepto'],
function ($) {
function SnapshotAction (exportImageService, dialogService, context) {
this.exportImageService = exportImageService;
this.dialogService = dialogService;
this.domainObject = context.domainObject;
}
SnapshotAction.prototype.perform = function () {
var elementToSnapshot =
$(document.body).find(".overlay .object-holder")[0] ||
$(document.body).find("[key='representation.selected.key']")[0];
$(elementToSnapshot).addClass("s-status-taking-snapshot");
this.exportImageService.exportPNGtoSRC(elementToSnapshot).then(function (blob) {
$(elementToSnapshot).removeClass("s-status-taking-snapshot");
if (blob) {
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
this.saveSnapshot(reader.result, blob.type, blob.size);
}.bind(this);
}
}.bind(this));
};
SnapshotAction.prototype.saveSnapshot = function (imageURL, imageType, imageSize) {
var taskForm = this.generateTaskForm(),
domainObject = this.domainObject,
domainObjectId = domainObject.getId(),
cssClass = domainObject.getCapability('type').typeDef.cssClass,
name = domainObject.model.name;
this.dialogService.getDialogResponse(
'overlay-dialog',
taskForm,
function () {
return taskForm.value;
}
).then(function (options) {
var snapshotObject = {
src: imageURL,
type: imageType,
size: imageSize
};
options.notebook.useCapability('mutation', function (model) {
var date = Date.now();
model.entries.push({
id: 'entry-' + date,
createdOn: date,
text: options.entry,
embeds: [{
name: name,
cssClass: cssClass,
type: domainObjectId,
id: 'embed-' + date,
createdOn: date,
snapshot: snapshotObject
}]
});
});
});
};
SnapshotAction.prototype.generateTaskForm = function () {
var taskForm = {
name: "Create a Notebook Entry",
hint: "Please select a Notebook",
sections: [{
rows: [{
name: 'Entry',
key: 'entry',
control: 'textarea',
required: false,
"cssClass": "l-textarea-sm"
},
{
name: 'Save in Notebook',
key: 'notebook',
control: 'locator',
validate: validateLocation
}]
}]
};
var overlayModel = {
title: taskForm.name,
message: 'AHAHAH',
structure: taskForm,
value: {'entry': ""}
};
function validateLocation(newParentObj) {
return newParentObj.model.type === 'notebook';
}
return overlayModel;
};
return SnapshotAction;
}
);

View File

@ -275,7 +275,6 @@ function (
function menuClickHandler(e) {
e.stopPropagation();
window.setTimeout(dismiss, 300);
}
// Dismiss any menu which was already showing

View File

@ -107,10 +107,10 @@ function (
EntryController.prototype.dropOnEntry = function (entryid, event) {
var data = event.dataTransfer.getData('domainObject');
var data = event.dataTransfer.getData('openmct/domain-object-path');
if (data) {
var selectedObject = JSON.parse(data),
var selectedObject = JSON.parse(data)[0],
selectedObjectId = selectedObject.identifier.key,
cssClass = this.openmct.types.get(selectedObject.type),
entryPos = this.entryPosById(entryid),

View File

@ -1,65 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
/**
* Module defining NewEntryController. */
define(
[],
function () {
function NewEntryController($scope,$rootScope) {
$scope.snapshot = undefined;
$scope.snapToggle = true;
$scope.entryText = '';
var annotateAction = $rootScope.selObj.getCapability('action').getActions({key: 'annotate-snapshot'})[0];
$scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = $rootScope.selObj;
$scope.objectName = $rootScope.selObj.getModel().name;
$scope.cssClass = $rootScope.selObj.getCapability('type').typeDef.cssClass;
$scope.annotateSnapshot = function ($event) {
if ($rootScope.currentDialog.value) {
$rootScope.newEntryText = $scope.$parent.$parent.ngModel.entry;
$rootScope.currentDialog.cancel();
annotateAction.perform($event, $rootScope.snapshot.src);
$rootScope.currentDialog = undefined;
}
};
function updateSnapshot(img) {
$scope.snapshot = img;
}
// Update set of actions whenever the action capability
// changes or becomes available.
$rootScope.$watch("snapshot", updateSnapshot);
$rootScope.$watch("selValue", toggleEmbed);
function toggleEmbed(value) {
$scope.snapToggle = value;
}
}
return NewEntryController;
}
);

View File

@ -27,7 +27,7 @@ define([
'../../res/templates/notebook.html',
'../../res/templates/entry.html',
'../../res/templates/embed.html',
'../../../../ui/components/controls/search.vue'
'../../../../ui/components/search.vue'
],
function (
Vue,
@ -120,8 +120,8 @@ function (
var date = Date.now(),
embed;
if (event.dataTransfer && event.dataTransfer.getData('domainObject')) {
var selectedObject = JSON.parse(event.dataTransfer.getData('domainObject')),
if (event.dataTransfer && event.dataTransfer.getData('openmct/domain-object-path')) {
var selectedObject = JSON.parse(event.dataTransfer.getData('openmct/domain-object-path'))[0],
selectedObjectId = selectedObject.identifier.key,
cssClass = this.openmct.types.get(selectedObject.type);

View File

@ -1,44 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
/**
* Module defining SelectSnapshotController. */
define(
[],
function () {
function SelectSnapshotController($scope,$rootScope) {
$scope.selectModel = true;
function selectprint(value) {
$rootScope.selValue = value;
$scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = value;
}
$scope.$watch("selectModel", selectprint);
}
return SelectSnapshotController;
}
);

View File

@ -1,86 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(['zepto'], function ($) {
function MCTSnapshot($rootScope, $document, exportImageService, dialogService, notificationService) {
var document = $document[0];
function link($scope, $element, $attrs) {
var objectElement = $(document.body).find(".overlay .object-holder")[0] || $(document.body).find("[key='representation.selected.key']")[0],
takeSnapshot,
makeImg,
saveImg;
$(objectElement).addClass("s-status-taking-snapshot");
saveImg = function (url, entryId, embedId) {
$scope.$parent.$parent.$parent.saveSnap(url, embedId, entryId);
};
makeImg = function (el) {
var scope = $scope;
exportImageService.exportPNGtoSRC(el).then(function (img) {
$(objectElement).removeClass("s-status-taking-snapshot");
if (img) {
if ($element[0].dataset.entry && $element[0].dataset.embed) {
saveImg(img, +$element[0].dataset.entry, +$element[0].dataset.embed);
} else {
var reader = new window.FileReader();
reader.readAsDataURL(img);
reader.onloadend = function () {
$($element[0]).attr("data-snapshot", reader.result);
$rootScope.snapshot = {
'src': reader.result,
'type': img.type,
'size': img.size,
'modified': Date.now()
};
scope.$destroy();
};
}
}
});
};
takeSnapshot = function () {
makeImg(objectElement);
};
takeSnapshot();
$scope.$on('$destroy', function () {
$element.remove();
});
}
return {
restrict: 'A',
link: link
};
}
return MCTSnapshot;
});

View File

@ -20,13 +20,13 @@
at runtime from the About dialog for additional information.
-->
<div class="gl-plot plot-legend-{{legend.get('position')}} {{legend.get('expanded')? 'plot-legend-expanded' : 'plot-legend-collapsed'}}">
<div class="gl-plot-legend flex-elem l-flex-row"
<div class="gl-plot-legend"
ng-class="{ 'hover-on-plot': !!highlights.length }"
ng-show="legend.get('position') !== 'hidden'">
<span class="view-control flex-elem"
ng-class="{ expanded: legend.get('expanded') }"
<div class="gl-plot-legend__view-control c-disclosure-triangle is-enabled"
ng-class="{ 'c-disclosure-triangle--expanded': legend.get('expanded') }"
ng-click="legend.set('expanded', !legend.get('expanded'));">
</span>
</div>
<!-- COLLAPSED PLOT LEGEND -->
<div class="plot-wrapper-collapsed-legend">
@ -52,7 +52,7 @@
</div>
<!-- EXPANDED PLOT LEGEND -->
<div class="plot-wrapper-expanded-legend flex-elem grows">
<div class="plot-wrapper-expanded-legend">
<table>
<thead>
<tr>
@ -133,7 +133,9 @@
ng-style="{
left: (tickWidth + 30) + 'px'
}">
<span class="t-object-alert t-alert-unsynced" title="This plot is not currently displaying the latest data. Reset Pan/zoom to return to view latest data."></span>
<span class="t-object-alert t-alert-unsynced"
title="This plot is not currently displaying the latest data.
Reset Pan/zoom to return to view latest data."></span>
<div class="gl-plot-display-area">
<mct-ticks axis="xAxis">
<div class="gl-plot-hash hash-v"

View File

@ -20,20 +20,20 @@
at runtime from the About dialog for additional information.
-->
<div ng-controller="PlotOptionsController">
<ul class="tree">
<ul class="tree c-tree">
<h2 title="Plot series display properties in this object">Plot Series</h2>
<li ng-repeat="series in config.series.models">
<span class="tree-item menus-to-left">
<span class='ui-symbol view-control flex-elem'
ng-class="{ expanded: series.expanded }"
<div class="c-tree__item menus-to-left">
<span class='c-disclosure-triangle is-enabled flex-elem'
ng-class="{ 'c-disclosure-triangle--expanded': series.expanded }"
ng-click="series.expanded = !series.expanded">
</span>
<mct-representation
class="rep-object-label"
class="rep-object-label c-tree__item__label"
key="'label'"
mct-object="series.oldObject">
</mct-representation>
</span>
</div>
<ul class="grid-properties" ng-show="series.expanded">
<li class="grid-row">
<div class="grid-cell label"
@ -70,17 +70,9 @@
<div class="grid-cell label"
title="The plot line and marker color for this series.">Color</div>
<div class="grid-cell value">
<!-- TODO: get this into a class -->
<span class="color-swatch"
<span class="c-color-swatch"
ng-style="{
'background': series.get('color').asHexString(),
'display': 'inline-block',
'border': '1px solid rgba(255, 255, 255, 0.2)',
'height': '10px',
'width': '10px',
'vertical-align': 'middle',
'margin-left': '3px',
'margin-top': -'2px'
'background': series.get('color').asHexString()
}">
</span>
</div>

View File

@ -20,49 +20,45 @@
at runtime from the About dialog for additional information.
-->
<div ng-controller="PlotOptionsController">
<ul class="tree l-inspector-part">
<h2 title="Display properties for this object">Plot Series Options</h2>
<ul class="tree c-tree">
<h2 title="Display properties for this object">Plot Series</h2>
<li ng-repeat="series in plotSeries"
ng-controller="PlotSeriesFormController"
form-model="series">
<span class="tree-item menus-to-left">
<span class='ui-symbol view-control flex-elem'
ng-class="{ expanded: expanded }"
<div class="c-tree__item menus-to-left">
<span class='c-disclosure-triangle is-enabled flex-elem'
ng-class="{ 'c-disclosure-triangle--expanded': expanded }"
ng-click="expanded = !expanded">
</span>
<mct-representation class="rep-object-label"
<mct-representation class="rep-object-label c-tree__item__label"
key="'label'"
mct-object="series.oldObject">
</mct-representation>
</span>
</div>
<ul class="grid-properties" ng-show="expanded">
<li class="grid-row">
<!-- Value to be displayed -->
<div class="grid-cell label"
title="The field to be plotted as a value for this series.">Value</div>
<div class="grid-cell value">
<div class="select">
<select ng-model="form.yKey">
<option ng-repeat="option in yKeyOptions"
value="{{option.value}}"
ng-selected="option.value == form.yKey">
{{option.name}}
</option>
</select>
</div>
<select ng-model="form.yKey">
<option ng-repeat="option in yKeyOptions"
value="{{option.value}}"
ng-selected="option.value == form.yKey">
{{option.name}}
</option>
</select>
</div>
</li>
<li class="grid-row">
<div class="grid-cell label"
title="The line rendering style for this series.">Line Style</div>
<div class="grid-cell value">
<div class="select">
<select ng-model="form.interpolate">
<option value="none">None</option>
<option value="linear">Linear interpolate</option>
<option value="stepAfter">Step after</option>
</select>
</div>
<select ng-model="form.interpolate">
<option value="none">None</option>
<option value="linear">Linear interpolate</option>
<option value="stepAfter">Step after</option>
</select>
</div>
</li>
<li class="grid-row">
@ -78,7 +74,7 @@
<li class="grid-row" ng-show="form.markers || form.alarmMarkers">
<div class="grid-cell label"
title="The size of regular and alarm markers for this series.">Marker Size:</div>
<div class="grid-cell value"><input class="sm" type="text" ng-model="form.markerSize"/></div>
<div class="grid-cell value"><input class="c-input--flex" type="text" ng-model="form.markerSize"/></div>
</li>
<li class="grid-row"
ng-controller="ClickAwayController as toggle"
@ -86,14 +82,14 @@
<div class="grid-cell label"
title="Manually set the plot line and marker color for this series.">Color</div>
<div class="grid-cell value">
<div class="s-menu-button" ng-click="toggle.toggle()">
<span class="color-swatch" ng-style="{ background: series.get('color').asHexString() }">
<div class="c-click-swatch c-click-swatch--menu" ng-click="toggle.toggle()">
<span class="c-color-swatch"
ng-style="{ background: series.get('color').asHexString() }">
</span>
</div>
<div class="l-inline-palette" ng-show="toggle.isActive()">
<!-- TODO: redo this as a grid -->
<div class="l-palette-row" ng-repeat="group in config.series.palette.groups()">
<div class="l-palette-item s-palette-item"
<div class="c-palette--inline c-palette__items" ng-show="toggle.isActive()">
<div class="u-contents" ng-repeat="group in config.series.palette.groups()">
<div class="c-palette__item"
ng-repeat="color in group"
ng-class="{ 'selected': series.get('color').equalTo(color) }"
ng-style="{ background: color.asHexString() }"
@ -115,7 +111,7 @@
<li class="grid-row">
<div class="grid-cell label"
title="Manually override how the Y axis is labeled.">Label</div>
<div class="grid-cell value"><input class="control" type="text" ng-model="form.label"/></div>
<div class="grid-cell value"><input class="c-input--flex" type="text" ng-model="form.label"/></div>
</li>
</ul>
<ul class="l-inspector-part">
@ -130,7 +126,7 @@
title="Percentage of padding above and below plotted min and max values. 0.1, 1.0, etc.">
Padding</div>
<div class="grid-cell value">
<input class="sm" type="text" ng-model="form.autoscalePadding"/>
<input class="c-input--flex" type="text" ng-model="form.autoscalePadding"/>
</div>
</li>
</ul>
@ -143,13 +139,13 @@
<div class="grid-cell label"
title="Minimum Y axis value.">Minimum Value</div>
<div class="grid-cell value">
<input class="sm" type="number" ng-model="form.range.min"/>
<input class="c-input--flex" type="number" ng-model="form.range.min"/>
</div>
</li>
<li class="grid-row">
<div class="grid-cell label"
title="Maximum Y axis value.">Maximum Value</div>
<div class="grid-cell value"><input class="sm" type="number" ng-model="form.range.max"/></div>
<div class="grid-cell value"><input class="c-input--flex" type="number" ng-model="form.range.max"/></div>
</li>
</ul>
</div>
@ -160,15 +156,13 @@
<div class="grid-cell label"
title="The position of the legend relative to the plot display area.">Position</div>
<div class="grid-cell value">
<div class="select">
<select ng-model="form.position">
<option value="hidden">Hidden</option>
<option value="top">Top</option>
<option value="right">Right</option>
<option value="bottom">Bottom</option>
<option value="left">Left</option>
</select>
</div>
<select ng-model="form.position">
<option value="hidden">Hidden</option>
<option value="top">Top</option>
<option value="right">Right</option>
<option value="bottom">Bottom</option>
<option value="left">Left</option>
</select>
</div>
</li>
<li class="grid-row">
@ -180,15 +174,13 @@
<div class="grid-cell label"
title="What to display in the legend when it's collapsed.">When collapsed show</div>
<div class="grid-cell value">
<div class="select">
<select ng-model="form.valueToShowWhenCollapsed">
<option value="none">nothing</option>
<option value="nearestTimestamp">nearest timestamp</option>
<option value="nearestValue">nearest Value</option>
<option value="min">minimum value</option>
<option value="max">maximum value</option>
</select>
</div>
<select ng-model="form.valueToShowWhenCollapsed">
<option value="none">Nothing</option>
<option value="nearestTimestamp">Nearest timestamp</option>
<option value="nearestValue">Nearest value</option>
<option value="min">Minimum value</option>
<option value="max">Maximum value</option>
</select>
</div>
</li>
<li class="grid-row">

View File

@ -137,8 +137,8 @@ define(
* @returns {promise}
*/
ExportImageService.prototype.exportPNGtoSRC = function (element) {
return this.renderElement(element, "png");
ExportImageService.prototype.exportPNGtoSRC = function (element, className) {
return this.renderElement(element, "png", className);
};
/**

View File

@ -40,7 +40,7 @@ define([
'./flexibleLayout/plugin',
'./tabs/plugin',
'../../platform/features/fixed/plugin',
'./preview/plugin'
'./LADTable/plugin'
], function (
_,
UTCTimeSystem,
@ -61,7 +61,7 @@ define([
FlexibleLayout,
Tabs,
FixedView,
PreviewPlugin
LADTable
) {
var bundleMap = {
LocalStorage: 'platform/persistence/local',
@ -176,7 +176,7 @@ define([
plugins.Tabs = Tabs;
plugins.FixedView = FixedView;
plugins.FlexibleLayout = FlexibleLayout;
plugins.Preview = PreviewPlugin.default;
plugins.LADTable = LADTable;
return plugins;
});

View File

@ -20,6 +20,9 @@ define([
canView: function (domainObject) {
return domainObject.type === 'summary-widget';
},
canEdit: function (domainObject) {
return domainObject.type === 'summary-widget';
},
view: function (domainObject) {
var statusService = openmct.$injector.get('statusService');
var objectId = objectUtils.makeKeyString(domainObject.identifier);
@ -32,7 +35,6 @@ define([
return new SummaryWidgetView(domainObject, openmct);
}
},
editable: true,
priority: function (domainObject) {
if (domainObject.type === 'summary-widget') {
return Number.MAX_VALUE;

View File

@ -15,14 +15,14 @@
v-for="(tab,index) in tabsList"
:key="index"
:class="[
{'is-current': tab=== currentTab},
{'is-current': tab=== currentTab},
tab.type.definition.cssClass
]"
@click="showTab(tab)">
<span class="c-button__label">{{tab.model.name}}</span>
</button>
</div>
<div class="c-tabs-view__object-holder"
<div class="c-tabs-view__object-holder"
v-for="(object, index) in tabsList"
:key="index"
:class="{'invisible': object !== currentTab}">
@ -86,7 +86,7 @@
</style>
<script>
import ObjectView from '../../../ui/components/layout/ObjectView.vue';
import ObjectView from '../../../ui/components/ObjectView.vue';
var unknownObjectType = {
definition: {
@ -147,7 +147,7 @@ export default {
this.setCurrentTab = true;
},
dragstart (e) {
if (e.dataTransfer.getData('domainObject')) {
if (e.dataTransfer.types.includes('openmct/domain-object-path')) {
this.isDragging = true;
}
},

View File

@ -35,6 +35,9 @@ define([
canView: function (domainObject) {
return domainObject.type === 'tabs';
},
canEdit: function (domainObject) {
return domainObject.type === 'tabs';
},
view: function (domainObject) {
let component;

View File

@ -79,8 +79,8 @@ define([
loadComposition() {
this.tableComposition = this.openmct.composition.get(this.domainObject);
if (this.tableComposition !== undefined){
this.tableComposition.load().then((composition)=>{
if (this.tableComposition !== undefined) {
this.tableComposition.load().then((composition) => {
composition = composition.filter(this.isTelemetryObject);
this.configuration.addColumnsForAllObjects(composition);
@ -122,7 +122,6 @@ define([
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
this.boundedRows.add(telemetryRows);
console.log('Loaded %i rows', telemetryRows.length);
this.decrementOutstandingRequests();
});
}
@ -131,7 +130,7 @@ define([
* @private
*/
incrementOutstandingRequests() {
if (this.outstandingRequests === 0){
if (this.outstandingRequests === 0) {
this.emit('outstanding-requests', true);
}
this.outstandingRequests++;
@ -143,7 +142,7 @@ define([
decrementOutstandingRequests() {
this.outstandingRequests--;
if (this.outstandingRequests === 0){
if (this.outstandingRequests === 0) {
this.emit('outstanding-requests', false);
}
}

View File

@ -64,6 +64,7 @@ define([
objectMutated(object) {
//Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible.
this.domainObject = object;
//Was it the configuration that changed?
if (!_.eq(object.configuration, this.oldConfiguration)) {
//Make copy of configuration, otherwise change detection is impossible if shared instance is being modified.
this.oldConfiguration = JSON.parse(JSON.stringify(this.getConfiguration()));
@ -91,16 +92,19 @@ define([
let columnsToRemove = this.columns[objectKeyString];
delete this.columns[objectKeyString];
let configuration = this.domainObject.configuration;
let configurationChanged = false;
columnsToRemove.forEach((column) => {
//There may be more than one column with the same key (eg. time system columns)
if (!this.hasColumnWithKey(column.getKey())) {
let configuration = this.domainObject.configuration;
delete configuration.hiddenColumns[column.getKey()];
// If there are no more columns with this key, delete any configuration, and trigger
// a column refresh.
this.openmct.objects.mutate(this.domainObject, 'configuration', configuration);
configurationChanged = true;
}
});
if (configurationChanged) {
this.updateConfiguration(configuration);
}
}
hasColumnWithKey(columnKey) {

View File

@ -36,13 +36,13 @@ define([
key: 'table',
name: 'Telemetry Table',
cssClass: 'icon-tabular-realtime',
editable: function(domainObject) {
return domainObject.type === 'table';
},
canView: function (domainObject) {
canView(domainObject) {
return domainObject.type === 'table' || domainObject.hasOwnProperty('telemetry');
},
view: function (domainObject) {
canEdit(domainObject) {
return domainObject.type === 'table';
},
view(domainObject) {
let csvExporter = new CSVExporter.default();
let table = new TelemetryTable(domainObject, openmct);
let component;
@ -67,7 +67,7 @@ define([
}
}
},
priority: function () {
priority() {
return 1;
}
}

View File

@ -34,8 +34,8 @@
<div class="c-telemetry-table__headers-w js-table__headers-w" ref="headersTable" :style="{ 'max-width': widthWithScroll}">
<table class="c-table__headers c-telemetry-table__headers">
<thead>
<tr>
<table-column-header
<tr class="c-telemetry-table__headers__name">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
:headerKey="key"
@ -50,7 +50,7 @@
:sortOptions="sortOptions"
>{{title}}</table-column-header>
</tr>
<tr>
<tr class="c-telemetry-table__headers__filter">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
@ -106,7 +106,6 @@
<style lang="scss">
@import "~styles/sass-base";
@import "~styles/table";
.c-telemetry-table__drop-target {
position: absolute;
@ -119,6 +118,9 @@
.c-telemetry-table {
// Table that displays telemetry in a scrolling body area
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
overflow: hidden;
th, td {
@ -128,6 +130,10 @@
vertical-align: middle; // This is crucial to hiding f**king 4px height injected by browser by default
}
td {
color: $colorTelemFresh;
}
/******************************* WRAPPERS */
&__headers-w {
// Wraps __headers table
@ -208,6 +214,22 @@
}
}
/******************************* EDITING */
.is-editing {
.c-telemetry-table__headers__name {
th[draggable],
th[draggable] > * {
cursor: move;
}
th[draggable]:hover {
$b: $editSelectableColor;
background: $b;
> * { background: $b; }
}
}
}
/******************************* LEGACY */
.s-status-taking-snapshot,
.overlay.snapshot {
@ -219,7 +241,7 @@
<script>
import TelemetryTableRow from './table-row.vue';
import search from '../../../ui/components/controls/search.vue';
import search from '../../../ui/components/search.vue';
import TableColumnHeader from './table-column-header.vue';
import _ from 'lodash';
@ -462,7 +484,7 @@ export default {
},
updateConfiguration(configuration) {
this.isAutosizeEnabled = configuration.autosize;
this.updateHeaders();
this.$nextTick().then(this.calculateColumnWidths);
},
@ -539,7 +561,7 @@ export default {
this.filterChanged = _.debounce(this.filterChanged, 500);
},
mounted() {
this.table.on('object-added', this.addObject);
this.table.on('object-removed', this.removeObject);
this.table.on('outstanding-requests', this.outstandingRequests);

View File

@ -55,7 +55,8 @@ $basicCr: 4px;
// Base colors
$colorBodyBg: #393939;
$colorBodyFg: #aaa;
$colorBodyFg: #aaaaaa;
$colorBodyFgEm: #fff;
$colorGenBg: #222;
$colorHeadBg: #262626;
$colorHeadFg: $colorBodyFg;
@ -64,7 +65,7 @@ $colorStatusBarFg: $colorBodyFg;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #00c0f6;
$colorKeyHov: #26d8ff;
$colorKeyFilter: invert(36%) sepia(76%) saturate(2514%) hue-rotate(170deg) brightness(99%) contrast(101%);
$colorKeyFilterHov: invert(63%) sepia(88%) saturate(3029%) hue-rotate(154deg) brightness(101%) contrast(100%);
$colorKeySelectedBg: $colorKey;
@ -110,32 +111,37 @@ $colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
// Base Colors
$dlSpread: 20%;
$editColor: #00c7c3;
$editColorAlt: #9971ff;
$editColorBgBase: darken($editColor, $dlSpread);
$editColorBg: rgba($editColorBgBase, 0.2);
$editColorFg: lighten($editColor, $dlSpread);
$editColorHov: lighten($editColor, 20%);
// Canvas
$editCanvasColorBg: $editColorBg; //#002524;
$editCanvasColorGrid: rgba($editColorBgBase, 0.4); //lighten($editCanvasColorBg, 3%);
$editCanvasColorBg: $editColorBg;
$editCanvasColorGrid: rgba($editColorBgBase, 0.4);
// Selectable
$editSelectableColor: #006563;
$editSelectableColorFg: lighten($editSelectableColor, 20%);
$editSelectableColorHov: lighten($editSelectableColor, 10%);
// Selectable selected
$editSelectableColorSelected: $editSelectableColorHov;
$editSelectableColorSelectedFg: lighten($editSelectableColorSelected, 30%);
$editSelectableColorFg: darken($editSelectableColor, 40%);
$editSelectableBorder: 1px dotted $editSelectableColor;
$editSelectableBorderHov: 1px dotted $editColor;
$editSelectableBorderHov: 1px dotted $editColorAlt;
$editSelectableBorderSelected: 1px solid $editColor;
$editSelectableShdwSelected: rgba($editColor, 0.75) 0 0 0 1px;
$editMoveableSelectedShdw: rgba($editColor, 0.5) 0 0 10px;
$editBorderDrilledIn: 1px dashed #9971ff;
$editBorderDrilledIn: 1px dashed $editColorAlt;
$colorGridLines: rgba($editColor, 0.2);
/************************************************** BROWSING */
$browseBorderSelectableHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseShdwSelectableHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
$browseSelectableBorderHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseSelectableShdwHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.6);
// Icons
$colorIconAlias: #4af6f3;
@ -165,6 +171,8 @@ $colorDropHint: $colorKey;
$colorDropHintBg: darken($colorDropHint, 10%);
$colorDropHintBgHov: $colorDropHint;
$colorDropHintFg: lighten($colorDropHint, 40%);
$colorDisclosureCtrl: rgba($colorBodyFg, 0.5);
$colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7);
// Menus
$colorMenuBg: lighten($colorBodyBg, 15%);
@ -217,20 +225,40 @@ $overlayColorFg: $colorMenuFg;
$overlayCr: $interiorMarginLg;
$overlayBrightnessAdjust: brightness(1.3);
// Toolbar
$toolBarEditColorBg: darken($editColorBgBase, 5%);
$toolBarEditColorFg: lighten($editColorBgBase, 20%);
$toolBarEditColorBtnFg: $toolBarEditColorFg;
$toolBarEditColorBtnBgHover: lighten($toolBarEditColorBg, 10%);
$toolBarEditColorBtnFgHover: lighten($toolBarEditColorFg, 10%);
// Indicator colors
$colorIndicatorAvailable: $colorKey;
$colorIndicatorDisabled: #444;
$colorIndicatorDisabled: #555555;
$colorIndicatorOn: $colorOk;
$colorIndicatorOff: #666;
$colorIndicatorOff: #777777;
// Limits and staleness colors//
// Staleness
$colorTelemFresh: lighten($colorBodyFg, 20%);
$colorTelemStale: darken($colorBodyFg, 20%);
$styleTelemStale: italic;
$colorLimitYellowBg: rgba(#ffaa00, 0.3);
$colorLimitYellowIc: #ffaa00;
$colorLimitRedBg: rgba(red, 0.3);
$colorLimitRedIc: red;
// Limits
$colorLimitYellowBg: #ac7300;
$colorLimitYellowFg: #ffe64d;
$colorLimitYellowIc: #ffb607;
$colorLimitRedBg: #940000;
$colorLimitRedFg: #ffa489;
$colorLimitRedIc: #ff4222;
// Status
$colorAlert: #ff3c00;
$colorWarningHi: #990000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
$colorCommand: #3693bd;
$colorInfo: #2294a2;
$colorOk: #33cc33;
// Bubble colors
$colorInfoBubbleBg: $colorMenuBg;
@ -250,8 +278,10 @@ $colorTabBorder: lighten($colorBodyBg, 10%);
$colorTabBodyBg: $colorBodyBg;
$colorTabBodyFg: lighten($colorBodyFg, 20%);
$colorTabHeaderBg: lighten($colorBodyBg, 10%);
$colorTabHeaderFg: lighten($colorBodyFg, 20%);
$colorTabHeaderFg: $colorBodyFg;
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: lighten($colorBodyBg, 5%);
$colorTabGroupHeaderFg: darken($colorTabHeaderFg, 10%);
// Plot
$colorPlotBg: rgba(black, 0.05);
@ -261,7 +291,6 @@ $opacityPlotHash: 0.2;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: darken($colorPlotFg, 20%);
$legendCollapsedNameMaxW: 50%;
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
// Tree
@ -277,8 +306,8 @@ $colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
$colorItemTreeEditingBg: darken($editColor, 20%);
$colorItemTreeEditingFg: $editColorFg;
$colorItemTreeEditingIcon: $editColorFg;
$colorItemTreeVC: rgba($colorBodyFg, 0.5);
$colorItemTreeVCHover: $colorKey;
$colorItemTreeVC: $colorDisclosureCtrl;
$colorItemTreeVCHover: $colorDisclosureCtrlHov;
$shdwItemTreeIcon: none;
// Images
@ -352,28 +381,6 @@ $createBtnTextTransform: uppercase;
box-shadow: rgba(black, 0.5) 0 0.5px 2px;
}
/**************************************************** NOT USED, LEAVE FOR NOW */
// Slider controls, not in use
/*
$sliderColorBase: $colorKey;
$sliderColorRangeHolder: rgba(black, 0.07);
$sliderColorRange: rgba($sliderColorBase, 0.2);
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
$sliderColorKnob: darken($sliderColorBase, 20%);
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
$sliderColorRangeValHovBg: $sliderColorRange;
$sliderColorRangeValHovFg: $colorBodyFg;
$sliderKnobW: 15px;
$sliderKnobR: 2px;
*/
// Content status
/*
$colorAlert: #ff3c00;
$colorWarningHi: #990000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
$colorCommand: #3693bd;
$colorInfo: #2294a2;
$colorOk: #33cc33;
*/
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect(linear-gradient(lighten($bg, 5%), $bg), $fg, lighten($bg, 20%), rgba(black, 0.5) 0 0.5px 3px);
}

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
/************************************************** MAELSTROM2 THEME CONSTANTS */
/************************************************** MAELSTROM THEME CONSTANTS */
// Fonts
@import url('https://fonts.googleapis.com/css?family=Chakra+Petch:400,600,700|Michroma|Teko:400,700');
@ -60,6 +60,7 @@ $basicCr: 4px;
// Base colors
$colorBodyBg: #393939;
$colorBodyFg: #ccc;
$colorBodyFgEm: #fff;
$colorGenBg: #222;
$colorHeadBg: #262626;
$colorHeadFg: $colorBodyFg;
@ -68,7 +69,7 @@ $colorStatusBarFg: $colorBodyFg;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #00c0f6;
$colorKeyHov: #26d8ff;
$colorKeyFilter: invert(36%) sepia(76%) saturate(2514%) hue-rotate(170deg) brightness(99%) contrast(101%);
$colorKeyFilterHov: invert(63%) sepia(88%) saturate(3029%) hue-rotate(154deg) brightness(101%) contrast(100%);
$colorKeySelectedBg: $colorKey;
@ -114,31 +115,37 @@ $colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
// Base Colors
$dlSpread: 20%;
$editColor: #00c7c3;
$editColorBg: darken($editColor, $dlSpread);
$editColorAlt: #9971ff;
$editColorBgBase: darken($editColor, $dlSpread);
$editColorBg: rgba($editColorBgBase, 0.2);
$editColorFg: lighten($editColor, $dlSpread);
$editColorHov: lighten($editColor, 20%);
// Canvas
$editCanvasColorBg: #002524;
$editCanvasColorGrid: darken($editCanvasColorBg, 2%);
$editCanvasColorBg: $editColorBg;
$editCanvasColorGrid: rgba($editColorBgBase, 0.4);
// Selectable
$editSelectableColor: #006563;
$editSelectableColorFg: lighten($editSelectableColor, 20%);
$editSelectableColorHov: lighten($editSelectableColor, 10%);
// Selectable selected
$editSelectableColorSelected: $editSelectableColorHov;
$editSelectableColorSelectedFg: lighten($editSelectableColorSelected, 30%);
$editSelectableColorFg: darken($editSelectableColor, 40%);
$editSelectableBorder: 1px dotted $editSelectableColor;
$editSelectableBorderHov: 1px dotted $editColor;
$editSelectableBorderHov: 1px dotted $editColorAlt;
$editSelectableBorderSelected: 1px solid $editColor;
$editSelectableShdwSelected: rgba($editColor, 0.75) 0 0 0 1px;
$editMoveableSelectedShdw: rgba($editColor, 0.5) 0 0 10px;
$editBorderDrilledIn: 1px dashed #9971ff;
$editBorderDrilledIn: 1px dashed $editColorAlt;
$colorGridLines: rgba($editColor, 0.2);
/************************************************** BROWSING */
$browseBorderSelectableHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseShdwSelectableHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
$browseSelectableBorderHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseSelectableShdwHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.5);
// Icons
$colorIconAlias: #4af6f3;
@ -168,6 +175,8 @@ $colorDropHint: $colorKey;
$colorDropHintBg: darken($colorDropHint, 10%);
$colorDropHintBgHov: $colorDropHint;
$colorDropHintFg: lighten($colorDropHint, 40%);
$colorDisclosureCtrl: rgba($colorBodyFg, 0.5);
$colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7);
// Menus
$colorMenuBg: lighten($colorBodyBg, 15%);
@ -220,20 +229,40 @@ $overlayColorFg: $colorMenuFg;
$overlayCr: $interiorMarginLg;
$overlayBrightnessAdjust: brightness(1.3);
// Toolbar
$toolBarEditColorBg: darken($editColorBgBase, 5%);
$toolBarEditColorFg: lighten($editColorBgBase, 20%);
$toolBarEditColorBtnFg: $toolBarEditColorFg;
$toolBarEditColorBtnBgHover: lighten($toolBarEditColorBg, 10%);
$toolBarEditColorBtnFgHover: lighten($toolBarEditColorFg, 10%);
// Indicator colors
$colorIndicatorAvailable: $colorKey;
$colorIndicatorDisabled: #444;
$colorIndicatorDisabled: #555555;
$colorIndicatorOn: $colorOk;
$colorIndicatorOff: #666;
$colorIndicatorOff: #777777;
// Limits and staleness colors//
// Staleness
$colorTelemFresh: lighten($colorBodyFg, 20%);
$colorTelemStale: darken($colorBodyFg, 20%);
$styleTelemStale: italic;
$colorLimitYellowBg: rgba(#ffaa00, 0.3);
$colorLimitYellowIc: #ffaa00;
$colorLimitRedBg: rgba(red, 0.3);
$colorLimitRedIc: red;
// Limits
$colorLimitYellowBg: #ac7300;
$colorLimitYellowFg: #ffe64d;
$colorLimitYellowIc: #ffb607;
$colorLimitRedBg: #940000;
$colorLimitRedFg: #ffa489;
$colorLimitRedIc: #ff4222;
// Status
$colorAlert: #ff3c00;
$colorWarningHi: #990000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
$colorCommand: #3693bd;
$colorInfo: #2294a2;
$colorOk: #33cc33;
// Bubble colors
$colorInfoBubbleBg: $colorMenuBg;
@ -253,8 +282,10 @@ $colorTabBorder: lighten($colorBodyBg, 10%);
$colorTabBodyBg: $colorBodyBg;
$colorTabBodyFg: lighten($colorBodyFg, 20%);
$colorTabHeaderBg: lighten($colorBodyBg, 10%);
$colorTabHeaderFg: lighten($colorBodyFg, 20%);
$colorTabHeaderFg: $colorBodyFg;
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: lighten($colorBodyBg, 5%);
$colorTabGroupHeaderFg: darken($colorTabHeaderFg, 10%);
// Plot
$colorPlotBg: rgba(black, 0.05);
@ -264,7 +295,6 @@ $opacityPlotHash: 0.2;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: darken($colorPlotFg, 20%);
$legendCollapsedNameMaxW: 50%;
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
// Tree
@ -280,8 +310,8 @@ $colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
$colorItemTreeEditingBg: darken($editColor, 20%);
$colorItemTreeEditingFg: $editColorFg;
$colorItemTreeEditingIcon: $editColorFg;
$colorItemTreeVC: rgba($colorBodyFg, 0.5);
$colorItemTreeVCHover: $colorKey;
$colorItemTreeVC: $colorDisclosureCtrl;
$colorItemTreeVCHover: $colorDisclosureCtrlHov;
$shdwItemTreeIcon: none;
// Images
@ -355,6 +385,10 @@ $createBtnTextTransform: uppercase;
box-shadow: rgba(black, 0.5) 0 0.5px 2px;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect(linear-gradient(lighten($bg, 5%), $bg), $fg, lighten($bg, 20%), rgba(black, 0.5) 0 0.5px 3px);
}
/**************************************************** OVERRIDES */
.c-frame {
&:not(.no-frame) {
@ -369,4 +403,4 @@ $createBtnTextTransform: uppercase;
border-right: $bLR !important;;
padding: 5px 10px 10px 10px !important;
}
}
}

View File

@ -56,6 +56,7 @@ $basicCr: 4px;
// Base colors
$colorBodyBg: #fcfcfc;
$colorBodyFg: #666;
$colorBodyFgEm: #333;
$colorGenBg: #fff;
$colorHeadBg: #eee;
$colorHeadFg: $colorBodyFg;
@ -109,33 +110,38 @@ $colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
/************************************************** EDITING */
// Base Colors
$dlSpread: 20%;
$editColor: #00c7c3;
$editColorBgBase: darken($editColor, $dlSpread);
$editColorBg: darken($editColor, $dlSpread);
$editColorFg: lighten($editColor, $dlSpread);
$editColor: #6afdff;
$editColorAlt: #9971ff;
$editColorBgBase: lighten($editColor, 20%);
$editColorBg: $editColor;
$editColorFg: darken($editColor, $dlSpread);
$editColorHov: lighten($editColor, 20%);
// Canvas
$editCanvasColorBg: #e6ffff;
$editCanvasColorGrid: darken($editCanvasColorBg, 10%);
$editCanvasColorBg: lighten($editColorBgBase, 5%);
$editCanvasColorGrid: $editColorBgBase;
// Selectable
$editSelectableColor: #acdad6;
$editSelectableColor: #00b3b1;
$editSelectableColorFg: darken($editSelectableColor, 20%);
$editSelectableColorHov: darken($editSelectableColor, 10%);
$editSelectableColorHov: darken($editSelectableColor, 20%);
// Selectable selected
$editSelectableColorSelected: $editColor; //$editSelectableColorHov;
$editSelectableColorSelected: #c60; //$editSelectableColorHov;
$editSelectableColorSelectedFg: lighten($editSelectableColorSelected, 50%);
$editSelectableColorFg: darken($editSelectableColor, 40%);
$editSelectableBorder: 1px dotted $editSelectableColor;
$editSelectableBorderHov: 1px dotted $editColor;
$editSelectableBorderSelected: 1px solid $editColor;
$editSelectableBorderHov: 1px dotted $editColorAlt;
$editSelectableBorderSelected: 1px solid $editSelectableColorSelected;
$editSelectableShdwSelected: rgba($editColor, 0.75) 0 0 0 1px;
$editMoveableSelectedShdw: rgba($editColor, 0.5) 0 0 10px;
$editBorderDrilledIn: 1px dashed #9971ff;
$editBorderDrilledIn: 1px dashed $editColorAlt;
$colorGridLines: rgba($editColor, 0.2);
/************************************************** BROWSING */
$browseBorderSelectableHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseShdwSelectableHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
$browseSelectableBorderHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseSelectableShdwHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.5);
// Icons
$colorIconAlias: #4af6f3;
@ -165,6 +171,8 @@ $colorDropHint: $colorKey;
$colorDropHintBg: lighten($colorDropHint, 30%);
$colorDropHintBgHov: lighten($colorDropHint, 40%);
$colorDropHintFg: lighten($colorDropHint, 0);
$colorDisclosureCtrl: rgba($colorBodyFg, 0.5);
$colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7);
// Menus
$colorMenuBg: lighten($colorBodyBg, 10%);
@ -217,20 +225,40 @@ $overlayColorFg: $colorMenuFg;
$overlayCr: $interiorMarginLg;
$overlayBrightnessAdjust: brightness(1);
// Toolbar
$toolBarEditColorBg: darken($editColorBgBase, 5%);
$toolBarEditColorFg: rgba(black, 0.7);
$toolBarEditColorBtnFg: $toolBarEditColorFg;
$toolBarEditColorBtnBgHover: lighten($toolBarEditColorBg, 10%);
$toolBarEditColorBtnFgHover: rgba(black, 0.9);
// Indicator colors
$colorIndicatorAvailable: $colorKey;
$colorIndicatorDisabled: #444;
$colorIndicatorOn: $colorOk;
$colorIndicatorOff: #666;
// Limits and staleness colors//
// Staleness
$colorTelemFresh: darken($colorBodyFg, 20%);
$colorTelemStale: lighten($colorBodyFg, 20%);
$styleTelemStale: italic;
$colorLimitYellowBg: rgba(#ffaa00, 0.3);
$colorLimitYellowIc: #ffaa00;
$colorLimitRedBg: rgba(red, 0.3);
$colorLimitRedIc: red;
// Limits
$colorLimitYellowBg: #ffe64d;
$colorLimitYellowFg: #7f4f20;
$colorLimitYellowIc: #e7a115;
$colorLimitRedBg: #ff0000;
$colorLimitRedFg: #fff;
$colorLimitRedIc: #ffa99a;
// Status
$colorAlert: #ff3c00;
$colorWarningHi: #990000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
$colorCommand: #3693bd;
$colorInfo: #2294a2;
$colorOk: #33cc33;
// Bubble colors
$colorInfoBubbleBg: $colorMenuBg;
@ -252,6 +280,8 @@ $colorTabBodyFg: darken($colorBodyFg, 20%);
$colorTabHeaderBg: darken($colorBodyBg, 10%);
$colorTabHeaderFg: darken($colorBodyFg, 20%);
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: darken($colorBodyBg, 5%);
$colorTabGroupHeaderFg: darken($colorTabGroupHeaderBg, 40%);
// Plot
$colorPlotBg: rgba(black, 0.05);
@ -261,7 +291,6 @@ $opacityPlotHash: 0.2;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: lighten($colorPlotFg, 20%);
$legendCollapsedNameMaxW: 50%;
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
// Tree
@ -277,8 +306,8 @@ $colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
$colorItemTreeEditingBg: $editColor;
$colorItemTreeEditingFg: $editColorFg;
$colorItemTreeEditingIcon: $editColorFg;
$colorItemTreeVC: rgba($colorBodyFg, 0.5);
$colorItemTreeVCHover: $colorKey;
$colorItemTreeVC: $colorDisclosureCtrl;
$colorItemTreeVCHover: $colorDisclosureCtrlHov;
$shdwItemTreeIcon: none;
// Images
@ -351,29 +380,6 @@ $createBtnTextTransform: uppercase;
background: $c;
}
/**************************************************** NOT USED, LEAVE FOR NOW */
// Slider controls, not in use
/*
$sliderColorBase: $colorKey;
$sliderColorRangeHolder: rgba(black, 0.07);
$sliderColorRange: rgba($sliderColorBase, 0.2);
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
$sliderColorKnob: lighten($sliderColorBase, 20%);
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
$sliderColorRangeValHovBg: $sliderColorRange;
$sliderColorRangeValHovFg: $colorBodyFg;
$sliderKnobW: 15px;
$sliderKnobR: 2px;
*/
// Content status
/*
$colorAlert: #ff3c00;
$colorWarningHi: #990000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
$colorCommand: #3693bd;
$colorInfo: #2294a2;
$colorOk: #33cc33;
*/
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect($bg, $fg, lighten($bg, 20%), none);
}

View File

@ -50,6 +50,15 @@ $gridItemMobile: 32px;
$tabularHeaderH: 22px;
$tabularTdPadLR: $itemPadLR;
$tabularTdPadTB: 2px;
/*************** Plots */
$plotYBarW: 60px;
$plotYLabelMinH: 20px;
$plotYLabelW: 10px;
$plotXBarH: 20px;
$plotLegendH: 20px;
$plotSwatchD: 8px;
$plotDisplayArea: (0, 0, $plotXBarH, $plotYBarW); // 1: Top, 2: right, 3: bottom, 4: left
$plotMinH: 95px;
/************************** MOBILE */
$mobileMenuIconD: 24px; // Used

View File

@ -31,11 +31,13 @@ button {
@include cButton();
}
.c-button--menu {
&:after {
content: $glyph-icon-arrow-down;
font-family: symbolsfont;
opacity: 0.5;
.c-button {
&--menu {
&:after {
content: $glyph-icon-arrow-down;
font-family: symbolsfont;
opacity: 0.5;
}
}
}
@ -44,23 +46,25 @@ button {
}
/********* Icon Buttons */
.c-click-icon {
.c-click-icon,
.c-click-swatch {
@include cClickIcon();
.c-click-icon__label {
margin-left: $interiorMargin;
}
&--menu {
&:after {
content: $glyph-icon-arrow-down;
font-family: symbolsfont;
font-size: 0.6em;
font-size: 0.7em;
margin-left: floor($interiorMarginSm * 0.8);
opacity: 0.5;
}
}
}
.c-click-icon {
.c-click-icon__label {
margin-left: $interiorMargin;
}
&--swatched {
// Color control, show swatch element
@ -101,9 +105,10 @@ button {
}
/********* Disclosure Triangle */
// Provides an arrow icon that when clicked expands an element to reveal its contents.
// Used in tree items. Always placed BEFORE an element.
// Used in tree items, plot legends. Always placed BEFORE an element.
.c-disclosure-triangle {
$d: 12px;
color: $colorDisclosureCtrl;
display: flex;
align-items: center;
justify-content: center;
@ -111,15 +116,22 @@ button {
width: $d;
position: relative;
&.is-enabled:before {
$s: .65;
content: $glyph-icon-arrow-right-equilateral;
display: block;
font-family: symbolsfont;
font-size: 1rem * $s;
position: absolute;
transform-origin: floor(($d / 2) * $s); // This is slightly better than 'center'
transition: transform 100ms ease-in-out;
&.is-enabled {
cursor: pointer;
&:hover {
color: $colorDisclosureCtrlHov;
}
&:before {
$s: .65;
content: $glyph-icon-arrow-right-equilateral;
display: block;
font-family: symbolsfont;
font-size: 1rem * $s;
transform-origin: center;
transition: transform 100ms ease-in-out;
}
}
&--expanded {
@ -154,6 +166,11 @@ input[type=number]::-webkit-outer-spin-button {
}
.c-input {
&--flex {
width: 100%;
min-width: 20px;
}
&--datetime {
// Sized for values such as 2018-09-28 22:32:33.468Z
width: 160px;
@ -211,6 +228,17 @@ input[type=number]::-webkit-outer-spin-button {
}
}
// SELECTS
select {
@include appearanceNone();
@include themedSelect();
background-repeat: no-repeat, no-repeat;
background-position: right .4em top 90%, 0 0;
border: none;
border-radius: $controlCr;
padding: 1px 20px 1px $interiorMargin;
}
/******************************************************** HYPERLINKS AND HYPERLINK BUTTONS */
.c-hyperlink {
&--link {
@ -252,6 +280,7 @@ input[type=number]::-webkit-outer-spin-button {
color: $colorMenuHovIc;
}
}
&:before {
color: $colorMenuIc;
font-size: 1em;
@ -335,16 +364,16 @@ input[type=number]::-webkit-outer-spin-button {
&__items {
flex: 1 1 auto;
display: grid;
grid-template-columns: repeat(10, [col] auto );
grid-template-columns: repeat(auto-fill, 12px);
grid-gap: 1px;
}
&__item {
$d: 16px;
$d: 12px;
border: 1px solid transparent;
cursor: pointer;
width: 16px; height: 16px;
min-width: $d; min-height: $d;
transition: $transOut;
&:hover {
@ -375,6 +404,12 @@ input[type=number]::-webkit-outer-spin-button {
}
}
/******************************************************** SWATCHES */
.c-color-swatch {
border: 1px solid rgba(#fff, 0.2);
box-shadow: rgba(#000, 0.2) 0 0 0 1px;
}
/******************************************************** TOOLBAR */
.c-ctrl-wrapper {
@include cCtrlWrapper();
@ -397,21 +432,31 @@ input[type=number]::-webkit-outer-spin-button {
.c-toolbar {
$p: $interiorMargin;
border-top: 1px solid $colorInteriorBorder;
background: $toolBarEditColorBg;
border-radius: $basicCr;
height: $p + 24px; // Need to standardize the height
padding-top: $p;
padding: $p;
&__separator {
@include cToolbarSeparator();
}
.c-click-icon,
.c-labeled-input {
color: $toolBarEditColorBtnFg;
}
.c-click-icon {
@include cControl();
$pLR: $interiorMargin - 1;
$pTB: 2px;
color: $colorBodyFg;
padding: $pTB $pLR;
&:hover {
background: $toolBarEditColorBtnBgHover !important;
color: $toolBarEditColorBtnFgHover !important;
}
&--swatched {
padding-bottom: floor($pTB / 2);
width: 2em; // Standardize the width
@ -441,6 +486,10 @@ input[type=number]::-webkit-outer-spin-button {
margin-left: $interiorMargin;
}
}
.c-palette {
min-width: 136px;
}
}
/********* Button Sets */
@ -453,10 +502,6 @@ input[type=number]::-webkit-outer-spin-button {
> * {
// Assume buttons are immediate descendants
flex: 0 0 auto;
+ * {
// margin-left: $interiorMarginSm;
}
}
+ .c-button-set {
@ -497,6 +542,54 @@ input[type=number]::-webkit-outer-spin-button {
> * + * { margin-left: $interiorMargin; }
}
/******************************************************** SLIDERS AND RANGE */
@mixin sliderKnobRound() {
$h: 12px;
@include themedButton();
cursor: pointer;
width: $h;
height: $h;
border-radius: 50% !important;
transform: translateY(-42%);
}
input[type="range"] {
// HTML5 range inputs
@include appearanceNone(); /* Hides the slider so that custom slider can be made */
background: transparent; /* Otherwise white in Chrome */
&:focus {
outline: none; /* Removes the blue border. */
}
// Thumb
&::-webkit-slider-thumb {
-webkit-appearance: none;
@include sliderKnobRound();
}
&::-moz-range-thumb {
border: none;
@include sliderKnobRound();
}
&::-ms-thumb {
border: none;
@include sliderKnobRound();
}
// Track
&::-webkit-slider-runnable-track {
width: 100%;
height: 3px;
@include sliderTrack();
}
&::-moz-range-track {
width: 100%;
height: 3px;
@include sliderTrack();
}
}
/***************************************************** DRAG AND DROP */
.c-drop-hint {
// Used in Tabs View, Flexible Grid Layouts
@ -545,3 +638,27 @@ input[type=number]::-webkit-outer-spin-button {
opacity: 0.9;
}
}
/***************************************************** LEGACY */
.l-btn-set {
// Fixes
display: flex;
align-items: center;
}
.h-local-controls {
&-overlay-content {
box-shadow: $colorBodyBg 0 0 0 2px;
display: inline-block;
position: absolute;
right: $interiorMargin; top: $interiorMargin;
z-index: 2;
}
&-trans {
// Has a translucent background plate
background: rgba($colorBodyBg, 0.8);
border-radius: $controlCr;
}
}

View File

@ -141,17 +141,22 @@ li {
// Local Controls: Controls placed in proximity to or overlaid on components and views
body.desktop .has-local-controls {
// Provides hover ability to show local controls
&:hover [class*="local-controls--hidden"] {
transition: opacity 50ms ease-in-out;
opacity: 1;
pointer-events: inherit;
}
[class*="local-controls--hidden"] {
[class*='local-controls--hidden'] {
transition: opacity 500ms ease-in-out;
opacity: 0;
pointer-events: none;
}
// Look down up to two levels and display hidden LC's on hover
&:hover {
> [class*='local-controls--hidden'],
> * > [class*='local-controls--hidden'],
> * > * > [class*='local-controls--hidden'] {
transition: opacity 50ms ease-in-out;
opacity: 1;
pointer-events: inherit;
}
}
}
/******************************************************** ICON BACKGROUNDS */
@ -174,30 +179,6 @@ body.desktop .has-local-controls {
}
}
//[class*="local-controls"] {
// // An explicit outer holder for controls. Typically placed in upper right.
// //font-size: 0.7rem;
// display: flex;
// align-items: center;
// justify-content: flex-end;
//
//
// &.h-local-controls-overlay-content {
// // Imagery controls
// $p: $interiorMargin;
// position: absolute;
// top: $p; right: $p;
// z-index: 2;
// }
//.l-btn-set,
//.s-button {
// &:not(:first-child) {
// margin-left: $interiorMargin;
// }
//}
//}
/******************************************************** SELECTION AND EDITING */
// Provides supporting styles for Display Layouts and augmented legacy Fixed Position view
@ -217,7 +198,7 @@ body.desktop .has-local-controls {
/*************************** SELECTION */
.u-inspectable {
&:hover {
box-shadow: $browseShdwSelectableHov;
box-shadow: $browseSelectableShdwHov;
}
}
@ -226,13 +207,14 @@ body.desktop .has-local-controls {
*:not(.is-drilled-in).c-frame {
border: $editSelectableBorder;
&:hover {
border: $editSelectableBorderHov;
&:not([s-selected]) {
&:hover {
border: $editSelectableBorderHov;
}
}
&[s-selected],
&.is-selected {
border: $editSelectableBorderSelected;
&[s-selected] {
box-shadow: $editSelectableShdwSelected;
> .c-frame-edit {
display: block; // Show the editing rect and handles
@ -244,7 +226,7 @@ body.desktop .has-local-controls {
border: $editBorderDrilledIn;
}
*[s-selected] {
.is-moveable {
cursor: move;
}
@ -526,42 +508,3 @@ a.disabled {
}
}
}
/************************** TEMP LEGACY FIXES */
.overlay {
.outer-holder {
background: $colorMenuBg;
color: $colorMenuFg !important;
}
}
.form .form-row {
.label {
color: $colorMenuFg !important;
}
.selector-list {
@include reactive-input();
background: $colorInputBg !important;
color: $colorInputFg !important;
}
}
.ui-symbol.view-control {
display: block;
transform-origin: center center;
&:before { content: $glyph-icon-arrow-right-equilateral; }
&.expanded {
transform: rotate(90deg);
}
}
.t-imagery {
display: contents;
}
.t-frame-outer {
min-width: 200px;
min-height: 200px;
}

614
src/styles-new/_legacy.scss Normal file
View File

@ -0,0 +1,614 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
/********************************************************************* PLOTS */
mct-plot {
display: contents;
}
/********************************************* STACKED PLOT LAYOUT */
.t-plot-stacked {
.l-view-section {
// Make this a flex container
display: flex;
flex-flow: column nowrap;
.gl-plot.child-frame {
mct-plot {
display: flex;
flex: 1 1 auto;
height: 100%;
position: relative;
}
flex: 1 1 auto;
&:not(:first-child) {
margin-top: $interiorMargin;
}
}
}
.s-status-timeconductor-unsynced .holder-plot {
.t-object-alert.t-alert-unsynced {
display: block;
}
}
}
.gl-plot {
color: $colorPlotFg;
display: flex;
font-size: 0.7rem;
position: relative;
width: 100%;
height: 100%;
min-height: $plotMinH;
/********************************************* AXIS AND DISPLAY AREA */
.plot-wrapper-axis-and-display-area {
margin-top: $interiorMargin; // Keep the top tick label from getting clipped
position: relative;
flex: 1 1 auto;
.t-object-alert {
position: absolute;
display: block;
font-size: 1.5em;
top: $interiorMarginSm;
left: $interiorMarginSm;
z-index: 2;
}
}
.gl-plot-wrapper-display-area-and-x-axis {
// Holds the plot area and the X-axis only
position: absolute;
top: nth($plotDisplayArea, 1);
right:0; //nth($plotDisplayArea, 2);
bottom: 0;
left: nth($plotDisplayArea, 4);
.gl-plot-display-area {
position: absolute;
top: 0;
right: 0;
bottom: nth($plotDisplayArea, 3);
left: 0;
}
.gl-plot-axis-area.gl-plot-x {
top: auto;
right: 0;
bottom: 0;
left: 0;
height: $plotXBarH;
width: auto;
overflow: hidden;
}
}
.gl-plot-axis-area {
position: absolute;
&.gl-plot-y {
top: nth($plotDisplayArea, 1);
right: auto;
bottom: nth($plotDisplayArea, 3);
left: 0;
width: $plotYBarW;
}
}
.gl-plot-coords {
box-sizing: border-box;
border-radius: $controlCr;
background: black;
color: lighten($colorBodyFg, 30%);
padding: 2px 5px;
position: absolute;
top: nth($plotDisplayArea,1) + $interiorMarginLg;
right: auto;
bottom: auto;
left: nth($plotDisplayArea,4) + $interiorMarginLg;
z-index: 10;
&:empty {
display: none;
}
}
.gl-plot-label,
.l-plot-label {
color: $colorPlotLabelFg;
position: absolute;
text-align: center;
&.gl-plot-x-label,
&.l-plot-x-label {
top: auto;
right: 0;
bottom: 0;
left: 0;
height: auto;
}
&.gl-plot-y-label,
&.l-plot-y-label {
$x: -50%;
$r: -90deg;
transform-origin: 50% 0;
transform: translateX($x) rotate($r);
display: inline-block;
margin-left: $interiorMargin; // Kick off the left edge
left: 0;
top: 50%;
white-space: nowrap;
}
}
.gl-plot-x-options,
.gl-plot-y-options {
$h: 24px;
position: absolute;
height: $h;
min-height: $h;
z-index: 2;
}
.gl-plot-x-options {
transform: translateX(-50%);
bottom: 0;
left: 50%;
}
.gl-plot-y-options {
transform: translateY(-50%);
min-width: 150px; // Need this due to enclosure of .select
top: 50%;
left: $plotYLabelW + $interiorMargin * 2;
}
.t-plot-display-controls {
position: absolute;
top: $interiorMargin;
right: $interiorMargin;
}
.gl-plot-hash {
position: absolute;
opacity: $opacityPlotHash;
&.hash-v {
border-right: 1px $colorPlotHash $stylePlotHash;
height: 100%;
}
&.hash-h {
border-bottom: 1px $colorPlotHash $stylePlotHash;
width: 100%;
}
}
}
.gl-plot-display-area,
.plot-display-area {
@if $colorPlotBg != none {
background-color: $colorPlotBg;
}
cursor: crosshair;
border: 1px solid $colorPlotAreaBorder;
}
.tick {
position: absolute;
border: 0 $colorPlotHash solid;
&.tick-x {
border-right-width: 1px;
height: 100%; // Assumption is that the tick will be in a holder that will set it's height;
}
}
.gl-plot-tick,
.tick-label {
@include reverseEllipsis();
font-size: 0.7rem;
position: absolute;
&.gl-plot-x-tick-label,
&.tick-label-x {
right: auto;
bottom: auto;
left: auto;
height: auto;
width: 20%;
margin-left: -10%;
text-align: center;
}
&.gl-plot-y-tick-label,
&.tick-label-y {
top: auto;
height: 1em;
width: auto;
margin-bottom: -0.5em;
text-align: right;
}
}
.gl-plot-tick {
&.gl-plot-x-tick-label {
top: $interiorMargin;
}
&.gl-plot-y-tick-label {
right: $interiorMargin;
left: $interiorMargin;
}
}
.tick-label {
&.tick-label-x {
top: 0;
}
&.tick-label-y {
right: 0;
left: 0;
}
}
.export-plot {
$bg: white;
$fg: black;
$gry: #999;
background: $bg !important;
z-index: -10;
.l-view-section {
$m: $interiorMargin;
top: $m !important;
right: $m;
bottom: $m;
left: $m;
.s-status-timeconductor-unsynced .holder-plot {
.t-object-alert.t-alert-unsynced {
display: none;
}
}
}
.gl-plot-display-area {
background: none !important;
border-color: $gry !important;
.gl-plot-local-controls,
.h-local-controls {
opacity: 0;
}
}
.gl-plot {
color: $fg;
.gl-plot-hash {
opacity: 0.1;
border-color: $fg;
}
}
table {
thead {
border-bottom: none;
th {
background: #eee;
border-left-color: $bg;
color: #666;
}
tr {
border: none;
}
}
tbody {
tr {
border-top: 1px solid #ccc;
}
td {
color: $fg;
}
}
}
}
/*************************************************************************** _LEGEND.SCSS */
.gl-plot-legend {
display: flex;
align-items: flex-start;
&__view-control {
padding-top: 2px;
margin-right: $interiorMarginSm;
}
table {
table-layout: fixed;
th,
td {
@include ellipsize(); // Note: this won't work if table-layout uses anything other than fixed.
padding: 1px 3px; // Tighter than standard tabular padding
//width: 1%;
}
}
&.hover-on-plot {
// User is hovering over the plot to get a value at a point
.hover-value-enabled {
background-color: $legendHoverValueBg;
border-radius: $smallCr;
padding: 0 $interiorMarginSm;
&.value-to-display-min:before {
content: 'MIN ';
}
&.value-to-display-max:before {
content: 'MAX ';
}
}
}
}
/***************** GENERAL STYLES, ALL STATES */
.plot-legend-item {
// General styles for legend items, both expanded and collapsed legend states
.plot-series-color-swatch {
border-radius: $smallCr;
border: 1px solid $colorBodyBg;
display: inline-block;
height: $plotSwatchD;
width: $plotSwatchD;
}
.plot-series-name {
display: inline;
}
.plot-series-value {
@include ellipsize();
}
}
.plot-wrapper-expanded-legend {
flex: 1 1 auto;
}
.gl-plot {
&.plot-legend-collapsed .plot-wrapper-expanded-legend { display: none; }
&.plot-legend-expanded .plot-wrapper-collapsed-legend { display: none; }
/***************** GENERAL STYLES, COLLAPSED */
&.plot-legend-collapsed {
// .plot-legend-item is a span of spans.
&.plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; }
&.plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; }
&.plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; }
&.plot-legend-left .gl-plot-legend { margin-right: $interiorMargin; }
.plot-legend-item {
display: flex;
align-items: center;
justify-content: stretch;
&:not(:first-child) {
margin-left: $interiorMarginLg;
}
.plot-series-swatch-and-name,
.plot-series-value {
@include ellipsize();
flex: 1 1 auto;
}
.plot-series-swatch-and-name {
margin-right: $interiorMarginSm;
}
.plot-series-value {
text-align: left;
}
}
}
/***************** GENERAL STYLES, EXPANDED */
&.plot-legend-expanded {
.gl-plot-legend {
max-height: 70%;
}
.plot-wrapper-expanded-legend {
overflow-y: auto;
}
}
/***************** TOP OR BOTTOM */
&.plot-legend-top,
&.plot-legend-bottom {
// General styles when legend is on the top or bottom
flex-direction: column;
&.plot-legend-collapsed {
// COLLAPSED ON TOP OR BOTTOM
.plot-wrapper-collapsed-legend {
display: flex;
flex: 1 1 auto;
overflow: hidden;
}
}
}
/***************** EITHER SIDE */
&.plot-legend-left,
&.plot-legend-right {
// If the legend is expanded, use flex-col instead so that the legend gets the width it needs.
&.plot-legend-expanded {
// EXPANDED, ON EITHER SIDE
flex-direction: column;
}
&.plot-legend-collapsed {
// COLLAPSED, ON EITHER SIDE
.gl-plot-legend {
max-height: inherit;
width: 25%;
}
.plot-wrapper-collapsed-legend {
display: flex;
flex-flow: column nowrap;
min-width: 0;
flex: 1 1 auto;
overflow-y: auto;
}
.plot-legend-item {
margin-bottom: 1px;
margin-left: 0;
flex-wrap: wrap;
.plot-series-swatch-and-name {
flex: 0 1 auto;
min-width: 20%;
}
.plot-series-value {
flex: 0 1 auto;
width: auto;
}
}
}
}
/***************** ON BOTTOM OR RIGHT */
&.plot-legend-right:not(.plot-legend-expanded),
&.plot-legend-bottom {
.gl-plot-legend {
order: 2;
}
.plot-wrapper-axis-and-display-area {
order: 1;
}
}
}
/********************************************************* CLOCKS AND TIMERS */
.c-clock,
.c-timer {
display: flex;
align-items: center;
font-size: 1.25em;
> * {
flex: 0 0 auto;
display: flex;
align-items: center;
}
&__value {
color: $colorBodyFgEm;
}
}
.c-clock {
> * + * { margin-left: $interiorMargin; }
}
.c-timer {
$ctrlW: 22px;
&__controls {
margin-right: 0;
min-width: 0;
overflow: hidden;
transition: $transOut;
width: 0;
.c-click-icon:before { font-size: 1em; }
}
&__direction {
font-size: 0.9em;
margin-right: $interiorMargin;
}
&__ng-controller {
font-size: 0;
width: 0;
}
&:hover {
.c-timer__controls {
transition: $transOut; // On purpose: want this to take a bit longer
margin-right: $interiorMargin;
width: $ctrlW * 2;
}
&.is-stopped .c-timer__controls { width: $ctrlW; }
}
&__direction,
&__value {
opacity: 0.5;
}
&.is-started {
.c-timer {
&__direction,
&__value {
opacity: 1;
}
}
}
}
/******************************************************************* VARIOUS */
.overlay {
.outer-holder {
background: $colorMenuBg;
color: $colorMenuFg !important;
}
}
.form .form-row {
.label {
color: $colorMenuFg !important;
}
.selector-list {
@include reactive-input();
background: $colorInputBg !important;
color: $colorInputFg !important;
}
}
.ui-symbol.view-control {
display: block;
transform-origin: center center;
&:before { content: $glyph-icon-arrow-right-equilateral; }
&.expanded {
transform: rotate(90deg);
}
}
.t-imagery {
display: contents;
}
.t-frame-outer {
min-width: 200px;
min-height: 200px;
}

View File

@ -60,6 +60,16 @@
width: $d;
}
@mixin appearanceNone() {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
&:focus {
outline: none;
}
}
@mixin isAlias() {
&:after {
color:$colorIconAlias;
@ -133,6 +143,12 @@
background-repeat: $repeatDir;
}
@mixin sliderTrack($bg: $scrollbarTrackColorBg) {
border-radius: 2px;
box-sizing: border-box;
background-color: $bg;
}
@mixin bgVertStripes($c: yellow, $a: 0.1, $d: 40px) {
background-image: linear-gradient(-90deg,
rgba($c, $a) 0%, rgba($c, $a) 50%,
@ -188,7 +204,7 @@
}
@mixin htmlInputReset() {
appearance: none;
@include appearanceNone();
background: transparent;
border: none;
border-radius: 0;
@ -257,6 +273,7 @@
display: inline-flex;
align-items: center;
justify-content: center;
line-height: $fs; // Remove effect on top and bottom padding
overflow: hidden;
&:before,
@ -266,6 +283,10 @@
flex: 0 0 auto;
}
&:before {
font-size: 0.9em;
}
&:after {
font-size: 0.8em;
}
@ -273,22 +294,25 @@
[class*="__label"] {
@include ellipsize();
display: block;
line-height: $fs; // Remove effect on top and bottom padding
font-size: $fs;
}
&[class*='icon'] > [class*="__label"] {
// When button holds both an icon and a label, provide margin between them.
margin-left: $interiorMarginSm;
}
}
@mixin cButton() {
@include cControl();
@include themedButton();
//@include buttonBehavior();
border-radius: $controlCr;
color: $colorBtnFg;
cursor: pointer;
padding: $interiorMargin floor($interiorMargin * 1.25);
&:after,
> * {
> * + * {
margin-left: $interiorMarginSm;
}
@ -323,13 +347,12 @@
// Make the icon bigger relative to its container
@include cControl();
$pLR: 4px;
$pTB: 3px;
$pTB: 4px;
background: none;
box-shadow: none;
border-radius: $controlCr;
color: $colorKey;
cursor: pointer;
padding: $pTB $pLR ;
padding: $pTB $pLR;
@include hover() {
background: $colorClickIconBgHov;
@ -342,6 +365,10 @@
// Needed for c-togglebutton.
font-size: 1.25em;
}
&[class*="--major"] {
color: $colorKey;
}
}
@mixin cCtrlWrapper {
@ -412,6 +439,13 @@
}
}
@mixin cSelect($bg, $fg, $arwClr, $shdw) {
$svgArwClr: str-slice(inspect($arwClr), 2, str-length(inspect($arwClr))); // Remove initial # in color value
background: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3e%3cpath fill='%23#{$svgArwClr}' d='M5 5l5-5H0z'/%3e%3c/svg%3e"), $bg;
color: $fg;
box-shadow: $shdw;
}
@mixin wrappedInput() {
// An input that is wrapped. Optionally includes a __label or icon element.
// Based on .c-search.
@ -500,5 +534,7 @@
}
@mixin test($c: deeppink, $a: 0.3) {
background: rgba($c, $a) !important;
background-color: rgba($c, $a) !important;
box-shadow: deeppink 0 0 10px 1px !important;
}

113
src/styles-new/_status.scss Normal file
View File

@ -0,0 +1,113 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
/*************************************************** MIXINS */
@mixin statusStyle($bg, $fg, $ic) {
background: $bg !important;
background-color: $bg !important;
color: $fg !important;
&:before {
color: $ic;
display: inline-block;
font-family: symbolsfont;
font-size: 0.7em;
margin-right: $interiorMargin;
}
}
@mixin elementStatusColors($c) {
// Sets bg and icon colors for elements
background: rgba($c, 0.5) !important;
&:before {
color: $c !important;
}
}
@mixin indicatorStatusColors($c) {
&:before, .count {
color: $c;
}
}
.is-limit--yellow {
@include statusStyle($colorLimitYellowBg, $colorLimitYellowFg, $colorLimitYellowIc);
&.is-limit--upr:before { content: $glyph-icon-arrow-up; }
&.is-limit--lwr:before { content: $glyph-icon-arrow-down; }
}
.is-limit--red {
@include statusStyle($colorLimitRedBg, $colorLimitRedFg, $colorLimitRedIc);
&.is-limit--upr:before { content: $glyph-icon-arrow-double-up; }
&.is-limit--lwr:before { content: $glyph-icon-arrow-double-down; }
}
/*************************************************** STATUS */
[class*='s-status'] {
&:before {
margin-right: $interiorMargin;
}
}
.s-status-warning-hi, .s-status-icon-warning-hi { @include elementStatusColors($colorWarningHi); }
.s-status-warning-lo, .s-status-icon-warning-lo { @include elementStatusColors($colorWarningLo); }
.s-status-diagnostic, .s-status-icon-diagnostic { @include elementStatusColors($colorDiagnostic); }
.s-status-info, .s-status-icon-info { @include elementStatusColors($colorInfo); }
.s-status-ok, .s-status-icon-ok { @include elementStatusColors($colorOk); }
.s-status-icon-warning-hi:before { content: $glyph-icon-alert-triangle; }
.s-status-icon-warning-lo:before { content: $glyph-icon-alert-rect; }
.s-status-icon-diagnostic:before { content: $glyph-icon-eye-open; }
.s-status-icon-info:before { content: $glyph-icon-info; }
.s-status-icon-ok:before { content: $glyph-icon-check; }
/*************************************************** INDICATOR COLORING */
.ls-indicator {
&.s-status-info {
@include indicatorStatusColors($colorInfo);
}
&.s-status-disabled {
@include indicatorStatusColors($colorIndicatorDisabled);
}
&.s-status-available {
@include indicatorStatusColors($colorIndicatorAvailable);
}
&.s-status-on,
&.s-status-enabled {
@include indicatorStatusColors($colorIndicatorOn);
}
&.s-status-off {
@include indicatorStatusColors($colorIndicatorOff);
}
&.s-status-caution,
&.s-status-warning,
&.s-status-alert {
@include indicatorStatusColors($colorStatusAlert);
}
&.s-status-error {
@include indicatorStatusColors($colorStatusError);
}
}

View File

@ -21,15 +21,41 @@
*****************************************************************************/
/******************************************************** TABLE */
table {
$minW: 50px;
width: 100%;
thead {
background: $colorTabHeaderBg;
th + th {
border-left: 1px solid $colorTabHeaderBorder;
}
}
tbody {
tr + tr {
border-top: 1px solid $colorTabBorder;
}
}
th, td {
white-space: nowrap;
min-width: $minW;
padding: $tabularTdPadTB $tabularTdPadLR;
}
td {
vertical-align: top;
}
}
.c-table {
// Can be used by any type of table, scrolling, LAD, etc.
$min-w: 50px;
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
width: 100%;
&__control-bar,
&__headers-w {
@ -37,21 +63,12 @@
}
/******************************* ELEMENTS */
th, td {
white-space: nowrap;
min-width: $min-w;
padding: $tabularTdPadTB $tabularTdPadLR;
}
td {
color: $colorTelemFresh;
vertical-align: top;
}
&__control-bar {
margin-bottom: $interiorMarginSm;
}
thead tr,
[class*="__header"] {
background: $colorTabHeaderBg;
@ -62,14 +79,20 @@
}
}
tbody,
&__body {
tr {
&:not(:first-child) {
border-top: 1px solid $colorTabBorder;
}
tr:not(.c-table__group-header) + tr:not(.c-table__group-header) {
border-top: 1px solid $colorTabBorder;
}
}
&__group-header {
// tr element found in LAD Table Sets
border-top: 1px solid $colorTabHeaderBorder;
background: $colorTabGroupHeaderBg;
td { color: $colorTabGroupHeaderFg; }
}
&--sortable {
.is-sorting {
&:after {
@ -88,4 +111,10 @@
cursor: pointer;
}
}
}
.c-lad-table {
th, td {
width: 33%; // Needed to prevent size jumping as values dynamically update
}
}

View File

@ -26,7 +26,10 @@
/******************** RENDERS CSS */
@import "glyphs";
@import "global";
@import "status";
@import "controls";
@import "table";
@import "legacy";
/******************** LEGACY CSS */
$output-bourbon-deprecation-warnings: false;

View File

@ -14,7 +14,7 @@
//@import "../styles/about";
//@import "../styles/text";
@import "../styles/icons";
@import "../styles/status";
//@import "../styles/status";
@import "../styles/data-status";
@import "../styles/helpers/bubbles";
@import "../styles/helpers/splitter";
@ -57,8 +57,8 @@
//!********************************* VIEWS *!
@import "../styles/fixed-position";
//@import "../styles/lists/tabular";
@import "../styles/plots/plots-main";
@import "../styles/plots/legend";
//@import "../styles/plots/plots-main";
//@import "../styles/plots/legend";
@import "../styles/iframe";
@import "../styles/views";
@import "../styles/items/item";
@ -69,11 +69,9 @@
//!********************************* TO BE MOVED *!
@import "../styles/autoflow";
@import "../styles/features/imagery";
@import "../styles/features/time-display";
//@import "../styles/features/time-display";
@import "../styles/widgets";
//
//!********************************* APP STARTUP *!
//@import "../styles/app-start";
@import "../styles/conductor/time-conductor-snow";
//@import "../styles/notebook/notebook-snow";

View File

@ -53,7 +53,7 @@
}
> .abs.outer-holder {
z-index: 72;
z-index: 70;
> .abs.inner-holder {
$m: $overlayMargin;
top: $m;

View File

@ -0,0 +1,5 @@
# Components
Components in this folder are intended for reuse in other parts of the
application. In order for components to be reused, they must not depend on
parent styling, and they should have minimum internal state.

View File

@ -0,0 +1,134 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
<template>
<div class="u-contents c-so-view has-local-controls"
:class="{
'c-so-view--no-frame': !hasFrame
}">
<div class="c-so-view__header">
<div class="c-so-view__header__start">
<div class="c-so-view__header__name"
:class="cssClass">
{{ domainObject && domainObject.name }}
</div>
<context-menu-drop-down
:object-path="objectPath">
</context-menu-drop-down>
</div>
<div class="c-so-view__header__end">
<div class="c-button icon-expand local-controls--hidden"></div>
</div>
</div>
<object-view class="c-so-view__object-view"
:object="domainObject"></object-view>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-so-view {
/*************************** HEADER */
&__header {
display: flex;
align-items: center;
&__start,
&__end {
display: flex;
flex: 1 1 auto;
}
&__end {
justify-content: flex-end;
}
&__name {
@include headerFont(1em);
display: flex;
&:before {
margin-right: $interiorMarginSm;
}
}
}
&--no-frame .c-so-view__header {
display: none;
}
&__name {
@include ellipsize();
@include headerFont(1.2em);
flex: 0 1 auto;
&:before {
// Object type icon
flex: 0 0 auto;
margin-right: $interiorMarginSm;
opacity: 0.5;
}
}
/*************************** OBJECT VIEW */
&__object-view {
flex: 1 1 auto;
overflow: auto;
.c-object-view {
.u-fills-container {
// Expand component types that fill a container
@include abs();
}
}
}
}
</style>
<script>
import ObjectView from './ObjectView.vue'
import ContextMenuDropDown from './contextMenuDropDown.vue';
export default {
inject: ['openmct'],
props: {
domainObject: Object,
objectPath: Array,
hasFrame: Boolean,
},
computed: {
cssClass() {
if (!this.domainObject || !this.domainObject.type) {
return;
}
let objectType = this.openmct.types.get(this.domainObject.type);
if (!objectType || !objectType.definition) {
return; // TODO: return unknown icon type.
}
return objectType.definition.cssClass;
}
},
components: {
ObjectView,
ContextMenuDropDown,
}
}
</script>

View File

@ -0,0 +1,84 @@
<template>
<a class="c-tree__item__label"
draggable="true"
@dragstart="dragStart"
@click="navigateOrPreview"
:href="objectLink">
<div class="c-tree__item__type-icon"
:class="typeClass"></div>
<div class="c-tree__item__name">{{ observedObject.name }}</div>
</a>
</template>
<script>
import ObjectLink from '../mixins/object-link';
import ContextMenuGesture from '../mixins/context-menu-gesture';
import PreviewAction from '../preview/PreviewAction.js';
export default {
mixins: [ObjectLink, ContextMenuGesture],
inject: ['openmct'],
props: {
domainObject: Object,
objectPath: {
type: Array,
default() {
return [];
}
}
},
data() {
return {
observedObject: this.domainObject
};
},
mounted() {
if (this.observedObject) {
let removeListener = this.openmct.objects.observe(this.observedObject, '*', (newObject) => {
this.observedObject = newObject;
});
this.$once('hook:destroyed', removeListener);
}
this.previewAction = new PreviewAction(this.openmct);
},
computed: {
typeClass() {
let type = this.openmct.types.get(this.observedObject.type);
if (!type) {
return 'icon-object-unknown';
}
return type.definition.cssClass;
}
},
methods: {
navigateOrPreview(event) {
if (this.openmct.editor.isEditing()){
event.preventDefault();
this.preview();
}
},
preview() {
if (this.previewAction.appliesTo(this.objectPath)){
this.previewAction.invoke(this.objectPath);
}
},
dragStart(event) {
let navigatedObject = this.openmct.router.path[0];
let serializedPath = JSON.stringify(this.objectPath);
/*
* Cannot inspect data transfer objects on dragover/dragenter so impossible to determine composability at
* that point. If dragged object can be composed by navigated object, then indicate with presence of
* 'composable-domain-object' in data transfer
*/
if (this.openmct.composition.checkPolicy(navigatedObject, this.observedObject)) {
event.dataTransfer.setData("openmct/composable-domain-object", JSON.stringify(this.domainObject));
}
// serialize domain object anyway, because some views can drag-and-drop objects without composition
// (eg. notabook.)
event.dataTransfer.setData("openmct/domain-object-path", serializedPath);
}
}
}
</script>

View File

@ -88,26 +88,25 @@ export default {
this.updateView(immediatelySelect);
},
onDragOver(event) {
event.preventDefault();
if (this.hasComposableDomainObject(event)) {
event.preventDefault();
}
},
onDrop(event) {
let parentObject = this.currentObject;
let d = event.dataTransfer.getData("domainObject");
if (d) {
let childObject = JSON.parse(d);
if (this.openmct.composition.checkPolicy(parentObject, childObject)){
if (!this.openmct.editor.isEditing() && parentObject.type !== 'folder'){
this.openmct.editor.edit();
}
parentObject.composition.push(childObject.identifier);
this.openmct.objects.mutate(parentObject, 'composition', parentObject.composition);
}
if (this.hasComposableDomainObject(event)) {
let composableDomainObject = this.getComposableDomainObject(event);
this.currentObject.composition.push(composableDomainObject.identifier);
this.openmct.objects.mutate(this.currentObject, 'composition', this.currentObject.composition);
event.preventDefault();
event.stopPropagation();
}
},
hasComposableDomainObject(event) {
return event.dataTransfer.types.includes('openmct/composable-domain-object')
},
getComposableDomainObject(event) {
let serializedDomainObject = event.dataTransfer.getData('openmct/composable-domain-object');
return JSON.parse(serializedDomainObject);
}
}
}

View File

@ -1,51 +0,0 @@
<template>
<a class="c-tree__item__label"
draggable="true"
@dragstart="dragStart"
:href="objectLink">
<div class="c-tree__item__type-icon"
:class="typeClass"></div>
<div class="c-tree__item__name">{{ observedObject.name }}</div>
</a>
</template>
<script>
import ObjectLink from '../mixins/object-link';
import ContextMenuGesture from '../mixins/context-menu-gesture';
export default {
mixins: [ObjectLink, ContextMenuGesture],
inject: ['openmct'],
props: {
domainObject: Object
},
data() {
return {
observedObject: this.domainObject
};
},
mounted() {
if (this.observedObject) {
let removeListener = this.openmct.objects.observe(this.observedObject, '*', (newObject) => {
this.observedObject = newObject;
});
this.$once('hook:destroyed', removeListener);
}
},
computed: {
typeClass() {
let type = this.openmct.types.get(this.observedObject.type);
if (!type) {
return 'icon-object-unknown';
}
return type.definition.cssClass;
}
},
methods: {
dragStart(event) {
event.dataTransfer.setData("domainObject", JSON.stringify(this.observedObject));
}
}
}
</script>

View File

@ -18,9 +18,6 @@
.c-search {
@include wrappedInput();
padding-top: 2px;
padding-bottom: 2px;
&:before {
// Mag glass icon
content: $glyph-icon-magnify;
@ -35,6 +32,11 @@
display: block;
}
}
input[type='text'],
input[type='search'] {
text-align: left;
}
}
</style>

View File

@ -16,7 +16,7 @@
</li>
<li class="js-last-place" @drop="moveToIndex(elements.length)"></li>
</ul>
<div v-if="elements.length === 0">No contained elements</div>
<div v-if="elements.length === 0">No contained elements</div>
</div>
</div>
</template>
@ -55,8 +55,8 @@
}
</style>
<script>
import Search from '../controls/search.vue';
import ObjectLabel from '../controls/ObjectLabel.vue';
import Search from '../components/search.vue';
import ObjectLabel from '../components/ObjectLabel.vue';
export default {
inject: ['openmct'],
@ -147,7 +147,7 @@ export default {
composition.splice(deleteIndex, 1);
composition.splice(moveToIndex, 0, moveFromId);
}
this.openmct.objects.mutate(this.parentObject, 'composition', composition);
},
moveFrom(index){
@ -155,6 +155,7 @@ export default {
}
},
destroyed() {
this.openmct.selection.off('change', this.showSelection);
}
}
</script>

View File

@ -49,6 +49,14 @@
}
}
.c-color-swatch {
$d: 12px;
display: block;
flex: 0 0 auto;
width: $d;
height: $d;
}
/************************************************************** LEGACY */
// TODO: refactor when legacy properties markup can be converted
.inspector-location {
@ -128,9 +136,6 @@
grid-column: 1 / 3;
}
+ .c-properties {
// Margin between components
margin-top: $interiorMarginLg;
@ -176,11 +181,32 @@
}
}
}
/********************************************* LEGACY SUPPORT */
.c-inspector {
li.grid-row + li.grid-row {
> * {
border-top: 1px solid $colorInspectorSectionHeaderBg;
}
}
li.grid-row .label {
color: $colorInspectorPropName;
}
li.grid-row .value {
color: $colorInspectorPropVal;
word-break: break-all;
&:first-child {
// If there is no preceding .label element, make value span columns
grid-column: 1 / 3;
}
}
}
</style>
<script>
import multipane from '../controls/multipane.vue';
import pane from '../controls/pane.vue';
import multipane from '../layout/multipane.vue';
import pane from '../layout/pane.vue';
import Elements from './Elements.vue';
import Location from './Location.vue';
import Properties from './Properties.vue';

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