Compare commits

...

42 Commits

Author SHA1 Message Date
b0b160d71e Renamed InspectorView.vue to InspectorViews.vue 2019-02-22 13:28:09 -08:00
9c4553dd90 Support multiple inspector views 2019-02-22 12:51:38 -08:00
86e6885fb9 Added telemetry filters to the API 2019-02-22 12:50:10 -08:00
0e30fba72d Tree search implementation (#2280)
Re-implements search UI using legacy existing search service.
2019-02-19 15:34:47 -08:00
1c77ef142c Revert object duplication check from https://github.com/nasa/openmct/pull/2287/ (#2294) 2019-02-15 16:52:05 -08:00
853764d863 Added editing support to the View API (#2279)
* Added edit to view API

* Fixed listener deregistration bug
2019-02-13 19:26:26 -08:00
d0ab59f9da Toolbar number input (#2288)
* Listen for ‘input’ event when input type is number, otherwise listen for 'change' event.

* Remove checks for options type in the event handlers.
2019-02-13 12:16:52 -08:00
21e08709cb Prevent self-composition in layouts (#2287) 2019-02-13 11:42:43 -08:00
a1aa99837b Update isTelemetry logic to ignore imagery. (#2285) 2019-02-12 11:32:53 -08:00
037264b0bf Quick compatibility fix to support dismissing notifications from legacy list (#2283) 2019-02-12 11:32:23 -08:00
1a06702dbe Resolve conductor configuration immediately (#2276)
* Set time system / bounds immediately based on conductor configuration

* Hide date picker if not UTC based time system. Improve Conductor configuration error messages.
2019-02-07 11:36:37 -08:00
666bb41697 [Selection] support getting object view's selection context (#2272)
* Get selection context from object view for constructing the context in subobject view.

* Implement getSelectionContext for flexible layout provider and remove code that makes flexible layout self selectable.

* Get selection context from object frame when constructing context for frames.

* Disable Add button when selected parent is a flexible layout

* Make 'Add' button working for selected display layouts in a flexible layout.

* fix expand error and fix flexible layout toggle container issue

* Check for parent object before getting composition.
2019-02-01 17:40:30 -08:00
e254fafb5c More fixes for TCR (#2255)
* Open in new tab
* Fix splitter resizing error, and css background issue
* Prevent new line on enter key press when editing name in object browse bar. Update domainObject name on enter key press in Object Browse Bar
* Flexible layout should react to composition remove, and fix delete container
* Render a drag ghost when dragging frame items in flexible layout
* Use composition.on add to add new frames
2019-01-29 14:55:38 -08:00
1dc1cc6c24 [Toolbar] hide toolbar when in browse mode (#2278)
* Hide toolbar when not editing and the selected object has no toolbar.

* Remove unused code
2019-01-28 15:52:03 -08:00
baa5d10009 [Fixed Position] cleanup (#2275)
* Delete unused files

* Remove fixed view plugin and style imports.
2019-01-28 12:50:17 -08:00
ac2b9acccb Time conductor validation (#2273)
* Fixed validation issues for bounds

* Validate offsets correctly

* Reset validation on mode change

* Use toggle mixin for Conductor menus
2019-01-25 13:40:46 -08:00
075d4deecb R&I Misc UI 4b (#2271)
* Styling for selects
- New cleaner styling approach;
- New cSelect and appearanceNone mixins;
- Converted selects in Notebook, plot-options-edit;

* List View fixes
- Ellipsizing now works;
- Better icon and text alignment;

* Remove updateDrilledIn function and calls

* Telemetry Table editing styles

- Headers now have hover effects;

* Change 'toggle'-style toolbar buttons to reflect current state, rather
than what will be the setting once clicked
- When frame is hidden, button displays the frame-hidden icon, and
tooltip says 'Frame hidden';

* Enable all sub-object views in Display Layout to use numeric inputs for
x, y, width and height

* Toolbar sanding and polishing
- Button order tweaked to place stack order near X, Y, etc. inputs;
- Improved spacing between items themselves and separators;

* Fix indentation

* Fix indentation part deux
2019-01-25 12:50:16 -08:00
ac11f898d4 A bunch of fixes for TCR (#2250)
* fix add links by drag and drop

* fix dialog component logging errors

* fix search component errors

* fix sort

* remove unused entrydnd file

* remove unnecessary console logs

* fix preview action in embed dropdown, which was throwing a type error

* invoke PreviewAction once in NotebookController and pass into git add -a

* add navigation capability to embeds, and a bunch of cleanup

* code cleanup and avoid calling dismiss twice on overlay destroy, which was throwing a DOM error. Calling code should dismiss the overlay

* only show elements pool if domainObject has composition

* fix error in inspector when no selection is present

* wire up object view expand button

* listen to composition#remove in TabsView

* make reviewer requested changes

* make reviewer requested changes, and fix for an edge case where removed tab is at the end of the array and currentTab is not set properly

* remove array wrapping dynamic classes in embed.html

* add title='View Large' to expand button

* change model variable to domainObject in tabs.vue

* dismiss top level overlay when esc is pressed (only if overlay is dismissable)

* fix link navigation from embeds

* use positive flag dismissable instead of negative notDismissable for overlays

* make overlays dismissable by default, unless set to false
2019-01-24 16:23:50 -08:00
dd31de6935 Add form to display layout type to allow setting grid size. Also fix generator's form. (#2274) 2019-01-24 16:03:09 -08:00
9e811e722f [Display Layout] support ordering items (#2266)
* Add a toolbar menu for changing the display order of items.

* - Wire up orderItem
- Modify the toolbar API to support function as alternative for property path.
2019-01-23 10:51:29 -08:00
8ef53d85c4 R&I Layout editing mods (#2256)
* Layout mods for sub object editing without is-drilled-in
* Remove drilled-in logic
2019-01-22 11:52:56 -08:00
abcc5cb023 Implemented go to parent (#2264) 2019-01-17 16:32:12 -08:00
931871ff95 [Display Layout] Snap to grid toolbar toggle button (#2262)
* Add a  button in the toolbar to toggle snapp to grid.

* Convert item's coordinates and size from grid unit to pixels depending on useGrid value.

* Rename selectionListener to removeSelectionListener
2019-01-17 09:24:59 -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
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
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
202 changed files with 4604 additions and 8419 deletions

View File

@ -33,7 +33,13 @@ define([
formatString: '%0.2f',
hints: {
range: 1
}
},
filters: ['equals']
/*
filters: [{
comparator: 'equals',
possibleValues: [1,2,3,4]
}]*/
},
{
key: "cos",

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

@ -43,15 +43,14 @@ define([
form: [
{
name: "State Duration (seconds)",
control: "textfield",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "duration",
required: true,
property: [
"telemetry",
"duration"
],
pattern: "^\\d*(\\.\\d*)?$"
]
}
],
initialize: function (object) {

View File

@ -36,7 +36,9 @@
<body>
</body>
<script>
var THIRTY_MINUTES = 30 * 60 * 1000;
const FIVE_MINUTES = 5 * 60 * 1000;
const THIRTY_MINUTES = 30 * 60 * 1000;
[
'example/eventGenerator',
'example/styleguide'
@ -49,7 +51,6 @@
openmct.install(openmct.plugins.ExampleImagery());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(openmct.plugins.ImportExport());
openmct.install(openmct.plugins.FixedView());
openmct.install(openmct.plugins.AutoflowView({
type: "telemetry.panel"
}));
@ -68,8 +69,8 @@
timeSystem: 'utc',
clock: 'local',
clockOffsets: {
start: -25 * 60 * 1000,
end: 5 * 60 * 1000
start: - THIRTY_MINUTES,
end: FIVE_MINUTES
}
}
]
@ -79,206 +80,7 @@
openmct.install(openmct.plugins.FolderView());
openmct.install(openmct.plugins.Tabs());
openmct.install(openmct.plugins.FlexibleLayout());
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');
openmct.install(openmct.plugins.LADTable());
openmct.start();
// openmct.toolbars.addProvider({
// name: "Testing Toolbar",
// key: "testing",
// description: "a mock toolbar that exercises all controls",
// forSelection: function (selection) {
// return true; // always applies.
// },
// toolbar: function (selection) {
// return [
// {
// control: 'menu',
// icon: 'icon-plus',
// label: 'Add',
// options: [
// { name: 'Box', class: 'icon-box', title: 'Add Box' },
// { name: 'Line', class: 'icon-line-horz', title: 'Add Line' },
// { name: 'Text', class: 'icon-font', title: 'Add Text' },
// { name: 'Image', class: 'icon-image', title: 'Add Image' }
// ]
// },
// {
// control: 'separator'
// },
// {
// control: 'color-picker',
// icon: 'icon-paint-bucket',
// value: '#33ff00',
// },
// {
// control: 'color-picker',
// icon: 'icon-pencil',
// value: '#ffffff',
// },
// {
// control: 'color-picker',
// icon: 'icon-font',
// value: '#333333',
// },
//
// {
// control: 'separator'
// },
// {
// control: 'select-menu',
// value: 11,
// options: [
// { value: 9, name: '9 px' },
// { value: 10, name: '10 px' },
// { value: 11, name: '11 px' },
// { value: 12, name: '12 px' },
// { value: 13, name: '13 px' },
// { value: 14, name: '14 px' },
// { value: 16, name: '16 px' },
// { value: 18, name: '18 px' },
// { value: 20, name: '20 px' },
// { value: 24, name: '24 px' },
// { value: 28, name: '28 px' },
// { value: 32, name: '32 px' },
// { value: 40, name: '40 px' },
// { value: 48, name: '48 px' },
// { value: 56, name: '56 px' },
// { value: 64, name: '64 px' },
// { value: 72, name: '72 px' },
// { value: 80, name: '80 px' },
// { value: 88, name: '88 px' },
// { value: 96, name: '96 px' },
// { value: 128, name: '128 px' },
// { value: 160, name: '160 px' }
// ]
// },
//
// {
// control: 'separator'
// },
// {
// control: 'menu',
// icon: 'icon-layers',
// options: [
// { name: 'Move to top', class: 'icon-arrow-double-up', title: 'Move to top' },
// { name: 'Move up', class: 'icon-arrow-up', title: 'Move up' },
// { name: 'Move down', class: 'icon-arrow-down', title: 'Move down' },
// { name: 'Move to bottom', class: 'icon-arrow-double-down', title: 'Move to bottom' }
// ]
// },
//
// {
// control: 'separator'
// },
// {
// control: 'button',
// icon: 'icon-gear'
// },
//
// {
// control: 'separator'
// },
// {
// control: 'input',
// type: 'number',
// label: 'X',
// value: 1,
// title: 'X position'
// },
// {
// control: 'input',
// type: 'number',
// label: 'Y',
// value: 2,
// title: 'Y position'
// },
// {
// control: 'input',
// type: 'number',
// label: 'W',
// value: 3,
// title: 'Width'
// },
// {
// control: 'input',
// type: 'number',
// label: 'H',
// value: 4,
// title: 'Height'
// },
//
// {
// control: 'separator'
// },
// {
// control: 'button',
// icon: 'icon-trash',
// label: 'delete',
// modifier: 'caution'
// },
//
// {
// control: 'separator'
// },
// {
// control: 'checkbox',
// name: 'this is a checkbox',
// },
// {
// control: 'separator'
// },
// {
// control: 'toggle-button',
// title: 'Toggle Frame',
// property: 'hideFrame',
// value: false,
// options: [
// {
// value: true,
// icon: 'icon-frame-hide'
// },
// {
// value: false,
// icon: 'icon-frame-show'
// }
// ]
// },
// {
// control: 'toggle-button',
// title: 'Snap to grid',
// property: 'snapToGrid',
// value: true,
// options: [
// {
// value: true,
// icon: 'icon-grid-snap-to'
// },
// {
// value: false,
// icon: 'icon-grid-snap-no'
// }
// ]
// },
// {
// control: 'toggle-button',
// title: 'Toggle label',
// property: 'showLabel',
// value: true,
// options: [
// {
// value: true,
// icon: 'icon-two-parts-both'
// },
// {
// value: false,
// icon: 'icon-two-parts-one-only'
// }
// ]
// }
// ];
// }
// });
</script>
</html>

View File

@ -10,6 +10,16 @@
ng-show="ngModel.progressPerc !== undefined"></mct-include>
</div>
<div class="bottom-bar">
<a ng-repeat="dialogOption in ngModel.options"
class="s-button"
ng-click="dialogOption.callback()">
{{dialogOption.label}}
</a>
<a class="s-button major"
ng-if="ngModel.primaryOption"
ng-click="ngModel.primaryOption.callback()">
{{ngModel.primaryOption.label}}
</a>
</div>
</div>
</div>

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

@ -169,15 +169,17 @@ function (
}
function saveAfterClone(clonedObject) {
return domainObject.getCapability("editor").save()
.then(resolveWith(clonedObject));
return this.openmct.editor.save().then(() => {
// Force mutation for search indexing
clonedObject.useCapability('mutation', (model) => {
return model;
});
return clonedObject;
})
}
function finishEditing(clonedObject) {
return domainObject.getCapability("editor").finish()
.then(function () {
return fetchObject(clonedObject.getId());
});
return fetchObject(clonedObject.getId())
}
function onSuccess(object) {

View File

@ -65,11 +65,10 @@ define(
CreateAction.prototype.perform = function () {
var newModel = this.type.getInitialModel(),
openmct = this.openmct,
newObject,
editAction;
newObject;
function onSave() {
openmct.editor.save();
// openmct.editor.save();
}
function onCancel() {
@ -81,7 +80,6 @@ define(
newObject = this.parent.useCapability('instantiation', newModel);
openmct.editor.edit();
editAction = newObject.getCapability("action").getActions("edit")[0];
newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
// TODO: support editing object without saving object first.
// Which means we have to toggle createwizard afterwards. For now,

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

@ -43,12 +43,25 @@ define(
* Launch a dialog showing a list of current notifications.
*/
$scope.showNotificationsList = function () {
let notificationsList = openmct.notifications.notifications.map(notification => {
if (notification.model.severity === 'alert' || notification.model.severity === 'info') {
notification.model.primaryOption = {
label: 'Dismiss',
callback: () => {
let currentIndex = notificationsList.indexOf(notification);
notification.dismiss();
notificationsList.splice(currentIndex, 1);
}
}
}
return notification;
})
dialogService.getDialogResponse('overlay-message-list', {
dialog: {
title: "Messages",
//Launch the message list dialog with the models
// from the notifications
messages: openmct.notifications.notifications
messages: notificationsList
}
});

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

@ -1,475 +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/FixedController",
"./templates/fixed.html",
"./templates/frame.html",
"./templates/elements/telemetry.html",
"./templates/elements/box.html",
"./templates/elements/line.html",
"./templates/elements/text.html",
"./templates/elements/image.html",
"legacyRegistry"
], function (
FixedController,
fixedTemplate,
frameTemplate,
telemetryTemplate,
boxTemplate,
lineTemplate,
textTemplate,
imageTemplate,
legacyRegistry
) {
return function() {
return function (openmct) {
openmct.legacyRegistry.register("platform/features/fixed", {
"name": "Fixed position components.",
"description": "Plug in adding Fixed Position object type.",
"extensions": {
"views": [
{
"key": "fixed-display",
"name": "Fixed Position Display",
"cssClass": "icon-box-with-dashed-lines",
"type": "telemetry.fixed",
"template": fixedTemplate,
"uses": ["composition"],
"editable": true
}
],
"templates": [
{
"key": "fixed.telemetry",
"template": telemetryTemplate
},
{
"key": "fixed.box",
"template": boxTemplate
},
{
"key": "fixed.line",
"template": lineTemplate
},
{
"key": "fixed.text",
"template": textTemplate
},
{
"key": "fixed.image",
"template": imageTemplate
}
],
"controllers": [
{
"key": "FixedController",
"implementation": FixedController,
"depends": [
"$scope",
"$q",
"dialogService",
"openmct",
"$element"
]
}
],
"toolbars": [
{
name: "Fixed Position Toolbar",
key: "fixed.position",
description: "Toolbar for the selected element inside a fixed position display.",
forSelection: function (selection) {
if (!selection) {
return;
}
return (openmct.editor.isEditing() &&
selection[0] && selection[0].context.elementProxy &&
((selection[1] && selection[1].context.item.type === 'telemetry.fixed') ||
(selection[0] && selection[0].context.item && selection[0].context.item.type === 'telemetry.fixed')));
},
toolbar: function (selection) {
var imageProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "url"];
var boxProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill"];
var textProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill", "color", "size", "text"];
var lineProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "x2", "y2"];
var telemetryProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill", "color", "size", "titled"];
var fixedPageProperties = ["add"];
var properties = [],
fixedItem = selection[0] && selection[0].context.item,
elementProxy = selection[0] && selection[0].context.elementProxy,
domainObject = selection[1] && selection[1].context.item,
path;
if (elementProxy) {
var type = elementProxy.element.type;
path = "configuration['fixed-display'].elements[" + elementProxy.index + "]";
properties =
type === 'fixed.image' ? imageProperties :
type === 'fixed.text' ? textProperties :
type === 'fixed.box' ? boxProperties :
type === 'fixed.line' ? lineProperties :
type === 'fixed.telemetry' ? telemetryProperties : [];
} else if (fixedItem) {
properties = domainObject && domainObject.type === 'layout' ? [] : fixedPageProperties;
}
return [
{
control: "menu",
domainObject: domainObject || selection[0].context.item,
method: function (option) {
selection[0].context.fixedController.add(option.key);
},
key: "add",
icon: "icon-plus",
label: "Add",
options: [
{
"name": "Box",
"class": "icon-box",
"key": "fixed.box"
},
{
"name": "Line",
"class": "icon-line-horz",
"key": "fixed.line"
},
{
"name": "Text",
"class": "icon-T",
"key": "fixed.text"
},
{
"name": "Image",
"class": "icon-image",
"key": "fixed.image"
}
]
},
{
control: "menu",
domainObject: domainObject,
method: function (option) {
console.log('option', option)
selection[0].context.fixedController.order(
selection[0].context.elementProxy,
option.key
);
},
key: "order",
icon: "icon-layers",
title: "Move the selected object above or below other objects",
options: [
{
"name": "Move to Top",
"class": "icon-arrow-double-up",
"key": "top"
},
{
"name": "Move Up",
"class": "icon-arrow-up",
"key": "up"
},
{
"name": "Move Down",
"class": "icon-arrow-down",
"key": "down"
},
{
"name": "Move to Bottom",
"class": "icon-arrow-double-down",
"key": "bottom"
}
]
},
{
control: "color-picker",
domainObject: domainObject,
property: path + ".fill",
icon: "icon-paint-bucket",
title: "Set fill color",
key: 'fill'
},
{
control: "color-picker",
domainObject: domainObject,
property: path + ".stroke",
icon: "icon-line-horz",
title: "Set border color",
key: 'stroke'
},
{
control: "button",
domainObject: domainObject,
property: path + ".url",
icon: "icon-image",
title: "Edit image properties",
key: 'url',
dialog: {
control: "input",
type: "text",
name: "Image URL",
class: "l-input-lg",
required: true
}
},
{
control: "color-picker",
domainObject: domainObject,
property: path + ".color",
icon: "icon-T",
mandatory: true,
title: "Set text color",
key: 'color'
},
{
control: "select-menu",
domainObject: domainObject,
property: path + ".size",
title: "Set text size",
key: 'size',
options: [9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96].map(function (size) {
return { "value": size + "px"};
})
},
{
control: "input",
type: "number",
domainObject: domainObject,
property: path + ".x",
label: "X",
title: "X position",
key: "x",
class: "l-input-sm",
min: "0"
},
{
control: "input",
type: "number",
domainObject: domainObject,
property: path + ".y",
label: "Y",
title: "Y position",
key: "y",
class: "l-input-sm",
min: "0"
},
{
control: "input",
type: "number",
domainObject: domainObject,
property: path + ".x",
label: "X1",
title: "X1 position",
key: "x1",
class: "l-input-sm",
min: "0"
},
{
control: "input",
type: "number",
domainObject: domainObject,
property: path + ".y",
label: "Y1",
title: "Y1 position",
key: "y1",
class: "l-input-sm",
min: "0"
},
{
control: "input",
type: "number",
domainObject: domainObject,
property: path + ".x2",
label: "X2",
title: "X2 position",
key: "x2",
class: "l-input-sm",
min: "0"
},
{
control: "input",
type: "number",
domainObject: domainObject,
property: path + ".y2",
label: "Y2",
title: "Y2 position",
key: "y2",
class: "l-input-sm",
min: "0"
},
{
control: "input",
type: "number",
domainObject: domainObject,
property: path + ".height",
label: "H",
title: "Resize object height",
key: "height",
class: "l-input-sm",
min: "1"
},
{
control: "input",
type: "number",
domainObject: domainObject,
property: path + ".width",
label: "W",
title: "Resize object width",
key: "width",
class: "l-input-sm",
min: "1"
},
{
control: "toggle-button",
domainObject: domainObject,
property: path + ".useGrid",
key: "useGrid",
options: [
{
value: true,
icon: 'icon-grid-snap-to',
title: 'Snap to grid'
},
{
value: false,
icon: 'icon-grid-snap-no',
title: "Do not snap to grid"
}
]
},
{
control: "button",
domainObject: domainObject,
property: path + ".text",
icon: "icon-gear",
title: "Edit text properties",
key: "text",
dialog: {
control: "input",
type: "text",
name: "Text",
required: true
}
},
{
control: "toggle-button",
domainObject: domainObject,
property: path + ".titled",
key: "titled",
options: [
{
value: true,
icon: 'icon-two-parts-both',
title: 'Show label'
},
{
value: false,
icon: 'icon-two-parts-one-only',
title: "Hide label"
}
]
},
{
control: "button",
domainObject: domainObject,
method: function () {
selection[0].context.fixedController.remove(
selection[0].context.elementProxy
);
},
key: "remove",
icon: "icon-trash"
}
].filter(function (item) {
var filtered;
properties.forEach(function (property) {
if (item.property && item.key === property ||
item.method && item.key === property) {
filtered = item;
}
});
return filtered;
});
}
}
],
"types": [
{
"key": "telemetry.fixed",
"name": "Fixed Position Display",
"cssClass": "icon-box-with-dashed-lines",
"description": "Collect and display telemetry elements in " +
"alphanumeric format in a simple canvas workspace. " +
"Elements can be positioned and sized. " +
"Lines, boxes and images can be added as well.",
"priority": 899,
"delegates": [
"telemetry"
],
"features": "creation",
"contains": [
{
"has": "telemetry"
}
],
"model": {
"layoutGrid": [64, 16],
"composition": []
},
"properties": [
{
"name": "Layout Grid",
"control": "composite",
"items": [
{
"name": "Horizontal grid (px)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric"
},
{
"name": "Vertical grid (px)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric"
}
],
"pattern": "^(\\d*[1-9]\\d*)?$",
"property": "layoutGrid",
"conversion": "number[]"
}
],
"views": [
"fixed-display"
]
}
]
}
});
openmct.legacyRegistry.enable("platform/features/fixed");
}
}
});

View File

@ -1,720 +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(
[
'lodash',
'./FixedProxy',
'./elements/ElementProxies',
'./FixedDragHandle',
'../../../../src/api/objects/object-utils'
],
function (
_,
FixedProxy,
ElementProxies,
FixedDragHandle,
objectUtils
) {
var DEFAULT_DIMENSIONS = [2, 1];
// Convert from element x/y/width/height to an
// appropriate ng-style argument, to position elements.
function convertPosition(elementProxy) {
if (elementProxy.getStyle) {
return elementProxy.getStyle();
}
var gridSize = elementProxy.getGridSize();
// Multiply position/dimensions by grid size
return {
left: (gridSize[0] * elementProxy.element.x) + 'px',
top: (gridSize[1] * elementProxy.element.y) + 'px',
width: (gridSize[0] * elementProxy.element.width) + 'px',
height: (gridSize[1] * elementProxy.element.height) + 'px'
};
}
/**
* The FixedController is responsible for supporting the
* Fixed Position view. It arranges frames according to saved
* configuration and provides methods for updating these based on
* mouse movement.
* @memberof platform/features/layout
* @constructor
* @param {Scope} $scope the controller's Angular scope
*/
function FixedController($scope, $q, dialogService, openmct, $element) {
this.names = {}; // Cache names by ID
this.values = {}; // Cache values by ID
this.elementProxiesById = {};
this.telemetryObjects = {};
this.subscriptions = {};
this.openmct = openmct;
this.$element = $element;
this.$scope = $scope;
this.dialogService = dialogService;
this.$q = $q;
this.newDomainObject = $scope.domainObject.useCapability('adapter');
this.fixedViewSelectable = false;
var self = this;
[
'digest',
'fetchHistoricalData',
'getTelemetry',
'setDisplayedValue',
'subscribeToObject',
'unsubscribe',
'updateView'
].forEach(function (name) {
self[name] = self[name].bind(self);
});
// Decorate an element for display
function makeProxyElement(element, index, elements) {
var ElementProxy = ElementProxies[element.type],
e = ElementProxy && new ElementProxy(element, index, elements, self.gridSize);
if (e) {
// Provide a displayable position (convert from grid to px)
e.style = convertPosition(e);
// Template names are same as type names, presently
e.template = element.type;
}
return e;
}
// Decorate elements in the current configuration
function refreshElements() {
var elements = (((self.newDomainObject.configuration || {})['fixed-display'] || {}).elements || []);
// Create the new proxies...
self.elementProxies = elements.map(makeProxyElement);
if (self.selectedElementProxy) {
// If selection is not in array, select parent.
// Otherwise, set the element to select after refresh.
var index = elements.indexOf(self.selectedElementProxy.element);
if (index === -1) {
self.$element[0].click();
} else if (!self.elementToSelectAfterRefresh) {
self.elementToSelectAfterRefresh = self.elementProxies[index].element;
}
}
// Finally, rebuild lists of elements by id to
// facilitate faster update when new telemetry comes in.
self.elementProxiesById = {};
self.elementProxies.forEach(function (elementProxy) {
var id = elementProxy.id;
if (elementProxy.element.type === 'fixed.telemetry') {
// Provide it a cached name/value to avoid flashing
elementProxy.name = self.names[id];
elementProxy.value = self.values[id];
self.elementProxiesById[id] = self.elementProxiesById[id] || [];
self.elementProxiesById[id].push(elementProxy);
}
});
}
// Trigger a new query for telemetry data
function updateDisplayBounds(bounds, isTick) {
if (!isTick) {
//Reset values
self.values = {};
refreshElements();
//Fetch new data
Object.values(self.telemetryObjects).forEach(function (object) {
self.fetchHistoricalData(object);
});
}
}
// Add an element to this view
function addElement(element) {
var index;
var elements = (((self.newDomainObject.configuration || {})['fixed-display'] || {}).elements || []);
elements.push(element);
if (self.selectedElementProxy) {
index = elements.indexOf(self.selectedElementProxy.element);
}
self.mutate("configuration['fixed-display'].elements", elements);
elements = (self.newDomainObject.configuration)['fixed-display'].elements || [];
self.elementToSelectAfterRefresh = elements[elements.length - 1];
if (self.selectedElementProxy) {
// Update the selected element with the new
// value since newDomainOject is mutated.
self.selectedElementProxy.element = elements[index];
}
refreshElements();
}
// Position a panel after a drop event
function handleDrop(e, id, position) {
// Don't handle this event if it has already been handled
if (e.defaultPrevented) {
return;
}
e.preventDefault();
// Store the position of this element.
// color is set to "" to let the CSS theme determine the default color
addElement({
type: "fixed.telemetry",
x: Math.floor(position.x / self.gridSize[0]),
y: Math.floor(position.y / self.gridSize[1]),
id: id,
stroke: "transparent",
color: "",
titled: true,
width: DEFAULT_DIMENSIONS[0],
height: DEFAULT_DIMENSIONS[1],
useGrid: true
});
// Subscribe to the new object to get telemetry
self.openmct.objects.get(id).then(function (object) {
self.getTelemetry(object);
});
}
this.elementProxies = [];
this.addElement = addElement;
this.refreshElements = refreshElements;
this.fixedProxy = new FixedProxy(this.addElement, this.$q, this.dialogService);
this.composition = this.openmct.composition.get(this.newDomainObject);
this.composition.on('add', this.onCompositionAdd, this);
this.composition.on('remove', this.onCompositionRemove, this);
this.composition.load();
// Position panes where they are dropped
$scope.$on("mctDrop", handleDrop);
$scope.$on("$destroy", this.destroy.bind(this));
// Respond to external bounds changes
this.openmct.time.on("bounds", updateDisplayBounds);
this.openmct.selection.on('change', this.setSelection.bind(this));
this.openmct.editor.on('isEditing', this.handleEditing.bind(this));
this.$element.on('click', this.bypassSelection.bind(this));
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
this.newDomainObject = JSON.parse(JSON.stringify(obj));
this.updateElementPositions(this.newDomainObject.layoutGrid);
}.bind(this));
this.updateElementPositions(this.newDomainObject.layoutGrid);
refreshElements();
}
FixedController.prototype.updateElementPositions = function (layoutGrid) {
this.gridSize = layoutGrid;
this.elementProxies.forEach(function (elementProxy) {
elementProxy.setGridSize(this.gridSize);
elementProxy.style = convertPosition(elementProxy);
}.bind(this));
};
FixedController.prototype.onCompositionAdd = function (object) {
this.getTelemetry(object);
};
FixedController.prototype.onCompositionRemove = function (identifier) {
// Defer mutation of newDomainObject to prevent mutating an
// outdated version since this is triggered by a composition change.
setTimeout(function () {
var id = objectUtils.makeKeyString(identifier);
var elements = this.newDomainObject.configuration['fixed-display'].elements || [];
var newElements = elements.filter(function (proxy) {
return proxy.id !== id;
});
this.mutate("configuration['fixed-display'].elements", newElements);
if (this.subscriptions[id]) {
this.subscriptions[id]();
delete this.subscriptions[id];
}
delete this.telemetryObjects[id];
this.refreshElements();
}.bind(this));
};
/**
* Removes an element from the view.
*
* @param {Object} elementProxy the element proxy to remove.
*/
FixedController.prototype.remove = function (elementProxy) {
var element = elementProxy.element;
var elements = this.newDomainObject.configuration['fixed-display'].elements || [];
elements.splice(elements.indexOf(element), 1);
if (element.type === 'fixed.telemetry') {
this.newDomainObject.composition = this.newDomainObject.composition.filter(function (identifier) {
return objectUtils.makeKeyString(identifier) !== element.id;
});
}
this.mutate("configuration['fixed-display'].elements", elements);
this.refreshElements();
};
/**
* Adds a new element to the view.
*
* @param {string} type the type of element to add. Supported types are:
* `fixed.image`
* `fixed.box`
* `fixed.text`
* `fixed.line`
*/
FixedController.prototype.add = function (type) {
this.fixedProxy.add(type);
};
/**
* Change the display order of the element proxy.
*/
FixedController.prototype.order = function (elementProxy, position) {
var elements = elementProxy.order(position);
// Find the selected element index in the updated array.
var selectedElemenetIndex = elements.indexOf(this.selectedElementProxy.element);
this.mutate("configuration['fixed-display'].elements", elements);
elements = (this.newDomainObject.configuration)['fixed-display'].elements || [];
// Update the selected element with the new
// value since newDomainOject is mutated.
this.selectedElementProxy.element = elements[selectedElemenetIndex];
this.refreshElements();
};
FixedController.prototype.generateDragHandle = function (elementProxy, elementHandle) {
var index = this.elementProxies.indexOf(elementProxy);
if (elementHandle) {
elementHandle.element = elementProxy.element;
elementProxy = elementHandle;
}
return new FixedDragHandle(
elementProxy,
"configuration['fixed-display'].elements[" + index + "]",
this
);
};
FixedController.prototype.generateDragHandles = function (elementProxy) {
return elementProxy.handles().map(function (handle) {
return this.generateDragHandle(elementProxy, handle);
}, this);
};
FixedController.prototype.updateSelectionStyle = function () {
this.selectedElementProxy.style = convertPosition(this.selectedElementProxy);
};
FixedController.prototype.setSelection = function (selectable) {
var selection = selectable[0];
if (this.selectionListeners) {
this.selectionListeners.forEach(function (l) {
l();
});
}
this.selectionListeners = [];
if (!selection) {
return;
}
if (selection.context.elementProxy) {
this.selectedElementProxy = selection.context.elementProxy;
this.attachSelectionListeners();
this.mvHandle = this.generateDragHandle(this.selectedElementProxy);
this.resizeHandles = this.generateDragHandles(this.selectedElementProxy);
} else {
// Make fixed view selectable if it's not already.
if (!this.fixedViewSelectable && selectable.length === 1) {
this.fixedViewSelectable = true;
selection.context.fixedController = this;
this.openmct.selection.select(selection);
}
this.resizeHandles = [];
this.mvHandle = undefined;
this.selectedElementProxy = undefined;
}
};
FixedController.prototype.attachSelectionListeners = function () {
var index = this.elementProxies.indexOf(this.selectedElementProxy);
var path = "configuration['fixed-display'].elements[" + index + "]";
this.selectionListeners.push(this.openmct.objects.observe(this.newDomainObject, path + ".useGrid", function (newValue) {
if (this.selectedElementProxy.useGrid() !== newValue) {
this.selectedElementProxy.useGrid(newValue);
this.updateSelectionStyle();
this.openmct.objects.mutate(this.newDomainObject, path, this.selectedElementProxy.element);
}
}.bind(this)));
[
"width",
"height",
"stroke",
"fill",
"x",
"y",
"x1",
"y1",
"x2",
"y2",
"color",
"size",
"text",
"titled"
].forEach(function (property) {
this.selectionListeners.push(this.openmct.objects.observe(this.newDomainObject, path + "." + property, function (newValue) {
this.selectedElementProxy.element[property] = newValue;
this.updateSelectionStyle();
}.bind(this)));
}.bind(this));
};
FixedController.prototype.destroy = function () {
this.unsubscribe();
this.unlisten();
this.openmct.time.off("bounds", this.updateDisplayBounds);
this.openmct.selection.off("change", this.setSelection);
this.composition.off('add', this.onCompositionAdd, this);
this.composition.off('remove', this.onCompositionRemove, this);
this.openmct.editor.off('isEditing', this.handleEditing, this);
};
/**
* A rate-limited digest function. Caps digests at 60Hz
* @private
*/
FixedController.prototype.digest = function () {
var self = this;
if (!this.digesting) {
this.digesting = true;
requestAnimationFrame(function () {
self.$scope.$digest();
self.digesting = false;
});
}
};
/**
* Unsubscribe all listeners
* @private
*/
FixedController.prototype.unsubscribe = function () {
Object.values(this.subscriptions).forEach(function (unsubscribeFunc) {
unsubscribeFunc();
});
this.subscriptions = {};
this.telemetryObjects = {};
};
/**
* Subscribe to the given domain object
* @private
* @param {object} object Domain object to subscribe to
* @returns {object} The provided object, for chaining.
*/
FixedController.prototype.subscribeToObject = function (object) {
var self = this;
var timeAPI = this.openmct.time;
var id = objectUtils.makeKeyString(object.identifier);
this.subscriptions[id] = self.openmct.telemetry.subscribe(object, function (datum) {
if (timeAPI.clock() !== undefined) {
self.updateView(object, datum);
}
}, {});
return object;
};
/**
* Print the values from the given datum against the provided object in the view.
* @private
* @param {object} telemetryObject The domain object associated with the given telemetry data
* @param {object} datum The telemetry datum containing the values to print
*/
FixedController.prototype.updateView = function (telemetryObject, datum) {
var metadata = this.openmct.telemetry.getMetadata(telemetryObject);
var valueMetadata = this.chooseValueMetadataToDisplay(metadata);
var formattedTelemetryValue = this.getFormattedTelemetryValueForKey(valueMetadata, datum);
var limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
var alarm = limitEvaluator && limitEvaluator.evaluate(datum, valueMetadata);
this.setDisplayedValue(
telemetryObject,
formattedTelemetryValue,
alarm && alarm.cssClass
);
this.digest();
};
/**
* @private
*/
FixedController.prototype.getFormattedTelemetryValueForKey = function (valueMetadata, datum) {
var formatter = this.openmct.telemetry.getValueFormatter(valueMetadata);
return formatter.format(datum);
};
/**
* @private
*/
FixedController.prototype.chooseValueMetadataToDisplay = function (metadata) {
// If there is a range value, show that preferentially
var valueMetadata = metadata.valuesForHints(['range'])[0];
// If no range is defined, default to the highest priority non time-domain data.
if (valueMetadata === undefined) {
var valuesOrderedByPriority = metadata.values();
valueMetadata = valuesOrderedByPriority.filter(function (values) {
return !(values.hints.domain);
})[0];
}
return valueMetadata;
};
/**
* Request the last historical data point for the given domain object
* @param {object} object
* @returns {object} the provided object for chaining.
*/
FixedController.prototype.fetchHistoricalData = function (object) {
var bounds = this.openmct.time.bounds();
var self = this;
self.openmct.telemetry.request(object, {start: bounds.start, end: bounds.end, size: 1})
.then(function (data) {
if (data.length > 0) {
self.updateView(object, data[data.length - 1]);
}
});
return object;
};
/**
* Print a value to the onscreen element associated with a given telemetry object.
* @private
* @param {object} telemetryObject The telemetry object associated with the value
* @param {string | number} value The value to print to screen
* @param {string} [cssClass] an optional CSS class to apply to the onscreen element.
*/
FixedController.prototype.setDisplayedValue = function (telemetryObject, value, cssClass) {
var id = objectUtils.makeKeyString(telemetryObject.identifier);
var self = this;
(self.elementProxiesById[id] || []).forEach(function (element) {
self.names[id] = telemetryObject.name;
self.values[id] = value;
element.name = self.names[id];
element.value = self.values[id];
element.cssClass = cssClass;
});
};
FixedController.prototype.getTelemetry = function (domainObject) {
var id = objectUtils.makeKeyString(domainObject.identifier);
if (this.subscriptions[id]) {
this.subscriptions[id]();
delete this.subscriptions[id];
}
delete this.telemetryObjects[id];
if (!this.openmct.telemetry.isTelemetryObject(domainObject)) {
return;
}
// Initialize display
this.telemetryObjects[id] = domainObject;
this.setDisplayedValue(domainObject, "");
return Promise.resolve(domainObject)
.then(this.fetchHistoricalData)
.then(this.subscribeToObject);
};
/**
* Get the size of the grid, in pixels. The returned array
* is in the form `[x, y]`.
* @returns {number[]} the grid size
* @memberof platform/features/layout.FixedController#
*/
FixedController.prototype.getGridSize = function () {
return this.gridSize;
};
/**
* Get an array of elements in this panel; these are
* decorated proxies for both selection and display.
* @returns {Array} elements in this panel
*/
FixedController.prototype.getElements = function () {
return this.elementProxies;
};
/**
* Checks if the element should be selected or not.
*
* @param elementProxy the element to check
* @returns {boolean} true if the element should be selected.
*/
FixedController.prototype.shouldSelect = function (elementProxy) {
if (elementProxy.element === this.elementToSelectAfterRefresh) {
delete this.elementToSelectAfterRefresh;
return true;
} else {
return false;
}
};
/**
* Checks if an element is currently selected.
*
* @returns {boolean} true if an element is selected.
*/
FixedController.prototype.isElementSelected = function () {
return (this.selectedElementProxy) ? true : false;
};
/**
* Gets the style for the selected element.
*
* @returns {string} element style
*/
FixedController.prototype.getSelectedElementStyle = function () {
return (this.selectedElementProxy) ? this.selectedElementProxy.style : undefined;
};
/**
* Gets the selected element.
*
* @returns the selected element
*/
FixedController.prototype.getSelectedElement = function () {
return this.selectedElementProxy;
};
/**
* Prevents the event from bubbling up if drag is in progress.
*/
FixedController.prototype.bypassSelection = function ($event) {
if (this.dragInProgress) {
if ($event) {
$event.stopPropagation();
}
return;
}
};
/**
* Get drag handles.
* @returns {platform/features/layout.FixedDragHandle[]}
* drag handles for the current selection
*/
FixedController.prototype.handles = function () {
return this.resizeHandles;
};
/**
* Get the handle to handle dragging to reposition an element.
* @returns {platform/features/layout.FixedDragHandle} the drag handle
*/
FixedController.prototype.moveHandle = function () {
return this.mvHandle;
};
/**
* Gets the selection context.
*
* @param elementProxy the element proxy
* @returns {object} the context object which includes elementProxy
*/
FixedController.prototype.getContext = function (elementProxy) {
return {
elementProxy: elementProxy,
fixedController: this
};
};
/**
* End drag.
*
* @param handle the resize handle
*/
FixedController.prototype.endDrag = function (handle) {
this.dragInProgress = true;
setTimeout(function () {
this.dragInProgress = false;
}.bind(this), 0);
if (handle) {
handle.endDrag();
} else {
this.moveHandle().endDrag();
}
};
FixedController.prototype.mutate = function (path, value) {
this.openmct.objects.mutate(this.newDomainObject, path, value);
};
FixedController.prototype.handleEditing = function (isEditing) {
// Listen for edit mode changes and update selection if necessary.
// Mainly to ensure fixedController is on the selection context when editing.
this.setSelection(this.openmct.selection.get());
}
return FixedController;
}
);

View File

@ -1,110 +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 () {
// Drag handle dimensions
var DRAG_HANDLE_SIZE = [6, 6];
/**
* Template-displayable drag handle for an element in fixed
* position mode.
*
* @param elementHandle the element handle
* @param configPath the configuration path of an element
* @param {Object} fixedControl the fixed controller
* @memberof platform/features/layout
* @constructor
*/
function FixedDragHandle(elementHandle, configPath, fixedControl) {
this.elementHandle = elementHandle;
this.configPath = configPath;
this.fixedControl = fixedControl;
}
/**
* Get a CSS style to position this drag handle.
*
* @returns CSS style object (for `ng-style`)
* @memberof platform/features/layout.FixedDragHandle#
*/
FixedDragHandle.prototype.style = function () {
var gridSize = this.elementHandle.getGridSize();
// Adjust from grid to pixel coordinates
var x = this.elementHandle.x() * gridSize[0],
y = this.elementHandle.y() * gridSize[1];
// Convert to a CSS style centered on that point
return {
left: (x - DRAG_HANDLE_SIZE[0] / 2) + 'px',
top: (y - DRAG_HANDLE_SIZE[1] / 2) + 'px',
width: DRAG_HANDLE_SIZE[0] + 'px',
height: DRAG_HANDLE_SIZE[1] + 'px'
};
};
/**
* Start a drag gesture. This should be called when a drag
* begins to track initial state.
*/
FixedDragHandle.prototype.startDrag = function () {
// Cache initial x/y positions
this.dragging = {
x: this.elementHandle.x(),
y: this.elementHandle.y()
};
};
/**
* Continue a drag gesture; update x/y positions.
*
* @param {number[]} delta x/y pixel difference since drag started
*/
FixedDragHandle.prototype.continueDrag = function (delta) {
var gridSize = this.elementHandle.getGridSize();
if (this.dragging) {
// Update x/y positions (snapping to grid)
var newX = this.dragging.x + Math.round(delta[0] / gridSize[0]);
var newY = this.dragging.y + Math.round(delta[1] / gridSize[1]);
this.elementHandle.x(Math.max(0, newX));
this.elementHandle.y(Math.max(0, newY));
this.fixedControl.updateSelectionStyle();
}
};
/**
* End a drag gesture. This should be called when a drag
* concludes to trigger commit of changes.
*/
FixedDragHandle.prototype.endDrag = function () {
this.dragging = undefined;
this.fixedControl.mutate(this.configPath, this.elementHandle.element);
};
return FixedDragHandle;
}
);

View File

@ -1,76 +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(
['./elements/ElementFactory'],
function (ElementFactory) {
/**
* Proxy for configuring a fixed position view via the toolbar.
* @memberof platform/features/layout
* @constructor
* @param {Function} addElementCallback callback to invoke when
* elements are created
* @param $q Angular's $q, for promise-handling
* @param {DialogService} dialogService dialog service to use
* when adding a new element will require user input
*/
function FixedProxy(addElementCallback, $q, dialogService) {
this.factory = new ElementFactory(dialogService);
this.$q = $q;
this.addElementCallback = addElementCallback;
}
/**
* Add a new visual element to this view. Supported types are:
*
* * `fixed.image`
* * `fixed.box`
* * `fixed.text`
* * `fixed.line`
*
* @param {string} type the type of element to add
*/
FixedProxy.prototype.add = function (type) {
var addElementCallback = this.addElementCallback;
// Place a configured element into the view configuration
function addElement(element) {
// Configure common properties of the element
element.x = element.x || 0;
element.y = element.y || 0;
element.width = element.width || 1;
element.height = element.height || 1;
element.type = type;
element.useGrid = true;
// Finally, add it to the view's configuration
addElementCallback(element);
}
// Defer creation to the factory
this.$q.when(this.factory.createElement(type)).then(addElement);
};
return FixedProxy;
}
);

View File

@ -1,115 +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 () {
/**
* Handles drag interactions on frames in layouts. This will
* provides new positions/dimensions for frames based on
* relative pixel positions provided; these will take into account
* the grid size (in a snap-to sense) and will enforce some minimums
* on both position and dimensions.
*
* The provided position and dimensions factors will determine
* whether this is a move or a resize, and what type of resize it
* will be. For instance, a position factor of [1, 1]
* will move a frame along with the mouse as the drag
* proceeds, while a dimension factor of [0, 0] will leave
* dimensions unchanged. Combining these in different
* ways results in different handles; a position factor of
* [1, 0] and a dimensions factor of [-1, 0] will implement
* a left-edge resize, as the horizontal position will move
* with the mouse while the horizontal dimensions shrink in
* kind (and vertical properties remain unmodified.)
*
* @param {object} rawPosition the initial position/dimensions
* of the frame being interacted with
* @param {number[]} posFactor the position factor
* @param {number[]} dimFactor the dimensions factor
* @param {number[]} the size of each grid element, in pixels
* @constructor
* @memberof platform/features/layout
*/
function LayoutDrag(rawPosition, posFactor, dimFactor, gridSize) {
this.rawPosition = rawPosition;
this.posFactor = posFactor;
this.dimFactor = dimFactor;
this.gridSize = gridSize;
}
// Convert a delta from pixel coordinates to grid coordinates,
// rounding to whole-number grid coordinates.
function toGridDelta(gridSize, pixelDelta) {
return pixelDelta.map(function (v, i) {
return Math.round(v / gridSize[i]);
});
}
// Utility function to perform element-by-element multiplication
function multiply(array, factors) {
return array.map(function (v, i) {
return v * factors[i];
});
}
// Utility function to perform element-by-element addition
function add(array, other) {
return array.map(function (v, i) {
return v + other[i];
});
}
// Utility function to perform element-by-element max-choosing
function max(array, other) {
return array.map(function (v, i) {
return Math.max(v, other[i]);
});
}
/**
* Get a new position object in grid coordinates, with
* position and dimensions both offset appropriately
* according to the factors supplied in the constructor.
* @param {number[]} pixelDelta the offset from the
* original position, in pixels
*/
LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
return {
position: max(add(
this.rawPosition.position,
multiply(gridDelta, this.posFactor)
), [0, 0]),
dimensions: max(add(
this.rawPosition.dimensions,
multiply(gridDelta, this.dimFactor)
), [1, 1])
};
};
return LayoutDrag;
}
);

View File

@ -1,105 +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',
'../../../commonUI/general/src/services/Overlay'
], function (
$,
Overlay
) {
/**
* MCT Trigger Modal is intended for use in only one location: inside the
* object-header to allow views in a layout to be popped out in a modal.
* Users can close the modal and go back to normal, and everything generally
* just works fine.
*
* This code is sensitive to how our html is constructed-- particularly with
* how it locates the the container of an element in a layout. However, it
* should be able to handle slight relocations so long as it is always a
* descendent of a `.frame` element.
*/
function MCTTriggerModal($document) {
function link($scope, $element) {
var actions = $scope.domainObject.getCapability('action'),
notebookAction = actions.getActions({key: 'notebook-new-entry'})[0];
var frame = $element.parent();
for (var i = 0; i < 10; i++) {
if (frame.hasClass('frame')) {
break;
}
frame = frame.parent();
}
if (!frame.hasClass('frame')) {
$element.remove();
return;
}
frame = frame[0];
var layoutContainer = frame.parentElement;
var notebookButton = notebookAction ?
[
{
class: 'icon-notebook new-notebook-entry',
title: 'New Notebook Entry',
clickHandler: function (event) {
event.stopPropagation();
notebookAction.perform();
}
}
] : [];
var overlayService = new Overlay ({
$document: $document,
$scope: $scope,
$element: frame,
overlayWillMount: function () {
$(frame).removeClass('frame frame-template');
layoutContainer.removeChild(frame);
},
overlayDidUnmount: function () {
$(frame).addClass('frame frame-template');
layoutContainer.appendChild(frame);
},
browseBarButtons: notebookButton
});
$element.on('click', overlayService.toggleOverlay);
$scope.$on('$destroy', function () {
$element.off('click', overlayService.toggleOverlay);
});
}
return {
restrict: 'A',
link: link
};
}
return MCTTriggerModal;
});

View File

@ -1,58 +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 () {
/**
* Utility function for creating getter-setter functions,
* since these are frequently useful for element proxies.
*
* An optional third argument may be supplied in order to
* constrain or modify arguments when using as a setter;
* this argument is a function which takes two arguments
* (the current value for the property, and the requested
* new value.) This is useful when values need to be kept
* in certain ranges; specifically, to keep x/y positions
* non-negative in a fixed position view.
*
* @memberof platform/features/layout
* @constructor
* @param {Object} object the object to get/set values upon
* @param {string} key the property to get/set
* @param {function} [updater] function used to process updates
*/
function AccessorMutator(object, key, updater) {
return function (value) {
if (arguments.length > 0) {
object[key] = updater ?
updater(value, object[key]) :
value;
}
return object[key];
};
}
return AccessorMutator;
}
);

View File

@ -1,61 +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(
['./ElementProxy', './AccessorMutator'],
function (ElementProxy, AccessorMutator) {
/**
* Selection proxy for Box elements in a fixed position view.
* Also serves as a superclass for Text elements, since those
* elements have a superset of Box properties.
*
* Note that arguments here are meant to match those expected
* by `Array.prototype.map`
*
* @memberof platform/features/layout
* @constructor
* @param element the fixed position element, as stored in its
* configuration
* @param index the element's index within its array
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @param {Array} elements the full array of elements
*/
function BoxProxy(element, index, elements, gridSize) {
var proxy = new ElementProxy(element, index, elements, gridSize);
/**
* Get/set this element's fill color. (Omitting the
* argument makes this act as a getter.)
* @method
* @param {string} fill the new fill color
* @returns {string} the fill color
* @memberof platform/features/layout.BoxProxy#
*/
proxy.fill = new AccessorMutator(element, 'fill');
return proxy;
}
return BoxProxy;
}
);

View File

@ -1,115 +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 () {
var INITIAL_STATES = {
"fixed.image": {
stroke: "transparent"
},
"fixed.box": {
fill: "#717171",
border: "transparent",
stroke: "transparent"
},
"fixed.line": {
x: 5,
y: 9,
x2: 6,
y2: 6,
stroke: "#717171"
},
"fixed.text": {
fill: "transparent",
stroke: "transparent",
size: "13px"
}
},
DIALOGS = {
"fixed.image": {
name: "Image Properties",
sections: [
{
rows: [
{
key: "url",
control: "textfield",
name: "Image URL",
"cssClass": "l-input-lg",
required: true
}
]
}
]
},
"fixed.text": {
name: "Text Element Properties",
sections: [
{
rows: [
{
key: "text",
control: "textfield",
name: "Text",
required: true
}
]
}
]
}
};
/**
* The ElementFactory creates new instances of elements for the
* fixed position view, prompting for user input where necessary.
* @param {DialogService} dialogService service to request user input
* @memberof platform/features/layout
* @constructor
*/
function ElementFactory(dialogService) {
this.dialogService = dialogService;
}
/**
* Create a new element for the fixed position view.
* @param {string} type the type of element to create
* @returns {Promise|object} the created element, or a promise
* for that element
*/
ElementFactory.prototype.createElement = function (type) {
var initialState = INITIAL_STATES[type] || {};
// Clone that state
initialState = JSON.parse(JSON.stringify(initialState));
// Show a dialog to configure initial state, if appropriate
return DIALOGS[type] ? this.dialogService.getUserInput(
DIALOGS[type],
initialState
) : initialState;
};
return ElementFactory;
}
);

View File

@ -1,35 +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(
['./TelemetryProxy', './ImageProxy', './LineProxy', './BoxProxy', './TextProxy'],
function (TelemetryProxy, ImageProxy, LineProxy, BoxProxy, TextProxy) {
return {
"fixed.telemetry": TelemetryProxy,
"fixed.line": LineProxy,
"fixed.box": BoxProxy,
"fixed.image": ImageProxy,
"fixed.text": TextProxy
};
}
);

View File

@ -1,209 +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(
['./AccessorMutator', './ResizeHandle', './UnitAccessorMutator'],
function (AccessorMutator, ResizeHandle, UnitAccessorMutator) {
// Index deltas for changes in order
var ORDERS = {
top: Number.POSITIVE_INFINITY,
up: 1,
down: -1,
bottom: Number.NEGATIVE_INFINITY
};
// Mininmum pixel height and width for objects
var MIN_WIDTH = 10;
var MIN_HEIGHT = 10;
// Ensure a value is non-negative (for x/y setters)
function clamp(value) {
return Math.max(value, 0);
}
/**
* Abstract superclass for other classes which provide useful
* interfaces upon an elements in a fixed position view.
* This handles the generic operations (e.g. remove) so that
* subclasses only need to implement element-specific behaviors.
*
* Note that arguments here are meant to match those expected
* by `Array.prototype.map`
*
* @memberof platform/features/layout
* @constructor
* @param element the fixed position element, as stored in its
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] from
*/
function ElementProxy(element, index, elements, gridSize) {
/**
* The element as stored in the view configuration.
* @memberof platform/features/layout.ElementProxy#
*/
this.element = element;
/**
* The current grid size of the layout.
* @memberof platform/features/layout.ElementProxy#
*/
this.gridSize = gridSize || [1,1]; //Ensure a reasonable default
/**
* Get and/or set the x position of this element.
* Units are in fixed position grid space.
* @param {number} [x] the new x position (if setting)
* @returns {number} the x position
* @memberof platform/features/layout.ElementProxy#
*/
this.x = new AccessorMutator(element, 'x', clamp);
/**
* Get and/or set the y position of this element.
* Units are in fixed position grid space.
* @param {number} [y] the new y position (if setting)
* @returns {number} the y position
* @memberof platform/features/layout.ElementProxy#
*/
this.y = new AccessorMutator(element, 'y', clamp);
/**
* Get and/or set the stroke color of this element.
* @param {string} [stroke] the new stroke color (if setting)
* @returns {string} the stroke color
* @memberof platform/features/layout.ElementProxy#
*/
this.stroke = new AccessorMutator(element, 'stroke');
/**
* Get and/or set the width of this element.
* Units are in fixed position grid space.
* @param {number} [w] the new width (if setting)
* @returns {number} the width
* @memberof platform/features/layout.ElementProxy#
*/
this.width = new AccessorMutator(element, 'width');
/**
* Get and/or set the height of this element.
* Units are in fixed position grid space.
* @param {number} [h] the new height (if setting)
* @returns {number} the height
* @memberof platform/features/layout.ElementProxy#
*/
this.height = new AccessorMutator(element, 'height');
this.useGrid = new UnitAccessorMutator(this);
this.index = index;
this.elements = elements;
this.resizeHandles = [new ResizeHandle(this, this.element)];
}
/**
* Change the display order of this element.
* @param {string} o where to move this element;
* one of "top", "up", "down", or "bottom"
* @return {Array} the full array of elements
*/
ElementProxy.prototype.order = function (o) {
var index = this.index,
elements = this.elements,
element = this.element,
delta = ORDERS[o] || 0,
desired = Math.max(
Math.min(index + delta, elements.length - 1),
0
);
// Move to the desired index, if this is a change
if ((desired !== index) && (elements[index] === element)) {
// Splice out the current element
elements.splice(index, 1);
// Splice it back in at the correct index
elements.splice(desired, 0, element);
// Track change in index (proxy should be recreated
// anyway, but be consistent)
this.index = desired;
}
return elements;
};
/**
* Get handles to control specific features of this element,
* e.g. corner size.
* @return {platform/features/layout.ElementHandle[]} handles
* for moving/resizing this element
*/
ElementProxy.prototype.handles = function () {
return this.resizeHandles;
};
/**
* Returns which grid size the element is currently using.
* @return {number[]} The current grid size in [x,y] form if the element
* is currently using the grid, [1,1] if it is using
* pixels.
*/
ElementProxy.prototype.getGridSize = function () {
var gridSize;
// Default to using the grid if useGrid was not defined
if (typeof this.element.useGrid === 'undefined') {
this.element.useGrid = true;
}
if (this.element.useGrid) {
gridSize = this.gridSize;
} else {
gridSize = [1,1];
}
return gridSize;
};
/**
* Set the current grid size stored by this element proxy
* @param {number[]} gridSize The current layout grid size in [x,y] form
*/
ElementProxy.prototype.setGridSize = function (gridSize) {
this.gridSize = gridSize;
};
/**
* Get the current minimum element width in grid units
* @return {number} The current minimum element width
*/
ElementProxy.prototype.getMinWidth = function () {
return Math.ceil(MIN_WIDTH / this.getGridSize()[0]);
};
/**
* Get the current minimum element height in grid units
* @return {number} The current minimum element height
*/
ElementProxy.prototype.getMinHeight = function () {
return Math.ceil(MIN_HEIGHT / this.getGridSize()[1]);
};
return ElementProxy;
}
);

View File

@ -1,58 +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(
['./ElementProxy', './AccessorMutator'],
function (ElementProxy, AccessorMutator) {
/**
* Selection proxy for Image elements in a fixed position view.
*
* Note that arguments here are meant to match those expected
* by `Array.prototype.map`
*
* @memberof platform/features/layout
* @constructor
* @param element the fixed position element, as stored in its
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @augments {platform/features/layout.ElementProxy}
*/
function ImageProxy(element, index, elements, gridSize) {
var proxy = new ElementProxy(element, index, elements, gridSize);
/**
* Get and/or set the displayed text of this element.
* @param {string} [text] the new text (if setting)
* @returns {string} the text
* @memberof platform/features/layout.ImageProxy#
*/
proxy.url = new AccessorMutator(element, 'url');
return proxy;
}
return ImageProxy;
}
);

View File

@ -1,94 +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 () {
/**
* Handle for changing x/y position of a line's end point.
* This is used to support drag handles for line elements
* in a fixed position view. Field names for opposite ends
* are provided to avoid zero-length lines.
* @memberof platform/features/layout
* @constructor
* @param element the line element
* @param {string} xProperty field which stores x position
* @param {string} yProperty field which stores y position
* @param {string} xOther field which stores x of other end
* @param {string} yOther field which stores y of other end
* @implements {platform/features/layout.ElementHandle}
*/
function LineHandle(element, elementProxy, xProperty, yProperty, xOther, yOther) {
this.elementProxy = elementProxy;
this.element = element;
this.xProperty = xProperty;
this.yProperty = yProperty;
this.xOther = xOther;
this.yOther = yOther;
}
LineHandle.prototype.x = function (value) {
var element = this.element,
xProperty = this.xProperty,
yProperty = this.yProperty,
xOther = this.xOther,
yOther = this.yOther;
if (arguments.length > 0) {
// Ensure we stay in view
value = Math.max(value, 0);
// Make sure end points will still be different
if (element[yOther] !== element[yProperty] ||
element[xOther] !== value) {
element[xProperty] = value;
}
}
return element[xProperty];
};
LineHandle.prototype.y = function (value) {
var element = this.element,
xProperty = this.xProperty,
yProperty = this.yProperty,
xOther = this.xOther,
yOther = this.yOther;
if (arguments.length > 0) {
// Ensure we stay in view
value = Math.max(value, 0);
// Make sure end points will still be different
if (element[xOther] !== element[xProperty] ||
element[yOther] !== value) {
element[yProperty] = value;
}
}
return element[yProperty];
};
LineHandle.prototype.getGridSize = function () {
return this.elementProxy.getGridSize();
};
return LineHandle;
}
);

View File

@ -1,171 +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(
['./ElementProxy', './LineHandle', './AccessorMutator'],
function (ElementProxy, LineHandle, AccessorMutator) {
/**
* Selection/diplay proxy for line elements of a fixed position
* view.
* @memberof platform/features/layout
* @constructor
* @param element the fixed position element, as stored in its
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @augments {platform/features/layout.ElementProxy}
*/
function LineProxy(element, index, elements, gridSize) {
var proxy = new ElementProxy(element, index, elements, gridSize),
handles = [
new LineHandle(element, proxy, 'x', 'y', 'x2', 'y2'),
new LineHandle(element, proxy, 'x2', 'y2', 'x', 'y')
];
/**
* Gets style specific to line proxy.
*/
proxy.getStyle = function () {
var layoutGridSize = proxy.getGridSize();
return {
left: (layoutGridSize[0] * proxy.x()) + 'px',
top: (layoutGridSize[1] * proxy.y()) + 'px',
width: (layoutGridSize[0] * proxy.width()) + 'px',
height: (layoutGridSize[1] * proxy.height()) + 'px'
};
};
/**
* Get the top-left x coordinate, in grid space, of
* this line's bounding box.
* @returns {number} the x coordinate
* @memberof platform/features/layout.LineProxy#
*/
proxy.x = function (v) {
var x = Math.min(element.x, element.x2),
delta = Math.max(v, 0) - x;
if (arguments.length > 0 && delta) {
element.x += delta;
element.x2 += delta;
}
return x;
};
/**
* Get the top-left y coordinate, in grid space, of
* this line's bounding box.
* @returns {number} the y coordinate
* @memberof platform/features/layout.LineProxy#
*/
proxy.y = function (v) {
var y = Math.min(element.y, element.y2),
delta = Math.max(v, 0) - y;
if (arguments.length > 0 && delta) {
element.y += delta;
element.y2 += delta;
}
return y;
};
/**
* Get the width, in grid space, of
* this line's bounding box.
* @returns {number} the width
* @memberof platform/features/layout.LineProxy#
*/
proxy.width = function () {
return Math.max(Math.abs(element.x - element.x2), 1);
};
/**
* Get the height, in grid space, of
* this line's bounding box.
* @returns {number} the height
* @memberof platform/features/layout.LineProxy#
*/
proxy.height = function () {
return Math.max(Math.abs(element.y - element.y2), 1);
};
/**
* Get the x position, in grid units relative to
* the top-left corner, of the first point in this line
* segment.
* @returns {number} the x position of the first point
* @memberof platform/features/layout.LineProxy#
*/
proxy.x1 = function () {
return element.x - proxy.x();
};
/**
* Get the y position, in grid units relative to
* the top-left corner, of the first point in this line
* segment.
* @returns {number} the y position of the first point
* @memberof platform/features/layout.LineProxy#
*/
proxy.y1 = function () {
return element.y - proxy.y();
};
/**
* Get the x position, in grid units relative to
* the top-left corner, of the second point in this line
* segment.
* @returns {number} the x position of the second point
* @memberof platform/features/layout.LineProxy#
*/
proxy.x2 = function () {
return element.x2 - proxy.x();
};
/**
* Get the y position, in grid units relative to
* the top-left corner, of the second point in this line
* segment.
* @returns {number} the y position of the second point
* @memberof platform/features/layout.LineProxy#
*/
proxy.y2 = function () {
return element.y2 - proxy.y();
};
/**
* Get element handles for changing the position of end
* points of this line.
* @returns {LineHandle[]} line handles for both end points
* @memberof platform/features/layout.LineProxy#
*/
proxy.handles = function () {
return handles;
};
return proxy;
}
return LineProxy;
}
);

View File

@ -1,72 +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 () {
/**
* @interface platform/features/layout.ElementHandle
* @private
*/
/**
* Handle for changing width/height properties of an element.
* This is used to support drag handles for different
* element types in a fixed position view.
* @memberof platform/features/layout
* @constructor
*/
function ResizeHandle(elementProxy, element) {
this.elementProxy = elementProxy;
this.element = element;
}
ResizeHandle.prototype.x = function (value) {
var element = this.element;
if (arguments.length > 0) {
element.width = Math.max(
this.elementProxy.getMinWidth(),
value - element.x
);
}
return element.x + element.width;
};
ResizeHandle.prototype.y = function (value) {
var element = this.element;
if (arguments.length > 0) {
element.height = Math.max(
this.elementProxy.getMinHeight(),
value - element.y
);
}
return element.y + element.height;
};
ResizeHandle.prototype.getGridSize = function () {
return this.elementProxy.getGridSize();
};
return ResizeHandle;
}
);

View File

@ -1,56 +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(
['./TextProxy'],
function (TextProxy) {
/**
* Selection proxy for telemetry elements in a fixed position view.
*
* Note that arguments here are meant to match those expected
* by `Array.prototype.map`
*
* @memberof platform/features/layout
* @constructor
* @param element the fixed position element, as stored in its
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] form
* @augments {platform/features/layout.ElementProxy}
*/
function TelemetryProxy(element, index, elements, gridSize) {
var proxy = new TextProxy(element, index, elements, gridSize);
// Expose the domain object identifier
proxy.id = element.id;
// Don't expose text configuration
delete proxy.text;
return proxy;
}
return TelemetryProxy;
}
);

View File

@ -1,75 +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(
['./BoxProxy', './AccessorMutator'],
function (BoxProxy, AccessorMutator) {
/**
* Selection proxy for Text elements in a fixed position view.
*
* Note that arguments here are meant to match those expected
* by `Array.prototype.map`
*
* @memberof platform/features/layout
* @constructor
* @param element the fixed position element, as stored in its
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @augments {platform/features/layout.ElementProxy}
*/
function TextProxy(element, index, elements, gridSize) {
var proxy = new BoxProxy(element, index, elements, gridSize);
/**
* Get and/or set the text color of this element.
* @param {string} [color] the new text color (if setting)
* @returns {string} the text color
* @memberof platform/features/layout.TextProxy#
*/
proxy.color = new AccessorMutator(element, 'color');
/**
* Get and/or set the displayed text of this element.
* @param {string} [text] the new text (if setting)
* @returns {string} the text
* @memberof platform/features/layout.TextProxy#
*/
proxy.text = new AccessorMutator(element, 'text');
/**
* Get and/or set the text size of this element.
*
* @param {string} [size] the new text size (if setting)
* @returns {string} the text size
* @memberof platform/features/layout.TextProxy#
*/
proxy.size = new AccessorMutator(element, 'size');
return proxy;
}
return TextProxy;
}
);

View File

@ -1,92 +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 () {
/**
* Variant of AccessorMutator to handle the specific case of updating
* useGrid, in order update the positions appropriately from within
* the scope of UnitAccessorMutator
*
* @memberof platform/features/layout
* @constructor
* @param {ElementProxy} proxy ElementProxy object to perform the update
* upon
*/
function UnitAccessorMutator(elementProxy) {
var self = this;
this.elementProxy = elementProxy;
return function (useGrid) {
var current = elementProxy.element.useGrid;
if (arguments.length > 0) {
elementProxy.element.useGrid = useGrid;
if (useGrid && !current) {
self.convertCoordsTo('grid');
} else if (!useGrid && current) {
self.convertCoordsTo('px');
}
}
return elementProxy.element.useGrid;
};
}
/**
* For the elementProxy object called upon, convert its element's
* coordinates and size from pixels to grid units, or vice-versa.
* @param {string} unit When called with 'px', converts grid units to
* pixels; when called with 'grid', snaps element
* to grid units
*/
UnitAccessorMutator.prototype.convertCoordsTo = function (unit) {
var proxy = this.elementProxy,
gridSize = proxy.gridSize,
element = proxy.element,
minWidth = proxy.getMinWidth(),
minHeight = proxy.getMinHeight();
if (unit === 'px') {
element.x = element.x * gridSize[0];
element.y = element.y * gridSize[1];
element.width = element.width * gridSize[0];
element.height = element.height * gridSize[1];
if (element.x2 && element.y2) {
element.x2 = element.x2 * gridSize[0];
element.y2 = element.y2 * gridSize[1];
}
} else if (unit === 'grid') {
element.x = Math.round(element.x / gridSize[0]);
element.y = Math.round(element.y / gridSize[1]);
element.width = Math.max(Math.round(element.width / gridSize[0]), minWidth);
element.height = Math.max(Math.round(element.height / gridSize[1]), minHeight);
if (element.x2 && element.y2) {
element.x2 = Math.round(element.x2 / gridSize[0]);
element.y2 = Math.round(element.y2 / gridSize[1]);
}
}
};
return UnitAccessorMutator;
}
);

View File

@ -1,26 +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.
-->
<div
class="l-fixed-position-box"
ng-style="{ background: ngModel.fill(), border: '1px ' + ngModel.stroke() + ' solid' }"
>
</div>

View File

@ -1,26 +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.
-->
<div
ng-style="{ 'background-image': 'url(' + ngModel.element.url + ')', border: '1px solid ' + ngModel.stroke() }"
class="l-fixed-position-image"
>
</div>

View File

@ -1,31 +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.
-->
<svg ng-attr-width="{{ngModel.getGridSize()[0] * ngModel.width()}}"
ng-attr-height="{{ngModel.getGridSize()[1] * ngModel.height()}}">
<line ng-attr-x1="{{ngModel.getGridSize()[0] * ngModel.x1() + 1}}"
ng-attr-y1="{{ngModel.getGridSize()[1] * ngModel.y1() + 1}}"
ng-attr-x2="{{ngModel.getGridSize()[0] * ngModel.x2() + 1}}"
ng-attr-y2="{{ngModel.getGridSize()[1] * ngModel.y2() + 1}}"
ng-attr-stroke="{{ngModel.stroke()}}"
stroke-width="2">
</line>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,27 +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.
-->
<div
class="l-fixed-position-text l-static-text"
ng-style="{ background: ngModel.fill(), 'border-color': ngModel.stroke(), color: ngModel.color(), 'font-size': ngModel.size() }"
>
{{ngModel.element.text}}
</div>

View File

@ -1,62 +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.
-->
<div class="t-fixed-position l-fixed-position"
ng-controller="FixedController as controller">
<!-- Background grid -->
<div class="l-fixed-position__grid-holder l-grid-holder c-grid" ng-click="controller.bypassSelection($event)">
<div class="c-grid__x l-grid l-grid-x"
ng-if="!controller.getGridSize()[0] < 3"
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
<div class="c-grid__y l-grid l-grid-y"
ng-if="!controller.getGridSize()[1] < 3"
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
</div>
<!-- Fixed position elements -->
<div ng-repeat="element in controller.getElements()"
class="l-fixed-position-item s-selectable s-moveable is-selectable is-moveable"
ng-style="element.style"
mct-selectable="controller.getContext(element)"
mct-init-select="controller.shouldSelect(element)">
<mct-include key="element.template"
parameters="{ gridSize: controller.getGridSize() }"
ng-model="element">
</mct-include>
</div>
<!-- Selection highlight, handles -->
<span class="c-frame-edit" ng-if="controller.isElementSelected()">
<div class="c-frame-edit__move"
mct-drag-down="controller.moveHandle().startDrag()"
mct-drag="controller.moveHandle().continueDrag(delta)"
mct-drag-up="controller.endDrag()"
ng-style="controller.getSelectedElementStyle()">
</div>
<div ng-repeat="handle in controller.handles()"
class="c-frame-edit__handle c-frame-edit__handle--nwse"
ng-style="handle.style()"
mct-drag-down="handle.startDrag()"
mct-drag="handle.continueDrag(delta)"
mct-drag-up="controller.endDrag(handle)">
</div>
</span>
</div>

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.
-->
<div class="frame frame-template t-frame-inner abs has-local-controls t-object-type-{{ domainObject.getModel().type }}">
<div class="abs object-browse-bar l-flex-row">
<div class="left flex-elem l-flex-row grows">
<mct-representation
key="'object-header-frame'"
mct-object="domainObject"
class="l-flex-row flex-elem object-header grows">
</mct-representation>
</div>
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed h-local-controls local-controls-hidden">
<mct-representation
key="'switcher'"
ng-model="representation"
mct-object="domainObject">
</mct-representation>
<a class="s-button icon-expand t-btn-view-large"
title="View large"
mct-trigger-modal>
</a>
</div>
</div>
<div class="abs object-holder">
<mct-representation
key="representation.selected.key"
mct-object="representation.selected.key && domainObject">
</mct-representation>
</div>
</div>

View File

@ -1,641 +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/FixedController",
"zepto"
],
function (
FixedController,
$
) {
describe("The Fixed Position controller", function () {
var mockScope,
mockQ,
mockDialogService,
mockFormatter,
mockDomainObject,
mockEvent,
testGrid,
testModel,
testConfiguration,
mockOpenMCT,
mockTelemetryAPI,
mockCompositionAPI,
mockCompositionCollection,
mockChildren,
mockConductor,
mockMetadata,
mockTimeSystem,
mockLimitEvaluator,
mockSelection,
mockObjects,
mockNewDomainObject,
unlistenFunc,
$element = [],
selectable = [],
controller;
// Utility function; find a $on calls for a given expression.
function findOn(expr) {
var on;
mockScope.$on.calls.all().forEach(function (call) {
if (call.args[0] === expr) {
on = call.args[1];
}
});
return on;
}
function makeMockDomainObject(id) {
return {
identifier: {
key: "domainObject-" + id,
namespace: ""
},
name: "Point " + id
};
}
beforeEach(function () {
mockScope = jasmine.createSpyObj(
'$scope',
["$on", "$watch", "$digest", "commit"]
);
mockQ = jasmine.createSpyObj('$q', ['when']);
mockDialogService = jasmine.createSpyObj(
'dialogService',
['getUserInput']
);
mockFormatter = jasmine.createSpyObj(
'telemetryFormatter',
['format']
);
mockFormatter.format.and.callFake(function (valueMetadata) {
return "Formatted " + valueMetadata.value;
});
mockConductor = jasmine.createSpyObj('conductor', [
'on',
'off',
'bounds',
'timeSystem',
'clock'
]);
mockConductor.bounds.and.returnValue({});
mockTimeSystem = {
metadata: {
key: 'key'
}
};
mockConductor.timeSystem.and.returnValue(mockTimeSystem);
mockEvent = jasmine.createSpyObj(
'event',
['preventDefault']
);
mockTelemetryAPI = jasmine.createSpyObj('telemetry',
[
'subscribe',
'request',
'isTelemetryObject',
'getMetadata',
'limitEvaluator',
'getValueFormatter'
]
);
mockTelemetryAPI.isTelemetryObject.and.returnValue(true);
mockTelemetryAPI.request.and.returnValue(Promise.resolve([]));
testGrid = [123, 456];
testModel = {
composition: ['a', 'b', 'c'],
layoutGrid: testGrid
};
testConfiguration = { elements: [
{ type: "fixed.telemetry", id: 'a', x: 1, y: 1, useGrid: true},
{ type: "fixed.telemetry", id: 'b', x: 1, y: 1, useGrid: true},
{ type: "fixed.telemetry", id: 'c', x: 1, y: 1, useGrid: true}
]};
mockChildren = testModel.composition.map(makeMockDomainObject);
mockCompositionCollection = jasmine.createSpyObj('compositionCollection', [
'load',
'on',
'off'
]);
mockCompositionAPI = jasmine.createSpyObj('composition', [
'get'
]);
mockCompositionAPI.get.and.returnValue(mockCompositionCollection);
mockCompositionCollection.load.and.returnValue(
Promise.resolve(mockChildren)
);
mockScope.model = testModel;
mockScope.configuration = testConfiguration;
mockNewDomainObject = jasmine.createSpyObj("newDomainObject", [
'layoutGrid',
'configuration',
'composition'
]);
mockNewDomainObject.layoutGrid = testGrid;
mockNewDomainObject.configuration = {
'fixed-display': testConfiguration
};
mockNewDomainObject.composition = ['a', 'b', 'c'];
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getId', 'getModel', 'getCapability', 'useCapability']
);
mockDomainObject.useCapability.and.returnValue(mockNewDomainObject);
mockScope.domainObject = mockDomainObject;
selectable[0] = {
context: {
oldItem: mockDomainObject
}
};
mockSelection = jasmine.createSpyObj("selection", [
'select',
'on',
'off',
'get'
]);
mockSelection.get.and.returnValue([]);
unlistenFunc = jasmine.createSpy("unlisten");
mockObjects = jasmine.createSpyObj('objects', [
'observe',
'get'
]);
mockObjects.observe.and.returnValue(unlistenFunc);
mockOpenMCT = {
time: mockConductor,
telemetry: mockTelemetryAPI,
composition: mockCompositionAPI,
selection: mockSelection,
objects: mockObjects
};
$element = $('<div></div>');
spyOn($element[0], 'click');
mockMetadata = jasmine.createSpyObj('mockMetadata', [
'valuesForHints',
'value',
'values'
]);
mockMetadata.value.and.returnValue({
key: 'value'
});
mockMetadata.valuesForHints.and.callFake(function (hints) {
if (hints === ['domain']) {
return [{
key: 'time'
}];
} else {
return [{
key: 'value'
}];
}
});
mockLimitEvaluator = jasmine.createSpyObj('limitEvaluator', [
'evaluate'
]);
mockLimitEvaluator.evaluate.and.returnValue({});
mockTelemetryAPI.getMetadata.and.returnValue(mockMetadata);
mockTelemetryAPI.limitEvaluator.and.returnValue(mockLimitEvaluator);
mockTelemetryAPI.getValueFormatter.and.returnValue(mockFormatter);
controller = new FixedController(
mockScope,
mockQ,
mockDialogService,
mockOpenMCT,
$element
);
spyOn(controller, "mutate");
});
it("subscribes a domain object", function () {
var object = makeMockDomainObject("mock");
return controller.getTelemetry(object).then(function () {
expect(mockTelemetryAPI.subscribe).toHaveBeenCalledWith(
object,
jasmine.any(Function),
jasmine.any(Object)
);
});
});
it("releases subscription when a domain objects is removed", function () {
var unsubscribe = jasmine.createSpy('unsubscribe');
var unsubscribePromise = new Promise(function (resolve) {
unsubscribe.and.callFake(resolve);
});
var object = makeMockDomainObject("mock");
mockTelemetryAPI.subscribe.and.returnValue(unsubscribe);
return controller.getTelemetry(object).then(function () {
controller.onCompositionRemove(object.identifier);
return unsubscribePromise;
}).then(function () {
expect(unsubscribe).toHaveBeenCalled();
});
});
it("exposes visible elements based on configuration", function () {
var elements = controller.getElements();
expect(elements.length).toEqual(3);
expect(elements[0].id).toEqual('a');
expect(elements[1].id).toEqual('b');
expect(elements[2].id).toEqual('c');
});
it("allows elements to be selected", function () {
selectable[0].context.elementProxy = controller.getElements()[1];
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
expect(controller.isElementSelected()).toBe(true);
});
it("allows selection retrieval", function () {
var elements = controller.getElements();
selectable[0].context.elementProxy = elements[1];
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
expect(controller.getSelectedElement()).toEqual(elements[1]);
});
it("selects the parent view when selected element is removed", function () {
var elements = controller.getElements();
selectable[0].context.elementProxy = elements[1];
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
controller.remove(elements[1]);
expect($element[0].click).toHaveBeenCalled();
});
it("retains selections during refresh", function () {
// Get elements; remove one of them; trigger refresh.
// Same element (at least by index) should still be selected.
var elements = controller.getElements();
selectable[0].context.elementProxy = elements[1];
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
expect(controller.getSelectedElement()).toEqual(elements[1]);
controller.remove(elements[2]);
elements = controller.getElements();
// Verify removal, as test assumes this
expect(elements.length).toEqual(2);
expect(controller.shouldSelect(elements[1])).toBe(true);
});
it("Displays received values for telemetry elements", function () {
var elements;
var mockTelemetry = {
time: 100,
value: 200
};
var testElement = {};
var telemetryObject = {
identifier: {
key: '12345'
}
};
mockConductor.clock.and.returnValue({});
controller.elementProxiesById = {};
controller.elementProxiesById['12345'] = [testElement];
controller.elementProxies = [testElement];
controller.subscribeToObject(telemetryObject);
mockTelemetryAPI.subscribe.calls.mostRecent().args[1](mockTelemetry);
return new Promise(function (resolve) {
mockScope.$digest.and.callFake(resolve);
}).then(function () {
// Get elements that controller is now exposing
elements = controller.getElements();
// Formatted values should be available
expect(elements[0].value).toEqual("Formatted 200");
});
});
it("updates elements styles when grid size changes", function () {
// Grid size is initially set to testGrid which is [123, 456]
var originalLeft = controller.getElements()[0].style.left;
// Change the grid size
controller.updateElementPositions([20, 20]);
expect(controller.getElements()[0].style.left).not.toEqual(originalLeft);
});
it("listens for drop events", function () {
mockScope.domainObject = mockDomainObject;
mockScope.model = testModel;
// Layout should position panels according to
// where the user dropped them, so it needs to
// listen for drop events.
expect(mockScope.$on).toHaveBeenCalledWith(
'mctDrop',
jasmine.any(Function)
);
// Verify precondition
expect(testConfiguration.elements.length).toEqual(3);
// Notify that a drop occurred
testModel.composition.push('d');
mockObjects.get.and.returnValue(Promise.resolve([]));
findOn('mctDrop')(
mockEvent,
'd',
{ x: 300, y: 100 }
);
// Should have added an element
expect(testConfiguration.elements.length).toEqual(4);
// ...and prevented default...
expect(mockEvent.preventDefault).toHaveBeenCalled();
});
it("ignores drops when default has been prevented", function () {
// Avoids redundant drop-handling, WTD-1233
mockEvent.defaultPrevented = true;
// Notify that a drop occurred
testModel.composition.push('d');
findOn('mctDrop')(
mockEvent,
'd',
{ x: 300, y: 100 }
);
// Should NOT have added an element
expect(testConfiguration.elements.length).toEqual(3);
});
it("unsubscribes when destroyed", function () {
var unsubscribe = jasmine.createSpy('unsubscribe');
var object = makeMockDomainObject("mock");
mockTelemetryAPI.subscribe.and.returnValue(unsubscribe);
return controller.getTelemetry(object).then(function () {
expect(unsubscribe).not.toHaveBeenCalled();
// Destroy the scope
findOn('$destroy')();
expect(unsubscribe).toHaveBeenCalled();
});
});
it("exposes its grid size", function () {
expect(controller.getGridSize()).toEqual(testGrid);
});
it("exposes drag handles", function () {
var handles;
selectable[0].context.elementProxy = controller.getElements()[1];
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
// Should have a non-empty array of handles
handles = controller.handles();
expect(handles).toEqual(jasmine.any(Array));
expect(handles.length).not.toEqual(0);
// And they should have start/continue/end drag methods
handles.forEach(function (handle) {
expect(handle.startDrag).toEqual(jasmine.any(Function));
expect(handle.continueDrag).toEqual(jasmine.any(Function));
expect(handle.endDrag).toEqual(jasmine.any(Function));
});
});
it("exposes a move handle", function () {
selectable[0].context.elementProxy = controller.getElements()[1];
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
// Should have a move handle
var handle = controller.moveHandle();
// And it should have start/continue/end drag methods
expect(handle.startDrag).toEqual(jasmine.any(Function));
expect(handle.continueDrag).toEqual(jasmine.any(Function));
expect(handle.endDrag).toEqual(jasmine.any(Function));
});
it("updates selection style during drag", function () {
var oldStyle;
selectable[0].context.elementProxy = controller.getElements()[1];
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
// Get style
oldStyle = controller.getSelectedElementStyle();
// Start a drag gesture
controller.moveHandle().startDrag();
// Haven't moved yet; style shouldn't have updated yet
expect(controller.getSelectedElementStyle()).toEqual(oldStyle);
// Drag a little
controller.moveHandle().continueDrag([1000, 100]);
// Style should have been updated
expect(controller.getSelectedElementStyle()).not.toEqual(oldStyle);
});
it("cleans up selection on scope destroy", function () {
expect(mockScope.$on).toHaveBeenCalledWith(
'$destroy',
jasmine.any(Function)
);
mockScope.$on.calls.mostRecent().args[1]();
expect(mockOpenMCT.selection.off).toHaveBeenCalledWith(
'change',
jasmine.any(Function)
);
});
describe("on display bounds changes", function () {
var testBounds;
var boundsChangeCallback;
var objectOne;
var objectTwo;
beforeEach(function () {
testBounds = { start: 123, end: 321 };
boundsChangeCallback = mockConductor.on.calls.mostRecent().args[1];
objectOne = {};
objectTwo = {};
controller.telemetryObjects = [
objectOne,
objectTwo
];
spyOn(controller, "fetchHistoricalData");
controller.fetchHistoricalData.and.callThrough();
});
it("registers a bounds change listener", function () {
expect(mockConductor.on).toHaveBeenCalledWith("bounds", jasmine.any(Function));
});
it("requests only a single point", function () {
mockConductor.clock.and.returnValue(undefined);
boundsChangeCallback(testBounds);
expect(mockTelemetryAPI.request.calls.count()).toBe(2);
mockTelemetryAPI.request.calls.all().forEach(function (call) {
expect(call.args[1].size).toBe(1);
});
});
it("Does not fetch historical data on tick", function () {
boundsChangeCallback(testBounds, true);
expect(mockTelemetryAPI.request.calls.count()).toBe(0);
});
});
describe("on receipt of telemetry", function () {
var mockTelemetryObject;
var testValue;
var testElement;
beforeEach(function () {
mockTelemetryObject = {
identifier: {
key: '12345'
}
};
testValue = 30;
testElement = {};
controller.elementProxiesById = {};
controller.elementProxiesById['12345'] = [testElement];
controller.elementProxies = [testElement];
});
it("updates displayed values from historical telemetry", function () {
spyOn(controller, "updateView");
controller.updateView.and.callThrough();
mockTelemetryAPI.request.and.returnValue(Promise.resolve([{
time: 100,
value: testValue
}]));
controller.fetchHistoricalData(mockTelemetryObject);
return new Promise(function (resolve) {
mockScope.$digest.and.callFake(resolve);
}).then(function () {
expect(controller.updateView).toHaveBeenCalled();
expect(controller.getElements()[0].value)
.toEqual("Formatted " + testValue);
});
});
it("selects an range value to display, if available", function () {
mockMetadata.valuesForHints.and.returnValue([
{
key: 'range',
source: 'range'
}
]);
var key = controller.chooseValueMetadataToDisplay(mockMetadata).source;
expect(key).toEqual('range');
});
it("selects the first non-domain value to display, if no range available", function () {
mockMetadata.valuesForHints.and.returnValue([]);
mockMetadata.values.and.returnValue([
{
key: 'domain',
source: 'domain',
hints: {
domain: 1
}
},
{
key: 'image',
source: 'image',
hints: {
image: 1
}
}
]);
var key = controller.chooseValueMetadataToDisplay(mockMetadata).source;
expect(key).toEqual('image');
});
it("reflects limit status", function () {
mockLimitEvaluator.evaluate.and.returnValue({cssClass: "alarm-a"});
controller.updateView(mockTelemetryObject, [{
time: 100,
value: testValue
}]);
return new Promise(function (resolve) {
mockScope.$digest.and.callFake(resolve);
}).then(function () {
// Limit-based CSS classes should be available
expect(controller.getElements()[0].cssClass).toEqual("alarm-a");
});
});
it("listens for selection change events", function () {
expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
'change',
jasmine.any(Function)
);
});
});
});
}
);

View File

@ -1,92 +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/FixedDragHandle'],
function (FixedDragHandle) {
var TEST_GRID_SIZE = [13, 33];
describe("A fixed position drag handle", function () {
var mockElementHandle,
mockConfigPath,
mockFixedControl,
handle;
beforeEach(function () {
mockElementHandle = jasmine.createSpyObj(
'elementHandle',
['x', 'y','getGridSize']
);
mockElementHandle.x.and.returnValue(6);
mockElementHandle.y.and.returnValue(8);
mockElementHandle.getGridSize.and.returnValue(TEST_GRID_SIZE);
mockFixedControl = jasmine.createSpyObj(
'fixedControl',
['updateSelectionStyle', 'mutate']
);
mockFixedControl.updateSelectionStyle.and.returnValue();
mockFixedControl.mutate.and.returnValue();
mockConfigPath = jasmine.createSpy('configPath');
handle = new FixedDragHandle(
mockElementHandle,
mockConfigPath,
mockFixedControl
);
});
it("provides a style for positioning", function () {
var style = handle.style();
// 6 grid coords * 13 pixels - 3 pixels for centering
expect(style.left).toEqual('75px');
// 8 grid coords * 33 pixels - 3 pixels for centering
expect(style.top).toEqual('261px');
});
it("allows handles to be dragged", function () {
handle.startDrag();
handle.continueDrag([16, 8]);
// Should update x/y, snapped to grid
expect(mockElementHandle.x).toHaveBeenCalledWith(7);
expect(mockElementHandle.y).toHaveBeenCalledWith(8);
handle.continueDrag([-16, -35]);
// Should have interpreted relative to initial state
expect(mockElementHandle.x).toHaveBeenCalledWith(5);
expect(mockElementHandle.y).toHaveBeenCalledWith(7);
// Should have called updateSelectionStyle once per continueDrag
expect(mockFixedControl.updateSelectionStyle.calls.count()).toEqual(2);
// Finally, ending drag should mutate
handle.endDrag();
expect(mockFixedControl.mutate).toHaveBeenCalled();
});
});
}
);

View File

@ -1,71 +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/FixedProxy'],
function (FixedProxy) {
describe("Fixed Position view's selection proxy", function () {
var mockCallback,
mockQ,
mockDialogService,
mockPromise,
proxy;
beforeEach(function () {
mockCallback = jasmine.createSpy('callback');
mockQ = jasmine.createSpyObj('$q', ['when']);
mockDialogService = jasmine.createSpyObj('dialogService', ['getUserInput']);
mockPromise = jasmine.createSpyObj('promise', ['then']);
mockQ.when.and.returnValue(mockPromise);
proxy = new FixedProxy(mockCallback, mockQ, mockDialogService);
});
it("handles promised element creation", function () {
// The element factory may return promises (e.g. if
// user input is required) so make sure proxy is wrapping these
proxy.add("fixed.box");
expect(mockQ.when).toHaveBeenCalled();
});
it("notifies its callback when an element is created", function () {
proxy.add("fixed.box");
// Callback should not have been invoked yet
expect(mockCallback).not.toHaveBeenCalled();
// Resolve the promise
mockPromise.then.calls.mostRecent().args[0]({});
// Should have fired the callback
expect(mockCallback).toHaveBeenCalledWith({
type: "fixed.box",
x: 0,
y: 0,
width: 1,
height: 1,
useGrid: true
});
});
});
}
);

View File

@ -1,81 +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/LayoutDrag"],
function (LayoutDrag) {
describe("A Layout drag handler", function () {
var testPosition = {
position: [8, 11],
dimensions: [3, 2]
};
it("changes position by a supplied factor, rounding by grid size", function () {
var handler = new LayoutDrag(
testPosition,
[1, 1],
[0, 0],
[10, 20]
);
expect(handler.getAdjustedPosition([37, 84])).toEqual({
position: [12, 15],
dimensions: [3, 2]
});
expect(handler.getAdjustedPosition([-37, 84])).toEqual({
position: [4, 15],
dimensions: [3, 2]
});
});
it("changes dimensions by a supplied factor, rounding by grid size", function () {
var handler = new LayoutDrag(
testPosition,
[0, 0],
[1, 1],
[10, 20]
);
expect(handler.getAdjustedPosition([37, 84])).toEqual({
position: [8, 11],
dimensions: [7, 6]
});
});
it("allows mixing dimension and position factors", function () {
var handler = new LayoutDrag(
testPosition,
[0, 1],
[-1, 0],
[10, 20]
);
expect(handler.getAdjustedPosition([11, 84])).toEqual({
position: [8, 15],
dimensions: [2, 2]
});
});
});
}
);

View File

@ -1,128 +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([
'../src/MCTTriggerModal'
], function (
MCTTriggerModal
) {
describe('MCTTriggerModal', function () {
var $scope,
$element,
frame,
layoutContainer,
$document,
mctTriggerModal;
function makeElement(classes, parentEl) {
var elem = jasmine.createSpyObj('element.' + classes.join('.'), [
'hasClass',
'parent'
]);
elem.hasClass.and.callFake(function (className) {
return classes.indexOf(className) !== -1;
});
elem.parent.and.returnValue(parentEl);
var div = document.createElement('div');
div.className = classes.join(' ');
parentEl[0].appendChild(div);
elem[0] = div;
return elem;
}
beforeEach(function () {
$scope = jasmine.createSpyObj('$scope', ['$on']);
$scope.domainObject = { getCapability: function () {
return { getActions: function () {
return [];
}};
}};
$element = jasmine.createSpyObj('$element', [
'parent',
'remove',
'on',
'off'
]);
layoutContainer = document.createElement('div');
frame = makeElement(['frame'], [layoutContainer]);
var child = makeElement([], frame);
for (var i = 0; i < 5; i++) {
child = makeElement([], child);
}
$element.parent.and.returnValue(child);
$document = [jasmine.createSpyObj('document', ['createElement'])];
$document[0].body = document.createElement('div');
$document[0].createElement.and.callFake(function (tag) {
return document.createElement(tag);
});
mctTriggerModal = new MCTTriggerModal($document);
});
it('is a directive definition', function () {
expect(mctTriggerModal.restrict).toBe('A');
expect(mctTriggerModal.link).toEqual(jasmine.any(Function));
});
describe('link', function () {
beforeEach(function () {
mctTriggerModal.link($scope, $element);
});
it('attaches handlers to $element', function () {
expect($element.on).toHaveBeenCalledWith(
'click',
jasmine.any(Function)
);
});
it('cleans up on $scope $destroy', function () {
expect($scope.$on).toHaveBeenCalledWith(
'$destroy',
jasmine.any(Function)
);
$scope.$on.calls.mostRecent().args[1]();
expect($element.off).toHaveBeenCalledWith(
'click',
jasmine.any(Function)
);
});
it('opens and closes overlays', function () {
[
'a.close', 'a.t-done', '.abs.blocker'
].forEach(function (selector) {
$element.on.calls.mostRecent().args[1]();
var container = $document[0].body.querySelector('.t-contents');
expect(container.children[0]).toBe(frame[0]);
expect(layoutContainer.children[0]).not.toBe(frame[0]);
$document[0].body.querySelector(selector)
.dispatchEvent(new Event('click'));
expect(container.children[0]).not.toBe(frame[0]);
expect(layoutContainer.children[0]).toBe(frame[0]);
});
});
});
});
});

View File

@ -1,50 +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/elements/AccessorMutator'],
function (AccessorMutator) {
describe("An accessor-mutator", function () {
var testObject,
am;
beforeEach(function () {
testObject = { t: 42, other: 100 };
am = new AccessorMutator(testObject, 't');
});
it("allows access to a property", function () {
expect(am()).toEqual(42);
});
it("allows mutation of a property", function () {
expect(am("some other value")).toEqual("some other value");
expect(testObject).toEqual({
t: "some other value",
other: 100
});
});
});
}
);

View File

@ -1,55 +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/elements/BoxProxy'],
function (BoxProxy) {
describe("A fixed position box proxy", function () {
var testElement,
testElements,
proxy;
beforeEach(function () {
testElement = {
x: 1,
y: 2,
width: 42,
height: 24,
fill: "transparent"
};
testElements = [{}, {}, testElement, {}];
proxy = new BoxProxy(
testElement,
testElements.indexOf(testElement),
testElements
);
});
it("provides getter/setter for fill color", function () {
expect(proxy.fill()).toEqual('transparent');
expect(proxy.fill('#FFF')).toEqual('#FFF');
expect(proxy.fill()).toEqual('#FFF');
});
});
}
);

View File

@ -1,69 +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/elements/ElementFactory'],
function (ElementFactory) {
var DIALOG_ELEMENTS = ['image', 'text'],
NON_DIALOG_ELEMENTS = ['box', 'line'];
describe("The fixed position element factory", function () {
var mockDialogService,
mockPromise,
factory;
beforeEach(function () {
mockDialogService = jasmine.createSpyObj(
'dialogService',
['getUserInput']
);
mockPromise = jasmine.createSpyObj(
'promise',
['then']
);
mockDialogService.getUserInput.and.returnValue(mockPromise);
mockPromise.then.and.returnValue(mockPromise);
factory = new ElementFactory(mockDialogService);
});
DIALOG_ELEMENTS.forEach(function (type) {
it("shows a dialog for " + type + " elements", function () {
expect(factory.createElement('fixed.' + type))
.toEqual(mockPromise);
expect(mockDialogService.getUserInput).toHaveBeenCalled();
});
});
NON_DIALOG_ELEMENTS.forEach(function (type) {
it("immediately provides " + type + " elements", function () {
var result = factory.createElement('fixed.' + type);
expect(result).toBeDefined();
expect(result).not.toEqual(mockPromise);
expect(mockDialogService.getUserInput).not.toHaveBeenCalled();
});
});
});
}
);

