mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-19 16:02:15 +00:00
fix(Dashboard Mobile Touch Events): fixes the behaviour of the touch event for the dashboard grid
This commit is contained in:
@@ -77,3 +77,11 @@
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.dragged-widget-icon{
|
||||
position: absolute;
|
||||
height: 250px;
|
||||
width: 200px;
|
||||
top: -999px;
|
||||
left: -999px;
|
||||
z-index: 3;
|
||||
}
|
||||
@@ -34,6 +34,7 @@ export default {
|
||||
provide() {
|
||||
return {
|
||||
editMode: Vue.computed(()=>this.editMode),
|
||||
widgetsSetup: Vue.computed(() => this.widgets),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -142,6 +143,19 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
axios.get(this.apiurl + '/Widget/getWidgetsForDashboard', {
|
||||
params: {
|
||||
db: this.dashboard
|
||||
}
|
||||
}).then(res => {
|
||||
res.data.retval.forEach(widget => {
|
||||
widget.arguments = JSON.parse(widget.arguments);
|
||||
widget.setup = JSON.parse(widget.setup);
|
||||
});
|
||||
this.widgets = res.data.retval;
|
||||
}).catch(err => console.error('ERROR:', err));
|
||||
|
||||
axios.get(this.apiurl + '/Config', {params:{
|
||||
db: this.dashboard
|
||||
}}).then(res => {
|
||||
|
||||
@@ -49,18 +49,23 @@ export default {
|
||||
return 'margin-bottom: 8px;';
|
||||
},
|
||||
items() {
|
||||
|
||||
const computeNearestPlace = (item, gridWidth) =>{
|
||||
let place;
|
||||
if (Object.keys(item.place).length > 0) {
|
||||
const nearestIndex = Object.keys(item.place)
|
||||
.sort((a, b) => Math.abs(a - gridWidth) - Math.abs(b - gridWidth))
|
||||
.pop();
|
||||
place = item.place[nearestIndex];
|
||||
}
|
||||
else{
|
||||
place = { x: 0, y: 0, w: 1, h: 1 };
|
||||
}
|
||||
return place;
|
||||
}
|
||||
|
||||
return this.widgets.map(item => {
|
||||
let place;
|
||||
if(!item.place[this.gridWidth]){
|
||||
const nearestIndex = Object.keys(item.place).sort((a,b)=>Math.abs(a-this.gridWidth)-Math.abs(b-this.gridWidth)).pop();
|
||||
if (nearestIndex === null){
|
||||
place = {x:0,y:0,w:1,h:1};
|
||||
}else{
|
||||
place = item.place[nearestIndex];
|
||||
}
|
||||
}
|
||||
return { ...item, ...(item.place[this.gridWidth] || place)};
|
||||
return { ...item, ...(item.place[this.gridWidth] || computeNearestPlace(item, this.gridWidth))};
|
||||
});
|
||||
},
|
||||
items_hashmap() {
|
||||
@@ -73,10 +78,6 @@ export default {
|
||||
items_placeholders(){
|
||||
let placeholders = [];
|
||||
let col_max = this.gridWidth;
|
||||
// OLD way of calculating the max rows
|
||||
//let max_row = Math.max(...this.items.map(item => item.y)) + 1;
|
||||
//let max_row_max_height = Math.max(...this.items.filter(item => item.y == (max_row - 1)).map(item => item.h));
|
||||
//max_row + max_row_max_height - 1;
|
||||
let rows_max = this.gridHeight;
|
||||
|
||||
// occupied hashmap to keep track of the occupied cells
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import BsModal from "../../Bootstrap/Modal.js";
|
||||
import WidgetIcon from "./WidgetIcon.js";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BsModal
|
||||
BsModal,
|
||||
WidgetIcon,
|
||||
},
|
||||
props: [
|
||||
"widgets"
|
||||
@@ -28,11 +30,7 @@ export default {
|
||||
this.callbacks = {};
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
path(src) {
|
||||
if (src[0] == '/')
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + src;
|
||||
return src;
|
||||
}
|
||||
|
||||
},
|
||||
template: `<div class="dashboard-widget-picker">
|
||||
<bs-modal ref="modal" class="fade" :dialog-class="{'modal-fullscreen-sm-down': 1, 'modal-xl': widgets && widgets.length > 0}" @hiddenBsModal="close">
|
||||
@@ -43,13 +41,7 @@ export default {
|
||||
No Widgets available
|
||||
</div>
|
||||
<div v-for="widget in widgets" :key="widget.widget_id" class="col-sm-6 col-md-4 col-lg-3 col-xl-2">
|
||||
<div class="card h-100" @click="pick(widget.widget_id)">
|
||||
<img class="card-img-top" :src="path(widget.setup.icon)" :alt="'pictogram for ' + (widget.setup.name || widget.widget_kurzbz)">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ widget.setup.name || widget.widget_kurzbz }}</h5>
|
||||
<p class="card-text">{{ widget.beschreibung }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<widget-icon @select="pick" :widget="widget" ></widget-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="text-center"><i class="fa-solid fa-spinner fa-pulse fa-3x"></i></div>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
props:{
|
||||
widget:{
|
||||
type:Object,
|
||||
required:true,
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
path(src) {
|
||||
if (src[0] == '/')
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + src;
|
||||
return src;
|
||||
}
|
||||
},
|
||||
emits:["select"],
|
||||
template: /*html */`
|
||||
<div class="card h-100" @click="$emit('select',widget.widget_id); pick(widget.widget_id)">
|
||||
<img class="card-img-top" :src="path(widget.setup.icon)" :alt="'pictogram for ' + (widget.setup.name || widget.widget_kurzbz)">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ widget.setup.name || widget.widget_kurzbz }}</h5>
|
||||
<p class="card-text">{{ widget.beschreibung }}</p>
|
||||
</div>
|
||||
</div>`,
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import GridItem from './Grid/Item.js';
|
||||
import GridLogic from '../../composables/GridLogic.js';
|
||||
import WidgetIcon from '../Dashboard/Widget/WidgetIcon.js';
|
||||
|
||||
const MODE_IDLE = 0;
|
||||
const MODE_MOVE = 1;
|
||||
@@ -10,10 +11,10 @@ const MODE_RESIZE = 2;
|
||||
export default {
|
||||
name: 'Grid',
|
||||
components: {
|
||||
GridItem
|
||||
},
|
||||
inject: {
|
||||
GridItem,
|
||||
WidgetIcon,
|
||||
},
|
||||
inject: ["widgetsSetup"],
|
||||
props: {
|
||||
cols: Number,
|
||||
items: Array,
|
||||
@@ -50,6 +51,7 @@ export default {
|
||||
fixedPositionUpdates: null,
|
||||
draggedOffset: [0,0],
|
||||
draggedItem: null,
|
||||
draggedItemIcon: null,
|
||||
additionalRow: null,
|
||||
}
|
||||
},
|
||||
@@ -125,7 +127,15 @@ export default {
|
||||
if (!this.active || !this.grid || this.mode != MODE_IDLE || this.x < 0 || this.y < 0 || this.x >= this.cols || this.y >= this.rows)
|
||||
return false;
|
||||
return this.grid.isFreeSlot(this.x, this.y);
|
||||
}
|
||||
},
|
||||
widgetSetup(){
|
||||
if (!this.widgetsSetup)
|
||||
return;
|
||||
return this.widgetsSetup.reduce((acc, ele) => {
|
||||
acc[ele.widget_id] =ele;
|
||||
return acc;
|
||||
} ,{});
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
active(active) {
|
||||
@@ -157,6 +167,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
toggleDraggedItemOverlay(condition){
|
||||
if(!this.draggedItem)
|
||||
return;
|
||||
let draggedItemNode = document.getElementById(this.draggedItem.data.id);
|
||||
if(condition){
|
||||
draggedItemNode.classList.add("dashboard-item-overlay");
|
||||
@@ -165,13 +177,11 @@ export default {
|
||||
}
|
||||
},
|
||||
dragging(event){
|
||||
if(this.mode == MODE_MOVE)
|
||||
if(this.mode == MODE_MOVE){
|
||||
this.toggleDraggedItemOverlay(true);
|
||||
/* use case: instead of showing the ghost widget when dragging,
|
||||
change the x and y position of the widget when dragging to drag the whole widget
|
||||
event.target.style.top = `${this.clientY}px`;
|
||||
event.target.style.left = `${this.clientX}px`;
|
||||
*/
|
||||
this.draggedItemIcon.style.top = `${this.clientY}px`;
|
||||
this.draggedItemIcon.style.left = `${this.clientX}px`;
|
||||
}
|
||||
},
|
||||
createNewGrid(items) {
|
||||
this.grid = new GridLogic(this.cols);
|
||||
@@ -270,10 +280,9 @@ export default {
|
||||
|
||||
return true;
|
||||
},
|
||||
_dragStart(evt) {
|
||||
_dragStart(evt, item) {
|
||||
if (evt.dataTransfer) {
|
||||
if(this.mode == MODE_RESIZE)
|
||||
evt.dataTransfer.setDragImage(evt.target, -99999, -99999);
|
||||
evt.dataTransfer.setDragImage(evt.target, -99999, -99999);
|
||||
evt.dataTransfer.dropEffect = 'move';
|
||||
evt.dataTransfer.effectAllowed = 'move';
|
||||
}
|
||||
@@ -282,10 +291,11 @@ export default {
|
||||
if (!this.active)
|
||||
return;
|
||||
|
||||
this._dragStart(evt);
|
||||
this.mode = MODE_MOVE;
|
||||
this.draggedItem = item;
|
||||
this.draggedItemIcon = document.getElementById(`widget${this.draggedItem?.data.widget}`);
|
||||
this.draggedOffset = [item.x - this.x, item.y - this.y];
|
||||
this._dragStart(evt, item);
|
||||
},
|
||||
startResize(evt, item) {
|
||||
if (!this.active)
|
||||
@@ -334,14 +344,21 @@ export default {
|
||||
}
|
||||
},
|
||||
dragCancel() {
|
||||
|
||||
this.toggleDraggedItemOverlay(false);
|
||||
this.mode = MODE_IDLE;
|
||||
this.positionUpdates = null;
|
||||
this.draggedOffset = [0,0],
|
||||
this.draggedItem = null;
|
||||
|
||||
if(this.draggedItemIcon){
|
||||
this.draggedItemIcon.style.top = '-999px';
|
||||
this.draggedItemIcon.style.left = '-999px';
|
||||
this.draggedItemIcon = null;
|
||||
}
|
||||
|
||||
},
|
||||
dragEnd() {
|
||||
if(this.mode == MODE_MOVE)
|
||||
this.toggleDraggedItemOverlay(false);
|
||||
if (this.mode == MODE_IDLE)
|
||||
return;
|
||||
if (!this.active || this.x < 0 || this.y < 0 || this.x >= this.cols)
|
||||
@@ -388,6 +405,11 @@ export default {
|
||||
@mousemove="updateCursorOnMouseMove"
|
||||
@mouseleave="mouseLeave">
|
||||
<TransitionGroup tag="div">
|
||||
<template v-for="(item,index) in placedItems">
|
||||
<div class="dragged-widget-icon" :id="'widget'+item.data.widget" >
|
||||
<widget-icon v-if="widgetsSetup" :widget="widgetSetup[item.data.widget]"></widget-icon>
|
||||
</div>
|
||||
</template>
|
||||
<grid-item
|
||||
v-for="(item,index) in (mode == 0 && active ? placedItems_withPlaceholders : placedItems)"
|
||||
:key="item.data.id"
|
||||
@@ -397,6 +419,7 @@ export default {
|
||||
@dragging="dragging"
|
||||
@end-drag="dragCancel"
|
||||
@drop-drag="dragEnd"
|
||||
@touchEvent="updateCursorOnMouseMove"
|
||||
class="position-absolute"
|
||||
:active="active"
|
||||
:style="{
|
||||
|
||||
@@ -13,7 +13,8 @@ export default {
|
||||
"dragging",
|
||||
"endDrag",
|
||||
"dropDrag",
|
||||
"item"
|
||||
"item",
|
||||
"touchEvent"
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
@@ -54,20 +55,20 @@ export default {
|
||||
this.dragging = false;
|
||||
this.$emit('dropDrag', evt);
|
||||
},
|
||||
test(evt) {
|
||||
let dragAction = this.dragAction || evt.target.getAttribute('drag-action');
|
||||
if (dragAction) {
|
||||
this.dragging = true;
|
||||
}
|
||||
touchStart(event){
|
||||
this.$emit('touchEvent', event);
|
||||
this.registerDragAction(event);
|
||||
this.tryDragStart(event, this.item);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="drop-grid-item"
|
||||
@mousedown="registerDragAction"
|
||||
@touchstart.prevent="tryDragStart($event, item)"
|
||||
@touchstart.prevent="touchStart"
|
||||
@touchend="touchDragEnd"
|
||||
@dragstart="tryDragStart($event, item)"
|
||||
@drag="$emit('dragging',$event)"
|
||||
@touchmove="$emit('dragging',$event)"
|
||||
@dragend="$emit('endDrag', $event)"
|
||||
:draggable="active && !item.placeholder && dragAction != ''">
|
||||
<slot v-bind="item"></slot>
|
||||
|
||||
Reference in New Issue
Block a user