Compare commits

...

40 Commits

Author SHA1 Message Date
07c2b0820a merge tree search implementation for testing purposes 2019-02-20 11:16:48 -08:00
a0d2cd5711 fixes for toolbar not updating on selection change 2019-02-19 10:25:20 -08:00
2d8f58573d force mutation in save-as to trigger indexing 2019-02-15 13:31:28 -08:00
e4e7ecd74e throw an error when user cancels instead of returning false 2019-02-14 12:54:30 -08:00
f148583318 remove Root from path 2019-02-14 11:55:18 -08:00
514896884f fix index undefined error when reordering containers 2019-02-12 13:49:16 -08:00
fc024e583e remove domainObjects from composition when deleting frames and containers, and also fix a bug whereby a user can add domainObject via drag and drop(composition) but because of the lack of containers, it will not be added to the flexible layout 2019-02-12 12:36:39 -08:00
7f2f060417 navigate and edit on create 2019-02-11 14:05:34 -08:00
a94d50226a move search implementation inside mct-tree 2019-02-11 12:46:03 -08:00
6eda100af8 fix anonymous render error in layout 2019-02-11 12:16:54 -08:00
782ee9aa37 fix current Search error 2019-02-11 12:01:50 -08:00
29e94befe8 fix elements search in inspector 2019-02-11 11:59:56 -08:00
24a1e9ba75 fix saveAs in plot image export 2019-02-11 11:51:11 -08:00
edeefe8f2f pin fast-sass-loader version to 1.4.6 2019-02-11 10:12:11 -08:00
d263723a0c Merge branch 'topic-core-refactor' of https://github.com/nasa/openmct into tcr-fixes-2 2019-02-04 13:52:53 -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
b74c14b334 get context before passing into mxt-tree 2019-01-31 13:17:01 -08:00
d8f733d424 add no results found message to mct-tree 2019-01-30 14:34:55 -08:00
b39f3fab3f remove unused method 2019-01-30 12:51:11 -08:00
4912188fe4 first working version of search 2019-01-30 12:44:43 -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
58048d44b2 fix for preview image overlay 2019-01-25 14:32:17 -08:00
775e93484e add notebook snapshot to preview 2019-01-25 14:15:18 -08:00
0e27234389 Merge branch 'topic-core-refactor' of https://github.com/nasa/openmct into tcr-fixes-2 2019-01-25 13:49:36 -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
15d4b1a8e5 prevent default on dragover in dropHint, to allow drop event to fire 2019-01-24 11:59:46 -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
123 changed files with 1925 additions and 6230 deletions

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

@ -49,7 +49,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"
}));

View File

@ -25,7 +25,7 @@
"eventemitter3": "^1.2.0",
"exports-loader": "^0.7.0",
"express": "^4.13.1",
"fast-sass-loader": "^1.4.5",
"fast-sass-loader": "1.4.6",
"file-loader": "^1.1.11",
"file-saver": "^1.3.8",
"git-rev-sync": "^1.4.0",

View File