View File

@ -1,51 +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/elements/ElementProxies'],
function (ElementProxies) {
// Expect these element types to have proxies
var ELEMENT_TYPES = [
"fixed.telemetry",
"fixed.line",
"fixed.box",
"fixed.text",
"fixed.image"
];
// Verify that the set of proxies exposed matches the specific
// list above.
describe("The set of element proxies", function () {
ELEMENT_TYPES.forEach(function (t) {
it("exposes a proxy wrapper for " + t + " elements", function () {
expect(typeof ElementProxies[t]).toEqual('function');
});
});
it("exposes no additional wrappers", function () {
expect(Object.keys(ElementProxies).length)
.toEqual(ELEMENT_TYPES.length);
});
});
}
);

View File

@ -1,98 +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/elements/ElementProxy'],
function (ElementProxy) {
describe("A fixed position element proxy", function () {
var testElement,
testElements,
proxy;
beforeEach(function () {
testElement = {
x: 1,
y: 2,
stroke: '#717171',
width: 42,
height: 24,
useGrid: true
};
testElements = [{}, {}, testElement, {}];
proxy = new ElementProxy(
testElement,
testElements.indexOf(testElement),
testElements,
[13,21]
);
});
it("exposes element properties", function () {
Object.keys(testElement).forEach(function (k) {
expect(proxy[k]()).toEqual(testElement[k]);
});
});
it("allows order to be changed", function () {
proxy.order("down");
expect(testElements).toEqual([{}, testElement, {}, {}]);
proxy.order("up");
expect(testElements).toEqual([{}, {}, testElement, {}]);
proxy.order("bottom");
expect(testElements).toEqual([testElement, {}, {}, {}]);
proxy.order("top");
expect(testElements).toEqual([{}, {}, {}, testElement]);
});
it("ensures x/y values are non-negative", function () {
proxy.x(-1);
proxy.y(-400);
expect(proxy.x()).toEqual(0);
expect(proxy.y()).toEqual(0);
});
it("allows modifying the current grid size", function () {
proxy.setGridSize([112,420]);
expect(proxy.gridSize).toEqual([112,420]);
});
it("returns the current grid size only if the element snaps to grid", function () {
expect(proxy.getGridSize()).toEqual([13,21]);
proxy.useGrid(false);
expect(proxy.getGridSize()).toEqual([1,1]);
});
it("returns the mininum height and width of an element currently used units", function () {
// Assumes mininum height and width are 10, in pixels
expect(proxy.getMinWidth()).toEqual(1);
expect(proxy.getMinHeight()).toEqual(1);
proxy.setGridSize([7,4]);
expect(proxy.getMinWidth()).toEqual(2);
expect(proxy.getMinHeight()).toEqual(3);
proxy.useGrid(false);
expect(proxy.getMinWidth()).toEqual(10);
expect(proxy.getMinHeight()).toEqual(10);
});
});
}
);

