Flexible Layout (#2201)
* first cut of flexible layout * better drag handling * add drop targets to every row * enable drag and drop between columns and rows * enable persistance * add editing capability * chage rows to frames and columns to containers, switch draggable to whole frame object * Merge latest, resolve conflicts. Need to just apply these changes to Deep's branch and push * enhancements to drag targets * WIP in flexibleLayout, container.vue files - Refined classes and markup; - min-width changed to flex-basis; - Added toggle direction button; * Significant progress but still WIP - Refined classes and markup; - Layout toggling working; - Add Container working properly; - TODOs: fix sizing in empty container, fix bordering, more refinements; * add resizing of frames - still wip * Significant enhancements - Moved all CSS into flexibleLayout.vue; - Layout now improved for empty container and drop hints; - Proportional sizing now better for frames and containers; * Resize handle WIP * abstract splitter and logic into self contained component that will emit an event when mouse is moving * Resize handle WIP - Minor tweak to handle padding and hover; * add container resize todo persist * persist container resize * add frame header, fix column resize on last column * Refinements to resize-handle - Fixed sizing; - Transition on hover; - TODOs: needs is-dragging to maintain hover style while dragging; * fix drop hints showing after drop * move header * improve mouse move gesture * Added frame size indicator * add snapto functionality * Refined container and frame size indicators - Also added overflow handling to l-grid-view * improve resizing logic * add selection on frames * Various resizing-frames related - Fixed overflow - now frame widths can be collapsed to 5% minimum; - Sizing indicators refined, better positioning and layout; - Added grippy drag indicators to column heads; - TODOs: add column head cursors and hover effects, hide indicators when not in edit mode, handle nested layout and flex layouts while editing * Selecting and emtpy layout messaging - Better empty layout message; - Moved s-selected to proper element in c-fl-frame; * Drop-hint and sizing related various - Drop-hints for first placeholder container now display; - Drop-hints moved into drag-wrapper; * add delete frame * Editing various - Adjust Snow theme constants related to editing; - Changed delete message wording; * Updated icon and added description * add toggle and remove container to toolbar * miscellaneous cleanup * add container button to toolbar * improve toolbar * code cleanup in plugin.js * Various icons, toolbar separator - Copied in c-toolbar__separator and associated changes in _controls from Pegah's layout_alpha branch - may have conflicts later. - Added separator to FL toolbar; - Updated icons for grippy-ew, toolbar icons; * add check for empty containers" * logic to resize frames on drop * fix delete frame and persisting toolbar * Significant changes to edit / selection styling - Both Flexible and fixed Display Layouts addressed; - Both themes addressed; - Changed drop-hint icon to icon-plus; * add correct icons to frame header and fix toolbars showing up in wrong views * Moving and resizing various - Cursors; - Grippy added to frame resize-handle, WIP!; * add container reordering * add frame/no frame support to toolbar' * fix regression of resize handles showing after last frame in container * force selection of flexible-layout when editing is first clicked, to apply correct toolbar * make changes to simplify toolbar * Modified sizing algorithm slightly * make changes reviewer requested * fix regression that causes top drop hint to not show * remove unused variables and bind events to vue * unsub selection before destroy
This commit is contained in:
committed by
Pete Richards
parent
d13d59bfa0
commit
1069a45cfc
214
src/plugins/flexibleLayout/components/container.vue
Normal file
214
src/plugins/flexibleLayout/components/container.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="c-fl-container"
|
||||
:style="[{'flex-basis': size}]"
|
||||
:class="{'is-empty': frames.length === 1}">
|
||||
<div class="c-fl-container__header icon-grippy-ew"
|
||||
v-show="isEditing"
|
||||
draggable="true"
|
||||
@dragstart="startContainerDrag"
|
||||
@dragend="stopContainerDrag">
|
||||
<span class="c-fl-container__size-indicator">{{ size }}</span>
|
||||
</div>
|
||||
<div class="c-fl-container__frames-holder">
|
||||
<div class="u-contents"
|
||||
v-for="(frame, i) in frames"
|
||||
:key="i">
|
||||
|
||||
<frame-component
|
||||
class="c-fl-container__frame"
|
||||
:style="{
|
||||
'flex-basis': `${frame.height}%`
|
||||
}"
|
||||
:frame="frame"
|
||||
:size="frame.height"
|
||||
:index="i"
|
||||
:containerIndex="index"
|
||||
:isEditing="isEditing"
|
||||
:isDragging="isDragging"
|
||||
@frame-drag-from="frameDragFrom"
|
||||
@frame-drop-to="frameDropTo"
|
||||
@delete-frame="promptBeforeDeletingFrame"
|
||||
@add-container="addContainer">
|
||||
</frame-component>
|
||||
|
||||
<resize-handle
|
||||
v-if="i !== 0 && (i !== frames.length - 1)"
|
||||
v-show="isEditing"
|
||||
:index="i"
|
||||
:orientation="rowsLayout ? 'horizontal' : 'vertical'"
|
||||
@init-move="startFrameResizing"
|
||||
@move="frameResizing"
|
||||
@end-move="endFrameResizing">
|
||||
</resize-handle>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FrameComponent from './frame.vue';
|
||||
import Frame from '../utils/frame';
|
||||
import ResizeHandle from './resizeHandle.vue';
|
||||
|
||||
const SNAP_TO_PERCENTAGE = 1;
|
||||
const MIN_FRAME_SIZE = 5;
|
||||
|
||||
export default {
|
||||
inject:['openmct', 'domainObject'],
|
||||
props: ['size', 'frames', 'index', 'isEditing', 'isDragging', 'rowsLayout'],
|
||||
components: {
|
||||
FrameComponent,
|
||||
ResizeHandle
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
initialPos: 0,
|
||||
frameIndex: 0,
|
||||
maxMoveSize: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
frameDragFrom(frameIndex) {
|
||||
this.$emit('frame-drag-from', this.index, frameIndex);
|
||||
},
|
||||
frameDropTo(frameIndex, event) {
|
||||
let domainObject = event.dataTransfer.getData('domainObject'),
|
||||
frameObject;
|
||||
|
||||
if (domainObject) {
|
||||
frameObject = new Frame(JSON.parse(domainObject));
|
||||
}
|
||||
|
||||
this.$emit('frame-drop-to', this.index, frameIndex, frameObject);
|
||||
},
|
||||
startFrameResizing(index) {
|
||||
let beforeFrame = this.frames[index],
|
||||
afterFrame = this.frames[index + 1];
|
||||
|
||||
this.maxMoveSize = beforeFrame.height + afterFrame.height;
|
||||
},
|
||||
frameResizing(index, delta, event) {
|
||||
|
||||
let percentageMoved = (delta / this.getElSize(this.$el))*100,
|
||||
beforeFrame = this.frames[index],
|
||||
afterFrame = this.frames[index + 1];
|
||||
|
||||
beforeFrame.height = this.snapToPercentage(beforeFrame.height + percentageMoved);
|
||||
afterFrame.height = this.snapToPercentage(afterFrame.height - percentageMoved);
|
||||
},
|
||||
endFrameResizing(index, event) {
|
||||
this.persist();
|
||||
},
|
||||
getElSize(el) {
|
||||
if (this.rowsLayout) {
|
||||
return el.offsetWidth;
|
||||
} else {
|
||||
return el.offsetHeight;
|
||||
}
|
||||
},
|
||||
getFrameSize(size) {
|
||||
if (size < MIN_FRAME_SIZE) {
|
||||
return MIN_FRAME_SIZE
|
||||
} else if (size > (this.maxMoveSize - MIN_FRAME_SIZE)) {
|
||||
return (this.maxMoveSize - MIN_FRAME_SIZE);
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
},
|
||||
snapToPercentage(value){
|
||||
let rem = value % SNAP_TO_PERCENTAGE,
|
||||
roundedValue;
|
||||
|
||||
if (rem < 0.5) {
|
||||
roundedValue = Math.floor(value/SNAP_TO_PERCENTAGE)*SNAP_TO_PERCENTAGE;
|
||||
} else {
|
||||
roundedValue = Math.ceil(value/SNAP_TO_PERCENTAGE)*SNAP_TO_PERCENTAGE;
|
||||
}
|
||||
|
||||
return this.getFrameSize(roundedValue);
|
||||
},
|
||||
persist() {
|
||||
this.$emit('persist', this.index);
|
||||
},
|
||||
promptBeforeDeletingFrame(frameIndex) {
|
||||
let deleteFrame = this.deleteFrame;
|
||||
|
||||
let prompt = this.openmct.overlays.dialog({
|
||||
iconClass: 'alert',
|
||||
message: `This action will remove ${this.frames[frameIndex].domainObject.name} from this Flexible Layout. Do you want to continue?`,
|
||||
buttons: [
|
||||
{
|
||||
label: 'Ok',
|
||||
emphasis: 'true',
|
||||
callback: function () {
|
||||
deleteFrame(frameIndex);
|
||||
prompt.dismiss();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: function () {
|
||||
prompt.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
deleteFrame(frameIndex) {
|
||||
this.frames.splice(frameIndex, 1);
|
||||
this.$parent.recalculateOldFrameSize(this.frames);
|
||||
this.persist();
|
||||
},
|
||||
deleteContainer() {
|
||||
this.$emit('delete-container', this.index);
|
||||
},
|
||||
addContainer() {
|
||||
this.$emit('add-container', this.index);
|
||||
},
|
||||
startContainerDrag(event) {
|
||||
event.stopPropagation();
|
||||
this.$emit('start-container-drag', this.index);
|
||||
},
|
||||
stopContainerDrag(event) {
|
||||
event.stopPropagation();
|
||||
this.$emit('stop-container-drag');
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let context = {
|
||||
item: this.domainObject,
|
||||
method: this.deleteContainer,
|
||||
addContainer: this.addContainer,
|
||||
index: this.index,
|
||||
type: 'container'
|
||||
}
|
||||
|
||||
this.unsubscribeSelection = this.openmct.selection.selectable(this.$el, context, false);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.unsubscribeSelection();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user