@ -92,16 +92,7 @@ function (
* @memberof platform/commonUI/edit.SaveAction#
*/
SaveAsAction.prototype.perform = function () {
// Discard the current root view (which will be the editing
// UI, which will have been pushed atop the Browse UI.)
function returnToBrowse(object) {
if (object) {
object.getCapability("action").perform("navigate");
}
return object;
}
return this.save().then(returnToBrowse);
return this.save();
};
/**
@ -169,15 +160,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) {
@ -190,7 +183,7 @@ function (
if (reason !== "user canceled") {
self.notificationService.error("Save Failed");
}
return false;
throw reason;
}
return getParent(domainObject)

View File

@ -65,24 +65,33 @@ define(
CreateAction.prototype.perform = function () {
var newModel = this.type.getInitialModel(),
openmct = this.openmct,
newObject,
editAction;
function onSave() {
openmct.editor.save();
}
newObject;
function onCancel() {
openmct.editor.cancel();
}
function navigateAndEdit(object) {
let objectPath = object.getCapability('context').getPath(),
url = '#/browse/' + objectPath
.map(function (o) {
return o && openmct.objects.makeKeyString(o.getId())
})
.join('/');
window.location.href = url;
openmct.editor.edit();
}
newModel.type = this.type.getKey();
newModel.location = this.parent.getId();
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);
newObject.getCapability("action").perform("save-as")
.then(navigateAndEdit, onCancel)
// TODO: support editing object without saving object first.
// Which means we have to toggle createwizard afterwards. For now,
// We will disable this.

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,39 +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-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>
<span
class="l-elem l-title"
ng-show="ngModel.element.titled"
>
{{ngModel.name}}
</span>
</div>

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

@ -29,13 +29,22 @@ define(
function SnapshotPreviewController($scope, openmct) {
$scope.previewImage = function (imageUrl) {
var image = document.createElement('img');
image.src = imageUrl;
let imageDiv = document.createElement('div');
imageDiv.classList = 'image-main s-image-main';
imageDiv.style.backgroundImage = `url(${imageUrl})`;
openmct.overlays.overlay(
let previewImageOverlay = openmct.overlays.overlay(
{
element: image,
size: 'large'
element: imageDiv,
size: 'large',
buttons: [
{
label: 'Done',
callback: function () {
previewImageOverlay.dismiss();
}
}
]
}
);
};
@ -43,13 +52,13 @@ define(
$scope.annotateImage = function (ngModel, field, imageUrl) {
$scope.imageUrl = imageUrl;
var div = document.createElement('div'),
let div = document.createElement('div'),
painterroInstance = {},
save = false;
div.id = 'snap-annotation';
openmct.overlays.overlay(
let annotateImageOverlay = openmct.overlays.overlay(
{
element: div,
size: 'large',
@ -59,6 +68,7 @@ define(
callback: function () {
save = false;
painterroInstance.save();
annotateImageOverlay.dismiss();
}
},
{
@ -66,6 +76,7 @@ define(
callback: function () {
save = true;
painterroInstance.save();
annotateImageOverlay.dismiss();
}
}
]
@ -97,7 +108,7 @@ define(
},
saveHandler: function (image, done) {
if (save) {
var url = image.asBlob(),
let url = image.asBlob(),
reader = new window.FileReader();
reader.readAsDataURL(url);

View File

@ -43,6 +43,7 @@ define([
'./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

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

View File

@ -46,6 +46,7 @@ define([
function DefaultCompositionProvider(publicAPI, compositionAPI) {
this.publicAPI = publicAPI;
this.listeningTo = {};
this.onMutation = this.onMutation.bind(this);
this.cannotContainDuplicates = this.cannotContainDuplicates.bind(this);
this.cannotContainItself = this.cannotContainItself.bind(this);
@ -177,8 +178,12 @@ define([
* @method remove
*/
DefaultCompositionProvider.prototype.remove = function (domainObject, childId) {
// TODO: this needs to be synchronized via mutation.
throw new Error('Default Provider does not implement removal.');
let composition = domainObject.composition.filter(function (child) {
return !(childId.namespace === child.namespace &&
childId.key === child.key);
});
this.publicAPI.objects.mutate(domainObject, 'composition', composition);
};
/**
@ -208,9 +213,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 +226,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 +234,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

@ -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

@ -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

@ -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,7 +124,6 @@ define([], function () {
return toolbar;
}
let path = `configuration.items[${layoutItemIndex}]`;
let separator = {
control: "separator"
};
@ -140,7 +142,7 @@ define([], function () {
label: 'Ok',
emphasis: 'true',
callback: function () {
removeItem(layoutItem, layoutItemIndex);
removeItem(layoutItem, selection[0].context.index);
prompt.dismiss();
}
},
@ -154,6 +156,96 @@ define([], function () {
});
}
};
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) {
@ -163,124 +255,113 @@ define([], function () {
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,
@ -292,18 +373,22 @@ define([], function () {
separator,
size,
separator,
stackOrder,
x,
y,
height,
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']
@ -311,14 +396,16 @@ define([], function () {
toolbar = [
fill,
stroke,
color,
separator,
color,
size,
separator,
stackOrder,
x,
y,
height,
width,
useGrid,
separator,
text,
separator,
@ -329,10 +416,12 @@ define([], function () {
fill,
stroke,
separator,
stackOrder,
x,
y,
height,
width,
useGrid,
separator,
remove
];
@ -340,7 +429,9 @@ define([], function () {
let url = {
control: "button",
domainObject: selectedParent,
property: path,
property: function () {
return getPath();
},
icon: "icon-image",
title: "Edit image properties",
dialog: DIALOG_FORM['image']
@ -348,10 +439,12 @@ define([], function () {
toolbar = [
stroke,
separator,
stackOrder,
x,
y,
height,
width,
useGrid,
separator,
url,
separator,
@ -362,7 +455,9 @@ define([], function () {
control: "input",
type: "number",
domainObject: selectedParent,
property: path + ".x2",
property: function () {
return getPath() + ".x2";
},
label: "X2:",
title: "X2 position"
},
@ -370,17 +465,21 @@ 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,
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'],

View File

@ -25,30 +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"
:key="item.id"
: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>
@ -59,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: $browseSelectedBorder;
.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>
@ -104,6 +117,12 @@
'text-view': TextView,
'image-view': ImageView
};
const ORDERS = {
top: Number.POSITIVE_INFINITY,
up: 1,
down: -1,
bottom: Number.NEGATIVE_INFINITY
};
function getItemDefinition(itemType, ...options) {
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
@ -119,7 +138,6 @@
data() {
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
return {
drilledIn: undefined,
internalDomainObject: domainObject,
initSelectIndex: undefined
};
@ -144,16 +162,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) {
@ -177,13 +228,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]),
@ -234,12 +285,17 @@
this.initSelectIndex = this.layoutItems.length - 1;
},
trackItem(item) {
if (!item.identifier) {
return;
}
let keyString = this.openmct.objects.makeKeyString(item.identifier);
if (item.type === "telemetry-view") {
let keyString = this.openmct.objects.makeKeyString(item.identifier);
let count = this.telemetryViewMap[keyString] || 0;
this.telemetryViewMap[keyString] = ++count;
} else if (item.type === "subobject-view") {
this.objectViewMap[this.openmct.objects.makeKeyString(item.identifier)] = true;
this.objectViewMap[keyString] = true;
}
},
removeItem(item, index) {
@ -311,13 +367,28 @@
});
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);
@ -330,7 +401,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'],

View File

@ -25,25 +25,24 @@
: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

@ -66,7 +66,8 @@
y: 10,
x2: 10,
y2: 5,
stroke: '#717171'
stroke: '#717171',
useGrid: true
};
},
inject: ['openmct'],

View File

@ -22,12 +22,12 @@
<template>
<layout-frame :item="item"
:grid-size="gridSize"
@endDrag="(item, updates) => $emit('endDrag', item, updates)"
@drilledIn="item => $emit('drilledIn', item)">
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
<object-frame v-if="domainObject"
:domain-object="domainObject"
:object-path="objectPath"
:has-frame="item.hasFrame">
:has-frame="item.hasFrame"
ref="objectFrame">
</object-frame>
</layout-frame>
</template>
@ -65,7 +65,8 @@
x: position[0],
y: position[1],
identifier: domainObject.identifier,
hasFrame: hasFrameByDefault(domainObject.type)
hasFrame: hasFrameByDefault(domainObject.type),
useGrid: true
};
},
inject: ['openmct'],
@ -98,13 +99,15 @@
setObject(domainObject) {
this.domainObject = domainObject;
this.objectPath = [this.domainObject].concat(this.openmct.router.path);
this.context = {
item: domainObject,
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, this.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'],

View File

@ -59,7 +59,8 @@
y: 1,
width: 10,
height: 5,
text: element.text
text: element.text,
useGrid: true
};
},
inject: ['openmct'],

View File

@ -61,7 +61,8 @@ export default function () {
return {
item: domainObject,
addElement: component && component.$refs.displayLayout.addElement,
removeItem: component && component.$refs.displayLayout.removeItem
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">
@ -55,7 +55,7 @@
:key="i"
:index="i"
:allowDrop="allowDrop"
@object-drop-to="moveOrCreateFrame">
@object-drop-to="moveOrCreateNewFrame">
</drop-hint>
<resize-handle
@ -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>
@ -50,7 +55,7 @@
:container="container"
:rowsLayout="rowsLayout"
@move-frame="moveFrame"
@create-frame="createFrame"
@new-frame="setFrameLocation"
@persist="persist">
</container-component>
@ -79,6 +84,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 +121,6 @@
> * + * { margin-left: 1px; }
&[class*='--rows'] {
//@include test(blue, 0.1);
flex-direction: column;
> * + * {
margin-left: 0;
@ -122,13 +142,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 +174,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 +184,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 +205,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 +234,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 +246,8 @@
overflow: hidden;
&:before {
// Drag grippy
transform: rotate(90deg) translate(-50%, 50%);
// Grippy
@include containerGrippy($headerSize, 'y');
}
}
@ -235,8 +270,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 +308,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 +336,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 +353,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;
}
}
}
@ -467,7 +473,8 @@ export default {
},
data() {
return {
domainObject: this.layoutObject
domainObject: this.layoutObject,
newFrameLocation: []
}
},
computed: {
@ -496,9 +503,27 @@ export default {
this.persist();
},
deleteContainer(containerId) {
let container = this.containers.filter(c => c.id === containerId)[0];
let containerIndex = this.containers.indexOf(container);
let container = this.containers.filter(c => c.id === containerId)[0],
containerIndex = this.containers.indexOf(container);
/*
remove associated domainObjects from composition
*/
container.frames.forEach(f => {
this.composition.remove({identifier: f.domainObjectIdentifier});
});
this.containers.splice(containerIndex, 1);
/*
add a container when there are no containers in the FL,
to prevent user from not being able to add a frame via
drag and drop.
*/
if (this.containers.length === 0) {
this.containers.push(new Container(100));
}
sizeToFill(this.containers);
this.persist();
},
@ -513,12 +538,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
@ -528,6 +563,12 @@ export default {
.frames
.filter((f => f.id === frameId))[0];
let frameIndex = container.frames.indexOf(frame);
/*
remove associated domainObject from composition
*/
this.composition.remove({identifier: frame.domainObjectIdentifier});
container.frames.splice(frameIndex, 1);
sizeToFill(container.frames);
this.persist(containerIndex);
@ -600,24 +641,33 @@ export default {
} else {
this.containers.splice(toIndex, 0, container);
}
this.persist();
},
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,7 +26,7 @@
'flex-basis': `${frame.size}%`
}">
<div class="c-frame c-fl-frame__drag-wrapper is-selectable is-moveable"
<div class="c-frame c-fl-frame__drag-wrapper is-selectable u-inspectable is-moveable"
draggable="true"
@dragstart="initDrag"
ref="frame">
@ -35,7 +35,8 @@
v-if="domainObject"
:domain-object="domainObject"
:object-path="objectPath"
:has-frame="hasFrame">
:has-frame="hasFrame"
ref="objectFrame">
</object-frame>
<div class="c-fl-frame__size-indicator"
@ -73,22 +74,33 @@ export default {
},
methods: {
setDomainObject(object) {
console.log('setting object!');
this.domainObject = object;
this.objectPath = [object];
this.setSelection();
},
setSelection() {
let context = {
item: this.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);
}
@ -99,6 +111,8 @@ export default {
this.setDomainObject(object);
});
}
this.dragGhost = document.getElementById('js-fl-drag-ghost');
},
beforeDestroy() {
if (this.unsubscribeSelection) {

View File

@ -52,9 +52,18 @@ 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'
};
},
destroy: function (element) {
component.$destroy();
component = undefined;

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',
@ -202,7 +204,7 @@ function ToolbarProvider(openmct) {
addContainer,
toggleFrame ? separator: undefined,
toggleFrame,
deleteFrame || deleteContainer ? separator: undefined,
deleteFrame || deleteContainer ? separator : undefined,
deleteFrame,
deleteContainer
];

View File

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

View File

@ -78,9 +78,12 @@
td {
$p: floor($interiorMargin * 1.5);
font-size: 1.1em;
@include ellipsize();
line-height: 120%; // Needed for icon alignment
max-width: 0;
padding-top: $p;
padding-bottom: $p;
width: 25%;
&:not(.c-list-item__name) {
color: $colorItemFgDetails;

View File

@ -7,18 +7,19 @@
<div class="c-ne__embed__info">
<div class="c-ne__embed__name">
<a class="c-ne__embed__link"
v-on:click="navigate(embed.type)"
v-bind:class="[embed.cssClass]">{{embed.name}}</a>
:href="objectLink"
:class="embed.cssClass">{{embed.name}}</a>
<a class="c-ne__embed__context-available icon-arrow-down"
v-on:click="toggleActionMenu"></a>
@click="toggleActionMenu"></a>
</div>
<div class="hide-menu hidden">
<div class="menu-element context-menu-wrapper mobile-disable-select">
<div class="menu context-menu">
<div class="c-menu">
<ul>
<li v-for="action in actions"
v-bind:class="[action.cssClass]"
v-on:click="action.perform(embed, entry)">
<li v-for="action in actions"
:key="action.name"
:class="action.cssClass"
@click="action.perform(embed, entry)">
{{ action.name }}
</li>
</ul>

View File

@ -1,7 +1,5 @@
<li class="c-notebook__entry c-ne has-local-controls"
v-on:drop="dropOnEntry(entry.id, $event)"
v-on:dragover="dragoverOnEntry"
>
@drop.prevent="dropOnEntry(entry.id, $event)">
<div class="c-ne__time-and-content">
<div class="c-ne__time">
<span>{{formatTime(entry.createdOn, 'YYYY-MM-DD')}}</span>
@ -11,18 +9,18 @@
<div class="c-ne__text c-input-inline"
contenteditable="true"
ref="contenteditable"
v-on:blur="textBlur($event, entry.id)"
v-on:focus="textFocus($event, entry.id)"
v-bind:key="entry.id"
@blur="textBlur($event, entry.id)"
@focus="textFocus($event, entry.id)"
v-html="entry.text">
</div>
<div class="c-ne__embeds">
<notebook-embed
v-for="(embed, index) in entry.embeds"
:key="index"
v-for="embed in entry.embeds"
:key="embed.id"
:embed="embed"
:entry="entry"
></notebook-embed>
:objectPath="embed.objectPath"
:entry="entry">
</notebook-embed>
</div>
</div>
</div>
@ -30,6 +28,7 @@
<div class="c-ne__local-controls--hidden">
<button class="c-click-icon c-click-icon--major icon-trash"
title="Delete this entry"
v-on:click="deleteEntry"></button>
@click="deleteEntry">
</button>
</div>
</li>

View File

@ -5,30 +5,25 @@
@input="search"
@clear="search">
</search>
<div class="c-notebook__controls">
<div class="select c-notebook__controls__time">
<select v-model="showTime">
<option value="0" selected="selected">Show all</option>
<option value="1">Last hour</option>
<option value="8">Last 8 hours</option>
<option value="24">Last 24 hours</option>
</select>
</div>
<div class="select c-notebook__controls__sort">
<select v-model="sortEntries">
<option value="newest" :selected="sortEntries === 'newest'">Newest first</option>
<option value="oldest" :selected="sortEntries === 'oldest'">Oldest first</option>
</select>
</div>
<div class="c-notebook__controls ">
<select class="c-notebook__controls__time" v-model="showTime">
<option value="0" selected="selected">Show all</option>
<option value="1">Last hour</option>
<option value="8">Last 8 hours</option>
<option value="24">Last 24 hours</option>
</select>
<select class="c-notebook__controls__time" v-model="sortEntries">
<option value="newest" :selected="sortEntries === 'newest'">Newest first</option>
<option value="oldest" :selected="sortEntries === 'oldest'">Oldest first</option>
</select>
</div>
</div>
<div class="c-notebook__drag-area icon-plus"
@click="newEntry($event)"
@drop="newEntry($event)"
id="newEntry">
@drop="newEntry($event)">
<span class="c-notebook__drag-area__label">To start a new entry, click here or drag and drop any object</span>
</div>
<div class="c-notebook__entries" ng-mouseover="handleActive()">
<div class="c-notebook__entries">
<ul>
<notebook-entry
v-for="(entry,index) in filteredAndSortedEntries"

View File

@ -34,28 +34,17 @@ function (
Vue,
Painterro
) {
function EmbedController (openmct, domainObject) {
function EmbedController(openmct, domainObject) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectService = openmct.$injector.get('objectService');
this.navigationService = openmct.$injector.get('navigationService');
this.popupService = openmct.$injector.get('popupService');
this.agentService = openmct.$injector.get('agentService');
this.dialogService = openmct.$injector.get('dialogService');
this.navigate = this.navigate.bind(this);
this.exposedData = this.exposedData.bind(this);
this.exposedMethods = this.exposedMethods.bind(this);
this.toggleActionMenu = this.toggleActionMenu.bind(this);
}
EmbedController.prototype.navigate = function (embedType) {
this.objectService.getObjects([embedType]).then(function (objects) {
this.navigationService.setNavigation(objects[embedType]);
}.bind(this));
};
EmbedController.prototype.openSnapshot = function (domainObject, entry, embed) {
function annotateSnapshot(openmct) {
@ -63,20 +52,22 @@ function (
var save = false,
painterroInstance = {},
annotateOverlay = new Vue({
annotateVue = new Vue({
template: '<div id="snap-annotation"></div>'
}),
self = this;
openmct.overlays.overlay({
element: annotateOverlay.$mount().$el,
let annotateOverlay = openmct.overlays.overlay({
element: annotateVue.$mount().$el,
size: 'large',
dismissable: false,
buttons: [
{
label: 'Cancel',
callback: function () {
save = false;
painterroInstance.save();
annotateOverlay.dismiss();
}
},
{
@ -84,11 +75,12 @@ function (
callback: function () {
save = true;
painterroInstance.save();
annotateOverlay.dismiss();
}
}
],
onDestroy: function () {
annotateOverlay.$destroy(true);
annotateVue.$destroy(true);
}
});
@ -162,14 +154,11 @@ function (
}
});
function onDestroyCallback() {
snapshot.$destroy(true);
}
var snapshotOverlay = this.openmct.overlays.overlay({
element: snapshot.$mount().$el,
onDestroy: onDestroyCallback,
onDestroy: () => {snapshot.$destroy(true)},
size: 'large',
dismissable: true,
buttons: [
{
label: 'Done',
@ -199,23 +188,20 @@ function (
return foundId;
};
EmbedController.prototype.actionToMenuDecorator = function (action) {
return {
name: action.getMetadata().name,
cssClass: action.getMetadata().cssClass,
perform: action.perform
};
};
EmbedController.prototype.populateActionMenu = function (objectService, actionService) {
EmbedController.prototype.populateActionMenu = function (openmct, actions) {
return function () {
var self = this;
objectService.getObjects([self.embed.type]).then(function (resp) {
var domainObject = resp[self.embed.type],
previewAction = actionService.getActions({key: 'mct-preview-action', domainObject: domainObject})[0];
self.actions.push(self.actionToMenuDecorator(previewAction));
openmct.objects.get(self.embed.type).then(function (domainObject) {
actions.forEach((action) => {
self.actions.push({
cssClass: action.cssClass,
name: action.name,
perform: () => {
action.invoke([domainObject].concat(openmct.router.path));
}
});
});
});
};
};
@ -268,13 +254,14 @@ function (
// Remove the context menu
function dismiss() {
container.find('.hide-menu').append(menu);
body.off(initiatingEvent, dismiss);
menu.off(initiatingEvent, menuClickHandler);
body.off(initiatingEvent, menuClickHandler);
dismissExistingMenu = undefined;
}
function menuClickHandler(e) {
e.stopPropagation();
window.setTimeout(() => {
dismiss();
}, 100);
}
// Dismiss any menu which was already showing
@ -290,11 +277,7 @@ function (
marginY: -50
});
// Stop propagation so that clicks or touches on the menu do not close the menu
menu.on(initiatingEvent, menuClickHandler);
body.on(initiatingEvent, dismiss);
body.on(initiatingEvent, menuClickHandler);
};
EmbedController.prototype.exposedData = function () {
@ -308,11 +291,9 @@ function (
var self = this;
return {
navigate: self.navigate,
openSnapshot: self.openSnapshot,
formatTime: self.formatTime,
toggleActionMenu: self.toggleActionMenu,
actionToMenuDecorator: self.actionToMenuDecorator,
findInArray: self.findInArray
};
};

View File

@ -30,8 +30,6 @@ function (
function EntryController (openmct, domainObject) {
this.openmct = openmct;
this.domainObject = domainObject;
this.dndService = this.openmct.$injector.get('dndService');
this.dialogService = this.openmct.$injector.get('dialogService');
this.currentEntryValue = '';
@ -106,37 +104,35 @@ function (
};
EntryController.prototype.dropOnEntry = function (entryid, event) {
var data = event.dataTransfer.getData('domainObject');
var data = event.dataTransfer.getData('openmct/domain-object-path');
if (data) {
var selectedObject = JSON.parse(data),
selectedObjectId = selectedObject.identifier.key,
cssClass = this.openmct.types.get(selectedObject.type),
var objectPath = JSON.parse(data),
domainObject = objectPath[0],
domainObjectKey = domainObject.identifier.key,
domainObjectType = this.openmct.types.get(domainObject.type),
cssClass = domainObjectType && domainObjectType.definition ?
domainObjectType.definition.cssClass : 'icon-object-unknown',
entryPos = this.entryPosById(entryid),
currentEntryEmbeds = this.domainObject.entries[entryPos].embeds,
newEmbed = {
type: selectedObjectId,
id: '' + Date.now(),
domainObject: domainObject,
objectPath: objectPath,
type: domainObjectKey,
cssClass: cssClass,
name: selectedObject.name,
name: domainObject.name,
snapshot: ''
};
currentEntryEmbeds.push(newEmbed);
this.openmct.objects.mutate(this.domainObject, 'entries[' + entryPos + '].embeds', currentEntryEmbeds);
}
};
EntryController.prototype.dragoverOnEntry = function () {
};
EntryController.prototype.exposedData = function () {
return {
openmct: this.openmct,
domainObject: this.domainObject,
dialogService: this.dialogService,
currentEntryValue: this.currentEntryValue
};
};
@ -148,8 +144,7 @@ function (
textBlur: this.textBlur,
formatTime: this.formatTime,
deleteEntry: this.deleteEntry,
dropOnEntry: this.dropOnEntry,
dragoverOnEntry: this.dragoverOnEntry
dropOnEntry: this.dropOnEntry
};
};
return EntryController;

View File

@ -27,7 +27,9 @@ define([
'../../res/templates/notebook.html',
'../../res/templates/entry.html',
'../../res/templates/embed.html',
'../../../../ui/components/search.vue'
'../../../../ui/components/search.vue',
'../../../../ui/preview/PreviewAction',
'../../../../ui/mixins/object-link'
],
function (
Vue,
@ -36,15 +38,16 @@ function (
NotebookTemplate,
EntryTemplate,
EmbedTemplate,
search
search,
PreviewAction,
objectLinkMixin
) {
function NotebookController(openmct, domainObject) {
this.openmct = openmct;
this.domainObject = domainObject;
this.entrySearch = '';
this.objectService = openmct.$injector.get('objectService');
this.actionService = openmct.$injector.get('actionService');
this.previewAction = new PreviewAction.default(openmct);
this.show = this.show.bind(this);
this.destroy = this.destroy.bind(this);
@ -61,11 +64,12 @@ function (
var notebookEmbed = {
inject:['openmct', 'domainObject'],
mixins:[objectLinkMixin.default],
props:['embed', 'entry'],
template: EmbedTemplate,
data: embedController.exposedData,
methods: embedController.exposedMethods(),
beforeMount: embedController.populateActionMenu(self.objectService, self.actionService)
beforeMount: embedController.populateActionMenu(self.openmct, [self.previewAction])
};
var entryComponent = {
@ -120,8 +124,8 @@ function (
var date = Date.now(),
embed;
if (event.dataTransfer && event.dataTransfer.getData('domainObject')) {
var selectedObject = JSON.parse(event.dataTransfer.getData('domainObject')),
if (event.dataTransfer && event.dataTransfer.getData('openmct/domain-object-path')) {
var selectedObject = JSON.parse(event.dataTransfer.getData('openmct/domain-object-path'))[0],
selectedObjectId = selectedObject.identifier.key,
cssClass = this.openmct.types.get(selectedObject.type);

View File

@ -41,28 +41,24 @@
<div class="grid-cell label"
title="The field to be plotted as a value for this series.">Value</div>
<div class="grid-cell value">
<div class="select">
<select ng-model="form.yKey">
<option ng-repeat="option in yKeyOptions"
value="{{option.value}}"
ng-selected="option.value == form.yKey">
{{option.name}}
</option>
</select>
</div>
<select ng-model="form.yKey">
<option ng-repeat="option in yKeyOptions"
value="{{option.value}}"
ng-selected="option.value == form.yKey">
{{option.name}}
</option>
</select>
</div>
</li>
<li class="grid-row">
<div class="grid-cell label"
title="The line rendering style for this series.">Line Style</div>
<div class="grid-cell value">
<div class="select">
<select ng-model="form.interpolate">
<option value="none">None</option>
<option value="linear">Linear interpolate</option>
<option value="stepAfter">Step after</option>
</select>
</div>
<select ng-model="form.interpolate">
<option value="none">None</option>
<option value="linear">Linear interpolate</option>
<option value="stepAfter">Step after</option>
</select>
</div>
</li>
<li class="grid-row">
@ -160,15 +156,13 @@
<div class="grid-cell label"
title="The position of the legend relative to the plot display area.">Position</div>
<div class="grid-cell value">
<div class="select">
<select ng-model="form.position">
<option value="hidden">Hidden</option>
<option value="top">Top</option>
<option value="right">Right</option>
<option value="bottom">Bottom</option>
<option value="left">Left</option>
</select>
</div>
<select ng-model="form.position">
<option value="hidden">Hidden</option>
<option value="top">Top</option>
<option value="right">Right</option>
<option value="bottom">Bottom</option>
<option value="left">Left</option>
</select>
</div>
</li>
<li class="grid-row">
@ -180,15 +174,13 @@
<div class="grid-cell label"
title="What to display in the legend when it's collapsed.">When collapsed show</div>
<div class="grid-cell value">
<div class="select">
<select ng-model="form.valueToShowWhenCollapsed">
<option value="none">nothing</option>
<option value="nearestTimestamp">nearest timestamp</option>
<option value="nearestValue">nearest Value</option>
<option value="min">minimum value</option>
<option value="max">maximum value</option>
</select>
</div>
<select ng-model="form.valueToShowWhenCollapsed">
<option value="none">Nothing</option>
<option value="nearestTimestamp">Nearest timestamp</option>
<option value="nearestValue">Nearest value</option>
<option value="min">Minimum value</option>
<option value="max">Maximum value</option>
</select>
</div>
</li>
<li class="grid-row">

View File

@ -30,7 +30,7 @@ define(
],
function (
html2canvas,
saveAs
{ saveAs }
) {
/**

View File

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

View File

@ -15,25 +15,25 @@
v-for="(tab,index) in tabsList"
:key="index"
:class="[
{'is-current': tab=== currentTab},
{'is-current': isCurrent(tab)},
tab.type.definition.cssClass
]"
@click="showTab(tab)">
<span class="c-button__label">{{tab.model.name}}</span>
<span class="c-button__label">{{tab.domainObject.name}}</span>
</button>
</div>
<div class="c-tabs-view__object-holder"
v-for="(object, index) in tabsList"
v-for="(tab, index) in tabsList"
:key="index"
:class="{'invisible': object !== currentTab}">
:class="{'invisible': !isCurrent(tab)}">
<div class="c-tabs-view__object-name l-browse-bar__object-name--w"
:class="currentTab.type.definition.cssClass">
<div class="l-browse-bar__object-name">
{{currentTab.model.name}}
{{currentTab.domainObject.name}}
</div>
</div>
<object-view class="c-tabs-view__object"
:object="object.model">
:object="tab.domainObject">
</object-view>
</div>
</div>
@ -87,6 +87,7 @@
<script>
import ObjectView from '../../../ui/components/ObjectView.vue';
import _ from 'lodash';
var unknownObjectType = {
definition: {
@ -100,9 +101,71 @@ export default {
components: {
ObjectView
},
data: function () {
return {
currentTab: {},
tabsList: [],
setCurrentTab: true,
isDragging: false,
allowDrop: false
};
},
methods:{
showTab(tab) {
this.currentTab = tab;
},
addItem(domainObject) {
let type = this.openmct.types.get(domainObject.type) || unknownObjectType,
tabItem = {
domainObject,
type: type
};
this.tabsList.push(tabItem);
if (this.setCurrentTab) {
this.currentTab = tabItem;
this.setCurrentTab = false;
}
},
removeItem(identifier) {
let pos = this.tabsList.findIndex(tab =>
tab.domainObject.identifier.namespace === identifier.namespace && tab.domainObject.identifier.key === identifier.key
),
tabToBeRemoved = this.tabsList[pos];
this.tabsList.splice(pos, 1);
if (this.isCurrent(tabToBeRemoved)) {
this.showTab(this.tabsList[this.tabsList.length - 1]);
}
},
onDrop(e) {
this.setCurrentTab = true;
},
dragstart (e) {
if (e.dataTransfer.types.includes('openmct/domain-object-path')) {
this.isDragging = true;
}
},
dragend(e) {
this.isDragging = false;
this.allowDrop = false;
},
dragenter() {
this.allowDrop = true;
},
dragleave() {
this.allowDrop = false;
},
isCurrent(tab) {
return _.isEqual(this.currentTab, tab)
}
},
mounted () {
if (this.composition) {
this.composition.on('add', this.addItem, this);
this.composition.on('add', this.addItem);
this.composition.on('remove', this.removeItem);
this.composition.load();
}
@ -116,54 +179,9 @@ export default {
dropHint.addEventListener('dragleave', this.dragleave);
}
},
data: function () {
return {
currentTab: {},
tabsList: [],
setCurrentTab: true,
isDragging: false,
allowDrop: false
};
},
methods:{
showTab (tab) {
this.currentTab = tab;
},
addItem (model) {
let type = this.openmct.types.get(model.type) || unknownObjectType,
tabItem = {
model,
type: type
};
this.tabsList.push(tabItem);
if (this.setCurrentTab) {
this.currentTab = tabItem;
this.setCurrentTab = false;
}
},
onDrop (e) {
this.setCurrentTab = true;
},
dragstart (e) {
if (e.dataTransfer.getData('domainObject')) {
this.isDragging = true;
}
},
dragend (e) {
this.isDragging = false;
this.allowDrop = false;
},
dragenter () {
this.allowDrop = true;
},
dragleave() {
this.allowDrop = false;
}
},
destroyed() {
this.composition.off('add', this.addItem, this);
this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem);
document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend);

View File

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

View File

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

View File

@ -34,7 +34,7 @@
<div class="c-telemetry-table__headers-w js-table__headers-w" ref="headersTable" :style="{ 'max-width': widthWithScroll}">
<table class="c-table__headers c-telemetry-table__headers">
<thead>
<tr>
<tr class="c-telemetry-table__headers__name">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
@ -50,7 +50,7 @@
:sortOptions="sortOptions"
>{{title}}</table-column-header>
</tr>
<tr>
<tr class="c-telemetry-table__headers__filter">
<table-column-header
v-for="(title, key, headerIndex) in headers"
:key="key"
@ -110,8 +110,8 @@
.c-telemetry-table__drop-target {
position: absolute;
width: 2px;
background-color: $editColor;
box-shadow: rgba($editColor, 0.5) 0 0 10px;
background-color: $editUIColor;
box-shadow: rgba($editUIColor, 0.5) 0 0 10px;
z-index: 1;
pointer-events: none;
}
@ -214,6 +214,22 @@
}
}
/******************************* EDITING */
.is-editing {
.c-telemetry-table__headers__name {
th[draggable],
th[draggable] > * {
cursor: move;
}
th[draggable]:hover {
$b: $editFrameHovMovebarColorBg;
background: $b;
> * { background: $b; }
}
}
}
/******************************* LEGACY */
.s-status-taking-snapshot,
.overlay.snapshot {

View File

@ -22,9 +22,8 @@
<template>
<div class="c-conductor"
:class="[isFixed ? 'is-fixed-mode' : 'is-realtime-mode']">
<form class="u-contents" ref="conductorForm"
@submit="isFixed ? setBoundsFromView($event) : setOffsetsFromView($event)">
<form class="u-contents" ref="conductorForm" @submit.prevent="updateTimeFromConductor">
<button class="c-input--submit" type="submit" ref="submitButton"></button>
<ConductorModeIcon class="c-conductor__mode-icon"></ConductorModeIcon>
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start-fixed"
@ -35,7 +34,7 @@
type="text" autocorrect="off" spellcheck="false"
ref="startDate"
v-model="formattedBounds.start"
@change="validateBounds('start', $event.target); setBoundsFromView()" />
@change="validateAllBounds(); submitForm()" />
<date-picker
:default-date-time="formattedBounds.start"
:formatter="timeFormatter"
@ -48,9 +47,10 @@
<div class="c-direction-indicator icon-minus"></div>
<input class="c-input--hrs-min-sec"
type="text" autocorrect="off"
ref="startOffset"
spellcheck="false"
v-model="offsets.start"
@change="validateOffsets($event); setOffsetsFromView()">
@change="validateAllOffsets(); submitForm()">
</div>
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end-fixed">
@ -63,7 +63,7 @@
v-model="formattedBounds.end"
:disabled="!isFixed"
ref="endDate"
@change="validateBounds('end', $event.target); setBoundsFromView()">
@change="validateAllBounds(); submitForm()">
<date-picker
class="c-ctrl-wrapper--menus-left"
:default-date-time="formattedBounds.end"
@ -80,8 +80,9 @@
type="text"
autocorrect="off"
spellcheck="false"
ref="endOffset"
v-model="offsets.end"
@change="validateOffsets($event); setOffsetsFromView()">
@change="validateAllOffsets(); submitForm()">
</div>
<conductor-axis
@ -101,6 +102,14 @@
<style lang="scss">
@import "~styles/sass-base";
.c-input--submit {
// Can't use display: none because some browsers will pretend the input doesn't exist, and enter won't work
visibility: none;
height: 0;
width: 0;
padding: 0;
}
/*********************************************** CONDUCTOR LAYOUT */
.c-conductor {
display: grid;
@ -357,6 +366,7 @@ export default {
},
setViewFromClock(clock) {
this.isFixed = clock === undefined;
this.clearAllValidation();
},
setViewFromBounds(bounds) {
this.formattedBounds.start = this.timeFormatter.format(bounds.start);
@ -368,45 +378,87 @@ export default {
this.offsets.start = this.durationFormatter.format(Math.abs(offsets.start));
this.offsets.end = this.durationFormatter.format(Math.abs(offsets.end));
},
validateBounds(startOrEnd, input) {
let validationResult = true;
if (!this.timeFormatter.validate(input.value)){
validationResult = 'Invalid date value';
updateTimeFromConductor() {
if (this.isFixed) {
this.setBoundsFromView();
} else {
let boundsValues = {
start: this.timeFormatter.parse(this.formattedBounds.start),
end: this.timeFormatter.parse(this.formattedBounds.end)
};
validationResult = this.openmct.time.validateBounds(boundsValues);
}
if (validationResult !== true){
input.setCustomValidity(validationResult);
} else {
input.setCustomValidity('');
this.setOffsetsFromView();
}
},
validateOffsets(event) {
let input = event.target;
let validationResult = true;
if (!this.durationFormatter.validate(input.value)) {
validationResult = 'Invalid offset value';
} else {
let offsetValues = {
start: 0 - this.durationFormatter.parse(this.offsets.start),
end: this.durationFormatter.parse(this.offsets.end)
};
validationResult = this.openmct.time.validateOffsets(offsetValues);
}
if (validationResult !== true){
input.setCustomValidity(validationResult);
} else {
clearAllValidation() {
[this.$refs.startDate, this.$refs.endDate, this.$refs.startOffset, this.$refs.endOffset].forEach((input) => {
input.setCustomValidity('');
}
input.title = '';
});
},
validateAllBounds() {
return [this.$refs.startDate, this.$refs.endDate].every((input) => {
let validationResult = true;
let formattedDate;
if (input === this.$refs.startDate) {
formattedDate = this.formattedBounds.start;
} else {
formattedDate = this.formattedBounds.end;
}
if (!this.timeFormatter.validate(formattedDate)){
validationResult = 'Invalid date';
} else {
let boundsValues = {
start: this.timeFormatter.parse(this.formattedBounds.start),
end: this.timeFormatter.parse(this.formattedBounds.end)
};
validationResult = this.openmct.time.validateBounds(boundsValues);
}
if (validationResult !== true){
input.setCustomValidity(validationResult);
input.title = validationResult;
return false;
} else {
input.setCustomValidity('');
input.title = '';
return true;
}
});
},
validateAllOffsets(event) {
return [this.$refs.startOffset, this.$refs.endOffset].every((input) => {
let validationResult = true;
let formattedOffset;
if (input === this.$refs.startOffset) {
formattedOffset = this.offsets.start;
} else {
formattedOffset = this.offsets.end;
}
if (!this.durationFormatter.validate(formattedOffset)) {
validationResult = 'Offsets must be in the format hh:mm:ss and less than 24 hours in duration';
} else {
let offsetValues = {
start: 0 - this.durationFormatter.parse(this.offsets.start),
end: this.durationFormatter.parse(this.offsets.end)
};
validationResult = this.openmct.time.validateOffsets(offsetValues);
}
if (validationResult !== true){
input.setCustomValidity(validationResult);
input.title = validationResult;
return false;
} else {
input.setCustomValidity('');
input.title = '';
return true;
}
});
},
submitForm() {
// Allow Vue model to catch up to user input.
// Submitting form will cause validation messages to display (but only if triggered by button click)
this.$nextTick(() => this.$refs.submitButton.click());
},
getFormatter(key) {
return this.openmct.telemetry.getValueFormatter({
@ -415,13 +467,13 @@ export default {
},
startDateSelected(date){
this.formattedBounds.start = this.timeFormatter.format(date);
this.validateBounds('start', this.$refs.startDate);
this.setBoundsFromView();
this.validateAllBounds();
this.submitForm();
},
endDateSelected(date){
this.formattedBounds.end = this.timeFormatter.format(date);
this.validateBounds('end', this.$refs.endDate);
this.setBoundsFromView();
this.validateAllBounds();
this.submitForm();
},
},
mounted() {

View File

@ -22,11 +22,11 @@
<template>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
<button class="c-button--menu c-mode-button"
@click="toggleMenu($event)">
@click.prevent="toggle">
<span class="c-button__label">{{selectedMode.name}}</span>
</button>
<div class="c-menu c-super-menu c-conductor__mode-menu"
v-if="showMenu">
v-if="open">
<div class="c-super-menu__menu">
<ul>
<li v-for="mode in modes"
@ -69,8 +69,11 @@
</style>
<script>
import toggleMixin from '../../ui/mixins/toggle-mixin';
export default {
inject: ['openmct', 'configuration'],
mixins: [toggleMixin],
data: function () {
let activeClock = this.openmct.time.clock();
if (activeClock !== undefined) {
@ -81,8 +84,7 @@ export default {
selectedMode: this.getModeOptionForClock(activeClock),
selectedTimeSystem: JSON.parse(JSON.stringify(this.openmct.time.timeSystem())),
modes: [],
hoveredMode: {},
showMenu: false
hoveredMode: {}
};
},
methods: {
@ -177,17 +179,7 @@ export default {
setViewFromClock(clock) {
this.selectedMode = this.getModeOptionForClock(clock);
},
toggleMenu(event) {
this.showMenu = !this.showMenu;
if (this.showMenu) {
document.addEventListener('click', this.toggleMenu, true);
} else {
document.removeEventListener('click', this.toggleMenu, true);
}
},
}
},
mounted: function () {
this.loadClocksFromConfiguration();

View File

@ -24,10 +24,10 @@
v-if="selectedTimeSystem.name">
<button class="c-button--menu c-time-system-button"
:class="selectedTimeSystem.cssClass"
@click="toggleMenu($event)">
@click.prevent="toggle">
<span class="c-button__label">{{selectedTimeSystem.name}}</span>
</button>
<div class="c-menu" v-if="showMenu">
<div class="c-menu" v-if="open">
<ul>
<li @click="setTimeSystemFromView(timeSystem)"
v-for="timeSystem in timeSystems"
@ -41,15 +41,17 @@
</template>
<script>
import toggleMixin from '../../ui/mixins/toggle-mixin';
export default {
inject: ['openmct', 'configuration'],
mixins: [toggleMixin],
data: function () {
let activeClock = this.openmct.time.clock();
return {
selectedTimeSystem: JSON.parse(JSON.stringify(this.openmct.time.timeSystem())),
timeSystems: this.getValidTimesystemsForClock(activeClock),
showMenu: false
timeSystems: this.getValidTimesystemsForClock(activeClock)
};
},
methods: {
@ -94,16 +96,6 @@ export default {
return this.configuration.menuOptions.filter(configMatches)[0];
},
toggleMenu(event) {
this.showMenu = !this.showMenu;
if (this.showMenu) {
document.addEventListener('click', this.toggleMenu, true);
} else {
document.removeEventListener('click', this.toggleMenu, true);
}
},
setViewFromTimeSystem(timeSystem) {
this.selectedTimeSystem = timeSystem;
},

View File

@ -22,12 +22,12 @@
<template>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up c-datetime-picker__wrapper" ref="calendarHolder">
<a class="c-click-icon icon-calendar"
@click="togglePicker()"></a>
@click="toggle"></a>
<div class="c-menu c-menu--mobile-modal c-datetime-picker"
v-if="showPicker">
v-if="open">
<div class="c-datetime-picker__close-button">
<button class="c-click-icon icon-x-in-circle"
@click="togglePicker()"></button>
@click="toggle"></button>
</div>
<div class="c-datetime-picker__pager c-pager l-month-year-pager">
<div class="c-pager__prev c-click-icon icon-arrow-left"
@ -160,6 +160,7 @@
<script>
import moment from 'moment';
import toggleMixin from '../../ui/mixins/toggle-mixin';
const TIME_NAMES = {
'hours': "Hour",
@ -181,13 +182,13 @@ const TIME_OPTIONS = (function makeRanges() {
export default {
inject: ['openmct'],
mixins: [toggleMixin],
props: {
defaultDateTime: String,
formatter: Object
},
data: function () {
return {
showPicker: false,
picker: {
year: undefined,
month: undefined,
@ -285,7 +286,6 @@ export default {
this.date.year = cell.year;
this.date.day = cell.day;
this.updateFromView();
this.showPicker = false;
},
dateEquals(d1, d2) {
@ -315,23 +315,6 @@ export default {
optionsFor(key) {
return TIME_OPTIONS[key];
},
hidePicker(event) {
let path = event.composedPath();
if (path.indexOf(this.$refs.calendarHolder) === -1) {
this.showPicker = false;
}
},
togglePicker() {
this.showPicker = !this.showPicker;
if (this.showPicker) {
document.addEventListener('click', this.hidePicker, {
capture: true
});
}
}
},
mounted: function () {
this.updateFromModel(this.defaultDateTime);

View File

@ -47,6 +47,14 @@ $bodyFont: $heroFont;
@return linear-gradient(lighten($c, 5%), $c);
}
@function pullForward($val, $amt) {
@return lighten($val, $amt);
}
@function pushBack($val, $amt) {
@return darken($val, $amt);
}
// Constants
$fontBaseSize: 12px;
$smallCr: 2px;
@ -55,7 +63,7 @@ $basicCr: 4px;
// Base colors
$colorBodyBg: #393939;
$colorBodyFg: #aaa;
$colorBodyFg: #aaaaaa;
$colorBodyFgEm: #fff;
$colorGenBg: #222;
$colorHeadBg: #262626;
@ -65,10 +73,11 @@ $colorStatusBarFg: $colorBodyFg;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #00c0f6;
$colorKeyHov: #26d8ff;
$colorKeyFilter: invert(36%) sepia(76%) saturate(2514%) hue-rotate(170deg) brightness(99%) contrast(101%);
$colorKeyFilterHov: invert(63%) sepia(88%) saturate(3029%) hue-rotate(154deg) brightness(101%) contrast(100%);
$colorKeySelectedBg: $colorKey;
$uiColor: #00b2ff; // Resize bars, splitter bars, etc.
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
$colorA: #ccc;
$colorAHov: #fff;
@ -94,51 +103,52 @@ $colorPausedFg: #fff;
$colorOk: #33cc33;
// Base variations
$colorBodyBgSubtle: lighten($colorBodyBg, 5%);
$colorBodyBgSubtleHov: darken($colorKey, 50%);
$colorKeySubtle: darken($colorKey, 10%);
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
$colorKeySubtle: pushBack($colorKey, 10%);
// Time Colors
$colorTime: #618cff;
$colorTimeBg: $colorTime;
$colorTimeFg: lighten($colorTimeBg, 30%);
$colorTimeHov: lighten($colorTime, 10%);
$colorTimeSubtle: darken($colorTime, 20%);
$colorTimeFg: pullForward($colorTimeBg, 30%);
$colorTimeHov: pullForward($colorTime, 10%);
$colorTimeSubtle: pushBack($colorTime, 20%);
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
/************************************************** EDITING */
// Base Colors
$dlSpread: 20%;
$editColor: #00c7c3;
$editColorAlt: #9971ff;
$editColorBgBase: darken($editColor, $dlSpread);
$editColorBg: rgba($editColorBgBase, 0.2);
$editColorFg: lighten($editColor, $dlSpread);
$editColorHov: lighten($editColor, 20%);
// Canvas
$editCanvasColorBg: $editColorBg; //#002524;
$editCanvasColorGrid: rgba($editColorBgBase, 0.4); //lighten($editCanvasColorBg, 3%);
// Selectable
$editSelectableColor: #006563;
$editSelectableColorFg: lighten($editSelectableColor, 20%);
$editSelectableColorHov: lighten($editSelectableColor, 10%);
// Selectable selected
$editSelectableColorSelected: $editSelectableColorHov;
$editSelectableColorSelectedFg: lighten($editSelectableColorSelected, 30%);
$editSelectableColorFg: darken($editSelectableColor, 40%);
$editSelectableBorder: 1px dotted $editSelectableColor;
$editSelectableBorderHov: 1px dotted $editColorAlt;
$editSelectableBorderSelected: 1px solid $editColor;
$editSelectableShdwSelected: rgba($editColor, 0.75) 0 0 0 1px;
$editMoveableSelectedShdw: rgba($editColor, 0.5) 0 0 10px;
$editBorderDrilledIn: 1px dashed $editColorAlt;
$colorGridLines: rgba($editColor, 0.2);
/************************************************** BROWSING */
$browseSelectableBorderHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseSelectableShdwHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.6);
$browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
/************************************************** EDITING */
$editUIColor: $uiColor; // Base color
$editUIColorHov: pullForward(saturate($uiColor, 10%), 20%); // Hover color when $editUIColor is applied as a base color
$editUIBaseColor: #344b8d; // Base color, toolbar bg
$editUIBaseColorHov: pullForward($editUIBaseColor, 20%);
$editUIBaseColorFg: #ffffff; // Toolbar button icon colors, etc.
$editUIAreaBaseColor: pullForward(saturate($editUIBaseColor, 30%), 20%);
$editUIAreaShdw: $editUIAreaBaseColor 0 0 0 2px; // Edit area s-selected-parent
$editUIAreaShdwSelected: $editUIAreaBaseColor 0 0 0 3px; // Edit area s-selected
$editUIGridColorBg: rgba($editUIBaseColor, 0.2); // Background of layout editing area
$editUIGridColorFg: rgba(#000, 0.1); // Grid lines in layout editing area
$editFrameColor: $browseFrameColor; // Solid or dotted border applied to non-selected frames in a layout; move-bar on frame hover
$editFrameBorder: 1px dotted $editFrameColor;
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
$editFrameColorSelected: #ccc; // Border of selected frames
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
$editFrameSelectedShdw: rgba(black, 0.5) 0 1px 10px 1px;
$editFrameSelectedBorder: 1px dashed $editFrameColorSelected; // Selected frame element
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
$editFrameHovMovebarColorFg: pullForward($editFrameMovebarColorFg, 10%);
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
$editFrameMovebarH: 10px; // Height of move bar in layout frame
// Icons
$colorIconAlias: #4af6f3;
@ -148,16 +158,16 @@ $colorIconAliasForKeyFilter: #aaa;
$colorTabsHolderBg: rgba(black, 0.2);
// Buttons and Controls
$colorBtnBg: lighten($colorBodyBg, 10%);
$colorBtnBgHov: lighten($colorBtnBg, 10%);
$colorBtnFg: lighten($colorBodyFg, 10%);
$colorBtnReverseFg: lighten($colorBtnFg, 10%);
$colorBtnReverseBg: lighten($colorBtnBg, 10%);
$colorBtnBg: pullForward($colorBodyBg, 10%);
$colorBtnBgHov: pullForward($colorBtnBg, 10%);
$colorBtnFg: pullForward($colorBodyFg, 10%);
$colorBtnReverseFg: pullForward($colorBtnFg, 10%);
$colorBtnReverseBg: pullForward($colorBtnBg, 10%);
$colorBtnFgHov: $colorBtnFg;
$colorBtnMajorBg: $colorKey;
$colorBtnMajorBgHov: $colorKeyHov;
$colorBtnMajorFg: $colorKeyFg;
$colorBtnMajorFgHov: darken($colorBtnMajorFg, 10%);
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%);
$colorBtnCautionBg: #f16f6f;
$colorBtnCautionBgHov: #f1504e;
$colorBtnCautionFg: $colorBtnFg;
@ -165,20 +175,20 @@ $colorClickIcon: $colorKey;
$colorClickIconBgHov: rgba($colorKey, 0.6);
$colorClickIconFgHov: $colorKeyHov;
$colorDropHint: $colorKey;
$colorDropHintBg: darken($colorDropHint, 10%);
$colorDropHintBg: pushBack($colorDropHint, 10%);
$colorDropHintBgHov: $colorDropHint;
$colorDropHintFg: lighten($colorDropHint, 40%);
$colorDropHintFg: pullForward($colorDropHint, 40%);
$colorDisclosureCtrl: rgba($colorBodyFg, 0.5);
$colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7);
// Menus
$colorMenuBg: lighten($colorBodyBg, 15%);
$colorMenuFg: lighten($colorBodyFg, 30%);
$colorMenuIc: lighten($colorKey, 15%);
$colorMenuBg: pullForward($colorBodyBg, 15%);
$colorMenuFg: pullForward($colorBodyFg, 30%);
$colorMenuIc: pullForward($colorKey, 15%);
$colorMenuHovBg: $colorMenuIc;
$colorMenuHovFg: lighten($colorMenuFg, 10%);
$colorMenuHovFg: pullForward($colorMenuFg, 10%);
$colorMenuHovIc: $colorMenuHovFg;
$colorMenuElementHilite: lighten($colorMenuBg, 10%);
$colorMenuElementHilite: pullForward($colorMenuBg, 10%);
$shdwMenu: rgba(black, 0.5) 0 1px 5px;
$shdwMenuText: none;
$menuItemPad: $interiorMargin, floor($interiorMargin * 1.25);
@ -200,21 +210,21 @@ $colorFormLines: rgba(#000, 0.1);
$colorFormSectionHeader: rgba(#000, 0.05);
$colorInputBg: rgba(black, 0.2);
$colorInputFg: $colorBodyFg;
$colorInputPlaceholder: darken($colorBodyFg, 20%);
$colorFormText: darken($colorBodyFg, 10%);
$colorInputIcon: darken($colorBodyFg, 25%);
$colorFieldHint: lighten($colorBodyFg, 40%);
$colorInputPlaceholder: pushBack($colorBodyFg, 20%);
$colorFormText: pushBack($colorBodyFg, 10%);
$colorInputIcon: pushBack($colorBodyFg, 25%);
$colorFieldHint: pullForward($colorBodyFg, 40%);
$shdwInput: inset rgba(black, 0.4) 0 0 1px;
$shdwInputHov: inset rgba(black, 0.7) 0 0 2px;
$shdwInputFoc: inset rgba(black, 0.8) 0 0.25px 3px;
// Inspector
$colorInspectorBg: lighten($colorBodyBg, 5%);
$colorInspectorBg: pullForward($colorBodyBg, 5%);
$colorInspectorFg: $colorBodyFg;
$colorInspectorPropName: darken($colorBodyFg, 20%);
$colorInspectorPropVal: lighten($colorInspectorFg, 15%);
$colorInspectorSectionHeaderBg: lighten($colorInspectorBg, 5%);
$colorInspectorSectionHeaderFg: lighten($colorInspectorBg, 40%);
$colorInspectorPropName: pushBack($colorBodyFg, 20%);
$colorInspectorPropVal: pullForward($colorInspectorFg, 15%);
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
// Overlay
$overlayColorBg: $colorMenuBg;
@ -229,8 +239,8 @@ $colorIndicatorOn: $colorOk;
$colorIndicatorOff: #777777;
// Staleness
$colorTelemFresh: lighten($colorBodyFg, 20%);
$colorTelemStale: darken($colorBodyFg, 20%);
$colorTelemFresh: pullForward($colorBodyFg, 20%);
$colorTelemStale: pushBack($colorBodyFg, 20%);
$styleTelemStale: italic;
// Limits
@ -256,22 +266,22 @@ $colorInfoBubbleFg: #666;
// Items
$colorItemBg: buttonBg($colorBtnBg);
$colorItemBgHov: buttonBg(lighten($colorBtnBg, 5%));
$colorItemBgHov: buttonBg(pullForward($colorBtnBg, 5%));
$colorListItemBg: transparent;
$colorListItemBgHov: rgba($colorKey, 0.1);
$colorItemFg: $colorBtnFg;
$colorItemFgDetails: darken($colorItemFg, 20%);
$colorItemFgDetails: pushBack($colorItemFg, 20%);
$shdwItemText: none;
// Tabular
$colorTabBorder: lighten($colorBodyBg, 10%);
$colorTabBorder: pullForward($colorBodyBg, 10%);
$colorTabBodyBg: $colorBodyBg;
$colorTabBodyFg: lighten($colorBodyFg, 20%);
$colorTabHeaderBg: lighten($colorBodyBg, 10%);
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
$colorTabHeaderBg: pullForward($colorBodyBg, 10%);
$colorTabHeaderFg: $colorBodyFg;
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: lighten($colorBodyBg, 5%);
$colorTabGroupHeaderFg: darken($colorTabHeaderFg, 10%);
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);
$colorTabGroupHeaderFg: pushBack($colorTabHeaderFg, 10%);
// Plot
$colorPlotBg: rgba(black, 0.05);
@ -280,22 +290,22 @@ $colorPlotHash: black;
$opacityPlotHash: 0.2;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: darken($colorPlotFg, 20%);
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
// Tree
$colorTreeBg: transparent;
$colorItemTreeHoverBg: lighten($colorBodyBg, 10%);
$colorItemTreeHoverFg: lighten($colorBodyFg, 20%);
$colorItemTreeHoverBg: pullForward($colorBodyBg, 10%);
$colorItemTreeHoverFg: pullForward($colorBodyFg, 20%);
$colorItemTreeIcon: $colorKey; // Used
$colorItemTreeIconHover: $colorItemTreeIcon; // Used
$colorItemTreeFg: $colorBodyFg;
$colorItemTreeSelectedBg: darken($colorKey, 15%);
$colorItemTreeSelectedBg: pushBack($colorKey, 15%);
$colorItemTreeSelectedFg: $colorItemTreeHoverFg;
$colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
$colorItemTreeEditingBg: darken($editColor, 20%);
$colorItemTreeEditingFg: $editColorFg;
$colorItemTreeEditingIcon: $editColorFg;
$colorItemTreeEditingBg: pushBack($editUIColor, 20%);
$colorItemTreeEditingFg: $editUIColor;
$colorItemTreeEditingIcon: $editUIColor;
$colorItemTreeVC: $colorDisclosureCtrl;
$colorItemTreeVCHover: $colorDisclosureCtrlHov;
$shdwItemTreeIcon: none;
@ -307,18 +317,18 @@ $colorThumbHoverBg: $colorItemTreeHoverBg;
$scrollbarTrackSize: 7px;
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
$scrollbarTrackColorBg: rgba(#000, 0.2);
$scrollbarThumbColor: darken($colorBodyBg, 50%);
$scrollbarThumbColor: pushBack($colorBodyBg, 50%);
$scrollbarThumbColorHov: $colorKey;
$scrollbarThumbColorMenu: lighten($colorMenuBg, 10%);
$scrollbarThumbColorMenuHov: lighten($scrollbarThumbColorMenu, 2%);
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 10%);
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
// Splitter
$splitterHandleD: 2px;
$splitterHandleHitMargin: 4px;
$colorSplitterBaseBg: $colorBodyBg;
$colorSplitterBg: lighten($colorSplitterBaseBg, 10%);
$colorSplitterBg: pullForward($colorBodyBg, 10%);
$colorSplitterFg: $colorBodyBg;
$colorSplitterHover: $colorKey;
$colorSplitterHover: $uiColor;
$colorSplitterActive: $colorKey;
$splitterBtnD: (16px, 35px); // height, width
$splitterBtnColorBg: $colorBtnBg;
@ -330,7 +340,7 @@ $splitterCollapsedBtnColorBgHov: $colorKey;
$splitterCollapsedBtnColorFgHov: $colorKeyFg;
// Mobile
$colorMobilePaneLeft: darken($colorBodyBg, 2%);
$colorMobilePaneLeft: pushBack($colorBodyBg, 2%);
$colorMobilePaneLeftTreeItemBg: rgba($colorBodyFg, 0.1);
$colorMobilePaneLeftTreeItemFg: $colorItemTreeFg;
$colorMobileSelectListTreeItemBg: rgba(#000, 0.05);
@ -367,21 +377,10 @@ $createBtnTextTransform: uppercase;
}
@mixin themedButton($c: $colorBtnBg) {
background: linear-gradient(lighten($c, 5%), $c);
background: linear-gradient(pullForward($c, 5%), $c);
box-shadow: rgba(black, 0.5) 0 0.5px 2px;
}
/**************************************************** NOT USED, LEAVE FOR NOW */
// Slider controls, not in use
/*
$sliderColorBase: $colorKey;
$sliderColorRangeHolder: rgba(black, 0.07);
$sliderColorRange: rgba($sliderColorBase, 0.2);
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
$sliderColorKnob: darken($sliderColorBase, 20%);
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
$sliderColorRangeValHovBg: $sliderColorRange;
$sliderColorRangeValHovFg: $colorBodyFg;
$sliderKnobW: 15px;
$sliderKnobR: 2px;
*/
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect(linear-gradient(lighten($bg, 5%), $bg), $fg, lighten($bg, 20%), rgba(black, 0.5) 0 0.5px 3px);
}

View File

@ -51,6 +51,14 @@ $bodyFont: 'Chakra Petch', sans-serif;
@return linear-gradient(lighten($c, 5%), $c);
}
@function pullForward($val, $amt) {
@return lighten($val, $amt);
}
@function pushBack($val, $amt) {
@return darken($val, $amt);
}
// Constants
$fontBaseSize: 12px;
$smallCr: 2px;
@ -69,10 +77,11 @@ $colorStatusBarFg: $colorBodyFg;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #00c0f6;
$colorKeyHov: #26d8ff;
$colorKeyFilter: invert(36%) sepia(76%) saturate(2514%) hue-rotate(170deg) brightness(99%) contrast(101%);
$colorKeyFilterHov: invert(63%) sepia(88%) saturate(3029%) hue-rotate(154deg) brightness(101%) contrast(100%);
$colorKeySelectedBg: $colorKey;
$uiColor: #00b2ff; // Resize bars, splitter bars, etc.
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
$colorA: #ccc;
$colorAHov: #fff;
@ -98,51 +107,52 @@ $colorPausedFg: #fff;
$colorOk: #33cc33;
// Base variations
$colorBodyBgSubtle: lighten($colorBodyBg, 5%);
$colorBodyBgSubtleHov: darken($colorKey, 50%);
$colorKeySubtle: darken($colorKey, 10%);
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
$colorKeySubtle: pushBack($colorKey, 10%);
// Time Colors
$colorTime: #618cff;
$colorTimeBg: $colorTime;
$colorTimeFg: lighten($colorTimeBg, 30%);
$colorTimeHov: lighten($colorTime, 10%);
$colorTimeSubtle: darken($colorTime, 20%);
$colorTimeFg: pullForward($colorTimeBg, 30%);
$colorTimeHov: pullForward($colorTime, 10%);
$colorTimeSubtle: pushBack($colorTime, 20%);
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
/************************************************** EDITING */
// Base Colors
$dlSpread: 20%;
$editColor: #00c7c3;
$editColorAlt: #9971ff;
$editColorBgBase: darken($editColor, $dlSpread);
$editColorBg: rgba($editColorBgBase, 0.2);
$editColorFg: lighten($editColor, $dlSpread);
$editColorHov: lighten($editColor, 20%);
// Canvas
$editCanvasColorBg: $editColorBg; //#002524;
$editCanvasColorGrid: rgba($editColorBgBase, 0.4); //lighten($editCanvasColorBg, 3%);
// Selectable
$editSelectableColor: #006563;
$editSelectableColorFg: lighten($editSelectableColor, 20%);
$editSelectableColorHov: lighten($editSelectableColor, 10%);
// Selectable selected
$editSelectableColorSelected: $editSelectableColorHov;
$editSelectableColorSelectedFg: lighten($editSelectableColorSelected, 30%);
$editSelectableColorFg: darken($editSelectableColor, 40%);
$editSelectableBorder: 1px dotted $editSelectableColor;
$editSelectableBorderHov: 1px dotted $editColorAlt;
$editSelectableBorderSelected: 1px solid $editColor;
$editSelectableShdwSelected: rgba($editColor, 0.75) 0 0 0 1px;
$editMoveableSelectedShdw: rgba($editColor, 0.5) 0 0 10px;
$editBorderDrilledIn: 1px dashed $editColorAlt;
$colorGridLines: rgba($editColor, 0.2);
/************************************************** BROWSING */
$browseSelectableBorderHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseSelectableShdwHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.6);
$browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
/************************************************** EDITING */
$editUIColor: $uiColor; // Base color
$editUIColorHov: pullForward(saturate($uiColor, 10%), 20%); // Hover color when $editUIColor is applied as a base color
$editUIBaseColor: #344b8d; // Base color, toolbar bg
$editUIBaseColorHov: pullForward($editUIBaseColor, 20%);
$editUIBaseColorFg: #ffffff; // Toolbar button icon colors, etc.
$editUIAreaBaseColor: pullForward(saturate($editUIBaseColor, 30%), 20%);
$editUIAreaShdw: $editUIAreaBaseColor 0 0 0 2px; // Edit area s-selected-parent
$editUIAreaShdwSelected: $editUIAreaBaseColor 0 0 0 3px; // Edit area s-selected
$editUIGridColorBg: rgba($editUIBaseColor, 0.2); // Background of layout editing area
$editUIGridColorFg: rgba(#000, 0.1); // Grid lines in layout editing area
$editFrameColor: $browseFrameColor; // Solid or dotted border applied to non-selected frames in a layout; move-bar on frame hover
$editFrameBorder: 1px dotted $editFrameColor;
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
$editFrameColorSelected: #ccc; // Border of selected frames
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
$editFrameSelectedShdw: rgba(black, 0.5) 0 1px 10px 1px;
$editFrameSelectedBorder: 1px dashed $editFrameColorSelected; // Selected frame element
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
$editFrameHovMovebarColorFg: pullForward($editFrameMovebarColorFg, 10%);
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
$editFrameMovebarH: 10px; // Height of move bar in layout frame
// Icons
$colorIconAlias: #4af6f3;
@ -152,16 +162,16 @@ $colorIconAliasForKeyFilter: #aaa;
$colorTabsHolderBg: rgba(black, 0.2);
// Buttons and Controls
$colorBtnBg: lighten($colorBodyBg, 10%);
$colorBtnBgHov: lighten($colorBtnBg, 10%);
$colorBtnFg: lighten($colorBodyFg, 10%);
$colorBtnReverseFg: lighten($colorBtnFg, 10%);
$colorBtnReverseBg: lighten($colorBtnBg, 10%);
$colorBtnBg: pullForward($colorBodyBg, 10%);
$colorBtnBgHov: pullForward($colorBtnBg, 10%);
$colorBtnFg: pullForward($colorBodyFg, 10%);
$colorBtnReverseFg: pullForward($colorBtnFg, 10%);
$colorBtnReverseBg: pullForward($colorBtnBg, 10%);
$colorBtnFgHov: $colorBtnFg;
$colorBtnMajorBg: $colorKey;
$colorBtnMajorBgHov: $colorKeyHov;
$colorBtnMajorFg: $colorKeyFg;
$colorBtnMajorFgHov: darken($colorBtnMajorFg, 10%);
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%);
$colorBtnCautionBg: #f16f6f;
$colorBtnCautionBgHov: #f1504e;
$colorBtnCautionFg: $colorBtnFg;
@ -169,20 +179,20 @@ $colorClickIcon: $colorKey;
$colorClickIconBgHov: rgba($colorKey, 0.6);
$colorClickIconFgHov: $colorKeyHov;
$colorDropHint: $colorKey;
$colorDropHintBg: darken($colorDropHint, 10%);
$colorDropHintBg: pushBack($colorDropHint, 10%);
$colorDropHintBgHov: $colorDropHint;
$colorDropHintFg: lighten($colorDropHint, 40%);
$colorDropHintFg: pullForward($colorDropHint, 40%);
$colorDisclosureCtrl: rgba($colorBodyFg, 0.5);
$colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7);
// Menus
$colorMenuBg: lighten($colorBodyBg, 15%);
$colorMenuFg: lighten($colorBodyFg, 30%);
$colorMenuIc: lighten($colorKey, 15%);
$colorMenuBg: pullForward($colorBodyBg, 15%);
$colorMenuFg: pullForward($colorBodyFg, 30%);
$colorMenuIc: pullForward($colorKey, 15%);
$colorMenuHovBg: $colorMenuIc;
$colorMenuHovFg: lighten($colorMenuFg, 10%);
$colorMenuHovFg: pullForward($colorMenuFg, 10%);
$colorMenuHovIc: $colorMenuHovFg;
$colorMenuElementHilite: lighten($colorMenuBg, 10%);
$colorMenuElementHilite: pullForward($colorMenuBg, 10%);
$shdwMenu: rgba(black, 0.5) 0 1px 5px;
$shdwMenuText: none;
$menuItemPad: $interiorMargin, floor($interiorMargin * 1.25);
@ -204,21 +214,21 @@ $colorFormLines: rgba(#000, 0.1);
$colorFormSectionHeader: rgba(#000, 0.05);
$colorInputBg: rgba(black, 0.2);
$colorInputFg: $colorBodyFg;
$colorInputPlaceholder: darken($colorBodyFg, 20%);
$colorFormText: darken($colorBodyFg, 10%);
$colorInputIcon: darken($colorBodyFg, 25%);
$colorFieldHint: lighten($colorBodyFg, 40%);
$colorInputPlaceholder: pushBack($colorBodyFg, 20%);
$colorFormText: pushBack($colorBodyFg, 10%);
$colorInputIcon: pushBack($colorBodyFg, 25%);
$colorFieldHint: pullForward($colorBodyFg, 40%);
$shdwInput: inset rgba(black, 0.4) 0 0 1px;
$shdwInputHov: inset rgba(black, 0.7) 0 0 2px;
$shdwInputFoc: inset rgba(black, 0.8) 0 0.25px 3px;
// Inspector
$colorInspectorBg: lighten($colorBodyBg, 5%);
$colorInspectorBg: pullForward($colorBodyBg, 5%);
$colorInspectorFg: $colorBodyFg;
$colorInspectorPropName: darken($colorBodyFg, 20%);
$colorInspectorPropVal: lighten($colorInspectorFg, 15%);
$colorInspectorSectionHeaderBg: lighten($colorInspectorBg, 5%);
$colorInspectorSectionHeaderFg: lighten($colorInspectorBg, 40%);
$colorInspectorPropName: pushBack($colorBodyFg, 20%);
$colorInspectorPropVal: pullForward($colorInspectorFg, 15%);
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
// Overlay
$overlayColorBg: $colorMenuBg;
@ -233,8 +243,8 @@ $colorIndicatorOn: $colorOk;
$colorIndicatorOff: #777777;
// Staleness
$colorTelemFresh: lighten($colorBodyFg, 20%);
$colorTelemStale: darken($colorBodyFg, 20%);
$colorTelemFresh: pullForward($colorBodyFg, 20%);
$colorTelemStale: pushBack($colorBodyFg, 20%);
$styleTelemStale: italic;
// Limits
@ -260,22 +270,22 @@ $colorInfoBubbleFg: #666;
// Items
$colorItemBg: buttonBg($colorBtnBg);
$colorItemBgHov: buttonBg(lighten($colorBtnBg, 5%));
$colorItemBgHov: buttonBg(pullForward($colorBtnBg, 5%));
$colorListItemBg: transparent;
$colorListItemBgHov: rgba($colorKey, 0.1);
$colorItemFg: $colorBtnFg;
$colorItemFgDetails: darken($colorItemFg, 20%);
$colorItemFgDetails: pushBack($colorItemFg, 20%);
$shdwItemText: none;
// Tabular
$colorTabBorder: lighten($colorBodyBg, 10%);
$colorTabBorder: pullForward($colorBodyBg, 10%);
$colorTabBodyBg: $colorBodyBg;
$colorTabBodyFg: lighten($colorBodyFg, 20%);
$colorTabHeaderBg: lighten($colorBodyBg, 10%);
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
$colorTabHeaderBg: pullForward($colorBodyBg, 10%);
$colorTabHeaderFg: $colorBodyFg;
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: lighten($colorBodyBg, 5%);
$colorTabGroupHeaderFg: darken($colorTabHeaderFg, 10%);
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);
$colorTabGroupHeaderFg: pushBack($colorTabHeaderFg, 10%);
// Plot
$colorPlotBg: rgba(black, 0.05);
@ -284,22 +294,22 @@ $colorPlotHash: black;
$opacityPlotHash: 0.2;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: darken($colorPlotFg, 20%);
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
// Tree
$colorTreeBg: transparent;
$colorItemTreeHoverBg: lighten($colorBodyBg, 10%);
$colorItemTreeHoverFg: lighten($colorBodyFg, 20%);
$colorItemTreeHoverBg: pullForward($colorBodyBg, 10%);
$colorItemTreeHoverFg: pullForward($colorBodyFg, 20%);
$colorItemTreeIcon: $colorKey; // Used
$colorItemTreeIconHover: $colorItemTreeIcon; // Used
$colorItemTreeFg: $colorBodyFg;
$colorItemTreeSelectedBg: darken($colorKey, 15%);
$colorItemTreeSelectedBg: pushBack($colorKey, 15%);
$colorItemTreeSelectedFg: $colorItemTreeHoverFg;
$colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
$colorItemTreeEditingBg: darken($editColor, 20%);
$colorItemTreeEditingFg: $editColorFg;
$colorItemTreeEditingIcon: $editColorFg;
$colorItemTreeEditingBg: pushBack($editUIColor, 20%);
$colorItemTreeEditingFg: $editUIColor;
$colorItemTreeEditingIcon: $editUIColor;
$colorItemTreeVC: $colorDisclosureCtrl;
$colorItemTreeVCHover: $colorDisclosureCtrlHov;
$shdwItemTreeIcon: none;
@ -311,18 +321,18 @@ $colorThumbHoverBg: $colorItemTreeHoverBg;
$scrollbarTrackSize: 7px;
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
$scrollbarTrackColorBg: rgba(#000, 0.2);
$scrollbarThumbColor: darken($colorBodyBg, 50%);
$scrollbarThumbColor: pushBack($colorBodyBg, 50%);
$scrollbarThumbColorHov: $colorKey;
$scrollbarThumbColorMenu: lighten($colorMenuBg, 10%);
$scrollbarThumbColorMenuHov: lighten($scrollbarThumbColorMenu, 2%);
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 10%);
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
// Splitter
$splitterHandleD: 2px;
$splitterHandleHitMargin: 4px;
$colorSplitterBaseBg: $colorBodyBg;
$colorSplitterBg: lighten($colorSplitterBaseBg, 10%);
$colorSplitterBg: pullForward($colorBodyBg, 10%);
$colorSplitterFg: $colorBodyBg;
$colorSplitterHover: $colorKey;
$colorSplitterHover: $uiColor;
$colorSplitterActive: $colorKey;
$splitterBtnD: (16px, 35px); // height, width
$splitterBtnColorBg: $colorBtnBg;
@ -334,7 +344,7 @@ $splitterCollapsedBtnColorBgHov: $colorKey;
$splitterCollapsedBtnColorFgHov: $colorKeyFg;
// Mobile
$colorMobilePaneLeft: darken($colorBodyBg, 2%);
$colorMobilePaneLeft: pushBack($colorBodyBg, 2%);
$colorMobilePaneLeftTreeItemBg: rgba($colorBodyFg, 0.1);
$colorMobilePaneLeftTreeItemFg: $colorItemTreeFg;
$colorMobileSelectListTreeItemBg: rgba(#000, 0.05);
@ -371,10 +381,14 @@ $createBtnTextTransform: uppercase;
}
@mixin themedButton($c: $colorBtnBg) {
background: linear-gradient(lighten($c, 5%), $c);
background: linear-gradient(pullForward($c, 5%), $c);
box-shadow: rgba(black, 0.5) 0 0.5px 2px;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect(linear-gradient(lighten($bg, 5%), $bg), $fg, lighten($bg, 20%), rgba(black, 0.5) 0 0.5px 3px);
}
/**************************************************** OVERRIDES */
.c-frame {
&:not(.no-frame) {

View File

@ -47,6 +47,14 @@ $bodyFont: $heroFont;
@return $c;
}
@function pullForward($val, $amt) {
@return darken($val, $amt);
}
@function pushBack($val, $amt) {
@return lighten($val, $amt);
}
// Constants
$fontBaseSize: 12px;
$smallCr: 2px;
@ -69,6 +77,7 @@ $colorKeyHov: #00c0f6;
$colorKeyFilter: invert(37%) sepia(100%) saturate(686%) hue-rotate(157deg) brightness(102%) contrast(102%);
$colorKeyFilterHov: invert(69%) sepia(87%) saturate(3243%) hue-rotate(151deg) brightness(97%) contrast(102%);
$colorKeySelectedBg: $colorKey;
$uiColor: #289fec; // Resize bars, splitter bars, etc.
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
$colorA: #999;
$colorAHov: $colorKey;
@ -94,51 +103,52 @@ $colorPausedFg: #fff;
$colorOk: #33cc33;
// Base variations
$colorBodyBgSubtle: darken($colorBodyBg, 5%);
$colorBodyBgSubtleHov: lighten($colorKey, 50%);
$colorKeySubtle: lighten($colorKey, 50%);
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
$colorKeySubtle: pushBack($colorKey, 10%);
// Time Colors
$colorTime: #618cff;
$colorTimeBg: $colorTime;
$colorTimeFg: $colorBodyBg;
$colorTimeHov: lighten($colorTime, 5%);
$colorTimeSubtle: lighten($colorTime, 20%);
$colorTimeHov: pushBack($colorTime, 5%);
$colorTimeSubtle: pushBack($colorTime, 20%);
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
/************************************************** EDITING */
// Base Colors
$dlSpread: 20%;
$editColor: #00c7c3;
$editColorAlt: #9971ff;
$editColorBgBase: darken($editColor, $dlSpread);
$editColorBg: darken($editColor, $dlSpread);
$editColorFg: lighten($editColor, $dlSpread);
$editColorHov: lighten($editColor, 20%);
// Canvas
$editCanvasColorBg: #e6ffff;
$editCanvasColorGrid: darken($editCanvasColorBg, 10%);
// Selectable
$editSelectableColor: #acdad6;
$editSelectableColorFg: darken($editSelectableColor, 20%);
$editSelectableColorHov: darken($editSelectableColor, 10%);
// Selectable selected
$editSelectableColorSelected: $editColor;
$editSelectableColorSelectedFg: lighten($editSelectableColorSelected, 50%);
$editSelectableColorFg: darken($editSelectableColor, 40%);
$editSelectableBorder: 1px dotted $editSelectableColor;
$editSelectableBorderHov: 1px dotted $editColorAlt;
$editSelectableBorderSelected: 1px solid $editColor;
$editSelectableShdwSelected: rgba($editColor, 0.75) 0 0 0 1px;
$editMoveableSelectedShdw: rgba($editColor, 0.5) 0 0 10px;
$editBorderDrilledIn: 1px dashed $editColorAlt;
$colorGridLines: rgba($editColor, 0.2);
/************************************************** BROWSING */
$browseSelectableBorderHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseSelectableShdwHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.6);
$browseFrameColor: pullForward($colorBodyBg, 10%);
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
/************************************************** EDITING */
$editUIColor: $uiColor; // Base color
$editUIColorHov: pullForward(saturate($uiColor, 10%), 20%); // Hover color when $editUIColor is applied as a base color
$editUIBaseColor: #cae1ff; // Base color, toolbar bg
$editUIBaseColorHov: pushBack($editUIBaseColor, 20%);
$editUIBaseColorFg: #4c4c4c; // Toolbar button icon colors, etc.
$editUIAreaBaseColor: pullForward(saturate($editUIBaseColor, 30%), 20%);
$editUIAreaShdw: $editUIAreaBaseColor 0 0 0 2px; // Edit area s-selected-parent
$editUIAreaShdwSelected: $editUIAreaBaseColor 0 0 0 3px; // Edit area s-selected
$editUIGridColorBg: rgba($editUIBaseColor, 0.2); // Background of layout editing area
$editUIGridColorFg: rgba($editUIBaseColor, 0.3); // Grid lines in layout editing area
$editFrameColor: $browseFrameColor; // Solid or dotted border applied to non-selected frames in a layout; move-bar on frame hover
$editFrameBorder: 1px dotted $editFrameColor;
$editFrameColorHov: $editUIColor; // Solid border hover on frames; hover should not be applied to selected objects
$editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
$editFrameColorSelected: #333; // Border of selected frames
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
$editFrameSelectedShdw: rgba(black, 0.5) 0 1px 10px 1px;
$editFrameSelectedBorder: 1px dashed $editFrameColorSelected; // Selected frame element
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
$editFrameHovMovebarColorFg: pullForward($editFrameMovebarColorFg, 10%);
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
$editFrameMovebarH: 10px; // Height of move bar in layout frame
// Icons
$colorIconAlias: #4af6f3;
@ -149,7 +159,7 @@ $colorTabsHolderBg: rgba($colorBodyFg, 0.2);
// Buttons and Controls
$colorBtnBg: #aaa;
$colorBtnBgHov: darken($colorBtnBg, 10%);
$colorBtnBgHov: pullForward($colorBtnBg, 10%);
$colorBtnFg: #fff;
$colorBtnReverseFg: $colorBodyBg;
$colorBtnReverseBg: $colorBodyFg;
@ -157,7 +167,7 @@ $colorBtnFgHov: $colorBtnFg;
$colorBtnMajorBg: $colorKey;
$colorBtnMajorBgHov: $colorKeyHov;
$colorBtnMajorFg: $colorKeyFg;
$colorBtnMajorFgHov: lighten($colorBtnMajorFg, 10%);
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%);
$colorBtnCautionBg: #f16f6f;
$colorBtnCautionBgHov: #f1504e;
$colorBtnCautionFg: $colorBtnFg;
@ -165,15 +175,15 @@ $colorClickIcon: $colorKey;
$colorClickIconBgHov: rgba($colorKey, 0.2);
$colorClickIconFgHov: $colorKeyHov;
$colorDropHint: $colorKey;
$colorDropHintBg: lighten($colorDropHint, 30%);
$colorDropHintBgHov: lighten($colorDropHint, 40%);
$colorDropHintFg: lighten($colorDropHint, 0);
$colorDropHintBg: pushBack($colorDropHint, 10%);
$colorDropHintBgHov: pushBack($colorDropHint, 40%);
$colorDropHintFg: pushBack($colorDropHint, 0);
$colorDisclosureCtrl: rgba($colorBodyFg, 0.5);
$colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7);
// Menus
$colorMenuBg: lighten($colorBodyBg, 10%);
$colorMenuFg: darken($colorMenuBg, 70%);
$colorMenuBg: pushBack($colorBodyBg, 10%);
$colorMenuFg: pullForward($colorMenuBg, 70%);
$colorMenuIc: $colorKey;
$colorMenuHovBg: $colorMenuIc;
$colorMenuHovFg: $colorMenuBg;
@ -200,27 +210,27 @@ $colorFormLines: rgba(#000, 0.1);
$colorFormSectionHeader: rgba(#000, 0.05);
$colorInputBg: $colorGenBg;
$colorInputFg: $colorBodyFg;
$colorInputPlaceholder: lighten($colorBodyFg, 20%);
$colorFormText: lighten($colorBodyFg, 10%);
$colorInputIcon: lighten($colorBodyFg, 25%);
$colorFieldHint: darken($colorBodyFg, 40%);
$colorInputPlaceholder: pushBack($colorBodyFg, 20%);
$colorFormText: pushBack($colorBodyFg, 10%);
$colorInputIcon: pushBack($colorBodyFg, 25%);
$colorFieldHint: pullForward($colorBodyFg, 40%);
$shdwInput: inset rgba(black, 0.7) 0 0 1px;
$shdwInputHov: inset rgba(black, 0.7) 0 0 2px;
$shdwInputFoc: inset rgba(black, 0.8) 0 0.25px 3px;
// Inspector
$colorInspectorBg: darken($colorBodyBg, 5%);
$colorInspectorBg: pullForward($colorBodyBg, 5%);
$colorInspectorFg: $colorBodyFg;
$colorInspectorPropName: lighten($colorBodyFg, 20%);
$colorInspectorPropVal: darken($colorInspectorFg, 15%);
$colorInspectorSectionHeaderBg: darken($colorInspectorBg, 5%);
$colorInspectorSectionHeaderFg: darken($colorInspectorBg, 40%);
$colorInspectorPropName: pushBack($colorBodyFg, 20%);
$colorInspectorPropVal: pullForward($colorInspectorFg, 15%);
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
// Overlay
$overlayColorBg: $colorMenuBg;
$overlayColorFg: $colorMenuFg;
$overlayCr: $interiorMarginLg;
$overlayBrightnessAdjust: brightness(1);
$overlayBrightnessAdjust: brightness(1.3);
// Indicator colors
$colorIndicatorAvailable: $colorKey;
@ -229,8 +239,8 @@ $colorIndicatorOn: $colorOk;
$colorIndicatorOff: #666;
// Staleness
$colorTelemFresh: darken($colorBodyFg, 20%);
$colorTelemStale: lighten($colorBodyFg, 20%);
$colorTelemFresh: pullForward($colorBodyFg, 20%);
$colorTelemStale: pushBack($colorBodyFg, 20%);
$styleTelemStale: italic;
// Limits
@ -255,23 +265,23 @@ $colorInfoBubbleBg: $colorMenuBg;
$colorInfoBubbleFg: #666;
// Items
$colorItemBg: lighten($colorBtnBg, 20%);
$colorItemBgHov: lighten($colorItemBg, 5%);
$colorItemBg: pushBack($colorBtnBg, 20%);
$colorItemBgHov: pushBack($colorItemBg, 5%);
$colorListItemBg: transparent;
$colorListItemBgHov: rgba($colorKey, 0.1);
$colorItemFg: $colorBodyFg;
$colorItemFgDetails: lighten($colorItemFg, 15%);
$colorItemFgDetails: pushBack($colorItemFg, 15%);
$shdwItemText: none;
// Tabular
$colorTabBorder: darken($colorBodyBg, 10%);
$colorTabBorder: pullForward($colorBodyBg, 10%);
$colorTabBodyBg: $colorBodyBg;
$colorTabBodyFg: darken($colorBodyFg, 20%);
$colorTabHeaderBg: darken($colorBodyBg, 10%);
$colorTabHeaderFg: darken($colorBodyFg, 20%);
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
$colorTabHeaderBg: pullForward($colorBodyBg, 10%);
$colorTabHeaderFg: pullForward($colorBodyFg, 20%);
$colorTabHeaderBorder: $colorBodyBg;
$colorTabGroupHeaderBg: darken($colorBodyBg, 5%);
$colorTabGroupHeaderFg: darken($colorTabGroupHeaderBg, 40%);
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);
$colorTabGroupHeaderFg: pullForward($colorTabGroupHeaderBg, 40%);
// Plot
$colorPlotBg: rgba(black, 0.05);
@ -280,22 +290,22 @@ $colorPlotHash: black;
$opacityPlotHash: 0.2;
$stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: lighten($colorPlotFg, 20%);
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
// Tree
$colorTreeBg: transparent;
$colorItemTreeHoverBg: darken($colorBodyBg, 10%);
$colorItemTreeHoverFg: darken($colorBodyFg, 10%);
$colorItemTreeHoverBg: pullForward($colorBodyBg, 10%);
$colorItemTreeHoverFg: pullForward($colorBodyFg, 10%);
$colorItemTreeIcon: $colorKey; // Used
$colorItemTreeIconHover: $colorItemTreeIcon; // Used
$colorItemTreeFg: $colorBodyFg;
$colorItemTreeSelectedBg: lighten($colorKey, 15%);
$colorItemTreeSelectedBg: pushBack($colorKey, 15%);
$colorItemTreeSelectedFg: $colorBodyBg;
$colorItemTreeSelectedIcon: $colorItemTreeSelectedFg;
$colorItemTreeEditingBg: $editColor;
$colorItemTreeEditingFg: $editColorFg;
$colorItemTreeEditingIcon: $editColorFg;
$colorItemTreeEditingBg: pushBack($editUIColor, 20%);
$colorItemTreeEditingFg: $editUIColor;
$colorItemTreeEditingIcon: $editUIColor;
$colorItemTreeVC: $colorDisclosureCtrl;
$colorItemTreeVCHover: $colorDisclosureCtrlHov;
$shdwItemTreeIcon: none;
@ -307,16 +317,16 @@ $colorThumbHoverBg: $colorItemTreeHoverBg;
$scrollbarTrackSize: 7px;
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
$scrollbarTrackColorBg: rgba(#000, 0.2);
$scrollbarThumbColor: darken($colorBodyBg, 50%);
$scrollbarThumbColor: pullForward($colorBodyBg, 50%);
$scrollbarThumbColorHov: $colorKey;
$scrollbarThumbColorMenu: darken($colorMenuBg, 10%);
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 10%);
$scrollbarThumbColorMenuHov: darken($scrollbarThumbColorMenu, 2%);
// Splitter
$splitterHandleD: 2px;
$splitterHandleHitMargin: 4px;
$colorSplitterBaseBg: $colorBodyBg;
$colorSplitterBg: darken($colorSplitterBaseBg, 20%);
$colorSplitterBg: pullForward($colorSplitterBaseBg, 20%);
$colorSplitterFg: $colorBodyBg;
$colorSplitterHover: $colorKey;
$colorSplitterActive: $colorKey;
@ -330,7 +340,7 @@ $splitterCollapsedBtnColorBgHov: $colorKey;
$splitterCollapsedBtnColorFgHov: $colorKeyFg;
// Mobile
$colorMobilePaneLeft: darken($colorBodyBg, 2%);
$colorMobilePaneLeft: pullForward($colorBodyBg, 2%);
$colorMobilePaneLeftTreeItemBg: rgba($colorBodyFg, 0.1);
$colorMobilePaneLeftTreeItemFg: $colorItemTreeFg;
$colorMobileSelectListTreeItemBg: rgba(#000, 0.05);
@ -370,16 +380,6 @@ $createBtnTextTransform: uppercase;
background: $c;
}
/**************************************************** NOT USED, LEAVE FOR NOW */
// Content status
/*
$colorAlert: #ff3c00;
$colorWarningHi: #990000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
$colorCommand: #3693bd;
$colorInfo: #2294a2;
$colorOk: #33cc33;
*/
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect($bg, $fg, lighten($bg, 20%), none);
}

View File

@ -228,6 +228,17 @@ input[type=number]::-webkit-outer-spin-button {
}
}
// SELECTS
select {
@include appearanceNone();
@include themedSelect();
background-repeat: no-repeat, no-repeat;
background-position: right .4em top 80%, 0 0;
border: none;
border-radius: $controlCr;
padding: 1px 20px 1px $interiorMargin;
}
/******************************************************** HYPERLINKS AND HYPERLINK BUTTONS */
.c-hyperlink {
&--link {
@ -411,7 +422,7 @@ input[type=number]::-webkit-outer-spin-button {
}
@mixin cToolbarSeparator() {
$m: $interiorMargin;
$m: 1px;
$b: 1px;
display: block;
width: $m + $b; // Allow for border
@ -421,21 +432,35 @@ input[type=number]::-webkit-outer-spin-button {
.c-toolbar {
$p: $interiorMargin;
border-top: 1px solid $colorInteriorBorder;
background: $editUIBaseColor;
border-radius: $basicCr;
height: $p + 24px; // Need to standardize the height
padding-top: $p;
padding: $p;
> * + * {
margin-left: 2px;
}
&__separator {
@include cToolbarSeparator();
}
.c-click-icon,
.c-labeled-input {
color: $editUIBaseColorFg;
}
.c-click-icon {
@include cControl();
$pLR: $interiorMargin - 1;
$pTB: 2px;
color: $colorBodyFg;
padding: $pTB $pLR;
&:hover {
background: $editUIBaseColorHov !important;
color: $editUIBaseColorFg !important;
}
&--swatched {
padding-bottom: floor($pTB / 2);
width: 2em; // Standardize the width

View File

@ -191,8 +191,8 @@ body.desktop .has-local-controls {
.c-grid {
pointer-events: none;
&__x { @include bgTicks($editCanvasColorGrid, 'x'); }
&__y { @include bgTicks($editCanvasColorGrid, 'y'); }
&__x { @include bgTicks($editUIGridColorFg, 'x'); }
&__y { @include bgTicks($editUIGridColorFg, 'y'); }
}
/*************************** SELECTION */
@ -200,32 +200,14 @@ body.desktop .has-local-controls {
&:hover {
box-shadow: $browseSelectableShdwHov;
}
&[s-selected] {
border: $browseSelectedBorder;
}
}
/**************************** EDITING */
.is-editing {
*:not(.is-drilled-in).c-frame {
border: $editSelectableBorder;
&:not([s-selected]) {
&:hover {
border: $editSelectableBorderHov;
}
}
&[s-selected] {
box-shadow: $editSelectableShdwSelected;
> .c-frame-edit {
display: block; // Show the editing rect and handles
}
}
}
*.is-drilled-in {
border: $editBorderDrilledIn;
}
.is-moveable {
cursor: move;
}
@ -234,116 +216,8 @@ body.desktop .has-local-controls {
// Applied in markup to objects that provide links. Disable while editing.
pointer-events: none;
}
.c-frame-edit {
// In Layouts, this is the editing rect and handles
// In Fixed Position, this is a wrapper element
$z: 10;
@include abs();
display: none;
&__move {
@include abs();
box-shadow: $editMoveableSelectedShdw;
cursor: move;
z-index: $z;
}
&__handle {
$d: 8px;
$o: floor($d * -0.5);
background: rgba($editColor, 0.3);
border: 1px solid $editColor;
position: absolute;
width: $d; height: $d;
top: auto; right: auto; bottom: auto; left: auto;
z-index: $z + 1;
&:before {
// Extended hit area
$m: -5px;
content: '';
display: block;
position: absolute;
top: $m; right: $m; bottom: $m; left: $m;
z-index: -1;
}
&:hover {
background: $editColor;
}
&--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;
}
}
}
// TODO: move this into DisplayLayout and Fixed Position vue files respectively
.l-shell__main-container > .l-layout,
.l-shell__main-container > .c-object-view .l-fixed-position {
// Target the top-most layout container and color its background
background: $editCanvasColorBg;
}
.l-shell__main-container {
box-shadow: $colorBodyBg 0 0 0 1px, rgba($editColor, 0.7) 0 0 0 2px;
&[s-selected] {
// Provide a clearer selection context articulation
box-shadow: $colorBodyBg 0 0 0 1px, $editColor 0 0 0px 3px;
}
}
// Layouts
[s-selected],
[s-selected-parent] {
.l-layout {
// Show the layout grid for the top-most child of the current selection,
// and hide the grid for deeper nested levels.
[class*="__grid-holder"] {
display: block;
}
.l-layout [class*="__grid-holder"] {
display: none;
}
}
}
// Fixed position
.l-fixed-position {
&__grid-holder {
display: block;
}
.c-frame-edit {
display: block;
}
}
}
/************************** LEGACY */
mct-container {

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