View File

@ -1,56 +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/elements/ImageProxy'],
function (ImageProxy) {
describe("A fixed position image proxy", function () {
var testElement,
testElements,
proxy;
beforeEach(function () {
testElement = {
x: 1,
y: 2,
width: 42,
height: 24,
url: "http://www.nasa.gov"
};
testElements = [{}, {}, testElement, {}];
proxy = new ImageProxy(
testElement,
testElements.indexOf(testElement),
testElements
);
});
it("provides getter/setter for image URL", function () {
expect(proxy.url()).toEqual("http://www.nasa.gov");
expect(proxy.url("http://www.nasa.gov/some.jpg"))
.toEqual("http://www.nasa.gov/some.jpg");
expect(proxy.url()).toEqual("http://www.nasa.gov/some.jpg");
});
});
}
);

View File

@ -1,81 +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/elements/LineHandle'],
function (LineHandle) {
describe("A fixed position drag handle", function () {
var testElement,
mockElementProxy,
handle,
TEST_GRID_SIZE = [45, 21];
beforeEach(function () {
testElement = {
x: 3,
y: 42,
x2: 8,
y2: 11,
useGrid: true
};
mockElementProxy = jasmine.createSpyObj('elementProxy', ['getGridSize']);
mockElementProxy.getGridSize.and.returnValue(TEST_GRID_SIZE);
handle = new LineHandle(testElement, mockElementProxy, 'x', 'y', 'x2', 'y2');
});
it("provides x/y grid coordinates for its corner", function () {
expect(handle.x()).toEqual(3);
expect(handle.y()).toEqual(42);
});
it("changes x and y positions", function () {
handle.x(30);
expect(testElement.x).toEqual(30);
handle.y(40);
expect(testElement.y).toEqual(40);
});
it("disallows values less than zero", function () {
handle.x(-1);
handle.y(-400);
expect(testElement.x).toEqual(0);
expect(testElement.y).toEqual(0);
});
it("ensures that end points remain different", function () {
handle.x(testElement.x2);
handle.y(testElement.y2);
// First change should have been fine, because y was different
expect(testElement.x).toEqual(testElement.x2);
// Second change should have been rejected
expect(testElement.y).not.toEqual(testElement.y2);
});
it("returns the correct grid size", function () {
expect(handle.getGridSize()).toEqual(TEST_GRID_SIZE);
});
});
}
);

