mirror of
https://github.com/nasa/openmct.git
synced 2025-07-02 21:20:52 +00:00
Compare commits
10 Commits
dialog-ser
...
context-me
Author | SHA1 | Date | |
---|---|---|---|
485e948abe | |||
64b9d4c24a | |||
88bcb6078e | |||
5f9f3cd8e8 | |||
814b404614 | |||
ba2bb2180b | |||
72cdb352f0 | |||
cedf942c0c | |||
27506a3757 | |||
acc4e03c88 |
@ -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++
|
||||||
});
|
});
|
||||||
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -223,6 +223,8 @@ 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.editor = new api.EditorAPI.default(this);
|
||||||
|
@ -29,6 +29,7 @@ define([
|
|||||||
'./ui/GestureAPI',
|
'./ui/GestureAPI',
|
||||||
'./telemetry/TelemetryAPI',
|
'./telemetry/TelemetryAPI',
|
||||||
'./indicators/IndicatorAPI',
|
'./indicators/IndicatorAPI',
|
||||||
|
'./notifications/NotificationAPI',
|
||||||
'./Editor'
|
'./Editor'
|
||||||
|
|
||||||
], function (
|
], function (
|
||||||
@ -40,6 +41,7 @@ define([
|
|||||||
GestureAPI,
|
GestureAPI,
|
||||||
TelemetryAPI,
|
TelemetryAPI,
|
||||||
IndicatorAPI,
|
IndicatorAPI,
|
||||||
|
NotificationAPI,
|
||||||
EditorAPI
|
EditorAPI
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
@ -51,6 +53,7 @@ define([
|
|||||||
GestureAPI: GestureAPI,
|
GestureAPI: GestureAPI,
|
||||||
TelemetryAPI: TelemetryAPI,
|
TelemetryAPI: TelemetryAPI,
|
||||||
IndicatorAPI: IndicatorAPI,
|
IndicatorAPI: IndicatorAPI,
|
||||||
|
NotificationAPI: NotificationAPI.default,
|
||||||
EditorAPI: EditorAPI
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -79,7 +79,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.c-grid {
|
.c-grid {
|
||||||
z-index: -1;
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
&__x { @include bgTicks($colorGridLines, 'x'); }
|
&__x { @include bgTicks($colorGridLines, 'x'); }
|
||||||
@ -92,13 +91,18 @@
|
|||||||
background: rgba($editColor, 0.1);
|
background: rgba($editColor, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-frame,
|
.s-selected,
|
||||||
|
.s-selected-parent {
|
||||||
.l-layout {
|
.l-layout {
|
||||||
&.s-selected,
|
// Show the layout grid for the top-most child of the current selection,
|
||||||
&.s-selected-parent {
|
// and hide the grid for deeper nested levels.
|
||||||
[class*="__grid-holder"] {
|
[class*="__grid-holder"] {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.l-layout [class*="__grid-holder"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,20 +314,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.removeSelectable = this.openmct.selection.selectable(
|
|
||||||
this.$el,
|
|
||||||
{
|
|
||||||
item: this.newDomainObject
|
|
||||||
},
|
|
||||||
this.initSelect
|
|
||||||
);
|
|
||||||
this.openmct.selection.on('change', this.setSelection);
|
this.openmct.selection.on('change', this.setSelection);
|
||||||
},
|
},
|
||||||
destroyed: function () {
|
destroyed: function () {
|
||||||
this.composition.off('add', this.onAddComposition);
|
this.composition.off('add', this.onAddComposition);
|
||||||
this.composition.off('remove', this.onRemoveComposition);
|
this.composition.off('remove', this.onRemoveComposition);
|
||||||
this.openmct.off('change', this.selection);
|
this.openmct.off('change', this.selection);
|
||||||
this.removeSelectable();
|
|
||||||
this.unlisten();
|
this.unlisten();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div class="c-ne__embed">
|
<div class="c-ne__embed">
|
||||||
<div class="c-ne__embed__snap-thumb"
|
<div class="c-ne__embed__snap-thumb"
|
||||||
v-if="embed.snapshot"
|
v-if="embed.snapshot"
|
||||||
v-on:click="openSnapshot(domainObject, entry, embed)">
|
v-on:click="openSnapshot">
|
||||||
<img v-bind:src="embed.snapshot.src">
|
<img v-bind:src="embed.snapshot.src">
|
||||||
</div>
|
</div>
|
||||||
<div class="c-ne__embed__info">
|
<div class="c-ne__embed__info">
|
||||||
|
@ -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)"
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<div class="flex-elem holder flex-can-shrink s-snapshot-datetime">
|
<div class="flex-elem holder flex-can-shrink s-snapshot-datetime">
|
||||||
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
||||||
</div>
|
</div>
|
||||||
<a class="s-button icon-pencil" title="Annotate" v-on:click="annotateSnapshot">
|
<a class="s-button icon-pencil" title="Annotate">
|
||||||
<span class="title-label">Annotate</span>
|
<span class="title-label">Annotate</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,16 +23,16 @@
|
|||||||
define([
|
define([
|
||||||
'moment',
|
'moment',
|
||||||
'zepto',
|
'zepto',
|
||||||
|
'../utils/SnapshotOverlay',
|
||||||
'../../res/templates/snapshotTemplate.html',
|
'../../res/templates/snapshotTemplate.html',
|
||||||
'vue',
|
'vue'
|
||||||
'painterro'
|
|
||||||
],
|
],
|
||||||
function (
|
function (
|
||||||
Moment,
|
Moment,
|
||||||
$,
|
$,
|
||||||
|
SnapshotOverlay,
|
||||||
SnapshotTemplate,
|
SnapshotTemplate,
|
||||||
Vue,
|
Vue
|
||||||
Painterro
|
|
||||||
) {
|
) {
|
||||||
function EmbedController (openmct, domainObject) {
|
function EmbedController (openmct, domainObject) {
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
@ -56,98 +56,7 @@ function (
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
EmbedController.prototype.openSnapshot = function (domainObject, entry, embed) {
|
EmbedController.prototype.openSnapshot = function () {
|
||||||
|
|
||||||
function annotateSnapshot(openmct) {
|
|
||||||
return function () {
|
|
||||||
|
|
||||||
var save = false,
|
|
||||||
painterroInstance = {},
|
|
||||||
annotateOverlay = new Vue({
|
|
||||||
template: '<div id="snap-annotation"></div>'
|
|
||||||
}),
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
cssClass: 'l-large-view',
|
|
||||||
onDestroy: function () {
|
|
||||||
annotateOverlay.$destroy(true);
|
|
||||||
},
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
label: 'Cancel',
|
|
||||||
callback: function () {
|
|
||||||
save = false;
|
|
||||||
painterroInstance.save();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Save',
|
|
||||||
callback: function () {
|
|
||||||
save = true;
|
|
||||||
painterroInstance.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
openmct.OverlayService.show(annotateOverlay.$mount().$el, options);
|
|
||||||
|
|
||||||
painterroInstance = Painterro({
|
|
||||||
id: 'snap-annotation',
|
|
||||||
activeColor: '#ff0000',
|
|
||||||
activeColorAlpha: 1.0,
|
|
||||||
activeFillColor: '#fff',
|
|
||||||
activeFillColorAlpha: 0.0,
|
|
||||||
backgroundFillColor: '#000',
|
|
||||||
backgroundFillColorAlpha: 0.0,
|
|
||||||
defaultFontSize: 16,
|
|
||||||
defaultLineWidth: 2,
|
|
||||||
defaultTool: 'ellipse',
|
|
||||||
hiddenTools: ['save', 'open', 'close', 'eraser', 'pixelize', 'rotate', 'settings', 'resize'],
|
|
||||||
translation: {
|
|
||||||
name: 'en',
|
|
||||||
strings: {
|
|
||||||
lineColor: 'Line',
|
|
||||||
fillColor: 'Fill',
|
|
||||||
lineWidth: 'Size',
|
|
||||||
textColor: 'Color',
|
|
||||||
fontSize: 'Size',
|
|
||||||
fontStyle: 'Style'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
saveHandler: function (image, done) {
|
|
||||||
if (save) {
|
|
||||||
var entryPos = self.findInArray(domainObject.entries, entry.id),
|
|
||||||
embedPos = self.findInArray(entry.embeds, embed.id);
|
|
||||||
|
|
||||||
if (entryPos !== -1 && embedPos !== -1) {
|
|
||||||
var url = image.asBlob(),
|
|
||||||
reader = new window.FileReader();
|
|
||||||
|
|
||||||
reader.readAsDataURL(url);
|
|
||||||
reader.onloadend = function () {
|
|
||||||
var snapshot = reader.result,
|
|
||||||
snapshotObject = {
|
|
||||||
src: snapshot,
|
|
||||||
type: url.type,
|
|
||||||
size: url.size,
|
|
||||||
modified: Date.now()
|
|
||||||
},
|
|
||||||
dirString = 'entries[' + entryPos + '].embeds[' + embedPos + '].snapshot';
|
|
||||||
|
|
||||||
openmct.objects.mutate(domainObject, dirString, snapshotObject);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('You cancelled the annotation!!!');
|
|
||||||
}
|
|
||||||
done(true);
|
|
||||||
}
|
|
||||||
}).show(embed.snapshot.src);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var self = this,
|
var self = this,
|
||||||
snapshot = new Vue({
|
snapshot = new Vue({
|
||||||
template: SnapshotTemplate,
|
template: SnapshotTemplate,
|
||||||
@ -157,22 +66,15 @@ function (
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatTime: self.formatTime,
|
formatTime: self.formatTime
|
||||||
annotateSnapshot: annotateSnapshot(self.openmct),
|
|
||||||
findInArray: self.findInArray
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function onDestroyCallback() {
|
function onDestroyCallback() {
|
||||||
snapshot.$destroy(true);
|
snapshot.$destroy(true);
|
||||||
}
|
}
|
||||||
var options = {
|
|
||||||
onDestroy: onDestroyCallback,
|
|
||||||
cssClass: 'l-large-view'
|
|
||||||
};
|
|
||||||
|
|
||||||
|
this.openmct.OverlayService.show(snapshot.$mount().$el, {onDestroy: onDestroyCallback, cssClass: 'l-large-view'});
|
||||||
this.openmct.OverlayService.show(snapshot.$mount().$el, options);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EmbedController.prototype.formatTime = function (unixTime, timeFormat) {
|
EmbedController.prototype.formatTime = function (unixTime, timeFormat) {
|
||||||
@ -223,20 +125,23 @@ function (
|
|||||||
var entryPosition = self.findInArray(self.domainObject.entries, entry.id),
|
var entryPosition = self.findInArray(self.domainObject.entries, entry.id),
|
||||||
embedPosition = self.findInArray(entry.embeds, embed.id);
|
embedPosition = self.findInArray(entry.embeds, embed.id);
|
||||||
|
|
||||||
self.openmct.OverlayService.showBlockingMessage({
|
var warningDialog = self.dialogService.showBlockingMessage({
|
||||||
severity: "error",
|
severity: "error",
|
||||||
actionText: 'This Action will permanently delete this embed. Do you wish to continue?',
|
title: "This action will permanently delete this embed. Do you wish to continue?",
|
||||||
buttons: [{
|
options: [{
|
||||||
label: "No",
|
label: "OK",
|
||||||
callback: function () {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Yes",
|
|
||||||
callback: function () {
|
callback: function () {
|
||||||
entry.embeds.splice(embedPosition, 1);
|
entry.embeds.splice(embedPosition, 1);
|
||||||
var dirString = 'entries[' + entryPosition + '].embeds';
|
var dirString = 'entries[' + entryPosition + '].embeds';
|
||||||
|
|
||||||
self.openmct.objects.mutate(self.domainObject, dirString, entry.embeds);
|
self.openmct.objects.mutate(self.domainObject, dirString, entry.embeds);
|
||||||
|
|
||||||
|
warningDialog.dismiss();
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
label: "Cancel",
|
||||||
|
callback: function () {
|
||||||
|
warningDialog.dismiss();
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
@ -302,8 +207,7 @@ function (
|
|||||||
openSnapshot: self.openSnapshot,
|
openSnapshot: self.openSnapshot,
|
||||||
formatTime: self.formatTime,
|
formatTime: self.formatTime,
|
||||||
toggleActionMenu: self.toggleActionMenu,
|
toggleActionMenu: self.toggleActionMenu,
|
||||||
actionToMenuDecorator: self.actionToMenuDecorator,
|
actionToMenuDecorator: self.actionToMenuDecorator
|
||||||
findInArray: self.findInArray
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,18 +81,21 @@ function (
|
|||||||
|
|
||||||
if (entryPos !== -1) {
|
if (entryPos !== -1) {
|
||||||
|
|
||||||
this.openmct.OverlayService.showBlockingMessage({
|
var errorDialog = this.dialogService.showBlockingMessage({
|
||||||
severity: "error",
|
severity: "error",
|
||||||
actionText: "This action will permanently delete this Notebook entry. Do you wish to continue?",
|
title: "This action will permanently delete this Notebook entry. Do you wish to continue?",
|
||||||
buttons: [{
|
options: [{
|
||||||
label: "No",
|
label: "OK",
|
||||||
callback: function () {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Yes",
|
|
||||||
callback: function () {
|
callback: function () {
|
||||||
domainObject.entries.splice(entryPos, 1);
|
domainObject.entries.splice(entryPos, 1);
|
||||||
openmct.objects.mutate(domainObject, 'entries', domainObject.entries);
|
openmct.objects.mutate(domainObject, 'entries', domainObject.entries);
|
||||||
|
|
||||||
|
errorDialog.dismiss();
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
label: "Cancel",
|
||||||
|
callback: function () {
|
||||||
|
errorDialog.dismiss();
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
@ -60,7 +60,7 @@ function (
|
|||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
||||||
var notebookEmbed = {
|
var notebookEmbed = {
|
||||||
inject:['openmct', 'domainObject'],
|
inject:['openmct'],
|
||||||
props:['embed', 'entry'],
|
props:['embed', 'entry'],
|
||||||
template: EmbedTemplate,
|
template: EmbedTemplate,
|
||||||
data: embedController.exposedData,
|
data: embedController.exposedData,
|
||||||
@ -81,7 +81,7 @@ function (
|
|||||||
|
|
||||||
var notebookVue = Vue.extend({
|
var notebookVue = Vue.extend({
|
||||||
template: NotebookTemplate,
|
template: NotebookTemplate,
|
||||||
provide: {openmct: self.openmct, domainObject: self.domainObject},
|
provide: {openmct: self.openmct},
|
||||||
components: {
|
components: {
|
||||||
'notebook-entry': entryComponent,
|
'notebook-entry': entryComponent,
|
||||||
'search': search.default
|
'search': search.default
|
||||||
|
@ -27,12 +27,10 @@
|
|||||||
|
|
||||||
<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 -->
|
|
||||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start__fixed"
|
|
||||||
v-if="isFixed">
|
v-if="isFixed">
|
||||||
<!-- Fixed input -->
|
<!-- Fixed start -->
|
||||||
<div class="c-conductor__start__fixed__label">Start</div>
|
<div class="c-conductor__start-fixed__label">Start</div>
|
||||||
<input class="c-input--datetime"
|
<input class="c-input--datetime"
|
||||||
type="text" autocorrect="off" spellcheck="false"
|
type="text" autocorrect="off" spellcheck="false"
|
||||||
ref="startDate"
|
ref="startDate"
|
||||||
@ -44,9 +42,9 @@
|
|||||||
@date-selected="startDateSelected"></date-picker>
|
@date-selected="startDateSelected"></date-picker>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start__delta"
|
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start-delta"
|
||||||
v-if="!isFixed">
|
v-if="!isFixed">
|
||||||
<!-- RT input -->
|
<!-- RT start -->
|
||||||
<div class="c-direction-indicator icon-minus"></div>
|
<div class="c-direction-indicator icon-minus"></div>
|
||||||
<input class="c-input--hrs-min-sec"
|
<input class="c-input--hrs-min-sec"
|
||||||
type="text" autocorrect="off"
|
type="text" autocorrect="off"
|
||||||
@ -54,14 +52,12 @@
|
|||||||
v-model="offsets.start"
|
v-model="offsets.start"
|
||||||
@change="validateOffsets($event); setOffsetsFromView()">
|
@change="validateOffsets($event); setOffsetsFromView()">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="c-conductor__end-input">
|
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end-fixed">
|
||||||
<!-- End input and controls -->
|
<!-- Fixed end and RT 'last update' display -->
|
||||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end__fixed"
|
<div class="c-conductor__end-fixed__label">
|
||||||
v-if="isFixed">
|
{{ isFixed ? 'End' : 'Updated' }}
|
||||||
<!-- Fixed input -->
|
</div>
|
||||||
<div class="c-conductor__end__fixed__label">End</div>
|
|
||||||
<input class="c-input--datetime"
|
<input class="c-input--datetime"
|
||||||
type="text" autocorrect="off" spellcheck="false"
|
type="text" autocorrect="off" spellcheck="false"
|
||||||
v-model="formattedBounds.end"
|
v-model="formattedBounds.end"
|
||||||
@ -72,12 +68,13 @@
|
|||||||
class="c-ctrl-wrapper--menus-left"
|
class="c-ctrl-wrapper--menus-left"
|
||||||
:default-date-time="formattedBounds.end"
|
:default-date-time="formattedBounds.end"
|
||||||
:formatter="timeFormatter"
|
:formatter="timeFormatter"
|
||||||
@date-selected="endDateSelected"></date-picker>
|
@date-selected="endDateSelected"
|
||||||
|
v-if="isFixed"></date-picker>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end__delta"
|
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end-delta"
|
||||||
v-if="!isFixed">
|
v-if="!isFixed">
|
||||||
<!-- RT input -->
|
<!-- RT end -->
|
||||||
<div class="c-direction-indicator icon-plus"></div>
|
<div class="c-direction-indicator icon-plus"></div>
|
||||||
<input class="c-input--hrs-min-sec"
|
<input class="c-input--hrs-min-sec"
|
||||||
type="text"
|
type="text"
|
||||||
@ -86,7 +83,6 @@
|
|||||||
v-model="offsets.end"
|
v-model="offsets.end"
|
||||||
@change="validateOffsets($event); setOffsetsFromView()">
|
@change="validateOffsets($event); setOffsetsFromView()">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<conductor-axis
|
<conductor-axis
|
||||||
class="c-conductor__ticks"
|
class="c-conductor__ticks"
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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); // Used
|
|
||||||
$colorOvrBg: $colorBodyBg; // Used
|
|
||||||
$colorOvrFg: $colorBodyFg; // Used
|
|
||||||
$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,20 +40,20 @@ $inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
|
|||||||
$menuLineH: 1.5rem;
|
$menuLineH: 1.5rem;
|
||||||
$treeItemIndent: 16px;
|
$treeItemIndent: 16px;
|
||||||
$treeTypeIconW: 18px;
|
$treeTypeIconW: 18px;
|
||||||
$overlayOuterMarginLg: 5%;
|
$overlayOuterMargin: 5%;
|
||||||
$overlayOuterMarginDialog: 20%;
|
|
||||||
$overlayInnerMargin: 25px;
|
$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 */
|
||||||
|
@ -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 {
|
||||||
@ -237,11 +128,44 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************** FORM ELEMENTS */
|
/******************************************************** FORM ELEMENTS */
|
||||||
/********* Inline inputs */
|
input, textarea {
|
||||||
.c-input-inline {
|
font-family: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
letter-spacing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text],
|
||||||
|
input[type=search],
|
||||||
|
input[type=number] {
|
||||||
|
@include reactive-input();
|
||||||
|
padding: $inputTextP;
|
||||||
|
&.numeric {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=number]::-webkit-inner-spin-button,
|
||||||
|
input[type=number]::-webkit-outer-spin-button {
|
||||||
|
margin-right: -5px !important;
|
||||||
|
margin-top: -1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-input {
|
||||||
|
&--datetime {
|
||||||
|
// Sized for values such as 2018-09-28 22:32:33.468Z
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--hrs-min-sec {
|
||||||
|
// Sized for values such as 00:25:00
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-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 input-base();
|
@include reactive-input($bg: transparent);
|
||||||
border: 1px solid transparent;
|
box-shadow: none;
|
||||||
display: block !important;
|
display: block !important;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
@ -256,19 +180,14 @@ button {
|
|||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
|
background: $colorInputBg;
|
||||||
padding-left: $inputTextPLeftRight;
|
padding-left: $inputTextPLeftRight;
|
||||||
padding-right: $inputTextPLeftRight;
|
padding-right: $inputTextPLeftRight;
|
||||||
}
|
}
|
||||||
&:hover {
|
|
||||||
border-color: rgba($colorBodyFg, 0.2);
|
|
||||||
}
|
}
|
||||||
&:focus {
|
|
||||||
@include nice-input($shdw: rgba(0, 0, 0, 0.6) 0 1px 3px);
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-labeled-input {
|
&--labeled {
|
||||||
|
// 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();
|
||||||
@ -276,16 +195,6 @@ button {
|
|||||||
input {
|
input {
|
||||||
margin-left: $interiorMarginSm;
|
margin-left: $interiorMarginSm;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************** HYPERLINKS AND HYPERLINK BUTTONS */
|
|
||||||
.c-hyperlink {
|
|
||||||
&--link {
|
|
||||||
color: $colorKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--button {
|
|
||||||
@include cButton();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,7 +232,6 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mixin menuInner() {
|
@mixin menuInner() {
|
||||||
color: $colorMenuFg;
|
|
||||||
li {
|
li {
|
||||||
@include cControl();
|
@include cControl();
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
@ -349,10 +257,6 @@ button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin modalMenu() {
|
|
||||||
// Optional modifier that makes a c-menu more mobile-friendly
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-menu {
|
.c-menu {
|
||||||
@include menuOuter();
|
@include menuOuter();
|
||||||
@include menuInner();
|
@include menuInner();
|
||||||
@ -397,11 +301,6 @@ button {
|
|||||||
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;
|
||||||
@ -413,6 +312,7 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__name {
|
&__name {
|
||||||
|
color: $colorMenuFg;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
@ -576,3 +476,9 @@ button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************** SLIDERS */
|
||||||
|
.c-slider {
|
||||||
|
@include cControl();
|
||||||
|
> * + * { margin-left: $interiorMargin; }
|
||||||
|
}
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************** RESETS */
|
/******************************* RESETS */
|
||||||
*,
|
*,
|
||||||
:before,
|
:before,
|
||||||
:after {
|
:after {
|
||||||
@ -60,7 +60,7 @@ div {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************** UTILITIES */
|
/******************************* UTILITIES */
|
||||||
.u-contents {
|
.u-contents {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ div {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************** BROWSER ELEMENTS */
|
/******************************* BROWSER ELEMENTS */
|
||||||
body.desktop {
|
body.desktop {
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -92,30 +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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=number]::-webkit-inner-spin-button,
|
|
||||||
input[type=number]::-webkit-outer-spin-button {
|
|
||||||
//margin: -1px -5px inherit -5px !important;
|
|
||||||
margin-right: -5px !important;
|
|
||||||
margin-top: -1px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** HTML ENTITIES */
|
/************************** HTML ENTITIES */
|
||||||
@ -223,21 +209,7 @@ body.desktop .has-local-controls {
|
|||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
/******************************************************** IS */
|
/************************** LEGACY */
|
||||||
|
|
||||||
.is-selectable {
|
|
||||||
&:hover {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-editing {
|
|
||||||
.is-selectable {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/******************************************************** LEGACY */
|
|
||||||
|
|
||||||
mct-container {
|
mct-container {
|
||||||
display: block;
|
display: block;
|
||||||
@ -309,6 +281,21 @@ a.disabled {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-selection {
|
||||||
|
// aka selection = "None". Used in palettes and their menu buttons.
|
||||||
|
$c: red;
|
||||||
|
$s: 48%;
|
||||||
|
$e: 52%;
|
||||||
|
background-image: linear-gradient(-45deg,
|
||||||
|
transparent $s - 5%,
|
||||||
|
$c $s,
|
||||||
|
$c $e,
|
||||||
|
transparent $e + 5%
|
||||||
|
);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
.scrolling,
|
.scrolling,
|
||||||
.scroll {
|
.scroll {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -20,8 +20,6 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
// VERSION MANUALLY MIGRATED FROM VUE-TOOLBAR
|
|
||||||
|
|
||||||
/************************** VISUALS */
|
/************************** VISUALS */
|
||||||
@mixin ancillaryIcon($d, $c) {
|
@mixin ancillaryIcon($d, $c) {
|
||||||
// Used for small icons used in combination with larger icons,
|
// Used for small icons used in combination with larger icons,
|
||||||
@ -115,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;
|
|
||||||
grid-row-gap: 0;
|
|
||||||
grid-template-columns: 1fr 2fr;
|
|
||||||
align-items: start;
|
|
||||||
|
|
||||||
[class*="header"] {
|
|
||||||
border-radius: $smallCr;
|
border-radius: $smallCr;
|
||||||
background-color: $colorInspectorSectionHeaderBg;
|
background-color: $colorInspectorSectionHeaderBg;
|
||||||
color: $colorInspectorSectionHeaderFg;
|
color: $colorInspectorSectionHeaderFg;
|
||||||
|
font-weight: normal;
|
||||||
margin: 0 0 $interiorMarginSm 0;
|
margin: 0 0 $interiorMarginSm 0;
|
||||||
padding: $interiorMarginSm $interiorMargin;
|
padding: $interiorMarginSm $interiorMargin;
|
||||||
|
text-transform: uppercase;
|
||||||
&: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() {
|
||||||
@ -165,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;
|
||||||
@ -184,7 +170,7 @@
|
|||||||
border-radius: $controlCr;
|
border-radius: $controlCr;
|
||||||
|
|
||||||
&.error {
|
&.error {
|
||||||
background-color: $colorFormFieldErrorBg;
|
background: $colorFormFieldErrorBg;
|
||||||
color: $colorFormFieldErrorFg;
|
color: $colorFormFieldErrorFg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,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.
|
||||||
|
@ -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";
|
@ -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>
|
||||||
@ -62,13 +63,10 @@
|
|||||||
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 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__collapse-button {
|
&__header {
|
||||||
$m: 2px;
|
font-size: floor(12px * .9);
|
||||||
$h: 12px;
|
}
|
||||||
color: $splitterBtnColorFg;
|
|
||||||
flex: 0 0 nth($splitterBtnD, 1);
|
|
||||||
font-size: $h * .9;
|
|
||||||
position: relative;
|
|
||||||
justify-content: start;
|
|
||||||
transition: $transOut;
|
|
||||||
|
|
||||||
&:after {
|
&__collapse-button {
|
||||||
// Close icon
|
box-shadow: none;
|
||||||
background: $colorBtnBg;
|
background: $splitterBtnColorBg;
|
||||||
|
color: $splitterBtnColorFg;
|
||||||
border-radius: $smallCr;
|
border-radius: $smallCr;
|
||||||
color: $colorBtnFg;
|
|
||||||
content: $glyph-icon-arrow-right-equilateral;
|
|
||||||
display: block;
|
|
||||||
font-family: symbolsfont;
|
|
||||||
font-size: 6px;
|
font-size: 6px;
|
||||||
line-height: 90%;
|
line-height: 90%;
|
||||||
padding: 3px 15px;
|
padding: 3px 15px;
|
||||||
position: absolute;
|
|
||||||
right: $m;
|
|
||||||
top: $m;
|
|
||||||
transition: $transOut;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
@include hover() {
|
||||||
background: rgba(black, 0.1);
|
background: $colorBtnBgHov;
|
||||||
&:after {
|
color: $colorBtnFgHov;
|
||||||
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 */
|
||||||
position: absolute;
|
[class*="__header"] {
|
||||||
top: 0; right: 0; bottom: 0; left: 0;
|
@include abs();
|
||||||
height: auto; width: 100%;
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
[class*="label"] {
|
[class*="label"] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: translate($interiorMarginLg + 1, 18px) rotate(90deg);
|
transform: translate($interiorMarginLg + 1, 18px) rotate(90deg);
|
||||||
|
left: 3px;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
.l-pane__collapse-button {
|
||||||
background: none;
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0; // Only have to do this once, because of scaleX(-1) below.
|
||||||
|
position: absolute;
|
||||||
|
top: 0; right: 0; bottom: 0; left: 0;
|
||||||
|
height: auto; width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
top: $interiorMargin;
|
|
||||||
left: 50%;
|
&:before {
|
||||||
right: auto;
|
position: absolute;
|
||||||
transform: translateX(-50%);
|
top: 5px;
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,12 @@
|
|||||||
this.openmct.editor.cancel();
|
this.openmct.editor.cancel();
|
||||||
},
|
},
|
||||||
saveAndFinishEditing() {
|
saveAndFinishEditing() {
|
||||||
this.openmct.editor.save();
|
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 () {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="l-shell" :class="{'is-editing': isEditing}">
|
<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,12 +25,9 @@
|
|||||||
<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">
|
||||||
:class="{ 'is-editing' : true }">
|
|
||||||
<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>
|
||||||
@ -48,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>
|
||||||
@ -62,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
|
||||||
@ -138,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*="__"] {
|
||||||
@ -165,27 +184,40 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******************************* 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%;
|
||||||
@ -198,18 +230,12 @@
|
|||||||
&__pane-inspector {
|
&__pane-inspector {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__toolbar {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-bottom: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<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';
|
||||||
@ -219,6 +245,7 @@
|
|||||||
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';
|
import Toolbar from './Toolbar.vue';
|
||||||
|
|
||||||
var enterFullScreen = () => {
|
var enterFullScreen = () => {
|
||||||
@ -251,12 +278,8 @@
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
data() {
|
|
||||||
return {isEditing: false};
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
Inspector,
|
Inspector,
|
||||||
MctStatus,
|
|
||||||
MctTree,
|
MctTree,
|
||||||
ObjectView,
|
ObjectView,
|
||||||
'mct-template': MctTemplate,
|
'mct-template': MctTemplate,
|
||||||
@ -266,6 +289,7 @@
|
|||||||
multipane,
|
multipane,
|
||||||
pane,
|
pane,
|
||||||
BrowseBar,
|
BrowseBar,
|
||||||
|
StatusBar,
|
||||||
Toolbar
|
Toolbar
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -276,7 +300,8 @@
|
|||||||
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>
|
|
@ -1,10 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div class="c-tree__wrapper">
|
||||||
<ul class="c-tree">
|
<ul class="c-tree">
|
||||||
<tree-item v-for="child in children"
|
<tree-item v-for="child in children"
|
||||||
:key="child.id"
|
:key="child.id"
|
||||||
:node="child">
|
:node="child">
|
||||||
</tree-item>
|
</tree-item>
|
||||||
</ul>
|
</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;
|
||||||
}
|
}
|
||||||
@ -99,7 +106,7 @@
|
|||||||
children: []
|
children: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'domainObject'],
|
inject: ['openmct'],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.openmct.objects.get('ROOT')
|
this.openmct.objects.get('ROOT')
|
||||||
.then(root => this.openmct.composition.get(root).load())
|
.then(root => this.openmct.composition.get(root).load())
|
||||||
|
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>
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,91 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="c-message"
|
|
||||||
v-bind:class="">
|
|
||||||
<!-- This element is displayed within the overlay service as well as in the list of messages
|
|
||||||
Uses flex-row -->
|
|
||||||
<div class="c-message__icon"
|
|
||||||
:class="['message-severity-' + model.severity]"></div>
|
|
||||||
<div class="c-message__text">
|
|
||||||
<!-- Uses flex-column -->
|
|
||||||
<div class="c-message__title"
|
|
||||||
v-if="model.title">
|
|
||||||
{{model.title}}
|
|
||||||
</div>
|
|
||||||
<div class="c-message__hint"
|
|
||||||
v-if="model.hint">
|
|
||||||
{{model.hint}}
|
|
||||||
<span v-if="model.timestamp">[{{model.timestamp}}]</span>
|
|
||||||
</div>
|
|
||||||
<div class="c-message__action-text"
|
|
||||||
v-if="model.actionText">
|
|
||||||
{{model.actionText}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="c-message__actions"
|
|
||||||
v-if="model.primaryOption">
|
|
||||||
<a class="c-button c-button--major"
|
|
||||||
@click="model.primaryOption.callback()">
|
|
||||||
{{model.primaryOption.label}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "~styles/sass-base";
|
|
||||||
|
|
||||||
.c-message {
|
|
||||||
display: flex;
|
|
||||||
padding: $interiorMarginLg;
|
|
||||||
|
|
||||||
> * + * {
|
|
||||||
@include test();
|
|
||||||
margin-left: $interiorMarginLg;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon {
|
|
||||||
$s: 50px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
min-width: $s;
|
|
||||||
min-height: $s;
|
|
||||||
|
|
||||||
&.message-severity {
|
|
||||||
// TEMP: TODO: replace with SVG background assets
|
|
||||||
&-alert {
|
|
||||||
background: $colorAlert;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-error {
|
|
||||||
background: $colorFormError;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
|
|
||||||
> * + * {
|
|
||||||
@include test();
|
|
||||||
margin-top: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// __text elements
|
|
||||||
&__title,
|
|
||||||
&__action-text {
|
|
||||||
font-size: 1.2em; // TEMP
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
inject:['model']
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -8,19 +8,9 @@
|
|||||||
v-on:click="destroy">
|
v-on:click="destroy">
|
||||||
</button>
|
</button>
|
||||||
<div class="c-overlay__contents" ref="element"></div>
|
<div class="c-overlay__contents" ref="element"></div>
|
||||||
<div class="c-overlay__button-bar" v-if="!buttons">
|
<div class="c-overlay__button-bar">
|
||||||
<button class="c-button c-button--major"
|
<button class="c-button c-button--major"
|
||||||
v-on:click="destroy">
|
v-on:click="destroy">Done</button>
|
||||||
Done
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="c-overlay__button-bar" v-if="buttons">
|
|
||||||
<button class="c-button c-button--major"
|
|
||||||
v-for="(button, index) in buttons"
|
|
||||||
:key="index"
|
|
||||||
@click="buttonClickHandler(button.callback)">
|
|
||||||
{{button.label}}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -29,13 +19,6 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
@mixin overlaySizing($marginTB: 5%, $marginLR: $marginTB, $width: auto, $height: auto) {
|
|
||||||
position: absolute;
|
|
||||||
top: $marginTB; right: $marginLR; bottom: $marginTB; left: $marginLR;
|
|
||||||
width: $width;
|
|
||||||
height: $height;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-overlay-wrapper {
|
.l-overlay-wrapper {
|
||||||
// Created by overlayService.js, contains this template.
|
// Created by overlayService.js, contains this template.
|
||||||
// Acts as an anchor for one or more overlays.
|
// Acts as an anchor for one or more overlays.
|
||||||
@ -52,8 +35,8 @@
|
|||||||
|
|
||||||
&__outer {
|
&__outer {
|
||||||
@include abs();
|
@include abs();
|
||||||
background: $colorOvrBg;
|
background: $overlayColorBg;
|
||||||
color: $colorOvrFg;
|
color: $overlayColorFg;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: $overlayInnerMargin;
|
padding: $overlayInnerMargin;
|
||||||
@ -79,77 +62,30 @@
|
|||||||
margin-top: $interiorMargin;
|
margin-top: $interiorMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.desktop & {
|
||||||
// Overlay types, styling independent of platform.
|
|
||||||
.l-large-view & {
|
|
||||||
// Default
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-dialog & {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-message & {
|
|
||||||
&__outer {
|
|
||||||
// background: orange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
body.desktop {
|
|
||||||
.c-overlay {
|
|
||||||
&__blocker {
|
&__blocker {
|
||||||
@include abs();
|
@include abs();
|
||||||
background: $colorOvrBlocker;
|
background: rgba(black, 0.7);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__outer {
|
&__outer {
|
||||||
|
$m: $overlayOuterMargin;
|
||||||
|
top: $m; right: $m; bottom: $m; left: $m;
|
||||||
border-radius: $overlayCr;
|
border-radius: $overlayCr;
|
||||||
box-shadow: rgba(black, 0.5) 0 2px 25px;
|
box-shadow: rgba(black, 0.5) 0 2px 25px;
|
||||||
// Defaults to l-large-view
|
|
||||||
@include overlaySizing($overlayOuterMarginLg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overlay types, styling for desktop.
|
|
||||||
.l-large-view {
|
|
||||||
// Default
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-dialog {
|
|
||||||
.c-overlay__outer {
|
|
||||||
@include overlaySizing($overlayOuterMarginDialog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-message {
|
|
||||||
.c-overlay__outer {
|
|
||||||
@include overlaySizing(auto);
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
inject: ['destroy', 'element', 'buttons'],
|
inject: ['destroy', 'element'],
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$refs.element.appendChild(this.element);
|
this.$refs.element.appendChild(this.element);
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
buttonClickHandler: function (method) {
|
|
||||||
method();
|
|
||||||
this.destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -22,19 +22,15 @@
|
|||||||
|
|
||||||
define([
|
define([
|
||||||
'./overlay.vue',
|
'./overlay.vue',
|
||||||
'./blockingMessage.vue',
|
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
OverlayComponent,
|
OverlayComponent,
|
||||||
BlockingMessage,
|
|
||||||
Vue
|
Vue
|
||||||
) {
|
) {
|
||||||
|
|
||||||
function OverlayService() {
|
function OverlayService() {
|
||||||
this.activeOverlays = [];
|
this.activeOverlays = [];
|
||||||
this.overlayId = 0;
|
this.overlayId = 0;
|
||||||
|
|
||||||
this.showBlockingMessage = this.showBlockingMessage.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayService.prototype.show = function (element, options) {
|
OverlayService.prototype.show = function (element, options) {
|
||||||
@ -47,96 +43,45 @@ define([
|
|||||||
component = new Vue({
|
component = new Vue({
|
||||||
provide: {
|
provide: {
|
||||||
destroy: this.destroy.bind(this),
|
destroy: this.destroy.bind(this),
|
||||||
element: element,
|
element: element
|
||||||
buttons: options.buttons
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
OverlayComponent: OverlayComponent.default
|
OverlayComponent: OverlayComponent.default
|
||||||
},
|
},
|
||||||
template: '<overlay-component></overlay-component>'
|
template: '<overlay-component></overlay-component>'
|
||||||
}),
|
});
|
||||||
dialog = {};
|
|
||||||
|
|
||||||
|
|
||||||
overlay.classList.add('l-overlay-wrapper', overlayTypeCssClass);
|
overlay.classList.add('l-overlay-wrapper', overlayTypeCssClass);
|
||||||
document.body.appendChild(overlay);
|
document.body.appendChild(overlay);
|
||||||
|
|
||||||
overlay.appendChild(component.$mount().$el);
|
overlay.appendChild(component.$mount().$el);
|
||||||
|
|
||||||
var overlayObject = {
|
this.activeOverlays.push({
|
||||||
overlay: overlay,
|
overlay: overlay,
|
||||||
component: component,
|
component: component,
|
||||||
onDestroy: options.onDestroy,
|
onDestroy: options.onDestroy,
|
||||||
id: this.overlayId,
|
id: this.overlayId
|
||||||
dialog: dialog
|
});
|
||||||
|
|
||||||
|
this.overlayId++;
|
||||||
};
|
};
|
||||||
|
|
||||||
dialog.dismiss = function () {
|
OverlayService.prototype.destroy = function () {
|
||||||
let pos = findInArray(overlayObject.id, this.activeOverlays);
|
var lastActiveOverlayObject = this.activeOverlays.pop(),
|
||||||
|
lastActiveOverlay = lastActiveOverlayObject.overlay,
|
||||||
|
lastActiveComponent = lastActiveOverlayObject.component;
|
||||||
|
|
||||||
if (pos !== -1) {
|
if (lastActiveOverlayObject.onDestroy && typeof lastActiveOverlayObject.onDestroy === 'function') {
|
||||||
if (overlayObject.onDestroy && typeof overlayObject.onDestroy === 'function') {
|
lastActiveOverlayObject.onDestroy();
|
||||||
overlayObject.onDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
overlayObject.component.$destroy(true);
|
lastActiveComponent.$destroy(true);
|
||||||
document.body.removeChild(overlayObject.overlay);
|
document.body.removeChild(lastActiveOverlay);
|
||||||
this.activeOverlays.splice(pos, 1);
|
|
||||||
|
|
||||||
if (this.activeOverlays.length) {
|
if (this.activeOverlays.length) {
|
||||||
this.activeOverlays[this.activeOverlays.length - 1].overlay.classList.remove('invisible');
|
this.activeOverlays[this.activeOverlays.length - 1].overlay.classList.remove('invisible');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
this.activeOverlays.push(overlayObject);
|
|
||||||
this.overlayId++;
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OverlayService.prototype.destroy = function () {
|
|
||||||
var lastActiveOverlayObject = this.activeOverlays[this.activeOverlays.length - 1];
|
|
||||||
|
|
||||||
lastActiveOverlayObject.dialog.dismiss(lastActiveOverlayObject.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
OverlayService.prototype.showBlockingMessage = function (model) {
|
|
||||||
let component = new Vue({
|
|
||||||
provide: {
|
|
||||||
model: model
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
BlockingMessage: BlockingMessage.default
|
|
||||||
},
|
|
||||||
template: '<blocking-message></blocking-message>'
|
|
||||||
});
|
|
||||||
|
|
||||||
function destroy() {
|
|
||||||
component.$destroy(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let options = {
|
|
||||||
cssClass: 'l-message',
|
|
||||||
onDestroy: destroy,
|
|
||||||
buttons: model.buttons
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.show(component.$mount().$el, options);
|
|
||||||
};
|
|
||||||
|
|
||||||
function findInArray(id, array) {
|
|
||||||
var found = -1;
|
|
||||||
|
|
||||||
array.forEach(function (o,i) {
|
|
||||||
if (o.id === id) {
|
|
||||||
found = i;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
return OverlayService;
|
return OverlayService;
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user