GridEditor.vue 51.9 KB
Newer Older
Anton's avatar
Intial  
Anton committed
1 2
<template lang="pug">

3
  div.cell-grid-container(
4
  :class="{'overflow-hidden': activeHandler}",
5
  style="overflow-y: hidden; scroll-behavior: smooth;")
christianrhansen's avatar
christianrhansen committed
6

christianrhansen's avatar
christianrhansen committed
7 8 9
    q-window-resize-observable(@resize="updateGridDimensions")

    //----- modal for existing cell editing
10
    q-modal(v-model="modal", minimized, content-css="background-color: #eee; border-radius: .75rem;")
11
      grid-editor-editing-cells-mobile
12

13
    // -----------------------------------------------------------------------------------------------------------------
christianrhansen's avatar
christianrhansen committed
14
    // ----------------------------------------------------------------------------------------------- "new cell"-header
15 16
    #new-cell-header.fixed-top.z-top.bg-dark.text-white.transition(:class="{'show': cachedNewCell}")
      q-item.q-pl-md.q-pr-xs.q-py-none.full-height
17
        q-item-main
18
          strong New {{ newCellType }}
19

christianrhansen's avatar
christianrhansen committed
20 21
        q-item-side.text-white
          q-btn(@click="event => {addMobileCell(event)}", round, flat)
22 23
            q-icon(name="check")

christianrhansen's avatar
christianrhansen committed
24
          q-btn.clear-button.q-px-md.q-mr-md.on-right(@click="clearHandler('cached cell')", flat)
christianrhansen's avatar
christianrhansen committed
25
            q-icon(name="clear")
26

christianrhansen's avatar
christianrhansen committed
27
    // ------------------------------------------------------------------------------------------ "selected cell"-header
28
    #selected-cell-header.fixed-top.z-top.bg-dark.text-white.transition(:class="{'show': showEditingCells}")
29
      q-item.q-pl-md.q-pr-none.q-py-none.full-height(v-if="!modal")
30
        q-item-main
31
          strong {{ selectedCell.type }}
32

christianrhansen's avatar
christianrhansen committed
33 34
        q-item-side.text-white
          q-btn.q-px-sm(@click="event => {handleCellEdit(event, selectedCell.annotation)}", flat)
35 36
            q-icon(name="edit")

christianrhansen's avatar
christianrhansen committed
37 38
          q-btn.q-px-sm.on-right.on-left(
          @click="event => {handleCellContextMenuDelete(event, mobileSelectedCell)}", flat)
39
            q-icon(name="delete")
40

christianrhansen's avatar
christianrhansen committed
41
          q-btn.clear-button.q-px-md.q-mr-md.on-right(@click="clearHandler('cell')", flat)
42 43
            q-icon(name="clear")

44
    // -----------------------------------------------------------------------------------------------------------------
45
    // ------------------------------------------------------------------------------------------------------------ grid
46
    div.cell-grid.relative-position(
47
    v-touch-pan="panGrid",
48 49 50 51 52 53
    @dragenter="handleGridDragOver",
    @dragover="handleGridDragOver",
    @dragleave="handleGridDragEnd",
    @drop="handleGridDrop",
    @contextmenu="handleGridContextMenu",
    :style="gridStyle")
Anton's avatar
Intial  
Anton committed
54

christianrhansen's avatar
christianrhansen committed
55
      //----- context menu grid (desktop only)
56
      q-context-menu.desktop-only(ref="gridmenu")
Anton's avatar
Intial  
Anton committed
57 58
        q-list(link, separator, no-border, style="min-width: 150px; max-height: 300px;")
          q-item(
59 60 61 62 63
          v-for="action in gridContextMenuActions",
          :key="action.label",
          v-close-overlay,
          @click.native="event => {action.handler(event)}")
            q-item-main(:label="action.label")
Anton's avatar
Intial  
Anton committed
64 65 66

      template(v-if="!resizingGrid")

christianrhansen's avatar
christianrhansen committed
67 68
        //--------------------------------------------------------------------------------------------------------------
        //--------------------------------------------------------------------------------------------------------- cell
69
        template(v-for="(annotation, index) in annotations")
70
          // v-touch-hold="event => {cellCopy(event, annotation)}",
Anton's avatar
Intial  
Anton committed
71
          .cell-item(
72 73 74 75 76 77 78 79 80 81
          v-if="!annotationUIStates[annotation._uuid] || !annotationUIStates[annotation._uuid].beingDragged",
          draggable="true",
          @click.prevent="event => {handleCellTouch(event, annotation)}",
          @dragstart="event => {handleCellDragStart(event, annotation)}",
          @dragend="event => {handleCellDragEnd(event, annotation)}",
          @contextmenu="handleCellContextMenu",
          :style="getAnnotationStyle(annotation)",
          :class="getAnnotationClasses(annotation._uuid, 'cell-item')",
          :key="`cell-${index}`")

82
            //-------------------------------------------------------------------------------------------------- desktop
83
            .desktop-only
Mathias Bär's avatar
Mathias Bär committed
84
              q-btn.edit-button.absolute-top-right(
85 86 87
              @click.prevent="event => {handleCellEditClick(event, annotation)}",
              :class="getAnnotationClasses(annotation._uuid, 'editing')",
              style="top: 8px; right: 8px;",
christianrhansen's avatar
christianrhansen committed
88 89
              :icon="annotationUIStates[annotation._uuid].editing ? 'close' : 'edit'", flat, round, size="md")

90
            //--------------------------------------------------------------------------------------------------- mobile
91
            .mobile-only
92
              .edit-button.absolute.fit.bg-transparent(
93
              v-touch-hold="event => {handleCellEdit(event, annotation)}",
94
              @click.prevent="event => {touchMobileCell(event, annotation)}")
95

96
            //----- selecting cells disabled because it has no use currently
97 98 99 100 101
            // switch with cell component below to re-enable it
            //cell(
              @click.native.prevent="event => {handleCellClick(event, annotation)}", :annotation="annotation", :preview="true")
            cell(
            :annotation="annotation",
christianrhansen's avatar
christianrhansen committed
102
            :preview="true")
103

christianrhansen's avatar
christianrhansen committed
104
            //----- resize-handler (desktop only)
105
            .desktop-only.cell-item-resize-handle(
106 107 108 109
            draggable="true",
            @dragstart="event => {handleCellResizerDragStart(event, annotation)}",
            @dragend="event => {handleCellResizerDragEnd(event, annotation)}",
            @dragexit="event => {handleCellResizerDragEnd(event, annotation)}")