View File

@ -1,95 +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/elements/LineProxy'],
function (LineProxy) {
describe("A fixed position line proxy", function () {
var vertical, horizontal, diagonal, reversed;
beforeEach(function () {
vertical = { x: 1, y: 4, x2: 1, y2: 8};
horizontal = { x: 3, y: 3, x2: 12, y2: 3};
diagonal = { x: 3, y: 8, x2: 5, y2: 11};
reversed = { x2: 3, y2: 8, x: 5, y: 11};
});
it("ensures visible width for vertical lines", function () {
expect(new LineProxy(vertical).width()).toEqual(1);
});
it("ensures visible height for horizontal lines", function () {
expect(new LineProxy(horizontal).height()).toEqual(1);
});
it("provides a bounding box for lines", function () {
var proxy = new LineProxy(diagonal);
expect(proxy.x()).toEqual(3);
expect(proxy.y()).toEqual(8);
expect(proxy.width()).toEqual(2);
expect(proxy.height()).toEqual(3);
});
it("bounds lines identically regardless of point order", function () {
// That is, x(), width(), y(), and height() should always give
// the same results for the same line segments, regardless of
// which point is x,y and which is x2,y2
['x', 'y', 'width', 'height'].forEach(function (method) {
expect(new LineProxy(diagonal)[method]())
.toEqual(new LineProxy(reversed)[method]());
});
});
it("adjusts both ends when mutating x", function () {
var proxy = new LineProxy(diagonal);
proxy.x(6);
expect(diagonal).toEqual({ x: 6, y: 8, x2: 8, y2: 11});
});
it("adjusts both ends when mutating y", function () {
var proxy = new LineProxy(diagonal);
proxy.y(6);
expect(diagonal).toEqual({ x: 3, y: 6, x2: 5, y2: 9});
});
it("provides internal positions for SVG lines", function () {
var proxy;
proxy = new LineProxy(diagonal);
expect(proxy.x1()).toEqual(0);
expect(proxy.y1()).toEqual(0);
expect(proxy.x2()).toEqual(2);
expect(proxy.y2()).toEqual(3);
proxy = new LineProxy(reversed);
expect(proxy.x1()).toEqual(2);
expect(proxy.y1()).toEqual(3);
expect(proxy.x2()).toEqual(0);
expect(proxy.y2()).toEqual(0);
});
it("provides handles for both ends", function () {
expect(new LineProxy(diagonal).handles().length).toEqual(2);
});
});
}
);

