More fixes for TCR (#2255)

* Open in new tab
* Fix splitter resizing error, and css background issue
* Prevent new line on enter key press when editing name in object browse bar. Update domainObject name on enter key press in Object Browse Bar
* Flexible layout should react to composition remove, and fix delete container
* Render a drag ghost when dragging frame items in flexible layout
* Use composition.on add to add new frames
This commit is contained in:
Deep Tailor 2019-01-29 14:55:38 -08:00 committed by Andrew Henry
parent 1dc1cc6c24
commit e254fafb5c
10 changed files with 109 additions and 35 deletions

View File

@ -35,7 +35,7 @@
class="c-fl-frame__drop-hint" class="c-fl-frame__drop-hint"
:index="-1" :index="-1"
:allow-drop="allowDrop" :allow-drop="allowDrop"
@object-drop-to="moveOrCreateFrame"> @object-drop-to="moveOrCreateNewFrame">
</drop-hint> </drop-hint>
<div class="c-fl-container__frames-holder"> <div class="c-fl-container__frames-holder">
@ -55,7 +55,7 @@
:key="i" :key="i"
:index="i" :index="i"
:allowDrop="allowDrop" :allowDrop="allowDrop"
@object-drop-to="moveOrCreateFrame"> @object-drop-to="moveOrCreateNewFrame">
</drop-hint> </drop-hint>
<resize-handle <resize-handle
@ -123,15 +123,12 @@ export default {
return true; return true;
} }
}, },
moveOrCreateFrame(insertIndex, event) { moveOrCreateNewFrame(insertIndex, event) {
if (event.dataTransfer.types.includes('openmct/domain-object-path')) { if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
// create frame using domain object
let domainObject = JSON.parse(event.dataTransfer.getData('openmct/domain-object-path'))[0];
this.$emit( this.$emit(
'create-frame', 'new-frame',
this.index, this.index,
insertIndex, insertIndex
domainObject.identifier
); );
return; return;
}; };

View File

@ -24,6 +24,7 @@
<div v-show="isValidTarget"> <div v-show="isValidTarget">
<div class="c-drop-hint c-drop-hint--always-show" <div class="c-drop-hint c-drop-hint--always-show"
:class="{'is-mouse-over': isMouseOver}" :class="{'is-mouse-over': isMouseOver}"
@dragover.prevent
@dragenter="dragenter" @dragenter="dragenter"
@dragleave="dragleave" @dragleave="dragleave"
@drop="dropHandler"> @drop="dropHandler">
@ -71,10 +72,12 @@ export default {
mounted() { mounted() {
document.addEventListener('dragstart', this.dragstart); document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend); document.addEventListener('dragend', this.dragend);
document.addEventListener('drop', this.dragend);
}, },
destroyed() { destroyed() {
document.removeEventListener('dragstart', this.dragstart); document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend); document.removeEventListener('dragend', this.dragend);
document.removeEventListener('drop', this.dragend);
} }
} }
</script> </script>

View File