110
              q-icon.q-ma-xs(name="network cell")
111

112 113 114
            //----- context menu for cells (desktop only)
            // TODO: needs revision
            q-context-menu.desktop-only
115 116 117 118 119 120 121
              q-list(link, separator, no-border, style="min-width: 150px; max-height: 300px;")
                q-item(
                v-for="action in cellContextMenuActions",
                :key="action.label",
                v-close-overlay,
                @click.native="event => {action.handler(event, annotation)}")
                  q-item-main(:label="action.label")
Anton's avatar
Intial  
Anton committed
122

christianrhansen's avatar
christianrhansen committed
123 124
        //----------------------------------------------------------------------------------------------- temporary cell
        //------------------------------------------------------------------------------------------------------ desktop
125
        template(v-for="(tmpCell, index) in tmpObjects")
126
          .cell-item.cell-item-tmp(:style="getAnnotationStyle(tmpCell)", :key="`cell-tmp-${index}`")
Anton's avatar
Intial  
Anton committed
127 128
            cell(:cell="tmpCell")

christianrhansen's avatar
christianrhansen committed
129
        //------------------------------------------------------------------------------------------------------- mobile
130
        template(v-if="mobileTempCell.show && cachedNewCell")
131

132 133 134
          .cell-item.cell-item-tmp-mobile.row.justify-center.items-center(
          ref="_mobileTempCell",
          :style="mobileTempCellStyle(mobileTempCell)")
135

christianrhansen's avatar
christianrhansen committed
136
            cell.absolute-top-left.q-ma-sm(:cell="cachedNewCell", :temp="true")
137

138 139 140 141 142
            //
              q-btn.text-white(v-if="mobileTempCell.button",
              @click="event => {addMobileCell(event)}", round, flat, size="lg",
              style="background-color: rgba(0, 0, 0, 0);")
                q-icon(name="check")
143

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        //------------------------------------------------------------------------------------------------- move handler
        //----- (main)
        cell-handler-mobile.main-handler.shadow-1(
        v-if="!cellHandler.resize.pushed",
        @onIntersectionChange="intersectionChanged",
        :element="'move'",
        v-touch-pan="handleMoveCell",
        :style="{left: cellHandler.move.x - 20 + 'px', top: cellHandler.move.y - 20 + 'px'}",
        :class="[{'pushed': !cellHandler.move.pushed}, {'hide': !mobileTempCell.onGrid && !showEditingCells}]")
          q-icon.rotate-180(name="open_with", size="22px")

        //----- (temp)
        //----- (when main move handler is outside of viewport)
        cell-handler-mobile.temp-handler.shadow-1(
        v-touch-pan="handleMoveCell",
        :doubleTap="{el: $el, type: 'scroll', oLeft: mobileTempCell.left}",
        :class="[(!mobileTempCell.onGrid || tempHandler.move.intersectingMainHandler || cellHandler.resize.pushed || cellHandler.move.pushed ? 'hide': 'show'), (tempHandler.move.side === 'left' ? 'left-side' : 'right-side')]",
        :style="{top: cellHandler.move.y + 59 - 20 + 'px'}",)
          q-icon.rotate-180(name="open_with", size="22px")

        //----------------------------------------------------------------------------------------------- resize handler
        //----- (main)
        cell-handler-mobile.main-handler.shadow-1(
        v-if="!cellHandler.move.pushed",
        @onIntersectionChange="intersectionChanged",
        :element="'resize'",
        v-touch-pan="handleResizeCell",
        :style="{left: cellHandler.resize.x - 20 + 'px', top: cellHandler.resize.y - 20 + 'px'}",
        :class="[{'pushed': !cellHandler.resize.pushed}, {'hide': !mobileTempCell.onGrid && !showEditingCells}]")
          q-icon(name="signal_cellular_4_bar", size="12px", style="margin-left: -3px;")

        //----- (temp)
        //----- (when main resize handler is outside of viewport)
        cell-handler-mobile.temp-handler.shadow-1(
        v-touch-pan="handleResizeCell",
        :class="[(!mobileTempCell.onGrid || tempHandler.resize.intersectingMainHandler || cellHandler.move.pushed || cellHandler.resize.pushed ? 'hide': 'show'), (tempHandler.resize.side === 'left' ? 'left-side' : 'right-side')]",
        :style="{top: cellHandler.resize.y + 59 - 20 + 'px'}",)
          q-icon(name="signal_cellular_4_bar", size="12px", style="margin-left: -3px;")
182

christianrhansen's avatar
christianrhansen committed
183
      // ---------------------------------------------------------------------------------------------------------------
Anton's avatar
Intial  
Anton committed
184
      template(v-else)
185
        .cell-item(:style="getAnnotationStyle({x:0,y:0,width:1,height:1})", key="cell-grid-resizer")
Anton's avatar
Intial  
Anton committed
186
          div.cell-item-resize-handle(
187 188 189 190 191
          draggable="true",
          @dragstart="event => {handleGridResizerDragStart(event)}",
          @dragend="event => {handleGridResizerDragEnd(event)}",
          @dragexit="event => {handleGridResizerDragEnd(event)}")
            q-icon(name="network cell")
Anton's avatar
Intial  
Anton committed
192

Mathias Bär's avatar
Mathias Bär committed
193
      //template(v-if="!isMobile")
194 195 196 197 198
        .fixed-top-right(style="right:18px; top:68px", v-if="!$store.state.mosys.showSources")
          q-btn(round, color="primary", small, @click="handleGridButtonClickEdit", style="margin-right: 0.5em")
            q-icon(name="add")
          q-btn(round, color="primary", small, @click="$router.push(`/mosys/grids/${$route.params.uuid}`)")
            q-icon(name="remove red eye")
Mathias Bär's avatar
Mathias Bär committed
199
      //template(v-if="isMobile")
Mathias Bär's avatar
Mathias Bär committed
200 201 202 203 204
        .fixed-top-right.q-mt-sm(v-if="!$store.state.mosys.showSources", style="z-index: 10000; padding-top: 3px;")
          q-btn.q-mr-sm(round, color="primary", size="sm", @click="handleGridButtonClickEdit")
            q-icon(name="add")
          q-btn.q-mr-md(round, color="primary", size="sm", @click="$router.push(`/mosys/grids/${$route.params.uuid}`)")
            q-icon(name="remove red eye")
