Overlay Service re-written in Vue (#2186)

* working overlayService

* wire to snapshot, and add onDestroy Callback

* increment overlayId

* New branch from topic-core-refactor to use as central point for common
CSS work

- Manually migrated changes from vue-toolbar, expect conflicts there and
 in vue-layout;

* Manually update constants-snow from vue-toolbar branch

* Update markup to use latest button classnames

- c-menu-button > c-button--menu;
- c-icon-button > c-click-icon;

* Various from vue-conductor-style

- Mods to input styling;
- Input[] styles moved to _controls;
- New/revised constants vals;

* Resolve bizarre merge conflict when applying stash

* Code cleanup

* remove duplicate div

* Alias and type-icon fixes

- More robust approach to alias indicators;
- Added alias indication to tree-item.vue;
- TODO: wire up alias indication tree-item.vue;

* Accessibility mods, convert elements to <button>

- Better reset styles for htmlInputReset mixin to allow use of <button>
without browser default styling;
- Create button;
- BrowseBar action buttons;
- c-click-icons;
- Removed Preview button from BrowseBar.vue;

* Overlay styling WIP

- Base markup pretty solid;
- Stubbed in temp values for overlayTypeCssClass in overlayService.js;
- TODO: styling for contents area;

* add options object, scope variables to show function, add destroy callback to active Overlay Object (for easier retrieval
This commit is contained in:
Deep Tailor 2018-10-04 15:59:58 -07:00 committed by Pete Richards
parent e7cdb334de
commit f40c9fa6f9
10 changed files with 243 additions and 9 deletions

View File

@ -40,6 +40,7 @@ define([
'./styles-new/core.scss',
'./styles-new/notebook.scss',
'./ui/components/layout/Layout.vue',
'./ui/overlayService/overlayService',
'vue'
], function (
EventEmitter,
@ -61,6 +62,7 @@ define([
coreStyles,
NotebookStyles,
Layout,
OverlayService,
Vue
) {
/**
@ -225,6 +227,8 @@ define([
this.editor = new api.EditorAPI.default(this);
this.OverlayService = new OverlayService();
this.legacyRegistry = defaultRegistry;
this.install(this.plugins.Plot());
this.install(this.plugins.TelemetryTable());

View File

@ -0,0 +1,29 @@
<div class="u-contents">
<div class="t-snapshot abs l-view-header">
<div class="abs object-browse-bar l-flex-row">
<div class="left flex-elem l-flex-row grows">
<div class="object-header flex-elem l-flex-row grows">
<div class="type-icon flex-elem embed-icon holder" v-bind:class="embed.cssClass"></div>
<div class="title-label flex-elem holder flex-can-shrink">{{embed.name}}</div>
</div>
</div>
</div>
</div>
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
<div class="flex-elem holder flex-can-shrink s-snapshot-datetime">
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
</div>
<a class="s-button icon-pencil" title="Annotate">
<span class="title-label">Annotate</span>
</a>
</div>
<div class="abs object-holder t-image-holder s-image-holder">
<div
class="image-main s-image-main"
v-bind:style="{ backgroundImage: 'url(' + embed.snapshot.src + ')' }">
</div>
</div>
</div>

View File

@ -24,11 +24,15 @@ define([
'moment',
'zepto',
'../utils/SnapshotOverlay',
'../../res/templates/snapshotTemplate.html',
'vue'
],
function (
Moment,
$,
SnapshotOverlay
SnapshotOverlay,
SnapshotTemplate,
Vue
) {
function EmbedController (openmct, domainObject) {
this.openmct = openmct;
@ -53,11 +57,24 @@ function (
};
EmbedController.prototype.openSnapshot = function () {
if (!this.snapshotOverlay) {
this.snapShotOverlay = new SnapshotOverlay(this.embed, this.formatTime);
} else {
this.snapShotOverlay = undefined;
var self = this,
snapshot = new Vue({
template: SnapshotTemplate,
data: function () {
return {
embed: self.embed
};
},
methods: {
formatTime: self.formatTime
}
});
function onDestroyCallback() {
snapshot.$destroy(true);
}
this.openmct.OverlayService.show(snapshot.$mount().$el, {onDestroy: onDestroyCallback, cssClass: 'l-large-view'});
};
EmbedController.prototype.formatTime = function (unixTime, timeFormat) {

View File

@ -60,6 +60,7 @@ function (
this.container = container;
var notebookEmbed = {
inject:['openmct'],
props:['embed', 'entry'],
template: EmbedTemplate,
data: embedController.exposedData,
@ -80,6 +81,7 @@ function (
var notebookVue = Vue.extend({
template: NotebookTemplate,
provide: {openmct: self.openmct},
components: {
'notebook-entry': entryComponent,
'search': search.default

View File

@ -224,9 +224,9 @@ $colorThumbsBubbleFg: pullForward($colorBodyFg, 10%);
$colorThumbsBubbleBg: pullForward($colorBodyBg, 10%);
// Overlay
$colorOvrBlocker: rgba(black, 0.7);//
$colorOvrBg: $colorBodyBg;
$colorOvrFg: $colorBodyFg;
$colorOvrBlocker: rgba(black, 0.7); // Used
$colorOvrBg: $colorBodyBg; // Used
$colorOvrFg: $colorBodyFg; // Used
$colorOvrBtnBg: pullForward($colorOvrBg, 40%);
$colorOvrBtnFg: #fff;
$colorFieldHintOverlay: pullForward($colorOvrBg, 40%);

View File

@ -40,6 +40,8 @@ $inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
$menuLineH: 1.5rem;
$treeItemIndent: 16px;
$treeTypeIconW: 18px;
$overlayOuterMargin: 5%;
$overlayInnerMargin: 25px;
/*************** Items */
$itemPadLR: 5px;

View File

@ -20,6 +20,8 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
// VERSION MANUALLY MIGRATED FROM VUE-TOOLBAR
/************************** VISUALS */
@mixin ancillaryIcon($d, $c) {
// Used for small icons used in combination with larger icons,

View File

@ -30,7 +30,7 @@
import viewControl from '../controls/viewControl.vue'
export default {
name: 'tree-item',
inject: ['openmct'],
inject: ['openmct', 'domainObject'],
props: {
node: Object
},

View File

@ -0,0 +1,91 @@
<template>
<div class="c-overlay">
<div class="c-overlay__blocker"
v-on:click="destroy">
</div>
<div class="c-overlay__outer">
<button class="c-click-icon c-overlay__close-button icon-x-in-circle"
v-on:click="destroy">
</button>
<div class="c-overlay__contents" ref="element"></div>
<div class="c-overlay__button-bar">
<button class="c-button c-button--major"
v-on:click="destroy">Done</button>
</div>
</div>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.l-overlay-wrapper {
// Created by overlayService.js, contains this template.
// Acts as an anchor for one or more overlays.
display: contents;
}
.c-overlay {
@include abs();
z-index: 100;
&__blocker {
display: none; // Mobile-first
}
&__outer {
@include abs();
background: $colorOvrBg;
color: $colorOvrFg;
display: flex;
flex-direction: column;
padding: $overlayInnerMargin;
}
&__close-button {
$p: $interiorMarginSm;
border-radius: 100%;
display: inline-block;
position: absolute;
top: $p; right: $p;
}
&__contents {
flex: 1 1 auto;
overflow: auto;
}
&__button-bar {
flex: 0 0 auto;
display: flex;
justify-content: flex-end;
margin-top: $interiorMargin;
}
body.desktop & {
&__blocker {
@include abs();
background: $colorOvrBlocker;
cursor: pointer;
display: block;
}
&__outer {
$m: $overlayOuterMargin;
top: $m; right: $m; bottom: $m; left: $m;
border-radius: $overlayCr;
box-shadow: rgba(black, 0.5) 0 2px 25px;
}
}
}
</style>
<script>
export default {
inject: ['destroy', 'element'],
mounted() {
this.$refs.element.appendChild(this.element);
}
}
</script>

View File

@ -0,0 +1,87 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'./overlay.vue',
'vue'
], function (
OverlayComponent,
Vue
) {
function OverlayService() {
this.activeOverlays = [];
this.overlayId = 0;
}
OverlayService.prototype.show = function (element, options) {
if(this.activeOverlays.length) {
this.activeOverlays[this.activeOverlays.length - 1].overlay.classList.add('invisible');
}
let overlayTypeCssClass = options.cssClass, // Values could be l-large-view, l-dialog, l-message
overlay = document.createElement('div'),
component = new Vue({
provide: {
destroy: this.destroy.bind(this),
element: element
},
components: {
OverlayComponent: OverlayComponent.default
},
template: '<overlay-component></overlay-component>'
});
overlay.classList.add('l-overlay-wrapper', overlayTypeCssClass);
document.body.appendChild(overlay);
overlay.appendChild(component.$mount().$el);
this.activeOverlays.push({
overlay: overlay,
component: component,
onDestroy: options.onDestroy,
id: this.overlayId
});
this.overlayId++;
};
OverlayService.prototype.destroy = function () {
var lastActiveOverlayObject = this.activeOverlays.pop(),
lastActiveOverlay = lastActiveOverlayObject.overlay,
lastActiveComponent = lastActiveOverlayObject.component;
if (lastActiveOverlayObject.onDestroy && typeof lastActiveOverlayObject.onDestroy === 'function') {
lastActiveOverlayObject.onDestroy();
}
lastActiveComponent.$destroy(true);
document.body.removeChild(lastActiveOverlay);
if (this.activeOverlays.length) {
this.activeOverlays[this.activeOverlays.length - 1].overlay.classList.remove('invisible');
}
};
return OverlayService;
});