@ -22,6 +22,11 @@
<template> <template>
<div class="c-fl"> <div class="c-fl">
<div
id="js-fl-drag-ghost"
class="c-fl__drag-ghost">
</div>
<div class="c-fl__empty" <div class="c-fl__empty"
v-if="areAllContainersEmpty()"> v-if="areAllContainersEmpty()">
<span class="c-fl__empty-message">This Flexible Layout is currently empty</span> <span class="c-fl__empty-message">This Flexible Layout is currently empty</span>
@ -50,7 +55,7 @@
:container="container" :container="container"
:rowsLayout="rowsLayout" :rowsLayout="rowsLayout"
@move-frame="moveFrame" @move-frame="moveFrame"
@create-frame="createFrame" @new-frame="setFrameLocation"
@persist="persist"> @persist="persist">
</container-component> </container-component>
@ -137,6 +142,23 @@
opacity: 0.5; opacity: 0.5;
} }
} }
&__drag-ghost{
background: $colorItemTreeHoverBg;
color: $colorItemTreeHoverFg;
border-radius: $basicCr;
display: flex;
align-items: center;
padding: $interiorMarginLg $interiorMarginLg * 2;
position: absolute;
top: -10000px;
z-index: 2;
&:before {
color: $colorKey;
margin-right: $interiorMarginSm;
}
}
} }
.c-fl-container { .c-fl-container {
@ -451,7 +473,8 @@ export default {
}, },
data() { data() {
return { return {
domainObject: this.layoutObject domainObject: this.layoutObject,
newFrameLocation: []
} }
}, },
computed: { computed: {
@ -497,12 +520,22 @@ export default {
sizeItems(toContainer.frames, frame); sizeItems(toContainer.frames, frame);
this.persist(); this.persist();
}, },
createFrame(containerIndex, insertFrameIndex, objectIdentifier) { setFrameLocation(containerIndex, insertFrameIndex) {
let frame = new Frame(objectIdentifier); this.newFrameLocation = [containerIndex, insertFrameIndex];
let container = this.containers[containerIndex]; },
container.frames.splice(insertFrameIndex + 1, 0, frame); addFrame(domainObject) {
sizeItems(container.frames, frame); if (this.newFrameLocation.length) {
this.persist(); let containerIndex = this.newFrameLocation[0],
frameIndex = this.newFrameLocation[1],
frame = new Frame(domainObject.identifier),
container = this.containers[containerIndex];
container.frames.splice(frameIndex + 1, 0, frame);
sizeItems(container.frames, frame);
this.newFrameLocation = [];
this.persist(containerIndex);
}
}, },
deleteFrame(frameId) { deleteFrame(frameId) {
let container = this.containers let container = this.containers
@ -584,13 +617,33 @@ export default {
} else { } else {
this.containers.splice(toIndex, 0, container); this.containers.splice(toIndex, 0, container);
} }
this.persist(index);
},
removeChildObject(identifier) {
let removeIdentifier = this.openmct.objects.makeKeyString(identifier);
this.containers.forEach(container => {
container.frames = container.frames.filter(frame => {
let frameIdentifier = this.openmct.objects.makeKeyString(frame.domainObjectIdentifier);
return removeIdentifier !== frameIdentifier;
});
});
this.persist(); this.persist();
} }
}, },
mounted() { mounted() {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('remove', this.removeChildObject);
this.composition.on('add', this.addFrame);
this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject); this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
}, },
beforeDestroy() { beforeDestroy() {
this.composition.off('remove', this.removeChildObject);
this.composition.off('add', this.addFrame);
this.unobserve(); this.unobserve();
} }
} }

View File