View File

@ -1,93 +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/elements/ResizeHandle'],
function (ResizeHandle) {
var TEST_MIN_WIDTH = 4,
TEST_MIN_HEIGHT = 2,
TEST_GRID_SIZE = [34, 81];
describe("A fixed position drag handle", function () {
var testElement,
mockElementProxy,
handle;
beforeEach(function () {
testElement = {
x: 3,
y: 42,
width: 30,
height: 36,
useGrid: true
};
mockElementProxy = jasmine.createSpyObj('elementProxy', [
'getGridSize',
'getMinWidth',
'getMinHeight'
]);
mockElementProxy.getGridSize.and.returnValue(TEST_GRID_SIZE);
mockElementProxy.getMinWidth.and.returnValue(TEST_MIN_WIDTH);
mockElementProxy.getMinHeight.and.returnValue(TEST_MIN_HEIGHT);
handle = new ResizeHandle(
mockElementProxy,
testElement
);
});
it("provides x/y grid coordinates for lower-right corner", function () {
expect(handle.x()).toEqual(33);
expect(handle.y()).toEqual(78);
});
it("changes width of an element", function () {
handle.x(30);
// Should change width, not x
expect(testElement.x).toEqual(3);
expect(testElement.width).toEqual(27);
});
it("changes height of an element", function () {
handle.y(60);
// Should change height, not y
expect(testElement.y).toEqual(42);
expect(testElement.height).toEqual(18);
});
it("enforces minimum width/height", function () {
handle.x(testElement.x);
handle.y(testElement.y);
expect(testElement.x).toEqual(3);
expect(testElement.y).toEqual(42);
expect(testElement.width).toEqual(TEST_MIN_WIDTH);
expect(testElement.height).toEqual(TEST_MIN_HEIGHT);
});
it("returns the correct grid size", function () {
expect(handle.getGridSize()).toEqual(TEST_GRID_SIZE);
});
});
}
);

