mirror of
https://github.com/nasa/openmct.git
synced 2025-06-29 20:23:04 +00:00
Compare commits
15 Commits
vue-conduc
...
context-me
Author | SHA1 | Date | |
---|---|---|---|
485e948abe | |||
64b9d4c24a | |||
88bcb6078e | |||
5f9f3cd8e8 | |||
814b404614 | |||
ba2bb2180b | |||
72cdb352f0 | |||
cedf942c0c | |||
27506a3757 | |||
acc4e03c88 | |||
9a6090cd02 | |||
f40c9fa6f9 | |||
e7cdb334de | |||
afca6cd2e9 | |||
3c324cbea0 |
@ -26,12 +26,16 @@ define([
|
|||||||
"./src/NotificationLaunchController",
|
"./src/NotificationLaunchController",
|
||||||
"./src/DialogLaunchIndicator",
|
"./src/DialogLaunchIndicator",
|
||||||
"./src/NotificationLaunchIndicator",
|
"./src/NotificationLaunchIndicator",
|
||||||
|
"./res/dialog-launch.html",
|
||||||
|
"./res/notification-launch.html",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
DialogLaunchController,
|
DialogLaunchController,
|
||||||
NotificationLaunchController,
|
NotificationLaunchController,
|
||||||
DialogLaunchIndicator,
|
DialogLaunchIndicator,
|
||||||
NotificationLaunchIndicator,
|
NotificationLaunchIndicator,
|
||||||
|
DialogLaunch,
|
||||||
|
NotificationLaunch,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
"use strict";
|
"use strict";
|
||||||
@ -41,11 +45,11 @@ define([
|
|||||||
"templates": [
|
"templates": [
|
||||||
{
|
{
|
||||||
"key": "dialogLaunchTemplate",
|
"key": "dialogLaunchTemplate",
|
||||||
"templateUrl": "dialog-launch.html"
|
"template": DialogLaunch
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "notificationLaunchTemplate",
|
"key": "notificationLaunchTemplate",
|
||||||
"templateUrl": "notification-launch.html"
|
"template": NotificationLaunch
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"controllers": [
|
"controllers": [
|
||||||
|
@ -51,76 +51,26 @@ define(
|
|||||||
return actionTexts[Math.floor(Math.random()*3)];
|
return actionTexts[Math.floor(Math.random()*3)];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExampleActions() {
|
|
||||||
var actions = [
|
|
||||||
{
|
|
||||||
label: "Try Again",
|
|
||||||
callback: function () {
|
|
||||||
$log.debug("Try Again pressed");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Remove",
|
|
||||||
callback: function () {
|
|
||||||
$log.debug("Remove pressed");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Cancel",
|
|
||||||
callback: function () {
|
|
||||||
$log.debug("Cancel pressed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// Randomly remove some actions off the top; leave at least one
|
|
||||||
actions.splice(0,Math.floor(Math.random() * actions.length));
|
|
||||||
|
|
||||||
return actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getExampleSeverity() {
|
|
||||||
var severities = [
|
|
||||||
"info",
|
|
||||||
"alert",
|
|
||||||
"error"
|
|
||||||
];
|
|
||||||
return severities[Math.floor(Math.random() * severities.length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch a new notification with a severity level of 'Error'.
|
* Launch a new notification with a severity level of 'Error'.
|
||||||
*/
|
*/
|
||||||
$scope.newError = function(){
|
$scope.newError = function () {
|
||||||
|
|
||||||
notificationService.notify({
|
notificationService.notify({
|
||||||
title: "Example error notification " + messageCounter++,
|
title: "Example error notification " + messageCounter++,
|
||||||
hint: "An error has occurred",
|
hint: "An error has occurred",
|
||||||
severity: "error",
|
severity: "error"
|
||||||
primaryOption: {
|
});
|
||||||
label: 'Retry',
|
|
||||||
callback: function() {
|
|
||||||
$log.info('Retry clicked');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options: getExampleActions()});
|
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Launch a new notification with a severity of 'Alert'.
|
* Launch a new notification with a severity of 'Alert'.
|
||||||
*/
|
*/
|
||||||
$scope.newAlert = function(){
|
$scope.newAlert = function () {
|
||||||
|
|
||||||
notificationService.notify({
|
notificationService.notify({
|
||||||
title: "Alert notification " + (messageCounter++),
|
title: "Alert notification " + (messageCounter++),
|
||||||
hint: "This is an alert message",
|
hint: "This is an alert message",
|
||||||
severity: "alert",
|
severity: "alert",
|
||||||
primaryOption: {
|
autoDismiss: true
|
||||||
label: 'Retry',
|
});
|
||||||
callback: function() {
|
|
||||||
$log.info('Retry clicked');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options: getExampleActions()});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -128,39 +78,38 @@ define(
|
|||||||
* Launch a new notification with a progress bar that is updated
|
* Launch a new notification with a progress bar that is updated
|
||||||
* periodically, tracking an ongoing process.
|
* periodically, tracking an ongoing process.
|
||||||
*/
|
*/
|
||||||
$scope.newProgress = function(){
|
$scope.newProgress = function () {
|
||||||
|
|
||||||
var notificationModel = {
|
var notificationModel = {
|
||||||
title: "Progress notification example",
|
title: "Progress notification example",
|
||||||
severity: "info",
|
severity: "info",
|
||||||
progress: 0,
|
progress: 0,
|
||||||
actionText: getExampleActionText(),
|
actionText: getExampleActionText()
|
||||||
unknownProgress: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulate an ongoing process and update the progress bar.
|
* Simulate an ongoing process and update the progress bar.
|
||||||
* @param notification
|
* @param notification
|
||||||
*/
|
*/
|
||||||
function incrementProgress(notificationModel) {
|
function incrementProgress() {
|
||||||
notificationModel.progress = Math.min(100, Math.floor(notificationModel.progress + Math.random() * 30));
|
notificationModel.progress = Math.min(100, Math.floor(notificationModel.progress + Math.random() * 30));
|
||||||
notificationModel.progressText = ["Estimated time" +
|
notificationModel.progressText = ["Estimated time" +
|
||||||
" remaining:" +
|
" remaining:" +
|
||||||
" about ", 60 - Math.floor((notificationModel.progress / 100) * 60), " seconds"].join(" ");
|
" about ", 60 - Math.floor((notificationModel.progress / 100) * 60), " seconds"].join(" ");
|
||||||
if (notificationModel.progress < 100) {
|
if (notificationModel.progress < 100) {
|
||||||
$timeout(function(){incrementProgress(notificationModel);}, 1000);
|
$timeout(function () {
|
||||||
|
incrementProgress(notificationModel);
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationService.notify(notificationModel);
|
notificationService.notify(notificationModel);
|
||||||
incrementProgress(notificationModel);
|
incrementProgress();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch a new notification with severity level of INFO.
|
* Launch a new notification with severity level of INFO.
|
||||||
*/
|
*/
|
||||||
$scope.newInfo = function(){
|
$scope.newInfo = function () {
|
||||||
|
|
||||||
notificationService.info({
|
notificationService.info({
|
||||||
title: "Example Info notification " + messageCounter++
|
title: "Example Info notification " + messageCounter++
|
||||||
});
|
});
|
||||||
|
@ -58,7 +58,7 @@ define([], function () {
|
|||||||
|
|
||||||
function checkNavigation() {
|
function checkNavigation() {
|
||||||
var navigatedObject = navigationService.getNavigation();
|
var navigatedObject = navigationService.getNavigation();
|
||||||
if (navigatedObject.hasCapability('context')) {
|
if (navigatedObject && navigatedObject.hasCapability('context')) {
|
||||||
if (!navigatedObject.getCapability('editor').isEditContextRoot()) {
|
if (!navigatedObject.getCapability('editor').isEditContextRoot()) {
|
||||||
preventOrphanNavigation(navigatedObject);
|
preventOrphanNavigation(navigatedObject);
|
||||||
}
|
}
|
||||||
|
@ -405,7 +405,8 @@ define([
|
|||||||
"description": "Provides transactional editing capabilities",
|
"description": "Provides transactional editing capabilities",
|
||||||
"implementation": EditorCapability,
|
"implementation": EditorCapability,
|
||||||
"depends": [
|
"depends": [
|
||||||
"transactionService"
|
"transactionService",
|
||||||
|
"openmct"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -36,9 +36,11 @@ define(
|
|||||||
*/
|
*/
|
||||||
function EditorCapability(
|
function EditorCapability(
|
||||||
transactionService,
|
transactionService,
|
||||||
|
openmct,
|
||||||
domainObject
|
domainObject
|
||||||
) {
|
) {
|
||||||
this.transactionService = transactionService;
|
this.transactionService = transactionService;
|
||||||
|
this.openmct = openmct;
|
||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,27 +50,19 @@ define(
|
|||||||
* or finish() are called.
|
* or finish() are called.
|
||||||
*/
|
*/
|
||||||
EditorCapability.prototype.edit = function () {
|
EditorCapability.prototype.edit = function () {
|
||||||
this.transactionService.startTransaction();
|
console.warn('DEPRECATED: cannot edit via edit capability, use openmct.editor instead.');
|
||||||
|
this.openmct.editor.edit();
|
||||||
this.domainObject.getCapability('status').set('editing', true);
|
this.domainObject.getCapability('status').set('editing', true);
|
||||||
};
|
};
|
||||||
|
|
||||||
function isEditContextRoot(domainObject) {
|
|
||||||
return domainObject.getCapability('status').get('editing');
|
|
||||||
}
|
|
||||||
|
|
||||||
function isEditing(domainObject) {
|
|
||||||
return isEditContextRoot(domainObject) ||
|
|
||||||
domainObject.hasCapability('context') &&
|
|
||||||
isEditing(domainObject.getCapability('context').getParent());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether this object, or any of its ancestors are
|
* Determines whether this object, or any of its ancestors are
|
||||||
* currently being edited.
|
* currently being edited.
|
||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
EditorCapability.prototype.inEditContext = function () {
|
EditorCapability.prototype.inEditContext = function () {
|
||||||
return isEditing(this.domainObject);
|
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
|
||||||
|
return this.openmct.editor.isEditing();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,7 +71,8 @@ define(
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
EditorCapability.prototype.isEditContextRoot = function () {
|
EditorCapability.prototype.isEditContextRoot = function () {
|
||||||
return isEditContextRoot(this.domainObject);
|
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
|
||||||
|
return this.openmct.editor.isEditing();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,10 +81,7 @@ define(
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
EditorCapability.prototype.save = function () {
|
EditorCapability.prototype.save = function () {
|
||||||
var transactionService = this.transactionService;
|
console.warn('DEPRECATED: cannot save via edit capability, use openmct.editor instead.');
|
||||||
return transactionService.commit().then(function () {
|
|
||||||
transactionService.startTransaction();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
|
EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
|
||||||
@ -100,16 +92,7 @@ define(
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
EditorCapability.prototype.finish = function () {
|
EditorCapability.prototype.finish = function () {
|
||||||
var domainObject = this.domainObject;
|
console.warn('DEPRECATED: cannot finish via edit capability, use openmct.editor instead.');
|
||||||
|
|
||||||
if (this.transactionService.isActive()) {
|
|
||||||
return this.transactionService.cancel().then(function () {
|
|
||||||
domainObject.getCapability("status").set("editing", false);
|
|
||||||
return domainObject;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(domainObject);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,7 +60,7 @@ define(
|
|||||||
};
|
};
|
||||||
//If the notification is dismissed by the user, close
|
//If the notification is dismissed by the user, close
|
||||||
// the dialog.
|
// the dialog.
|
||||||
notification.onDismiss(function () {
|
notification.on('dismiss', function () {
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -23,33 +23,17 @@
|
|||||||
define([
|
define([
|
||||||
"./src/NotificationIndicatorController",
|
"./src/NotificationIndicatorController",
|
||||||
"./src/NotificationIndicator",
|
"./src/NotificationIndicator",
|
||||||
"./src/NotificationService",
|
|
||||||
"./res/notification-indicator.html",
|
"./res/notification-indicator.html",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
NotificationIndicatorController,
|
NotificationIndicatorController,
|
||||||
NotificationIndicator,
|
NotificationIndicator,
|
||||||
NotificationService,
|
|
||||||
notificationIndicatorTemplate,
|
notificationIndicatorTemplate,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
|
|
||||||
legacyRegistry.register("platform/commonUI/notification", {
|
legacyRegistry.register("platform/commonUI/notification", {
|
||||||
"extensions": {
|
"extensions": {
|
||||||
"constants": [
|
|
||||||
{
|
|
||||||
"key": "DEFAULT_AUTO_DISMISS",
|
|
||||||
"value": 3000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "FORCE_AUTO_DISMISS",
|
|
||||||
"value": 1000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "MINIMIZE_TIMEOUT",
|
|
||||||
"value": 300
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"templates": [
|
"templates": [
|
||||||
{
|
{
|
||||||
"key": "notificationIndicatorTemplate",
|
"key": "notificationIndicatorTemplate",
|
||||||
@ -76,12 +60,11 @@ define([
|
|||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"key": "notificationService",
|
"key": "notificationService",
|
||||||
"implementation": NotificationService,
|
"implementation": function (openmct) {
|
||||||
|
return openmct.notifications;
|
||||||
|
},
|
||||||
"depends": [
|
"depends": [
|
||||||
"$timeout",
|
"openmct"
|
||||||
"topic",
|
|
||||||
"DEFAULT_AUTO_DISMISS",
|
|
||||||
"MINIMIZE_TIMEOUT"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,437 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This bundle implements the notification service, which can be used to
|
|
||||||
* show banner notifications to the user. Banner notifications
|
|
||||||
* are used to inform users of events in a non-intrusive way. As
|
|
||||||
* much as possible, notifications share a model with blocking
|
|
||||||
* dialogs so that the same information can be provided in a dialog
|
|
||||||
* and then minimized to a banner notification if needed.
|
|
||||||
*
|
|
||||||
* @namespace platform/commonUI/notification
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
['moment'],
|
|
||||||
function (moment) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A representation of a user action. Options are provided to
|
|
||||||
* dialogs and notifications and are shown as buttons.
|
|
||||||
*
|
|
||||||
* @typedef {object} NotificationOption
|
|
||||||
* @property {string} label the label to appear on the button for
|
|
||||||
* this action
|
|
||||||
* @property {function} callback a callback function to be invoked
|
|
||||||
* when the button is clicked
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A representation of a banner notification. Banner notifications
|
|
||||||
* are used to inform users of events in a non-intrusive way. As
|
|
||||||
* much as possible, notifications share a model with blocking
|
|
||||||
* dialogs so that the same information can be provided in a dialog
|
|
||||||
* and then minimized to a banner notification if needed, or vice-versa.
|
|
||||||
*
|
|
||||||
* @typedef {object} NotificationModel
|
|
||||||
* @property {string} title The title of the message
|
|
||||||
* @property {string} severity The importance of the message (one of
|
|
||||||
* 'info', 'alert', or 'error' where info < alert <error)
|
|
||||||
* @property {number} [progress] The completion status of a task
|
|
||||||
* represented numerically
|
|
||||||
* @property {boolean} [unknownProgress] a boolean indicating that the
|
|
||||||
* progress of the underlying task is unknown. This will result in a
|
|
||||||
* visually distinct progress bar.
|
|
||||||
* @property {boolean} [autoDismiss] If truthy, dialog will
|
|
||||||
* be automatically minimized or dismissed (depending on severity).
|
|
||||||
* Additionally, if the provided value is a number, it will be used
|
|
||||||
* as the delay period before being dismissed.
|
|
||||||
* @property {boolean} [dismissable=true] If true, notification will
|
|
||||||
* include an option to dismiss it completely.
|
|
||||||
* @property {NotificationOption} [primaryOption] the default user
|
|
||||||
* response to
|
|
||||||
* this message. Will be represented as a button with the provided
|
|
||||||
* label and action. May be used by banner notifications to display
|
|
||||||
* only the most important option to users.
|
|
||||||
* @property {NotificationOption[]} [options] any additional
|
|
||||||
* actions the user can take. Will be represented as additional buttons
|
|
||||||
* that may or may not be available from a banner.
|
|
||||||
* @see DialogModel
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A wrapper object that is returned as a handle to a newly created
|
|
||||||
* notification. Wraps the notifications model and decorates with
|
|
||||||
* functions to dismiss or minimize the notification.
|
|
||||||
*
|
|
||||||
* @typedef {object} Notification
|
|
||||||
* @property {function} dismiss This method is added to the object
|
|
||||||
* returned by {@link NotificationService#notify} and can be used to
|
|
||||||
* dismiss this notification. Dismissing a notification will remove
|
|
||||||
* it completely and it will not appear in the notification indicator
|
|
||||||
* @property {function} minimize This method is added to the object
|
|
||||||
* returned by {@link NotificationService#notify} and can be used to
|
|
||||||
* minimize this notification. Minimizing a notification will send
|
|
||||||
* it to the notification indicator
|
|
||||||
* @property {function} dismissOrMinimize This method is added to the
|
|
||||||
* object returned by {@link NotificationService#notify}. It will
|
|
||||||
* hide the notification by either dismissing or minimizing it,
|
|
||||||
* depending on severity. Typically this is the method that should
|
|
||||||
* be used for dismissing a notification. If more control is
|
|
||||||
* required, then the minimize or dismiss functions can be called
|
|
||||||
* individually.
|
|
||||||
* @property {function} onDismiss Allows listening for on dismiss
|
|
||||||
* events. This allows cleanup etc. when the notification is dismissed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The notification service is responsible for informing the user of
|
|
||||||
* events via the use of banner notifications.
|
|
||||||
* @memberof platform/commonUI/notification
|
|
||||||
* @constructor
|
|
||||||
* @param $timeout the Angular $timeout service
|
|
||||||
* @param defaultAutoDismissTimeout The period of time that an
|
|
||||||
* auto-dismissed message will be displayed for.
|
|
||||||
* @param minimizeAnimationTimeout When notifications are minimized, a brief
|
|
||||||
* animation is shown. This animation requires some time to execute,
|
|
||||||
* so a timeout is required before the notification is hidden
|
|
||||||
*/
|
|
||||||
function NotificationService($timeout, topic, defaultAutoDismissTimeout, minimizeAnimationTimeout) {
|
|
||||||
this.notifications = [];
|
|
||||||
this.$timeout = $timeout;
|
|
||||||
this.highest = { severity: "info" };
|
|
||||||
this.AUTO_DISMISS_TIMEOUT = defaultAutoDismissTimeout;
|
|
||||||
this.MINIMIZE_ANIMATION_TIMEOUT = minimizeAnimationTimeout;
|
|
||||||
this.topic = topic;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A context in which to hold the active notification and a
|
|
||||||
* handle to its timeout.
|
|
||||||
*/
|
|
||||||
this.active = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimize a notification. The notification will still be available
|
|
||||||
* from the notification list. Typically notifications with a
|
|
||||||
* severity of 'info' should not be minimized, but rather
|
|
||||||
* dismissed. If you're not sure which is appropriate,
|
|
||||||
* use {@link Notification#dismissOrMinimize}
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.minimize = function (service, notification) {
|
|
||||||
//Check this is a known notification
|
|
||||||
var index = service.notifications.indexOf(notification);
|
|
||||||
|
|
||||||
if (service.active.timeout) {
|
|
||||||
/*
|
|
||||||
Method can be called manually (clicking dismiss) or
|
|
||||||
automatically from an auto-timeout. this.active.timeout
|
|
||||||
acts as a semaphore to prevent race conditions. Cancel any
|
|
||||||
timeout in progress (for the case where a manual dismiss
|
|
||||||
has shortcut an active auto-dismiss), and clear the
|
|
||||||
semaphore.
|
|
||||||
*/
|
|
||||||
service.$timeout.cancel(service.active.timeout);
|
|
||||||
delete service.active.timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= 0) {
|
|
||||||
notification.model.minimized = true;
|
|
||||||
//Add a brief timeout before showing the next notification
|
|
||||||
// in order to allow the minimize animation to run through.
|
|
||||||
service.$timeout(function () {
|
|
||||||
service.setActiveNotification(service.selectNextNotification());
|
|
||||||
}, service.MINIMIZE_ANIMATION_TIMEOUT);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Completely removes a notification. This will dismiss it from the
|
|
||||||
* message banner and remove it from the list of notifications.
|
|
||||||
* Typically only notifications with a severity of info should be
|
|
||||||
* dismissed. If you're not sure whether to dismiss or minimize a
|
|
||||||
* notification, use {@link Notification#dismissOrMinimize}.
|
|
||||||
* dismiss
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.dismiss = function (service, notification) {
|
|
||||||
//Check this is a known notification
|
|
||||||
var index = service.notifications.indexOf(notification);
|
|
||||||
|
|
||||||
if (service.active.timeout) {
|
|
||||||
/* Method can be called manually (clicking dismiss) or
|
|
||||||
* automatically from an auto-timeout. this.active.timeout
|
|
||||||
* acts as a semaphore to prevent race conditions. Cancel any
|
|
||||||
* timeout in progress (for the case where a manual dismiss
|
|
||||||
* has shortcut an active auto-dismiss), and clear the
|
|
||||||
* semaphore.
|
|
||||||
*/
|
|
||||||
|
|
||||||
service.$timeout.cancel(service.active.timeout);
|
|
||||||
delete service.active.timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= 0) {
|
|
||||||
service.notifications.splice(index, 1);
|
|
||||||
}
|
|
||||||
service.setActiveNotification(service.selectNextNotification());
|
|
||||||
|
|
||||||
this.setHighestSeverity();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Depending on the severity of the notification will selectively
|
|
||||||
* dismiss or minimize where appropriate.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.dismissOrMinimize = function (notification) {
|
|
||||||
var model = notification.model;
|
|
||||||
if (model.severity === "info") {
|
|
||||||
if (model.autoDismiss === false) {
|
|
||||||
notification.minimize();
|
|
||||||
} else {
|
|
||||||
notification.dismiss();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
notification.minimize();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the notification that is currently visible in the banner area
|
|
||||||
* @returns {Notification}
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.getActiveNotification = function () {
|
|
||||||
return this.active.notification;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A convenience method for info notifications. Notifications
|
|
||||||
* created via this method will be auto-dismissed after a default
|
|
||||||
* wait period unless explicitly forbidden by the caller through
|
|
||||||
* the {autoDismiss} property on the {NotificationModel}, in which
|
|
||||||
* case the notification will be minimized after the wait.
|
|
||||||
* @param {NotificationModel | string} message either a string for
|
|
||||||
* the title of the notification message, or a {@link NotificationModel}
|
|
||||||
* defining the options notification to display
|
|
||||||
* @returns {Notification} the provided notification decorated with
|
|
||||||
* functions to dismiss or minimize
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.info = function (message) {
|
|
||||||
var notificationModel = typeof message === "string" ? {title: message} : message;
|
|
||||||
notificationModel.severity = "info";
|
|
||||||
return this.notify(notificationModel);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A convenience method for alert notifications. Notifications
|
|
||||||
* created via this method will will have severity of "alert" enforced
|
|
||||||
* @param {NotificationModel | string} message either a string for
|
|
||||||
* the title of the alert message with default options, or a
|
|
||||||
* {@link NotificationModel} defining the options notification to
|
|
||||||
* display
|
|
||||||
* @returns {Notification} the provided notification decorated with
|
|
||||||
* functions to dismiss or minimize
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.alert = function (message) {
|
|
||||||
var notificationModel = typeof message === "string" ? {title: message} : message;
|
|
||||||
notificationModel.severity = "alert";
|
|
||||||
return this.notify(notificationModel);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A convenience method for error notifications. Notifications
|
|
||||||
* created via this method will will have severity of "error" enforced
|
|
||||||
* @param {NotificationModel | string} message either a string for
|
|
||||||
* the title of the error message with default options, or a
|
|
||||||
* {@link NotificationModel} defining the options notification to
|
|
||||||
* display
|
|
||||||
* @returns {Notification} the provided notification decorated with
|
|
||||||
* functions to dismiss or minimize
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.error = function (message) {
|
|
||||||
var notificationModel = typeof message === "string" ? {title: message} : message;
|
|
||||||
notificationModel.severity = "error";
|
|
||||||
return this.notify(notificationModel);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.setHighestSeverity = function () {
|
|
||||||
var severity = {
|
|
||||||
"info": 1,
|
|
||||||
"alert": 2,
|
|
||||||
"error": 3
|
|
||||||
};
|
|
||||||
this.highest.severity = this.notifications.reduce(function (previous, notification) {
|
|
||||||
if (severity[notification.model.severity] > severity[previous]) {
|
|
||||||
return notification.model.severity;
|
|
||||||
} else {
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
}, "info");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies the user of an event. If there is a banner notification
|
|
||||||
* already active, then it will be dismissed or minimized automatically,
|
|
||||||
* and the provided notification displayed in its place.
|
|
||||||
*
|
|
||||||
* @param {NotificationModel} notificationModel The notification to
|
|
||||||
* display
|
|
||||||
* @returns {Notification} the provided notification decorated with
|
|
||||||
* functions to {@link Notification#dismiss} or {@link Notification#minimize}
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.notify = function (notificationModel) {
|
|
||||||
var self = this,
|
|
||||||
notification,
|
|
||||||
activeNotification = self.active.notification,
|
|
||||||
topic = this.topic();
|
|
||||||
|
|
||||||
notificationModel.severity = notificationModel.severity || "info";
|
|
||||||
notificationModel.timestamp = moment.utc().format('YYYY-MM-DD hh:mm:ss.ms');
|
|
||||||
|
|
||||||
notification = {
|
|
||||||
model: notificationModel,
|
|
||||||
|
|
||||||
minimize: function () {
|
|
||||||
self.minimize(self, notification);
|
|
||||||
},
|
|
||||||
|
|
||||||
dismiss: function () {
|
|
||||||
self.dismiss(self, notification);
|
|
||||||
topic.notify();
|
|
||||||
},
|
|
||||||
|
|
||||||
dismissOrMinimize: function () {
|
|
||||||
self.dismissOrMinimize(notification);
|
|
||||||
},
|
|
||||||
|
|
||||||
onDismiss: function (callback) {
|
|
||||||
topic.listen(callback);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Notifications support a 'dismissable' attribute. This is a
|
|
||||||
// convenience to support adding a 'dismiss' option to the
|
|
||||||
// notification for the common case of dismissing a
|
|
||||||
// notification. Could also be done manually by specifying an
|
|
||||||
// option on the model
|
|
||||||
if (notificationModel.dismissable !== false) {
|
|
||||||
notificationModel.options = notificationModel.options || [];
|
|
||||||
notificationModel.options.unshift({
|
|
||||||
label: "Dismiss",
|
|
||||||
callback: function () {
|
|
||||||
notification.dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.notifications.push(notification);
|
|
||||||
|
|
||||||
this.setHighestSeverity();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Check if there is already an active (ie. visible) notification
|
|
||||||
*/
|
|
||||||
if (!this.active.notification) {
|
|
||||||
this.setActiveNotification(notification);
|
|
||||||
|
|
||||||
} else if (!this.active.timeout) {
|
|
||||||
/*
|
|
||||||
If there is already an active notification, time it out. If it's
|
|
||||||
already got a timeout in progress (either because it has had
|
|
||||||
timeout forced because of a queue of messages, or it had an
|
|
||||||
autodismiss specified), leave it to run. Otherwise force a
|
|
||||||
timeout.
|
|
||||||
|
|
||||||
This notification has been added to queue and will be
|
|
||||||
serviced as soon as possible.
|
|
||||||
*/
|
|
||||||
this.active.timeout = this.$timeout(function () {
|
|
||||||
activeNotification.dismissOrMinimize();
|
|
||||||
}, this.AUTO_DISMISS_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return notification;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used internally by the NotificationService
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.setActiveNotification = function (notification) {
|
|
||||||
var shouldAutoDismiss;
|
|
||||||
this.active.notification = notification;
|
|
||||||
|
|
||||||
if (!notification) {
|
|
||||||
delete this.active.timeout;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notification.model.severity === "info") {
|
|
||||||
shouldAutoDismiss = true;
|
|
||||||
} else {
|
|
||||||
shouldAutoDismiss = notification.model.autoDismiss;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldAutoDismiss || this.selectNextNotification()) {
|
|
||||||
this.active.timeout = this.$timeout(function () {
|
|
||||||
notification.dismissOrMinimize();
|
|
||||||
}, this.AUTO_DISMISS_TIMEOUT);
|
|
||||||
} else {
|
|
||||||
delete this.active.timeout;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used internally by the NotificationService
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
NotificationService.prototype.selectNextNotification = function () {
|
|
||||||
var notification,
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Loop through the notifications queue and find the first one that
|
|
||||||
has not already been minimized (manually or otherwise).
|
|
||||||
*/
|
|
||||||
for (; i < this.notifications.length; i++) {
|
|
||||||
notification = this.notifications[i];
|
|
||||||
|
|
||||||
if (!notification.model.minimized &&
|
|
||||||
notification !== this.active.notification) {
|
|
||||||
|
|
||||||
return notification;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return NotificationService;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,275 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
/*global describe,it,expect,beforeEach,jasmine*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['../src/NotificationService'],
|
|
||||||
function (NotificationService) {
|
|
||||||
|
|
||||||
describe("The notification service ", function () {
|
|
||||||
var notificationService,
|
|
||||||
mockTimeout,
|
|
||||||
mockAutoDismiss,
|
|
||||||
mockMinimizeTimeout,
|
|
||||||
mockTopicFunction,
|
|
||||||
mockTopicObject,
|
|
||||||
infoModel,
|
|
||||||
alertModel,
|
|
||||||
errorModel;
|
|
||||||
|
|
||||||
function elapseTimeout() {
|
|
||||||
mockTimeout.calls.mostRecent().args[0]();
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockTimeout = jasmine.createSpy("$timeout");
|
|
||||||
mockTopicFunction = jasmine.createSpy("topic");
|
|
||||||
mockTopicObject = jasmine.createSpyObj("topicObject", ["listen", "notify"]);
|
|
||||||
mockTopicFunction.and.returnValue(mockTopicObject);
|
|
||||||
|
|
||||||
mockAutoDismiss = mockMinimizeTimeout = 1000;
|
|
||||||
notificationService = new NotificationService(mockTimeout, mockTopicFunction, mockAutoDismiss, mockMinimizeTimeout);
|
|
||||||
|
|
||||||
infoModel = {
|
|
||||||
title: "Mock Info Notification",
|
|
||||||
severity: "info"
|
|
||||||
};
|
|
||||||
|
|
||||||
alertModel = {
|
|
||||||
title: "Mock Alert Notification",
|
|
||||||
severity: "alert"
|
|
||||||
};
|
|
||||||
|
|
||||||
errorModel = {
|
|
||||||
title: "Mock Error Notification",
|
|
||||||
severity: "error"
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("notifies listeners on dismissal of notification", function () {
|
|
||||||
var dismissListener = jasmine.createSpy("ondismiss");
|
|
||||||
var notification = notificationService.notify(infoModel);
|
|
||||||
notification.onDismiss(dismissListener);
|
|
||||||
expect(mockTopicObject.listen).toHaveBeenCalled();
|
|
||||||
notification.dismiss();
|
|
||||||
expect(mockTopicObject.notify).toHaveBeenCalled();
|
|
||||||
mockTopicObject.listen.calls.mostRecent().args[0]();
|
|
||||||
expect(dismissListener).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("dismisses a notification when the notification's dismiss method is used", function () {
|
|
||||||
var notification = notificationService.info(infoModel);
|
|
||||||
notification.dismiss();
|
|
||||||
expect(notificationService.getActiveNotification()).toBeUndefined();
|
|
||||||
expect(notificationService.notifications.length).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("minimizes a notification when the notification's minimize method is used", function () {
|
|
||||||
var notification = notificationService.info(infoModel);
|
|
||||||
notification.minimize();
|
|
||||||
elapseTimeout(); // needed for the minimize animation timeout
|
|
||||||
expect(notificationService.getActiveNotification()).toBeUndefined();
|
|
||||||
expect(notificationService.notifications.length).toEqual(1);
|
|
||||||
expect(notificationService.notifications[0]).toEqual(notification);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when receiving info notifications", function () {
|
|
||||||
it("minimizes info notifications if the caller disables auto-dismiss", function () {
|
|
||||||
infoModel.autoDismiss = false;
|
|
||||||
var notification = notificationService.info(infoModel);
|
|
||||||
elapseTimeout();
|
|
||||||
// 2nd elapse for the minimize animation timeout
|
|
||||||
elapseTimeout();
|
|
||||||
expect(notificationService.getActiveNotification()).toBeUndefined();
|
|
||||||
expect(notificationService.notifications.length).toEqual(1);
|
|
||||||
expect(notificationService.notifications[0]).toEqual(notification);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("dismisses info notifications if the caller ignores auto-dismiss", function () {
|
|
||||||
notificationService.info(infoModel);
|
|
||||||
elapseTimeout();
|
|
||||||
expect(notificationService.getActiveNotification()).toBeUndefined();
|
|
||||||
expect(notificationService.notifications.length).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("dismisses info notifications if the caller requests auto-dismiss", function () {
|
|
||||||
infoModel.autoDismiss = true;
|
|
||||||
notificationService.info(infoModel);
|
|
||||||
elapseTimeout();
|
|
||||||
expect(notificationService.getActiveNotification()).toBeUndefined();
|
|
||||||
expect(notificationService.notifications.length).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when receiving alert notifications", function () {
|
|
||||||
it("minimizes alert notifications if the caller enables auto-dismiss", function () {
|
|
||||||
alertModel.autoDismiss = true;
|
|
||||||
var notification = notificationService.alert(alertModel);
|
|
||||||
elapseTimeout();
|
|
||||||
elapseTimeout();
|
|
||||||
expect(notificationService.getActiveNotification()).toBeUndefined();
|
|
||||||
expect(notificationService.notifications.length).toEqual(1);
|
|
||||||
expect(notificationService.notifications[0]).toEqual(notification);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps alert notifications active if the caller disables auto-dismiss", function () {
|
|
||||||
mockTimeout.and.callFake(function (callback, time) {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
alertModel.autoDismiss = false;
|
|
||||||
var notification = notificationService.alert(alertModel);
|
|
||||||
expect(notificationService.getActiveNotification()).toEqual(notification);
|
|
||||||
expect(notificationService.notifications.length).toEqual(1);
|
|
||||||
expect(notificationService.notifications[0]).toEqual(notification);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps alert notifications active if the caller ignores auto-dismiss", function () {
|
|
||||||
mockTimeout.and.callFake(function (callback, time) {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
var notification = notificationService.alert(alertModel);
|
|
||||||
expect(notificationService.getActiveNotification()).toEqual(notification);
|
|
||||||
expect(notificationService.notifications.length).toEqual(1);
|
|
||||||
expect(notificationService.notifications[0]).toEqual(notification);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when receiving error notifications", function () {
|
|
||||||
it("minimizes error notifications if the caller enables auto-dismiss", function () {
|
|
||||||
errorModel.autoDismiss = true;
|
|
||||||
var notification = notificationService.error(errorModel);
|
|
||||||
elapseTimeout();
|
|
||||||
elapseTimeout();
|
|
||||||
expect(notificationService.getActiveNotification()).toBeUndefined();
|
|
||||||
expect(notificationService.notifications.length).toEqual(1);
|
|
||||||
expect(notificationService.notifications[0]).toEqual(notification);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps error notifications active if the caller disables auto-dismiss", function () {
|
|
||||||
mockTimeout.and.callFake(function (callback, time) {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
errorModel.autoDismiss = false;
|
|
||||||
var notification = notificationService.error(errorModel);
|
|
||||||
expect(notificationService.getActiveNotification()).toEqual(notification);
|
|
||||||
expect(notificationService.notifications.length).toEqual(1);
|
|
||||||
expect(notificationService.notifications[0]).toEqual(notification);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps error notifications active if the caller ignores auto-dismiss", function () {
|
|
||||||
mockTimeout.and.callFake(function (callback, time) {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
var notification = notificationService.error(errorModel);
|
|
||||||
expect(notificationService.getActiveNotification()).toEqual(notification);
|
|
||||||
expect(notificationService.notifications.length).toEqual(1);
|
|
||||||
expect(notificationService.notifications[0]).toEqual(notification);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when called with multiple notifications", function () {
|
|
||||||
it("auto-dismisses the previously active notification, making the new notification active", function () {
|
|
||||||
var activeNotification;
|
|
||||||
infoModel.autoDismiss = false;
|
|
||||||
//First pre-load with a info message
|
|
||||||
notificationService.notify(infoModel);
|
|
||||||
activeNotification = notificationService.getActiveNotification();
|
|
||||||
//Initially expect the active notification to be info
|
|
||||||
expect(activeNotification.model).toBe(infoModel);
|
|
||||||
//Then notify of an error
|
|
||||||
notificationService.notify(errorModel);
|
|
||||||
//But it should be auto-dismissed and replaced with the
|
|
||||||
// error notification
|
|
||||||
elapseTimeout();
|
|
||||||
//Two timeouts, one is to force minimization after
|
|
||||||
// displaying the message for a minimum period, the
|
|
||||||
// second is to allow minimization animation to take place.
|
|
||||||
elapseTimeout();
|
|
||||||
activeNotification = notificationService.getActiveNotification();
|
|
||||||
expect(activeNotification.model).toBe(errorModel);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("auto-minimizes an active error notification", function () {
|
|
||||||
var activeNotification;
|
|
||||||
//First pre-load with an error message
|
|
||||||
notificationService.notify(errorModel);
|
|
||||||
//Then notify of info
|
|
||||||
notificationService.notify(infoModel);
|
|
||||||
expect(notificationService.notifications.length).toEqual(2);
|
|
||||||
//Mock the auto-minimize
|
|
||||||
elapseTimeout();
|
|
||||||
//Two timeouts, one is to force minimization after
|
|
||||||
// displaying the message for a minimum period, the
|
|
||||||
// second is to allow minimization animation to take place.
|
|
||||||
elapseTimeout();
|
|
||||||
//Previous error message should be minimized, not
|
|
||||||
// dismissed
|
|
||||||
expect(notificationService.notifications.length).toEqual(2);
|
|
||||||
activeNotification = notificationService.getActiveNotification();
|
|
||||||
expect(activeNotification.model).toBe(infoModel);
|
|
||||||
expect(errorModel.minimized).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("auto-minimizes errors when a number of them arrive in short succession", function () {
|
|
||||||
var activeNotification,
|
|
||||||
error2 = {
|
|
||||||
title: "Second Mock Error Notification",
|
|
||||||
severity: "error"
|
|
||||||
},
|
|
||||||
error3 = {
|
|
||||||
title: "Third Mock Error Notification",
|
|
||||||
severity: "error"
|
|
||||||
};
|
|
||||||
|
|
||||||
//First pre-load with a info message
|
|
||||||
notificationService.notify(errorModel);
|
|
||||||
//Then notify of a third error
|
|
||||||
notificationService.notify(error2);
|
|
||||||
notificationService.notify(error3);
|
|
||||||
expect(notificationService.notifications.length).toEqual(3);
|
|
||||||
//Mock the auto-minimize
|
|
||||||
elapseTimeout();
|
|
||||||
//Two timeouts, one is to force minimization after
|
|
||||||
// displaying the message for a minimum period, the
|
|
||||||
// second is to allow minimization animation to take place.
|
|
||||||
elapseTimeout();
|
|
||||||
//Previous error message should be minimized, not
|
|
||||||
// dismissed
|
|
||||||
expect(notificationService.notifications.length).toEqual(3);
|
|
||||||
activeNotification = notificationService.getActiveNotification();
|
|
||||||
expect(activeNotification.model).toBe(error2);
|
|
||||||
expect(errorModel.minimized).toEqual(true);
|
|
||||||
|
|
||||||
//Mock the second auto-minimize
|
|
||||||
elapseTimeout();
|
|
||||||
//Two timeouts, one is to force minimization after
|
|
||||||
// displaying the message for a minimum period, the
|
|
||||||
// second is to allow minimization animation to take place.
|
|
||||||
elapseTimeout();
|
|
||||||
activeNotification = notificationService.getActiveNotification();
|
|
||||||
expect(activeNotification.model).toBe(error3);
|
|
||||||
expect(error2.minimized).toEqual(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -19,10 +19,10 @@
|
|||||||
this source code distribution or the Licensing information page available
|
this source code distribution or the Licensing information page available
|
||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<a class="l-hyperlink s-hyperlink" ng-controller="HyperlinkController as hyperlink" href="{{domainObject.getModel().url}}"
|
<a class="c-hyperlink u-links" ng-controller="HyperlinkController as hyperlink" href="{{domainObject.getModel().url}}"
|
||||||
ng-attr-target="{{hyperlink.openNewTab() ? '_blank' : undefined}}"
|
ng-attr-target="{{hyperlink.openNewTab() ? '_blank' : undefined}}"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
's-button': hyperlink.isButton()
|
'c-hyperlink--button u-fills-container' : hyperlink.isButton(),
|
||||||
}">
|
'c-hyperlink--link' : !hyperlink.isButton() }">
|
||||||
<span class="label">{{domainObject.getModel().displayText}}</span>
|
<span class="c-hyperlink__label">{{domainObject.getModel().displayText}}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -1,83 +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="abs l-layout {{ domainObject.getModel().layoutAdvancedCss }}"
|
|
||||||
ng-controller="LayoutController as controller"
|
|
||||||
ng-click="controller.bypassSelection($event)">
|
|
||||||
|
|
||||||
<!-- Background grid -->
|
|
||||||
<div class="l-grid-holder"
|
|
||||||
ng-show="!controller.drilledIn"
|
|
||||||
ng-click="controller.bypassSelection($event)">
|
|
||||||
<div class="l-grid l-grid-x"
|
|
||||||
ng-if="!controller.getGridSize()[0] < 3"
|
|
||||||
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
|
||||||
<div class="l-grid l-grid-y"
|
|
||||||
ng-if="!controller.getGridSize()[1] < 3"
|
|
||||||
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="frame t-frame-outer child-frame panel s-selectable s-moveable s-hover-border t-object-type-{{ childObject.getModel().type }}"
|
|
||||||
data-layout-id="{{childObject.getId() + '-' + $id}}"
|
|
||||||
ng-class="{ 'no-frame': !controller.hasFrame(childObject), 's-drilled-in': controller.isDrilledIn(childObject) }"
|
|
||||||
ng-repeat="childObject in composition"
|
|
||||||
ng-init="controller.selectIfNew(childObject.getId() + '-' + $id, childObject)"
|
|
||||||
mct-selectable="controller.getContext(childObject)"
|
|
||||||
ng-dblclick="controller.drill($event, childObject)"
|
|
||||||
ng-style="controller.getFrameStyle(childObject.getId())">
|
|
||||||
|
|
||||||
<mct-representation key="'frame'"
|
|
||||||
class="t-rep-frame holder contents abs"
|
|
||||||
mct-object="childObject">
|
|
||||||
</mct-representation>
|
|
||||||
<!-- Drag handles -->
|
|
||||||
<span class="abs t-edit-handle-holder" ng-if="controller.selected(childObject) && !controller.isDrilledIn(childObject)">
|
|
||||||
<span class="edit-handle edit-move"
|
|
||||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [0,0])"
|
|
||||||
mct-drag="controller.continueDrag(delta)"
|
|
||||||
mct-drag-up="controller.endDrag()">
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="edit-corner edit-resize-nw"
|
|
||||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [-1,-1])"
|
|
||||||
mct-drag="controller.continueDrag(delta)"
|
|
||||||
mct-drag-up="controller.endDrag()">
|
|
||||||
</span>
|
|
||||||
<span class="edit-corner edit-resize-ne"
|
|
||||||
mct-drag-down="controller.startDrag(childObject.getId(), [0,1], [1,-1])"
|
|
||||||
mct-drag="controller.continueDrag(delta)"
|
|
||||||
mct-drag-up="controller.endDrag()">
|
|
||||||
</span>
|
|
||||||
<span class="edit-corner edit-resize-sw"
|
|
||||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,0], [-1,1])"
|
|
||||||
mct-drag="controller.continueDrag(delta)"
|
|
||||||
mct-drag-up="controller.endDrag()">
|
|
||||||
</span>
|
|
||||||
<span class="edit-corner edit-resize-se"
|
|
||||||
mct-drag-down="controller.startDrag(childObject.getId(), [0,0], [1,1])"
|
|
||||||
mct-drag="controller.continueDrag(delta)"
|
|
||||||
mct-drag-up="controller.endDrag()">
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
@ -1,524 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This bundle implements object types and associated views for
|
|
||||||
* display-building.
|
|
||||||
* @namespace platform/features/layout
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'zepto',
|
|
||||||
'./LayoutDrag'
|
|
||||||
],
|
|
||||||
function (
|
|
||||||
$,
|
|
||||||
LayoutDrag
|
|
||||||
) {
|
|
||||||
|
|
||||||
var DEFAULT_DIMENSIONS = [12, 8],
|
|
||||||
DEFAULT_GRID_SIZE = [32, 32],
|
|
||||||
MINIMUM_FRAME_SIZE = [320, 180];
|
|
||||||
|
|
||||||
var DEFAULT_HIDDEN_FRAME_TYPES = [
|
|
||||||
'hyperlink'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The LayoutController is responsible for supporting the
|
|
||||||
* Layout view. It arranges frames according to saved configuration
|
|
||||||
* and provides methods for updating these based on mouse
|
|
||||||
* movement.
|
|
||||||
* @memberof platform/features/layout
|
|
||||||
* @constructor
|
|
||||||
* @param {Scope} $scope the controller's Angular scope
|
|
||||||
*/
|
|
||||||
function LayoutController($scope, $element, openmct) {
|
|
||||||
var self = this,
|
|
||||||
callbackCount = 0;
|
|
||||||
|
|
||||||
this.$element = $element;
|
|
||||||
|
|
||||||
// Update grid size when it changed
|
|
||||||
function updateGridSize(layoutGrid) {
|
|
||||||
var oldSize = self.gridSize;
|
|
||||||
|
|
||||||
self.gridSize = layoutGrid || DEFAULT_GRID_SIZE;
|
|
||||||
|
|
||||||
// Only update panel positions if this actually changed things
|
|
||||||
if (self.gridSize[0] !== oldSize[0] ||
|
|
||||||
self.gridSize[1] !== oldSize[1]) {
|
|
||||||
self.layoutPanels(Object.keys(self.positions));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Position a panel after a drop event
|
|
||||||
function handleDrop(e, id, position) {
|
|
||||||
if (e.defaultPrevented) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.configuration = $scope.configuration || {};
|
|
||||||
$scope.configuration.panels = $scope.configuration.panels || {};
|
|
||||||
|
|
||||||
self.openmct.objects.get(id).then(function (object) {
|
|
||||||
$scope.configuration.panels[id] = {
|
|
||||||
position: [
|
|
||||||
Math.floor(position.x / self.gridSize[0]),
|
|
||||||
Math.floor(position.y / self.gridSize[1])
|
|
||||||
],
|
|
||||||
dimensions: self.defaultDimensions(),
|
|
||||||
hasFrame: self.getDefaultFrame(object.type)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Store the id so that the newly-dropped object
|
|
||||||
// gets selected during refresh composition
|
|
||||||
self.droppedIdToSelectAfterRefresh = id;
|
|
||||||
|
|
||||||
self.commit();
|
|
||||||
|
|
||||||
// Populate template-facing position for this id
|
|
||||||
self.rawPositions[id] = $scope.configuration.panels[id];
|
|
||||||
self.populatePosition(id);
|
|
||||||
refreshComposition();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Layout may contain embedded views which will
|
|
||||||
// listen for drops, so call preventDefault() so
|
|
||||||
// that they can recognize that this event is handled.
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Will fetch fully contextualized composed objects, and populate
|
|
||||||
// scope with them.
|
|
||||||
function refreshComposition() {
|
|
||||||
//Keep a track of how many composition callbacks have been made
|
|
||||||
var thisCount = ++callbackCount;
|
|
||||||
|
|
||||||
$scope.domainObject.useCapability('composition').then(function (composition) {
|
|
||||||
var ids;
|
|
||||||
|
|
||||||
//Is this callback for the most recent composition
|
|
||||||
// request? If not, discard it. Prevents race condition
|
|
||||||
if (thisCount === callbackCount) {
|
|
||||||
ids = composition.map(function (object) {
|
|
||||||
return object.getId();
|
|
||||||
}) || [];
|
|
||||||
|
|
||||||
$scope.composition = composition;
|
|
||||||
self.layoutPanels(ids);
|
|
||||||
self.setFrames(ids);
|
|
||||||
|
|
||||||
if (self.selectedId &&
|
|
||||||
self.selectedId !== $scope.domainObject.getId() &&
|
|
||||||
composition.indexOf(self.selectedId) === -1) {
|
|
||||||
// Click triggers selection of layout parent.
|
|
||||||
self.$element[0].click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// End drag; we don't want to put $scope into this
|
|
||||||
// because it triggers "cpws" (copy window or scope)
|
|
||||||
// errors in Angular.
|
|
||||||
this.endDragInScope = function () {
|
|
||||||
// Write to configuration; this is watched and
|
|
||||||
// saved by the EditRepresenter.
|
|
||||||
$scope.configuration =
|
|
||||||
$scope.configuration || {};
|
|
||||||
|
|
||||||
$scope.configuration.panels =
|
|
||||||
$scope.configuration.panels || {};
|
|
||||||
|
|
||||||
$scope.configuration.panels[self.activeDragId] =
|
|
||||||
$scope.configuration.panels[self.activeDragId] || {};
|
|
||||||
|
|
||||||
$scope.configuration.panels[self.activeDragId].position =
|
|
||||||
self.rawPositions[self.activeDragId].position;
|
|
||||||
$scope.configuration.panels[self.activeDragId].dimensions =
|
|
||||||
self.rawPositions[self.activeDragId].dimensions;
|
|
||||||
|
|
||||||
self.commit();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sets the selectable object in response to the selection change event.
|
|
||||||
function setSelection(selectable) {
|
|
||||||
var selection = selectable[0];
|
|
||||||
|
|
||||||
if (!selection) {
|
|
||||||
delete self.selectedId;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.selectedId = selection.context.oldItem.getId();
|
|
||||||
self.drilledIn = undefined;
|
|
||||||
self.selectable = selectable;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.positions = {};
|
|
||||||
this.rawPositions = {};
|
|
||||||
this.gridSize = DEFAULT_GRID_SIZE;
|
|
||||||
this.$scope = $scope;
|
|
||||||
this.drilledIn = undefined;
|
|
||||||
this.openmct = openmct;
|
|
||||||
|
|
||||||
// Watch for changes to the grid size in the model
|
|
||||||
$scope.$watch("model.layoutGrid", updateGridSize);
|
|
||||||
|
|
||||||
// Update composed objects on screen, and position panes
|
|
||||||
$scope.$watchCollection("model.composition", refreshComposition);
|
|
||||||
|
|
||||||
openmct.selection.on('change', setSelection);
|
|
||||||
|
|
||||||
$scope.$on("$destroy", function () {
|
|
||||||
openmct.selection.off("change", setSelection);
|
|
||||||
self.unlisten();
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.$on("mctDrop", handleDrop);
|
|
||||||
|
|
||||||
self.unlisten = self.$scope.domainObject.getCapability('mutation').listen(function (model) {
|
|
||||||
$scope.configuration = model.configuration.layout;
|
|
||||||
$scope.model = model;
|
|
||||||
var panels = $scope.configuration.panels;
|
|
||||||
|
|
||||||
Object.keys(panels).forEach(function (key) {
|
|
||||||
if (self.frames && self.frames.hasOwnProperty(key)) {
|
|
||||||
self.frames[key] = panels[key].hasFrame;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility function to copy raw positions from configuration,
|
|
||||||
// without writing directly to configuration (to avoid triggering
|
|
||||||
// persistence from watchers during drags).
|
|
||||||
function shallowCopy(obj, keys) {
|
|
||||||
var copy = {};
|
|
||||||
keys.forEach(function (k) {
|
|
||||||
copy[k] = obj[k];
|
|
||||||
});
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the frames value. If a configuration panel has "hasFrame' property,
|
|
||||||
* use that value, otherwise set a default value. A 'hyperlink' object should
|
|
||||||
* have no frame by default.
|
|
||||||
*
|
|
||||||
* @param {string[]} ids the object ids
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.setFrames = function (ids) {
|
|
||||||
var panels = shallowCopy(this.$scope.configuration.panels || {}, ids);
|
|
||||||
this.frames = {};
|
|
||||||
|
|
||||||
this.$scope.composition.forEach(function (object) {
|
|
||||||
var id = object.getId();
|
|
||||||
panels[id] = panels[id] || {};
|
|
||||||
|
|
||||||
if (panels[id].hasOwnProperty('hasFrame')) {
|
|
||||||
this.frames[id] = panels[id].hasFrame;
|
|
||||||
} else {
|
|
||||||
this.frames[id] = this.getDefaultFrame(object.getModel().type);
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the default value for frame.
|
|
||||||
*
|
|
||||||
* @param type the domain object type
|
|
||||||
* @return {boolean} true if the object should have
|
|
||||||
* frame by default, false, otherwise
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.getDefaultFrame = function (type) {
|
|
||||||
return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Convert from { positions: ..., dimensions: ... } to an
|
|
||||||
// appropriate ng-style argument, to position frames.
|
|
||||||
LayoutController.prototype.convertPosition = function (raw) {
|
|
||||||
var gridSize = this.gridSize;
|
|
||||||
// Multiply position/dimensions by grid size
|
|
||||||
return {
|
|
||||||
left: (gridSize[0] * raw.position[0]) + 'px',
|
|
||||||
top: (gridSize[1] * raw.position[1]) + 'px',
|
|
||||||
width: (gridSize[0] * raw.dimensions[0]) + 'px',
|
|
||||||
height: (gridSize[1] * raw.dimensions[1]) + 'px',
|
|
||||||
minWidth: (gridSize[0] * raw.dimensions[0]) + 'px',
|
|
||||||
minHeight: (gridSize[1] * raw.dimensions[1]) + 'px'
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate default positions for a new panel
|
|
||||||
LayoutController.prototype.defaultDimensions = function () {
|
|
||||||
var gridSize = this.gridSize;
|
|
||||||
return MINIMUM_FRAME_SIZE.map(function (min, i) {
|
|
||||||
return Math.max(
|
|
||||||
Math.ceil(min / gridSize[i]),
|
|
||||||
DEFAULT_DIMENSIONS[i]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate a default position (in its raw format) for a frame.
|
|
||||||
// Use an index to ensure that default positions are unique.
|
|
||||||
LayoutController.prototype.defaultPosition = function (index) {
|
|
||||||
return {
|
|
||||||
position: [index, index],
|
|
||||||
dimensions: this.defaultDimensions()
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Store a computed position for a contained frame by its
|
|
||||||
// domain object id. Called in a forEach loop, so arguments
|
|
||||||
// are as expected there.
|
|
||||||
LayoutController.prototype.populatePosition = function (id, index) {
|
|
||||||
this.rawPositions[id] =
|
|
||||||
this.rawPositions[id] || this.defaultPosition(index || 0);
|
|
||||||
this.positions[id] =
|
|
||||||
this.convertPosition(this.rawPositions[id]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a style object for a frame with the specified domain
|
|
||||||
* object identifier, suitable for use in an `ng-style`
|
|
||||||
* directive to position a frame as configured for this layout.
|
|
||||||
* @param {string} id the object identifier
|
|
||||||
* @returns {Object.<string, string>} an object with
|
|
||||||
* appropriate left, width, etc fields for positioning
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.getFrameStyle = function (id) {
|
|
||||||
// Called in a loop, so just look up; the "positions"
|
|
||||||
// object is kept up to date by a watch.
|
|
||||||
return this.positions[id];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a drag gesture to move/resize a frame.
|
|
||||||
*
|
|
||||||
* The provided position and dimensions factors will determine
|
|
||||||
* whether this is a move or a resize, and what type 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 {string} id the identifier of the domain object
|
|
||||||
* in the frame being manipulated
|
|
||||||
* @param {number[]} posFactor the position factor
|
|
||||||
* @param {number[]} dimFactor the dimensions factor
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.startDrag = function (id, posFactor, dimFactor) {
|
|
||||||
this.activeDragId = id;
|
|
||||||
this.activeDrag = new LayoutDrag(
|
|
||||||
this.rawPositions[id],
|
|
||||||
posFactor,
|
|
||||||
dimFactor,
|
|
||||||
this.gridSize
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Continue an active drag gesture.
|
|
||||||
* @param {number[]} delta the offset, in pixels,
|
|
||||||
* of the current pointer position, relative
|
|
||||||
* to its position when the drag started
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.continueDrag = function (delta) {
|
|
||||||
if (this.activeDrag) {
|
|
||||||
this.rawPositions[this.activeDragId] =
|
|
||||||
this.activeDrag.getAdjustedPosition(delta);
|
|
||||||
this.populatePosition(this.activeDragId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute panel positions based on the layout's object model.
|
|
||||||
* Defined as member function to facilitate testing.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.layoutPanels = function (ids) {
|
|
||||||
var configuration = this.$scope.configuration || {},
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
// Pull panel positions from configuration
|
|
||||||
this.rawPositions =
|
|
||||||
shallowCopy(configuration.panels || {}, ids);
|
|
||||||
|
|
||||||
// Clear prior computed positions
|
|
||||||
this.positions = {};
|
|
||||||
|
|
||||||
// Update width/height that we are tracking
|
|
||||||
this.gridSize =
|
|
||||||
(this.$scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
|
|
||||||
|
|
||||||
// Compute positions and add defaults where needed
|
|
||||||
ids.forEach(function (id, index) {
|
|
||||||
self.populatePosition(id, index);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End the active drag gesture. This will update the
|
|
||||||
* view configuration.
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.endDrag = function () {
|
|
||||||
this.dragInProgress = true;
|
|
||||||
|
|
||||||
setTimeout(function () {
|
|
||||||
this.dragInProgress = false;
|
|
||||||
}.bind(this), 0);
|
|
||||||
|
|
||||||
this.endDragInScope();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the object is currently selected.
|
|
||||||
*
|
|
||||||
* @param {string} obj the object to check for selection
|
|
||||||
* @returns {boolean} true if selected, otherwise false
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.selected = function (obj) {
|
|
||||||
var sobj = this.openmct.selection.get()[0];
|
|
||||||
return (sobj && sobj.context.oldItem.getId() === obj.getId()) ? true : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bypasses selection if drag is in progress.
|
|
||||||
*
|
|
||||||
* @param event the angular event object
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.bypassSelection = function (event) {
|
|
||||||
if (this.dragInProgress) {
|
|
||||||
if (event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the domain object is drilled in.
|
|
||||||
*
|
|
||||||
* @param domainObject the domain object
|
|
||||||
* @return true if the object is drilled in, false otherwise
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.isDrilledIn = function (domainObject) {
|
|
||||||
return this.drilledIn === domainObject.getId();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts the given object in the drilled-in mode.
|
|
||||||
*
|
|
||||||
* @param event the angular event object
|
|
||||||
* @param domainObject the domain object
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.drill = function (event, domainObject) {
|
|
||||||
if (event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!domainObject.getCapability('editor').inEditContext()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!domainObject.hasCapability('composition')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable since fixed position doesn't use the selection API yet
|
|
||||||
if (domainObject.getModel().type === 'telemetry.fixed') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drilledIn = domainObject.getId();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the object has frame.
|
|
||||||
*
|
|
||||||
* @param {object} obj the object
|
|
||||||
* @return {boolean} true if object has frame, otherwise false
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.hasFrame = function (obj) {
|
|
||||||
return this.frames[obj.getId()];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the size of the grid, in pixels. The returned array
|
|
||||||
* is in the form `[x, y]`.
|
|
||||||
* @returns {number[]} the grid size
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.getGridSize = function () {
|
|
||||||
return this.gridSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the selection context.
|
|
||||||
*
|
|
||||||
* @param domainObject the domain object
|
|
||||||
* @returns {object} the context object which includes item and oldItem
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.getContext = function (domainObject) {
|
|
||||||
return {
|
|
||||||
item: domainObject.useCapability('adapter'),
|
|
||||||
oldItem: domainObject
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
LayoutController.prototype.commit = function () {
|
|
||||||
var model = this.$scope.model;
|
|
||||||
model.configuration = model.configuration || {};
|
|
||||||
model.configuration.layout = this.$scope.configuration;
|
|
||||||
|
|
||||||
this.$scope.domainObject.useCapability('mutation', function () {
|
|
||||||
return model;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selects a newly-dropped object.
|
|
||||||
*
|
|
||||||
* @param classSelector the css class selector
|
|
||||||
* @param domainObject the domain object
|
|
||||||
*/
|
|
||||||
LayoutController.prototype.selectIfNew = function (selector, domainObject) {
|
|
||||||
if (domainObject.getId() === this.droppedIdToSelectAfterRefresh) {
|
|
||||||
setTimeout(function () {
|
|
||||||
$('[data-layout-id="' + selector + '"]')[0].click();
|
|
||||||
delete this.droppedIdToSelectAfterRefresh;
|
|
||||||
}.bind(this), 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return LayoutController;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,479 +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/LayoutController",
|
|
||||||
"zepto"
|
|
||||||
],
|
|
||||||
function (
|
|
||||||
LayoutController,
|
|
||||||
$
|
|
||||||
) {
|
|
||||||
|
|
||||||
describe("The Layout controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
mockEvent,
|
|
||||||
testModel,
|
|
||||||
testConfiguration,
|
|
||||||
controller,
|
|
||||||
mockCompositionCapability,
|
|
||||||
mockComposition,
|
|
||||||
mockCompositionObjects,
|
|
||||||
mockOpenMCT,
|
|
||||||
mockSelection,
|
|
||||||
mockDomainObjectCapability,
|
|
||||||
mockObjects,
|
|
||||||
unlistenFunc,
|
|
||||||
$element = [],
|
|
||||||
selectable = [];
|
|
||||||
|
|
||||||
function mockPromise(value) {
|
|
||||||
return {
|
|
||||||
then: function (thenFunc) {
|
|
||||||
return mockPromise(thenFunc(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mockDomainObject(id) {
|
|
||||||
return {
|
|
||||||
getId: function () {
|
|
||||||
return id;
|
|
||||||
},
|
|
||||||
useCapability: function () {
|
|
||||||
return mockCompositionCapability;
|
|
||||||
},
|
|
||||||
getModel: function () {
|
|
||||||
if (id === 'b') {
|
|
||||||
return {
|
|
||||||
type : 'hyperlink'
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getCapability: function () {
|
|
||||||
return mockDomainObjectCapability;
|
|
||||||
},
|
|
||||||
hasCapability: function (param) {
|
|
||||||
if (param === 'composition') {
|
|
||||||
return id !== 'b';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
type: "testType"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockScope = jasmine.createSpyObj(
|
|
||||||
"$scope",
|
|
||||||
["$watch", "$watchCollection", "$on"]
|
|
||||||
);
|
|
||||||
mockEvent = jasmine.createSpyObj(
|
|
||||||
'event',
|
|
||||||
['preventDefault', 'stopPropagation']
|
|
||||||
);
|
|
||||||
|
|
||||||
testModel = {};
|
|
||||||
|
|
||||||
mockComposition = ["a", "b", "c"];
|
|
||||||
mockCompositionObjects = mockComposition.map(mockDomainObject);
|
|
||||||
|
|
||||||
testConfiguration = {
|
|
||||||
panels: {
|
|
||||||
a: {
|
|
||||||
position: [20, 10],
|
|
||||||
dimensions: [5, 5]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
unlistenFunc = jasmine.createSpy("unlisten");
|
|
||||||
mockDomainObjectCapability = jasmine.createSpyObj('capability',
|
|
||||||
['inEditContext', 'listen']
|
|
||||||
);
|
|
||||||
mockDomainObjectCapability.listen.and.returnValue(unlistenFunc);
|
|
||||||
|
|
||||||
mockCompositionCapability = mockPromise(mockCompositionObjects);
|
|
||||||
|
|
||||||
mockScope.domainObject = mockDomainObject("mockDomainObject");
|
|
||||||
mockScope.model = testModel;
|
|
||||||
mockScope.configuration = testConfiguration;
|
|
||||||
|
|
||||||
selectable[0] = {
|
|
||||||
context: {
|
|
||||||
oldItem: mockScope.domainObject
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mockSelection = jasmine.createSpyObj("selection", [
|
|
||||||
'select',
|
|
||||||
'on',
|
|
||||||
'off',
|
|
||||||
'get'
|
|
||||||
]);
|
|
||||||
mockSelection.get.and.returnValue(selectable);
|
|
||||||
|
|
||||||
mockObjects = jasmine.createSpyObj('objects', [
|
|
||||||
'get'
|
|
||||||
]);
|
|
||||||
mockObjects.get.and.returnValue(mockPromise(mockDomainObject("mockObject")));
|
|
||||||
mockOpenMCT = {
|
|
||||||
selection: mockSelection,
|
|
||||||
objects: mockObjects
|
|
||||||
};
|
|
||||||
|
|
||||||
$element = $('<div></div>');
|
|
||||||
$(document).find('body').append($element);
|
|
||||||
spyOn($element[0], 'click');
|
|
||||||
|
|
||||||
spyOn(mockScope.domainObject, "useCapability").and.callThrough();
|
|
||||||
|
|
||||||
controller = new LayoutController(mockScope, $element, mockOpenMCT);
|
|
||||||
spyOn(controller, "layoutPanels").and.callThrough();
|
|
||||||
spyOn(controller, "commit");
|
|
||||||
|
|
||||||
jasmine.clock().install();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
$element.remove();
|
|
||||||
jasmine.clock().uninstall();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it("listens for selection change events", function () {
|
|
||||||
expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
|
|
||||||
'change',
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("cleans up on scope destroy", function () {
|
|
||||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
|
||||||
'$destroy',
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
|
|
||||||
mockScope.$on.calls.all()[0].args[1]();
|
|
||||||
|
|
||||||
expect(mockOpenMCT.selection.off).toHaveBeenCalledWith(
|
|
||||||
'change',
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Model changes will indicate that panel positions
|
|
||||||
// may have changed, for instance.
|
|
||||||
it("watches for changes to composition", function () {
|
|
||||||
expect(mockScope.$watchCollection).toHaveBeenCalledWith(
|
|
||||||
"model.composition",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Retrieves updated composition from composition capability", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
expect(mockScope.domainObject.useCapability).toHaveBeenCalledWith(
|
|
||||||
"composition"
|
|
||||||
);
|
|
||||||
expect(controller.layoutPanels).toHaveBeenCalledWith(
|
|
||||||
mockComposition
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Is robust to concurrent changes to composition", function () {
|
|
||||||
var secondMockComposition = ["a", "b", "c", "d"],
|
|
||||||
secondMockCompositionObjects = secondMockComposition.map(mockDomainObject),
|
|
||||||
firstCompositionCB,
|
|
||||||
secondCompositionCB;
|
|
||||||
|
|
||||||
spyOn(mockCompositionCapability, "then");
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
firstCompositionCB = mockCompositionCapability.then.calls.all()[0].args[0];
|
|
||||||
secondCompositionCB = mockCompositionCapability.then.calls.all()[1].args[0];
|
|
||||||
|
|
||||||
//Resolve promises in reverse order
|
|
||||||
secondCompositionCB(secondMockCompositionObjects);
|
|
||||||
firstCompositionCB(mockCompositionObjects);
|
|
||||||
|
|
||||||
//Expect the promise call that was initiated most recently to
|
|
||||||
// be the one used to populate scope, irrespective of order that
|
|
||||||
// it was eventually resolved
|
|
||||||
expect(mockScope.composition).toBe(secondMockCompositionObjects);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it("provides styles for frames, from configuration", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
expect(controller.getFrameStyle("a")).toEqual({
|
|
||||||
top: "320px",
|
|
||||||
left: "640px",
|
|
||||||
width: "160px",
|
|
||||||
height: "160px",
|
|
||||||
minWidth : '160px',
|
|
||||||
minHeight : '160px'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("provides default styles for frames", function () {
|
|
||||||
var styleB, styleC;
|
|
||||||
|
|
||||||
// b and c do not have configured positions
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
styleB = controller.getFrameStyle("b");
|
|
||||||
styleC = controller.getFrameStyle("c");
|
|
||||||
|
|
||||||
// Should have a position, but we don't care what
|
|
||||||
expect(styleB.left).toBeDefined();
|
|
||||||
expect(styleB.top).toBeDefined();
|
|
||||||
expect(styleC.left).toBeDefined();
|
|
||||||
expect(styleC.top).toBeDefined();
|
|
||||||
|
|
||||||
// Should have ensured some difference in position
|
|
||||||
expect(styleB).not.toEqual(styleC);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows panels to be dragged", function () {
|
|
||||||
// Populate scope
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
// Verify precondition
|
|
||||||
expect(testConfiguration.panels.b).not.toBeDefined();
|
|
||||||
|
|
||||||
// Do a drag
|
|
||||||
controller.startDrag("b", [1, 1], [0, 0]);
|
|
||||||
controller.continueDrag([100, 100]);
|
|
||||||
controller.endDrag();
|
|
||||||
|
|
||||||
// We do not look closely at the details here;
|
|
||||||
// that is tested in LayoutDragSpec. Just make sure
|
|
||||||
// that a configuration for b has been defined.
|
|
||||||
expect(testConfiguration.panels.b).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it("invokes commit after drag", function () {
|
|
||||||
// Populate scope
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
// Do a drag
|
|
||||||
controller.startDrag("b", [1, 1], [0, 0]);
|
|
||||||
controller.continueDrag([100, 100]);
|
|
||||||
controller.endDrag();
|
|
||||||
|
|
||||||
expect(controller.commit).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("listens for drop events", function () {
|
|
||||||
// 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.panels.d).not.toBeDefined();
|
|
||||||
|
|
||||||
// Notify that a drop occurred
|
|
||||||
mockScope.$on.calls.mostRecent().args[1](
|
|
||||||
mockEvent,
|
|
||||||
'd',
|
|
||||||
{ x: 300, y: 100 }
|
|
||||||
);
|
|
||||||
expect(testConfiguration.panels.d).toBeDefined();
|
|
||||||
expect(mockEvent.preventDefault).toHaveBeenCalled();
|
|
||||||
expect(controller.commit).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("ignores drops when default has been prevented", function () {
|
|
||||||
// Avoids redundant drop-handling, WTD-1233
|
|
||||||
mockEvent.defaultPrevented = true;
|
|
||||||
|
|
||||||
// Notify that a drop occurred
|
|
||||||
mockScope.$on.calls.mostRecent().args[1](
|
|
||||||
mockEvent,
|
|
||||||
'd',
|
|
||||||
{ x: 300, y: 100 }
|
|
||||||
);
|
|
||||||
expect(testConfiguration.panels.d).not.toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("ensures a minimum frame size", function () {
|
|
||||||
var styleB;
|
|
||||||
|
|
||||||
// Start with a very small frame size
|
|
||||||
testModel.layoutGrid = [1, 1];
|
|
||||||
|
|
||||||
// White-boxy; we know which watch is which
|
|
||||||
mockScope.$watch.calls.all()[0].args[1](testModel.layoutGrid);
|
|
||||||
mockScope.$watchCollection.calls.all()[0].args[1](testModel.composition);
|
|
||||||
|
|
||||||
styleB = controller.getFrameStyle("b");
|
|
||||||
|
|
||||||
// Resulting size should still be reasonably large pixel-size
|
|
||||||
expect(parseInt(styleB.width, 10)).toBeGreaterThan(63);
|
|
||||||
expect(parseInt(styleB.width, 10)).toBeGreaterThan(31);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("ensures a minimum frame size on drop", function () {
|
|
||||||
var style;
|
|
||||||
|
|
||||||
// Start with a very small frame size
|
|
||||||
testModel.layoutGrid = [1, 1];
|
|
||||||
mockScope.$watch.calls.all()[0].args[1](testModel.layoutGrid);
|
|
||||||
|
|
||||||
// Add a new object to the composition
|
|
||||||
mockComposition = ["a", "b", "c", "d"];
|
|
||||||
mockCompositionObjects = mockComposition.map(mockDomainObject);
|
|
||||||
mockCompositionCapability = mockPromise(mockCompositionObjects);
|
|
||||||
|
|
||||||
// Notify that a drop occurred
|
|
||||||
mockScope.$on.calls.mostRecent().args[1](
|
|
||||||
mockEvent,
|
|
||||||
'd',
|
|
||||||
{ x: 300, y: 100 }
|
|
||||||
);
|
|
||||||
|
|
||||||
style = controller.getFrameStyle("d");
|
|
||||||
|
|
||||||
// Resulting size should still be reasonably large pixel-size
|
|
||||||
expect(parseInt(style.width, 10)).toBeGreaterThan(63);
|
|
||||||
expect(parseInt(style.height, 10)).toBeGreaterThan(31);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates positions of existing objects on a drop", function () {
|
|
||||||
var oldStyle;
|
|
||||||
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
oldStyle = controller.getFrameStyle("b");
|
|
||||||
|
|
||||||
expect(oldStyle).toBeDefined();
|
|
||||||
|
|
||||||
// ...drop event...
|
|
||||||
mockScope.$on.calls.mostRecent()
|
|
||||||
.args[1](mockEvent, 'b', { x: 300, y: 100 });
|
|
||||||
|
|
||||||
expect(controller.getFrameStyle("b"))
|
|
||||||
.not.toEqual(oldStyle);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows objects to be selected", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
var childObj = mockCompositionObjects[0];
|
|
||||||
selectable[0].context.oldItem = childObj;
|
|
||||||
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
|
||||||
|
|
||||||
expect(controller.selected(childObj)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("prevents event bubbling while drag is in progress", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
var childObj = mockCompositionObjects[0];
|
|
||||||
|
|
||||||
// Do a drag
|
|
||||||
controller.startDrag(childObj.getId(), [1, 1], [0, 0]);
|
|
||||||
controller.continueDrag([100, 100]);
|
|
||||||
controller.endDrag();
|
|
||||||
|
|
||||||
// Because mouse position could cause the parent object to be selected, this should be ignored.
|
|
||||||
controller.bypassSelection(mockEvent);
|
|
||||||
|
|
||||||
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
|
||||||
|
|
||||||
// Shoud be able to select another object when dragging is done.
|
|
||||||
jasmine.clock().tick(0);
|
|
||||||
mockEvent.stopPropagation.calls.reset();
|
|
||||||
controller.bypassSelection(mockEvent);
|
|
||||||
|
|
||||||
expect(mockEvent.stopPropagation).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shows frames by default", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
expect(controller.hasFrame(mockCompositionObjects[0])).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("hyperlinks hide frame by default", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
expect(controller.hasFrame(mockCompositionObjects[1])).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("selects the parent object when selected object is removed", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
var childObj = mockCompositionObjects[0];
|
|
||||||
selectable[0].context.oldItem = childObj;
|
|
||||||
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
|
||||||
|
|
||||||
var composition = ["b", "c"];
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1](composition);
|
|
||||||
|
|
||||||
expect($element[0].click).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows objects to be drilled-in only when editing", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
var childObj = mockCompositionObjects[0];
|
|
||||||
childObj.getCapability().inEditContext.and.returnValue(false);
|
|
||||||
controller.drill(mockEvent, childObj);
|
|
||||||
|
|
||||||
expect(controller.isDrilledIn(childObj)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows objects to be drilled-in only if it has sub objects", function () {
|
|
||||||
mockScope.$watchCollection.calls.mostRecent().args[1]();
|
|
||||||
var childObj = mockCompositionObjects[1];
|
|
||||||
childObj.getCapability().inEditContext.and.returnValue(true);
|
|
||||||
controller.drill(mockEvent, childObj);
|
|
||||||
|
|
||||||
expect(controller.isDrilledIn(childObj)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("selects a newly-dropped object", function () {
|
|
||||||
mockScope.$on.calls.mostRecent().args[1](
|
|
||||||
mockEvent,
|
|
||||||
'd',
|
|
||||||
{ x: 300, y: 100 }
|
|
||||||
);
|
|
||||||
|
|
||||||
var childObj = mockDomainObject("d");
|
|
||||||
var testElement = $("<div data-layout-id='some-id'></div>");
|
|
||||||
$element.append(testElement);
|
|
||||||
spyOn(testElement[0], 'click');
|
|
||||||
|
|
||||||
controller.selectIfNew('some-id', childObj);
|
|
||||||
jasmine.clock().tick(0);
|
|
||||||
|
|
||||||
expect(testElement[0].click).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
19
src/MCT.js
19
src/MCT.js
@ -40,6 +40,7 @@ define([
|
|||||||
'./styles-new/core.scss',
|
'./styles-new/core.scss',
|
||||||
'./styles-new/notebook.scss',
|
'./styles-new/notebook.scss',
|
||||||
'./ui/components/layout/Layout.vue',
|
'./ui/components/layout/Layout.vue',
|
||||||
|
'./ui/overlayService/overlayService',
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
@ -61,6 +62,7 @@ define([
|
|||||||
coreStyles,
|
coreStyles,
|
||||||
NotebookStyles,
|
NotebookStyles,
|
||||||
Layout,
|
Layout,
|
||||||
|
OverlayService,
|
||||||
Vue
|
Vue
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
@ -221,11 +223,18 @@ define([
|
|||||||
*/
|
*/
|
||||||
this.indicators = new api.IndicatorAPI(this);
|
this.indicators = new api.IndicatorAPI(this);
|
||||||
|
|
||||||
|
this.notifications = new api.NotificationAPI();
|
||||||
|
|
||||||
this.Dialog = api.Dialog;
|
this.Dialog = api.Dialog;
|
||||||
|
|
||||||
|
this.editor = new api.EditorAPI.default(this);
|
||||||
|
|
||||||
|
this.OverlayService = new OverlayService();
|
||||||
|
|
||||||
this.legacyRegistry = defaultRegistry;
|
this.legacyRegistry = defaultRegistry;
|
||||||
this.install(this.plugins.Plot());
|
this.install(this.plugins.Plot());
|
||||||
this.install(this.plugins.TelemetryTable());
|
this.install(this.plugins.TelemetryTable());
|
||||||
|
this.install(this.plugins.DisplayLayout());
|
||||||
|
|
||||||
if (typeof BUILD_CONSTANTS !== 'undefined') {
|
if (typeof BUILD_CONSTANTS !== 'undefined') {
|
||||||
this.install(buildInfoPlugin(BUILD_CONSTANTS));
|
this.install(buildInfoPlugin(BUILD_CONSTANTS));
|
||||||
@ -310,13 +319,17 @@ define([
|
|||||||
this.$injector.get('objectService');
|
this.$injector.get('objectService');
|
||||||
|
|
||||||
var appLayout = new Vue({
|
var appLayout = new Vue({
|
||||||
mixins: [Layout.default],
|
components: {
|
||||||
|
'Layout': Layout.default
|
||||||
|
},
|
||||||
provide: {
|
provide: {
|
||||||
openmct: this
|
openmct: this
|
||||||
}
|
},
|
||||||
|
template: '<Layout ref="layout"></Layout>'
|
||||||
});
|
});
|
||||||
domElement.appendChild(appLayout.$mount().$el);
|
domElement.appendChild(appLayout.$mount().$el);
|
||||||
this.layout = appLayout;
|
|
||||||
|
this.layout = appLayout.$refs.layout;
|
||||||
Browse(this);
|
Browse(this);
|
||||||
this.router.start();
|
this.router.start();
|
||||||
this.emit('start');
|
this.emit('start');
|
||||||
|
95
src/adapter/views/TypeInspectorViewProvider.js
Normal file
95
src/adapter/views/TypeInspectorViewProvider.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
define([
|
||||||
|
|
||||||
|
], function (
|
||||||
|
|
||||||
|
) {
|
||||||
|
const DEFAULT_VIEW_PRIORITY = 100;
|
||||||
|
|
||||||
|
const PRIORITY_LEVELS = {
|
||||||
|
"fallback": Number.NEGATIVE_INFINITY,
|
||||||
|
"default": -100,
|
||||||
|
"none": 0,
|
||||||
|
"optional": DEFAULT_VIEW_PRIORITY,
|
||||||
|
"preferred": 1000,
|
||||||
|
"mandatory": Number.POSITIVE_INFINITY
|
||||||
|
};
|
||||||
|
|
||||||
|
function TypeInspectorViewProvider(typeDefinition, openmct, convertToLegacyObject) {
|
||||||
|
console.warn(`DEPRECATION WARNING: Migrate ${typeDefinition.key} from ${typeDefinition.bundle.path} to use the new Inspector View APIs. Legacy Inspector view support will be removed soon.`);
|
||||||
|
let representation = openmct.$injector.get('representations[]')
|
||||||
|
.filter((r) => r.key === typeDefinition.inspector)[0];
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: representation.key,
|
||||||
|
name: representation.name,
|
||||||
|
cssClass: representation.cssClass,
|
||||||
|
description: representation.description,
|
||||||
|
canView: function (selection) {
|
||||||
|
if (!selection[0] || !selection[0].context.item) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let domainObject = selection[0].context.item;
|
||||||
|
return domainObject.type === typeDefinition.key;
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let domainObject = selection[0].context.item;
|
||||||
|
let $rootScope = openmct.$injector.get('$rootScope');
|
||||||
|
let templateLinker = openmct.$injector.get('templateLinker');
|
||||||
|
let scope = $rootScope.$new();
|
||||||
|
let legacyObject = convertToLegacyObject(domainObject);
|
||||||
|
let isDestroyed = false;
|
||||||
|
scope.domainObject = legacyObject;
|
||||||
|
scope.model = legacyObject.getModel();
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (container) {
|
||||||
|
// TODO: implement "gestures" support ?
|
||||||
|
let uses = representation.uses || [];
|
||||||
|
let promises = [];
|
||||||
|
let results = uses.map(function (capabilityKey, i) {
|
||||||
|
let result = legacyObject.useCapability(capabilityKey);
|
||||||
|
if (result.then) {
|
||||||
|
promises.push(result.then(function (r) {
|
||||||
|
results[i] = r;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
function link() {
|
||||||
|
if (isDestroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uses.forEach(function (key, i) {
|
||||||
|
scope[key] = results[i];
|
||||||
|
});
|
||||||
|
templateLinker.link(
|
||||||
|
scope,
|
||||||
|
openmct.$angular.element(container),
|
||||||
|
representation
|
||||||
|
);
|
||||||
|
container.style.height = '100%';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (promises.length) {
|
||||||
|
Promise.all(promises)
|
||||||
|
.then(function () {
|
||||||
|
link();
|
||||||
|
scope.$digest();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
link();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
scope.$destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return TypeInspectorViewProvider;
|
||||||
|
|
||||||
|
});
|
@ -1,8 +1,10 @@
|
|||||||
define([
|
define([
|
||||||
'./LegacyViewProvider',
|
'./LegacyViewProvider',
|
||||||
|
'./TypeInspectorViewProvider',
|
||||||
'../../api/objects/object-utils'
|
'../../api/objects/object-utils'
|
||||||
], function (
|
], function (
|
||||||
LegacyViewProvider,
|
LegacyViewProvider,
|
||||||
|
TypeInspectorViewProvider,
|
||||||
objectUtils
|
objectUtils
|
||||||
) {
|
) {
|
||||||
function installLegacyViews(openmct, legacyViews, instantiate) {
|
function installLegacyViews(openmct, legacyViews, instantiate) {
|
||||||
@ -16,6 +18,13 @@ define([
|
|||||||
legacyViews.forEach(function (legacyView) {
|
legacyViews.forEach(function (legacyView) {
|
||||||
openmct.objectViews.addProvider(new LegacyViewProvider(legacyView, openmct, convertToLegacyObject));
|
openmct.objectViews.addProvider(new LegacyViewProvider(legacyView, openmct, convertToLegacyObject));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let inspectorTypes = openmct.$injector.get('types[]')
|
||||||
|
.filter((t) => t.hasOwnProperty('inspector'));
|
||||||
|
|
||||||
|
inspectorTypes.forEach(function (typeDefinition) {
|
||||||
|
openmct.inspectorViews.addProvider(new TypeInspectorViewProvider(typeDefinition, openmct, convertToLegacyObject));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return installLegacyViews;
|
return installLegacyViews;
|
||||||
|
83
src/api/Editor.js
Normal file
83
src/api/Editor.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import EventEmitter from 'EventEmitter';
|
||||||
|
|
||||||
|
export default class Editor extends EventEmitter {
|
||||||
|
constructor(openmct) {
|
||||||
|
super();
|
||||||
|
this.editing = false;
|
||||||
|
this.openmct = openmct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate an editing session. This will start a transaction during
|
||||||
|
* which any persist operations will be deferred until either save()
|
||||||
|
* or finish() are called.
|
||||||
|
*/
|
||||||
|
edit() {
|
||||||
|
this.editing = true;
|
||||||
|
this.getTransactionService().startTransaction();
|
||||||
|
this.emit('isEditing', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns true if the application is in edit mode, false otherwise.
|
||||||
|
*/
|
||||||
|
isEditing() {
|
||||||
|
return this.editing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save any unsaved changes from this editing session. This will
|
||||||
|
* end the current transaction.
|
||||||
|
*/
|
||||||
|
save() {
|
||||||
|
return this.getTransactionService().commit().then((result)=>{
|
||||||
|
this.editing = false;
|
||||||
|
this.emit('isEditing', false);
|
||||||
|
return result
|
||||||
|
}).catch((error)=>{
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End the currently active transaction and discard unsaved changes.
|
||||||
|
*/
|
||||||
|
cancel() {
|
||||||
|
this.getTransactionService().cancel();
|
||||||
|
this.editing = false;
|
||||||
|
this.emit('isEditing', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
getTransactionService() {
|
||||||
|
if (!this.transactionService) {
|
||||||
|
this.transactionService = this.openmct.$injector.get('transactionService');
|
||||||
|
}
|
||||||
|
return this.transactionService;
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,10 @@ define([
|
|||||||
'./ui/Dialog',
|
'./ui/Dialog',
|
||||||
'./ui/GestureAPI',
|
'./ui/GestureAPI',
|
||||||
'./telemetry/TelemetryAPI',
|
'./telemetry/TelemetryAPI',
|
||||||
'./indicators/IndicatorAPI'
|
'./indicators/IndicatorAPI',
|
||||||
|
'./notifications/NotificationAPI',
|
||||||
|
'./Editor'
|
||||||
|
|
||||||
], function (
|
], function (
|
||||||
TimeAPI,
|
TimeAPI,
|
||||||
ObjectAPI,
|
ObjectAPI,
|
||||||
@ -37,7 +40,9 @@ define([
|
|||||||
Dialog,
|
Dialog,
|
||||||
GestureAPI,
|
GestureAPI,
|
||||||
TelemetryAPI,
|
TelemetryAPI,
|
||||||
IndicatorAPI
|
IndicatorAPI,
|
||||||
|
NotificationAPI,
|
||||||
|
EditorAPI
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
TimeAPI: TimeAPI,
|
TimeAPI: TimeAPI,
|
||||||
@ -47,6 +52,8 @@ define([
|
|||||||
TypeRegistry: TypeRegistry,
|
TypeRegistry: TypeRegistry,
|
||||||
GestureAPI: GestureAPI,
|
GestureAPI: GestureAPI,
|
||||||
TelemetryAPI: TelemetryAPI,
|
TelemetryAPI: TelemetryAPI,
|
||||||
IndicatorAPI: IndicatorAPI
|
IndicatorAPI: IndicatorAPI,
|
||||||
|
NotificationAPI: NotificationAPI.default,
|
||||||
|
EditorAPI: EditorAPI
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -28,7 +28,7 @@ define([
|
|||||||
) {
|
) {
|
||||||
function IndicatorAPI(openmct) {
|
function IndicatorAPI(openmct) {
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
this.indicatorElements = [];
|
this.indicatorObjects = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
IndicatorAPI.prototype.simpleIndicator = function () {
|
IndicatorAPI.prototype.simpleIndicator = function () {
|
||||||
@ -55,12 +55,7 @@ define([
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
IndicatorAPI.prototype.add = function (indicator) {
|
IndicatorAPI.prototype.add = function (indicator) {
|
||||||
// So that we can consistently position indicator elements,
|
this.indicatorObjects.push(indicator);
|
||||||
// guarantee that they are wrapped in an element we control
|
|
||||||
var wrapperNode = document.createElement('div');
|
|
||||||
wrapperNode.className = 'h-indicator';
|
|
||||||
wrapperNode.appendChild(indicator.element);
|
|
||||||
this.indicatorElements.push(wrapperNode);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return IndicatorAPI;
|
return IndicatorAPI;
|
||||||
|
48
src/api/notifications/MCTNotification.js
Normal file
48
src/api/notifications/MCTNotification.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import EventEmitter from 'EventEmitter';
|
||||||
|
export default class MCTNotification extends EventEmitter {
|
||||||
|
|
||||||
|
constructor(notificationModel, notificationAPI) {
|
||||||
|
super();
|
||||||
|
this.notifications = notificationAPI;
|
||||||
|
this.model = notificationModel;
|
||||||
|
this.initializeModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
minimize() {
|
||||||
|
this.notifications.minimize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss() {
|
||||||
|
this.notifications.dismiss(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
dismissOrMinimize() {
|
||||||
|
this.notifications.dismissOrMinimize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeModel() {
|
||||||
|
this.model.minimized = this.model.minimized || false;
|
||||||
|
}
|
||||||
|
}
|
353
src/api/notifications/NotificationApi.js
Normal file
353
src/api/notifications/NotificationApi.js
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This bundle implements the notification service, which can be used to
|
||||||
|
* show banner notifications to the user. Banner notifications
|
||||||
|
* are used to inform users of events in a non-intrusive way. As
|
||||||
|
* much as possible, notifications share a model with blocking
|
||||||
|
* dialogs so that the same information can be provided in a dialog
|
||||||
|
* and then minimized to a banner notification if needed.
|
||||||
|
*
|
||||||
|
* @namespace platform/api/notifications
|
||||||
|
*/
|
||||||
|
import moment from 'moment';
|
||||||
|
import EventEmitter from 'EventEmitter';
|
||||||
|
import MCTNotification from './MCTNotification.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of a banner notification. Banner notifications
|
||||||
|
* are used to inform users of events in a non-intrusive way. As
|
||||||
|
* much as possible, notifications share a model with blocking
|
||||||
|
* dialogs so that the same information can be provided in a dialog
|
||||||
|
* and then minimized to a banner notification if needed, or vice-versa.
|
||||||
|
*
|
||||||
|
* @typedef {object} NotificationModel
|
||||||
|
* @property {string} title The title of the message
|
||||||
|
* @property {string} severity The importance of the message (one of
|
||||||
|
* 'info', 'alert', or 'error' where info < alert <error)
|
||||||
|
* @property {number} [progress] The completion status of a task
|
||||||
|
* represented numerically
|
||||||
|
* @property {boolean} [unknownProgress] a boolean indicating that the
|
||||||
|
* progress of the underlying task is unknown. This will result in a
|
||||||
|
* visually distinct progress bar.
|
||||||
|
* @property {boolean} [autoDismiss] If truthy, dialog will
|
||||||
|
* be automatically minimized or dismissed (depending on severity).
|
||||||
|
* Additionally, if the provided value is a number, it will be used
|
||||||
|
* as the delay period before being dismissed.
|
||||||
|
* @property {boolean} [dismissable=true] If true, notification will
|
||||||
|
* include an option to dismiss it completely.
|
||||||
|
* @see DialogModel
|
||||||
|
*/
|
||||||
|
|
||||||
|
const DEFAULT_AUTO_DISMISS_TIMEOUT = 3000;
|
||||||
|
const MINIMIZE_ANIMATION_TIMEOUT = 300;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The notification service is responsible for informing the user of
|
||||||
|
* events via the use of banner notifications.
|
||||||
|
* @memberof platform/commonUI/notification
|
||||||
|
* @constructor
|
||||||
|
* @param defaultAutoDismissTimeout The period of time that an
|
||||||
|
* auto-dismissed message will be displayed for.
|
||||||
|
* @param minimizeAnimationTimeout When notifications are minimized, a brief
|
||||||
|
* animation is shown. This animation requires some time to execute,
|
||||||
|
* so a timeout is required before the notification is hidden
|
||||||
|
*/
|
||||||
|
export default class NotificationAPI extends EventEmitter {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.notifications = [];
|
||||||
|
this.highest = { severity: "info" };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A context in which to hold the active notification and a
|
||||||
|
* handle to its timeout.
|
||||||
|
*/
|
||||||
|
this.activeNotification = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimize a notification. The notification will still be available
|
||||||
|
* from the notification list. Typically notifications with a
|
||||||
|
* severity of 'info' should not be minimized, but rather
|
||||||
|
* dismissed. If you're not sure which is appropriate,
|
||||||
|
* use {@link Notification#dismissOrMinimize}
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
minimize(notification) {
|
||||||
|
//Check this is a known notification
|
||||||
|
let index = this.notifications.indexOf(notification);
|
||||||
|
|
||||||
|
if (this.activeTimeout) {
|
||||||
|
/*
|
||||||
|
Method can be called manually (clicking dismiss) or
|
||||||
|
automatically from an auto-timeout. this.activeTimeout
|
||||||
|
acts as a semaphore to prevent race conditions. Cancel any
|
||||||
|
timeout in progress (for the case where a manual dismiss
|
||||||
|
has shortcut an active auto-dismiss), and clear the
|
||||||
|
semaphore.
|
||||||
|
*/
|
||||||
|
clearTimeout(this.activeTimeout);
|
||||||
|
delete this.activeTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
notification.model.minimized = true;
|
||||||
|
//Add a brief timeout before showing the next notification
|
||||||
|
// in order to allow the minimize animation to run through.
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.emit('destroy');
|
||||||
|
this.setActiveNotification(this.selectNextNotification());
|
||||||
|
}, MINIMIZE_ANIMATION_TIMEOUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completely removes a notification. This will dismiss it from the
|
||||||
|
* message banner and remove it from the list of notifications.
|
||||||
|
* Typically only notifications with a severity of info should be
|
||||||
|
* dismissed. If you're not sure whether to dismiss or minimize a
|
||||||
|
* notification, use {@link Notification#dismissOrMinimize}.
|
||||||
|
* dismiss
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
dismiss(notification) {
|
||||||
|
//Check this is a known notification
|
||||||
|
let index = this.notifications.indexOf(notification);
|
||||||
|
|
||||||
|
if (this.activeTimeout) {
|
||||||
|
/* Method can be called manually (clicking dismiss) or
|
||||||
|
* automatically from an auto-timeout. this.activeTimeout
|
||||||
|
* acts as a semaphore to prevent race conditions. Cancel any
|
||||||
|
* timeout in progress (for the case where a manual dismiss
|
||||||
|
* has shortcut an active auto-dismiss), and clear the
|
||||||
|
* semaphore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
clearTimeout(this.activeTimeout);
|
||||||
|
delete this.activeTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
this.notifications.splice(index, 1);
|
||||||
|
}
|
||||||
|
this.setActiveNotification(this.selectNextNotification());
|
||||||
|
this.setHighestSeverity();
|
||||||
|
notification.emit('destroy');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Depending on the severity of the notification will selectively
|
||||||
|
* dismiss or minimize where appropriate.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
dismissOrMinimize(notification) {
|
||||||
|
let model = notification.model;
|
||||||
|
if (model.severity === "info") {
|
||||||
|
if (model.autoDismiss === false) {
|
||||||
|
this.minimize(notification);
|
||||||
|
} else {
|
||||||
|
this.dismiss(notification);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.minimize(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the notification that is currently visible in the banner area
|
||||||
|
* @returns {Notification}
|
||||||
|
*/
|
||||||
|
getActiveNotification() {
|
||||||
|
return this.activeNotification;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method for info notifications. Notifications
|
||||||
|
* created via this method will be auto-destroy after a default
|
||||||
|
* wait period unless explicitly forbidden by the caller through
|
||||||
|
* the {autoDismiss} property on the {NotificationModel}, in which
|
||||||
|
* case the notification will be minimized after the wait.
|
||||||
|
* @param {NotificationModel | string} message either a string for
|
||||||
|
* the title of the notification message, or a {@link NotificationModel}
|
||||||
|
* defining the options notification to display
|
||||||
|
* @returns {Notification} the provided notification decorated with
|
||||||
|
* functions to dismiss or minimize
|
||||||
|
*/
|
||||||
|
info(message) {
|
||||||
|
let notificationModel = typeof message === "string" ? {title: message} : message;
|
||||||
|
notificationModel.severity = "info";
|
||||||
|
return this.notify(notificationModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method for alert notifications. Notifications
|
||||||
|
* created via this method will will have severity of "alert" enforced
|
||||||
|
* @param {NotificationModel | string} message either a string for
|
||||||
|
* the title of the alert message with default options, or a
|
||||||
|
* {@link NotificationModel} defining the options notification to
|
||||||
|
* display
|
||||||
|
* @returns {Notification} the provided notification decorated with
|
||||||
|
* functions to dismiss or minimize
|
||||||
|
*/
|
||||||
|
alert(message) {
|
||||||
|
let notificationModel = typeof message === "string" ? {title: message} : message;
|
||||||
|
notificationModel.severity = "alert";
|
||||||
|
return this.notify(notificationModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method for error notifications. Notifications
|
||||||
|
* created via this method will will have severity of "error" enforced
|
||||||
|
* @param {NotificationModel | string} message either a string for
|
||||||
|
* the title of the error message with default options, or a
|
||||||
|
* {@link NotificationModel} defining the options of the notification to
|
||||||
|
* display
|
||||||
|
* @returns {Notification} the provided notification decorated with
|
||||||
|
* functions to dismiss or minimize
|
||||||
|
*/
|
||||||
|
error(message) {
|
||||||
|
let notificationModel = typeof message === "string" ? {title: message} : message;
|
||||||
|
notificationModel.severity = "error";
|
||||||
|
return this.notify(notificationModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
setHighestSeverity() {
|
||||||
|
let severity = {
|
||||||
|
"info": 1,
|
||||||
|
"alert": 2,
|
||||||
|
"error": 3
|
||||||
|
};
|
||||||
|
this.highest.severity = this.notifications.reduce((previous, notification) => {
|
||||||
|
if (severity[notification.model.severity] > severity[previous]) {
|
||||||
|
return notification.model.severity;
|
||||||
|
} else {
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
}, "info");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the user of an event. If there is a banner notification
|
||||||
|
* already active, then it will be dismissed or minimized automatically,
|
||||||
|
* and the provided notification displayed in its place.
|
||||||
|
*
|
||||||
|
* @param {NotificationModel} notificationModel The notification to
|
||||||
|
* display
|
||||||
|
* @returns {Notification} the provided notification decorated with
|
||||||
|
* functions to {@link Notification#dismiss} or {@link Notification#minimize}
|
||||||
|
*/
|
||||||
|
notify(notificationModel) {
|
||||||
|
let notification;
|
||||||
|
let activeNotification = this.activeNotification;
|
||||||
|
|
||||||
|
notificationModel.severity = notificationModel.severity || "info";
|
||||||
|
notificationModel.timestamp = moment.utc().format('YYYY-MM-DD hh:mm:ss.ms');
|
||||||
|
|
||||||
|
notification = new MCTNotification(notificationModel, this);
|
||||||
|
|
||||||
|
this.notifications.push(notification);
|
||||||
|
this.setHighestSeverity();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if there is already an active (ie. visible) notification
|
||||||
|
*/
|
||||||
|
if (!this.activeNotification) {
|
||||||
|
this.setActiveNotification(notification);
|
||||||
|
} else if (!this.activeTimeout) {
|
||||||
|
/*
|
||||||
|
If there is already an active notification, time it out. If it's
|
||||||
|
already got a timeout in progress (either because it has had
|
||||||
|
timeout forced because of a queue of messages, or it had an
|
||||||
|
autodismiss specified), leave it to run. Otherwise force a
|
||||||
|
timeout.
|
||||||
|
|
||||||
|
This notification has been added to queue and will be
|
||||||
|
serviced as soon as possible.
|
||||||
|
*/
|
||||||
|
this.activeTimeout = setTimeout(() => {
|
||||||
|
this.dismissOrMinimize(activeNotification);
|
||||||
|
}, DEFAULT_AUTO_DISMISS_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used internally by the NotificationService
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
setActiveNotification(notification) {
|
||||||
|
let shouldAutoDismiss;
|
||||||
|
this.activeNotification = notification;
|
||||||
|
|
||||||
|
if (!notification) {
|
||||||
|
delete this.activeTimeout;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.emit('notification', notification);
|
||||||
|
|
||||||
|
if (notification.model.severity === "info") {
|
||||||
|
shouldAutoDismiss = true;
|
||||||
|
} else {
|
||||||
|
shouldAutoDismiss = notification.model.autoDismiss;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldAutoDismiss || this.selectNextNotification()) {
|
||||||
|
this.activeTimeout = setTimeout(() => {
|
||||||
|
this.dismissOrMinimize(notification);
|
||||||
|
}, DEFAULT_AUTO_DISMISS_TIMEOUT);
|
||||||
|
} else {
|
||||||
|
delete this.activeTimeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used internally by the NotificationService
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
selectNextNotification() {
|
||||||
|
let notification;
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Loop through the notifications queue and find the first one that
|
||||||
|
has not already been minimized (manually or otherwise).
|
||||||
|
*/
|
||||||
|
for (; i < this.notifications.length; i++) {
|
||||||
|
notification = this.notifications[i];
|
||||||
|
|
||||||
|
if (!notification.model.minimized &&
|
||||||
|
notification !== this.activeNotification) {
|
||||||
|
return notification;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -56,7 +56,6 @@ define([
|
|||||||
'../platform/features/clock/bundle',
|
'../platform/features/clock/bundle',
|
||||||
'../platform/features/fixed/bundle',
|
'../platform/features/fixed/bundle',
|
||||||
'../platform/features/imagery/bundle',
|
'../platform/features/imagery/bundle',
|
||||||
'../platform/features/layout/bundle',
|
|
||||||
'../platform/features/my-items/bundle',
|
'../platform/features/my-items/bundle',
|
||||||
'../platform/features/pages/bundle',
|
'../platform/features/pages/bundle',
|
||||||
'../platform/features/hyperlink/bundle',
|
'../platform/features/hyperlink/bundle',
|
||||||
@ -99,7 +98,6 @@ define([
|
|||||||
'platform/features/clock',
|
'platform/features/clock',
|
||||||
'platform/features/fixed',
|
'platform/features/fixed',
|
||||||
'platform/features/imagery',
|
'platform/features/imagery',
|
||||||
'platform/features/layout',
|
|
||||||
'platform/features/pages',
|
'platform/features/pages',
|
||||||
'platform/features/hyperlink',
|
'platform/features/hyperlink',
|
||||||
'platform/features/timeline',
|
'platform/features/timeline',
|
||||||
|
327
src/plugins/displayLayout/DisplayLayout.vue
Normal file
327
src/plugins/displayLayout/DisplayLayout.vue
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="l-layout"
|
||||||
|
@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>
|
||||||
|
</div>
|
||||||
|
<layout-frame v-for="item in frameItems"
|
||||||
|
class="l-layout__frame"
|
||||||
|
:key="item.id"
|
||||||
|
:item="item"
|
||||||
|
:gridSize="gridSize"
|
||||||
|
@drilledIn="updateDrilledInState"
|
||||||
|
@dragInProgress="updatePosition"
|
||||||
|
@endDrag="endDrag">
|
||||||
|
</layout-frame>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
.l-layout,
|
||||||
|
.c-grid,
|
||||||
|
.c-grid__x,
|
||||||
|
.c-grid__y {
|
||||||
|
@include abs();
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-layout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&__grid-holder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__object {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__frame {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-grid {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&__x { @include bgTicks($colorGridLines, 'x'); }
|
||||||
|
&__y { @include bgTicks($colorGridLines, 'y'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-editing {
|
||||||
|
.l-shell__main-container > .l-layout {
|
||||||
|
// Target the top-most layout container and color its background
|
||||||
|
background: rgba($editColor, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import LayoutFrame from './LayoutFrame.vue';
|
||||||
|
|
||||||
|
const DEFAULT_GRID_SIZE = [32, 32],
|
||||||
|
DEFAULT_DIMENSIONS = [12, 8],
|
||||||
|
DEFAULT_POSITION = [0, 0],
|
||||||
|
MINIMUM_FRAME_SIZE = [320, 180],
|
||||||
|
DEFAULT_HIDDEN_FRAME_TYPES = [
|
||||||
|
'hyperlink'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
gridSize: [],
|
||||||
|
frameItems: [],
|
||||||
|
frames: [],
|
||||||
|
frameStyles: [],
|
||||||
|
rawPositions: {},
|
||||||
|
initSelect: true,
|
||||||
|
drilledIn: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: ['domainObject'],
|
||||||
|
components: {
|
||||||
|
LayoutFrame
|
||||||
|
},
|
||||||
|
created: function () {
|
||||||
|
this.newDomainObject = this.domainObject;
|
||||||
|
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;
|
||||||
|
this.composition = this.openmct.composition.get(this.newDomainObject);
|
||||||
|
let panels = (((this.newDomainObject.configuration || {}).layout || {}).panels || {});
|
||||||
|
|
||||||
|
if (this.composition !== undefined) {
|
||||||
|
this.composition.load().then((composition) => {
|
||||||
|
composition.forEach(function (domainObject) {
|
||||||
|
this.readLayoutConfiguration(domainObject, panels);
|
||||||
|
this.makeFrameItem(domainObject, false);
|
||||||
|
}.bind(this));
|
||||||
|
this.composition.on('add', this.onAddComposition);
|
||||||
|
this.composition.on('remove', this.onRemoveComposition);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
|
||||||
|
this.newDomainObject = JSON.parse(JSON.stringify(obj));
|
||||||
|
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;;
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
readLayoutConfiguration(domainObject, panels) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
|
this.rawPositions[id] = {
|
||||||
|
position: panels[id].position || DEFAULT_POSITION,
|
||||||
|
dimensions: panels[id].dimensions || this.defaultDimensions()
|
||||||
|
};
|
||||||
|
this.frameStyles[id] = this.convertPosition(this.rawPositions[id]);
|
||||||
|
this.frames[id] = panels[id].hasOwnProperty('hasFrame') ?
|
||||||
|
panels[id].hasFrame :
|
||||||
|
this.hasFrameByDefault(domainObject.type);
|
||||||
|
},
|
||||||
|
makeFrameItem(domainObject, initSelect) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
|
this.frameItems.push({
|
||||||
|
id: id,
|
||||||
|
hasFrame: this.frames[id],
|
||||||
|
domainObject,
|
||||||
|
style: this.frameStyles[id],
|
||||||
|
drilledIn: this.isDrilledIn(id),
|
||||||
|
initSelect: initSelect,
|
||||||
|
rawPosition: this.rawPositions[id]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onAddComposition(domainObject) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
|
this.rawPositions[id] = {
|
||||||
|
position: [
|
||||||
|
Math.floor(this.droppedObjectPosition.x / this.gridSize[0]),
|
||||||
|
Math.floor(this.droppedObjectPosition.y / this.gridSize[1])
|
||||||
|
],
|
||||||
|
dimensions: this.defaultDimensions()
|
||||||
|
};
|
||||||
|
this.frameStyles[id] = this.convertPosition(this.rawPositions[id]);
|
||||||
|
this.frames[id] = this.hasFrameByDefault(domainObject.type);
|
||||||
|
|
||||||
|
let newPanel = this.rawPositions[id];
|
||||||
|
newPanel.hasFrame = this.frames[id];
|
||||||
|
this.mutate("configuration.layout.panels[" + id + "]", newPanel);
|
||||||
|
this.makeFrameItem(domainObject, true);
|
||||||
|
},
|
||||||
|
onRemoveComposition(identifier) {
|
||||||
|
// TODO: remove the object from frameItems
|
||||||
|
},
|
||||||
|
defaultDimensions() {
|
||||||
|
let gridSize = this.gridSize;
|
||||||
|
return MINIMUM_FRAME_SIZE.map(function (min, i) {
|
||||||
|
return Math.max(
|
||||||
|
Math.ceil(min / gridSize[i]),
|
||||||
|
DEFAULT_DIMENSIONS[i]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
convertPosition(raw) {
|
||||||
|
return {
|
||||||
|
left: (this.gridSize[0] * raw.position[0]) + 'px',
|
||||||
|
top: (this.gridSize[1] * raw.position[1]) + 'px',
|
||||||
|
width: (this.gridSize[0] * raw.dimensions[0]) + 'px',
|
||||||
|
height: (this.gridSize[1] * raw.dimensions[1]) + 'px',
|
||||||
|
minWidth: (this.gridSize[0] * raw.dimensions[0]) + 'px',
|
||||||
|
minHeight: (this.gridSize[1] * raw.dimensions[1]) + 'px'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Checks if the frame should be hidden or not.
|
||||||
|
*
|
||||||
|
* @param type the domain object type
|
||||||
|
* @return {boolean} true if the object should have
|
||||||
|
* frame by default, false, otherwise
|
||||||
|
*/
|
||||||
|
hasFrameByDefault(type) {
|
||||||
|
return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1;
|
||||||
|
},
|
||||||
|
setSelection(selection) {
|
||||||
|
if (selection.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateDrilledInState();
|
||||||
|
},
|
||||||
|
updateDrilledInState(id) {
|
||||||
|
this.drilledIn = id;
|
||||||
|
this.frameItems.forEach(function (item) {
|
||||||
|
item.drilledIn = item.id === id;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isDrilledIn(id) {
|
||||||
|
return this.drilledIn === id;
|
||||||
|
},
|
||||||
|
updatePosition(id, newPosition) {
|
||||||
|
let newStyle = this.convertPosition(newPosition);
|
||||||
|
this.frameStyles[id] = newStyle;
|
||||||
|
this.rawPositions[id] = newPosition;
|
||||||
|
this.frameItems.forEach(function (item) {
|
||||||
|
if (item.id === id) {
|
||||||
|
item.style = newStyle;
|
||||||
|
item.rawPosition = newPosition;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
bypassSelection($event) {
|
||||||
|
if (this.dragInProgress) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
endDrag(id) {
|
||||||
|
this.dragInProgress = true;
|
||||||
|
setTimeout(function () {
|
||||||
|
this.dragInProgress = false;
|
||||||
|
}.bind(this), 0);
|
||||||
|
|
||||||
|
let path = "configuration.layout.panels[" + id + "]";
|
||||||
|
this.mutate(path + ".dimensions", this.rawPositions[id].dimensions);
|
||||||
|
this.mutate(path + ".position", this.rawPositions[id].position);
|
||||||
|
},
|
||||||
|
mutate(path, value) {
|
||||||
|
this.openmct.objects.mutate(this.newDomainObject, path, value);
|
||||||
|
},
|
||||||
|
handleDrop($event) {
|
||||||
|
$event.preventDefault();
|
||||||
|
|
||||||
|
let child = JSON.parse($event.dataTransfer.getData('domainObject'));
|
||||||
|
let duplicates = [];
|
||||||
|
let composition = this.newDomainObject.composition;
|
||||||
|
composition.forEach((object) => {
|
||||||
|
if (this.openmct.objects.makeKeyString(JSON.parse(JSON.stringify(object))) ===
|
||||||
|
this.openmct.objects.makeKeyString(child.identifier)) {
|
||||||
|
duplicates.push(object);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disallow adding a duplicate object to the composition
|
||||||
|
if (duplicates.length !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let elementRect = this.$el.getBoundingClientRect();
|
||||||
|
this.droppedObjectPosition = {
|
||||||
|
x: $event.pageX - elementRect.left,
|
||||||
|
y: $event.pageY - elementRect.top
|
||||||
|
}
|
||||||
|
// TODO: use the composition API to add child once the default composition
|
||||||
|
// provider supports it instead of mutating the composition directly.
|
||||||
|
// this.composition.add(child).
|
||||||
|
composition.push(child.identifier);
|
||||||
|
this.mutate('composition', composition);
|
||||||
|
},
|
||||||
|
handleDragOver($event){
|
||||||
|
$event.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.openmct.selection.on('change', this.setSelection);
|
||||||
|
},
|
||||||
|
destroyed: function () {
|
||||||
|
this.composition.off('add', this.onAddComposition);
|
||||||
|
this.composition.off('remove', this.onRemoveComposition);
|
||||||
|
this.openmct.off('change', this.selection);
|
||||||
|
this.unlisten();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
41
src/plugins/displayLayout/DisplayLayoutType.js
Normal file
41
src/plugins/displayLayout/DisplayLayoutType.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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 () {
|
||||||
|
function DisplayLayoutType() {
|
||||||
|
return {
|
||||||
|
name: "Display Layout",
|
||||||
|
creatable: true,
|
||||||
|
cssClass: 'icon-layout',
|
||||||
|
initialize(domainObject) {
|
||||||
|
domainObject.composition = [];
|
||||||
|
domainObject.configuration = {
|
||||||
|
layout: {
|
||||||
|
panels: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DisplayLayoutType;
|
||||||
|
});
|
115
src/plugins/displayLayout/LayoutDrag.js
Normal file
115
src/plugins/displayLayout/LayoutDrag.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
338
src/plugins/displayLayout/LayoutFrame.vue
Normal file
338
src/plugins/displayLayout/LayoutFrame.vue
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-frame has-local-controls is-selectable is-moveable"
|
||||||
|
:style="item.style"
|
||||||
|
:class="classObject"
|
||||||
|
@dblclick="drill(item.id, $event)">
|
||||||
|
<div class="c-frame__header">
|
||||||
|
<div class="c-frame__header__start">
|
||||||
|
<div class="c-frame__name icon-object">{{ item.domainObject.name }}</div>
|
||||||
|
<div class="c-frame__context-actions c-disclosure-button"></div>
|
||||||
|
</div>
|
||||||
|
<div class="c-frame__header__end">
|
||||||
|
<div class="c-button icon-expand local-controls--hidden"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<object-view class="c-frame__object-view"
|
||||||
|
:object="item.domainObject"></object-view>
|
||||||
|
|
||||||
|
<!-- Drag handles -->
|
||||||
|
<div class="c-frame-edit">
|
||||||
|
<div class="c-frame-edit__move"
|
||||||
|
@mousedown="startDrag([1,1], [0,0], $event)"></div>
|
||||||
|
<div class="c-frame-edit__handle --nw"
|
||||||
|
@mousedown="startDrag([1,1], [-1,-1], $event)"></div>
|
||||||
|
<div class="c-frame-edit__handle --ne"
|
||||||
|
@mousedown="startDrag([0,1], [1,-1], $event)"></div>
|
||||||
|
<div class="c-frame-edit__handle --sw"
|
||||||
|
@mousedown="startDrag([1,0], [-1,1], $event)"></div>
|
||||||
|
<div class="c-frame-edit__handle --se"
|
||||||
|
@mousedown="startDrag([0,0], [1,1], $event)"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
/******************************* FRAME */
|
||||||
|
.c-frame {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: transparent;
|
||||||
|
|
||||||
|
/*************************** HEADER */
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-bottom: $interiorMargin;
|
||||||
|
|
||||||
|
> [class*="__"] {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="__start"] {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="__end"] {
|
||||||
|
//justify-content: flex-end;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
[class*="button"] {
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
@include ellipsize();
|
||||||
|
flex: 0 1 auto;
|
||||||
|
font-size: 1.2em;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
// Object type icon
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** OBJECT VIEW */
|
||||||
|
&__object-view {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.c-object-view {
|
||||||
|
.u-fills-container {
|
||||||
|
// Expand component types that fill a container
|
||||||
|
@include abs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** NO-FRAME */
|
||||||
|
&.no-frame {
|
||||||
|
> [class*="__header"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.no-frame) {
|
||||||
|
background: $colorBodyBg;
|
||||||
|
border: 1px solid $colorInteriorBorder;
|
||||||
|
padding: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** SELECTION */
|
||||||
|
&.is-selectable {
|
||||||
|
&:hover {
|
||||||
|
box-shadow: $browseShdwSelectableHov;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.s-selected, // LEGACY
|
||||||
|
&.is-selected {
|
||||||
|
border: $browseBorderSelected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** EDITING */
|
||||||
|
.is-editing {
|
||||||
|
.c-frame {
|
||||||
|
&:not(.is-drilled-in).is-selectable {
|
||||||
|
border: $editBorderSelectable;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: $editBorderSelectableHov;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.s-selected,
|
||||||
|
&.is-selected {
|
||||||
|
border: $editBorderSelected;
|
||||||
|
|
||||||
|
> .c-frame-edit {
|
||||||
|
display: block; // Show the editing rect and handles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-drilled-in {
|
||||||
|
border: $editBorderDrilledIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-links {
|
||||||
|
// Applied in markup to objects that provide links. Disable while editing.
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-frame-edit {
|
||||||
|
// The editing rect and handles
|
||||||
|
$z: 10;
|
||||||
|
|
||||||
|
@include abs();
|
||||||
|
box-shadow: rgba($editColor, 0.5) 0 0 10px;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&__move {
|
||||||
|
@include abs();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ObjectView from '../../ui/components/layout/ObjectView.vue'
|
||||||
|
import LayoutDrag from './LayoutDrag'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
item: Object,
|
||||||
|
gridSize: Array
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ObjectView
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
classObject: function () {
|
||||||
|
return {
|
||||||
|
'is-drilled-in': this.item.drilledIn,
|
||||||
|
'no-frame': !this.item.hasFrame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
drill(id, $event) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isBeingEdited(this.item.domainObject)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.openmct.composition.get(this.item.domainObject) === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable for fixed position.
|
||||||
|
if (this.item.domainObject.type === 'telemetry.fixed') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('drilledIn', id);
|
||||||
|
},
|
||||||
|
isBeingEdited(object) {
|
||||||
|
// TODO: add logic when inEditContext() is implemented in Vue.
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
updatePosition(event) {
|
||||||
|
let currentPosition = [event.pageX, event.pageY];
|
||||||
|
this.initialPosition = this.initialPosition || currentPosition;
|
||||||
|
this.delta = currentPosition.map(function (value, index) {
|
||||||
|
return value - this.initialPosition[index];
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
startDrag(posFactor, dimFactor, event) {
|
||||||
|
document.body.addEventListener('mousemove', this.continueDrag);
|
||||||
|
document.body.addEventListener('mouseup', this.endDrag);
|
||||||
|
|
||||||
|
this.updatePosition(event);
|
||||||
|
this.activeDrag = new LayoutDrag(
|
||||||
|
this.item.rawPosition,
|
||||||
|
posFactor,
|
||||||
|
dimFactor,
|
||||||
|
this.gridSize
|
||||||
|
);
|
||||||
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
continueDrag(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.updatePosition(event);
|
||||||
|
|
||||||
|
if (this.activeDrag) {
|
||||||
|
this.$emit('dragInProgress', this.item.id, this.activeDrag.getAdjustedPosition(this.delta));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
endDrag(event) {
|
||||||
|
document.body.removeEventListener('mousemove', this.continueDrag);
|
||||||
|
document.body.removeEventListener('mouseup', this.endDrag);
|
||||||
|
this.continueDrag(event);
|
||||||
|
this.$emit('endDrag', this.item.id);
|
||||||
|
this.initialPosition = undefined;
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.removeSelectable = this.openmct.selection.selectable(
|
||||||
|
this.$el,
|
||||||
|
{
|
||||||
|
item: this.item.domainObject
|
||||||
|
},
|
||||||
|
this.item.initSelect
|
||||||
|
);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.removeSelectable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
67
src/plugins/displayLayout/plugin.js
Normal file
67
src/plugins/displayLayout/plugin.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import Layout from './DisplayLayout.vue'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import objectUtils from '../../api/objects/object-utils.js'
|
||||||
|
import DisplayLayoutType from './DisplayLayoutType.js'
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
return function (openmct) {
|
||||||
|
openmct.objectViews.addProvider({
|
||||||
|
key: 'layout.view',
|
||||||
|
canView: function (domainObject) {
|
||||||
|
return domainObject.type === 'layout';
|
||||||
|
},
|
||||||
|
view: function (domainObject) {
|
||||||
|
let component;
|
||||||
|
return {
|
||||||
|
show(container) {
|
||||||
|
component = new Vue({
|
||||||
|
components: {
|
||||||
|
Layout
|
||||||
|
},
|
||||||
|
template: '<layout :domain-object="domainObject"></layout>',
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
objectUtils
|
||||||
|
},
|
||||||
|
el: container,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
domainObject: domainObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy() {
|
||||||
|
component.$destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority() {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
openmct.types.addType('layout', DisplayLayoutType());
|
||||||
|
}
|
||||||
|
}
|
@ -14,9 +14,9 @@
|
|||||||
:title="item.model.name">{{item.model.name}}</div>
|
:title="item.model.name">{{item.model.name}}</div>
|
||||||
<div class="c-grid-item__metadata"
|
<div class="c-grid-item__metadata"
|
||||||
:title="item.type.name">
|
:title="item.type.name">
|
||||||
<span>{{item.type.name}}</span>
|
<span class="c-grid-item__metadata__type">{{item.type.name}}</span>
|
||||||
<span v-if="item.model.composition !== undefined">
|
<span class="c-grid-item__metadata__item-count" v-if="item.model.composition !== undefined">
|
||||||
- {{item.model.composition.length}} item<span v-if="item.model.composition.length !== 1">s</span>
|
{{item.model.composition.length}} item<span v-if="item.model.composition.length !== 1">s</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -45,8 +45,8 @@
|
|||||||
body.desktop & {
|
body.desktop & {
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
&__item {
|
&__item {
|
||||||
height: $ueBrowseGridItemLg;
|
height: $gridItemDesk;
|
||||||
width: $ueBrowseGridItemLg;
|
width: $gridItemDesk;
|
||||||
margin: 0 $interiorMargin $interiorMargin 0;
|
margin: 0 $interiorMargin $interiorMargin 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,8 +62,8 @@
|
|||||||
|
|
||||||
&__type-icon {
|
&__type-icon {
|
||||||
filter: $colorKeyFilter;
|
filter: $colorKeyFilter;
|
||||||
flex: 0 0 32px;
|
flex: 0 0 $gridItemMobile;
|
||||||
font-size: 2em; // Drives the size of the alias indicator when present
|
font-size: floor($gridItemMobile / 2);
|
||||||
margin-right: $interiorMarginLg;
|
margin-right: $interiorMarginLg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,13 +84,22 @@
|
|||||||
&__name {
|
&__name {
|
||||||
@include ellipsize();
|
@include ellipsize();
|
||||||
color: $colorItemFg;
|
color: $colorItemFg;
|
||||||
font-size: 1.3em;
|
font-size: 1.2em;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
margin-bottom: $interiorMarginSm;
|
margin-bottom: $interiorMarginSm;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__metadata {
|
&__metadata {
|
||||||
color: $colorItemFgDetails;
|
color: $colorItemFgDetails;
|
||||||
|
font-size: 0.9em;
|
||||||
|
|
||||||
|
body.mobile & {
|
||||||
|
[class*='__item-count'] {
|
||||||
|
&:before {
|
||||||
|
content: ' - ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__controls {
|
&__controls {
|
||||||
@ -136,8 +145,8 @@
|
|||||||
|
|
||||||
&__type-icon {
|
&__type-icon {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
font-size: 6em; // Drives the size of the alias indicator when present
|
font-size: floor($gridItemDesk / 3);
|
||||||
margin: $interiorMargin 22.5%;
|
margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%;
|
||||||
order: 2;
|
order: 2;
|
||||||
transform: scale(0.9);
|
transform: scale(0.9);
|
||||||
transform-origin: center;
|
transform-origin: center;
|
||||||
@ -149,6 +158,20 @@
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
order: 3;
|
order: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__metadata {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&__type {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
@include ellipsize();
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item-count {
|
||||||
|
opacity: 0.7;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
<span>{{formatTime(entry.createdOn, 'HH:mm:ss')}}</span>
|
<span>{{formatTime(entry.createdOn, 'HH:mm:ss')}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-ne__content">
|
<div class="c-ne__content">
|
||||||
<!-- TODO: fix styling for c-input-inline when SCSS is merged and remove s-input-inline class here -->
|
<div class="c-ne__text c-input-inline"
|
||||||
<div class="c-ne__text c-input-inline s-input-inline"
|
|
||||||
contenteditable="true"
|
contenteditable="true"
|
||||||
ref="contenteditable"
|
ref="contenteditable"
|
||||||
v-on:blur="textBlur($event, entry.id)"
|
v-on:blur="textBlur($event, entry.id)"
|
||||||
|
29
src/plugins/notebook/res/templates/snapshotTemplate.html
Normal file
29
src/plugins/notebook/res/templates/snapshotTemplate.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<div class="u-contents">
|
||||||
|
|
||||||
|
<div class="t-snapshot abs l-view-header">
|
||||||
|
<div class="abs object-browse-bar l-flex-row">
|
||||||
|
<div class="left flex-elem l-flex-row grows">
|
||||||
|
<div class="object-header flex-elem l-flex-row grows">
|
||||||
|
<div class="type-icon flex-elem embed-icon holder" v-bind:class="embed.cssClass"></div>
|
||||||
|
<div class="title-label flex-elem holder flex-can-shrink">{{embed.name}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
|
||||||
|
<div class="flex-elem holder flex-can-shrink s-snapshot-datetime">
|
||||||
|
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
||||||
|
</div>
|
||||||
|
<a class="s-button icon-pencil" title="Annotate">
|
||||||
|
<span class="title-label">Annotate</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="abs object-holder t-image-holder s-image-holder">
|
||||||
|
<div
|
||||||
|
class="image-main s-image-main"
|
||||||
|
v-bind:style="{ backgroundImage: 'url(' + embed.snapshot.src + ')' }">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -24,11 +24,15 @@ define([
|
|||||||
'moment',
|
'moment',
|
||||||
'zepto',
|
'zepto',
|
||||||
'../utils/SnapshotOverlay',
|
'../utils/SnapshotOverlay',
|
||||||
|
'../../res/templates/snapshotTemplate.html',
|
||||||
|
'vue'
|
||||||
],
|
],
|
||||||
function (
|
function (
|
||||||
Moment,
|
Moment,
|
||||||
$,
|
$,
|
||||||
SnapshotOverlay
|
SnapshotOverlay,
|
||||||
|
SnapshotTemplate,
|
||||||
|
Vue
|
||||||
) {
|
) {
|
||||||
function EmbedController (openmct, domainObject) {
|
function EmbedController (openmct, domainObject) {
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
@ -53,11 +57,24 @@ function (
|
|||||||
};
|
};
|
||||||
|
|
||||||
EmbedController.prototype.openSnapshot = function () {
|
EmbedController.prototype.openSnapshot = function () {
|
||||||
if (!this.snapshotOverlay) {
|
var self = this,
|
||||||
this.snapShotOverlay = new SnapshotOverlay(this.embed, this.formatTime);
|
snapshot = new Vue({
|
||||||
} else {
|
template: SnapshotTemplate,
|
||||||
this.snapShotOverlay = undefined;
|
data: function () {
|
||||||
|
return {
|
||||||
|
embed: self.embed
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatTime: self.formatTime
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function onDestroyCallback() {
|
||||||
|
snapshot.$destroy(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.openmct.OverlayService.show(snapshot.$mount().$el, {onDestroy: onDestroyCallback, cssClass: 'l-large-view'});
|
||||||
};
|
};
|
||||||
|
|
||||||
EmbedController.prototype.formatTime = function (unixTime, timeFormat) {
|
EmbedController.prototype.formatTime = function (unixTime, timeFormat) {
|
||||||
|
@ -60,6 +60,7 @@ function (
|
|||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
||||||
var notebookEmbed = {
|
var notebookEmbed = {
|
||||||
|
inject:['openmct'],
|
||||||
props:['embed', 'entry'],
|
props:['embed', 'entry'],
|
||||||
template: EmbedTemplate,
|
template: EmbedTemplate,
|
||||||
data: embedController.exposedData,
|
data: embedController.exposedData,
|
||||||
@ -80,6 +81,7 @@ function (
|
|||||||
|
|
||||||
var notebookVue = Vue.extend({
|
var notebookVue = Vue.extend({
|
||||||
template: NotebookTemplate,
|
template: NotebookTemplate,
|
||||||
|
provide: {openmct: self.openmct},
|
||||||
components: {
|
components: {
|
||||||
'notebook-entry': entryComponent,
|
'notebook-entry': entryComponent,
|
||||||
'search': search.default
|
'search': search.default
|
||||||
|
@ -35,6 +35,7 @@ define([
|
|||||||
'./telemetryTable/plugin',
|
'./telemetryTable/plugin',
|
||||||
'./staticRootPlugin/plugin',
|
'./staticRootPlugin/plugin',
|
||||||
'./notebook/plugin',
|
'./notebook/plugin',
|
||||||
|
'./displayLayout/plugin',
|
||||||
'./folderView/plugin'
|
'./folderView/plugin'
|
||||||
], function (
|
], function (
|
||||||
_,
|
_,
|
||||||
@ -51,6 +52,7 @@ define([
|
|||||||
TelemetryTablePlugin,
|
TelemetryTablePlugin,
|
||||||
StaticRootPlugin,
|
StaticRootPlugin,
|
||||||
Notebook,
|
Notebook,
|
||||||
|
DisplayLayoutPlugin,
|
||||||
FolderView
|
FolderView
|
||||||
) {
|
) {
|
||||||
var bundleMap = {
|
var bundleMap = {
|
||||||
@ -161,6 +163,7 @@ define([
|
|||||||
plugins.TelemetryMean = TelemetryMean;
|
plugins.TelemetryMean = TelemetryMean;
|
||||||
plugins.URLIndicator = URLIndicatorPlugin;
|
plugins.URLIndicator = URLIndicatorPlugin;
|
||||||
plugins.Notebook = Notebook;
|
plugins.Notebook = Notebook;
|
||||||
|
plugins.DisplayLayout = DisplayLayoutPlugin.default;
|
||||||
plugins.FolderView = FolderView;
|
plugins.FolderView = FolderView;
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
|
@ -264,7 +264,7 @@ define([
|
|||||||
this.applyStyle($('#widget', this.domElement), activeRule.getProperty('style'));
|
this.applyStyle($('#widget', this.domElement), activeRule.getProperty('style'));
|
||||||
$('#widget', this.domElement).prop('title', activeRule.getProperty('message'));
|
$('#widget', this.domElement).prop('title', activeRule.getProperty('message'));
|
||||||
$('#widgetLabel', this.domElement).html(activeRule.getProperty('label'));
|
$('#widgetLabel', this.domElement).html(activeRule.getProperty('label'));
|
||||||
$('#widgetLabel', this.domElement).removeClass().addClass('label widget-label ' + activeRule.getProperty('icon'));
|
$('#widgetLabel', this.domElement).removeClass().addClass('label widget-label c-summary-widget__label ' + activeRule.getProperty('icon'));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,7 +18,7 @@ define([
|
|||||||
this.widget.title = datum.message;
|
this.widget.title = datum.message;
|
||||||
this.label.title = datum.message;
|
this.label.title = datum.message;
|
||||||
this.label.innerHTML = datum.ruleLabel;
|
this.label.innerHTML = datum.ruleLabel;
|
||||||
this.label.className = 'label widget-label ' + datum.icon;
|
this.label.className = 'label widget-label c-summary-widget__label ' + datum.icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
SummaryWidgetView.prototype.render = function () {
|
SummaryWidgetView.prototype.render = function () {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div class="w-summary-widget s-status-no-data">
|
<div class="w-summary-widget s-status-no-data c-widget-wrapper u-contents">
|
||||||
<a class="t-summary-widget l-summary-widget s-summary-widget labeled">
|
<a class="t-summary-widget c-button c-summary-widget u-links u-fills-container">
|
||||||
<span class="label widget-label">Loading...</span>
|
<span class="label widget-label c-summary-widget__label">Loading...</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,30 +33,6 @@ define([
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
function TableConfigurationViewProvider(openmct) {
|
function TableConfigurationViewProvider(openmct) {
|
||||||
let instantiateService;
|
|
||||||
|
|
||||||
function isBeingEdited(object) {
|
|
||||||
let oldStyleObject = getOldStyleObject(object);
|
|
||||||
|
|
||||||
return oldStyleObject.hasCapability('editor') &&
|
|
||||||
oldStyleObject.getCapability('editor').inEditContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOldStyleObject(object) {
|
|
||||||
let oldFormatModel = objectUtils.toOldFormat(object);
|
|
||||||
let oldFormatId = objectUtils.makeKeyString(object.identifier);
|
|
||||||
|
|
||||||
return instantiate(oldFormatModel, oldFormatId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function instantiate(model, id) {
|
|
||||||
if (!instantiateService) {
|
|
||||||
instantiateService = openmct.$injector.get('instantiate');
|
|
||||||
}
|
|
||||||
return instantiateService(model, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key: 'table-configuration',
|
key: 'table-configuration',
|
||||||
name: 'Telemetry Table Configuration',
|
name: 'Telemetry Table Configuration',
|
||||||
@ -65,8 +41,7 @@ define([
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let object = selection[0].context.item;
|
let object = selection[0].context.item;
|
||||||
return object.type === 'table' &&
|
return object.type === 'table';
|
||||||
isBeingEdited(object);
|
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let component;
|
let component;
|
||||||
@ -86,7 +61,7 @@ define([
|
|||||||
el: element
|
el: element
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
destroy: function (element) {
|
destroy: function () {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
component = undefined;
|
component = undefined;
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,10 @@
|
|||||||
define([
|
define([
|
||||||
'lodash',
|
'lodash',
|
||||||
'EventEmitter',
|
'EventEmitter',
|
||||||
'./TelemetryTableColumn',
|
'./TelemetryTableColumn'
|
||||||
], function (_, EventEmitter, TelemetryTableColumn) {
|
], function (_, EventEmitter, TelemetryTableColumn) {
|
||||||
|
|
||||||
class TelemetryTableConfiguration extends EventEmitter{
|
class TelemetryTableConfiguration extends EventEmitter {
|
||||||
constructor(domainObject, openmct) {
|
constructor(domainObject, openmct) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -37,6 +37,8 @@ define([
|
|||||||
this.addColumnsForObject = this.addColumnsForObject.bind(this);
|
this.addColumnsForObject = this.addColumnsForObject.bind(this);
|
||||||
this.removeColumnsForObject = this.removeColumnsForObject.bind(this);
|
this.removeColumnsForObject = this.removeColumnsForObject.bind(this);
|
||||||
this.objectMutated = this.objectMutated.bind(this);
|
this.objectMutated = this.objectMutated.bind(this);
|
||||||
|
//Make copy of configuration, otherwise change detection is impossible if shared instance is being modified.
|
||||||
|
this.oldConfiguration = JSON.parse(JSON.stringify(this.getConfiguration()));
|
||||||
|
|
||||||
this.unlistenFromMutation = openmct.objects.observe(domainObject, '*', this.objectMutated);
|
this.unlistenFromMutation = openmct.objects.observe(domainObject, '*', this.objectMutated);
|
||||||
}
|
}
|
||||||
@ -56,11 +58,11 @@ define([
|
|||||||
* @param {*} object
|
* @param {*} object
|
||||||
*/
|
*/
|
||||||
objectMutated(object) {
|
objectMutated(object) {
|
||||||
let oldConfiguration = this.domainObject.configuration;
|
|
||||||
|
|
||||||
//Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible.
|
//Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible.
|
||||||
this.domainObject = JSON.parse(JSON.stringify(object));
|
this.domainObject = object;
|
||||||
if (!_.eq(object.configuration, oldConfiguration)){
|
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()));
|
||||||
this.emit('change', object.configuration);
|
this.emit('change', object.configuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="grid-properties">
|
<div class="c-properties" v-if="isEditing">
|
||||||
<!--form class="form" -->
|
<div class="c-properties__header">Table Columns</div>
|
||||||
<ul class="l-inspector-part">
|
<ul class="c-properties__section">
|
||||||
<h2>Table Columns</h2>
|
<li class="c-properties__row" v-for="(title, key) in headers">
|
||||||
<li class="grid-row" v-for="(title, key) in headers">
|
<div class="c-properties__label" title="Show or Hide Column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
|
||||||
<div class="grid-cell label" title="Show or Hide Column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
|
<div class="c-properties__value"><input type="checkbox" :id="key + 'ColumnControl'" :checked="configuration.hiddenColumns[key] !== true" @change="toggleColumn(key)"></div>
|
||||||
<div class="grid-cell value"><input type="checkbox" :id="key + 'ColumnControl'" :checked="configuration.hiddenColumns[key] !== true" @change="toggleColumn(key)"></div>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
<!--/form -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -21,6 +19,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
headers: {},
|
headers: {},
|
||||||
|
isEditing: this.openmct.editor.isEditing(),
|
||||||
configuration: this.tableConfiguration.getConfiguration()
|
configuration: this.tableConfiguration.getConfiguration()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -41,11 +40,14 @@ export default {
|
|||||||
removeObject(objectIdentifier) {
|
removeObject(objectIdentifier) {
|
||||||
this.tableConfiguration.removeColumnsForObject(objectIdentifier, true);
|
this.tableConfiguration.removeColumnsForObject(objectIdentifier, true);
|
||||||
this.updateHeaders(this.tableConfiguration.getAllHeaders());
|
this.updateHeaders(this.tableConfiguration.getAllHeaders());
|
||||||
|
},
|
||||||
|
toggleEdit(isEditing) {
|
||||||
|
this.isEditing = isEditing;
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.unlisteners = [];
|
this.unlisteners = [];
|
||||||
|
this.openmct.editor.on('isEditing', this.toggleEdit);
|
||||||
let compositionCollection = this.openmct.composition.get(this.tableConfiguration.domainObject);
|
let compositionCollection = this.openmct.composition.get(this.tableConfiguration.domainObject);
|
||||||
|
|
||||||
compositionCollection.load()
|
compositionCollection.load()
|
||||||
@ -62,6 +64,7 @@ export default {
|
|||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.tableConfiguration.destroy();
|
this.tableConfiguration.destroy();
|
||||||
|
this.openmct.editor.off('isEditing', this.toggleEdit);
|
||||||
this.unlisteners.forEach((unlisten) => unlisten());
|
this.unlisteners.forEach((unlisten) => unlisten());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,65 +27,61 @@
|
|||||||
|
|
||||||
<ConductorModeIcon class="c-conductor__mode-icon"></ConductorModeIcon>
|
<ConductorModeIcon class="c-conductor__mode-icon"></ConductorModeIcon>
|
||||||
|
|
||||||
<div class="c-conductor__start-input">
|
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start-fixed"
|
||||||
<!-- Start input and controls -->
|
v-if="isFixed">
|
||||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start__fixed"
|
<!-- Fixed start -->
|
||||||
v-if="isFixed">
|
<div class="c-conductor__start-fixed__label">Start</div>
|
||||||
<!-- Fixed input -->
|
<input class="c-input--datetime"
|
||||||
<div class="c-conductor__start__fixed__label">Start</div>
|
type="text" autocorrect="off" spellcheck="false"
|
||||||
<input class="c-input--datetime"
|
ref="startDate"
|
||||||
type="text" autocorrect="off" spellcheck="false"
|
v-model="formattedBounds.start"
|
||||||
ref="startDate"
|
@change="validateBounds('start', $event.target); setBoundsFromView()" />
|
||||||
v-model="formattedBounds.start"
|
<date-picker
|
||||||
@change="validateBounds('start', $event.target); setBoundsFromView()" />
|
:default-date-time="formattedBounds.start"
|
||||||
<date-picker
|
:formatter="timeFormatter"
|
||||||
:default-date-time="formattedBounds.start"
|
@date-selected="startDateSelected"></date-picker>
|
||||||
:formatter="timeFormatter"
|
|
||||||
@date-selected="startDateSelected"></date-picker>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start__delta"
|
|
||||||
v-if="!isFixed">
|
|
||||||
<!-- RT input -->
|
|
||||||
<div class="c-direction-indicator icon-minus"></div>
|
|
||||||
<input class="c-input--hrs-min-sec"
|
|
||||||
type="text" autocorrect="off"
|
|
||||||
spellcheck="false"
|
|
||||||
v-model="offsets.start"
|
|
||||||
@change="validateOffsets($event); setOffsetsFromView()">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="c-conductor__end-input">
|
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start-delta"
|
||||||
<!-- End input and controls -->
|
v-if="!isFixed">
|
||||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end__fixed"
|
<!-- RT start -->
|
||||||
v-if="isFixed">
|
<div class="c-direction-indicator icon-minus"></div>
|
||||||
<!-- Fixed input -->
|
<input class="c-input--hrs-min-sec"
|
||||||
<div class="c-conductor__end__fixed__label">End</div>
|
type="text" autocorrect="off"
|
||||||
<input class="c-input--datetime"
|
spellcheck="false"
|
||||||
type="text" autocorrect="off" spellcheck="false"
|
v-model="offsets.start"
|
||||||
v-model="formattedBounds.end"
|
@change="validateOffsets($event); setOffsetsFromView()">
|
||||||
:disabled="!isFixed"
|
</div>
|
||||||
ref="endDate"
|
|
||||||
@change="validateBounds('end', $event.target); setBoundsFromView()">
|
|
||||||
<date-picker
|
|
||||||
class="c-ctrl-wrapper--menus-left"
|
|
||||||
:default-date-time="formattedBounds.end"
|
|
||||||
:formatter="timeFormatter"
|
|
||||||
@date-selected="endDateSelected"></date-picker>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end__delta"
|
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end-fixed">
|
||||||
v-if="!isFixed">
|
<!-- Fixed end and RT 'last update' display -->
|
||||||
<!-- RT input -->
|
<div class="c-conductor__end-fixed__label">
|
||||||
<div class="c-direction-indicator icon-plus"></div>
|
{{ isFixed ? 'End' : 'Updated' }}
|
||||||
<input class="c-input--hrs-min-sec"
|
|
||||||
type="text"
|
|
||||||
autocorrect="off"
|
|
||||||
spellcheck="false"
|
|
||||||
v-model="offsets.end"
|
|
||||||
@change="validateOffsets($event); setOffsetsFromView()">
|
|
||||||
</div>
|
</div>
|
||||||
|
<input class="c-input--datetime"
|
||||||
|
type="text" autocorrect="off" spellcheck="false"
|
||||||
|
v-model="formattedBounds.end"
|
||||||
|
:disabled="!isFixed"
|
||||||
|
ref="endDate"
|
||||||
|
@change="validateBounds('end', $event.target); setBoundsFromView()">
|
||||||
|
<date-picker
|
||||||
|
class="c-ctrl-wrapper--menus-left"
|
||||||
|
:default-date-time="formattedBounds.end"
|
||||||
|
:formatter="timeFormatter"
|
||||||
|
@date-selected="endDateSelected"
|
||||||
|
v-if="isFixed"></date-picker>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end-delta"
|
||||||
|
v-if="!isFixed">
|
||||||
|
<!-- RT end -->
|
||||||
|
<div class="c-direction-indicator icon-plus"></div>
|
||||||
|
<input class="c-input--hrs-min-sec"
|
||||||
|
type="text"
|
||||||
|
autocorrect="off"
|
||||||
|
spellcheck="false"
|
||||||
|
v-model="offsets.end"
|
||||||
|
@change="validateOffsets($event); setOffsetsFromView()">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<conductor-axis
|
<conductor-axis
|
||||||
@ -112,65 +108,28 @@
|
|||||||
grid-row-gap: $interiorMargin;
|
grid-row-gap: $interiorMargin;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
// Default: fixed mode, desktop
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr 1fr;
|
||||||
grid-template-columns: 20px auto 1fr auto;
|
grid-template-columns: 20px auto 1fr auto;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"tc-mode-icon tc-start tc-ticks tc-end"
|
"tc-mode-icon tc-start tc-ticks tc-end"
|
||||||
"tc-controls tc-controls tc-controls tc-controls";
|
"tc-controls tc-controls tc-controls tc-controls";
|
||||||
|
|
||||||
.c-conductor__end-input {
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.phone.portrait & {
|
|
||||||
&.is-fixed-mode {
|
|
||||||
grid-row-gap: $interiorMargin;
|
|
||||||
grid-template-rows: auto auto auto;
|
|
||||||
grid-template-columns: 20px auto;
|
|
||||||
grid-template-areas:
|
|
||||||
"tc-mode-icon tc-start"
|
|
||||||
"tc-mode-icon tc-end"
|
|
||||||
"tc-mode-icon tc-controls";
|
|
||||||
|
|
||||||
.c-conductor {
|
|
||||||
&__mode-icon {
|
|
||||||
grid-row: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__ticks,
|
|
||||||
&__zoom {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-input [class*='__label'] {
|
|
||||||
// Start and end are in separate columns; make the labels line up
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__end-input {
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__mode-icon {
|
&__mode-icon {
|
||||||
grid-area: tc-mode-icon;
|
grid-area: tc-mode-icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__start-input,
|
&__start-fixed,
|
||||||
&__end-input {
|
&__start-delta {
|
||||||
|
grid-area: tc-start;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__start-input {
|
&__end-fixed,
|
||||||
grid-area: tc-start;
|
&__end-delta {
|
||||||
}
|
|
||||||
|
|
||||||
&__end-input {
|
|
||||||
grid-area: tc-end;
|
grid-area: tc-end;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__ticks {
|
&__ticks {
|
||||||
@ -186,12 +145,68 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[class*='__delta'] {
|
[class*='-delta'] {
|
||||||
&:before {
|
&:before {
|
||||||
content: $glyph-icon-clock;
|
content: $glyph-icon-clock;
|
||||||
font-family: symbolsfont;
|
font-family: symbolsfont;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-realtime-mode {
|
||||||
|
grid-template-columns: 20px auto 1fr auto auto;
|
||||||
|
grid-template-areas:
|
||||||
|
"tc-mode-icon tc-start tc-ticks tc-updated tc-end"
|
||||||
|
"tc-controls tc-controls tc-controls tc-controls tc-controls";
|
||||||
|
|
||||||
|
.c-conductor__end-fixed {
|
||||||
|
grid-area: tc-updated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.phone.portrait & {
|
||||||
|
grid-row-gap: $interiorMargin;
|
||||||
|
grid-template-rows: auto auto auto;
|
||||||
|
grid-template-columns: 20px auto auto;
|
||||||
|
|
||||||
|
&__mode-icon {
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__ticks,
|
||||||
|
&__zoom {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-fixed-mode {
|
||||||
|
[class*='__start-fixed'],
|
||||||
|
[class*='__end-fixed'] {
|
||||||
|
[class*='__label'] {
|
||||||
|
// Start and end are in separate columns; make the labels line up
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*='__end-input'] {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid-template-areas:
|
||||||
|
"tc-mode-icon tc-start tc-start"
|
||||||
|
"tc-mode-icon tc-end tc-end"
|
||||||
|
"tc-mode-icon tc-controls tc-controls";
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-realtime-mode {
|
||||||
|
grid-template-areas:
|
||||||
|
"tc-mode-icon tc-start tc-updated"
|
||||||
|
"tc-mode-icon tc-end tc-end"
|
||||||
|
"tc-mode-icon tc-controls tc-controls";
|
||||||
|
|
||||||
|
.c-conductor__end-fixed {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-conductor-input {
|
.c-conductor-input {
|
||||||
@ -215,16 +230,39 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
input:invalid {
|
input:invalid {
|
||||||
background: rgba($colorFormInvalid, 0.3);
|
background: rgba($colorFormInvalid, 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-realtime-mode {
|
.is-realtime-mode {
|
||||||
|
button {
|
||||||
|
@include themedButton($colorTimeBg);
|
||||||
|
color: $colorTimeFg;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $colorTimeHov !important;
|
||||||
|
color: $colorTimeFg !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.c-conductor-input {
|
.c-conductor-input {
|
||||||
&:before {
|
&:before {
|
||||||
color: $colorTime;
|
color: $colorTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.c-conductor__end-fixed {
|
||||||
|
// Displays last RT udpate
|
||||||
|
color: $colorTime;
|
||||||
|
|
||||||
|
input {
|
||||||
|
// Remove input look
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
color: $colorTime;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@ -396,5 +434,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
@include bgTicks($c: rgba($colorBodyFg, 0.4));
|
@include bgTicks($c: rgba($colorBodyFg, 0.4));
|
||||||
background-position: 0 50%;
|
background-position: 0 50%;
|
||||||
background-size: 5px 2px;
|
background-size: 5px 2px;
|
||||||
|
border-radius: $controlCr;
|
||||||
height: $h;
|
height: $h;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
@ -76,34 +77,37 @@
|
|||||||
body.desktop .is-fixed-mode & {
|
body.desktop .is-fixed-mode & {
|
||||||
@include cursorGrab();
|
@include cursorGrab();
|
||||||
background-size: 3px 30%;
|
background-size: 3px 30%;
|
||||||
border-radius: $controlCr;
|
|
||||||
background-color: $colorBodyBgSubtle;
|
background-color: $colorBodyBgSubtle;
|
||||||
box-shadow: inset rgba(black, 0.2) 0 1px 1px;
|
box-shadow: inset rgba(black, 0.4) 0 1px 1px;
|
||||||
|
transition: $transOut;
|
||||||
|
|
||||||
svg text {
|
svg text {
|
||||||
fill: $colorBodyFg;
|
fill: $colorBodyFg;
|
||||||
stroke: $colorBodyBgSubtle;
|
stroke: $colorBodyBgSubtle;
|
||||||
|
transition: $transOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:active {
|
&:active {
|
||||||
$c: $colorKeySubtle;
|
$c: $colorKeySubtle;
|
||||||
background-color: $c;
|
background-color: $c;
|
||||||
|
transition: $transIn;
|
||||||
svg text {
|
svg text {
|
||||||
stroke: $c;
|
stroke: $c;
|
||||||
|
transition: $transIn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-realtime-mode & {
|
.is-realtime-mode & {
|
||||||
|
$c: 1px solid rgba($colorTime, 0.7);
|
||||||
|
border-left: $c;
|
||||||
|
border-right: $c;
|
||||||
svg text {
|
svg text {
|
||||||
fill: $colorTime;
|
fill: $colorTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -21,10 +21,10 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
<template>
|
<template>
|
||||||
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
|
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
|
||||||
<div class="c-button--menu c-mode-button"
|
<button class="c-button--menu c-mode-button"
|
||||||
@click="toggleMenu($event)">
|
@click="toggleMenu($event)">
|
||||||
<span class="c-button__label">{{selectedMode.name}}</span>
|
<span class="c-button__label">{{selectedMode.name}}</span>
|
||||||
</div>
|
</button>
|
||||||
<div class="c-menu c-super-menu c-conductor__mode-menu"
|
<div class="c-menu c-super-menu c-conductor__mode-menu"
|
||||||
v-if="showMenu">
|
v-if="showMenu">
|
||||||
<div class="c-super-menu__menu">
|
<div class="c-super-menu__menu">
|
||||||
@ -66,16 +66,6 @@
|
|||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-realtime-mode {
|
|
||||||
.c-mode-button {
|
|
||||||
background: $colorTimeBg;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $colorTimeHov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -22,11 +22,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up"
|
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up"
|
||||||
v-if="selectedTimeSystem.name">
|
v-if="selectedTimeSystem.name">
|
||||||
<div class="c-button--menu c-time-system-button"
|
<button class="c-button--menu c-time-system-button"
|
||||||
:class="selectedTimeSystem.cssClass"
|
:class="selectedTimeSystem.cssClass"
|
||||||
@click="toggleMenu($event)">
|
@click="toggleMenu($event)">
|
||||||
<span class="c-button__label">{{selectedTimeSystem.name}}</span>
|
<span class="c-button__label">{{selectedTimeSystem.name}}</span>
|
||||||
</div>
|
</button>
|
||||||
<div class="c-menu" v-if="showMenu">
|
<div class="c-menu" v-if="showMenu">
|
||||||
<ul>
|
<ul>
|
||||||
<li @click="setTimeSystemFromView(timeSystem)"
|
<li @click="setTimeSystemFromView(timeSystem)"
|
||||||
@ -40,20 +40,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "~styles/sass-base";
|
|
||||||
|
|
||||||
.is-realtime-mode {
|
|
||||||
.c-time-system-button {
|
|
||||||
background: $colorTimeBg;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $colorTimeHov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'configuration'],
|
inject: ['openmct', 'configuration'],
|
||||||
|
@ -108,7 +108,7 @@
|
|||||||
grid-gap: 1px;
|
grid-gap: 1px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
$mutedOpacity: 0.7;
|
$mutedOpacity: 0.5;
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
display: contents;
|
display: contents;
|
||||||
@ -127,7 +127,7 @@
|
|||||||
padding: $interiorMargin;
|
padding: $interiorMargin;
|
||||||
|
|
||||||
&.is-in-month {
|
&.is-in-month {
|
||||||
background: rgba($colorBodyFg, 0.1);
|
background: $colorMenuElementHilite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ define(['EventEmitter'], function (EventEmitter) {
|
|||||||
this.selected[0].element.classList.remove('s-selected');
|
this.selected[0].element.classList.remove('s-selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selected[1]) {
|
if (this.selected[1] && this.selected[1].element) {
|
||||||
this.selected[1].element.classList.remove('s-selected-parent');
|
this.selected[1].element.classList.remove('s-selected-parent');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ define(['EventEmitter'], function (EventEmitter) {
|
|||||||
selectable[0].element.classList.add('s-selected');
|
selectable[0].element.classList.add('s-selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectable[1]) {
|
if (selectable[1] && selectable[1].element) {
|
||||||
selectable[1].element.classList.add('s-selected-parent');
|
selectable[1].element.classList.add('s-selected-parent');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ define(['EventEmitter'], function (EventEmitter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function () {
|
return function () {
|
||||||
element.removeEventListener('click', capture);
|
element.removeEventListener('click', capture, true);
|
||||||
element.removeEventListener('click', selectCapture);
|
element.removeEventListener('click', selectCapture);
|
||||||
|
|
||||||
if (unlisten) {
|
if (unlisten) {
|
||||||
|
330
src/styles-new/_constants-espresso.scss
Normal file
330
src/styles-new/_constants-espresso.scss
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/************************************************** ESPRESSO THEME CONSTANTS */
|
||||||
|
|
||||||
|
@import "constants";
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
@function buttonBg($c: $colorBtnBg) {
|
||||||
|
@return linear-gradient(lighten($c, 5%), $c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
$fontBaseSize: 12px;
|
||||||
|
$smallCr: 2px;
|
||||||
|
$controlCr: 3px;
|
||||||
|
$basicCr: 4px;
|
||||||
|
|
||||||
|
// Base colors
|
||||||
|
$colorBodyBg: #393939;
|
||||||
|
$colorBodyFg: #aaa;
|
||||||
|
$colorGenBg: #222;
|
||||||
|
$colorHeadBg: #262626;
|
||||||
|
$colorHeadFg: $colorBodyFg;
|
||||||
|
$colorStatusBarBg: $colorHeadBg;
|
||||||
|
$colorStatusBarFg: $colorBodyFg;
|
||||||
|
$colorStatusBarFgHov: #aaa;
|
||||||
|
$colorKey: #0099cc;
|
||||||
|
$colorKeyFg: #fff;
|
||||||
|
$colorKeyHov: #00c0f6;
|
||||||
|
$colorKeyFilter: brightness(1) sepia(1) hue-rotate(145deg) saturate(6);
|
||||||
|
$colorKeyFilterHov: brightness(1) sepia(1) hue-rotate(145deg) saturate(7);
|
||||||
|
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
||||||
|
$colorA: #ccc;
|
||||||
|
$colorAHov: #fff;
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
$shellMainPad: 4px 0;
|
||||||
|
$shellPanePad: $interiorMargin, 7px; // TODO: Sync this with Snow theme
|
||||||
|
|
||||||
|
// Status colors, mainly used for messaging and item ancillary symbols
|
||||||
|
$colorStatusFg: #999;
|
||||||
|
$colorStatusDefault: #ccc;
|
||||||
|
$colorStatusInfo: #60ba7b;
|
||||||
|
$colorStatusAlert: #ffb66c;
|
||||||
|
$colorStatusError: #da0004;
|
||||||
|
$colorStatusBtnBg: #666;
|
||||||
|
|
||||||
|
// States
|
||||||
|
$colorPausedBg: #ff9900;
|
||||||
|
$colorPausedFg: #fff;
|
||||||
|
$colorOk: #33cc33;
|
||||||
|
|
||||||
|
// Base variations
|
||||||
|
$colorBodyBgSubtle: lighten($colorBodyBg, 5%);
|
||||||
|
$colorBodyBgSubtleHov: darken($colorKey, 50%);
|
||||||
|
$colorKeySubtle: darken($colorKey, 10%);
|
||||||
|
|
||||||
|
// Time Colors
|
||||||
|
$colorTime: #618cff;
|
||||||
|
$colorTimeBg: $colorTime;
|
||||||
|
$colorTimeFg: lighten($colorTimeBg, 30%);
|
||||||
|
$colorTimeHov: lighten($colorTime, 10%);
|
||||||
|
$colorTimeSubtle: darken($colorTime, 20%);
|
||||||
|
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
|
||||||
|
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
|
||||||
|
|
||||||
|
// Edit Colors
|
||||||
|
$editColor: #00c7c3;
|
||||||
|
$editColorFg: $colorBodyFg;
|
||||||
|
$browseBorderSelectableHov: 1px dotted rgba($colorBodyFg, 0.2);
|
||||||
|
$browseShdwSelectableHov: rgba($colorBodyFg, 0.2) 0 0 3px;
|
||||||
|
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
|
||||||
|
$editBorderSelectable: 1px dotted rgba($editColor, 1);
|
||||||
|
$editBorderSelectableHov: 1px dashed rgba($editColor, 1);
|
||||||
|
$editBorderSelected: 1px solid $editColor;
|
||||||
|
$editBorderDrilledIn: 1px dashed #ff4d9a;
|
||||||
|
$colorGridLines: rgba($editColor, 0.2);
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
$colorIconAlias: #4af6f3;
|
||||||
|
$colorIconAliasForKeyFilter: #aaa;
|
||||||
|
$colorProgressBarOuter: rgba(#000, 0.1);
|
||||||
|
$colorProgressBarAmt: #0a0;
|
||||||
|
|
||||||
|
// Buttons and Controls
|
||||||
|
$colorBtnBg: lighten($colorBodyBg, 10%); // !
|
||||||
|
$colorBtnBgHov: lighten($colorBtnBg, 10%); // !
|
||||||
|
$colorBtnFg: lighten($colorBodyFg, 10%); // !
|
||||||
|
$colorBtnFgHov: $colorBtnFg;
|
||||||
|
$colorBtnMajorBg: $colorKey;
|
||||||
|
$colorBtnMajorBgHov: $colorKeyHov;
|
||||||
|
$colorBtnMajorFg: $colorKeyFg;
|
||||||
|
$colorBtnMajorFgHov: darken($colorBtnMajorFg, 10%);
|
||||||
|
$colorBtnCautionBg: #f16f6f;
|
||||||
|
$colorBtnCautionBgHov: #f1504e;
|
||||||
|
$colorBtnCautionFg: $colorBtnFg;
|
||||||
|
$colorClickIcon: $colorKey;
|
||||||
|
$colorClickIconBgHov: rgba($colorKey, 0.6);
|
||||||
|
$colorClickIconFgHov: $colorKeyHov;
|
||||||
|
|
||||||
|
// Menus
|
||||||
|
$colorMenuBg: lighten($colorBodyBg, 20%);
|
||||||
|
$colorMenuFg: lighten($colorBodyFg, 30%);
|
||||||
|
$colorMenuIc: lighten($colorKey, 15%);
|
||||||
|
$colorMenuHovBg: $colorMenuIc;
|
||||||
|
$colorMenuHovFg: lighten($colorMenuFg, 10%);
|
||||||
|
$colorMenuHovIc: $colorMenuHovFg;
|
||||||
|
$colorMenuElementHilite: lighten($colorMenuBg, 10%);
|
||||||
|
$shdwMenu: rgba(black, 0.5) 0 1px 5px;
|
||||||
|
$shdwMenuText: none;
|
||||||
|
$menuItemPad: $interiorMargin, floor($interiorMargin * 1.25);
|
||||||
|
|
||||||
|
// Palettes and Swatches
|
||||||
|
$paletteItemBorderOuterColorSelected: black;
|
||||||
|
$paletteItemBorderInnerColorSelected: white;
|
||||||
|
$paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
|
||||||
|
|
||||||
|
// Form colors
|
||||||
|
$colorCheck: $colorKey;
|
||||||
|
$colorFormRequired: $colorKey;
|
||||||
|
$colorFormValid: $colorOk;
|
||||||
|
$colorFormError: #990000;
|
||||||
|
$colorFormInvalid: #ff2200;
|
||||||
|
$colorFormFieldErrorBg: $colorFormError;
|
||||||
|
$colorFormFieldErrorFg: rgba(#fff, 0.6);
|
||||||
|
$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%);
|
||||||
|
$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%);
|
||||||
|
$colorInspectorFg: $colorBodyFg;
|
||||||
|
$colorInspectorPropName: darken($colorBodyFg, 20%);
|
||||||
|
$colorInspectorPropVal: lighten($colorInspectorFg, 15%);
|
||||||
|
$colorInspectorSectionHeaderBg: lighten($colorInspectorBg, 5%);
|
||||||
|
$colorInspectorSectionHeaderFg: lighten($colorInspectorBg, 40%);
|
||||||
|
|
||||||
|
// Overlay
|
||||||
|
$overlayColorBg: $colorMenuBg;
|
||||||
|
$overlayColorFg: $colorMenuFg;
|
||||||
|
$overlayButtonColorBg: lighten($overlayColorBg, 20%);
|
||||||
|
$overlayButtonColorFg: #fff;
|
||||||
|
$overlayCr: $interiorMarginLg;
|
||||||
|
|
||||||
|
// Indicator colors
|
||||||
|
$colorIndicatorAvailable: $colorKey;
|
||||||
|
$colorIndicatorDisabled: #444;
|
||||||
|
$colorIndicatorOn: $colorOk;
|
||||||
|
$colorIndicatorOff: #666;
|
||||||
|
|
||||||
|
// Limits and staleness colors//
|
||||||
|
$colorTelemFresh: lighten($colorBodyFg, 20%);
|
||||||
|
$colorTelemStale: darken($colorBodyFg, 20%);
|
||||||
|
$styleTelemStale: italic;
|
||||||
|
$colorLimitYellowBg: rgba(#ffaa00, 0.3);
|
||||||
|
$colorLimitYellowIc: #ffaa00;
|
||||||
|
$colorLimitRedBg: rgba(red, 0.3);
|
||||||
|
$colorLimitRedIc: red;
|
||||||
|
|
||||||
|
// Bubble colors
|
||||||
|
$colorInfoBubbleBg: $colorMenuBg;
|
||||||
|
$colorInfoBubbleFg: #666;
|
||||||
|
|
||||||
|
// Items
|
||||||
|
$colorItemBg: buttonBg($colorBtnBg);
|
||||||
|
$colorItemBgHov: buttonBg(lighten($colorBtnBg, 5%));
|
||||||
|
$colorListItemBg: transparent;
|
||||||
|
$colorListItemBgHov: rgba($colorKey, 0.1);
|
||||||
|
$colorItemFg: $colorBtnFg;
|
||||||
|
$colorItemFgDetails: darken($colorItemFg, 20%);
|
||||||
|
$shdwItemText: none;
|
||||||
|
|
||||||
|
// Tabular
|
||||||
|
$colorTabBorder: lighten($colorBodyBg, 10%);
|
||||||
|
$colorTabBodyBg: $colorBodyBg;
|
||||||
|
$colorTabBodyFg: lighten($colorBodyFg, 20%);
|
||||||
|
$colorTabHeaderBg: lighten($colorBodyBg, 10%);
|
||||||
|
$colorTabHeaderFg: lighten($colorBodyFg, 20%);
|
||||||
|
$colorTabHeaderBorder: $colorBodyBg;
|
||||||
|
|
||||||
|
// Plot
|
||||||
|
$colorPlotBg: rgba(black, 0.05);
|
||||||
|
$colorPlotFg: $colorBodyFg;
|
||||||
|
$colorPlotHash: black;
|
||||||
|
$opacityPlotHash: 0.2;
|
||||||
|
$stylePlotHash: dashed;
|
||||||
|
$colorPlotAreaBorder: $colorInteriorBorder;
|
||||||
|
$colorPlotLabelFg: darken($colorPlotFg, 20%);
|
||||||
|
$legendCollapsedNameMaxW: 50%;
|
||||||
|
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
|
||||||
|
|
||||||
|
// Tree
|
||||||
|
$colorTreeBg: transparent;
|
||||||
|
$colorItemTreeHoverBg: lighten($colorBodyBg, 10%);
|
||||||
|
$colorItemTreeHoverFg: lighten($colorBodyFg, 10%);
|
||||||
|
$colorItemTreeIcon: $colorKey; // Used
|
||||||
|
$colorItemTreeIconHover: $colorItemTreeIcon; // Used
|
||||||
|
$colorItemTreeFg: $colorBodyFg;
|
||||||
|
$colorItemTreeSelectedBg: darken($colorKey, 15%);
|
||||||
|
$colorItemTreeSelectedFg: $colorBodyBg;
|
||||||
|
$colorItemTreeEditingBg: $editColor;
|
||||||
|
$colorItemTreeEditingFg: $editColorFg;
|
||||||
|
$colorItemTreeVC: $colorBodyFg;
|
||||||
|
$colorItemTreeVCHover: $colorKey;
|
||||||
|
$shdwItemTreeIcon: none;
|
||||||
|
|
||||||
|
// Images
|
||||||
|
$colorThumbHoverBg: $colorItemTreeHoverBg;
|
||||||
|
|
||||||
|
// Scrollbar
|
||||||
|
$scrollbarTrackSize: 7px;
|
||||||
|
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
|
||||||
|
$scrollbarTrackColorBg: rgba(#000, 0.2);
|
||||||
|
$scrollbarThumbColor: darken($colorBodyBg, 50%);
|
||||||
|
$scrollbarThumbColorHov: $colorKey;
|
||||||
|
$scrollbarThumbColorMenu: lighten($colorMenuBg, 10%);
|
||||||
|
$scrollbarThumbColorMenuHov: lighten($scrollbarThumbColorMenu, 2%);
|
||||||
|
|
||||||
|
// Splitter
|
||||||
|
$splitterHandleD: 2px;
|
||||||
|
$splitterHandleHitMargin: 4px;
|
||||||
|
$colorSplitterBaseBg: $colorBodyBg;
|
||||||
|
$colorSplitterBg: lighten($colorSplitterBaseBg, 10%);
|
||||||
|
$colorSplitterFg: $colorBodyBg;
|
||||||
|
$colorSplitterHover: $colorKey;
|
||||||
|
$colorSplitterActive: $colorKey;
|
||||||
|
$splitterBtnD: (16px, 35px); // height, width
|
||||||
|
$splitterBtnColorBg: $colorBtnBg;
|
||||||
|
$splitterBtnColorFg: #999;
|
||||||
|
$splitterBtnLabelColorFg: #666;
|
||||||
|
$splitterCollapsedBtnColorBg: #222;
|
||||||
|
$splitterCollapsedBtnColorFg: #666;
|
||||||
|
$splitterCollapsedBtnColorBgHov: $colorKey;
|
||||||
|
$splitterCollapsedBtnColorFgHov: $colorKeyFg;
|
||||||
|
|
||||||
|
// Mobile
|
||||||
|
$colorMobilePaneLeft: darken($colorBodyBg, 2%);
|
||||||
|
$colorMobilePaneLeftTreeItemBg: rgba($colorBodyFg, 0.1);
|
||||||
|
$colorMobilePaneLeftTreeItemFg: $colorItemTreeFg;
|
||||||
|
$colorMobileSelectListTreeItemBg: rgba(#000, 0.05);
|
||||||
|
|
||||||
|
// About Screen
|
||||||
|
$colorAboutLink: $colorKeySubtle;
|
||||||
|
|
||||||
|
// Loading
|
||||||
|
$colorLoadingFg: #776ba2;
|
||||||
|
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
||||||
|
|
||||||
|
// Transitions
|
||||||
|
$transIn: all 50ms ease-in-out;
|
||||||
|
$transOut: all 250ms ease-in-out;
|
||||||
|
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
|
||||||
|
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
||||||
|
|
||||||
|
// Discrete items, like Notebook entries, Widget rules
|
||||||
|
$createBtnTextTransform: uppercase;
|
||||||
|
|
||||||
|
@mixin discreteItem() {
|
||||||
|
background: rgba($colorBodyFg,0.1);
|
||||||
|
border: none;
|
||||||
|
border-radius: $controlCr;
|
||||||
|
|
||||||
|
.c-input-inline:hover {
|
||||||
|
background: $colorBodyBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin discreteItemInnerElem() {
|
||||||
|
border: 1px solid rgba(#fff, 0.1);
|
||||||
|
border-radius: $controlCr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin themedButton($c: $colorBtnBg) {
|
||||||
|
background: linear-gradient(lighten($c, 5%), $c);
|
||||||
|
box-shadow: rgba(black, 0.5) 0 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************** NOT USED, LEAVE FOR NOW */
|
||||||
|
// Slider controls, not in use
|
||||||
|
/*
|
||||||
|
$sliderColorBase: $colorKey;
|
||||||
|
$sliderColorRangeHolder: rgba(black, 0.07);
|
||||||
|
$sliderColorRange: rgba($sliderColorBase, 0.2);
|
||||||
|
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
|
||||||
|
$sliderColorKnob: darken($sliderColorBase, 20%);
|
||||||
|
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
|
||||||
|
$sliderColorRangeValHovBg: $sliderColorRange;
|
||||||
|
$sliderColorRangeValHovFg: $colorBodyFg;
|
||||||
|
$sliderKnobW: 15px;
|
||||||
|
$sliderKnobR: 2px;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Content status
|
||||||
|
/*
|
||||||
|
$colorAlert: #ff3c00;
|
||||||
|
$colorWarningHi: #990000;
|
||||||
|
$colorWarningLo: #ff9900;
|
||||||
|
$colorDiagnostic: #a4b442;
|
||||||
|
$colorCommand: #3693bd;
|
||||||
|
$colorInfo: #2294a2;
|
||||||
|
$colorOk: #33cc33;
|
||||||
|
*/
|
@ -20,115 +20,73 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************** SNOW THEME CONSTANTS */
|
||||||
|
|
||||||
@import "constants";
|
@import "constants";
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
@function pullForward($c: $colorBodyBg, $p: 20%) {
|
@function buttonBg($c: $colorBtnBg) {
|
||||||
// For dark interfaces, lighter things come forward - opposite for light interfaces
|
@return $c;
|
||||||
@return darken($c, $p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@function pushBack($c: $colorBodyBg, $p: 20%) {
|
// Constants
|
||||||
// For dark interfaces, darker things move back - opposite for light interfaces
|
|
||||||
@return lighten($c, $p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global
|
|
||||||
$fontBaseSize: 12px;
|
$fontBaseSize: 12px;
|
||||||
|
$smallCr: 2px;
|
||||||
|
$controlCr: 3px;
|
||||||
|
$basicCr: 4px;
|
||||||
|
|
||||||
|
// Base colors
|
||||||
$colorBodyBg: #fcfcfc;
|
$colorBodyBg: #fcfcfc;
|
||||||
$colorBodyFg: #666;
|
$colorBodyFg: #666;
|
||||||
$colorGenBg: #fff;
|
$colorGenBg: #fff;
|
||||||
|
$colorHeadBg: #eee;
|
||||||
|
$colorHeadFg: $colorBodyFg;
|
||||||
$colorStatusBarBg: #000;
|
$colorStatusBarBg: #000;
|
||||||
$colorStatusBarFg: #999;
|
$colorStatusBarFg: #999;
|
||||||
$colorStatusBarFgHov: #aaa;
|
$colorStatusBarFgHov: #aaa;
|
||||||
$colorKey: #0099cc;
|
$colorKey: #0099cc;
|
||||||
$colorKeyFilter: brightness(0.9) sepia(1) hue-rotate(145deg) saturate(6);
|
|
||||||
$colorKeyFilterHov: brightness(1) sepia(1) hue-rotate(145deg) saturate(7);
|
|
||||||
$colorKeySelectedBg: $colorKey;
|
|
||||||
$colorKeyFg: #fff;
|
$colorKeyFg: #fff;
|
||||||
$colorKeyHov: #00c0f6;
|
$colorKeyHov: #00c0f6;
|
||||||
$colorEditAreaBg: #eafaff; // Deprecated, use $editColor instead
|
$colorKeyFilter: brightness(0.9) sepia(1) hue-rotate(145deg) saturate(6);
|
||||||
$colorEditAreaFg: #4bb1c7; // Deprecated, use $editColor instead
|
$colorKeyFilterHov: brightness(1) sepia(1) hue-rotate(145deg) saturate(7);
|
||||||
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
||||||
$colorA: #999;
|
$colorA: #999;
|
||||||
$colorAHov: $colorKey;
|
$colorAHov: $colorKey;
|
||||||
$contrastRatioPercent: 40%;
|
|
||||||
$hoverRatioPercent: 10%;
|
|
||||||
$basicCr: 4px;
|
|
||||||
$controlCr: 3px;
|
|
||||||
$smallCr: 2px;
|
|
||||||
$overlayCr: 11px;
|
|
||||||
$shdwTextSubtle: rgba(black, 0.2) 0 1px 2px;
|
|
||||||
|
|
||||||
// Variations
|
// Layout
|
||||||
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
|
$shellMainPad: 4px 0;
|
||||||
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
|
$shellPanePad: 0 7px;
|
||||||
$colorKeySubtle: pushBack($colorKey, 50%);
|
|
||||||
|
// Status colors, mainly used for messaging and item ancillary symbols
|
||||||
|
$colorStatusFg: #999;
|
||||||
|
$colorStatusDefault: #ccc;
|
||||||
|
$colorStatusInfo: #60ba7b;
|
||||||
|
$colorStatusAlert: #ffb66c;
|
||||||
|
$colorStatusError: #da0004;
|
||||||
|
$colorStatusBtnBg: #666;
|
||||||
|
|
||||||
|
// States
|
||||||
|
$colorPausedBg: #ff9900;
|
||||||
|
$colorPausedFg: #fff;
|
||||||
|
$colorOk: #33cc33;
|
||||||
|
|
||||||
|
// Base variations
|
||||||
|
$colorBodyBgSubtle: darken($colorBodyBg, 5%);
|
||||||
|
$colorBodyBgSubtleHov: lighten($colorKey, 50%);
|
||||||
|
$colorKeySubtle: lighten($colorKey, 50%);
|
||||||
|
|
||||||
|
// Time Colors
|
||||||
$colorTime: #618cff;
|
$colorTime: #618cff;
|
||||||
$colorTimeBg: $colorTime;
|
$colorTimeBg: $colorTime;
|
||||||
$colorTimeFg: $colorBodyBg;
|
$colorTimeFg: $colorBodyBg;
|
||||||
$colorTimeHov: pushBack($colorTime, 5%);
|
$colorTimeHov: lighten($colorTime, 5%);
|
||||||
$colorTimeSubtle: pushBack($colorTime, 20%);
|
$colorTimeSubtle: lighten($colorTime, 20%);
|
||||||
|
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
|
||||||
// Buttons and Controls
|
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
|
||||||
$btnPad: $interiorMargin, $interiorMargin * 1.25;
|
|
||||||
$colorBtnBg: #aaaaaa;
|
|
||||||
$colorBtnBgHov: pullForward($colorBtnBg, $hoverRatioPercent);
|
|
||||||
$colorBtnFg: #fff;
|
|
||||||
$colorBtnFgHov: $colorBtnFg;
|
|
||||||
$colorBtnIcon: #eee;
|
|
||||||
$colorBtnIconHov: $colorBtnFgHov;
|
|
||||||
$colorBtnMajorBg: $colorKey;
|
|
||||||
$colorBtnMajorBgHov: $colorKeyHov;
|
|
||||||
$colorBtnMajorFg: $colorKeyFg;
|
|
||||||
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, $hoverRatioPercent);
|
|
||||||
$colorBtnCautionBg: #f16f6f;
|
|
||||||
$colorBtnCautionBgHov: #f1504e;
|
|
||||||
$colorBtnCautionFg: $colorBtnFg;
|
|
||||||
$colorClickIcon: $colorKey;
|
|
||||||
$colorClickIconHov: $colorKeyHov;
|
|
||||||
$colorToggleIcon: rgba($colorClickIcon, 0.5);
|
|
||||||
$colorToggleIconActive: $colorKey;
|
|
||||||
$colorToggleIconHov: rgba($colorToggleIconActive, 0.5);
|
|
||||||
$colorInvokeMenu: #000;
|
|
||||||
$contrastInvokeMenuPercent: 40%;
|
|
||||||
$shdwBtns: none;
|
|
||||||
$shdwBtnsOverlay: none;
|
|
||||||
$sliderColorBase: $colorKey;
|
|
||||||
$sliderColorRangeHolder: rgba(black, 0.07);
|
|
||||||
$sliderColorRange: rgba($sliderColorBase, 0.2);
|
|
||||||
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
|
|
||||||
$sliderColorKnob: pushBack($sliderColorBase, 20%);
|
|
||||||
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
|
|
||||||
$sliderColorRangeValHovBg: $sliderColorRange;
|
|
||||||
$sliderColorRangeValHovFg: $colorBodyFg;
|
|
||||||
$sliderKnobW: 15px;
|
|
||||||
$sliderKnobR: 2px;
|
|
||||||
$timeControllerToiLineColor: $colorBodyFg;
|
|
||||||
$timeControllerToiLineColorHov: $colorTime;
|
|
||||||
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
|
|
||||||
$createBtnTextTransform: uppercase;
|
|
||||||
|
|
||||||
// Foundation Colors
|
|
||||||
$colorAlt1: #776ba2;
|
|
||||||
$colorAlert: #ff3c00;
|
|
||||||
$colorWarningHi: #990000;
|
|
||||||
$colorWarningLo: #ff9900;
|
|
||||||
$colorDiagnostic: #a4b442;
|
|
||||||
$colorCommand: #3693bd;
|
|
||||||
$colorInfo: #2294a2;
|
|
||||||
$colorOk: #33cc33;
|
|
||||||
$colorIconAlias: #4af6f3;
|
|
||||||
$colorIconAliasForKeyFilter: #aaa;
|
|
||||||
$colorPausedBg: #ff9900;
|
|
||||||
$colorPausedFg: #fff;
|
|
||||||
$colorCreateBtn: $colorKey;
|
|
||||||
$colorInvokeMenu: #fff;
|
|
||||||
$colorObjHdrTxt: $colorBodyFg;
|
|
||||||
$colorObjHdrIc: lighten($colorObjHdrTxt, 30%);
|
|
||||||
$colorTick: rgba(black, 0.2);
|
|
||||||
|
|
||||||
|
// Edit Colors
|
||||||
$editColor: #00c7c3;
|
$editColor: #00c7c3;
|
||||||
|
$editColorFg: $colorBodyFg;
|
||||||
$browseBorderSelectableHov: 1px dotted rgba($colorBodyFg, 0.2);
|
$browseBorderSelectableHov: 1px dotted rgba($colorBodyFg, 0.2);
|
||||||
$browseShdwSelectableHov: rgba($colorBodyFg, 0.2) 0 0 3px;
|
$browseShdwSelectableHov: rgba($colorBodyFg, 0.2) 0 0 3px;
|
||||||
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
|
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
|
||||||
@ -138,18 +96,39 @@ $editBorderSelected: 1px solid $editColor;
|
|||||||
$editBorderDrilledIn: 1px dashed #ff4d9a;
|
$editBorderDrilledIn: 1px dashed #ff4d9a;
|
||||||
$colorGridLines: rgba($editColor, 0.2);
|
$colorGridLines: rgba($editColor, 0.2);
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
$colorIconAlias: #4af6f3;
|
||||||
|
$colorIconAliasForKeyFilter: #aaa;
|
||||||
|
$colorProgressBarOuter: rgba(#000, 0.1);
|
||||||
|
$colorProgressBarAmt: #0a0;
|
||||||
|
|
||||||
|
// Buttons and Controls
|
||||||
|
$colorBtnBg: #aaaaaa;
|
||||||
|
$colorBtnBgHov: darken($colorBtnBg, 10%);
|
||||||
|
$colorBtnFg: #fff;
|
||||||
|
$colorBtnFgHov: $colorBtnFg;
|
||||||
|
$colorBtnMajorBg: $colorKey;
|
||||||
|
$colorBtnMajorBgHov: $colorKeyHov;
|
||||||
|
$colorBtnMajorFg: $colorKeyFg;
|
||||||
|
$colorBtnMajorFgHov: lighten($colorBtnMajorFg, 10%);
|
||||||
|
$colorBtnCautionBg: #f16f6f;
|
||||||
|
$colorBtnCautionBgHov: #f1504e;
|
||||||
|
$colorBtnCautionFg: $colorBtnFg;
|
||||||
|
$colorClickIcon: $colorKey;
|
||||||
|
$colorClickIconBgHov: rgba($colorKey, 0.2);
|
||||||
|
$colorClickIconFgHov: $colorKeyHov;
|
||||||
|
|
||||||
// Menus
|
// Menus
|
||||||
$colorMenuBg: pushBack($colorBodyBg, 10%);
|
$colorMenuBg: lighten($colorBodyBg, 10%);
|
||||||
$colorMenuFg: pullForward($colorMenuBg, 70%);
|
$colorMenuFg: darken($colorMenuBg, 70%);
|
||||||
$colorMenuIc: $colorKey;
|
$colorMenuIc: $colorKey;
|
||||||
$colorMenuHovBg: $colorMenuIc; //pullForward($colorMenuBg, $hoverRatioPercent);
|
$colorMenuHovBg: $colorMenuIc;
|
||||||
$colorMenuHovFg: $colorMenuBg;
|
$colorMenuHovFg: $colorMenuBg;
|
||||||
$colorMenuHovIc: $colorMenuBg;
|
$colorMenuHovIc: $colorMenuBg;
|
||||||
|
$colorMenuElementHilite: darken($colorMenuBg, 10%);
|
||||||
$shdwMenu: rgba(black, 0.5) 0 1px 5px;
|
$shdwMenu: rgba(black, 0.5) 0 1px 5px;
|
||||||
$shdwMenuText: none;
|
$shdwMenuText: none;
|
||||||
$colorCreateMenuLgIcon: $colorKey;
|
$menuItemPad: $interiorMargin, floor($interiorMargin * 1.25);
|
||||||
$colorCreateMenuText: $colorBodyFg;
|
|
||||||
$menuItemPad: ($interiorMargin, nth($btnPad, 2));
|
|
||||||
|
|
||||||
// Palettes and Swatches
|
// Palettes and Swatches
|
||||||
$paletteItemBorderOuterColorSelected: black;
|
$paletteItemBorderOuterColorSelected: black;
|
||||||
@ -160,7 +139,7 @@ $paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
|
|||||||
$colorCheck: $colorKey;
|
$colorCheck: $colorKey;
|
||||||
$colorFormRequired: $colorKey;
|
$colorFormRequired: $colorKey;
|
||||||
$colorFormValid: $colorOk;
|
$colorFormValid: $colorOk;
|
||||||
$colorFormError: $colorWarningHi;
|
$colorFormError: #990000;
|
||||||
$colorFormInvalid: #ff2200;
|
$colorFormInvalid: #ff2200;
|
||||||
$colorFormFieldErrorBg: $colorFormError;
|
$colorFormFieldErrorBg: $colorFormError;
|
||||||
$colorFormFieldErrorFg: rgba(#fff, 0.6);
|
$colorFormFieldErrorFg: rgba(#fff, 0.6);
|
||||||
@ -168,35 +147,28 @@ $colorFormLines: rgba(#000, 0.1);
|
|||||||
$colorFormSectionHeader: rgba(#000, 0.05);
|
$colorFormSectionHeader: rgba(#000, 0.05);
|
||||||
$colorInputBg: $colorGenBg;
|
$colorInputBg: $colorGenBg;
|
||||||
$colorInputFg: $colorBodyFg;
|
$colorInputFg: $colorBodyFg;
|
||||||
$colorInputPlaceholder: pushBack($colorBodyFg, 20%);
|
$colorInputPlaceholder: lighten($colorBodyFg, 20%);
|
||||||
$colorFormText: pushBack($colorBodyFg, 10%);
|
$colorFormText: lighten($colorBodyFg, 10%);
|
||||||
$colorInputIcon: pushBack($colorBodyFg, 25%);
|
$colorInputIcon: lighten($colorBodyFg, 25%);
|
||||||
$colorFieldHint: pullForward($colorBodyFg, 40%);
|
$colorFieldHint: darken($colorBodyFg, 40%);
|
||||||
$shdwInput: inset rgba(black, 0.4) 0 0 1px;
|
$shdwInput: inset rgba(black, 0.7) 0 0 1px;
|
||||||
$shdwInputHov: inset rgba(black, 0.7) 0 0 1px;
|
$shdwInputHov: inset rgba(black, 0.7) 0 0 2px;
|
||||||
$shdwInputFoc: inset rgba(black, 0.7) 0 0 3px;
|
$shdwInputFoc: inset rgba(black, 0.8) 0 0.25px 3px;
|
||||||
|
|
||||||
// Inspector
|
// Inspector
|
||||||
$colorInspectorBg: pullForward($colorBodyBg, 5%);
|
$colorInspectorBg: darken($colorBodyBg, 5%);
|
||||||
$colorInspectorFg: $colorBodyFg;
|
$colorInspectorFg: $colorBodyFg;
|
||||||
$colorInspectorPropName: pushBack($colorBodyFg, 20%);
|
$colorInspectorPropName: lighten($colorBodyFg, 20%);
|
||||||
$colorInspectorPropVal: pullForward($colorInspectorFg, 15%);
|
$colorInspectorPropVal: darken($colorInspectorFg, 15%);
|
||||||
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
|
$colorInspectorSectionHeaderBg: darken($colorInspectorBg, 5%);
|
||||||
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
|
$colorInspectorSectionHeaderFg: darken($colorInspectorBg, 40%);
|
||||||
|
|
||||||
// Status colors, mainly used for messaging and item ancillary symbols
|
// Overlay
|
||||||
$colorStatusFg: #999;
|
$overlayColorBg: $colorMenuBg;
|
||||||
$colorStatusDefault: #ccc;
|
$overlayColorFg: $colorMenuFg;
|
||||||
$colorStatusInfo: #60ba7b;
|
$overlayButtonColorBg: $colorBtnBg;
|
||||||
$colorStatusAlert: #ffb66c;
|
$overlayButtonColorFg: $colorBtnFg;
|
||||||
$colorStatusError: #da0004;
|
$overlayCr: $interiorMarginLg;
|
||||||
$colorStatusBtnBg: #666;
|
|
||||||
$colorProgressBarOuter: rgba(#000, 0.1);
|
|
||||||
$colorProgressBarAmt: #0a0;
|
|
||||||
$progressBarHOverlay: 15px;
|
|
||||||
$progressBarStripeW: 20px;
|
|
||||||
$shdwStatusIc: rgba(white, 0.8) 0 0px 5px;
|
|
||||||
$animPausedPulseDur: 1s;
|
|
||||||
|
|
||||||
// Indicator colors
|
// Indicator colors
|
||||||
$colorIndicatorAvailable: $colorKey;
|
$colorIndicatorAvailable: $colorKey;
|
||||||
@ -204,13 +176,9 @@ $colorIndicatorDisabled: #444;
|
|||||||
$colorIndicatorOn: $colorOk;
|
$colorIndicatorOn: $colorOk;
|
||||||
$colorIndicatorOff: #666;
|
$colorIndicatorOff: #666;
|
||||||
|
|
||||||
// Selects
|
|
||||||
$colorSelectBg: $colorBtnBg;
|
|
||||||
$colorSelectFg: $colorBtnFg;
|
|
||||||
|
|
||||||
// Limits and staleness colors//
|
// Limits and staleness colors//
|
||||||
$colorTelemFresh: pullForward($colorBodyFg, 20%);
|
$colorTelemFresh: darken($colorBodyFg, 20%);
|
||||||
$colorTelemStale: pushBack($colorBodyFg, 20%);
|
$colorTelemStale: lighten($colorBodyFg, 20%);
|
||||||
$styleTelemStale: italic;
|
$styleTelemStale: italic;
|
||||||
$colorLimitYellowBg: rgba(#ffaa00, 0.3);
|
$colorLimitYellowBg: rgba(#ffaa00, 0.3);
|
||||||
$colorLimitYellowIc: #ffaa00;
|
$colorLimitYellowIc: #ffaa00;
|
||||||
@ -220,37 +188,22 @@ $colorLimitRedIc: red;
|
|||||||
// Bubble colors
|
// Bubble colors
|
||||||
$colorInfoBubbleBg: $colorMenuBg;
|
$colorInfoBubbleBg: $colorMenuBg;
|
||||||
$colorInfoBubbleFg: #666;
|
$colorInfoBubbleFg: #666;
|
||||||
$colorThumbsBubbleFg: pullForward($colorBodyFg, 10%);
|
|
||||||
$colorThumbsBubbleBg: pullForward($colorBodyBg, 10%);
|
|
||||||
|
|
||||||
// Overlay
|
|
||||||
$colorOvrBlocker: rgba(black, 0.7);//
|
|
||||||
$colorOvrBg: $colorBodyBg;
|
|
||||||
$colorOvrFg: $colorBodyFg;
|
|
||||||
$colorOvrBtnBg: pullForward($colorOvrBg, 40%);
|
|
||||||
$colorOvrBtnFg: #fff;
|
|
||||||
$colorFieldHintOverlay: pullForward($colorOvrBg, 40%);
|
|
||||||
$durLargeViewExpand: 250ms;
|
|
||||||
|
|
||||||
// Items
|
// Items
|
||||||
$colorItemBg: #ddd;
|
$colorItemBg: lighten($colorBtnBg, 20%);
|
||||||
$colorItemBgHov: rgba($colorKey, 0.1); //pushBack($colorItemBg, $hoverRatioPercent * 0.4);
|
$colorItemBgHov: lighten($colorItemBg, 5%);
|
||||||
$colorListItemBg: transparent;
|
$colorListItemBg: transparent;
|
||||||
$colorListItemBgHov: rgba($colorKey, 0.1);
|
$colorListItemBgHov: rgba($colorKey, 0.1);
|
||||||
$colorItemFg: $colorBodyFg;
|
$colorItemFg: $colorBodyFg;
|
||||||
$colorItemFgDetails: pushBack($colorItemFg, 15%);
|
$colorItemFgDetails: lighten($colorItemFg, 15%);
|
||||||
$colorItemIc: $colorKey;
|
|
||||||
$colorItemSubIcons: $colorItemFgDetails;
|
|
||||||
$colorItemOpenIcon: $colorItemFgDetails;
|
|
||||||
$shdwItemText: none;
|
$shdwItemText: none;
|
||||||
$colorItemBgSelected: $colorKey;
|
|
||||||
|
|
||||||
// Tabular
|
// Tabular
|
||||||
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
$colorTabBorder: darken($colorBodyBg, 10%);
|
||||||
$colorTabBodyBg: $colorBodyBg;
|
$colorTabBodyBg: $colorBodyBg;
|
||||||
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
|
$colorTabBodyFg: darken($colorBodyFg, 20%);
|
||||||
$colorTabHeaderBg: pullForward($colorBodyBg, 10%);
|
$colorTabHeaderBg: darken($colorBodyBg, 10%);
|
||||||
$colorTabHeaderFg: pullForward($colorBodyFg, 20%);
|
$colorTabHeaderFg: darken($colorBodyFg, 20%);
|
||||||
$colorTabHeaderBorder: $colorBodyBg;
|
$colorTabHeaderBorder: $colorBodyBg;
|
||||||
|
|
||||||
// Plot
|
// Plot
|
||||||
@ -260,24 +213,23 @@ $colorPlotHash: black;
|
|||||||
$opacityPlotHash: 0.2;
|
$opacityPlotHash: 0.2;
|
||||||
$stylePlotHash: dashed;
|
$stylePlotHash: dashed;
|
||||||
$colorPlotAreaBorder: $colorInteriorBorder;
|
$colorPlotAreaBorder: $colorInteriorBorder;
|
||||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
|
$colorPlotLabelFg: lighten($colorPlotFg, 20%);
|
||||||
$legendCollapsedNameMaxW: 50%;
|
$legendCollapsedNameMaxW: 50%;
|
||||||
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
|
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
|
||||||
|
|
||||||
// Tree
|
// Tree
|
||||||
$colorTreeBg: #f0f0f0; // Used
|
$colorTreeBg: transparent;
|
||||||
$colorItemTreeHoverBg: pullForward($colorBodyBg, $hoverRatioPercent);
|
$colorItemTreeHoverBg: darken($colorBodyBg, 10%);
|
||||||
$colorItemTreeHoverFg: pullForward($colorBodyFg, $hoverRatioPercent);
|
$colorItemTreeHoverFg: darken($colorBodyFg, 10%);
|
||||||
$colorItemTreeIcon: $colorKey; // Used
|
$colorItemTreeIcon: $colorKey; // Used
|
||||||
$colorItemTreeIconHover: $colorItemTreeIcon; // Used
|
$colorItemTreeIconHover: $colorItemTreeIcon; // Used
|
||||||
$colorItemTreeFg: $colorBodyFg;
|
$colorItemTreeFg: $colorBodyFg;
|
||||||
$colorItemTreeSelectedBg: pushBack($colorKey, 15%);
|
$colorItemTreeSelectedBg: lighten($colorKey, 15%);
|
||||||
$colorItemTreeSelectedFg: $colorBodyBg;
|
$colorItemTreeSelectedFg: $colorBodyBg;
|
||||||
$colorItemTreeEditingBg: #caf1ff;
|
$colorItemTreeEditingBg: $editColor;
|
||||||
$colorItemTreeEditingFg: $colorEditAreaFg;
|
$colorItemTreeEditingFg: $editColorFg;
|
||||||
$colorItemTreeVC: $colorBodyFg;
|
$colorItemTreeVC: $colorBodyFg;
|
||||||
$colorItemTreeVCHover: $colorKey;
|
$colorItemTreeVCHover: $colorKey;
|
||||||
$colorItemTreeSelectedVC: $colorBodyBg;
|
|
||||||
$shdwItemTreeIcon: none;
|
$shdwItemTreeIcon: none;
|
||||||
|
|
||||||
// Images
|
// Images
|
||||||
@ -289,54 +241,37 @@ $scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
|
|||||||
$scrollbarTrackColorBg: rgba(#000, 0.2);
|
$scrollbarTrackColorBg: rgba(#000, 0.2);
|
||||||
$scrollbarThumbColor: darken($colorBodyBg, 50%);
|
$scrollbarThumbColor: darken($colorBodyBg, 50%);
|
||||||
$scrollbarThumbColorHov: $colorKey;
|
$scrollbarThumbColorHov: $colorKey;
|
||||||
$scrollbarThumbColorOverlay: darken($colorOvrBg, 50%);
|
$scrollbarThumbColorMenu: darken($colorMenuBg, 10%);
|
||||||
$scrollbarThumbColorOverlayHov: $scrollbarThumbColorHov;
|
$scrollbarThumbColorMenuHov: darken($scrollbarThumbColorMenu, 2%);
|
||||||
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 10%);
|
|
||||||
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
|
|
||||||
|
|
||||||
// Splitter
|
// Splitter
|
||||||
$splitterD: 7px;
|
|
||||||
$splitterHandleD: 2px;
|
$splitterHandleD: 2px;
|
||||||
$splitterHandleHitMargin: 4px;
|
$splitterHandleHitMargin: 4px;
|
||||||
$splitterGrippyD: ($splitterHandleD - 4, 75px, 50px); // thickness, length, min-length
|
|
||||||
$colorSplitterBaseBg: $colorBodyBg;
|
$colorSplitterBaseBg: $colorBodyBg;
|
||||||
$colorSplitterBg: pullForward($colorSplitterBaseBg, 20%);
|
$colorSplitterBg: darken($colorSplitterBaseBg, 20%);
|
||||||
$colorSplitterFg: $colorBodyBg;
|
$colorSplitterFg: $colorBodyBg;
|
||||||
$colorSplitterHover: $colorKey; // pullForward($colorSplitterBg, $hoverRatioPercent * 2);
|
$colorSplitterHover: $colorKey;
|
||||||
$colorSplitterActive: $colorKey;
|
$colorSplitterActive: $colorKey;
|
||||||
$splitterBtnD: (16px, 35px); // height, width
|
$splitterBtnD: (16px, 35px); // height, width
|
||||||
$splitterBtnColorBg: #eee;
|
$splitterBtnColorBg: $colorBtnBg;
|
||||||
$splitterBtnColorFg: #999;
|
$splitterBtnColorFg: #ddd;
|
||||||
$splitterBtnColorHoverBg: rgba($colorKey, 1);
|
$splitterBtnLabelColorFg: #999;
|
||||||
$splitterBtnColorHoverFg: $colorBodyBg;
|
$splitterCollapsedBtnColorBg: #ccc;
|
||||||
$colorSplitterGrippy: pullForward($colorSplitterBaseBg, 30%);
|
$splitterCollapsedBtnColorFg: #666;
|
||||||
$splitterShdw: none;
|
$splitterCollapsedBtnColorBgHov: $colorKey;
|
||||||
$splitterEndCr: none;
|
$splitterCollapsedBtnColorFgHov: $colorKeyFg;
|
||||||
|
|
||||||
// Minitabs
|
|
||||||
$colorMiniTabBg: $colorSplitterBg;
|
|
||||||
$colorMiniTabFg: pullForward($colorMiniTabBg, 30%);
|
|
||||||
$colorMiniTabBgHov: $colorSplitterHover;
|
|
||||||
$colorMiniTabFgHov: #fff;
|
|
||||||
|
|
||||||
// Mobile
|
// Mobile
|
||||||
$colorMobilePaneLeft: darken($colorBodyBg, 2%);
|
$colorMobilePaneLeft: darken($colorBodyBg, 2%);
|
||||||
$colorMobilePaneLeftTreeItemBg: rgba($colorBodyFg, 0.1); //pullForward($colorMobilePaneLeft, 3%);
|
$colorMobilePaneLeftTreeItemBg: rgba($colorBodyFg, 0.1);
|
||||||
$colorMobilePaneLeftTreeItemFg: $colorItemTreeFg;
|
$colorMobilePaneLeftTreeItemFg: $colorItemTreeFg;
|
||||||
$colorMobileSelectListTreeItemBg: rgba(#000, 0.05);
|
$colorMobileSelectListTreeItemBg: rgba(#000, 0.05);
|
||||||
|
|
||||||
// Datetime Picker, Calendar
|
|
||||||
$colorCalCellHovBg: $colorKey;
|
|
||||||
$colorCalCellHovFg: $colorKeyFg;
|
|
||||||
$colorCalCellSelectedBg: $colorItemTreeSelectedBg;
|
|
||||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
|
|
||||||
$colorCalCellInMonthBg: pullForward($colorMenuBg, 5%);
|
|
||||||
|
|
||||||
// About Screen
|
// About Screen
|
||||||
$colorAboutLink: #84b3ff;
|
$colorAboutLink: $colorKeySubtle;
|
||||||
|
|
||||||
// Loading
|
// Loading
|
||||||
$colorLoadingFg: $colorAlt1;
|
$colorLoadingFg: #776ba2;
|
||||||
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
||||||
|
|
||||||
// Transitions
|
// Transitions
|
||||||
@ -346,14 +281,50 @@ $transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
|
|||||||
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
||||||
|
|
||||||
// Discrete items, like Notebook entries, Widget rules
|
// Discrete items, like Notebook entries, Widget rules
|
||||||
|
$createBtnTextTransform: uppercase;
|
||||||
|
|
||||||
@mixin discreteItem() {
|
@mixin discreteItem() {
|
||||||
background: rgba($colorBodyFg,0.1);
|
background: rgba($colorBodyFg,0.1);
|
||||||
border: 1px solid $colorInteriorBorder;
|
border: 1px solid $colorInteriorBorder;
|
||||||
border-radius: $controlCr;
|
border-radius: $controlCr;
|
||||||
|
|
||||||
.c-input-inline:hover {
|
.c-input-inline:hover {
|
||||||
background: $colorBodyBg;
|
background: $colorBodyBg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin discreteItemInnerElem() {
|
@mixin discreteItemInnerElem() {
|
||||||
border: 1px solid $colorBodyBg;
|
border: 1px solid $colorBodyBg;
|
||||||
border-radius: $controlCr; }
|
border-radius: $controlCr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin themedButton($c: $colorBtnBg) {
|
||||||
|
background: $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************** NOT USED, LEAVE FOR NOW */
|
||||||
|
// Slider controls, not in use
|
||||||
|
/*
|
||||||
|
$sliderColorBase: $colorKey;
|
||||||
|
$sliderColorRangeHolder: rgba(black, 0.07);
|
||||||
|
$sliderColorRange: rgba($sliderColorBase, 0.2);
|
||||||
|
$sliderColorRangeHov: rgba($sliderColorBase, 0.4);
|
||||||
|
$sliderColorKnob: lighten($sliderColorBase, 20%);
|
||||||
|
$sliderColorKnobHov: rgba($sliderColorBase, 0.7);
|
||||||
|
$sliderColorRangeValHovBg: $sliderColorRange;
|
||||||
|
$sliderColorRangeValHovFg: $colorBodyFg;
|
||||||
|
$sliderKnobW: 15px;
|
||||||
|
$sliderKnobR: 2px;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Content status
|
||||||
|
/*
|
||||||
|
$colorAlert: #ff3c00;
|
||||||
|
$colorWarningHi: #990000;
|
||||||
|
$colorWarningLo: #ff9900;
|
||||||
|
$colorDiagnostic: #a4b442;
|
||||||
|
$colorCommand: #3693bd;
|
||||||
|
$colorInfo: #2294a2;
|
||||||
|
$colorOk: #33cc33;
|
||||||
|
*/
|
||||||
|
@ -40,17 +40,20 @@ $inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
|
|||||||
$menuLineH: 1.5rem;
|
$menuLineH: 1.5rem;
|
||||||
$treeItemIndent: 16px;
|
$treeItemIndent: 16px;
|
||||||
$treeTypeIconW: 18px;
|
$treeTypeIconW: 18px;
|
||||||
|
$overlayOuterMargin: 5%;
|
||||||
|
$overlayInnerMargin: 25px;
|
||||||
|
|
||||||
/*************** Items */
|
/*************** Items */
|
||||||
$itemPadLR: 5px;
|
$itemPadLR: 5px;
|
||||||
$ueBrowseGridItemLg: 200px;
|
$gridItemDesk: 175px;
|
||||||
|
$gridItemMobile: 32px;
|
||||||
/*************** Tabular */
|
/*************** Tabular */
|
||||||
$tabularHeaderH: 22px;
|
$tabularHeaderH: 22px;
|
||||||
$tabularTdPadLR: $itemPadLR;
|
$tabularTdPadLR: $itemPadLR;
|
||||||
$tabularTdPadTB: 2px;
|
$tabularTdPadTB: 2px;
|
||||||
|
|
||||||
/************************** MOBILE */
|
/************************** MOBILE */
|
||||||
$mobileMenuIconD: 34px; // Used
|
$mobileMenuIconD: 24px; // Used
|
||||||
$mobileTreeItemH: 35px; // Used
|
$mobileTreeItemH: 35px; // Used
|
||||||
|
|
||||||
/************************** VISUAL */
|
/************************** VISUAL */
|
||||||
@ -121,7 +124,7 @@ $glyph-icon-pointer-right: '\e1028';
|
|||||||
$glyph-icon-refresh: '\e1029';
|
$glyph-icon-refresh: '\e1029';
|
||||||
$glyph-icon-save: '\e1030';
|
$glyph-icon-save: '\e1030';
|
||||||
$glyph-icon-sine: '\e1031';
|
$glyph-icon-sine: '\e1031';
|
||||||
$glyph-icon-T: '\e1032';
|
$glyph-icon-font: '\e1032';
|
||||||
$glyph-icon-thumbs-strip: '\e1033';
|
$glyph-icon-thumbs-strip: '\e1033';
|
||||||
$glyph-icon-two-parts-both: '\e1034';
|
$glyph-icon-two-parts-both: '\e1034';
|
||||||
$glyph-icon-two-parts-one-only: '\e1035';
|
$glyph-icon-two-parts-one-only: '\e1035';
|
||||||
@ -138,7 +141,7 @@ $glyph-icon-frame-show: '\e1045';
|
|||||||
$glyph-icon-frame-hide: '\e1046';
|
$glyph-icon-frame-hide: '\e1046';
|
||||||
$glyph-icon-import: '\e1047';
|
$glyph-icon-import: '\e1047';
|
||||||
$glyph-icon-export: '\e1048';
|
$glyph-icon-export: '\e1048';
|
||||||
$glyph-icon-minimize: '\e1049'; // 12px only
|
$glyph-icon-font-size: '\e1049';
|
||||||
$glyph-icon-activity: '\e1100';
|
$glyph-icon-activity: '\e1100';
|
||||||
$glyph-icon-activity-mode: '\e1101';
|
$glyph-icon-activity-mode: '\e1101';
|
||||||
$glyph-icon-autoflow-tabular: '\e1102';
|
$glyph-icon-autoflow-tabular: '\e1102';
|
||||||
|
@ -20,115 +20,6 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/******************************************************** PLACEHOLDERS */
|
|
||||||
@mixin cControl() {
|
|
||||||
$fs: 1em;
|
|
||||||
@include userSelectNone();
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&:before,
|
|
||||||
&:after {
|
|
||||||
font-family: symbolsfont;
|
|
||||||
display: block;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="__label"] {
|
|
||||||
@include ellipsize();
|
|
||||||
display: block;
|
|
||||||
line-height: $fs; // Remove effect on top and bottom padding
|
|
||||||
font-size: $fs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin cButton() {
|
|
||||||
@include cControl();
|
|
||||||
background: $colorBtnBg;
|
|
||||||
border-radius: $controlCr;
|
|
||||||
color: $colorBtnFg;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: nth($btnPad, 1) nth($btnPad, 2);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $colorBtnBgHov;
|
|
||||||
color: $colorBtnFgHov;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[class*="--major"] {
|
|
||||||
background: $colorBtnMajorBg;
|
|
||||||
color: $colorBtnMajorFg;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $colorBtnMajorBgHov;
|
|
||||||
color: $colorBtnMajorFgHov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[class*='--caution'] {
|
|
||||||
background: $colorBtnCautionBg;
|
|
||||||
color: $colorBtnCautionFg;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $colorBtnCautionBgHov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin cClickIcon() {
|
|
||||||
// A clickable element that just includes the icon, no background
|
|
||||||
// Padding is included to facilitate a bigger hit area
|
|
||||||
// Make the icon bigger relative to its container
|
|
||||||
@include cControl();
|
|
||||||
$pLR: 3px;
|
|
||||||
$pTB: 3px;
|
|
||||||
border-radius: $controlCr;
|
|
||||||
color: $colorKey;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: $pTB $pLR ;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba($colorKey, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before,
|
|
||||||
*:before {
|
|
||||||
// *:before handles any nested containers that may contain glyph elements
|
|
||||||
// Needed for c-togglebutton.
|
|
||||||
font-size: 1.3em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin cCtrlWrapper {
|
|
||||||
// Provides a wrapper around buttons and other controls
|
|
||||||
// Contains control and provides positioning context for contained menu/palette.
|
|
||||||
// Wraps --menu elements, contains button and menu
|
|
||||||
overflow: visible;
|
|
||||||
|
|
||||||
.c-menu {
|
|
||||||
// Default position of contained menu
|
|
||||||
top: 100%; left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[class*='--menus-up'] {
|
|
||||||
.c-menu {
|
|
||||||
top: auto; bottom: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[class*='--menus-left'] {
|
|
||||||
.c-menu {
|
|
||||||
left: auto; right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/********* Buttons */
|
/********* Buttons */
|
||||||
// Optionally can include icon in :before via markup
|
// Optionally can include icon in :before via markup
|
||||||
button {
|
button {
|
||||||
@ -206,7 +97,7 @@ button {
|
|||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/********* Disclosure Triangle */
|
/********* Disclosure Triangle */
|
||||||
// Provides an arrow icon that when clicked expands an element to reveal its contents.
|
// Provides an arrow icon that when clicked expands an element to reveal its contents.
|
||||||
// Used in tree items. Always placed BEFORE an element.
|
// Used in tree items. Always placed BEFORE an element.
|
||||||
.c-disclosure-triangle {
|
.c-disclosure-triangle {
|
||||||
@ -253,6 +144,12 @@ input[type=number] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=number]::-webkit-inner-spin-button,
|
||||||
|
input[type=number]::-webkit-outer-spin-button {
|
||||||
|
margin-right: -5px !important;
|
||||||
|
margin-top: -1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.c-input {
|
.c-input {
|
||||||
&--datetime {
|
&--datetime {
|
||||||
// Sized for values such as 2018-09-28 22:32:33.468Z
|
// Sized for values such as 2018-09-28 22:32:33.468Z
|
||||||
@ -266,39 +163,40 @@ input[type=number] {
|
|||||||
|
|
||||||
&-inline,
|
&-inline,
|
||||||
&--inline {
|
&--inline {
|
||||||
// A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus
|
// A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus
|
||||||
@include reactive-input();
|
@include reactive-input($bg: transparent);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
display: block !important;
|
display: block !important;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: all 250ms ease;
|
transition: all 250ms ease;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
&:not(:focus) {
|
&:not(:focus) {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
padding-left: $inputTextPLeftRight;
|
background: $colorInputBg;
|
||||||
padding-right: $inputTextPLeftRight;
|
padding-left: $inputTextPLeftRight;
|
||||||
|
padding-right: $inputTextPLeftRight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&--labeled {
|
&--labeled {
|
||||||
// TODO: replace .c-labeled-input with this
|
// TODO: replace .c-labeled-input with this
|
||||||
// An input used in the Toolbar
|
// An input used in the Toolbar
|
||||||
// Assumes label is before the input
|
// Assumes label is before the input
|
||||||
@include cControl();
|
@include cControl();
|
||||||
|
|
||||||
input {
|
input {
|
||||||
margin-left: $interiorMarginSm;
|
margin-left: $interiorMarginSm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.c-labeled-input {
|
.c-labeled-input {
|
||||||
// An input used in the Toolbar
|
// An input used in the Toolbar
|
||||||
@ -334,7 +232,6 @@ input[type=number] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mixin menuInner() {
|
@mixin menuInner() {
|
||||||
color: $colorMenuFg;
|
|
||||||
li {
|
li {
|
||||||
@include cControl();
|
@include cControl();
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
@ -404,11 +301,6 @@ input[type=number] {
|
|||||||
justify-content: stretch;
|
justify-content: stretch;
|
||||||
|
|
||||||
.l-item-description {
|
.l-item-description {
|
||||||
&__icon,
|
|
||||||
&__description {
|
|
||||||
//flex: 1 1 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__name,
|
&__name,
|
||||||
&__description {
|
&__description {
|
||||||
margin-top: $interiorMarginLg;
|
margin-top: $interiorMarginLg;
|
||||||
@ -420,6 +312,7 @@ input[type=number] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__name {
|
&__name {
|
||||||
|
color: $colorMenuFg;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
|
@ -92,23 +92,16 @@ body.desktop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlay ::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-corner {
|
||||||
background: $scrollbarThumbColorOverlay;
|
background: transparent;
|
||||||
&:hover {
|
|
||||||
background: $scrollbarThumbColorOverlayHov;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu ::-webkit-scrollbar-thumb {
|
.c-menu ::-webkit-scrollbar-thumb {
|
||||||
background: $scrollbarThumbColorMenu;
|
background: $scrollbarThumbColorMenu;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $scrollbarThumbColorMenuHov;
|
background: $scrollbarThumbColorMenuHov;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-corner {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** HTML ENTITIES */
|
/************************** HTML ENTITIES */
|
||||||
@ -175,7 +168,6 @@ li {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************** HAS */
|
/******************************************************** HAS */
|
||||||
// Local Controls: Controls placed in proximity to or overlaid on components and views
|
// Local Controls: Controls placed in proximity to or overlaid on components and views
|
||||||
body.desktop .has-local-controls {
|
body.desktop .has-local-controls {
|
||||||
@ -386,3 +378,8 @@ a.disabled {
|
|||||||
.t-imagery {
|
.t-imagery {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.t-frame-outer {
|
||||||
|
min-width: 200px;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
@ -113,7 +113,7 @@
|
|||||||
.icon-refresh { @include glyphBefore($glyph-icon-refresh); }
|
.icon-refresh { @include glyphBefore($glyph-icon-refresh); }
|
||||||
.icon-save { @include glyphBefore($glyph-icon-save); }
|
.icon-save { @include glyphBefore($glyph-icon-save); }
|
||||||
.icon-sine { @include glyphBefore($glyph-icon-sine); }
|
.icon-sine { @include glyphBefore($glyph-icon-sine); }
|
||||||
.icon-T { @include glyphBefore($glyph-icon-T); }
|
.icon-font { @include glyphBefore($glyph-icon-font); }
|
||||||
.icon-thumbs-strip { @include glyphBefore($glyph-icon-thumbs-strip); }
|
.icon-thumbs-strip { @include glyphBefore($glyph-icon-thumbs-strip); }
|
||||||
.icon-two-parts-both { @include glyphBefore($glyph-icon-two-parts-both); }
|
.icon-two-parts-both { @include glyphBefore($glyph-icon-two-parts-both); }
|
||||||
.icon-two-parts-one-only { @include glyphBefore($glyph-icon-two-parts-one-only); }
|
.icon-two-parts-one-only { @include glyphBefore($glyph-icon-two-parts-one-only); }
|
||||||
@ -130,6 +130,7 @@
|
|||||||
.icon-frame-hide { @include glyphBefore($glyph-icon-frame-hide); }
|
.icon-frame-hide { @include glyphBefore($glyph-icon-frame-hide); }
|
||||||
.icon-import { @include glyphBefore($glyph-icon-import); }
|
.icon-import { @include glyphBefore($glyph-icon-import); }
|
||||||
.icon-export { @include glyphBefore($glyph-icon-export); }
|
.icon-export { @include glyphBefore($glyph-icon-export); }
|
||||||
|
.icon-font-size { @include glyphBefore($glyph-icon-font-size); }
|
||||||
.icon-activity { @include glyphBefore($glyph-icon-activity); }
|
.icon-activity { @include glyphBefore($glyph-icon-activity); }
|
||||||
.icon-activity-mode { @include glyphBefore($glyph-icon-activity-mode); }
|
.icon-activity-mode { @include glyphBefore($glyph-icon-activity-mode); }
|
||||||
.icon-autoflow-tabular { @include glyphBefore($glyph-icon-autoflow-tabular); }
|
.icon-autoflow-tabular { @include glyphBefore($glyph-icon-autoflow-tabular); }
|
||||||
|
@ -113,33 +113,14 @@
|
|||||||
top: $m; right: $m; bottom: $m; left: $m;
|
top: $m; right: $m; bottom: $m; left: $m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin gridTwoColumn() {
|
@mixin propertiesHeader() {
|
||||||
display: grid;
|
border-radius: $smallCr;
|
||||||
grid-row-gap: 0;
|
background-color: $colorInspectorSectionHeaderBg;
|
||||||
grid-template-columns: 1fr 2fr;
|
color: $colorInspectorSectionHeaderFg;
|
||||||
align-items: start;
|
font-weight: normal;
|
||||||
|
margin: 0 0 $interiorMarginSm 0;
|
||||||
[class*="header"] {
|
padding: $interiorMarginSm $interiorMargin;
|
||||||
border-radius: $smallCr;
|
text-transform: uppercase;
|
||||||
background-color: $colorInspectorSectionHeaderBg;
|
|
||||||
color: $colorInspectorSectionHeaderFg;
|
|
||||||
margin: 0 0 $interiorMarginSm 0;
|
|
||||||
padding: $interiorMarginSm $interiorMargin;
|
|
||||||
|
|
||||||
&:not(:first-child) {
|
|
||||||
// Allow multiple headers within a component
|
|
||||||
margin-top: $interiorMarginLg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="span-all"],
|
|
||||||
[class*="header"] {
|
|
||||||
@include gridTwoColumnSpanCols();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin gridTwoColumnSpanCols() {
|
|
||||||
grid-column: 1 / 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin modalFullScreen() {
|
@mixin modalFullScreen() {
|
||||||
@ -163,10 +144,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/************************** CONTROLS, BUTTONS */
|
/************************** CONTROLS, BUTTONS */
|
||||||
|
@mixin hover {
|
||||||
|
body.desktop & {
|
||||||
|
&:hover {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@mixin htmlInputReset() {
|
@mixin htmlInputReset() {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
background: none;
|
background: transparent;
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -177,13 +165,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@mixin input-base() {
|
@mixin input-base() {
|
||||||
@include htmlInputReset();
|
@include htmlInputReset();
|
||||||
border-radius: $controlCr;
|
border-radius: $controlCr;
|
||||||
|
|
||||||
&.error {
|
&.error {
|
||||||
background-color: $colorFormFieldErrorBg;
|
background: $colorFormFieldErrorBg;
|
||||||
color: $colorFormFieldErrorFg;
|
color: $colorFormFieldErrorFg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,22 +188,145 @@
|
|||||||
box-shadow: $shdwInput;
|
box-shadow: $shdwInput;
|
||||||
color: $fg;
|
color: $fg;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
box-shadow: $shdwInputHov;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
box-shadow: $shdwInputFoc;
|
box-shadow: $shdwInputFoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include hover() {
|
||||||
|
&:not(:focus) {
|
||||||
|
box-shadow: $shdwInputHov;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin button($bg: $colorBtnBg, $fg: $colorBtnFg, $radius: $controlCr, $shdw: none) {
|
@mixin button($bg: $colorBtnBg, $fg: $colorBtnFg, $radius: $controlCr, $shdw: none) {
|
||||||
|
// Is this being used? Remove if not.
|
||||||
background: $bg;
|
background: $bg;
|
||||||
color: $fg;
|
color: $fg;
|
||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
box-shadow: $shdw;
|
box-shadow: $shdw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin cControl() {
|
||||||
|
$fs: 1em;
|
||||||
|
@include userSelectNone();
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:before,
|
||||||
|
&:after {
|
||||||
|
font-family: symbolsfont;
|
||||||
|
display: block;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="__label"] {
|
||||||
|
@include ellipsize();
|
||||||
|
display: block;
|
||||||
|
line-height: $fs; // Remove effect on top and bottom padding
|
||||||
|
font-size: $fs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin cButton() {
|
||||||
|
@include cControl();
|
||||||
|
@include themedButton();
|
||||||
|
border-radius: $controlCr;
|
||||||
|
color: $colorBtnFg;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: $interiorMargin floor($interiorMargin * 1.25);
|
||||||
|
|
||||||
|
@include hover() {
|
||||||
|
background: $colorBtnBgHov;
|
||||||
|
color: $colorBtnFgHov;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[class*="--major"] {
|
||||||
|
background: $colorBtnMajorBg;
|
||||||
|
color: $colorBtnMajorFg;
|
||||||
|
|
||||||
|
@include hover() {
|
||||||
|
background: $colorBtnMajorBgHov;
|
||||||
|
color: $colorBtnMajorFgHov;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[class*='--caution'] {
|
||||||
|
background: $colorBtnCautionBg;
|
||||||
|
color: $colorBtnCautionFg;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $colorBtnCautionBgHov;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin cClickIcon() {
|
||||||
|
// A clickable element that just includes the icon, no background
|
||||||
|
// Padding is included to facilitate a bigger hit area
|
||||||
|
// Make the icon bigger relative to its container
|
||||||
|
@include cControl();
|
||||||
|
$pLR: 4px;
|
||||||
|
$pTB: 3px;
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
border-radius: $controlCr;
|
||||||
|
color: $colorKey;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: $pTB $pLR ;
|
||||||
|
|
||||||
|
@include hover() {
|
||||||
|
background: $colorClickIconBgHov;
|
||||||
|
color: $colorClickIconFgHov;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before,
|
||||||
|
*:before {
|
||||||
|
// *:before handles any nested containers that may contain glyph elements
|
||||||
|
// Needed for c-togglebutton.
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin cCtrlWrapper {
|
||||||
|
// Provides a wrapper around buttons and other controls
|
||||||
|
// Contains control and provides positioning context for contained menu/palette.
|
||||||
|
// Wraps --menu elements, contains button and menu
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
|
.c-menu {
|
||||||
|
// Default position of contained menu
|
||||||
|
top: 100%; left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[class*='--menus-up'] {
|
||||||
|
.c-menu {
|
||||||
|
top: auto; bottom: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[class*='--menus-left'] {
|
||||||
|
.c-menu {
|
||||||
|
left: auto; right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@mixin wrappedInput() {
|
@mixin wrappedInput() {
|
||||||
// An input that is wrapped. Optionally includes a __label or icon element.
|
// An input that is wrapped. Optionally includes a __label or icon element.
|
||||||
// Based on .c-search.
|
// Based on .c-search.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "openmct-symbols-16px",
|
"name": "openmct-symbols-16px",
|
||||||
"lastOpened": 0,
|
"lastOpened": 0,
|
||||||
"created": 1529545133464
|
"created": 1537817705550
|
||||||
},
|
},
|
||||||
"iconSets": [
|
"iconSets": [
|
||||||
{
|
{
|
||||||
@ -525,7 +525,7 @@
|
|||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 102,
|
"order": 149,
|
||||||
"prevSize": 24,
|
"prevSize": 24,
|
||||||
"name": "icon-T",
|
"name": "icon-T",
|
||||||
"id": 84,
|
"id": 84,
|
||||||
@ -660,13 +660,21 @@
|
|||||||
"code": 921672,
|
"code": 921672,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"order": 150,
|
||||||
|
"id": 119,
|
||||||
|
"name": "icon-font-size-alt1",
|
||||||
|
"prevSize": 24,
|
||||||
|
"code": 921673,
|
||||||
|
"tempChar": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"order": 37,
|
"order": 37,
|
||||||
"prevSize": 24,
|
"prevSize": 24,
|
||||||
"name": "icon-activity",
|
"name": "icon-activity",
|
||||||
"id": 32,
|
"id": 32,
|
||||||
"code": 921856,
|
"code": 921856,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 36,
|
"order": 36,
|
||||||
@ -674,7 +682,7 @@
|
|||||||
"name": "icon-activity-mode",
|
"name": "icon-activity-mode",
|
||||||
"id": 31,
|
"id": 31,
|
||||||
"code": 921857,
|
"code": 921857,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 52,
|
"order": 52,
|
||||||
@ -682,7 +690,7 @@
|
|||||||
"name": "icon-autoflow-tabular",
|
"name": "icon-autoflow-tabular",
|
||||||
"id": 47,
|
"id": 47,
|
||||||
"code": 921858,
|
"code": 921858,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 55,
|
"order": 55,
|
||||||
@ -690,7 +698,7 @@
|
|||||||
"name": "icon-clock",
|
"name": "icon-clock",
|
||||||
"id": 50,
|
"id": 50,
|
||||||
"code": 921859,
|
"code": 921859,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 58,
|
"order": 58,
|
||||||
@ -698,7 +706,7 @@
|
|||||||
"name": "icon-database",
|
"name": "icon-database",
|
||||||
"id": 53,
|
"id": 53,
|
||||||
"code": 921860,
|
"code": 921860,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 57,
|
"order": 57,
|
||||||
@ -706,7 +714,7 @@
|
|||||||
"name": "icon-database-query",
|
"name": "icon-database-query",
|
||||||
"id": 52,
|
"id": 52,
|
||||||
"code": 921861,
|
"code": 921861,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 17,
|
"order": 17,
|
||||||
@ -714,7 +722,7 @@
|
|||||||
"name": "icon-dataset",
|
"name": "icon-dataset",
|
||||||
"id": 12,
|
"id": 12,
|
||||||
"code": 921862,
|
"code": 921862,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 22,
|
"order": 22,
|
||||||
@ -722,7 +730,7 @@
|
|||||||
"name": "icon-datatable",
|
"name": "icon-datatable",
|
||||||
"id": 17,
|
"id": 17,
|
||||||
"code": 921863,
|
"code": 921863,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 59,
|
"order": 59,
|
||||||
@ -730,7 +738,7 @@
|
|||||||
"name": "icon-dictionary",
|
"name": "icon-dictionary",
|
||||||
"id": 54,
|
"id": 54,
|
||||||
"code": 921864,
|
"code": 921864,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 62,
|
"order": 62,
|
||||||
@ -738,7 +746,7 @@
|
|||||||
"name": "icon-folder",
|
"name": "icon-folder",
|
||||||
"id": 57,
|
"id": 57,
|
||||||
"code": 921865,
|
"code": 921865,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 66,
|
"order": 66,
|
||||||
@ -746,7 +754,7 @@
|
|||||||
"name": "icon-image",
|
"name": "icon-image",
|
||||||
"id": 61,
|
"id": 61,
|
||||||
"code": 921872,
|
"code": 921872,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 68,
|
"order": 68,
|
||||||
@ -754,7 +762,7 @@
|
|||||||
"name": "icon-layout",
|
"name": "icon-layout",
|
||||||
"id": 63,
|
"id": 63,
|
||||||
"code": 921873,
|
"code": 921873,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 77,
|
"order": 77,
|
||||||
@ -762,7 +770,7 @@
|
|||||||
"name": "icon-object",
|
"name": "icon-object",
|
||||||
"id": 72,
|
"id": 72,
|
||||||
"code": 921874,
|
"code": 921874,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 78,
|
"order": 78,
|
||||||
@ -770,7 +778,7 @@
|
|||||||
"name": "icon-object-unknown",
|
"name": "icon-object-unknown",
|
||||||
"id": 73,
|
"id": 73,
|
||||||
"code": 921875,
|
"code": 921875,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 79,
|
"order": 79,
|
||||||
@ -778,7 +786,7 @@
|
|||||||
"name": "icon-packet",
|
"name": "icon-packet",
|
||||||
"id": 74,
|
"id": 74,
|
||||||
"code": 921876,
|
"code": 921876,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 80,
|
"order": 80,
|
||||||
@ -786,7 +794,7 @@
|
|||||||
"name": "icon-page",
|
"name": "icon-page",
|
||||||
"id": 75,
|
"id": 75,
|
||||||
"code": 921877,
|
"code": 921877,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 135,
|
"order": 135,
|
||||||
@ -794,7 +802,7 @@
|
|||||||
"name": "icon-plot-overlay",
|
"name": "icon-plot-overlay",
|
||||||
"prevSize": 24,
|
"prevSize": 24,
|
||||||
"code": 921878,
|
"code": 921878,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 113,
|
"order": 113,
|
||||||
@ -802,7 +810,7 @@
|
|||||||
"name": "icon-plot-stacked",
|
"name": "icon-plot-stacked",
|
||||||
"prevSize": 24,
|
"prevSize": 24,
|
||||||
"code": 921879,
|
"code": 921879,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 10,
|
"order": 10,
|
||||||
@ -810,7 +818,7 @@
|
|||||||
"name": "icon-session",
|
"name": "icon-session",
|
||||||
"id": 5,
|
"id": 5,
|
||||||
"code": 921880,
|
"code": 921880,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 24,
|
"order": 24,
|
||||||
@ -818,7 +826,7 @@
|
|||||||
"name": "icon-tabular",
|
"name": "icon-tabular",
|
||||||
"id": 19,
|
"id": 19,
|
||||||
"code": 921881,
|
"code": 921881,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 7,
|
"order": 7,
|
||||||
@ -826,7 +834,7 @@
|
|||||||
"name": "icon-tabular-lad",
|
"name": "icon-tabular-lad",
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"code": 921888,
|
"code": 921888,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 6,
|
"order": 6,
|
||||||
@ -834,7 +842,7 @@
|
|||||||
"name": "icon-tabular-lad-set",
|
"name": "icon-tabular-lad-set",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"code": 921889,
|
"code": 921889,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 8,
|
"order": 8,
|
||||||
@ -842,7 +850,7 @@
|
|||||||
"name": "icon-tabular-realtime",
|
"name": "icon-tabular-realtime",
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"code": 921890,
|
"code": 921890,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 23,
|
"order": 23,
|
||||||
@ -850,7 +858,7 @@
|
|||||||
"name": "icon-tabular-scrolling",
|
"name": "icon-tabular-scrolling",
|
||||||
"id": 18,
|
"id": 18,
|
||||||
"code": 921891,
|
"code": 921891,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 112,
|
"order": 112,
|
||||||
@ -858,7 +866,7 @@
|
|||||||
"name": "icon-telemetry",
|
"name": "icon-telemetry",
|
||||||
"id": 86,
|
"id": 86,
|
||||||
"code": 921892,
|
"code": 921892,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 90,
|
"order": 90,
|
||||||
@ -866,7 +874,7 @@
|
|||||||
"name": "icon-telemetry-panel",
|
"name": "icon-telemetry-panel",
|
||||||
"id": 85,
|
"id": 85,
|
||||||
"code": 921893,
|
"code": 921893,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 93,
|
"order": 93,
|
||||||
@ -874,15 +882,15 @@
|
|||||||
"name": "icon-timeline",
|
"name": "icon-timeline",
|
||||||
"id": 88,
|
"id": 88,
|
||||||
"code": 921894,
|
"code": 921894,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 116,
|
"order": 116,
|
||||||
"id": 101,
|
"id": 101,
|
||||||
"name": "icon-timer-v1.5",
|
"name": "icon-timer-v15",
|
||||||
"prevSize": 24,
|
"prevSize": 24,
|
||||||
"code": 921895,
|
"code": 921895,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 11,
|
"order": 11,
|
||||||
@ -890,7 +898,7 @@
|
|||||||
"name": "icon-topic",
|
"name": "icon-topic",
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"code": 921896,
|
"code": 921896,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 115,
|
"order": 115,
|
||||||
@ -898,7 +906,7 @@
|
|||||||
"name": "icon-box-with-dashed-lines",
|
"name": "icon-box-with-dashed-lines",
|
||||||
"id": 29,
|
"id": 29,
|
||||||
"code": 921897,
|
"code": 921897,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 126,
|
"order": 126,
|
||||||
@ -906,7 +914,7 @@
|
|||||||
"name": "icon-summary-widget",
|
"name": "icon-summary-widget",
|
||||||
"prevSize": 24,
|
"prevSize": 24,
|
||||||
"code": 921904,
|
"code": 921904,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 139,
|
"order": 139,
|
||||||
@ -914,13 +922,13 @@
|
|||||||
"name": "icon-notebook",
|
"name": "icon-notebook",
|
||||||
"prevSize": 24,
|
"prevSize": 24,
|
||||||
"code": 921905,
|
"code": 921905,
|
||||||
"tempChar": ""
|
"tempChar": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "openmct-symbols-16px",
|
"name": "openmct-symbols-16px",
|
||||||
"importSize": {
|
"importSize": {
|
||||||
"width": 512,
|
"width": 745,
|
||||||
"height": 512
|
"height": 512
|
||||||
},
|
},
|
||||||
"designer": "Charles Hacskaylo",
|
"designer": "Charles Hacskaylo",
|
||||||
@ -2360,7 +2368,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"paths": [
|
"paths": [
|
||||||
"M0 0v256h128v-64h256v704h-192v128h640v-128h-192v-704h256v64h128v-256z"
|
"M800 1024h224l-384-1024h-256l-384 1024h224l84-224h408zM380 608l132-352 132 352z"
|
||||||
],
|
],
|
||||||
"grid": 16,
|
"grid": 16,
|
||||||
"tags": [
|
"tags": [
|
||||||
@ -2368,9 +2376,15 @@
|
|||||||
],
|
],
|
||||||
"defaultCode": 228,
|
"defaultCode": 228,
|
||||||
"id": 84,
|
"id": 84,
|
||||||
"attrs": [],
|
"attrs": [
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
"isMulticolor": false,
|
||||||
|
"isMulticolor2": false,
|
||||||
"colorPermutations": {
|
"colorPermutations": {
|
||||||
"1161751207457516161751": []
|
"1161751207457516161751": [
|
||||||
|
{}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -2840,6 +2854,30 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": 119,
|
||||||
|
"paths": [
|
||||||
|
"M1226.4 320h-176l-76.22 203.24 77 205.34 87.22-232.58 90.74 242h-174.44l49.5 132h174.44l57.76 154h154l-264-704z",
|
||||||
|
"M384 0l-384 1024h224l84-224h408l84 224h224l-384-1024zM380 608l132-352 132 352z"
|
||||||
|
],
|
||||||
|
"attrs": [
|
||||||
|
{},
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
"width": 1490,
|
||||||
|
"isMulticolor": false,
|
||||||
|
"isMulticolor2": false,
|
||||||
|
"grid": 16,
|
||||||
|
"tags": [
|
||||||
|
"icon-font-size-alt1"
|
||||||
|
],
|
||||||
|
"colorPermutations": {
|
||||||
|
"1161751207457516161751": [
|
||||||
|
{},
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"paths": [
|
"paths": [
|
||||||
"M576 64h-256l320 320h-290.256c-44.264-76.516-126.99-128-221.744-128h-128v512h128c94.754 0 177.48-51.484 221.744-128h290.256l-320 320h256l448-448-448-448z"
|
"M576 64h-256l320 320h-290.256c-44.264-76.516-126.99-128-221.744-128h-128v512h128c94.754 0 177.48-51.484 221.744-128h290.256l-320 320h256l448-448-448-448z"
|
||||||
@ -3740,7 +3778,9 @@
|
|||||||
"classSelector": ".ui-symbol",
|
"classSelector": ".ui-symbol",
|
||||||
"showMetrics": true,
|
"showMetrics": true,
|
||||||
"showMetadata": true,
|
"showMetadata": true,
|
||||||
"embed": false
|
"embed": false,
|
||||||
|
"noie8": true,
|
||||||
|
"ie7": false
|
||||||
},
|
},
|
||||||
"imagePref": {
|
"imagePref": {
|
||||||
"prefix": "icon-",
|
"prefix": "icon-",
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
<glyph unicode="󡀩" glyph-name="icon-refresh" d="M960 528v432l-164.8-164.8c-79.8 65.2-178.8 100.8-283.2 100.8-119.6 0-232.2-46.6-316.8-131.2s-131.2-197.2-131.2-316.8 46.6-232.2 131.2-316.8c84.6-84.6 197.2-131.2 316.8-131.2s232.2 46.6 316.8 131.2c69.4 69.4 113.2 157.4 126.6 252.8h-130c-29.8-145.8-159-256-313.6-256-176.4 0-320 143.6-320 320s143.8 320 320.2 320c72 0 138.4-23.8 192-64l-176-176h432z" />
|
<glyph unicode="󡀩" glyph-name="icon-refresh" d="M960 528v432l-164.8-164.8c-79.8 65.2-178.8 100.8-283.2 100.8-119.6 0-232.2-46.6-316.8-131.2s-131.2-197.2-131.2-316.8 46.6-232.2 131.2-316.8c84.6-84.6 197.2-131.2 316.8-131.2s232.2 46.6 316.8 131.2c69.4 69.4 113.2 157.4 126.6 252.8h-130c-29.8-145.8-159-256-313.6-256-176.4 0-320 143.6-320 320s143.8 320 320.2 320c72 0 138.4-23.8 192-64l-176-176h432z" />
|
||||||
<glyph unicode="󡀰" glyph-name="icon-save" d="M192.2 384c-0.2 0-0.2 0 0 0l-0.2-448h640v447.8c0 0 0 0-0.2 0.2h-639.6zM978.8 749.2l-165.4 165.4c-25 25-74.2 45.4-109.4 45.4h-576c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128v448c0 35.2 28.8 64 64 64h640c35.2 0 64-28.8 64-64v-448c70.4 0 128 57.6 128 128v576c0 35.2-20.4 84.4-45.2 109.2zM704 704c0-35.2-28.8-64-64-64h-448c-35.2 0-64 28.8-64 64v192h320v-192h128v192h128v-192z" />
|
<glyph unicode="󡀰" glyph-name="icon-save" d="M192.2 384c-0.2 0-0.2 0 0 0l-0.2-448h640v447.8c0 0 0 0-0.2 0.2h-639.6zM978.8 749.2l-165.4 165.4c-25 25-74.2 45.4-109.4 45.4h-576c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128v448c0 35.2 28.8 64 64 64h640c35.2 0 64-28.8 64-64v-448c70.4 0 128 57.6 128 128v576c0 35.2-20.4 84.4-45.2 109.2zM704 704c0-35.2-28.8-64-64-64h-448c-35.2 0-64 28.8-64 64v192h320v-192h128v192h128v-192z" />
|
||||||
<glyph unicode="󡀱" glyph-name="icon-sine" d="M1022.294 448c-1.746 7.196-3.476 14.452-5.186 21.786-20.036 85.992-53.302 208.976-98 306.538-22.42 48.938-45.298 86.556-69.946 115.006-48.454 55.93-98.176 67.67-131.356 67.67s-82.902-11.74-131.356-67.672c-24.648-28.45-47.528-66.068-69.948-115.006-44.696-97.558-77.962-220.544-98-306.538-21.646-92.898-46.444-175.138-71.71-237.836-16.308-40.46-30.222-66.358-40.6-82.604-10.378 16.246-24.292 42.142-40.6 82.604-23.272 57.75-46.144 132.088-66.524 216.052h-197.362c1.746-7.196 3.476-14.452 5.186-21.786 20.036-85.992 53.302-208.976 98-306.538 22.42-48.938 45.298-86.556 69.946-115.006 48.454-55.932 98.176-67.672 131.356-67.672s82.902 11.74 131.356 67.672c24.648 28.45 47.528 66.068 69.948 115.006 44.696 97.558 77.962 220.544 98 306.538 21.646 92.898 46.444 175.138 71.71 237.836 16.308 40.46 30.222 66.358 40.6 82.604 10.378-16.246 24.292-42.142 40.6-82.604 23.274-57.748 46.146-132.086 66.526-216.050h197.36z" />
|
<glyph unicode="󡀱" glyph-name="icon-sine" d="M1022.294 448c-1.746 7.196-3.476 14.452-5.186 21.786-20.036 85.992-53.302 208.976-98 306.538-22.42 48.938-45.298 86.556-69.946 115.006-48.454 55.93-98.176 67.67-131.356 67.67s-82.902-11.74-131.356-67.672c-24.648-28.45-47.528-66.068-69.948-115.006-44.696-97.558-77.962-220.544-98-306.538-21.646-92.898-46.444-175.138-71.71-237.836-16.308-40.46-30.222-66.358-40.6-82.604-10.378 16.246-24.292 42.142-40.6 82.604-23.272 57.75-46.144 132.088-66.524 216.052h-197.362c1.746-7.196 3.476-14.452 5.186-21.786 20.036-85.992 53.302-208.976 98-306.538 22.42-48.938 45.298-86.556 69.946-115.006 48.454-55.932 98.176-67.672 131.356-67.672s82.902 11.74 131.356 67.672c24.648 28.45 47.528 66.068 69.948 115.006 44.696 97.558 77.962 220.544 98 306.538 21.646 92.898 46.444 175.138 71.71 237.836 16.308 40.46 30.222 66.358 40.6 82.604 10.378-16.246 24.292-42.142 40.6-82.604 23.274-57.748 46.146-132.086 66.526-216.050h197.36z" />
|
||||||
<glyph unicode="󡀲" glyph-name="icon-T" d="M0 960v-256h128v64h256v-704h-192v-128h640v128h-192v704h256v-64h128v256z" />
|
<glyph unicode="󡀲" glyph-name="icon-T" d="M800-64h224l-384 1024h-256l-384-1024h224l84 224h408zM380 352l132 352 132-352z" />
|
||||||
<glyph unicode="󡀳" glyph-name="icon-thumbs-strip" d="M448 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM448 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320z" />
|
<glyph unicode="󡀳" glyph-name="icon-thumbs-strip" d="M448 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM448 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320z" />
|
||||||
<glyph unicode="󡀴" glyph-name="icon-two-parts-both" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM128 832h320v-768h-320v768zM896 64h-320v768h320v-768z" />
|
<glyph unicode="󡀴" glyph-name="icon-two-parts-both" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM128 832h320v-768h-320v768zM896 64h-320v768h320v-768z" />
|
||||||
<glyph unicode="󡀵" glyph-name="icon-two-parts-one-only" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM896 64h-320v768h320v-768z" />
|
<glyph unicode="󡀵" glyph-name="icon-two-parts-one-only" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM896 64h-320v768h320v-768z" />
|
||||||
@ -88,6 +88,7 @@
|
|||||||
<glyph unicode="󡁆" glyph-name="icon-frame-hide" d="M128 770h420l104 128h-652v-802.4l128 157.4zM896 130h-420l-104-128h652v802.4l-128-157.4zM832 962l-832-1024h192l832 1024zM392 578l104 128h-304v-128z" />
|
<glyph unicode="󡁆" glyph-name="icon-frame-hide" d="M128 770h420l104 128h-652v-802.4l128 157.4zM896 130h-420l-104-128h652v802.4l-128-157.4zM832 962l-832-1024h192l832 1024zM392 578l104 128h-304v-128z" />
|
||||||
<glyph unicode="󡁇" glyph-name="icon-import" d="M832 767.6v-639.4c0-0.2-0.2-0.2-0.4-0.4h-319.6v-192h320c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192h-320v-192h319.6c0.2 0 0.4-0.2 0.4-0.4zM192 256v-192l384 384-384 384v-192h-192v-384z" />
|
<glyph unicode="󡁇" glyph-name="icon-import" d="M832 767.6v-639.4c0-0.2-0.2-0.2-0.4-0.4h-319.6v-192h320c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192h-320v-192h319.6c0.2 0 0.4-0.2 0.4-0.4zM192 256v-192l384 384-384 384v-192h-192v-384z" />
|
||||||
<glyph unicode="󡁈" glyph-name="icon-export" d="M192 128.34v639.32l0.34 0.34h319.66v192h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h320v192h-319.66zM1024 448l-384 384v-192h-192v-384h192v-192l384 384z" />
|
<glyph unicode="󡁈" glyph-name="icon-export" d="M192 128.34v639.32l0.34 0.34h319.66v192h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h320v192h-319.66zM1024 448l-384 384v-192h-192v-384h192v-192l384 384z" />
|
||||||
|
<glyph unicode="󡁉" glyph-name="icon-font-size-alt1" horiz-adv-x="1490" d="M1226.4 640h-176l-76.22-203.24 77-205.34 87.22 232.58 90.74-242h-174.44l49.5-132h174.44l57.76-154h154l-264 704zM384 960l-384-1024h224l84 224h408l84-224h224l-384 1024zM380 352l132 352 132-352z" />
|
||||||
<glyph unicode="󡄀" glyph-name="icon-activity" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
|
<glyph unicode="󡄀" glyph-name="icon-activity" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
|
||||||
<glyph unicode="󡄁" glyph-name="icon-activity-mode" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
|
<glyph unicode="󡄁" glyph-name="icon-activity-mode" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
|
||||||
<glyph unicode="󡄂" glyph-name="icon-autoflow-tabular" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
|
<glyph unicode="󡄂" glyph-name="icon-autoflow-tabular" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
|
||||||
@ -115,7 +116,7 @@
|
|||||||
<glyph unicode="󡄤" glyph-name="icon-telemetry" d="M32 328.34c14.28 5.62 54.44 47.54 92.96 146 42.46 108.38 116.32 237.66 227.040 237.66 52.4 0 101.42-29.16 145.7-86.68 37.34-48.5 64.84-108.92 81.34-151.080 38.52-98.38 78.68-140.3 92.96-146 14.28 5.62 54.44 47.54 92.96 146 37.4 95.5 99.14 207.14 188.94 232.46-90.462 152.598-254.314 253.3-441.686 253.3-0.075 0-0.15 0-0.226 0-282.748 0-511.988-229.24-511.988-512 0-0.032 0-0.070 0-0.108 0-35.719 3.641-70.587 10.572-104.255 8.968-7.457 16.648-13.417 21.428-15.297zM992 567.66c-14.28-5.62-54.44-47.52-92.96-146-42.46-108.38-116.32-237.66-227.040-237.66-52.4 0-101.42 29.16-145.7 86.68-37.34 48.5-64.84 108.92-81.34 151.080-38.52 98.38-78.68 140.3-92.96 146-14.28-5.62-54.44-47.52-92.96-146-37.4-95.5-99.14-207.14-188.94-232.46 90.462-152.598 254.314-253.3 441.686-253.3 0.075 0 0.15 0 0.226 0 282.748 0 511.988 229.24 511.988 512 0 0.032 0 0.070 0 0.108 0 35.719-3.641 70.587-10.572 104.255-8.968 7.457-16.648 13.417-21.428 15.297z" />
|
<glyph unicode="󡄤" glyph-name="icon-telemetry" d="M32 328.34c14.28 5.62 54.44 47.54 92.96 146 42.46 108.38 116.32 237.66 227.040 237.66 52.4 0 101.42-29.16 145.7-86.68 37.34-48.5 64.84-108.92 81.34-151.080 38.52-98.38 78.68-140.3 92.96-146 14.28 5.62 54.44 47.54 92.96 146 37.4 95.5 99.14 207.14 188.94 232.46-90.462 152.598-254.314 253.3-441.686 253.3-0.075 0-0.15 0-0.226 0-282.748 0-511.988-229.24-511.988-512 0-0.032 0-0.070 0-0.108 0-35.719 3.641-70.587 10.572-104.255 8.968-7.457 16.648-13.417 21.428-15.297zM992 567.66c-14.28-5.62-54.44-47.52-92.96-146-42.46-108.38-116.32-237.66-227.040-237.66-52.4 0-101.42 29.16-145.7 86.68-37.34 48.5-64.84 108.92-81.34 151.080-38.52 98.38-78.68 140.3-92.96 146-14.28-5.62-54.44-47.52-92.96-146-37.4-95.5-99.14-207.14-188.94-232.46 90.462-152.598 254.314-253.3 441.686-253.3 0.075 0 0.15 0 0.226 0 282.748 0 511.988 229.24 511.988 512 0 0.032 0 0.070 0 0.108 0 35.719-3.641 70.587-10.572 104.255-8.968 7.457-16.648 13.417-21.428 15.297z" />
|
||||||
<glyph unicode="󡄥" glyph-name="icon-telemetry-panel" d="M169.2 512c14 56.4 33 122 56.6 176.8 15.4 35.8 31.2 63.2 48.2 84 18.4 22.4 49 49.2 91 49.2s72.6-26.8 91-49.2c17-20.6 32.6-48.2 48.2-84 23.6-54.8 42.8-120.4 56.6-176.8h461.2v256c0 105.6-86.4 192-192 192h-640c-105.6 0-192-86.4-192-192v-256h171.2zM718.6 384h-127.2c25-93.4 48.4-144.4 63.6-168.6 15.2 24.2 38.6 75.2 63.6 168.6zM301.4 512h127.2c-25 93.4-48.4 144.4-63.6 168.6-15.2-24.2-38.6-75.2-63.6-168.6zM850.8 384c-14-56.4-33-122-56.6-176.8-15.4-35.8-31.2-63.2-48.2-84-18.4-22.4-49-49.2-91-49.2s-72.6 26.8-91 49.2c-17 20.6-32.6 48.2-48.2 84-23.6 54.8-42.8 120.4-56.6 176.8h-461.2v-256c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v256h-171.2z" />
|
<glyph unicode="󡄥" glyph-name="icon-telemetry-panel" d="M169.2 512c14 56.4 33 122 56.6 176.8 15.4 35.8 31.2 63.2 48.2 84 18.4 22.4 49 49.2 91 49.2s72.6-26.8 91-49.2c17-20.6 32.6-48.2 48.2-84 23.6-54.8 42.8-120.4 56.6-176.8h461.2v256c0 105.6-86.4 192-192 192h-640c-105.6 0-192-86.4-192-192v-256h171.2zM718.6 384h-127.2c25-93.4 48.4-144.4 63.6-168.6 15.2 24.2 38.6 75.2 63.6 168.6zM301.4 512h127.2c-25 93.4-48.4 144.4-63.6 168.6-15.2-24.2-38.6-75.2-63.6-168.6zM850.8 384c-14-56.4-33-122-56.6-176.8-15.4-35.8-31.2-63.2-48.2-84-18.4-22.4-49-49.2-91-49.2s-72.6 26.8-91 49.2c-17 20.6-32.6 48.2-48.2 84-23.6 54.8-42.8 120.4-56.6 176.8h-461.2v-256c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v256h-171.2z" />
|
||||||
<glyph unicode="󡄦" glyph-name="icon-timeline" d="M256 704h384v-128h-384v128zM384 512h384v-128h-384v128zM320 320h384v-128h-384v128zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.2c0 0.2 0.2 0.2 0.4 0.4h127.6v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4z" />
|
<glyph unicode="󡄦" glyph-name="icon-timeline" d="M256 704h384v-128h-384v128zM384 512h384v-128h-384v128zM320 320h384v-128h-384v128zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.2c0 0.2 0.2 0.2 0.4 0.4h127.6v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4z" />
|
||||||
<glyph unicode="󡄧" glyph-name="icon-timer-v1.5" horiz-adv-x="896" d="M576 813.4v82.58c0 35.346-28.654 64-64 64h-128c-35.346 0-64-28.654-64-64v-82.58c-185.040-55.080-320-226.48-320-429.42 0-247.42 200.58-448 448-448s448 200.58 448 448c0 202.96-135 374.4-320 429.42zM468 363.98l-263.76-211c-57.105 59.935-92.24 141.251-92.24 230.772 0 0.080 0 0.16 0 0.24 0 185.268 150.72 335.988 336 335.988 6.72 0 13.38-0.22 20-0.62v-355.38z" />
|
<glyph unicode="󡄧" glyph-name="icon-timer-v15" horiz-adv-x="896" d="M576 813.4v82.58c0 35.346-28.654 64-64 64h-128c-35.346 0-64-28.654-64-64v-82.58c-185.040-55.080-320-226.48-320-429.42 0-247.42 200.58-448 448-448s448 200.58 448 448c0 202.96-135 374.4-320 429.42zM468 363.98l-263.76-211c-57.105 59.935-92.24 141.251-92.24 230.772 0 0.080 0 0.16 0 0.24 0 185.268 150.72 335.988 336 335.988 6.72 0 13.38-0.22 20-0.62v-355.38z" />
|
||||||
<glyph unicode="󡄨" glyph-name="icon-topic" d="M454.36 483.36l86.3 86.3c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c19.328-19.358 42.832-34.541 69.047-44.082l1.313 171.722-57.64 57.64c-34.407 34.33-81.9 55.558-134.35 55.558s-99.943-21.228-134.354-55.562l-86.296-86.297c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-28.674 28.654v-172.14c19.045-7.022 41.040-11.084 63.984-11.084 52.463 0 99.966 21.239 134.379 55.587zM505.64 412.64l-86.3-86.3c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-86.294 86.294c-2 2-4.2 4-6.36 6v-197.36c33.664-30.72 78.65-49.537 128.031-49.537 52.44 0 99.923 21.22 134.333 55.541l86.296 86.296c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c2-2 4.2-4 6.36-6v197.36c-33.664 30.72-78.65 49.537-128.031 49.537-52.44 0-99.923-21.22-134.333-55.541zM832 960h-128v-192h127.66l0.34-0.34v-639.32l-0.34-0.34h-127.66v-192h128c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM320 128h-127.66l-0.34 0.34v639.32l0.34 0.34h127.66v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192z" />
|
<glyph unicode="󡄨" glyph-name="icon-topic" d="M454.36 483.36l86.3 86.3c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c19.328-19.358 42.832-34.541 69.047-44.082l1.313 171.722-57.64 57.64c-34.407 34.33-81.9 55.558-134.35 55.558s-99.943-21.228-134.354-55.562l-86.296-86.297c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-28.674 28.654v-172.14c19.045-7.022 41.040-11.084 63.984-11.084 52.463 0 99.966 21.239 134.379 55.587zM505.64 412.64l-86.3-86.3c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-86.294 86.294c-2 2-4.2 4-6.36 6v-197.36c33.664-30.72 78.65-49.537 128.031-49.537 52.44 0 99.923 21.22 134.333 55.541l86.296 86.296c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c2-2 4.2-4 6.36-6v197.36c-33.664 30.72-78.65 49.537-128.031 49.537-52.44 0-99.923-21.22-134.333-55.541zM832 960h-128v-192h127.66l0.34-0.34v-639.32l-0.34-0.34h-127.66v-192h128c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM320 128h-127.66l-0.34 0.34v639.32l0.34 0.34h127.66v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192z" />
|
||||||
<glyph unicode="󡄩" glyph-name="icon-box-with-dashed-lines" d="M0 576h128v-256h-128v256zM128 831.78l0.22 0.22h191.78v128h-192c-70.606-0.215-127.785-57.394-128-127.979v-192.021h128v191.78zM128 64.22v191.78h-128v-192c0.215-70.606 57.394-127.785 127.979-128h192.021v128h-191.78zM384 960h256v-128h-256v128zM896 64.22l-0.22-0.22h-191.78v-128h192c70.606 0.215 127.785 57.394 128 127.979v192.021h-128v-191.78zM896 960h-192v-128h191.78l0.22-0.22v-191.78h128v192c-0.215 70.606-57.394 127.785-127.979 128zM896 576h128v-256h-128v256zM384 64h256v-128h-256v128zM256 704h512v-512h-512v512z" />
|
<glyph unicode="󡄩" glyph-name="icon-box-with-dashed-lines" d="M0 576h128v-256h-128v256zM128 831.78l0.22 0.22h191.78v128h-192c-70.606-0.215-127.785-57.394-128-127.979v-192.021h128v191.78zM128 64.22v191.78h-128v-192c0.215-70.606 57.394-127.785 127.979-128h192.021v128h-191.78zM384 960h256v-128h-256v128zM896 64.22l-0.22-0.22h-191.78v-128h192c70.606 0.215 127.785 57.394 128 127.979v192.021h-128v-191.78zM896 960h-192v-128h191.78l0.22-0.22v-191.78h128v192c-0.215 70.606-57.394 127.785-127.979 128zM896 576h128v-256h-128v256zM384 64h256v-128h-256v128zM256 704h512v-512h-512v512z" />
|
||||||
<glyph unicode="󡄰" glyph-name="icon-summary-widget" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM847.8 349.6l-82.6-143.2-189.6 131.6 19.2-230h-165.4l19.2 230-189.6-131.6-82.6 143.2 208.6 98.4-208.8 98.4 82.6 143.2 189.6-131.6-19.2 230h165.4l-19.2-230 189.6 131.6 82.6-143.2-208.6-98.4 208.8-98.4z" />
|
<glyph unicode="󡄰" glyph-name="icon-summary-widget" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM847.8 349.6l-82.6-143.2-189.6 131.6 19.2-230h-165.4l19.2 230-189.6-131.6-82.6 143.2 208.6 98.4-208.8 98.4 82.6 143.2 189.6-131.6-19.2 230h165.4l-19.2-230 189.6 131.6 82.6-143.2-208.6-98.4 208.8-98.4z" />
|
||||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Binary file not shown.
Binary file not shown.
@ -24,8 +24,8 @@
|
|||||||
//!********************************* CONTROLS *!
|
//!********************************* CONTROLS *!
|
||||||
//@import "../styles/controls/breadcrumb";
|
//@import "../styles/controls/breadcrumb";
|
||||||
@import "../styles/controls/buttons";
|
@import "../styles/controls/buttons";
|
||||||
@import "../styles/controls/palette";
|
//@import "../styles/controls/palette";
|
||||||
@import "../styles/controls/controls";
|
//@import "../styles/controls/controls";
|
||||||
@import "../styles/controls/lists";
|
@import "../styles/controls/lists";
|
||||||
@import "../styles/controls/menus";
|
@import "../styles/controls/menus";
|
||||||
@import "../styles/controls/messages";
|
@import "../styles/controls/messages";
|
||||||
@ -46,7 +46,7 @@
|
|||||||
//@import "../styles/search/search";
|
//@import "../styles/search/search";
|
||||||
//@import "../styles/mobile/search/search";
|
//@import "../styles/mobile/search/search";
|
||||||
@import "../styles/overlay/overlay";
|
@import "../styles/overlay/overlay";
|
||||||
//@import "../styles/tree/tree";
|
@import "../styles/tree/tree"; // TEMP - NEED FOR TREE IN INSPECTOR
|
||||||
@import "../styles/object-label";
|
@import "../styles/object-label";
|
||||||
//@import "../styles/mobile/tree";
|
//@import "../styles/mobile/tree";
|
||||||
@import "../styles/user-environ/frame";
|
@import "../styles/user-environ/frame";
|
||||||
|
@ -116,7 +116,6 @@
|
|||||||
$p: $interiorMarginSm;
|
$p: $interiorMarginSm;
|
||||||
@include discreteItem();
|
@include discreteItem();
|
||||||
display: flex;
|
display: flex;
|
||||||
//flex-wrap: wrap;
|
|
||||||
padding: $interiorMarginSm $interiorMarginSm $interiorMarginSm $interiorMargin;
|
padding: $interiorMarginSm $interiorMarginSm $interiorMarginSm $interiorMargin;
|
||||||
|
|
||||||
&__time,
|
&__time,
|
||||||
@ -156,7 +155,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__text {
|
&__text {
|
||||||
min-height: 24px; // Needed in Firefox when field is blank
|
min-height: 22px; // Needed in Firefox when field is blank
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
|
||||||
&.is-blank-notebook-entry {
|
&.is-blank-notebook-entry {
|
||||||
|
@ -24,5 +24,6 @@
|
|||||||
// Meant for use as a single line import in Vue SFC's.
|
// Meant for use as a single line import in Vue SFC's.
|
||||||
// Do not include anything that renders to CSS!
|
// Do not include anything that renders to CSS!
|
||||||
@import "constants";
|
@import "constants";
|
||||||
@import "constants-snow"; // TEMP
|
@import "constants-espresso"; // TEMP
|
||||||
|
//@import "constants-snow"; // TEMP
|
||||||
@import "mixins";
|
@import "mixins";
|
@ -21,6 +21,26 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/************************************************************* WIDGET OBJECT */
|
/************************************************************* WIDGET OBJECT */
|
||||||
|
@mixin cSummaryWidget() {
|
||||||
|
@include boxShdw($shdwBtns);
|
||||||
|
border-radius: $basicCr;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
cursor: default;
|
||||||
|
&[href] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
&:before {
|
||||||
|
// Widget icon
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.l-summary-widget {
|
.l-summary-widget {
|
||||||
// Widget layout classes here
|
// Widget layout classes here
|
||||||
@include ellipsize();
|
@include ellipsize();
|
||||||
@ -33,19 +53,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.s-summary-widget {
|
.c-summary-widget {
|
||||||
// Widget style classes here
|
@include cSummaryWidget();
|
||||||
@include boxShdw($shdwBtns);
|
|
||||||
border-radius: $basicCr;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 1px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
cursor: default;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
padding: $interiorMarginLg $interiorMarginLg * 2;
|
padding: $interiorMarginLg $interiorMarginLg * 2;
|
||||||
&[href] {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget-edit-holder {
|
.widget-edit-holder {
|
||||||
@ -267,7 +277,6 @@
|
|||||||
|
|
||||||
.widget-thumb {
|
.widget-thumb {
|
||||||
@include ellipsize();
|
@include ellipsize();
|
||||||
@extend .s-summary-widget;
|
@include cSummaryWidget();
|
||||||
@extend .l-summary-widget;
|
|
||||||
padding: $interiorMarginSm $interiorMargin;
|
padding: $interiorMarginSm $interiorMargin;
|
||||||
}
|
}
|
@ -31,10 +31,6 @@
|
|||||||
|
|
||||||
.c-create-button,
|
.c-create-button,
|
||||||
.c-create-menu {
|
.c-create-menu {
|
||||||
&--w {
|
|
||||||
// Wrapper for Create button and menu
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
168
src/ui/components/controls/checkboxCustom.vue
Normal file
168
src/ui/components/controls/checkboxCustom.vue
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<template>
|
||||||
|
<div class="c-custom-checkbox">
|
||||||
|
<input type="checkbox"
|
||||||
|
:id="id"
|
||||||
|
:name="name"
|
||||||
|
:value="value"
|
||||||
|
:required="required"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="onChange"
|
||||||
|
:checked="state">
|
||||||
|
<label :for="id">
|
||||||
|
<div class="c-custom-checkbox__box"></div>
|
||||||
|
<div class="c-custom-checkbox__label-text">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
.c-custom-checkbox {
|
||||||
|
$d: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
label {
|
||||||
|
@include userSelectNone();
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__box {
|
||||||
|
@include nice-input();
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: $d;
|
||||||
|
width: $d;
|
||||||
|
height: $d;
|
||||||
|
margin-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
&:checked + label > .c-custom-checkbox__box {
|
||||||
|
background: $colorKey;
|
||||||
|
&:before {
|
||||||
|
color: $colorKeyFg;
|
||||||
|
content: $glyph-icon-check;
|
||||||
|
font-family: symbolsfont;
|
||||||
|
font-size: 0.6em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:disabled) + label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled + label {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/*
|
||||||
|
Custom checkbox control. Use just like a checkbox in HTML, except label string is passed within tag.
|
||||||
|
Supports value, true-value, false-value, checked and disabled attributes.
|
||||||
|
Example usage:
|
||||||
|
<checkbox checked>Enable markers</checkbox>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
model: {
|
||||||
|
prop: 'modelValue',
|
||||||
|
event: 'input'
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: function () {
|
||||||
|
return 'checkbox-id-' + this._uid;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
checked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
model: {}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
state() {
|
||||||
|
if (this.modelValue === undefined) {
|
||||||
|
return this.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(this.modelValue)) {
|
||||||
|
return this.modelValue.indexOf(this.value) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!this.modelValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onChange() {
|
||||||
|
this.toggle();
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
let value;
|
||||||
|
|
||||||
|
if (Array.isArray(this.modelValue)) {
|
||||||
|
value = this.modelValue.slice(0);
|
||||||
|
|
||||||
|
if (this.state) {
|
||||||
|
value.splice(value.indexOf(this.value), 1);
|
||||||
|
} else {
|
||||||
|
value.push(this.value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = !this.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('input', value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
checked(newValue) {
|
||||||
|
if (newValue !== this.state) {
|
||||||
|
this.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
if (this.checked && !this.state) {
|
||||||
|
this.toggle();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
51
src/ui/components/controls/labeledNumberInput.vue
Normal file
51
src/ui/components/controls/labeledNumberInput.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<div class="c-labeled-input"
|
||||||
|
:title="title">
|
||||||
|
<div class="c-labeled-input__label">{{ label }}</div>
|
||||||
|
<input type="number"
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-bind:value="value"
|
||||||
|
v-on="inputListeners"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/* Emits input and clear events */
|
||||||
|
export default {
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: {
|
||||||
|
value: String,
|
||||||
|
label: String,
|
||||||
|
title: String
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
inputListeners: function () {
|
||||||
|
let vm = this;
|
||||||
|
return Object.assign({},
|
||||||
|
this.$listeners,
|
||||||
|
{
|
||||||
|
input: function (event) {
|
||||||
|
vm.$emit('input', event.target.value);
|
||||||
|
},
|
||||||
|
change: function (event) {
|
||||||
|
vm.$emit('change', event.target.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
// active: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clearInput() {
|
||||||
|
// Clear the user's input and set 'active' to false
|
||||||
|
this.value = '';
|
||||||
|
this.$emit('clear','');
|
||||||
|
this.active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -5,7 +5,6 @@
|
|||||||
'l-pane--horizontal-handle-after': type === 'horizontal' && handle === 'after',
|
'l-pane--horizontal-handle-after': type === 'horizontal' && handle === 'after',
|
||||||
'l-pane--vertical-handle-before': type === 'vertical' && handle === 'before',
|
'l-pane--vertical-handle-before': type === 'vertical' && handle === 'before',
|
||||||
'l-pane--vertical-handle-after': type === 'vertical' && handle === 'after',
|
'l-pane--vertical-handle-after': type === 'vertical' && handle === 'after',
|
||||||
'l-pane--collapsable' : collapsable,
|
|
||||||
'l-pane--collapsed': collapsed,
|
'l-pane--collapsed': collapsed,
|
||||||
'l-pane--reacts': !handle,
|
'l-pane--reacts': !handle,
|
||||||
'l-pane--resizing': resizing === true
|
'l-pane--resizing': resizing === true
|
||||||
@ -14,11 +13,13 @@
|
|||||||
class="l-pane__handle"
|
class="l-pane__handle"
|
||||||
@mousedown="start">
|
@mousedown="start">
|
||||||
</div>
|
</div>
|
||||||
<button v-if="label"
|
<div class="l-pane__header"
|
||||||
class="l-pane__collapse-button"
|
v-if="label">
|
||||||
@click="toggleCollapse">
|
|
||||||
<span class="l-pane__label">{{ label }}</span>
|
<span class="l-pane__label">{{ label }}</span>
|
||||||
</button>
|
<button class="l-pane__collapse-button c-button"
|
||||||
|
v-if="collapsable"
|
||||||
|
@click="toggleCollapse"></button>
|
||||||
|
</div>
|
||||||
<div class="l-pane__contents">
|
<div class="l-pane__contents">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
@ -61,14 +62,11 @@
|
|||||||
// __handle and __label don't appear in mobile
|
// __handle and __label don't appear in mobile
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__collapse-button {
|
&__header {
|
||||||
position: absolute;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
margin-bottom: $interiorMargin;
|
||||||
top: 0; right: 0; // Default
|
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&--reacts {
|
&--reacts {
|
||||||
@ -85,6 +83,7 @@
|
|||||||
transition: opacity 150ms ease;
|
transition: opacity 150ms ease;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
min-width: 0 !important;
|
min-width: 0 !important;
|
||||||
@ -111,7 +110,6 @@
|
|||||||
&__contents {
|
&__contents {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
padding: $interiorMargin;
|
|
||||||
pointer-events: inherit;
|
pointer-events: inherit;
|
||||||
transition: opacity 250ms ease 250ms;
|
transition: opacity 250ms ease 250ms;
|
||||||
|
|
||||||
@ -121,13 +119,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
> [class*="__"] + [class*="__"] {
|
> [class*="__"] + [class*="__"] {
|
||||||
// Create margin between elements in a pane
|
|
||||||
// Doesn't match first elem, but will match all subsequent
|
|
||||||
margin-top: $interiorMargin;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************ DESKTOP STYLES */
|
/************************************************ DESKTOP STYLES */
|
||||||
body.desktop & {
|
body.desktop & {
|
||||||
&__handle {
|
&__handle {
|
||||||
background: $colorSplitterBg;
|
background: $colorSplitterBg;
|
||||||
@ -150,52 +145,35 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
font-size: floor(12px * .9);
|
||||||
|
}
|
||||||
|
|
||||||
&__collapse-button {
|
&__collapse-button {
|
||||||
$m: 2px;
|
box-shadow: none;
|
||||||
$h: 12px;
|
background: $splitterBtnColorBg;
|
||||||
color: $splitterBtnColorFg;
|
color: $splitterBtnColorFg;
|
||||||
flex: 0 0 nth($splitterBtnD, 1);
|
border-radius: $smallCr;
|
||||||
font-size: $h * .9;
|
font-size: 6px;
|
||||||
position: relative;
|
line-height: 90%;
|
||||||
justify-content: start;
|
padding: 3px 15px;
|
||||||
transition: $transOut;
|
|
||||||
|
|
||||||
&:after {
|
@include hover() {
|
||||||
// Close icon
|
background: $colorBtnBgHov;
|
||||||
background: $colorBtnBg;
|
color: $colorBtnFgHov;
|
||||||
border-radius: $smallCr;
|
|
||||||
color: $colorBtnFg;
|
|
||||||
content: $glyph-icon-arrow-right-equilateral;
|
|
||||||
display: block;
|
|
||||||
font-family: symbolsfont;
|
|
||||||
font-size: 6px;
|
|
||||||
line-height: 90%;
|
|
||||||
padding: 3px 15px;
|
|
||||||
position: absolute;
|
|
||||||
right: $m;
|
|
||||||
top: $m;
|
|
||||||
transition: $transOut;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba(black, 0.1);
|
|
||||||
&:after {
|
|
||||||
background: $splitterBtnColorHoverBg;
|
|
||||||
color: $splitterBtnColorHoverFg;
|
|
||||||
transition: $transIn;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__label {
|
&__label {
|
||||||
// Name of the pane
|
// Name of the pane
|
||||||
@include ellipsize();
|
@include ellipsize();
|
||||||
|
@include userSelectNone();
|
||||||
|
color: $splitterBtnLabelColorFg;
|
||||||
display: block;
|
display: block;
|
||||||
padding-right: nth($splitterBtnD, 2) + $interiorMargin; // Force label to ellipsis
|
pointer-events: none;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
flex: 1 0 90%;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--resizing {
|
&--resizing {
|
||||||
@ -208,6 +186,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&[class*="--collapsed"] {
|
&[class*="--collapsed"] {
|
||||||
|
/********************************* STYLES FOR DESKTOP COLLAPSED PANES, ALL ORIENTATIONS */
|
||||||
$d: nth($splitterBtnD, 1);
|
$d: nth($splitterBtnD, 1);
|
||||||
flex-basis: $d;
|
flex-basis: $d;
|
||||||
min-width: $d !important;
|
min-width: $d !important;
|
||||||
@ -217,19 +196,24 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .l-pane__collapse-button {
|
.l-pane__header {
|
||||||
background: $splitterBtnColorFg;
|
|
||||||
color: $splitterBtnColorBg;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $splitterBtnColorHoverBg !important;
|
color: $splitterCollapsedBtnColorFgHov;
|
||||||
|
.l-pane__label {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
.l-pane__collapse-button {
|
||||||
|
background: $splitterCollapsedBtnColorBgHov;
|
||||||
|
color: inherit;
|
||||||
|
transition: $transIn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
> .l-pane__collapse-button {
|
.l-pane__collapse-button {
|
||||||
height: nth($splitterBtnD, 1);
|
background: $splitterCollapsedBtnColorBg;
|
||||||
padding: $interiorMarginSm $interiorMarginSm;
|
color: $splitterCollapsedBtnColorFg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&[class*="--horizontal"] {
|
&[class*="--horizontal"] {
|
||||||
@ -248,31 +232,44 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.l-pane__collapse-button {
|
||||||
|
&:before {
|
||||||
|
content: $glyph-icon-arrow-right-equilateral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&[class*="--collapsed"] {
|
&[class*="--collapsed"] {
|
||||||
> .l-pane__collapse-button {
|
/************************ COLLAPSED HORIZONTAL SPLITTER, EITHER DIRECTION */
|
||||||
|
[class*="__header"] {
|
||||||
|
@include abs();
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="label"] {
|
||||||
|
position: absolute;
|
||||||
|
transform: translate($interiorMarginLg + 1, 18px) rotate(90deg);
|
||||||
|
left: 3px;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-pane__collapse-button {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0; // Only have to do this once, because of scaleX(-1) below.
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0; right: 0; bottom: 0; left: 0;
|
top: 0; right: 0; bottom: 0; left: 0;
|
||||||
height: auto; width: 100%;
|
height: auto; width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
[class*="label"] {
|
&:before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: translate($interiorMarginLg + 1, 18px) rotate(90deg);
|
top: 5px;
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
background: none;
|
|
||||||
padding: 0;
|
|
||||||
top: $interiorMargin;
|
|
||||||
left: 50%;
|
|
||||||
right: auto;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: auto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** Horizontal Splitter Before */
|
/************************** Horizontal Splitter Before */
|
||||||
|
// Inspector pane
|
||||||
&[class*="-before"] {
|
&[class*="-before"] {
|
||||||
> .l-pane__handle {
|
> .l-pane__handle {
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -280,15 +277,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&[class*="--collapsed"] {
|
&[class*="--collapsed"] {
|
||||||
> .l-pane__collapse-button {
|
.l-pane__collapse-button {
|
||||||
&:after {
|
transform: scaleX(-1);
|
||||||
transform: translateX(-50%) scaleX(-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** Horizontal Splitter After */
|
/************************** Horizontal Splitter After */
|
||||||
|
// Tree pane
|
||||||
&[class*="-after"] {
|
&[class*="-after"] {
|
||||||
> .l-pane__handle {
|
> .l-pane__handle {
|
||||||
right: 0;
|
right: 0;
|
||||||
@ -296,7 +292,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:not([class*="--collapsed"]) {
|
&:not([class*="--collapsed"]) {
|
||||||
> .l-pane__collapse-button:after {
|
.l-pane__collapse-button {
|
||||||
transform: scaleX(-1);
|
transform: scaleX(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,19 +316,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/************************** Vertical Splitter Before */
|
/************************** Vertical Splitter Before */
|
||||||
// Pane collapses downward
|
// Pane collapses downward. Used by Elements pool in Inspector
|
||||||
&[class*="-before"] {
|
&[class*="-before"] {
|
||||||
> .l-pane__handle {
|
> .l-pane__handle {
|
||||||
top: 0;
|
top: 0;
|
||||||
transform: translateY(floor($splitterHandleD / -1));
|
transform: translateY(floor($splitterHandleD / -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
> .l-pane__collapse-button:after {
|
.l-pane__collapse-button:before {
|
||||||
content: $glyph-icon-arrow-down;
|
content: $glyph-icon-arrow-down;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.l-pane--collapsed {
|
&.l-pane--collapsed {
|
||||||
> .l-pane__collapse-button:after {
|
> .l-pane__collapse-button {
|
||||||
transform: scaleY(-1);
|
transform: scaleY(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,45 +15,15 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
/******************************* SEARCH */
|
|
||||||
.c-search {
|
.c-search {
|
||||||
@include nice-input();
|
@include wrappedInput();
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
padding-top: 2px;
|
||||||
padding: 2px 4px;
|
padding-bottom: 2px;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
// Mag glass icon
|
// Mag glass icon
|
||||||
content: $glyph-icon-magnify;
|
content: $glyph-icon-magnify;
|
||||||
direction: rtl; // Aligns glyph to right-hand side of container, for transition
|
|
||||||
display: block;
|
|
||||||
font-family: symbolsfont;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
opacity: 0.5;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 2px 0; // Prevents clipping
|
|
||||||
transition: width 250ms ease;
|
|
||||||
width: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
box-shadow: inset rgba(black, 0.8) 0 0px 2px;
|
|
||||||
&:before {
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--major {
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__input {
|
|
||||||
background: none !important;
|
|
||||||
box-shadow: none !important; // !important needed to override default for [input]
|
|
||||||
flex: 1 1 auto;
|
|
||||||
padding-left: 2px !important;
|
|
||||||
padding-right: 2px !important;
|
|
||||||
min-width: 10px; // Must be set to allow input to collapse below browser min
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__clear-input {
|
&__clear-input {
|
||||||
@ -61,11 +31,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
&:before {
|
|
||||||
padding: 2px 0px;
|
|
||||||
width: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-search__clear-input {
|
.c-search__clear-input {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
176
src/ui/components/controls/toggleButton.vue
Normal file
176
src/ui/components/controls/toggleButton.vue
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
<template>
|
||||||
|
<div class="c-togglebutton">
|
||||||
|
<input type="checkbox"
|
||||||
|
:id="id"
|
||||||
|
:name="name"
|
||||||
|
:value="value"
|
||||||
|
:required="required"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="onChange"
|
||||||
|
:checked="state">
|
||||||
|
<label :for="id">
|
||||||
|
<div class="c-togglebutton__on"
|
||||||
|
:class="innerClassOn"></div>
|
||||||
|
<div class="c-togglebutton__off"
|
||||||
|
:class="innerClassOff"></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
.c-togglebutton {
|
||||||
|
$d: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.c-togglebutton__on {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
&:checked + label {
|
||||||
|
.c-togglebutton__on {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.c-togglebutton__off {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:disabled) + label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled + label {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/*
|
||||||
|
Toggle button control, based on checkboxCustom. Use just like a checkbox in HTML.
|
||||||
|
Requires inner-class-on and -off attributes to be passed.
|
||||||
|
Supports checked and disabled attributes.
|
||||||
|
Example usage:
|
||||||
|
<toggle-button checked
|
||||||
|
class="c-click-icon"
|
||||||
|
inner-class-on="icon-grid-snap-to"
|
||||||
|
inner-class-off="icon-grid-snap-no"></toggle-button>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
model: {
|
||||||
|
prop: 'modelValue',
|
||||||
|
event: 'input'
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
innerClassOn: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
innerClassOff: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: function () {
|
||||||
|
return 'checkbox-id-' + this._uid;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
checked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
model: {}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
state() {
|
||||||
|
if (this.modelValue === undefined) {
|
||||||
|
return this.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(this.modelValue)) {
|
||||||
|
return this.modelValue.indexOf(this.value) > -1;
|
||||||
|
}
|
||||||
|
return !!this.modelValue;
|
||||||
|
},
|
||||||
|
stateClass() {
|
||||||
|
return this.onClass;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onChange() {
|
||||||
|
this.toggle();
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
let value;
|
||||||
|
|
||||||
|
if (Array.isArray(this.modelValue)) {
|
||||||
|
value = this.modelValue.slice(0);
|
||||||
|
|
||||||
|
if (this.state) {
|
||||||
|
value.splice(value.indexOf(this.value), 1);
|
||||||
|
} else {
|
||||||
|
value.push(this.value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = !this.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('input', value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
checked(newValue) {
|
||||||
|
if (newValue !== this.state) {
|
||||||
|
this.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
if (this.checked && !this.state) {
|
||||||
|
this.toggle();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
@ -18,8 +18,6 @@
|
|||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
.c-inspector {
|
.c-inspector {
|
||||||
min-width: 150px;
|
|
||||||
|
|
||||||
> [class*="__"] {
|
> [class*="__"] {
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
|
|
||||||
@ -52,7 +50,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************** LEGACY */
|
/************************************************************** LEGACY */
|
||||||
// TODO: refactor when markup can be converted
|
// TODO: refactor when legacy properties markup can be converted
|
||||||
.inspector-location {
|
.inspector-location {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
@ -93,10 +91,45 @@
|
|||||||
width: 4px;
|
width: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.l-inspector-part {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@include propertiesHeader();
|
||||||
|
font-size: 0.65rem;
|
||||||
|
grid-column: 1 / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree .grid-properties {
|
||||||
|
margin-left: $treeItemIndent + $interiorMarginLg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-properties {
|
.c-properties {
|
||||||
@include gridTwoColumn();
|
display: grid;
|
||||||
|
grid-row-gap: 0;
|
||||||
|
grid-template-columns: 1fr 2fr;
|
||||||
|
align-items: start;
|
||||||
|
min-width: 150px;
|
||||||
|
|
||||||
|
[class*="header"] {
|
||||||
|
@include propertiesHeader();
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
// Allow multiple headers within a component
|
||||||
|
margin-top: $interiorMarginLg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="span-all"],
|
||||||
|
[class*="header"] {
|
||||||
|
grid-column: 1 / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+ .c-properties {
|
+ .c-properties {
|
||||||
// Margin between components
|
// Margin between components
|
||||||
@ -139,7 +172,7 @@
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
&:first-child {
|
&:first-child {
|
||||||
// If there is no preceding .label element, make value span columns
|
// If there is no preceding .label element, make value span columns
|
||||||
@include gridTwoColumnSpanCols();
|
grid-column: 1 / 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-properties"></div>
|
<div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -10,22 +11,26 @@
|
|||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
mounted() {
|
mounted() {
|
||||||
this.openmct.selection.on('change', this.updateSelection);
|
this.openmct.selection.on('change', this.updateSelection);
|
||||||
this.updateSelection(this.openmct.selection.get());
|
this.updateSelection();
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.openmct.selection.off('change', this.updateSelection);
|
this.openmct.selection.off('change', this.updateSelection);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateSelection(selection) {
|
updateSelection() {
|
||||||
|
let selection = this.openmct.selection.get();
|
||||||
if (this.selectedView && this.selectedView.destroy) {
|
if (this.selectedView && this.selectedView.destroy) {
|
||||||
this.selectedView.destroy();
|
this.selectedView.destroy();
|
||||||
|
delete this.viewContainer;
|
||||||
|
this.$el.innerHTML = '';
|
||||||
}
|
}
|
||||||
this.$el.innerHTML = '';
|
|
||||||
this.selectedView = this.openmct.inspectorViews.get(selection);
|
this.selectedView = this.openmct.inspectorViews.get(selection);
|
||||||
if (!this.selectedView) {
|
if (!this.selectedView) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.selectedView.show(this.$el);
|
this.viewContainer = document.createElement('div');
|
||||||
|
this.$el.append(this.viewContainer)
|
||||||
|
this.selectedView.show(this.viewContainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Action buttons -->
|
<!-- Action buttons -->
|
||||||
<div class="l-browse-bar__actions">
|
<div class="l-browse-bar__actions">
|
||||||
<button class="l-browse-bar__actions__notebook-entry c-button icon-notebook" title="New Notebook entry"></button>
|
<button class="l-browse-bar__actions__edit c-button icon-notebook" title="New Notebook entry"></button>
|
||||||
<button class="l-browse-bar__actions__edit c-button c-button--major icon-pencil" title="Edit"></button>
|
<button class="l-browse-bar__actions__notebook-entry c-button c-button--major icon-pencil" title="Edit" v-if="!isEditing" @click="edit()"></button>
|
||||||
|
<button class="l-browse-bar__actions c-button c-button--major icon-save" title="Save and Finish Editing" v-if="isEditing" @click="saveAndFinishEditing()"></button>
|
||||||
|
<button class="l-browse-bar__actions c-button icon-x" title="Cancel Editing" v-if="isEditing" @click="cancelEditing()"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -65,13 +67,28 @@
|
|||||||
this.openmct.router.updateParams({
|
this.openmct.router.updateParams({
|
||||||
view: this.viewKey
|
view: this.viewKey
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
edit() {
|
||||||
|
this.openmct.editor.edit();
|
||||||
|
},
|
||||||
|
cancelEditing() {
|
||||||
|
this.openmct.editor.cancel();
|
||||||
|
},
|
||||||
|
saveAndFinishEditing() {
|
||||||
|
this.openmct.editor.save().then(()=> {
|
||||||
|
this.openmct.notifications.info('Save successful');
|
||||||
|
}).catch((error) => {
|
||||||
|
this.openmct.notifications.error('Error saving objects');
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
showViewMenu: false,
|
showViewMenu: false,
|
||||||
domainObject: {},
|
domainObject: {},
|
||||||
viewKey: undefined
|
viewKey: undefined,
|
||||||
|
isEditing: this.openmct.editor.isEditing()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -105,6 +122,10 @@
|
|||||||
this.showViewMenu = false;
|
this.showViewMenu = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.openmct.editor.on('isEditing', (isEditing) => {
|
||||||
|
this.isEditing = isEditing;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -126,7 +147,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
font-size: 1.4em;
|
|
||||||
margin-right: $interiorMargin;
|
margin-right: $interiorMargin;
|
||||||
min-width: 0; // Forces interior to compress when pushed on
|
min-width: 0; // Forces interior to compress when pushed on
|
||||||
}
|
}
|
||||||
@ -158,6 +178,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
|
font-size: 1.4em;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="l-shell">
|
<div class="l-shell" :class="{
|
||||||
|
'is-editing': isEditing
|
||||||
|
}">
|
||||||
<div class="l-shell__head">
|
<div class="l-shell__head">
|
||||||
<CreateButton class="l-shell__create-button"></CreateButton>
|
<CreateButton class="l-shell__create-button"></CreateButton>
|
||||||
<div class="l-shell__controls">
|
<div class="l-shell__controls">
|
||||||
@ -23,14 +25,13 @@
|
|||||||
<div class="l-shell__search">
|
<div class="l-shell__search">
|
||||||
<search class="c-search--major" ref="shell-search"></search>
|
<search class="c-search--major" ref="shell-search"></search>
|
||||||
</div>
|
</div>
|
||||||
<div class="l-shell__tree">
|
<mct-tree class="l-shell__tree"></mct-tree>
|
||||||
<mct-tree></mct-tree>
|
|
||||||
</div>
|
|
||||||
</pane>
|
</pane>
|
||||||
<pane class="l-shell__pane-main">
|
<pane class="l-shell__pane-main">
|
||||||
<browse-bar class="l-shell__main-view-browse-bar"
|
<browse-bar class="l-shell__main-view-browse-bar"
|
||||||
ref="browseBar">
|
ref="browseBar">
|
||||||
</browse-bar>
|
</browse-bar>
|
||||||
|
<toolbar class="l-shell__toolbar"></toolbar>
|
||||||
<object-view class="l-shell__main-container"
|
<object-view class="l-shell__main-container"
|
||||||
ref="browseObject">
|
ref="browseObject">
|
||||||
</object-view>
|
</object-view>
|
||||||
@ -46,7 +47,7 @@
|
|||||||
</pane>
|
</pane>
|
||||||
</multipane>
|
</multipane>
|
||||||
<div class="l-shell__status">
|
<div class="l-shell__status">
|
||||||
<MctStatus></MctStatus>
|
<StatusBar></StatusBar>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -60,47 +61,67 @@
|
|||||||
top: 0; right: 0; bottom: 0; left: 0;
|
top: 0; right: 0; bottom: 0; left: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
&__status {
|
&__status {
|
||||||
background: $colorBodyFg;
|
background: $colorStatusBarBg;
|
||||||
color: $colorBodyBg;
|
color: $colorStatusBarFg;
|
||||||
border-top: 1px solid $colorInteriorBorder;
|
|
||||||
height: 24px;
|
height: 24px;
|
||||||
padding: $interiorMarginSm;
|
padding: $interiorMarginSm;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__pane-tree {
|
&__pane-tree {
|
||||||
background: $colorTreeBg;
|
|
||||||
width: 40%;
|
width: 40%;
|
||||||
|
|
||||||
[class*="collapse-button"] {
|
[class*="collapse-button"] {
|
||||||
// For mobile, collapse button becomes menu icon
|
// For mobile, collapse button becomes menu icon
|
||||||
body.mobile & {
|
body.mobile & {
|
||||||
height: $mobileMenuIconD;
|
@include cClickIcon();
|
||||||
width: $mobileMenuIconD;
|
position: absolute;
|
||||||
|
right: -2 * nth($shellPanePad, 2); // Needs to be -1 * when pane is collapsed
|
||||||
|
top: 0;
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
|
width: $mobileMenuIconD;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
color: $colorKey;
|
|
||||||
content: $glyph-icon-menu-hamburger;
|
content: $glyph-icon-menu-hamburger;
|
||||||
font-family: symbolsfont;
|
|
||||||
font-size: 1.4em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__pane-main,
|
&__pane-tree,
|
||||||
&__pane-tree {
|
&__pane-inspector,
|
||||||
> .l-pane__contents {
|
&__pane-main {
|
||||||
|
.l-pane__contents {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
+ * {
|
||||||
|
margin-top: $interiorMarginLg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile & {
|
||||||
|
&__pane-tree {
|
||||||
|
background: linear-gradient(90deg, transparent 70%, rgba(black, 0.2) 99%, rgba(black, 0.3));
|
||||||
|
|
||||||
|
&[class*="--collapsed"] {
|
||||||
|
[class*="collapse-button"] {
|
||||||
|
right: -1 * nth($shellPanePad, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.phone.portrait & {
|
body.phone.portrait & {
|
||||||
&__pane-tree {
|
&__pane-tree {
|
||||||
width: calc(100% - #{$mobileMenuIconD});
|
width: calc(100% - #{$mobileMenuIconD + (2 * nth($shellPanePad, 2))});
|
||||||
|
|
||||||
+ .l-pane {
|
+ .l-pane {
|
||||||
// Hide pane-main when this pane is expanded
|
// Hide pane-main when this pane is expanded
|
||||||
@ -136,13 +157,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.mobile & .l-shell__main-view-browse-bar {
|
body.mobile & .l-shell__main-view-browse-bar {
|
||||||
margin-left: $mobileMenuIconD - $interiorMarginLg; // Make room for the hamburger!
|
margin-left: $mobileMenuIconD; // Make room for the hamburger!
|
||||||
}
|
}
|
||||||
|
|
||||||
&__head {
|
&__head {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
background: $colorHeadBg;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
border-bottom: 1px solid $colorInteriorBorder;
|
|
||||||
padding: $interiorMargin;
|
padding: $interiorMargin;
|
||||||
|
|
||||||
> [class*="__"] + [class*="__"] {
|
> [class*="__"] + [class*="__"] {
|
||||||
@ -162,28 +183,41 @@
|
|||||||
margin-right: 2.5%;
|
margin-right: 2.5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********** MAIN AREA */
|
/******************************* MAIN AREA */
|
||||||
|
|
||||||
&__main-container {
|
&__main-container {
|
||||||
// Wrapper for main views
|
// Wrapper for main views
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto !important;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
//font-size: 16px; // TEMP FOR LEGACY STYLING
|
//font-size: 16px; // TEMP FOR LEGACY STYLING
|
||||||
}
|
}
|
||||||
|
|
||||||
&__tree {
|
&__tree {
|
||||||
// Tree component within __pane-tree
|
// Tree component within __pane-tree
|
||||||
flex: 1 1 100%;
|
flex: 1 1 auto !important;
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__time-conductor {
|
&__time-conductor {
|
||||||
border-top: 1px solid $colorInteriorBorder;
|
border-top: 1px solid $colorInteriorBorder;
|
||||||
flex: 0 0 auto;
|
|
||||||
padding-top: $interiorMargin;
|
padding-top: $interiorMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__main {
|
||||||
|
> .l-pane {
|
||||||
|
padding: nth($shellPanePad, 1) nth($shellPanePad, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
body.desktop & {
|
body.desktop & {
|
||||||
/********** HEAD AND STATUS */
|
&__main {
|
||||||
|
// Top and bottom padding in container that holds tree, __pane-main and Inspector
|
||||||
|
padding: $shellMainPad;
|
||||||
|
> .l-pane {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__pane-tree,
|
&__pane-tree,
|
||||||
&__pane-inspector {
|
&__pane-inspector {
|
||||||
max-width: 30%;
|
max-width: 30%;
|
||||||
@ -202,7 +236,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Inspector from '../inspector/Inspector.vue';
|
import Inspector from '../inspector/Inspector.vue';
|
||||||
import MctStatus from './MctStatus.vue';
|
|
||||||
import MctTree from './mct-tree.vue';
|
import MctTree from './mct-tree.vue';
|
||||||
import ObjectView from './ObjectView.vue';
|
import ObjectView from './ObjectView.vue';
|
||||||
import MctTemplate from '../legacy/mct-template.vue';
|
import MctTemplate from '../legacy/mct-template.vue';
|
||||||
@ -212,6 +245,8 @@
|
|||||||
import multipane from '../controls/multipane.vue';
|
import multipane from '../controls/multipane.vue';
|
||||||
import pane from '../controls/pane.vue';
|
import pane from '../controls/pane.vue';
|
||||||
import BrowseBar from './BrowseBar.vue';
|
import BrowseBar from './BrowseBar.vue';
|
||||||
|
import StatusBar from './status-bar/StatusBar.vue';
|
||||||
|
import Toolbar from './Toolbar.vue';
|
||||||
|
|
||||||
var enterFullScreen = () => {
|
var enterFullScreen = () => {
|
||||||
var docElm = document.documentElement;
|
var docElm = document.documentElement;
|
||||||
@ -242,9 +277,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
components: {
|
components: {
|
||||||
Inspector,
|
Inspector,
|
||||||
MctStatus,
|
|
||||||
MctTree,
|
MctTree,
|
||||||
ObjectView,
|
ObjectView,
|
||||||
'mct-template': MctTemplate,
|
'mct-template': MctTemplate,
|
||||||
@ -253,12 +288,20 @@
|
|||||||
search,
|
search,
|
||||||
multipane,
|
multipane,
|
||||||
pane,
|
pane,
|
||||||
BrowseBar
|
BrowseBar,
|
||||||
|
StatusBar,
|
||||||
|
Toolbar
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.openmct.editor.on('isEditing', (isEditing)=>{
|
||||||
|
this.isEditing = isEditing;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
fullScreen: false,
|
fullScreen: false,
|
||||||
conductorComponent: {}
|
conductorComponent: {},
|
||||||
|
isEditing: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<template>
|
|
||||||
<span class="c-status">
|
|
||||||
[ Status ]
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -2,7 +2,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.l-object-view {
|
.c-object-view {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -33,6 +33,7 @@ export default {
|
|||||||
this.debounceUpdateView = _.debounce(this.updateView, 10);
|
this.debounceUpdateView = _.debounce(this.updateView, 10);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.currentObject = this.object;
|
||||||
this.updateView();
|
this.updateView();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -50,7 +51,7 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.viewContainer = document.createElement('div');
|
this.viewContainer = document.createElement('div');
|
||||||
this.viewContainer.classList.add('l-object-view');
|
this.viewContainer.classList.add('c-object-view');
|
||||||
this.$el.append(this.viewContainer);
|
this.$el.append(this.viewContainer);
|
||||||
let provider = this.openmct.objectViews.getByProviderKey(this.viewKey);
|
let provider = this.openmct.objectViews.getByProviderKey(this.viewKey);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
|
291
src/ui/components/layout/Toolbar.vue
Normal file
291
src/ui/components/layout/Toolbar.vue
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
<template>
|
||||||
|
<div class="c-toolbar">
|
||||||
|
<!-- VERSION MANUALLY RESTORED FROM VUE-LAYOUT -->
|
||||||
|
<div class="c-button-set">
|
||||||
|
<div class="c-ctrl-wrapper">
|
||||||
|
<div class="c-button--menu js-add-button icon-plus"
|
||||||
|
@click="toggleMenus">
|
||||||
|
<div class="c-button__label">Add</div>
|
||||||
|
</div>
|
||||||
|
<div class="c-menu" v-if="showMenus">
|
||||||
|
<ul>
|
||||||
|
<li v-for="item in addMenuItems"
|
||||||
|
:class="item.class"
|
||||||
|
:title="item.title">
|
||||||
|
{{ item.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-button-set"
|
||||||
|
v-if="toolsItemSelected">
|
||||||
|
<div class="c-ctrl-wrapper"
|
||||||
|
v-if="toolsItemSelected">
|
||||||
|
<div class="c-click-icon c-click-icon--menu js-layers icon-layers"
|
||||||
|
@click="toggleMenus"></div>
|
||||||
|
<div class="c-menu" v-if="showMenus">
|
||||||
|
<ul>
|
||||||
|
<li v-for="item in layersMenuItems"
|
||||||
|
:class="item.class"
|
||||||
|
:title="item.title">
|
||||||
|
{{ item.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-ctrl-wrapper"
|
||||||
|
v-if="toolsColorFill">
|
||||||
|
<div class="c-click-icon c-click-icon--swatched js-color-fill icon-paint-bucket"
|
||||||
|
@click="toggleMenus">
|
||||||
|
<div class="c-swatch" style="background: #33ff00;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="c-menu c-palette c-palette--color"
|
||||||
|
v-if="showMenus">
|
||||||
|
<div class="c-palette__item-none"
|
||||||
|
vif="this.palette.itemNone === true">
|
||||||
|
<div class="c-palette__item"
|
||||||
|
@click="this.setColor('no-color')"></div>
|
||||||
|
No fill
|
||||||
|
</div>
|
||||||
|
<div class="c-palette__items">
|
||||||
|
<div class="c-palette__item"
|
||||||
|
v-for="color in colorPalette"
|
||||||
|
:style="{ background: color.value }"
|
||||||
|
@click="this.setColor(color.value)"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-ctrl-wrapper"
|
||||||
|
v-if="toolsColorStroke">
|
||||||
|
<div class="c-click-icon c-click-icon--swatched js-color-stroke icon-pencil">
|
||||||
|
<div class="c-toolbar-button__swatch" style="background: #ffffff;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-ctrl-wrapper"
|
||||||
|
v-if="toolsColorText">
|
||||||
|
<div class="c-click-icon c-click-icon--swatched js-color-text icon-font">
|
||||||
|
<div class="c-toolbar-button__swatch" style="background: #333333;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-button-set"
|
||||||
|
v-if="toolsItemSelected && toolsFontSize">
|
||||||
|
<div class="c-ctrl-wrapper">
|
||||||
|
<div class="c-click-icon c-click-icon--menu js-font-size"
|
||||||
|
@click="toggleMenus">
|
||||||
|
<div class="c-button__label">11 px</div>
|
||||||
|
</div>
|
||||||
|
<div class="c-menu" v-if="showMenus">
|
||||||
|
<ul>
|
||||||
|
<li v-for="item in fontSizeMenuItems">
|
||||||
|
{{ item.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-button-set"
|
||||||
|
v-if="toolsItemSelected && toolsEditProperties">
|
||||||
|
<div class="c-ctrl-wrapper">
|
||||||
|
<div class="c-click-icon js-image icon-gear"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-button-set"
|
||||||
|
v-if="toolsItemSelected">
|
||||||
|
<labeledNumberInput label="X" value=1 title="X position"></labeledNumberInput>
|
||||||
|
<labeledNumberInput label="Y" value=2 title="Y position"></labeledNumberInput>
|
||||||
|
<labeledNumberInput label="W" value=3 title="Width"></labeledNumberInput>
|
||||||
|
<labeledNumberInput label="H" value=4 title="Height"></labeledNumberInput>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-button-set"
|
||||||
|
v-if="toolsItemSelected">
|
||||||
|
<div class="c-click-icon c-click-icon--caution icon-trash"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-button-set"
|
||||||
|
v-if="toolsItemSelected">
|
||||||
|
<checkbox checked title="This is a checkbox">Checkbox</checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-button-set"
|
||||||
|
v-if="toolsItemSelected">
|
||||||
|
<toggle-button title="Toggle frame" checked
|
||||||
|
class="c-click-icon"
|
||||||
|
inner-class-on="icon-frame-show"
|
||||||
|
inner-class-off="icon-frame-hide"></toggle-button>
|
||||||
|
<toggle-button title="Snap to grid" checked
|
||||||
|
class="c-click-icon"
|
||||||
|
inner-class-on="icon-grid-snap-to"
|
||||||
|
inner-class-off="icon-grid-snap-no"></toggle-button>
|
||||||
|
<toggle-button title="Show label and value" checked
|
||||||
|
class="c-click-icon"
|
||||||
|
inner-class-on="icon-two-parts-both"
|
||||||
|
inner-class-off="icon-two-parts-one-only"></toggle-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import labeledNumberInput from '../controls/labeledNumberInput.vue';
|
||||||
|
import checkbox from '../controls/checkboxCustom.vue';
|
||||||
|
import toggleButton from '../controls/toggleButton.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
labeledNumberInput,
|
||||||
|
checkbox,
|
||||||
|
toggleButton
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleMenus: function () {
|
||||||
|
this.showMenus = !this.showMenus;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
toolsItemSelected: { type: Boolean, default: true },
|
||||||
|
toolsColorFill: { type: Boolean, default: true },
|
||||||
|
toolsColorStroke: { type: Boolean, default: true },
|
||||||
|
toolsColorText: { type: Boolean, default: true },
|
||||||
|
toolsFontSize: { type: Boolean, default: true },
|
||||||
|
toolsEditProperties: { type: Boolean, default: true },
|
||||||
|
toolSetBox: ['toolsColorFill', 'toolsColorStroke'],
|
||||||
|
toolSetLine: ['toolsColorStroke'],
|
||||||
|
toolSetText: ['toolsColorFill', 'toolsColorStroke', 'toolsColorText', 'toolsFontSize', 'toolsEditProperties'],
|
||||||
|
toolSetImage: ['toolsColorStroke', 'toolsEditProperties'],
|
||||||
|
toolSetTelemetry: ['toolsColorFill', 'toolsColorStroke', 'toolsColorText', 'toolsFontSize', 'toolsLabelValue']
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
showMenus: false,
|
||||||
|
addMenuItems: [
|
||||||
|
{ name: 'Box', class: 'icon-box', title: 'Add Box' },
|
||||||
|
{ name: 'Line', class: 'icon-line-horz', title: 'Add Line' },
|
||||||
|
{ name: 'Text', class: 'icon-font', title: 'Add Text' },
|
||||||
|
{ name: 'Image', class: 'icon-image', title: 'Add Image' }
|
||||||
|
],
|
||||||
|
layersMenuItems: [
|
||||||
|
{ name: 'Move to top', class: 'icon-arrow-double-up', title: 'Move to top' },
|
||||||
|
{ name: 'Move up', class: 'icon-arrow-up', title: 'Move up' },
|
||||||
|
{ name: 'Move down', class: 'icon-arrow-down', title: 'Move down' },
|
||||||
|
{ name: 'Move to bottom', class: 'icon-arrow-double-down', title: 'Move to bottom' }
|
||||||
|
],
|
||||||
|
fontSizeMenuItems: [
|
||||||
|
{ value: '9', name: '9 px' },
|
||||||
|
{ value: '10', name: '10 px' },
|
||||||
|
{ value: '11', name: '11 px' },
|
||||||
|
{ value: '12', name: '12 px' },
|
||||||
|
{ value: '13', name: '13 px' },
|
||||||
|
{ value: '14', name: '14 px' },
|
||||||
|
{ value: '16', name: '16 px' },
|
||||||
|
{ value: '18', name: '18 px' },
|
||||||
|
{ value: '20', name: '20 px' },
|
||||||
|
{ value: '24', name: '24 px' },
|
||||||
|
{ value: '28', name: '28 px' },
|
||||||
|
{ value: '32', name: '32 px' },
|
||||||
|
{ value: '40', name: '40 px' },
|
||||||
|
{ value: '48', name: '48 px' },
|
||||||
|
{ value: '56', name: '56 px' },
|
||||||
|
{ value: '64', name: '64 px' },
|
||||||
|
{ value: '72', name: '72 px' },
|
||||||
|
{ value: '80', name: '80 px' },
|
||||||
|
{ value: '88', name: '88 px' },
|
||||||
|
{ value: '96', name: '96 px' },
|
||||||
|
{ value: '128', name: '128 px' },
|
||||||
|
{ value: '160', name: '160 px' }
|
||||||
|
],
|
||||||
|
colorPalette: [
|
||||||
|
{ value: '#000000' },
|
||||||
|
{ value: '#434343' },
|
||||||
|
{ value: '#666666' },
|
||||||
|
{ value: '#999999' },
|
||||||
|
{ value: '#b7b7b7' },
|
||||||
|
{ value: '#cccccc' },
|
||||||
|
{ value: '#d9d9d9' },
|
||||||
|
{ value: '#efefef' },
|
||||||
|
{ value: '#f3f3f3' },
|
||||||
|
{ value: '#ffffff' },
|
||||||
|
{ value: '#980000' },
|
||||||
|
{ value: '#ff0000' },
|
||||||
|
{ value: '#ff9900' },
|
||||||
|
{ value: '#ffff00' },
|
||||||
|
{ value: '#00ff00' },
|
||||||
|
{ value: '#00ffff' },
|
||||||
|
{ value: '#4a86e8' },
|
||||||
|
{ value: '#0000ff' },
|
||||||
|
{ value: '#9900ff' },
|
||||||
|
{ value: '#ff00ff' },
|
||||||
|
{ value: '#e6b8af' },
|
||||||
|
{ value: '#f4cccc' },
|
||||||
|
{ value: '#fce5cd' },
|
||||||
|
{ value: '#fff2cc' },
|
||||||
|
{ value: '#d9ead3' },
|
||||||
|
{ value: '#d0e0e3' },
|
||||||
|
{ value: '#c9daf8' },
|
||||||
|
{ value: '#cfe2f3' },
|
||||||
|
{ value: '#d9d2e9' },
|
||||||
|
{ value: '#ead1dc' },
|
||||||
|
{ value: '#dd7e6b' },
|
||||||
|
{ value: '#dd7e6b' },
|
||||||
|
{ value: '#f9cb9c' },
|
||||||
|
{ value: '#ffe599' },
|
||||||
|
{ value: '#b6d7a8' },
|
||||||
|
{ value: '#a2c4c9' },
|
||||||
|
{ value: '#a4c2f4' },
|
||||||
|
{ value: '#9fc5e8' },
|
||||||
|
{ value: '#b4a7d6' },
|
||||||
|
{ value: '#d5a6bd' },
|
||||||
|
{ value: '#cc4125' },
|
||||||
|
{ value: '#e06666' },
|
||||||
|
{ value: '#f6b26b' },
|
||||||
|
{ value: '#ffd966' },
|
||||||
|
{ value: '#93c47d' },
|
||||||
|
{ value: '#76a5af' },
|
||||||
|
{ value: '#6d9eeb' },
|
||||||
|
{ value: '#6fa8dc' },
|
||||||
|
{ value: '#8e7cc3' },
|
||||||
|
{ value: '#c27ba0' },
|
||||||
|
{ value: '#a61c00' },
|
||||||
|
{ value: '#cc0000' },
|
||||||
|
{ value: '#e69138' },
|
||||||
|
{ value: '#f1c232' },
|
||||||
|
{ value: '#6aa84f' },
|
||||||
|
{ value: '#45818e' },
|
||||||
|
{ value: '#3c78d8' },
|
||||||
|
{ value: '#3d85c6' },
|
||||||
|
{ value: '#674ea7' },
|
||||||
|
{ value: '#a64d79' },
|
||||||
|
{ value: '#85200c' },
|
||||||
|
{ value: '#990000' },
|
||||||
|
{ value: '#b45f06' },
|
||||||
|
{ value: '#bf9000' },
|
||||||
|
{ value: '#38761d' },
|
||||||
|
{ value: '#134f5c' },
|
||||||
|
{ value: '#1155cc' },
|
||||||
|
{ value: '#0b5394' },
|
||||||
|
{ value: '#351c75' },
|
||||||
|
{ value: '#741b47' },
|
||||||
|
{ value: '#5b0f00' },
|
||||||
|
{ value: '#660000' },
|
||||||
|
{ value: '#783f04' },
|
||||||
|
{ value: '#7f6000' },
|
||||||
|
{ value: '#274e13' },
|
||||||
|
{ value: '#0c343d' },
|
||||||
|
{ value: '#1c4587' },
|
||||||
|
{ value: '#073763' },
|
||||||
|
{ value: '#20124d' },
|
||||||
|
{ value: '#4c1130' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,10 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul class="c-tree">
|
<div class="c-tree__wrapper">
|
||||||
<tree-item v-for="child in children"
|
<ul class="c-tree">
|
||||||
:key="child.id"
|
<tree-item v-for="child in children"
|
||||||
:node="child">
|
:key="child.id"
|
||||||
</tree-item>
|
:node="child">
|
||||||
</ul>
|
</tree-item>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -16,6 +18,11 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
&__wrapper {
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
|
||||||
.c-tree {
|
.c-tree {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
|
41
src/ui/components/layout/status-bar/Indicators.vue
Normal file
41
src/ui/components/layout/status-bar/Indicators.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
Administration. All rights reserved.
|
||||||
|
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
Open MCT includes source code licensed under additional open source
|
||||||
|
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
this source code distribution or the Licensing information page available
|
||||||
|
at runtime from the About dialog for additional information.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<span id='status' class='status-holder'></span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.openmct.indicators.indicatorObjects.forEach((indicator) => {
|
||||||
|
// So that we can consistently position indicator elements,
|
||||||
|
// guarantee that they are wrapped in an element we control
|
||||||
|
var wrapperNode = document.createElement('span');
|
||||||
|
wrapperNode.className = 'l-indicator';
|
||||||
|
wrapperNode.appendChild(indicator.element);
|
||||||
|
this.$el.appendChild(wrapperNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
98
src/ui/components/layout/status-bar/NotificationBanner.vue
Normal file
98
src/ui/components/layout/status-bar/NotificationBanner.vue
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
Administration. All rights reserved.
|
||||||
|
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
Open MCT includes source code licensed under additional open source
|
||||||
|
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
this source code distribution or the Licensing information page available
|
||||||
|
at runtime from the About dialog for additional information.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="l-message-banner s-message-banner"
|
||||||
|
:class="[
|
||||||
|
activeModel.severity,
|
||||||
|
{
|
||||||
|
'minimized': activeModel.minimized,
|
||||||
|
'new': !activeModel.minimized
|
||||||
|
}]"
|
||||||
|
v-if="activeModel">
|
||||||
|
<span @click="maximize()" class="banner-elem label">{{activeModel.title}}</span>
|
||||||
|
<span @click="maximize()" v-if="activeModel.progress !== undefined || activeModel.unknownProgress">
|
||||||
|
<div class="banner-elem"><!-- was mct-include -->
|
||||||
|
<span class="l-progress-bar s-progress-bar"
|
||||||
|
:class="{'indeterminate': activeModel.unknownProgress }">
|
||||||
|
<span class="progress-amt-holder">
|
||||||
|
<span class="progress-amt" :style="progressWidth"></span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<div class="progress-info hint" v-if="activeModel.progressText !== undefined">
|
||||||
|
<span class="progress-amt-text" v-if="activeModel.progress > 0">{{activeModel.progress}}% complete. </span>
|
||||||
|
{{activeModel.progressText}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
<a class="close icon-x" @click="dismiss()"></a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.l-message-banner {
|
||||||
|
display: inline;
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.banner-elem {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let activeNotification = undefined;
|
||||||
|
let dialogService = undefined;
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeModel: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showNotification(notification) {
|
||||||
|
activeNotification = notification;
|
||||||
|
this.activeModel = notification.model;
|
||||||
|
activeNotification.once('destroy', () => {
|
||||||
|
if (this.activeModel === notification.model){
|
||||||
|
this.activeModel = undefined;
|
||||||
|
activeNotification = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dismiss() {
|
||||||
|
activeNotification.dismissOrMinimize();
|
||||||
|
},
|
||||||
|
maximize() {
|
||||||
|
//Not implemented yet.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
progressWidth() {
|
||||||
|
return {
|
||||||
|
width: this.activeModel.progress + '%'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
openmct.notifications.on('notification', this.showNotification);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
42
src/ui/components/layout/status-bar/StatusBar.vue
Normal file
42
src/ui/components/layout/status-bar/StatusBar.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
Administration. All rights reserved.
|
||||||
|
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
Open MCT includes source code licensed under additional open source
|
||||||
|
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
this source code distribution or the Licensing information page available
|
||||||
|
at runtime from the About dialog for additional information.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<span class="c-status">
|
||||||
|
<indicators></indicators>
|
||||||
|
<notification-banner></notification-banner>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.c-status {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Indicators from './Indicators.vue';
|
||||||
|
import NotificationBanner from './NotificationBanner.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Indicators,
|
||||||
|
NotificationBanner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -8,6 +8,8 @@
|
|||||||
@click="toggleChildren">
|
@click="toggleChildren">
|
||||||
</view-control>
|
</view-control>
|
||||||
<a class="c-tree__item__label"
|
<a class="c-tree__item__label"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="dragStart"
|
||||||
:href="href">
|
:href="href">
|
||||||
<div class="c-tree__item__type-icon"
|
<div class="c-tree__item__type-icon"
|
||||||
:class="cssClass"></div>
|
:class="cssClass"></div>
|
||||||
@ -28,7 +30,7 @@
|
|||||||
import viewControl from '../controls/viewControl.vue'
|
import viewControl from '../controls/viewControl.vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'tree-item',
|
name: 'tree-item',
|
||||||
inject: ['openmct'],
|
inject: ['openmct', 'domainObject'],
|
||||||
props: {
|
props: {
|
||||||
node: Object
|
node: Object
|
||||||
},
|
},
|
||||||
@ -89,6 +91,9 @@
|
|||||||
.then(() => this.loaded = true);
|
.then(() => this.loaded = true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
dragStart($event) {
|
||||||
|
$event.dataTransfer.setData("domainObject", JSON.stringify(this.node.object));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
viewControl
|
viewControl
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import ContextMenuDirective from './ContextMenuDirective.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
10
src/ui/context-menu/ContextMenuDirective.js
Normal file
10
src/ui/context-menu/ContextMenuDirective.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import ContextMenuGesture from './ContextMenuGesture.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
bind(element, binding) {
|
||||||
|
binding.vnode.context.destroy = new ContextMenuGesture(element, binding.value);
|
||||||
|
},
|
||||||
|
unbind(){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
31
src/ui/context-menu/ContextMenuGesture.js
Normal file
31
src/ui/context-menu/ContextMenuGesture.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import ContextMenu from '../components/ContextMenu.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function ContextMenuGesture (element, object) {
|
||||||
|
let vm;
|
||||||
|
element.addEventListener('context', showContextMenu);
|
||||||
|
|
||||||
|
function showContextMenu(event){
|
||||||
|
vm = new Vue({
|
||||||
|
...ContextMenu
|
||||||
|
});
|
||||||
|
document.body.appendChild(vm.$el);
|
||||||
|
document.addEventListener('click', hideContextMenu, {
|
||||||
|
capture: true,
|
||||||
|
once: true
|
||||||
|
});
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideContextMenu() {
|
||||||
|
vm.destroy();
|
||||||
|
document.body.removeChild(vm.$el);
|
||||||
|
}
|
||||||
|
|
||||||
|
return function destroy() {
|
||||||
|
element.removeEventListener('context', this.showContextMenu);
|
||||||
|
document.removeEventListener('click', hideContextMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
src/ui/overlayService/overlay.vue
Normal file
91
src/ui/overlayService/overlay.vue
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<div class="c-overlay">
|
||||||
|
<div class="c-overlay__blocker"
|
||||||
|
v-on:click="destroy">
|
||||||
|
</div>
|
||||||
|
<div class="c-overlay__outer">
|
||||||
|
<button class="c-click-icon c-overlay__close-button icon-x-in-circle"
|
||||||
|
v-on:click="destroy">
|
||||||
|
</button>
|
||||||
|
<div class="c-overlay__contents" ref="element"></div>
|
||||||
|
<div class="c-overlay__button-bar">
|
||||||
|
<button class="c-button c-button--major"
|
||||||
|
v-on:click="destroy">Done</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
.l-overlay-wrapper {
|
||||||
|
// Created by overlayService.js, contains this template.
|
||||||
|
// Acts as an anchor for one or more overlays.
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-overlay {
|
||||||
|
@include abs();
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
&__blocker {
|
||||||
|
display: none; // Mobile-first
|
||||||
|
}
|
||||||
|
|
||||||
|
&__outer {
|
||||||
|
@include abs();
|
||||||
|
background: $overlayColorBg;
|
||||||
|
color: $overlayColorFg;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: $overlayInnerMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__close-button {
|
||||||
|
$p: $interiorMarginSm;
|
||||||
|
border-radius: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
top: $p; right: $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contents {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button-bar {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.desktop & {
|
||||||
|
&__blocker {
|
||||||
|
@include abs();
|
||||||
|
background: rgba(black, 0.7);
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__outer {
|
||||||
|
$m: $overlayOuterMargin;
|
||||||
|
top: $m; right: $m; bottom: $m; left: $m;
|
||||||
|
border-radius: $overlayCr;
|
||||||
|
box-shadow: rgba(black, 0.5) 0 2px 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
inject: ['destroy', 'element'],
|
||||||
|
mounted() {
|
||||||
|
this.$refs.element.appendChild(this.element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
87
src/ui/overlayService/overlayService.js
Normal file
87
src/ui/overlayService/overlayService.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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([
|
||||||
|
'./overlay.vue',
|
||||||
|
'vue'
|
||||||
|
], function (
|
||||||
|
OverlayComponent,
|
||||||
|
Vue
|
||||||
|
) {
|
||||||
|
|
||||||
|
function OverlayService() {
|
||||||
|
this.activeOverlays = [];
|
||||||
|
this.overlayId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayService.prototype.show = function (element, options) {
|
||||||
|
if(this.activeOverlays.length) {
|
||||||
|
this.activeOverlays[this.activeOverlays.length - 1].overlay.classList.add('invisible');
|
||||||
|
}
|
||||||
|
|
||||||
|
let overlayTypeCssClass = options.cssClass, // Values could be l-large-view, l-dialog, l-message
|
||||||
|
overlay = document.createElement('div'),
|
||||||
|
component = new Vue({
|
||||||
|
provide: {
|
||||||
|
destroy: this.destroy.bind(this),
|
||||||
|
element: element
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
OverlayComponent: OverlayComponent.default
|
||||||
|
},
|
||||||
|
template: '<overlay-component></overlay-component>'
|
||||||
|
});
|
||||||
|
|
||||||
|
overlay.classList.add('l-overlay-wrapper', overlayTypeCssClass);
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
|
||||||
|
overlay.appendChild(component.$mount().$el);
|
||||||
|
|
||||||
|
this.activeOverlays.push({
|
||||||
|
overlay: overlay,
|
||||||
|
component: component,
|
||||||
|
onDestroy: options.onDestroy,
|
||||||
|
id: this.overlayId
|
||||||
|
});
|
||||||
|
|
||||||
|
this.overlayId++;
|
||||||
|
};
|
||||||
|
|
||||||
|
OverlayService.prototype.destroy = function () {
|
||||||
|
var lastActiveOverlayObject = this.activeOverlays.pop(),
|
||||||
|
lastActiveOverlay = lastActiveOverlayObject.overlay,
|
||||||
|
lastActiveComponent = lastActiveOverlayObject.component;
|
||||||
|
|
||||||
|
if (lastActiveOverlayObject.onDestroy && typeof lastActiveOverlayObject.onDestroy === 'function') {
|
||||||
|
lastActiveOverlayObject.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastActiveComponent.$destroy(true);
|
||||||
|
document.body.removeChild(lastActiveOverlay);
|
||||||
|
|
||||||
|
if (this.activeOverlays.length) {
|
||||||
|
this.activeOverlays[this.activeOverlays.length - 1].overlay.classList.remove('invisible');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return OverlayService;
|
||||||
|
});
|
@ -7,12 +7,24 @@ define([
|
|||||||
return function install(openmct) {
|
return function install(openmct) {
|
||||||
let navigateCall = 0;
|
let navigateCall = 0;
|
||||||
let browseObject;
|
let browseObject;
|
||||||
|
let removeSelectable = undefined;
|
||||||
|
|
||||||
|
|
||||||
function viewObject(object, viewProvider) {
|
function viewObject(object, viewProvider) {
|
||||||
|
if (removeSelectable) {
|
||||||
|
removeSelectable();
|
||||||
|
removeSelectable = undefined;
|
||||||
|
}
|
||||||
openmct.layout.$refs.browseObject.show(object, viewProvider.key);
|
openmct.layout.$refs.browseObject.show(object, viewProvider.key);
|
||||||
openmct.layout.$refs.browseBar.domainObject = object;
|
openmct.layout.$refs.browseBar.domainObject = object;
|
||||||
openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
|
openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
|
||||||
|
removeSelectable = openmct.selection.selectable(
|
||||||
|
openmct.layout.$refs.browseObject.$el,
|
||||||
|
{
|
||||||
|
item: object
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function navigateToPath(path, currentViewKey) {
|
function navigateToPath(path, currentViewKey) {
|
||||||
@ -22,40 +34,42 @@ define([
|
|||||||
if (!Array.isArray(path)) {
|
if (!Array.isArray(path)) {
|
||||||
path = path.split('/');
|
path = path.split('/');
|
||||||
}
|
}
|
||||||
let keyString = path[path.length - 1];
|
return Promise.all(path.map((keyString)=>{
|
||||||
// TODO: retain complete path in navigation.
|
return openmct.objects.get(keyString);
|
||||||
return openmct.objects.get(keyString)
|
})).then((objects)=>{
|
||||||
.then((object) => {
|
if (currentNavigation !== navigateCall) {
|
||||||
if (currentNavigation !== navigateCall) {
|
return; // Prevent race.
|
||||||
return; // Prevent race.
|
}
|
||||||
}
|
|
||||||
openmct.layout.$refs.browseBar.domainObject = object;
|
|
||||||
browseObject = object;
|
|
||||||
if (!object) {
|
|
||||||
openmct.layout.$refs.browseObject.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let currentProvider = openmct
|
|
||||||
.objectViews
|
|
||||||
.getByProviderKey(currentViewKey)
|
|
||||||
|
|
||||||
if (currentProvider && currentProvider.canView(object)) {
|
let navigatedObject = objects[objects.length - 1];
|
||||||
viewObject(object, currentProvider);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultProvider = openmct.objectViews.get(object)[0];
|
openmct.layout.$refs.browseBar.domainObject = navigatedObject;
|
||||||
if (defaultProvider) {
|
browseObject = navigatedObject;
|
||||||
openmct.router.updateParams({
|
if (!navigatedObject) {
|
||||||
view: defaultProvider.key
|
openmct.layout.$refs.browseObject.clear();
|
||||||
});
|
return;
|
||||||
} else {
|
}
|
||||||
openmct.router.updateParams({
|
let currentProvider = openmct
|
||||||
view: undefined
|
.objectViews
|
||||||
});
|
.getByProviderKey(currentViewKey)
|
||||||
openmct.layout.$refs.browseObject.clear();
|
|
||||||
}
|
if (currentProvider && currentProvider.canView(navigatedObject)) {
|
||||||
});
|
viewObject(navigatedObject, currentProvider);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultProvider = openmct.objectViews.get(navigatedObject)[0];
|
||||||
|
if (defaultProvider) {
|
||||||
|
openmct.router.updateParams({
|
||||||
|
view: defaultProvider.key
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
openmct.router.updateParams({
|
||||||
|
view: undefined
|
||||||
|
});
|
||||||
|
openmct.layout.$refs.browseObject.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
openmct.router.route(/^\/browse\/(.*)$/, (path, results, params) => {
|
openmct.router.route(/^\/browse\/(.*)$/, (path, results, params) => {
|
||||||
|
Reference in New Issue
Block a user