Anton's avatar
Intial  
Anton committed
205

christianrhansen's avatar
christianrhansen committed
206
    // ------------------------------------------------------------------------------------------ edit box (mobile only)
207

208
    q-page-sticky.edit-box.q-mx-md.q-mb-md.transition-bottom.backdrop-filter.shadow-6.overflow-hidden.hidden(
christianrhansen's avatar
christianrhansen committed
209
    v-if="isMobile",
210
    :class="[{'show-full' : carousel.visibility && showEditingCells}, {'show-minimized' : showEditingCells}]",
211
    style="border-radius: .5rem;",
212
    position="bottom-right")
christianrhansen's avatar
christianrhansen committed
213

214
      //------------------------- buttons
215 216
      // .row.text-dark(style="background-color: rgba(0, 0, 0, .2);")
      .row.text-dark(style="background-color: rgba(255, 150, 150, .3);")
217 218 219

        //----- delete cell
        .col
christianrhansen's avatar
christianrhansen committed
220
          q-btn.q-py-none.q-pl-sm.q-ml-xs(
221
            @click="event => {handleCellContextMenuDelete(event, mobileSelectedCell)}", flat, no-ripple)
christianrhansen's avatar
christianrhansen committed
222
            q-icon(name="delete")
christianrhansen's avatar
christianrhansen committed
223

224 225
        //----- toggle edit-box
        .col.text-right
christianrhansen's avatar
christianrhansen committed
226
          q-btn.q-py-none.q-pr-sm.q-mr-xs(@click="carouselVisibility()", flat, no-ripple)
christianrhansen's avatar
christianrhansen committed
227 228
            q-icon(v-if="carousel.visibility", name="keyboard_arrow_down")
            q-icon(v-else, name="keyboard_arrow_up")
229

christianrhansen's avatar
christianrhansen committed
230
      //q-item-separator.q-ma-none
231 232 233 234 235 236

      //------------------------- carousel
      q-carousel.q-py-sm.carousel.transition-opacity(ref="carousel", v-model="slide",
      infinite, @input="getCarouselIcon(index)", style="width: 180px;")

        //----- move
christianrhansen's avatar
christianrhansen committed
237 238
        // q-carousel-slide.q-py-sm
        q-carousel-slide.q-py-none
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
          .text-center
            q-btn.edit-cell-button(@click="mobileCellMove(mobileSelectedCell, 0, -1)", round, flat, size="md")
              q-icon.rotate-90(name="keyboard_backspace")
          .text-center
            q-btn.edit-cell-button(@click="mobileCellMove(mobileSelectedCell, -1, 0)", round, flat, size="md")
              q-icon(name="keyboard_backspace")
            q-btn.invisible.text-dark(round, flat, size="md")
              q-icon.flip-vertical(name="photo_size_select_small")
            q-btn.edit-cell-button(@click="mobileCellMove(mobileSelectedCell, 1, 0)", round, flat, size="md")
              q-icon.rotate-180(name="keyboard_backspace")
          .text-center
            q-btn.edit-cell-button(@click="mobileCellMove(mobileSelectedCell, 0, 1)", round, flat, size="md")
              q-icon.rotate-270(name="keyboard_backspace")

        //----- resize
christianrhansen's avatar
christianrhansen committed
254 255
        // q-carousel-slide.q-py-sm
        q-carousel-slide.q-py-none
256 257 258 259 260 261 262 263 264 265 266 267 268
          .text-center
            q-btn.edit-cell-button(@click="mobileCellResize(mobileSelectedCell, 0, -1)", round, flat, size="md")
              q-icon(name="remove")
          .text-center
            q-btn.edit-cell-button(@click="mobileCellResize(mobileSelectedCell, -1, 0)", round, flat, size="md")
              q-icon(name="remove")
            q-btn.invisible.text-dark(round, flat, size="md")
              q-icon.rotate-45(name="zoom_out_map")
            q-btn.edit-cell-button(@click="mobileCellResize(mobileSelectedCell, 1, 0)", round, flat, size="md")
              q-icon(name="add")
          .text-center
            q-btn.edit-cell-button(@click="mobileCellResize(mobileSelectedCell, 0, 1)", round, flat, size="md")
              q-icon(name="add")
Anton's avatar
Intial  
Anton committed
269 270 271 272
</template>

<script>
  import Cell from './Cell'
273 274
  import { userHasFeature } from 'mbjs-quasar/src/lib'
  import { mapGetters } from 'vuex'
275
  import GridEditorEditingCellsMobile from './/GridEditorEditingCellsMobile'
276
  import CellHandlerMobile from './CellHandlerMobile'