@ -73,7 +73,6 @@ export default {
}, },
methods: { methods: {
setDomainObject(object) { setDomainObject(object) {
console.log('setting object!');
this.domainObject = object; this.domainObject = object;
this.objectPath = [object]; this.objectPath = [object];
this.setSelection(); this.setSelection();
@ -89,6 +88,18 @@ export default {
this.unsubscribeSelection = this.openmct.selection.selectable(this.$refs.frame, context, false); this.unsubscribeSelection = this.openmct.selection.selectable(this.$refs.frame, context, false);
}, },
initDrag(event) { initDrag(event) {
let type = this.openmct.types.get(this.domainObject.type),
iconClass = type.definition ? type.definition.cssClass : 'icon-object-unknown';
if (this.dragGhost) {
let originalClassName = this.dragGhost.classList[0];
this.dragGhost.className = '';
this.dragGhost.classList.add(originalClassName, iconClass);
this.dragGhost.innerHTML = `<span>${this.domainObject.name}</span>`;
event.dataTransfer.setDragImage(this.dragGhost, 0, 0);
}
event.dataTransfer.setData('frameid', this.frame.id); event.dataTransfer.setData('frameid', this.frame.id);
event.dataTransfer.setData('containerIndex', this.containerIndex); event.dataTransfer.setData('containerIndex', this.containerIndex);
} }
@ -99,6 +110,8 @@ export default {
this.setDomainObject(object); this.setDomainObject(object);
}); });
} }
this.dragGhost = document.getElementById('js-fl-drag-ghost');
}, },
beforeDestroy() { beforeDestroy() {
if (this.unsubscribeSelection) { if (this.unsubscribeSelection) {

View File

@ -151,7 +151,7 @@ function ToolbarProvider(openmct) {
let prompt = openmct.overlays.dialog({ let prompt = openmct.overlays.dialog({
iconClass: 'alert', iconClass: 'alert',
message: `This action will permanently delete container ${containerIndex + 1} from this Flexible Layout`, message: 'This action will permanently delete this container from this Flexible Layout',
buttons: [ buttons: [
{ {
label: 'Ok', label: 'Ok',

View File

@ -14,7 +14,7 @@
</div> </div>
<div class="hide-menu hidden"> <div class="hide-menu hidden">
<div class="menu-element context-menu-wrapper mobile-disable-select"> <div class="menu-element context-menu-wrapper mobile-disable-select">
<div class="menu context-menu"> <div class="c-menu">
<ul> <ul>
<li v-for="action in actions" <li v-for="action in actions"
:key="action.name" :key="action.name"

View File

@ -254,13 +254,14 @@ function (
// Remove the context menu // Remove the context menu
function dismiss() { function dismiss() {
container.find('.hide-menu').append(menu); container.find('.hide-menu').append(menu);
body.off(initiatingEvent, dismiss); body.off(initiatingEvent, menuClickHandler);
menu.off(initiatingEvent, menuClickHandler);
dismissExistingMenu = undefined; dismissExistingMenu = undefined;
} }
function menuClickHandler(e) { function menuClickHandler(e) {
e.stopPropagation(); window.setTimeout(() => {
dismiss();
}, 100);
} }
// Dismiss any menu which was already showing // Dismiss any menu which was already showing
@ -276,11 +277,7 @@ function (
marginY: -50 marginY: -50
}); });
// Stop propagation so that clicks or touches on the menu do not close the menu body.on(initiatingEvent, menuClickHandler);
menu.on(initiatingEvent, menuClickHandler);
body.on(initiatingEvent, dismiss);
}; };
EmbedController.prototype.exposedData = function () { EmbedController.prototype.exposedData = function () {

View File

@ -8,7 +8,9 @@
:class="type.cssClass"> :class="type.cssClass">
<span <span
class="l-browse-bar__object-name c-input-inline" class="l-browse-bar__object-name c-input-inline"
v-on:blur="updateName" @blur="updateName"
@keydown.enter.prevent
@keyup.enter.prevent="updateNameOnEnterKeyPress"
contenteditable> contenteditable>
{{ domainObject.name }} {{ domainObject.name }}
</span> </span>
@ -60,17 +62,20 @@ const PLACEHOLDER_OBJECT = {};
export default { export default {
inject: ['openmct'], inject: ['openmct'],
methods: { methods: {
toggleViewMenu: function (event) { toggleViewMenu(event) {
event.stopPropagation(); event.stopPropagation();
this.showViewMenu = !this.showViewMenu; this.showViewMenu = !this.showViewMenu;
}, },
updateName: function (event) { updateName(event) {
// TODO: handle isssues with contenteditable text escaping. // TODO: handle isssues with contenteditable text escaping.
if (event.target.innerText !== this.domainObject.name) { if (event.target.innerText !== this.domainObject.name) {
this.openmct.objects.mutate(this.domainObject, 'name', event.target.innerText); this.openmct.objects.mutate(this.domainObject, 'name', event.target.innerText);
} }
}, },
setView: function (view) { updateNameOnEnterKeyPress (event) {
event.target.blur();
},
setView(view) {
this.viewKey = view.key; this.viewKey = view.key;
this.openmct.router.updateParams({ this.openmct.router.updateParams({
view: this.viewKey view: this.viewKey

View File

@ -338,7 +338,7 @@
} }
}, },
openInNewTab(event) { openInNewTab(event) {
event.target.href = window.location.href; window.open(window.location.href);
} }
} }
} }

View File

@ -183,6 +183,12 @@
+ .l-pane { + .l-pane {
@include userSelectNone(); @include userSelectNone();
} }
.l-pane {
&__handle {
background: $colorSplitterHover;
}
}
} }
&[class*="--collapsed"] { &[class*="--collapsed"] {
@ -368,12 +374,12 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
label: String, label: String
resizing: Boolean
}, },
data() { data() {
return { return {
collapsed: false collapsed: false,
resizing: false
} }
}, },
beforeMount() { beforeMount() {