View File

@ -1,54 +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/elements/TelemetryProxy'],
function (TelemetryProxy) {
describe("A fixed position telemetry proxy", function () {
var testElement,
testElements,
proxy;
beforeEach(function () {
testElement = {
x: 1,
y: 2,
z: 3,
width: 42,
height: 24,
id: "test-id"
};
testElements = [{}, {}, testElement, {}];
proxy = new TelemetryProxy(
testElement,
testElements.indexOf(testElement),
testElements
);
});
it("exposes the element's id", function () {
expect(proxy.id).toEqual('test-id');
});
});
}
);

View File

@ -1,70 +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/elements/TextProxy'],
function (TextProxy) {
describe("A fixed position text proxy", function () {
var testElement,
testElements,
proxy;
beforeEach(function () {
testElement = {
x: 1,
y: 2,
width: 42,
height: 24,
fill: "transparent",
size: "20px"
};
testElements = [{}, {}, testElement, {}];
proxy = new TextProxy(
testElement,
testElements.indexOf(testElement),
testElements
);
});
it("provides getter/setter for fill color", function () {
expect(proxy.fill()).toEqual('transparent');
expect(proxy.fill('#FFF')).toEqual('#FFF');
expect(proxy.fill()).toEqual('#FFF');
});
it("provides getter/setter for text size", function () {
expect(proxy.size()).toEqual('20px');
expect(proxy.size('12px')).toEqual('12px');
expect(proxy.size()).toEqual('12px');
});
it("defaults to 13px for unspecified text size", function () {
testElement = {x: 1, y: 2};
proxy = new TextProxy(testElement, 0, [testElement]);
expect(proxy.size()).toEqual('13px');
});
});
}
);

View File

@ -1,157 +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/elements/UnitAccessorMutator'],
function (UnitAccessorMutator) {
var GRID_SIZE = [13,17];
describe("An elementProxy.gridSize accessor-mutator", function () {
var mockElementProxy,
testElement,
mockLineProxy,
testLine,
uAM,
uAMLine;
beforeEach(function () {
testElement = {
x: 2,
y: 3,
width: 4,
height: 5,
useGrid: true
};
mockElementProxy = {
element: testElement,
gridSize: GRID_SIZE,
getMinHeight: jasmine.createSpy('minHeight'),
getMinWidth: jasmine.createSpy('minWidth')
};
testLine = {
x: 7,
y: 8,
x2: 9,
y2: 10,
width: 11,
height: 12,
useGrid: true
};
mockLineProxy = {
element: testLine,
gridSize: GRID_SIZE,
getMinHeight: jasmine.createSpy('minHeight'),
getMinWidth: jasmine.createSpy('minWidth')
};
uAM = new UnitAccessorMutator(mockElementProxy);
uAMLine = new UnitAccessorMutator(mockLineProxy);
mockElementProxy.getMinWidth.and.returnValue(1);
mockElementProxy.getMinHeight.and.returnValue(1);
mockLineProxy.getMinWidth.and.returnValue(1);
mockLineProxy.getMinHeight.and.returnValue(1);
});
it("allows access to useGrid", function () {
expect(uAM()).toEqual(mockElementProxy.element.useGrid);
});
it("allows mutation of useGrid", function () {
uAM(false);
expect(mockElementProxy.element.useGrid).toEqual(false);
});
it("converts coordinates appropriately for a box", function () {
uAM(false);
expect(mockElementProxy.element.x).toEqual(26);
expect(mockElementProxy.element.y).toEqual(51);
expect(mockElementProxy.element.width).toEqual(52);
expect(mockElementProxy.element.height).toEqual(85);
uAM(true);
expect(mockElementProxy.element.x).toEqual(2);
expect(mockElementProxy.element.y).toEqual(3);
expect(mockElementProxy.element.width).toEqual(4);
expect(mockElementProxy.element.height).toEqual(5);
});
it("converts coordinates appropriately for a line", function () {
uAMLine(false);
expect(mockLineProxy.element.x).toEqual(91);
expect(mockLineProxy.element.y).toEqual(136);
expect(mockLineProxy.element.x2).toEqual(117);
expect(mockLineProxy.element.y2).toEqual(170);
expect(mockLineProxy.element.width).toEqual(143);
expect(mockLineProxy.element.height).toEqual(204);
uAMLine(true);
expect(mockLineProxy.element.x).toEqual(7);
expect(mockLineProxy.element.y).toEqual(8);
expect(mockLineProxy.element.x2).toEqual(9);
expect(mockLineProxy.element.y2).toEqual(10);
expect(mockLineProxy.element.width).toEqual(11);
expect(mockLineProxy.element.height).toEqual(12);
});
it("doesn't covert coordinates unecessarily", function () {
uAM(false);
expect(mockElementProxy.element.x).toEqual(26);
expect(mockElementProxy.element.y).toEqual(51);
expect(mockElementProxy.element.width).toEqual(52);
expect(mockElementProxy.element.height).toEqual(85);
uAM(false);
expect(mockElementProxy.element.x).toEqual(26);
expect(mockElementProxy.element.y).toEqual(51);
expect(mockElementProxy.element.width).toEqual(52);
expect(mockElementProxy.element.height).toEqual(85);
});
it("snaps coordinates onto the grid", function () {
uAM(false);
mockElementProxy.element.x += 11;
mockElementProxy.element.y -= 27;
mockElementProxy.element.width -= 14;
mockElementProxy.element.height += 4;
uAM(true);
expect(mockElementProxy.element.x).toEqual(3);
expect(mockElementProxy.element.y).toEqual(1);
expect(mockElementProxy.element.width).toEqual(3);
expect(mockElementProxy.element.height).toEqual(5);
});
it("enforces a minimum height and width", function () {
uAM(false);
mockElementProxy.element.width = 4;
mockElementProxy.element.height = 4;
uAM(true);
expect(mockElementProxy.element.width).toEqual(1);
expect(mockElementProxy.element.height).toEqual(1);
});
});
}
);

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

@ -19,21 +19,18 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div
class="l-fixed-position-text l-telemetry"
ng-style="{ background: ngModel.fill(), 'border-color': ngModel.stroke(), color: ngModel.color(), 'font-size': ngModel.size() }"
>
<span
class="l-elem l-value l-obj-val-format"
data-value="{{ngModel.value}}"
ng-class="ngModel.cssClass"
>
{{ngModel.value}}
<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
class="l-elem l-title"
ng-show="ngModel.element.titled"
>
{{ngModel.name}}
</span>
</div>
</span>

View File

