Commit 43a2ce1b authored by Anton's avatar Anton
Browse files

Update mosys grid editor and cells for new data model

parent ece4fedb
<template lang="pug"> <template lang="pug">
.cell-item-inner(:class="{'display-preview': preview, 'display-full': display}") .cell-item-inner(:class="{'display-preview': preview, 'display-full': display}")
template(v-if="cellTypeName") template(v-if="cell")
component( component(
:is="cellTypeName", :is="cell.component",
:cell="cell", :cell="cell",
:class="cellClasses", :class="cellClasses",
:display="display", :display="display",
...@@ -21,21 +21,19 @@ ...@@ -21,21 +21,19 @@
import cellTypes from './cells' import cellTypes from './cells'
export default { export default {
props: ['cell', 'display', 'preview', 'annotation'], props: ['annotation', 'display', 'preview'],
data () { data () {
return { return {
cell: undefined,
selected: false, selected: false,
inViewPort: false inViewPort: false
} }
}, },
computed: { computed: {
cellTypeName () {
return this.cell.type ? this.cellTypeToClassName(this.cell.type) : ''
},
cellClasses () { cellClasses () {
let classes = ['cell-content'] let classes = ['cell-content']
if (this.cell) { if (this.cell) {
if (this.cell.type) classes.push(`cell-type-${this.cell.type.toLowerCase()}`) if (this.cell.component) classes.push(`cell-type-${this.cell.component.toLowerCase()}`)
if (this.cell.styleClass) { if (this.cell.styleClass) {
classes = classes.concat(this.cell.styleClass.split(' ')) classes = classes.concat(this.cell.styleClass.split(' '))
} }
...@@ -43,17 +41,23 @@ ...@@ -43,17 +41,23 @@
return classes return classes
} }
}, },
mounted () { watch: {
async annotation (val) {
if (val) await this.getCell()
}
},
async mounted () {
this.onScroll() this.onScroll()
this.$parent.$el.addEventListener('scroll', this.onScroll, false) this.$parent.$el.addEventListener('scroll', this.onScroll, false)
if (this.cellTypeName && cellTypes.hasOwnProperty(this.cellTypeName) === false) { if (this.annotation) await this.getCell()
throw new Error('This cell type is missing: ' + this.cell.type)
}
}, },
beforeDestroy () { beforeDestroy () {
this.$parent.$el.removeEventListener('scroll', this.onScroll) this.$parent.$el.removeEventListener('scroll', this.onScroll)
}, },
methods: { methods: {
async getCell () {
this.cell = await this.$store.dispatch('cells/get', this.annotation.body.source.id)
},
onScroll () { onScroll () {
const const
bounds = this.$el.getBoundingClientRect(), bounds = this.$el.getBoundingClientRect(),
...@@ -61,9 +65,6 @@ ...@@ -61,9 +65,6 @@
this.inViewPort = (bounds.left >= 0 && bounds.left <= boundsParent.width) || this.inViewPort = (bounds.left >= 0 && bounds.left <= boundsParent.width) ||
(bounds.right >= 0 && bounds.right <= boundsParent.width) (bounds.right >= 0 && bounds.right <= boundsParent.width)
}, },
cellTypeToClassName (type) {
return 'Cell' + type.slice(0, 1).toUpperCase() + type.slice(1).replace(/[^a-z0-9]/ig, '')
},
handleClick () { handleClick () {
this.selected = !this.selected this.selected = !this.selected
}, },
......
...@@ -257,12 +257,15 @@ ...@@ -257,12 +257,15 @@
} }
}, },
async updateCellContent (value, cell, path) { async updateCellContent (value, cell, path) {
const destUuid = cell._uuid if (cell.id) {
if (destUuid) { cell.data[path] = value
const annotation = await this.$store.dispatch('annotations/get', destUuid) await this.$store.dispatch('cells/patch', [cell.id, { data: { [path]: value } }])
cell[path] = value }
annotation.body.value = JSON.stringify(cell) },
await this.$store.dispatch('annotations/patch', [destUuid, { body: annotation.body, target: annotation.target }]) async updateCellConfig (value, cell, path) {
if (cell.id) {
cell.config[path] = value
await this.$store.dispatch('cells/patch', [cell.id, { config: { [path]: value } }])
} }
} }
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
div.cell-grid(:style="gridStyle") div.cell-grid(:style="gridStyle")
template(v-for="(cell, index) in cells") template(v-for="(cell, index) in cells")
.cell-item( .cell-item(
:style="getCellStyle(cell)", :style="getAnnotationStyle(cell)",
:title="cell.title") :title="cell.title")
cell(:cell="cell", display="display") cell(:cell="cell", display="display")
...@@ -225,7 +225,7 @@ ...@@ -225,7 +225,7 @@
} }
} }
}, },
getCellStyle (cell) { getAnnotationStyle (cell) {
return { return {
'grid-column-start': cell.x, 'grid-column-start': cell.x,
'grid-column-end': `span ${cell.width}`, 'grid-column-end': `span ${cell.width}`,
......
<
...@@ -21,24 +21,23 @@ ...@@ -21,24 +21,23 @@
template(v-if="!resizingGrid") template(v-if="!resizingGrid")
template(v-for="(cell, index) in cells") template(v-for="(annotation, index) in annotations")
.cell-item( .cell-item(
v-if="cellUIStates[cell._uuid] && !cellUIStates[cell._uuid].beingDragged", v-if="!annotationUIStates[annotation._uuid] || !annotationUIStates[annotation._uuid].beingDragged",
draggable="true", draggable="true",
@dragstart="event => {handleCellDragStart(event, cell)}", @dragstart="event => {handleCellDragStart(event, annotation)}",
@dragend="event => {handleCellDragEnd(event, cell)}", @dragend="event => {handleCellDragEnd(event, annotation)}",
@contextmenu="handleCellContextMenu", @contextmenu="handleCellContextMenu",
:style="getCellStyle(cell)", :style="getAnnotationStyle(annotation)",
:title="cell.title", @click.prevent="event => {handleCellClick(event, annotation)}",
@click.prevent="event => {handleCellClick(event, cell)}", :class="{selected: annotationUIStates[annotation._uuid] ? annotationUIStates[annotation._uuid].selected : false}",
:class="{selected: cellUIStates[cell._uuid] ? cellUIStates[cell._uuid].selected : false}",
:key="`cell-${index}`") :key="`cell-${index}`")
cell(:cell="cell", preview) cell(:annotation="annotation", preview)
div.cell-item-resize-handle( div.cell-item-resize-handle(
draggable="true", draggable="true",
@dragstart="event => {handleCellResizerDragStart(event, cell)}", @dragstart="event => {handleCellResizerDragStart(event, annotation)}",
@dragend="event => {handleCellResizerDragEnd(event, cell)}", @dragend="event => {handleCellResizerDragEnd(event, annotation)}",
@dragexit="event => {handleCellResizerDragEnd(event, cell)}") @dragexit="event => {handleCellResizerDragEnd(event, annotation)}")
q-icon(name="network cell") q-icon(name="network cell")
q-context-menu q-context-menu
...@@ -47,15 +46,15 @@ ...@@ -47,15 +46,15 @@
v-for="action in cellContextMenuActions", v-for="action in cellContextMenuActions",
:key="action.label", :key="action.label",
v-close-overlay, v-close-overlay,
@click.native="event => {action.handler(event, cell)}") @click.native="event => {action.handler(event, annotation)}")
q-item-main(:label="action.label") q-item-main(:label="action.label")
template(v-for="(tmpCell, index) in tmpCells") template(v-for="(tmpCell, index) in tmpCells")
.cell-item.cell-item-tmp(:style="getCellStyle(tmpCell)", :key="`cell-tmp-${index}`") .cell-item.cell-item-tmp(:style="getAnnotationStyle(tmpCell)", :key="`cell-tmp-${index}`")
cell(:cell="tmpCell") cell(:cell="tmpCell")
template(v-else) template(v-else)
.cell-item(:style="getCellStyle({x:0,y:0,width:1,height:1})", key="cell-grid-resizer") .cell-item(:style="getAnnotationStyle({x:0,y:0,width:1,height:1})", key="cell-grid-resizer")
div.cell-item-resize-handle( div.cell-item-resize-handle(
draggable="true", draggable="true",
@dragstart="event => {handleGridResizerDragStart(event)}", @dragstart="event => {handleGridResizerDragStart(event)}",
...@@ -114,10 +113,11 @@ ...@@ -114,10 +113,11 @@
} }
}, },
grid: undefined, grid: undefined,
annotations: undefined,
gridMetadata: {}, gridMetadata: {},
cells: [], cells: [],
tmpCells: [], tmpCells: [],
cellUIStates: {}, annotationUIStates: {},
gridDimensions: { gridWidth: 0, gridHeight: 0, cellWidth: 0, cellHeight: 0 }, gridDimensions: { gridWidth: 0, gridHeight: 0, cellWidth: 0, cellHeight: 0 },
gridStyle: {}, gridStyle: {},
contextMenuClickPosition: {}, contextMenuClickPosition: {},
...@@ -165,7 +165,7 @@ ...@@ -165,7 +165,7 @@
}, },
watch: { watch: {
cells () { cells () {
this.updateCellUIStates() this.updateAnnotationUIStates()
}, },
gridMetadata () { gridMetadata () {
this.updateGridDimensions() this.updateGridDimensions()
...@@ -178,9 +178,22 @@ ...@@ -178,9 +178,22 @@
async fetchData () { async fetchData () {
if (this.gridUuid) { if (this.gridUuid) {
this.grid = await this.$store.dispatch('maps/get', this.gridUuid) this.grid = await this.$store.dispatch('maps/get', this.gridUuid)
await this.fetchMetadataAnnotations() if (!Object.keys(this.grid.config).length) {
this.grid.config = {
columns: 10,
rows: 6,
ratio: 16 / 9.0
}
console.log('conf', this.grid.config)
await this.updateGridMetadataStore()
}
this.updateGridDimensions() this.updateGridDimensions()
await this.fetchCellAnnotations() const { items } = await this.$store.dispatch('annotations/find', {
'target.id': this.grid.id,
'body.purpose': 'linking',
'body.type': 'Cell'
})
this.annotations = items
} }
}, },
handleGridResizerDragStart (event) { handleGridResizerDragStart (event) {
...@@ -189,28 +202,31 @@ ...@@ -189,28 +202,31 @@
async handleGridResizerDragEnd () { async handleGridResizerDragEnd () {
await this.updateGridMetadataStore() await this.updateGridMetadataStore()
}, },
handleCellResizerDragStart (event, cell) { handleCellResizerDragStart (event, annotation) {
event.dataTransfer.setDragImage(nullImage, 0, 0) event.dataTransfer.setDragImage(nullImage, 0, 0)
this.cellUIStates[cell._uuid].beingResized = true this.annotationUIStates[annotation._uuid].beingResized = true
let tmpCell = this.getTmpCell(cell) let tmpCell = this.getTmpCell(annotation)
this.tmpCells.push(tmpCell) this.tmpCells.push(tmpCell)
}, },
handleCellResizerDragEnd (event, cell) { async handleCellResizerDragEnd (event, annotation) {
let position = this.getGridPositionForEvent(event) let position = this.getGridPositionForEvent(event)
cell.width = Math.max(1, 1 + position.x - cell.x) let
cell.height = Math.max(1, 1 + position.y - cell.y) parsed = annotation.target.selector.parse(),
this.cellUIStates[cell._uuid].beingResized = false [x, y, w, h] = parsed.xywh
w = Math.max(1, 1 + position.x - x)
h = Math.max(1, 1 + position.y - y)
const value = { xywh: [x, y, w, h] }
annotation.target.selector.value = value
this.annotationUIStates[annotation._uuid].beingResized = false
this.tmpCells = [] this.tmpCells = []
this.updateCellStore(cell) await this.$store.dispatch('annotations/patch', [annotation.id, { target: { selector: { value } } }])
}, },
handleCellClick (event, cell) { handleCellClick (event, cell) {
this.cellUIStates[cell._uuid].selected = !this.cellUIStates[cell._uuid].selected this.annotationUIStates[cell._uuid].selected = !this.annotationUIStates[cell._uuid].selected
this.updateSelectedCells() this.updateSelectedCells()
}, },
handleCellDragStart (event, cell) { handleCellDragStart (event, cell) {
if (this.cellUIStates[cell._uuid].beingResized) { if (!this.annotationUIStates[cell._uuid].beingResized) {
}
else {
event.dataTransfer.setData('text/plain', JSON.stringify(cell)) event.dataTransfer.setData('text/plain', JSON.stringify(cell))
event.dataTransfer.setDragImage(nullImage, 0, 0) event.dataTransfer.setDragImage(nullImage, 0, 0)
let elContainerBoundingBox = this.$el.getBoundingClientRect() let elContainerBoundingBox = this.$el.getBoundingClientRect()
...@@ -219,14 +235,14 @@ ...@@ -219,14 +235,14 @@
x: (event.clientX - elContainerBoundingBox.x) - (elBoundingBox.x - elContainerBoundingBox.x), x: (event.clientX - elContainerBoundingBox.x) - (elBoundingBox.x - elContainerBoundingBox.x),
y: (event.clientY - elContainerBoundingBox.y) - (elBoundingBox.y - elContainerBoundingBox.y) y: (event.clientY - elContainerBoundingBox.y) - (elBoundingBox.y - elContainerBoundingBox.y)
} }
this.cellUIStates[cell._uuid].draggingOffset = offset this.annotationUIStates[cell._uuid].draggingOffset = offset
this.cellUIStates[cell._uuid].beginDragged = true this.annotationUIStates[cell._uuid].beginDragged = true
} }
let tmpCell = this.getTmpCell(cell) let tmpCell = this.getTmpCell(cell)
this.tmpCells.push(tmpCell) this.tmpCells.push(tmpCell)
}, },
handleCellDragEnd (event, cell) { handleCellDragEnd (event, cell) {
this.cellUIStates[cell._uuid].beingDragged = false this.annotationUIStates[cell._uuid].beingDragged = false
}, },
// handleCellContextMenuClick () { // handleCellContextMenuClick () {
// }, // },
...@@ -235,7 +251,7 @@ ...@@ -235,7 +251,7 @@
// // this.$store.commit('mosys/setSourcesTab', 'tab-default-cells') // // this.$store.commit('mosys/setSourcesTab', 'tab-default-cells')
// }, // },
async handleCellContextMenuDelete (event, cell) { async handleCellContextMenuDelete (event, cell) {
this.cellUIStates[cell._uuid].selected = false this.annotationUIStates[cell._uuid].selected = false
this.updateSelectedCells() this.updateSelectedCells()
this.cells = this.cells.filter(c => c !== cell) this.cells = this.cells.filter(c => c !== cell)
await this.$store.dispatch('annotations/delete', cell._uuid) await this.$store.dispatch('annotations/delete', cell._uuid)
...@@ -264,65 +280,87 @@ ...@@ -264,65 +280,87 @@
} }
catch (e) { /* dialog canceled */ } catch (e) { /* dialog canceled */ }
}, },
handleGridDragOver (event) { async handleGridDragOver (event) {
let _this = this let _this = this
if (this.resizingGrid) { if (this.resizingGrid) {
const position = this.getGridPositionForEvent(event) const position = this.getGridPositionForEvent(event)
this.gridMetadata.ratio = position.ox / (position.oy * 1.0) this.grid.config.ratio = position.ox / (position.oy * 1.0)
this.updateGridDimensions() await this.updateGridMetadataStore()
} }
else { else {
let cell = Object.keys(this.cellUIStates).filter(uuid => { let annotation = this.annotations.filter(annotation => {
return _this.cellUIStates[uuid].beginDragged || _this.cellUIStates[uuid].beingResized if (!_this.annotationUIStates[annotation._uuid]) return false
}).map(uuid => { return _this.annotationUIStates[annotation._uuid].beginDragged ||
return _this.cellUIStates[uuid].cell _this.annotationUIStates[annotation._uuid].beingResized
}).shift() }).shift()
let offset, position let offset, position
if (!cell) { if (!annotation) {
cell = { uuid: null, x: 1, y: 1, width: 1, height: 1 } annotation = {
target: this.grid.get2DArea([1, 1], [1, 1])
}
position = this.getGridPositionForEvent(event) position = this.getGridPositionForEvent(event)
} }
else { else {
offset = this.cellUIStates[cell._uuid].draggingOffset offset = this.annotationUIStates[annotation._uuid].draggingOffset
position = this.getGridPositionForEvent(event, offset) position = this.getGridPositionForEvent(event, offset)
} }
if (!this.tmpCells.length) this.tmpCells.push(annotation)
let tmpCell = this.tmpCells[0] let tmpCell = this.tmpCells[0]
if (!tmpCell && this.tmpCells.length === 0) { const parsed = tmpCell.target.selector.parse()
tmpCell = this.getTmpCell(cell)
this.tmpCells.push(tmpCell)
}
if (event.dataTransfer.types.includes('text/plain')) { if (event.dataTransfer.types.includes('text/plain')) {
tmpCell.x = position.x tmpCell.target.selector.value = { xywh: [position.x, position.y] }
tmpCell.y = position.y parsed.xywh[0] = position.x
parsed.xywh[1] = position.y
event.preventDefault() event.preventDefault()
} }
else { else {
tmpCell.width = Math.max(1, 1 + position.x - tmpCell.x) parsed.xywh[2] = Math.max(1, 1 + position.x - tmpCell.x)
tmpCell.height = Math.max(1, 1 + position.y - tmpCell.y) parsed.xywh[3] = Math.max(1, 1 + position.y - tmpCell.y)
} }
tmpCell.target.selector.value = parsed
} }
}, },
handleGridDragEnd () { handleGridDragEnd () {
this.tmpCells = [] this.tmpCells = []
}, },
handleGridDrop (event) { async handleGridDrop (event) {
let cellDropped = event.dataTransfer.getData('text/plain') let dropData = event.dataTransfer.getData('text/plain')
if (cellDropped) { if (dropData) {
cellDropped = JSON.parse(cellDropped) dropData = JSON.parse(dropData)
let cell = this.cells.find(c => c._uuid === cellDropped._uuid) let annotation = this.cells.find(c => c.id === dropData.id)
let offset, position const { x, y } = this.getGridPositionForEvent(
if (cell) { event,
offset = this.cellUIStates[cell._uuid].draggingOffset annotation ? this.annotationUIStates[annotation._uuid].draggingOffset : undefined
position = this.getGridPositionForEvent(event, offset) )
const target = this.grid.get2DArea([x, y], [1, 1])
if (annotation) {
annotation.target.selector.value = target.selector.value
await this.$store.dispatch('annotations/patch', [annotation.id, {
target: {
selector: { value: target.selector.value }
}
}])
console.debug('dropped existing annotation', annotation)
} }
else { else {
cell = cellDropped const
position = this.getGridPositionForEvent(event) { data, config, component } = dropData,
cell = await this.$store.dispatch('cells/post', { data, config, component })
annotation = await this.$store.dispatch('annotations/post', {
body: {
type: 'Cell',
purpose: 'linking',
source: {
id: cell.id
}
},
target
})
console.debug('dropped new cell', cell, annotation)
} }
cell.x = position.x
cell.y = position.y
this.tmpCells = [] this.tmpCells = []
this.updateCellStore(cell) // this.updateCellStore(cell)
event.preventDefault() event.preventDefault()
} }
}, },
...@@ -404,23 +442,23 @@ ...@@ -404,23 +442,23 @@
}, },
updateSelectedCells () { updateSelectedCells () {
const _this = this const _this = this
let selectedCells = Object.keys(this.cellUIStates).filter(k => { let selectedCells = Object.keys(this.annotationUIStates).filter(k => {
return _this.cellUIStates[k].selected return _this.annotationUIStates[k].selected
}).map(k => { }).map(k => {
return _this.cells.find(c => c._uuid === k) return _this.cells.find(c => c._uuid === k)
}) })
this.$store.commit('mosys/setSelectedCells', selectedCells) this.$store.commit('mosys/setSelectedCells', selectedCells)
}, },
updateCellUIStates () { updateAnnotationUIStates () {
let newCellUIStates = {} let newAnnotationUIStates = {}
this.cells.map(c => { this.annotations.map(a => {
newCellUIStates[c._uuid] = { newAnnotationUIStates[a._uuid] = {
selected: false, selected: false,
beingResized: false, beingResized: false,
cell: c annotation: a
} }
}) })
this.cellUIStates = newCellUIStates this.annotationUIStates = newAnnotationUIStates
this.updateSelectedCells() this.updateSelectedCells()
}, },
getTmpCell (cell, type = 'UIFeedback') { getTmpCell (cell, type = 'UIFeedback') {
...@@ -445,13 +483,13 @@ ...@@ -445,13 +483,13 @@
updateGridDimensions () { updateGridDimensions () {
let elWidth = this.$el.offsetWidth let elWidth = this.$el.offsetWidth
let elHeight = this.$el.offsetHeight let elHeight = this.$el.offsetHeight
let cellSizeRatio = this.gridMetadata.ratio let cellSizeRatio = this.grid.config.ratio
let gridHeight = elHeight let gridHeight = elHeight
let cellHeight = gridHeight / this.gridMetadata.rows let cellHeight = gridHeight / this.grid.config.rows
let cellWidth = elWidth / Math.round(elWidth / (cellHeight * cellSizeRatio)) let cellWidth = elWidth / Math.round(elWidth / (cellHeight * cellSizeRatio))
let gridWidth = cellWidth * this.gridMetadata.columns let gridWidth = cellWidth * this.grid.config.columns
let cellsPerWidth = elWidth / cellWidth let cellsPerWidth = elWidth / cellWidth
let cellWidthMini = elWidth / this.gridMetadata.columns let cellWidthMini = elWidth / this.grid.config.columns
let gridHeightMini = cellWidthMini / cellSizeRatio let gridHeightMini = cellWidthMini / cellSizeRatio
this.gridDimensions = { this.gridDimensions = {
full: { full: {