Anton's avatar
Intial  
Anton committed
277 278 279 280 281 282

  const nullImage = new Image()
  nullImage.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='

  export default {
    components: {
283
      Cell,
284 285
      GridEditorEditingCellsMobile,
      CellHandlerMobile
Anton's avatar
Intial  
Anton committed
286
    },
287
    props: ['gridUuid', 'tabsAreOpen'],
Anton's avatar
Intial  
Anton committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
    data () {
      return {
        gridContextMenuActions: {
          insert_column_left: {
            label: 'Insert Column Left',
            handler: this.handleGridContextMenuInsertColumnLeft
          },
          delete_column: {
            label: 'Delete Column',
            handler: this.handleGridContextMenuDeleteColumn
          },
          insert_row_above: {
            label: 'Insert Row Above',
            handler: this.handleGridContextMenuInsertRowAbove
          },
          delete_row: {
            label: 'Delete Row',
            handler: this.handleGridContextMenuDeleteRow
          },
          edit_grid_dimensions: {
            label: 'Change Grid',
            handler: () => { this.resizingGrid = !this.resizingGrid }
          }
        },
        grid: undefined,
313
        annotations: undefined,
314
        tmpObjects: [],
315
        annotationUIStates: {},
Anton's avatar
Anton committed
316
        gridDimensions: { gridWidth: 0, gridHeight: 0, cellWidth: 0, cellHeight: 0 },
Anton's avatar
Intial  
Anton committed
317
        contextMenuClickPosition: {},
318
        resizingGrid: false,
christianrhansen's avatar
christianrhansen committed
319
        mobileSelectedCell: undefined,
320
        touch: {position: {top: undefined, left: undefined}},
321
        isMobile: this.$q.platform.is.mobile,
322 323 324 325 326 327 328 329 330 331 332 333
        mobileTempCell: {
          x: 0,
          y: 0,
          ox: 0,
          oy: 0,
          width: 1,
          height: 1,
          left: 0,
          show: false,
          onGrid: false,
          button: false
        },
334
        slide: undefined,
335
        modal: false,
336
        carousel: {visibility: false, icon: 'open_with', slide: 0},
christianrhansen's avatar
christianrhansen committed
337
        // cursor: {x: undefined, y: undefined},
338
        cellHandler: {
339
          size: {width: 40, height: 40},
340
          move: {x: 20, y: undefined, gridPosition: {row: undefined, column: undefined}, pushed: false, pos: undefined, inViewport: undefined, onLeft: undefined, onRight: undefined, dataLeft: undefined},
341
          resize: {x: undefined, y: undefined, gridPosition: {row: undefined, column: undefined}, pushed: false, pos: undefined}
342
        },
343
        tempHandler: {
christianrhansen's avatar
christianrhansen committed
344 345
          move: {left: undefined, intersectingMainHandler: false, side: undefined},
          resize: {left: undefined, intersectingMainHandler: false, side: undefined}
346
        },
347
        activeHandler: false,
348
        selectedCell: {type: undefined, annotation: undefined}
Anton's avatar
Intial  
Anton committed
349 350
      }
    },
351 352
    computed: {
      ...mapGetters({
christianrhansen's avatar
christianrhansen committed
353
        cachedNewCell: 'mosys/getNewCell',
354
        user: 'auth/getUserState',
355
        // isMobile: 'globalSettings/getIsMobile',
Mathias Bär's avatar
Mathias Bär committed
356
        // editingCells: 'mosys/getEditingCells'
357
        showEditingCells: 'mosys/getShowEditingCells',
358 359
        scrollPositionCache: 'mosys/getScrollPositionCache',
        editMode: 'mosys/getEditMode'
360
      }),
361 362 363 364 365 366
      newCellType () {
        if (this.cachedNewCell) {
          let type = this.cachedNewCell.component
          return type.substr(4, type.length - 4)
        }
      },
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
      cellContextMenuActions () {
        const actions = {
          delete: {
            label: 'Delete',
            handler: this.handleCellContextMenuDelete
          },
          insert_column_left: {
            label: 'Insert Column Left',
            handler: this.handleGridContextMenuInsertColumnLeft
          },
          insert_row_above: {
            label: 'Insert Row Above',
            handler: this.handleGridContextMenuInsertRowAbove
          }
        }
        if (userHasFeature(this.user, 'cssediting')) {
          actions.edit_css_classname = {
            label: 'Edit CSS class name',
            handler: this.handleCellContextMenuEditCSS
          }
        }
        return actions
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
      },
      gridStyle () {
        if (!this.gridDimensions || !this.gridDimensions.full) return {}
        // TODO: fix mobile grid editor view
        const cell = this.gridDimensions.full.cell
        return {
          width: `${this.gridDimensions.full.width}px`,
          height: '100%',
          'grid-auto-columns': `${cell.width}px`,
          'grid-auto-rows': `${cell.height}px`,
          'background-image': `url("data:image/svg+xml;utf8,` +
            `<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%'><defs>` +
            `<pattern id='smallGrid' width='${cell.width}' height='${cell.height}' patternUnits='userSpaceOnUse'>` +
            `<path d='M ${cell.width} 0 L 0 0 0 ${cell.height}' fill='none' stroke='gray' stroke-width='0.5'/>` +
            `</pattern></defs><rect width='100%' height='100%' fill='url(%23smallGrid)' /></svg>")`
        }
405 406
      }
    },
Anton's avatar
Intial  
Anton committed
407 408
    async mounted () {
      await this.fetchData()
409
      this.resetScrollPosition()
410 411 412
    },
    beforeDestroy () {
      this.observer.disconnect()
Anton's avatar
Intial  
Anton committed
413 414
    },
    watch: {
415
      'cellHandler.move.gridPosition': {
416 417 418 419
        handler: function (obj) {
          if (this.showEditingCells) {
            this.mobileCellMove(this.mobileSelectedCell, obj.column, obj.row)
          }
420 421 422
        },
        deep: true
      },
423 424 425
      'cellHandler.resize.gridPosition': {
        handler: function (obj) {
          if (this.showEditingCells) {
426 427 428
            let w = obj.column - this.cellHandler.move.gridPosition.column + 1
            let h = obj.row - this.cellHandler.move.gridPosition.row + 1
            this.mobileCellResize(this.mobileSelectedCell, w, h)
429 430 431 432
          }
        },
        deep: true
      },
433 434 435 436 437 438 439 440 441 442
      slide (val) {
        let icon
        switch (val) {
        case 0:
          icon = 'open_with'
          break
        case 1:
          icon = 'photo_size_select_small'
          break
        case 2:
443
          icon = 'more_horiz'
444 445 446 447 448
          break
        default:
          icon = 'open_with'
          break
        }
449 450 451
        // this.carousel.slide = val
        // this.carousel.icon = icon
        this.carousel = {slide: val, icon: icon, visibility: this.carousel.visibility}
452
      },
Anton's avatar
Anton committed
453
      annotations () {
454
        this.updateAnnotationUIStates()
Anton's avatar
Intial  
Anton committed
455 456 457 458 459 460
      },
      gridMetadata () {
        this.updateGridDimensions()
      },
      async gridUuid () {
        await this.fetchData()
Mathias Bär's avatar
Mathias Bär committed
461 462
      },
      showEditingCells (val) {
463
        // console.log('show editing cells', val)
Mathias Bär's avatar
Mathias Bär committed
464 465 466
        if (val === false) {
          this.updateAnnotationUIStates()
        }
467 468 469
      },
      tabsAreOpen () {
        this.resetScrollPosition()
Anton's avatar
Intial  
Anton committed
470 471 472
      }
    },
    methods: {
473 474 475 476 477 478 479 480
      clearHandler (target) {
        switch (target) {
        case 'cell':
          Object.keys(this.annotationUIStates).filter((k) => {
            this.annotationUIStates[k].editing = false
          })
          this.$store.commit('mosys/setEditingCells', '')
          break
481 482
        case 'cached cell':
          this.$store.commit('mosys/cacheNewCell', undefined)
483 484 485 486
          this.clearHandler('temp cell')
          break
        case 'temp cell':
          this.mobileTempCell = {x: undefined, y: undefined, width: undefined, height: undefined, onGrid: false, button: false}
487
          break
488 489
        }
      },
490
      intersectionChanged (obj) {
christianrhansen's avatar
christianrhansen committed
491 492
        let _offsetLeft = Math.sign(obj.offsetLeft)

493
        // -------------------- move
494
        if (obj.element === 'move') {
christianrhansen's avatar
christianrhansen committed
495
          this.tempHandler.move.intersectingMainHandler = obj.intersecting
496

christianrhansen's avatar
christianrhansen committed
497
          // behind left side
christianrhansen's avatar
christianrhansen committed
498
          if (_offsetLeft < 0) {
499
            this.tempHandler.move.side = 'left'
500
          }
501
          // intersecting
christianrhansen's avatar
christianrhansen committed
502
          else if (isNaN(_offsetLeft)) {
christianrhansen's avatar
christianrhansen committed
503
            if (this.tempHandler.move.intersectingMainHandler && this.tempHandler.move.side === 'right') this.tempHandler.resize.intersectingMainHandler = false
504
          }
christianrhansen's avatar
christianrhansen committed
505
          // behind right side
christianrhansen's avatar
christianrhansen committed
506
          else if (_offsetLeft === 1) {
507
            this.tempHandler.move.side = 'right'
christianrhansen's avatar
christianrhansen committed
508
            this.tempHandler.resize.intersectingMainHandler = true
509
          }
510
        }
511

512
        // -------------------- resize
christianrhansen's avatar
christianrhansen committed
513
        else if (obj.element === 'resize') {
christianrhansen's avatar
christianrhansen committed
514
          this.tempHandler.resize.intersectingMainHandler = obj.intersecting
515

christianrhansen's avatar
christianrhansen committed
516
          // on left side
christianrhansen's avatar
christianrhansen committed
517
          if (_offsetLeft === -1) {
518
            this.tempHandler.resize.side = 'left'
519
          }
christianrhansen's avatar
christianrhansen committed
520
          /*
521
          // intersecting
christianrhansen's avatar
christianrhansen committed
522
          else if (isNaN(Math.sign(obj.offsetLeft))) {
523
          }
christianrhansen's avatar
christianrhansen committed
524
          */
christianrhansen's avatar
christianrhansen committed
525
          // on right side
christianrhansen's avatar
christianrhansen committed
526
          else if (_offsetLeft === 1) {
527
            this.tempHandler.resize.side = 'right'
528
          }
529 530
        }
      },
christianrhansen's avatar
christianrhansen committed
531
      handleMoveCell (obj) {
532 533
        this.cellHandler.move.x = obj.position.left
        this.cellHandler.move.y = obj.position.top
534

christianrhansen's avatar
christianrhansen committed
535 536
        let res = this.getGridPositionForEvent(obj)

537 538 539
        this.cellHandler.move.gridPosition.row = res.y
        this.cellHandler.move.gridPosition.column = res.x

christianrhansen's avatar
christianrhansen committed
540
        if (obj.isFirst) {
541
          this.activeHandler = true
christianrhansen's avatar
christianrhansen committed
542
          this.mobileTempCell.show = true
543
          // this.mobileTempCell.button = false
544
          this.cellHandler.move.pushed = true
christianrhansen's avatar
christianrhansen committed
545
        }
546

christianrhansen's avatar
christianrhansen committed
547 548 549
        this.mobileTempCell.x = res.x
        this.mobileTempCell.y = res.y

550 551 552
        this.mobileTempCell.ox = res.ox
        this.mobileTempCell.oy = res.oy

553 554
        this.cellHandler.move.x = res.ox
        this.cellHandler.move.y = res.oy
555

christianrhansen's avatar
christianrhansen committed
556
        if (obj.isFinal) {
557
          this.activeHandler = false
christianrhansen's avatar
christianrhansen committed
558
          this.mobileTempCell.onGrid = true
559
          // this.mobileTempCell.button = true
560
          this.mobileTempCell.left = this.gridDimensions.full.cell.width * (res.x - 1)
561 562 563 564
          this.cellHandler.move.pushed = false
          // this.cellHandler.move.y = this.gridDimensions.full.cell.height * (res.y - 1) + 8 + 59 + 20
          this.cellHandler.move.x = this.gridDimensions.full.cell.width * (this.mobileTempCell.x - 1) + 8 + 20
          this.cellHandler.move.y = this.gridDimensions.full.cell.height * (this.mobileTempCell.y - 1) + 8 + 20
565

566 567
          this.cellHandler.resize.x = this.gridDimensions.full.cell.width * (res.x + this.mobileTempCell.width - 1) - 8 - 20
          this.cellHandler.resize.y = this.gridDimensions.full.cell.height * (res.y + this.mobileTempCell.height - 1) - 8 - 20
christianrhansen's avatar
christianrhansen committed
568 569
        }
      },
christianrhansen's avatar
christianrhansen committed
570
      handleResizeCell (obj) {
christianrhansen's avatar
christianrhansen committed
571
        // this.cursor = {x: obj.position.left, y: obj.position.top}
572 573 574
        // this.cellHandler.resize = {x: obj.position.left, y: obj.position.top}
        this.cellHandler.resize.x = obj.position.left
        this.cellHandler.resize.y = obj.position.top
575

576 577 578
        // ---> panGrid
        let res = this.getGridPositionForEvent(obj)

579 580 581
        this.cellHandler.resize.gridPosition.row = res.y
        this.cellHandler.resize.gridPosition.column = res.x

582
        if (obj.isFirst) {
583
          this.activeHandler = true
584
          this.mobileTempCell.show = true
585
          // this.mobileTempCell.button = false
586
          this.cellHandler.resize.pushed = true
587 588 589 590 591
        }

        this.mobileTempCell.width = res.x - this.mobileTempCell.x + 1
        this.mobileTempCell.height = res.y - this.mobileTempCell.y + 1

592 593
        this.cellHandler.resize.x = res.ox
        this.cellHandler.resize.y = res.oy
594

595
        if (obj.isFinal) {
596
          this.activeHandler = false
597
          this.mobileTempCell.onGrid = true
598
          // this.mobileTempCell.button = true
599
          this.cellHandler.resize.pushed = false
600 601
          // this.addMobileCell(obj)
          // this.mobileTempCell.show = false
602 603
          this.cellHandler.resize.x = this.gridDimensions.full.cell.width * res.x - 8 - 20
          this.cellHandler.resize.y = this.gridDimensions.full.cell.height * res.y - 8 - 20
604 605
        }
      },
606 607
      handleCellEdit (event, annotation) {
        console.log('handleCellEdit', annotation)
608 609 610
        this.touchMobileCell(event, annotation)
        this.handleModal()
      },
611 612 613 614
      getCarouselIcon (val) {
        console.log(val)
      },
      carouselVisibility () {
615 616 617 618
        console.log(this.carousel.slide)
        if (this.$refs.carousel) {
          this.$refs.carousel.goToSlide(this.carousel.slide)
        }
619 620
        this.carousel.visibility = !this.carousel.visibility
      },
621 622 623
      handleModal () {
        this.modal = !this.modal
      },
624
      panGrid (obj) {
625
        if (this.cachedNewCell && !this.mobileTempCell.onGrid) {
626
          // console.log('hhhhhhhhhhhhhhhhh', obj)
627 628 629 630
          let res = this.getGridPositionForEvent(obj)

          if (obj.isFirst) {
            this.mobileTempCell.show = true
631
            // this.mobileTempCell.button = false
632 633 634 635 636 637 638 639
            this.mobileTempCell.x = res.x
            this.mobileTempCell.y = res.y
          }

          this.mobileTempCell.width = res.x - this.mobileTempCell.x + 1
          this.mobileTempCell.height = res.y - this.mobileTempCell.y + 1

          if (obj.isFinal) {
640
            this.mobileTempCell.onGrid = true
641
            // this.mobileTempCell.button = true
642 643
            // this.addMobileCell(obj)
            // this.mobileTempCell.show = false
644 645
            this.cellHandler.move.x = this.gridDimensions.full.cell.width * (this.mobileTempCell.x - 1) + 8 + 20
            this.cellHandler.move.y = this.gridDimensions.full.cell.height * (this.mobileTempCell.y - 1) + 8 + 20
646

647 648
            this.cellHandler.resize.x = this.gridDimensions.full.cell.width * res.x - 8 - 20
            this.cellHandler.resize.y = this.gridDimensions.full.cell.height * res.y - 8 - 20
649
          }
650
        }
651
      },
652
      async cellCopy (event, annotation) {
653 654
        this.$store.commit('mosys/setEditingCells', '')

655
        this.$q.notify({
656
          message: 'Copied.',
657
          color: 'dark',
658 659
          textColor: 'white',
          position: 'bottom-right'
660 661 662 663 664 665 666 667 668 669
        })

        const _cell = await this.$store.dispatch('cells/get', annotation.body.source.id)
        const resourceCell = {
          data: { content: '' },
          config: {},
          component: _cell.component
        }
        this.$store.commit('mosys/cacheNewCell', resourceCell)
      },
christianrhansen's avatar
christianrhansen committed
670 671
      moveCachedCell (obj) {
        this.touch.position = {top: obj.position.top, left: obj.position.left}
672 673 674 675 676 677 678 679 680
        /*
        if (obj.isFinal) {
          console.log(obj.isFinal)
          console.log(window.event)
          console.log(this.touch.position)
          console.log('--->->->', this.getGridPositionForEvent(event))
        }
        */
        // console.log('--->>>', this.getGridPositionForEvent(event))
christianrhansen's avatar
christianrhansen committed
681
      },
682
      addMobileCell (event) {
christianrhansen's avatar
christianrhansen committed
683
        if (this.cachedNewCell) {
684
          this.handleGridDrop(event)
christianrhansen's avatar
christianrhansen committed
685
          this.$store.commit('mosys/cacheNewCell', undefined)
686 687
          this.$q.notify({
            message: 'Cell was added.',
688 689 690
            color: 'dark',
            position: 'center',
            timeout: 50
691
          })
christianrhansen's avatar
christianrhansen committed
692 693
        }
      },
694
      touchMobileCell (event, cell) {
695
        if (!this.mobileTempCell.onGrid && cell) {
696 697 698 699 700 701 702 703 704
          Object.keys(this.annotationUIStates).filter((k) => {
            if (k === cell._uuid && this.annotationUIStates[k].editing) console.log(k, cell._uuid)
            else this.annotationUIStates[k].editing = false
          })
          this.annotationUIStates[cell._uuid].editing = !this.annotationUIStates[cell._uuid].editing
          this.updateEditingCells()
          this.$root.$emit('mosys_saveScrollPosition')
          // this.handleCellEditClick(event, annotation)
        }
705
      },
christianrhansen's avatar
christianrhansen committed
706
      handleCellTouch (event, annotation) {
707
        console.log('handleCellTouch', annotation)
708
        if (!this.cachedNewCell) {
709 710 711 712 713 714 715 716 717 718 719 720 721 722
          let
            parsed = annotation.target.selector.parse(),
            sliced = parsed.xywh.slice(0, 4),
            x = sliced[0],
            y = sliced[1],
            w = sliced[2],
            h = sliced[3]

          this.cellHandler.move.x = this.gridDimensions.full.cell.width * (x - 1) + 8 + 20
          this.cellHandler.move.y = this.gridDimensions.full.cell.height * (y - 1) + 8 + 20

          this.cellHandler.resize.x = this.gridDimensions.full.cell.width * (x + w - 1) - 8 - 20
          this.cellHandler.resize.y = this.gridDimensions.full.cell.height * (y + h - 1) - 8 - 20

723
          this.mobileSelectedCell = annotation
724
          this.getCellType(annotation)
725
        }
christianrhansen's avatar
christianrhansen committed
726
      },
727 728 729 730 731
      async getCellType (annotation) {
        let cell = await this.$store.dispatch('cells/get', annotation.body.source.id)
        let cellType = cell.component
        this.selectedCell.type = cellType.substr(4, cellType.length - 4)
      },
732 733 734
      // async mobileCellMove (annotation, _x, _y) {
      async mobileCellMove (annotation, x, y) {
        // this.$el.scrollLeft = this.$el.scrollLeft + (this.gridDimensions.full.cell.width * _x)
735

736
        let
737 738
          parsed = annotation.target.selector.parse()
          /*
739
          sliced = parsed.xywh.slice(0, 4),
740
          x = sliced[0],
741 742 743
          y = sliced[1],
          w = sliced[2],
          h = sliced[3]
744
          */
745

746
        /*
747 748 749 750 751 752 753
        // ----- x
        if (_x === -1) if (x > 1) x += _x
        if (_x === 1 && x < this.grid.config.columns - w + 1) x += _x

        // ----- y
        if (_y === -1) if (y > 1) y += _y
        if (_y === 1 && y < this.grid.config.rows - h + 1) y += _y
754
        */
755 756 757 758

        // x += _x
        // y += _y

759 760 761 762 763 764 765 766
        let target = this.grid.get2DArea([x, y], parsed.xywh.slice(2))
        annotation.target.selector.value = target.selector.value
        await this.$store.dispatch('annotations/patch', [annotation.id, {
          target: {
            selector: { value: target.selector.value }
          }
        }])
      },
767
      async mobileCellResize (annotation, _w, _h) {
768 769 770
        let
          parsed = annotation.target.selector.parse(),
          [x, y, w, h] = parsed.xywh
771 772
        console.log('mobileCellResize', w, h)
        /*
773 774 775 776 777 778 779
        // ----- w
        if (_w === -1) if (w > 1) w += _w
        if (_w === 1 && x < this.grid.config.columns - w + 1) w += _w

        // ----- h
        if (_h === -1) if (h > 1) h += _h
        if (_h === 1 && y < this.grid.config.rows - h + 1) h += _h
780
        */
781 782 783 784

        // w += _w
        // h += _h

785
        const value = { xywh: [x, y, _w, _h] }
786 787 788 789 790 791 792
        annotation.target.selector.value = value

        await this.$store.dispatch('annotations/patch', [annotation.id, { target: { selector: { value } } }])
      },
      setEditMode (mode) {
        this.$store.commit('mosys/setEditMode', mode)
      },
793 794 795 796
      //
      // DATA
      //

Anton's avatar
Intial  
Anton committed
797 798 799
      async fetchData () {
        if (this.gridUuid) {
          this.grid = await this.$store.dispatch('maps/get', this.gridUuid)
800 801 802 803 804 805 806 807
          if (!Object.keys(this.grid.config).length) {
            this.grid.config = {
              columns: 10,
              rows: 6,
              ratio: 16 / 9.0
            }
            await this.updateGridMetadataStore()
          }
Anton's avatar
Intial  
Anton committed
808
          this.updateGridDimensions()
809 810 811 812 813 814
          const { items } = await this.$store.dispatch('annotations/find', {
            'target.id': this.grid.id,
            'body.purpose': 'linking',
            'body.type': 'Cell'
          })
          this.annotations = items
Anton's avatar
Intial  
Anton committed
815 816
        }
      },
817 818 819
      async updateGridMetadataStore () {
        await this.$store.dispatch('maps/patch', [this.grid.id, { config: this.grid.config }])
        this.updateGridDimensions()
Anton's avatar
Intial  
Anton committed
820
      },
821 822 823 824 825
      updateSelectedCells () {
        const _this = this
        let selectedCells = Object.keys(this.annotationUIStates).filter(k => {
          return _this.annotationUIStates[k].selected
        }).map(k => {
Christian Hansen's avatar
Christian Hansen committed
826 827
          // return _this.cells.find(c => c._uuid === k)
          return _this.annotations.find(c => c._uuid === k)
828 829
        })
        this.$store.commit('mosys/setSelectedCells', selectedCells)
Anton's avatar
Intial  
Anton committed
830
      },
Mathias Bär's avatar
Mathias Bär committed
831 832 833 834 835 836 837 838
      updateEditingCells () {
        const _this = this
        let editingCells = Object.keys(this.annotationUIStates).filter(k => {
          return _this.annotationUIStates[k].editing
        }).map(k => {
          // return _this.cells.find(c => c._uuid === k)
          return _this.annotations.find(c => c._uuid === k)
        })
839 840 841 842 843 844 845
        /*
        console.log('this.annotationUIStates: ', this.annotationUIStates)
        console.log('editingCells: ', editingCells)
        if (this.isMobile) {
          console.log('MOBILE')
        }
        */
Mathias Bär's avatar
Mathias Bär committed
846 847
        this.$store.commit('mosys/setEditingCells', editingCells)
      },
848 849 850 851 852
      updateAnnotationUIStates () {
        let newAnnotationUIStates = {}
        this.annotations.forEach(a => {
          newAnnotationUIStates[a._uuid] = {
            selected: false,
Mathias Bär's avatar
Mathias Bär committed
853
            editing: false,
854
            beingResized: false,
Mathias Bär's avatar
Mathias Bär committed
855
            beginDragged: false,
856
            annotation: a
Anton's avatar
Intial  
Anton committed
857
          }
858 859
        })
        this.annotationUIStates = newAnnotationUIStates
Anton's avatar
Intial  
Anton committed
860
        this.updateSelectedCells()
Mathias Bär's avatar
Mathias Bär committed
861
        this.updateEditingCells()
862
      },
863 864 865 866 867

      //
      // GRID DRAG & DROP HANDLERS
      //

868
      async handleGridDragOver (event) {
Anton's avatar
Intial  
Anton committed
869 870 871
        let _this = this
        if (this.resizingGrid) {
          const position = this.getGridPositionForEvent(event)
872 873
          this.grid.config.ratio = position.ox / (position.oy * 1.0)
          await this.updateGridMetadataStore()
Anton's avatar
Intial  
Anton committed
874 875
        }
        else {
876 877
          let annotation = this.annotations.filter(annotation => {
            if (!_this.annotationUIStates[annotation._uuid]) return false
Mathias Bär's avatar
Mathias Bär committed
878
            return _this.annotationUIStates[annotation._uuid].beingDragged ||
879
              _this.annotationUIStates[annotation._uuid].beingResized
Anton's avatar
Intial  
Anton committed
880 881
          }).shift()
          let offset, position
882 883 884 885
          if (!annotation) {
            annotation = {
              target: this.grid.get2DArea([1, 1], [1, 1])
            }
Anton's avatar
Intial  
Anton committed
886 887 888
            position = this.getGridPositionForEvent(event)
          }
          else {
889
            offset = this.annotationUIStates[annotation._uuid].draggingOffset
Anton's avatar
Intial  
Anton committed
890 891
            position = this.getGridPositionForEvent(event, offset)
          }
892 893
          if (!this.tmpObjects.length) this.tmpObjects.push(annotation)
          const parsed = annotation.target.selector.parse()
Anton's avatar
Intial  
Anton committed
894
          if (event.dataTransfer.types.includes('text/plain')) {
895 896
            parsed.xywh[0] = position.x
            parsed.xywh[1] = position.y
Anton's avatar
Intial  
Anton committed
897 898 899
            event.preventDefault()
          }
          else {
900 901
            parsed.xywh[2] = Math.max(1, 1 + position.x - parsed.xywh[0])
            parsed.xywh[3] = Math.max(1, 1 + position.y - parsed.xywh[1])
Anton's avatar
Intial  
Anton committed
902
          }
903
          annotation.target.selector.value = parsed
Anton's avatar
Intial  
Anton committed
904 905 906
        }
      },
      handleGridDragEnd () {
907
        this.tmpObjects = []
Anton's avatar
Intial  
Anton committed
908
      },
909
      async handleGridDrop (event) {
910 911 912 913 914
        let dropData
        if (event.dataTransfer) dropData = event.dataTransfer.getData('text/plain')
        if (!dropData) dropData = JSON.stringify(this.cachedNewCell)
        // console.log('handleGridDrop - event', event)
        // console.log('handleGridDrop - dropData', dropData)
915 916
        if (dropData) {
          dropData = JSON.parse(dropData)
917
          let annotation = this.annotations.find(a => a.id === dropData.id)
918 919 920 921 922
          const { x, y } = this.getGridPositionForEvent(
            event,
            annotation ? this.annotationUIStates[annotation._uuid].draggingOffset : undefined
          )
          if (annotation) {
923 924 925
            const
              parsed = annotation.target.selector.parse(),
              target = this.grid.get2DArea([x, y], parsed.xywh.slice(2))
926 927 928 929 930 931
            annotation.target.selector.value = target.selector.value
            await this.$store.dispatch('annotations/patch', [annotation.id, {
              target: {
                selector: { value: target.selector.value }
              }
            }])
Anton's avatar
Intial  
Anton committed
932 933
          }
          else {
934 935
            if (this.mobileTempCell.x) console.log('this.mobileTempCell', this.mobileTempCell)
            let test = this.grid.get2DArea([this.mobileTempCell.x, this.mobileTempCell.y], [this.mobileTempCell.width, this.mobileTempCell.height])
936 937 938 939 940 941 942 943 944 945 946
            const
              { 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
                }
              },
947 948
              // target: this.grid.get2DArea([x, y], [1, 1])
              target: test
949
            })
950
            this.annotations.push(annotation)
Anton's avatar
Anton committed
951
            this.updateAnnotationUIStates()
Anton's avatar
Intial  
Anton committed
952
          }
953

954
          this.tmpObjects = []
Anton's avatar
Intial  
Anton committed
955 956
          event.preventDefault()
        }