@ -0,0 +1,130 @@
/*****************************************************************************
* 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) {
let image = document.createElement('img');
image.src = imageUrl;
let previewImageOverlay = openmct.overlays.overlay(
{
element: image,
size: 'large',
buttons: [
{
label: 'Done',
callback: function () {
previewImageOverlay.dismiss();
}
}
]
}
);
};
$scope.annotateImage = function (ngModel, field, imageUrl) {
$scope.imageUrl = imageUrl;
let div = document.createElement('div'),
painterroInstance = {},
save = false;
div.id = 'snap-annotation';
let annotateImageOverlay = openmct.overlays.overlay(
{
element: div,
size: 'large',
buttons: [
{
label: 'Cancel',
callback: function () {
save = false;
painterroInstance.save();
annotateImageOverlay.dismiss();
}
},
{
label: 'Save',
callback: function () {
save = true;
painterroInstance.save();
annotateImageOverlay.dismiss();
}
}
]
}
);
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) {
let 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,12 +28,18 @@ export default class Editor extends EventEmitter {
super();
this.editing = false;
this.openmct = openmct;
document.addEventListener('drop', (event) => {
if (!this.isEditing()) {
this.edit();
}
}, {capture: true});
}
/**
* Initiate an editing session. This will start a transaction during
* which any persist operations will be deferred until either save()
* or finish() are called.
* @private
*/
edit() {
if (this.editing === true) {
@ -54,6 +60,8 @@ export default class Editor extends EventEmitter {
/**
* Save any unsaved changes from this editing session. This will
* end the current transaction.
*
* @private
*/
save() {
return this.getTransactionService().commit().then((result)=>{
@ -67,6 +75,8 @@ export default class Editor extends EventEmitter {
/**
* End the currently active transaction and discard unsaved changes.
*
* @private
*/
cancel() {
this.getTransactionService().cancel();

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

@ -215,6 +215,19 @@ define([
return utils.makeKeyString(identifier);
};
/**
* Given any number of identifiers, will return true if they are all equal, otherwise false.
* @param {module:openmct.ObjectAPI~Identifier[]} identifiers
*/
ObjectAPI.prototype.areIdsEqual = function (...identifiers) {
return identifiers.map(utils.parseKeyString)
.every(identifier => {
return identifier === identifiers[0] ||
(identifier.namespace === identifiers[0].namespace &&
identifier.key === identifiers[0].key);
});
}
/**
* Uniquely identifies a domain object.
*

View File

@ -22,7 +22,7 @@ class Dialog extends Overlay {
super({
element: component.$el,
size: 'fit',
notDismissable: true,
dismissable: false,
...options
});

View File

@ -12,6 +12,7 @@ class Overlay extends EventEmitter {
constructor(options) {
super();
this.dismissable = options.dismissable !== false ? true : false;
this.container = document.createElement('div');
this.container.classList.add('l-overlay-wrapper', cssClasses[options.size]);
@ -20,7 +21,7 @@ class Overlay extends EventEmitter {
dismiss: this.dismiss.bind(this),
element: options.element,
buttons: options.buttons,
notDismissable: options.notDismissable ? true : false
dismissable: this.dismissable
},
components: {
OverlayComponent: OverlayComponent
@ -35,8 +36,8 @@ class Overlay extends EventEmitter {
dismiss() {
this.emit('destroy');
this.component.$destroy();
document.body.removeChild(this.container);
this.component.$destroy();
}
/**

View File

@ -14,6 +14,14 @@ import ProgressDialog from './ProgressDialog';
class OverlayAPI {
constructor() {
this.activeOverlays = [];
this.dismissLastOverlay = this.dismissLastOverlay.bind(this);
document.addEventListener('keyup', (event) => {
if (event.key === 'Escape') {
this.dismissLastOverlay();
}
});
}
/**
@ -38,14 +46,24 @@ class OverlayAPI {
}
/**
] * A description of option properties that can be passed into the overlay
* @typedef options
* private
*/
dismissLastOverlay() {
let lastOverlay = this.activeOverlays[this.activeOverlays.length - 1];
if (lastOverlay && lastOverlay.dismissable) {
lastOverlay.dismiss();
}
}
/**
* A description of option properties that can be passed into the overlay
* @typedef options
* @property {object} element DOMElement that is to be inserted/shown on the overlay
* @property {string} size prefered size of the overlay (large, small, fit)
* @property {array} buttons optional button objects with label and callback properties
* @property {function} onDestroy callback to be called when overlay is destroyed
* @property {boolean} notDismissable to prevent user from dismissing the overlay, calling code
* will need to explicitly dismiss the overlay.
* @property {boolean} dismissable allow user to dismiss overlay by using esc, and clicking away
* from overlay. Unless set to false, all overlays will be dismissable by default.
*/
overlay(options) {
let overlay = new Overlay(options);

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';
@ -25,7 +25,7 @@ class ProgressDialog extends Overlay {
super({
element: component.$el,
size: 'fit',
notDismissable: true,
dismissable: false,
...options
});

View File

@ -5,7 +5,7 @@
</div>
<div class="c-overlay__outer">
<button class="c-click-icon c-overlay__close-button icon-x-in-circle"
v-if="!notDismissable"
v-if="dismissable"
@click="destroy">
</button>
<div class="c-overlay__contents" ref="element"></div>
@ -129,19 +129,19 @@
<script>
export default {
inject: ['dismiss', 'element', 'buttons', 'notDismissable'],
inject: ['dismiss', 'element', 'buttons', 'dismissable'],
mounted() {
this.$refs.element.appendChild(this.element);
},
methods: {
destroy: function () {
if (!this.notDismissable) {
if (this.dismissable) {
this.dismiss();
}
},
buttonClickHandler: function (method) {
method();
this.destroy();
this.$emit('destroy');
}
}
}

View File

@ -124,6 +124,10 @@ define([
return sortedMetadata;
};
TelemetryMetadataManager.prototype.getFilterableValues = function () {
return this.valueMetadatas.filter(metadatum => metadatum.filters && metadatum.filters.length > 0);
}
TelemetryMetadataManager.prototype.getDefaultDisplayValue = function () {
let valueMetadata = this.valuesForHints(['range'])[0];

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

@ -32,7 +32,7 @@ define([], function () {
// is inside a layout, or the main layout is selected.
return (openmct.editor.isEditing() && selection &&
((selection[1] && selection[1].context.item && selection[1].context.item.type === 'layout') ||
(selection[0].context.item && selection[0].context.item.type === 'layout')));
(selection[0].context.item && selection[0].context.item.type === 'layout')));
},
toolbar: function (selection) {
const DIALOG_FORM = {
@ -73,10 +73,13 @@ define([], function () {
return openmct.$injector.get('dialogService').getUserInput(form, {});
}
function getPath() {
return `configuration.items[${selection[0].context.index}]`;
}
let selectedParent = selection[1] && selection[1].context.item,
selectedObject = selection[0].context.item,
layoutItem = selection[0].context.layoutItem,
layoutItemIndex = selection[0].context.index,
toolbar = [];
if (selectedObject && selectedObject.type === 'layout') {
@ -121,134 +124,244 @@ define([], function () {
return toolbar;
}
let path = `configuration.items[${layoutItemIndex}]`;
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, selection[0].context.index);
prompt.dismiss();
}
},
{
label: 'Cancel',
callback: function () {
prompt.dismiss();
}
}
]
});
}
};
let stackOrder = {
control: "menu",
domainObject: selectedParent,
icon: "icon-layers",
title: "Move the selected object above or below other objects",
options: [
{
name: "Move to Top",
value: "top",
class: "icon-arrow-double-up"
},
{
name: "Move Up",
value: "up",
class: "icon-arrow-up"
},
{
name: "Move Down",
value: "down",
class: "icon-arrow-down"
},
{
name: "Move to Bottom",
value: "bottom",
class: "icon-arrow-double-down"
}
],
method: function (option) {
selection[1].context.orderItem(option.value, selection[0].context.index);
}
};
let useGrid = {
control: "toggle-button",
domainObject: selectedParent,
property: function () {
return getPath() + ".useGrid";
},
options: [
{
value: false,
icon: "icon-grid-snap-to",
title: "Grid snapping enabled"
},
{
value: true,
icon: "icon-grid-snap-no",
title: "Grid snapping disabled"
}
]
};
let x = {
control: "input",
type: "number",
domainObject: selectedParent,
property: function () {
return getPath() + ".x";
},
label: "X:",
title: "X position"
},
y = {
control: "input",
type: "number",
domainObject: selectedParent,
property: function () {
return getPath() + ".y";
},
label: "Y:",
title: "Y position",
},
width = {
control: 'input',
type: 'number',
domainObject: selectedParent,
property: function () {
return getPath() + ".width";
},
label: 'W:',
title: 'Resize object width'
},
height = {
control: 'input',
type: 'number',
domainObject: selectedParent,
property: function () {
return getPath() + ".height";
},
label: 'H:',
title: 'Resize object height'
};
if (layoutItem.type === 'subobject-view') {
if (toolbar.length > 0) {
toolbar.push(separator);
}
toolbar.push({
control: "toggle-button",
domainObject: selectedParent,
property: path + ".hasFrame",
property: function () {
return getPath() + ".hasFrame";
},
options: [
{
value: false,
icon: 'icon-frame-hide',
title: "Hide frame"
icon: 'icon-frame-show',
title: "Frame visible"
},
{
value: true,
icon: 'icon-frame-show',
title: "Show frame"
icon: 'icon-frame-hide',
title: "Frame hidden"
}
]
});
toolbar.push(separator);
toolbar.push(stackOrder);
toolbar.push(x);
toolbar.push(y);
toolbar.push(width);
toolbar.push(height);
toolbar.push(useGrid);
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];
const TEXT_SIZE = [8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96, 128];
let fill = {
control: "color-picker",
domainObject: selectedParent,
property: path + ".fill",
icon: "icon-paint-bucket",
title: "Set fill color"
control: "color-picker",
domainObject: selectedParent,
property: function () {
return getPath() + ".fill";
},
stroke = {
control: "color-picker",
domainObject: selectedParent,
property: path + ".stroke",
icon: "icon-line-horz",
title: "Set border color"
icon: "icon-paint-bucket",
title: "Set fill color"
},
stroke = {
control: "color-picker",
domainObject: selectedParent,
property: function () {
return getPath() + ".stroke";
},
color = {
control: "color-picker",
domainObject: selectedParent,
property: path + ".color",
icon: "icon-font",
mandatory: true,
title: "Set text color",
preventNone: true
icon: "icon-line-horz",
title: "Set border color"
},
color = {
control: "color-picker",
domainObject: selectedParent,
property: function () {
return getPath() + ".color";
},
size = {
control: "select-menu",
domainObject: selectedParent,
property: path + ".size",
title: "Set text size",
options: TEXT_SIZE.map(size => {
return {
value: size + "px"
};
})
icon: "icon-font",
mandatory: true,
title: "Set text color",
preventNone: true
},
size = {
control: "select-menu",
domainObject: selectedParent,
property: function () {
return getPath() + ".size";
},
x = {
control: "input",
type: "number",
domainObject: selectedParent,
property: path + ".x",
label: "X:",
title: "X position"
},
y = {
control: "input",
type: "number",
domainObject: selectedParent,
property: path + ".y",
label: "Y:",
title: "Y position",
},
width = {
control: 'input',
type: 'number',
domainObject: selectedParent,
property: path + ".width",
label: 'W:',
title: 'Resize object width'
},
height = {
control: 'input',
type: 'number',
domainObject: selectedParent,
property: path + ".height",
label: 'H:',
title: 'Resize object height'
};
title: "Set text size",
options: TEXT_SIZE.map(size => {
return {
value: size + "px"
};
})
};
if (layoutItem.type === 'telemetry-view') {
let displayMode = {
control: "select-menu",
domainObject: selectedParent,
property: path + ".displayMode",
title: "Set display mode",
options: [
{
name: 'Label + Value',
value: 'all'
},
{
name: "Label only",
value: "label"
},
{
name: "Value only",
value: "value"
}
]
control: "select-menu",
domainObject: selectedParent,
property: function () {
return getPath() + ".displayMode";
},
value = {
control: "select-menu",
domainObject: selectedParent,
property: path + ".value",
title: "Set value",
options: openmct.telemetry.getMetadata(selectedObject).values().map(value => {
return {
name: value.name,
value: value.key
}
})
};
title: "Set display mode",
options: [
{
name: 'Label + Value',
value: 'all'
},
{
name: "Label only",
value: "label"
},
{
name: "Value only",
value: "value"
}
]
},
value = {
control: "select-menu",
domainObject: selectedParent,
property: function () {
return getPath() + ".value";
},
title: "Set value",
options: openmct.telemetry.getMetadata(selectedObject).values().map(value => {
return {
name: value.name,
value: value.key
}
})
};
toolbar = [
displayMode,
separator,
@ -260,16 +373,22 @@ define([], function () {
separator,
size,
separator,
stackOrder,
x,
y,
height,
width
width,
useGrid,
separator,
remove
];
} else if (layoutItem.type === 'text-view' ) {
} else if (layoutItem.type === 'text-view') {
let text = {
control: "button",
domainObject: selectedParent,
property: path,
property: function () {
return getPath();
},
icon: "icon-gear",
title: "Edit text properties",
dialog: DIALOG_FORM['text']
@ -277,32 +396,42 @@ define([], function () {
toolbar = [
fill,
stroke,
color,
separator,
color,
size,
separator,
stackOrder,
x,
y,
height,
width,
useGrid,
separator,
text
text,
separator,
remove
];
} else if (layoutItem.type === 'box-view') {
toolbar = [
fill,
stroke,
separator,
stackOrder,
x,
y,
height,
width
width,
useGrid,
separator,
remove
];
} else if (layoutItem.type === 'image-view') {
let url = {
control: "button",
domainObject: selectedParent,
property: path,
property: function () {
return getPath();
},
icon: "icon-image",
title: "Edit image properties",
dialog: DIALOG_FORM['image']
@ -310,19 +439,25 @@ define([], function () {
toolbar = [
stroke,
separator,
stackOrder,
x,
y,
height,
width,
useGrid,
separator,
url
url,
separator,
remove
];
} else if (layoutItem.type === 'line-view') {
let x2 = {
control: "input",
type: "number",
domainObject: selectedParent,
property: path + ".x2",
property: function () {
return getPath() + ".x2";
},
label: "X2:",
title: "X2 position"
},
@ -330,17 +465,23 @@ define([], function () {
control: "input",
type: "number",
domainObject: selectedParent,
property: path + ".y2",
property: function () {
return getPath() + ".y2";
},
label: "Y2:",
title: "Y2 position",
};
toolbar = [
stroke,
separator,
stackOrder,
x,
y,
x2,
y2
y2,
useGrid,
separator,
remove
];
}
}

View File

@ -25,6 +25,7 @@ define(function () {
return {
name: "Display Layout",
creatable: true,
description: 'Assemble other objects and components together into a reusable screen layout. Simply drag in the objects you want, position and size them. Save your design and view or edit it at any time.',
cssClass: 'icon-layout',
initialize(domainObject) {
domainObject.composition = [];
@ -32,7 +33,31 @@ define(function () {
items: [],
layoutGrid: [10, 10],
};
}
},
form: [
{
name: "Horizontal grid (px)",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
property: [
"configuration",
"layoutGrid",
0
],
required: true
},
{
name: "Vertical grid (px)",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
property: [
"configuration",
"layoutGrid",
1
],
required: true
}
]
}
}

View File

@ -54,7 +54,8 @@
x: 1,
y: 1,
width: 10,
height: 5
height: 5,
useGrid: true
};
},
inject: ['openmct'],
@ -75,16 +76,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

@ -25,29 +25,26 @@
@dragover="handleDragOver"
@click="bypassSelection"
@drop="handleDrop">
<div class="l-layout__object">
<!-- Background grid -->
<div class="l-layout__grid-holder c-grid"
v-if="!drilledIn">
<div class="c-grid__x l-grid l-grid-x"
v-if="gridSize[0] >= 3"
:style="[{ backgroundSize: gridSize[0] + 'px 100%' }]">
</div>
<div class="c-grid__y l-grid l-grid-y"
v-if="gridSize[1] >= 3"
:style="[{ backgroundSize: '100%' + gridSize[1] + 'px' }]"></div>
<!-- Background grid -->
<div class="l-layout__grid-holder c-grid">
<div class="c-grid__x l-grid l-grid-x"
v-if="gridSize[0] >= 3"
:style="[{ backgroundSize: gridSize[0] + 'px 100%' }]">
</div>
<component v-for="(item, index) in layoutItems"
:is="item.type"
:item="item"
:gridSize="gridSize"
:initSelect="initSelectIndex === index"
:index="index"
@drilledIn="updateDrilledIn"
@endDrag="endDrag"
>
</component>
<div class="c-grid__y l-grid l-grid-y"
v-if="gridSize[1] >= 3"
:style="[{ backgroundSize: '100%' + gridSize[1] + 'px' }]"></div>
</div>
<component v-for="(item, index) in layoutItems"
:is="item.type"
:item="item"
:key="item.id"
:gridSize="item.useGrid ? gridSize : [1, 1]"
:initSelect="initSelectIndex === index"
:index="index"
@endDrag="endDrag"
>
</component>
</div>
</template>
@ -58,30 +55,47 @@
@include abs();
display: flex;
flex-direction: column;
overflow: auto;
&__grid-holder {
display: none;
}
&__object {
flex: 1 1 auto;
overflow: auto;
}
&__frame {
position: absolute;
}
}
.l-shell__main-container {
> .l-layout {
[s-selected] {
border: $browseBorderSelected;
.is-editing {
.l-shell__main-container {
&[s-selected],
&[s-selected-parent] {
// Display grid in main layout holder when editing
> .l-layout {
background: $editUIGridColorBg;
> [class*="__grid-holder"] {
display: block;
}
}
}
}
.l-layout__frame {
&[s-selected],
&[s-selected-parent] {
// Display grid in nested layouts when editing
> * > * > .l-layout {
background: $editUIGridColorBg;
box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
> [class*='grid-holder'] {
display: block;
}
}
}
}
}
// Styles moved to _global.scss;
</style>
@ -103,6 +117,14 @@
'text-view': TextView,
'image-view': ImageView
};
const ORDERS = {
top: Number.POSITIVE_INFINITY,
up: 1,
down: -1,
bottom: Number.NEGATIVE_INFINITY
};
const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
function getItemDefinition(itemType, ...options) {
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
@ -118,7 +140,6 @@
data() {
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
return {
drilledIn: undefined,
internalDomainObject: domainObject,
initSelectIndex: undefined
};
@ -143,16 +164,49 @@
return;
}
this.updateDrilledIn();
if (this.removeSelectionListener) {
this.removeSelectionListener();
}
let itemIndex = selection[0].context.index;
if (itemIndex !== undefined) {
this.attachSelectionListener(itemIndex);
}
},
updateDrilledIn(drilledInItem) {
let identifier = drilledInItem && this.openmct.objects.makeKeyString(drilledInItem.identifier);
this.drilledIn = identifier;
this.layoutItems.forEach(item => {
if (item.type === 'subobject-view') {
item.drilledIn = this.openmct.objects.makeKeyString(item.identifier) === identifier;
attachSelectionListener(index) {
let path = `configuration.items[${index}].useGrid`;
this.removeSelectionListener = this.openmct.objects.observe(this.internalDomainObject, path, function (value) {
let item = this.layoutItems[index];
if (value) {
item.x = Math.round(item.x / this.gridSize[0]);
item.y = Math.round(item.y / this.gridSize[1]);
item.width = Math.round(item.width / this.gridSize[0]);
item.height = Math.round(item.height / this.gridSize[1]);
if (item.x2) {
item.x2 = Math.round(item.x2 / this.gridSize[0]);
}
if (item.y2) {
item.y2 = Math.round(item.y2 / this.gridSize[1]);
}
} else {
item.x = this.gridSize[0] * item.x;
item.y = this.gridSize[1] * item.y;
item.width = this.gridSize[0] * item.width;
item.height = this.gridSize[1] * item.height;
if (item.x2) {
item.x2 = this.gridSize[0] * item.x2;
}
if (item.y2) {
item.y2 = this.gridSize[1] * item.y2;
}
}
});
item.useGrid = value;
this.mutate(`configuration.items[${index}]`, item);
}.bind(this));
},
bypassSelection($event) {
if (this.dragInProgress) {
@ -176,13 +230,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]),
@ -212,12 +266,26 @@
}
}
},
handleDragOver($event){
$event.preventDefault();
containsObject(identifier) {
return _.get(this.internalDomainObject, 'composition')
.some(childId => this.openmct.objects.areIdsEqual(childId, identifier));
},
handleDragOver($event) {
// Get the ID of the dragged object
let draggedKeyString = $event.dataTransfer.types
.filter(type => type.startsWith(DRAG_OBJECT_TRANSFER_PREFIX))
.map(type => type.substring(DRAG_OBJECT_TRANSFER_PREFIX.length))[0];
// If the layout already contains the given object, then shortcut the default dragover behavior and
// potentially allow drop. Display layouts allow drag drop of duplicate telemetry objects.
if (this.containsObject(draggedKeyString)){
$event.preventDefault();
}
},
isTelemetry(domainObject) {
if (this.openmct.telemetry.isTelemetryObject(domainObject)
&& domainObject.type !== 'summary-widget') {
&& domainObject.type !== 'summary-widget'
&& domainObject.type !== 'example.imagery') {
return true;
} else {
return false;
@ -226,17 +294,58 @@
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);
this.initSelectIndex = this.layoutItems.length - 1;
},
trackItem(item) {
if (item.type === "telemetry-view") {
this.telemetryViewMap[this.openmct.objects.makeKeyString(item.identifier)] = true;
} else if (item.type === "subobject-view") {
this.objectViewMap[this.openmct.objects.makeKeyString(item.identifier)] = true;
if (!item.identifier) {
return;
}
let keyString = this.openmct.objects.makeKeyString(item.identifier);
if (item.type === "telemetry-view") {
let count = this.telemetryViewMap[keyString] || 0;
this.telemetryViewMap[keyString] = ++count;
} else if (item.type === "subobject-view") {
this.objectViewMap[keyString] = 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 = {};
@ -254,14 +363,48 @@
}
},
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();
},
orderItem(position, index) {
let delta = ORDERS[position];
let newIndex = Math.max(Math.min(index + delta, this.layoutItems.length - 1), 0);
let item = this.layoutItems[index];
if (newIndex !== index) {
this.layoutItems.splice(index, 1);
this.layoutItems.splice(newIndex, 0, item);
this.mutate('configuration.items', this.layoutItems);
if (this.removeSelectionListener) {
this.removeSelectionListener();
this.attachSelectionListener(newIndex);
}
}
}
},
mounted() {
this.unlisten = this.openmct.objects.observe(this.internalDomainObject, '*', function (obj) {
this.internalDomainObject = JSON.parse(JSON.stringify(obj));
}.bind(this));
this.openmct.selection.on('change', this.setSelection);
this.initializeItems();
this.composition = this.openmct.composition.get(this.internalDomainObject);
@ -274,7 +417,10 @@
this.composition.off('add', this.addChild);
this.composition.off('remove', this.removeChild);
this.unlisten();
if (this.removeSelectionListener) {
this.removeSelectionListener();
}
}
}
</script>

View File

@ -56,7 +56,8 @@
y: 1,
width: 10,
height: 5,
url: element.url
url: element.url,
useGrid: true
};
},
inject: ['openmct'],
@ -77,13 +78,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,29 +21,28 @@
*****************************************************************************/
<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,
'is-drilled-in': item.drilledIn
'is-resizing': isResizing
}"
:style="style"
@dblclick="drill($event)">
:style="style">
<slot></slot>
<!-- Drag handles -->
<div class="c-frame-edit">
<div class="c-frame-edit__move"
@mousedown="startDrag([1,1], [0,0], $event)"></div>
@mousedown="startDrag([1,1], [0,0], $event, 'move')"></div>
<div class="c-frame-edit__handle c-frame-edit__handle--nw"
@mousedown="startDrag([1,1], [-1,-1], $event)"></div>
@mousedown="startDrag([1,1], [-1,-1], $event, 'resize')"></div>
<div class="c-frame-edit__handle c-frame-edit__handle--ne"
@mousedown="startDrag([0,1], [1,-1], $event)"></div>
@mousedown="startDrag([0,1], [1,-1], $event, 'resize')"></div>
<div class="c-frame-edit__handle c-frame-edit__handle--sw"
@mousedown="startDrag([1,0], [-1,1], $event)"></div>
@mousedown="startDrag([1,0], [-1,1], $event, 'resize')"></div>
<div class="c-frame-edit__handle c-frame-edit__handle--se"
@mousedown="startDrag([0,0], [1,1], $event)"></div>
@mousedown="startDrag([0,0], [1,1], $event, 'resize')"></div>
</div>
</div>
</template>
@ -55,20 +54,167 @@
.c-frame {
display: flex;
flex-direction: column;
border: 1px solid transparent;
/*************************** NO-FRAME */
&.no-frame {
> [class*="contents"] > [class*="__header"] {
display: none;
}
// Whatever is placed into the slot, make it fill the entirety of the space, obeying padding
> *:first-child {
flex: 1 1 auto;
}
&:not(.no-frame) {
background: $colorBodyBg;
border: 1px solid $colorInteriorBorder;
border: $browseFrameBorder;
padding: $interiorMargin;
}
}
.c-frame-edit {
// In Layouts, this is the editing rect and handles
// In Fixed Position, this is a wrapper element
@include abs();
display: none;
&__move {
@include abs();
cursor: move;
}
&__handle {
$d: 6px;
$o: floor($d * -0.5);
background: $editFrameColorHandleFg;
box-shadow: $editFrameColorHandleBg 0 0 0 2px;
display: none; // Set to block via s-selected selector
position: absolute;
width: $d; height: $d;
top: auto; right: auto; bottom: auto; left: auto;
&:before {
// Extended hit area
@include abs(-10px);
content: '';
display: block;
z-index: 0;
}
&:hover {
background: $editUIColor;
}
&--nwse {
cursor: nwse-resize;
}
&--nw {
cursor: nw-resize;
left: $o; top: $o;
}
&--ne {
cursor: ne-resize;
right: $o; top: $o;
}
&--se {
cursor: se-resize;
right: $o; bottom: $o;
}
&--sw {
cursor: sw-resize;
left: $o; bottom: $o;
}
}
}
.c-so-view.has-complex-content + .c-frame-edit {
// Target frames that hold domain objects that include header elements, as opposed to drawing and alpha objects
// Make the __move element a more affordable drag UI element
.c-frame-edit__move {
@include userSelectNone();
background: $editFrameMovebarColorBg;
box-shadow: rgba(black, 0.2) 0 1px;
bottom: auto;
height: 0; // Height is set on hover on s-selected.c-frame
opacity: 0.8;
max-height: 100%;
overflow: hidden;
text-align: center;
&:before {
// Grippy
$h: 4px;
$tbOffset: ($editFrameMovebarH - $h) / 2;
$lrOffset: 25%;
@include grippy($editFrameMovebarColorFg);
content: '';
display: block;
position: absolute;
top: $tbOffset; right: $lrOffset; bottom: $tbOffset; left: $lrOffset;
}
&:hover {
background: $editFrameHovMovebarColorBg;
&:before { @include grippy($editFrameHovMovebarColorFg); }
}
}
}
.is-editing {
.c-frame {
$moveBarOutDelay: 500ms;
&.no-frame {
border: $editFrameBorder; // Base border style for a frame element while editing.
}
&-edit {
display: contents;
}
&-edit__move,
.c-so-view {
transition: $transOut;
transition-delay: $moveBarOutDelay;
}
&:not([s-selected]) {
&:hover {
border: $editFrameBorderHov;
}
}
&[s-selected] {
// All frames selected while editing
border: $editFrameSelectedBorder;
box-shadow: $editFrameSelectedShdw;
> .c-frame-edit {
[class*='__handle'] {
display: block;
}
}
}
}
.l-layout__frame:not(.is-resizing) {
// Show and animate the __move bar for sub-object views with complex content
&:hover > .c-so-view.has-complex-content {
// Move content down so the __move bar doesn't cover it.
padding-top: $editFrameMovebarH;
transition: $transIn;
&.c-so-view--no-frame {
// Move content down with a bit more space
padding-top: $editFrameMovebarH + $interiorMarginSm;
}
// Show the move bar
+ .c-frame-edit .c-frame-edit__move {
height: $editFrameMovebarH;
transition: $transIn;
}
}
}
}
</style>
@ -84,7 +230,8 @@
},
data() {
return {
dragPosition: undefined
dragPosition: undefined,
isResizing: undefined
}
},
computed: {
@ -110,24 +257,6 @@
}
},
methods: {
drill($event) {
if ($event) {
$event.stopPropagation();
}
if (!this.openmct.editor.isEditing() || !this.item.identifier) {
return;
}
this.openmct.objects.get(this.item.identifier)
.then(domainObject => {
if (this.openmct.composition.get(domainObject) === undefined) {
return;
}
this.$emit('drilledIn', this.item);
});
},
updatePosition(event) {
let currentPosition = [event.pageX, event.pageY];
this.initialPosition = this.initialPosition || currentPosition;
@ -135,7 +264,7 @@
return value - this.initialPosition[index];
}.bind(this));
},
startDrag(posFactor, dimFactor, event) {
startDrag(posFactor, dimFactor, event, type) {
document.body.addEventListener('mousemove', this.continueDrag);
document.body.addEventListener('mouseup', this.endDrag);
@ -145,6 +274,7 @@
};
this.updatePosition(event);
this.activeDrag = new LayoutDrag(this.dragPosition, posFactor, dimFactor, this.gridSize);
this.isResizing = type === 'resize';
event.preventDefault();
},
continueDrag(event) {
@ -162,6 +292,7 @@
this.dragPosition = undefined;
this.initialPosition = undefined;
this.delta = undefined;
this.isResizing = undefined;
event.preventDefault();
}
}

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">
@ -67,7 +66,8 @@
y: 10,
x2: 10,
y2: 5,
stroke: '#717171'
stroke: '#717171',
useGrid: true
};
},
inject: ['openmct'],
@ -101,9 +101,6 @@
top: `${top}px`,
width: `${width}px`,
height: `${height}px`,
minWidth: `${width}px`,
minHeight: `${height}px`,
position: 'absolute'
};
},
startHandleClass() {
@ -210,17 +207,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

@ -22,92 +22,18 @@
<template>
<layout-frame :item="item"
: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>
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
<object-frame v-if="domainObject"
:domain-object="domainObject"
:object-path="objectPath"
:has-frame="item.hasFrame"
ref="objectFrame">
</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],
@ -139,7 +65,8 @@
x: position[0],
y: position[1],
identifier: domainObject.identifier,
hasFrame: hasFrameByDefault(domainObject.type)
hasFrame: hasFrameByDefault(domainObject.type),
useGrid: true
};
},
inject: ['openmct'],
@ -152,27 +79,35 @@
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 = {
item: domainObject,
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
this.$nextTick(function () {
let childContext = this.$refs.objectFrame.getSelectionContext();
childContext.item = domainObject;
childContext.layoutItem = this.item;
childContext.index = this.index;
this.context = childContext;
this.removeSelectable = this.openmct.selection.selectable(
this.$el, this.context, this.initSelect);
});
}
},
mounted() {

View File

@ -99,6 +99,7 @@
fill: "",
color: "",
size: "13px",
useGrid: true
};
},
inject: ['openmct'],
@ -160,6 +161,15 @@
domainObject: undefined
}
},
watch: {
index(newIndex) {
if (!this.context) {
return;
}
this.context.index = newIndex;
}
},
methods: {
requestHistoricalData() {
let bounds = this.openmct.time.bounds();
@ -205,13 +215,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

@ -59,7 +59,8 @@
y: 1,
width: 10,
height: 5,
text: element.text
text: element.text,
useGrid: true
};
},
inject: ['openmct'],
@ -82,13 +83,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,9 @@ 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,
orderItem: component && component.$refs.displayLayout.orderItem
}
},
destroy() {

View File

@ -24,7 +24,7 @@
<div class="c-fl-container"
:style="[{'flex-basis': sizeString}]"
:class="{'is-empty': !frames.length}">
<div class="c-fl-container__header icon-grippy-ew"
<div class="c-fl-container__header"
v-show="isEditing"
draggable="true"
@dragstart="startContainerDrag">
@ -35,7 +35,7 @@
class="c-fl-frame__drop-hint"
:index="-1"
:allow-drop="allowDrop"
@object-drop-to="moveOrCreateFrame">
@object-drop-to="moveOrCreateNewFrame">
</drop-hint>
<div class="c-fl-container__frames-holder">
@ -47,7 +47,8 @@
:key="frame.id"
:frame="frame"
:index="i"
:containerIndex="index">
:containerIndex="index"
:isEditing="isEditing">
</frame-component>
<drop-hint
@ -55,7 +56,7 @@
:key="i"
:index="i"
:allowDrop="allowDrop"
@object-drop-to="moveOrCreateFrame">
@object-drop-to="moveOrCreateNewFrame">
</drop-hint>
<resize-handle
@ -65,7 +66,8 @@
:orientation="rowsLayout ? 'horizontal' : 'vertical'"
@init-move="startFrameResizing"
@move="frameResizing"
@end-move="endFrameResizing">
@end-move="endFrameResizing"
:isEditing="isEditing">
</resize-handle>
</template>
</div>
@ -77,14 +79,12 @@ import FrameComponent from './frame.vue';
import Frame from '../utils/frame';
import ResizeHandle from './resizeHandle.vue';
import DropHint from './dropHint.vue';
import isEditingMixin from '../mixins/isEditing';
const MIN_FRAME_SIZE = 5;
export default {
inject:['openmct'],
props: ['container', 'index', 'rowsLayout'],
mixins: [isEditingMixin],
props: ['container', 'index', 'rowsLayout', 'isEditing'],
components: {
FrameComponent,
ResizeHandle,
@ -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'),
@ -123,15 +123,12 @@ export default {
return true;
}
},
moveOrCreateFrame(insertIndex, event) {
if (event.dataTransfer.types.includes('domainobject')) {
// create frame using domain object
let domainObject = JSON.parse(event.dataTransfer.getData('domainObject'));
moveOrCreateNewFrame(insertIndex, event) {
if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
this.$emit(
'create-frame',
'new-frame',
this.index,
insertIndex,
domainObject.identifier
insertIndex
);
return;
};

View File

@ -21,10 +21,10 @@
*****************************************************************************/
<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}"
@dragover.prevent
@dragenter="dragenter"
@dragleave="dragleave"
@drop="dropHandler">
@ -37,8 +37,6 @@
</style>
<script>
import isEditingMixin from '../mixins/isEditing';
export default {
props:{
index: Number,
@ -47,7 +45,6 @@ export default {
required: true
}
},
mixins: [isEditingMixin],
data() {
return {
isMouseOver: false,
@ -75,10 +72,12 @@ export default {
mounted() {
document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend);
document.addEventListener('drop', this.dragend);
},
destroyed() {
document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend);
document.removeEventListener('drop', this.dragend);
}
}
</script>

View File

@ -22,6 +22,11 @@
<template>
<div class="c-fl">
<div
id="js-fl-drag-ghost"
class="c-fl__drag-ghost">
</div>
<div class="c-fl__empty"
v-if="areAllContainersEmpty()">
<span class="c-fl__empty-message">This Flexible Layout is currently empty</span>
@ -49,8 +54,9 @@
:index="index"
:container="container"
:rowsLayout="rowsLayout"
:isEditing="isEditing"
@move-frame="moveFrame"
@create-frame="createFrame"
@new-frame="setFrameLocation"
@persist="persist">
</container-component>
@ -59,6 +65,7 @@
:key="index"
:index="index"
:orientation="rowsLayout ? 'vertical' : 'horizontal'"
:isEditing="isEditing"
@init-move="startContainerResizing"
@move="containerResizing"
@end-move="endContainerResizing">
@ -79,6 +86,22 @@
<style lang="scss">
@import '~styles/sass-base';
@mixin containerGrippy($headerSize, $dir) {
position: absolute;
$h: 6px;
$minorOffset: ($headerSize - $h) / 2;
$majorOffset: 35%;
content: '';
display: block;
position: absolute;
@include grippy($c: $editFrameSelectedMovebarColorFg, $dir: $dir);
@if $dir == 'x' {
top: $minorOffset; right: $majorOffset; bottom: $minorOffset; left: $majorOffset;
} @else {
top: $majorOffset; right: $minorOffset; bottom: $majorOffset; left: $minorOffset;
}
}
.c-fl {
@include abs();
@ -100,7 +123,6 @@
> * + * { margin-left: 1px; }
&[class*='--rows'] {
//@include test(blue, 0.1);
flex-direction: column;
> * + * {
margin-left: 0;
@ -122,13 +144,29 @@
opacity: 0.5;
}
}
&__drag-ghost{
background: $colorItemTreeHoverBg;
color: $colorItemTreeHoverFg;
border-radius: $basicCr;
display: flex;
align-items: center;
padding: $interiorMarginLg $interiorMarginLg * 2;
position: absolute;
top: -10000px;
z-index: 2;
&:before {
color: $colorKey;
margin-right: $interiorMarginSm;
}
}
}
.c-fl-container {
/***************************************************** CONTAINERS */
$headerSize: 16px;
border: 1px solid transparent;
display: flex;
flex-direction: column;
overflow: auto;
@ -138,9 +176,9 @@
flex-shrink: 1;
&__header {
// Only displayed when editing
background: $editSelectableColor;
color: $editSelectableColorFg;
// Only displayed when editing, controlled via JS
background: $editFrameMovebarColorBg;
color: $editFrameMovebarColorFg;
cursor: move;
display: flex;
align-items: center;
@ -148,12 +186,8 @@
&:before {
// Drag grippy
font-size: 0.8em;
@include containerGrippy($headerSize, 'x');
opacity: 0.5;
position: absolute;
left: 50%; top: 50%;
transform-origin: center;
transform: translate(-50%, -50%);
}
}
@ -173,19 +207,27 @@
}
.is-editing & {
//background: $editCanvasColorBg;
border-color: $editSelectableColor;
&:hover {
border-color: $editSelectableColorHov;
.c-fl-container__header {
background: $editFrameHovMovebarColorBg;
color: $editFrameHovMovebarColorFg;
&:before {
opacity: .75;
}
}
}
&[s-selected] {
border-color: $editSelectableColorSelected;
border: $editFrameSelectedBorder;
.c-fl-container__header {
background: $editSelectableColorSelected;
color: $editSelectableColorSelectedFg;
background:$editFrameSelectedMovebarColorBg;
color: $editFrameSelectedMovebarColorFg;
&:before {
// Grippy
opacity: 1;
}
}
}
}
@ -194,11 +236,6 @@
// Frames get styled here because this is particular to their presence in this layout type
.c-fl-frame {
@include browserPrefix(margin-collapse, collapse);
margin: 1px;
//&__drag-wrapper {
// border: 1px solid $colorInteriorBorder; // Now handled by is-selectable
//}
}
/****** ROWS LAYOUT */
@ -211,8 +248,8 @@
overflow: hidden;
&:before {
// Drag grippy
transform: rotate(90deg) translate(-50%, 50%);
// Grippy
@include containerGrippy($headerSize, 'y');
}
}
@ -235,8 +272,6 @@
$dropHintSize: 15px;
display: flex;
// justify-content: stretch;
// align-items: stretch;
flex: 1 1;
flex-direction: column;
overflow: hidden; // Needed to allow frames to collapse when sized down
@ -275,7 +310,6 @@
pointer-events: none;
text-align: center;
width: $size;
z-index: 2;
// Changed when layout is different, see below
border-top-right-radius: $controlCr;
@ -304,37 +338,16 @@
&:before {
// The visible resize line
background: $editColor;
background: $editUIColor;
content: '';
display: block;
flex: 1 1 auto;
min-height: $size; min-width: $size;
}
&__grippy {
// Grippy element
$d: 4px;
$c: black;
$a: 0.9;
$d: 5px;
background: $editColor;
color: $editColorBg;
border-radius: $smallCr;
font-size: 0.8em;
height: $d;
width: $d * 10;
position: absolute;
left: 50%; top: 50%;
text-align: center;
transform-origin: center center;
transform: translate(-50%, -50%);
z-index: 10;
}
&.vertical {
padding: $margin $size;
&:hover{
// padding: $marginHov 0;
cursor: row-resize;
}
}
@ -342,20 +355,15 @@
&.horizontal {
padding: $size $margin;
&:hover{
// padding: 0 $marginHov;
cursor: col-resize;
}
[class*='grippy'] {
transform: translate(-50%) rotate(90deg);
}
}
&:hover {
transition: $transOut;
&:before {
// The visible resize line
background: $editColorHov;
background: $editUIColorHov;
}
}
}
@ -414,7 +422,6 @@ import Container from '../utils/container';
import Frame from '../utils/frame';
import ResizeHandle from './resizeHandle.vue';
import DropHint from './dropHint.vue';
import isEditingMixin from '../mixins/isEditing';
const MIN_CONTAINER_SIZE = 5;
@ -459,7 +466,6 @@ function sizeToFill(items) {
export default {
inject: ['openmct', 'layoutObject'],
mixins: [isEditingMixin],
components: {
ContainerComponent,
ResizeHandle,
@ -467,9 +473,13 @@ export default {
},
data() {
return {
domainObject: this.layoutObject
domainObject: this.layoutObject,
newFrameLocation: []
}
},
props: {
isEditing: Boolean
},
computed: {
layoutDirectionStr() {
if (this.rowsLayout) {
@ -513,12 +523,22 @@ export default {
sizeItems(toContainer.frames, frame);
this.persist();
},
createFrame(containerIndex, insertFrameIndex, objectIdentifier) {
let frame = new Frame(objectIdentifier);
let container = this.containers[containerIndex];
container.frames.splice(insertFrameIndex + 1, 0, frame);
sizeItems(container.frames, frame);
this.persist();
setFrameLocation(containerIndex, insertFrameIndex) {
this.newFrameLocation = [containerIndex, insertFrameIndex];
},
addFrame(domainObject) {
if (this.newFrameLocation.length) {
let containerIndex = this.newFrameLocation[0],
frameIndex = this.newFrameLocation[1],
frame = new Frame(domainObject.identifier),
container = this.containers[containerIndex];
container.frames.splice(frameIndex + 1, 0, frame);
sizeItems(container.frames, frame);
this.newFrameLocation = [];
this.persist(containerIndex);
}
},
deleteFrame(frameId) {
let container = this.containers
@ -600,24 +620,33 @@ export default {
} else {
this.containers.splice(toIndex, 0, container);
}
this.persist(index);
},
removeChildObject(identifier) {
let removeIdentifier = this.openmct.objects.makeKeyString(identifier);
this.containers.forEach(container => {
container.frames = container.frames.filter(frame => {
let frameIdentifier = this.openmct.objects.makeKeyString(frame.domainObjectIdentifier);
return removeIdentifier !== frameIdentifier;
});
});
this.persist();
}
},
mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('remove', this.removeChildObject);
this.composition.on('add', this.addFrame);
let context = {
item: this.domainObject,
addContainer: this.addContainer,
deleteContainer: this.deleteContainer,
deleteFrame: this.deleteFrame,
type: 'flexible-layout'
}
this.unsubscribeSelection = this.openmct.selection.selectable(this.$el, context, true);
this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
},
beforeDestroy() {
this.unsubscribeSelection();
this.composition.off('remove', this.removeChildObject);
this.composition.off('add', this.addFrame);
this.unobserve();
}
}

View File

@ -26,16 +26,18 @@
'flex-basis': `${frame.size}%`
}">
<div class="c-frame c-fl-frame__drag-wrapper is-selectable is-moveable"
:class="{'no-frame': noFrame}"
<div class="c-frame c-fl-frame__drag-wrapper is-selectable u-inspectable is-moveable"
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"
ref="objectFrame">
</object-frame>
<div class="c-fl-frame__size-indicator"
v-if="isEditing"
@ -48,43 +50,55 @@
<script>
import ResizeHandle from './resizeHandle.vue';
import SubobjectView from '../../displayLayout/components/SubobjectView.vue';
import isEditingMixin from '../mixins/isEditing';
import ObjectFrame from '../../../ui/components/ObjectFrame.vue';
export default {
inject: ['openmct'],
props: ['frame', 'index', 'containerIndex'],
mixins: [isEditingMixin],
props: ['frame', 'index', 'containerIndex', 'isEditing'],
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;
this.domainObject = object;
this.objectPath = [object];
this.setSelection();
},
setSelection() {
let context = {
item: this.item.domainObject,
addContainer: this.addContainer,
type: 'frame',
frameId: this.frame.id
};
this.unsubscribeSelection = this.openmct.selection.selectable(this.$refs.frame, context, false);
this.$nextTick(function () {
let childContext = this.$refs.objectFrame.getSelectionContext();
childContext.item = this.domainObject;
childContext.type = 'frame';
childContext.frameId = this.frame.id;
this.unsubscribeSelection = this.openmct.selection.selectable(
this.$refs.frame, childContext, false);
});
},
initDrag(event) {
let type = this.openmct.types.get(this.domainObject.type),
iconClass = type.definition ? type.definition.cssClass : 'icon-object-unknown';
if (this.dragGhost) {
let originalClassName = this.dragGhost.classList[0];
this.dragGhost.className = '';
this.dragGhost.classList.add(originalClassName, iconClass);
this.dragGhost.innerHTML = `<span>${this.domainObject.name}</span>`;
event.dataTransfer.setDragImage(this.dragGhost, 0, 0);
}
event.dataTransfer.setData('frameid', this.frame.id);
event.dataTransfer.setData('containerIndex', this.containerIndex);
}
@ -95,6 +109,8 @@ export default {
this.setDomainObject(object);
});
}
this.dragGhost = document.getElementById('js-fl-drag-ghost');
},
beforeDestroy() {
if (this.unsubscribeSelection) {

View File

@ -29,11 +29,8 @@
</template>
<script>
import isEditingMixin from '../mixins/isEditing';
export default {
props: ['orientation', 'index'],
mixins: [isEditingMixin],
props: ['orientation', 'index', 'isEditing'],
data() {
return {
initialPos: 0,

View File

@ -35,12 +35,20 @@ define([
canView: function (domainObject) {
return domainObject.type === 'flexible-layout';
},
canEdit: function (domainObject) {
return domainObject.type === 'flexible-layout';
},
view: function (domainObject) {
let component;
return {
show: function (element) {
show: function (element, isEditing) {
component = new Vue({
data() {
return {
isEditing: isEditing
}
},
components: {
FlexibleLayoutComponent: FlexibleLayoutComponent.default
},
@ -49,9 +57,21 @@ define([
layoutObject: domainObject
},
el: element,
template: '<flexible-layout-component></flexible-layout-component>'
template: '<flexible-layout-component ref="flexibleLayout"></flexible-layout-component>'
});
},
getSelectionContext: function () {
return {
item: domainObject,
addContainer: component.$refs.flexibleLayout.addContainer,
deleteContainer: component.$refs.flexibleLayout.deleteContainer,
deleteFrame: component.$refs.flexibleLayout.deleteFrame,
type: 'flexible-layout'
};
},
onEditModeChange: function (isEditing) {
component.isEditing = isEditing;
},
destroy: function (element) {
component.$destroy();
component = undefined;

View File

@ -1,19 +0,0 @@
export default {
inject: ['openmct'],
data() {
return {
isEditing: this.openmct.editor.isEditing()
};
},
mounted() {
this.openmct.editor.on('isEditing', this.toggleEditing);
},
destroyed() {
this.openmct.editor.off('isEditing', this.toggleEditing);
},
methods: {
toggleEditing(value) {
this.isEditing = value;
}
}
};

View File

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

View File

@ -53,18 +53,18 @@ function ToolbarProvider(openmct) {
toggleContainer = {
control: 'toggle-button',
key: 'toggle-layout',
domainObject: secondary ? secondary.context.item : primary.context.item,
domainObject: primary.context.item,
property: 'configuration.rowsLayout',
options: [
{
value: false,
value: true,
icon: 'icon-columns',
title: 'Columns'
title: 'Columns layout'
},
{
value: true,
value: false,
icon: 'icon-rows',
title: 'Rows'
title: 'Rows layout'
}
]
};
@ -120,14 +120,14 @@ function ToolbarProvider(openmct) {
property: `configuration.containers[${containerIndex}].frames[${frameIndex}].noFrame`,
options: [
{
value: true,
value: false,
icon: 'icon-frame-hide',
title: "Hide frame"
title: "Frame hidden"
},
{
value: false,
value: true,
icon: 'icon-frame-show',
title: "Show frame"
title: "Frame visible"
}
]
};
@ -140,6 +140,8 @@ function ToolbarProvider(openmct) {
title: 'Add Container'
};
toggleContainer.domainObject = secondary.context.item;
} else if (primary.context.type === 'container') {
deleteContainer = {
@ -151,7 +153,7 @@ function ToolbarProvider(openmct) {
let prompt = openmct.overlays.dialog({
iconClass: 'alert',
message: `This action will permanently delete container ${containerIndex + 1} from this Flexible Layout`,
message: 'This action will permanently delete this container from this Flexible Layout',
buttons: [
{
label: 'Ok',

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';

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