957
        this.clearHandler('temp cell')
Anton's avatar
Intial  
Anton committed
958
      },
959 960 961 962

      //
      // CELL DRAG & DROP HANDLERS
      //
Mathias Bär's avatar
Mathias Bär committed
963 964 965
      handleCellEditClick (event, cell) {
        this.annotationUIStates[cell._uuid].editing = !this.annotationUIStates[cell._uuid].editing
        this.updateEditingCells()
966
        this.$root.$emit('mosys_saveScrollPosition')
Mathias Bär's avatar
Mathias Bär committed
967
      },
968
      /*
969 970 971 972
      handleCellClick (event, cell) {
        this.annotationUIStates[cell._uuid].selected = !this.annotationUIStates[cell._uuid].selected
        this.updateSelectedCells()
      },
973
      */
974
      handleCellDragStart (event, annotation) {
christianrhansen's avatar
christianrhansen committed
975
        console.log('§§§§§§§§', annotation)
976 977 978 979 980 981 982 983 984 985 986 987
        if (!this.isMobile) {
          if (!this.annotationUIStates[annotation._uuid].beingResized) {
            event.dataTransfer.setData('text/plain', JSON.stringify(annotation))
            event.dataTransfer.setDragImage(nullImage, 0, 0)
            let elContainerBoundingBox = this.$el.getBoundingClientRect()
            let elBoundingBox = event.target.getBoundingClientRect()
            let offset = {
              x: (event.clientX - elContainerBoundingBox.x) - (elBoundingBox.x - elContainerBoundingBox.x),
              y: (event.clientY - elContainerBoundingBox.y) - (elBoundingBox.y - elContainerBoundingBox.y)
            }
            this.annotationUIStates[annotation._uuid].draggingOffset = offset
            this.annotationUIStates[annotation._uuid].beingDragged = true
988
          }
989
          this.tmpObjects.push(annotation)
990 991 992
        }
      },
      handleCellDragEnd (event, annotation) {
993 994 995
        if (!this.mobile) {
          this.annotationUIStates[annotation._uuid].beingDragged = false
        }
996 997 998 999
      },
      async handleCellContextMenuDelete (event, annotation) {
        this.annotationUIStates[annotation._uuid].selected = false
        this.updateSelectedCells()
Mathias Bär's avatar
Mathias Bär committed
1000
        this.updateEditingCells()
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
        await this.$store.dispatch('cells/delete', annotation.body.source.id)
        await this.$store.dispatch('annotations/delete', annotation.id)
        this.annotations = this.annotations.filter(a => a.id !== annotation.id)
      },

      //
      // GRID RESIZE HANDLERS

      handleGridResizerDragStart (event) {
        event.dataTransfer.setDragImage(nullImage, 0, 0)
      },
      async handleGridResizerDragEnd () {
        await this.updateGridMetadataStore()
      },

      //
      // CELL RESIZE HANDLERS
      //

      handleCellResizerDragStart (event, annotation) {
        event.dataTransfer.setDragImage(nullImage, 0, 0)
        this.annotationUIStates[annotation._uuid].beingResized = true
        this.tmpObjects.push(annotation)
      },
      async handleCellResizerDragEnd (event, annotation) {
        let position = this.getGridPositionForEvent(event)
        let
          parsed = annotation.target.selector.parse(),
          [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.tmpObjects = []
        await this.$store.dispatch('annotations/patch', [annotation.id, { target: { selector: { value } } }])
      },

      //
      // CELL CONTEXT MENU
      //

      handleCellContextMenu (event) {
Anton's avatar
Intial  
Anton committed
1044 1045
        this.contextMenuClickPosition = this.getGridPositionForEvent(event)
      },