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

3
  div.cell-grid-container(
4
  :class="{'overflow-hidden': mobileTempCell.show && cachedNewCell && !mobileTempCell.button}",
5
  style="overflow-y: hidden; scroll-behavior: smooth;")
6
    q-modal(v-model="modal", minimized, content-css="background-color: #eee; border-radius: .75rem;")
7
      grid-editor-editing-cells-mobile
8 9 10
      //
        q-btn.absolute-top-right.q-ma-sm.bg-dark(@click="handleModal()", round, size="sm", flat)
          q-icon(name="clear")
11

12 13 14 15 16 17
    // this needs to stay for adding cells on mobile for whatever reason (strangest bug ever...)
    // FIXME: find the problem and fix it
    .mobile-only.fixed-top-left.q-caption.z-max.hidden
      .bg-red {{ cachedNewCell }}
      .bg-green {{ mobileTempCell }}

18
    q-window-resize-observable(@resize="updateGridDimensions")
Anton's avatar
Intial  
Anton committed
19

christianrhansen's avatar
christianrhansen committed
20
    // ------------------------------------------------------------------------------------------------- new cell header
21 22
    #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
23
        q-item-main
24
          | New {{ newCellType }}
25
        q-item-side
26
          q-btn.bg-transparent.text-white.on-right(@click.native="clearCachedCell()", round, flat)
christianrhansen's avatar
christianrhansen committed
27
            q-icon(name="clear")
28

29 30
    // -------------------------------------------------------------------------------------------- selected cell header
    #selected-cell-header.fixed-top.z-top.bg-dark.text-white.transition(:class="{'show': showEditingCells}")
31
      q-item.q-pl-md.q-pr-xs.q-py-none.full-height(v-if="!modal")
32
        q-item-main
33
          | {{ selectedCell.type }}
34 35 36 37
        q-item-side
          q-btn.bg-transparent.text-white.on-right(@click="event => {handleCellContextMenuDelete(event, mobileSelectedCell)}", round, flat)
            q-icon(name="delete")

38
    // ------------------------------------------------------------------------------------------------------------ grid
39
      @click="event => {addMobileCell(event)}",
40
    div.cell-grid.relative-position(
41
    v-touch-pan="panGrid",
42 43 44 45 46 47
    @dragenter="handleGridDragOver",
    @dragover="handleGridDragOver",
    @dragleave="handleGridDragEnd",
    @drop="handleGridDrop",
    @contextmenu="handleGridContextMenu",
    :style="gridStyle")
Anton's avatar
Intial  
Anton committed
48

49 50
      // context menu grid (desktop only)
      q-context-menu.desktop-only(ref="gridmenu")
Anton's avatar
Intial  
Anton committed
51 52
        q-list(link, separator, no-border, style="min-width: 150px; max-height: 300px;")
          q-item(
53 54 55 56 57
          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
58 59 60

      template(v-if="!resizingGrid")

61
        template(v-for="(annotation, index) in annotations")
christianrhansen's avatar
christianrhansen committed
62 63

          //----- cell
64
          // v-touch-hold="event => {cellHold(event, annotation)}",
Anton's avatar
Intial  
Anton committed
65
          .cell-item(
66 67 68 69 70 71 72 73 74 75 76 77 78
          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}`")

            //----- edit-/close-button
            // TODO: find a more elegant solution
            .desktop-only
Mathias Bär's avatar
Mathias Bär committed
79
              q-btn.edit-button.absolute-top-right(
80 81 82 83 84 85
              @click.prevent="event => {handleCellEditClick(event, annotation)}",
              :class="getAnnotationClasses(annotation._uuid, 'editing')",
              style="top: 8px; right: 8px;",
              :icon="annotationUIStates[annotation._uuid].editing ? 'close' : 'edit'", flat, round, size="md"
              )
            .mobile-only
86 87 88 89 90 91 92
              .edit-button.absolute.fit.bg-transparent(
              v-touch-hold="event => {handleCellInfoTouch(event, annotation)}",
              @click.prevent="event => {touchMobileCell(event, annotation)}")
                q-btn.absolute-top-right.text-dark.q-pa-none.q-mr-xs(
                @click.prevent="event => {handleCellInfoTouch(event, annotation)}",
                flat, round, size="sm", style="margin-top: 2px;")
                  q-icon(name="edit", size="20px")
christianrhansen's avatar
christianrhansen committed
93

94 95 96 97 98
              //----- invisible edit-modal handler
              //
                q-btn.absolute-top-left.bg-blue(
                @click.prevent="event => {handleCellInfoTouch(event, annotation)}", flat, style="opacity: 0") bla
                // @click.prevent="handleModal()", flat, style="opacity: 0") bla
99

100
            //----- selecting cells disabled because it has no use currently
101 102 103 104 105 106 107 108
            // switch with cell component below to re-enable it
            //cell(
              @click.native.prevent="event => {handleCellClick(event, annotation)}", :annotation="annotation", :preview="true")
            cell(
            :annotation="annotation",
            :preview="true"
            )

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

117 118 119
            //----- context menu for cells (desktop only)
            // TODO: needs revision
            q-context-menu.desktop-only
120 121 122 123 124 125 126
              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
127

128
        //----- temporary cell when pulling a new cell into grid (desktop)
129
        template(v-for="(tmpCell, index) in tmpObjects")
130
          .cell-item.cell-item-tmp(:style="getAnnotationStyle(tmpCell)", :key="`cell-tmp-${index}`")
Anton's avatar
Intial  
Anton committed
131 132
            cell(:cell="tmpCell")

christianrhansen's avatar
christianrhansen committed
133
        //-------------------------------------------------------------------------------------- temporary cell (mobile)
134 135
        // template
        template(v-if="mobileTempCell.show && cachedNewCell")
136

137
          //----- cell
138 139 140
          .cell-item.cell-item-tmp-mobile.row.justify-center.items-center(
          ref="_mobileTempCell",
          :style="mobileTempCellStyle(mobileTempCell)")
141

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

christianrhansen's avatar
christianrhansen committed
144
            q-btn.text-white(v-if="mobileTempCell.button",
145 146
            @click="event => {addMobileCell(event)}", round, flat, size="lg",
            style="background-color: rgba(0, 0, 0, 0);")
147
              q-icon(name="check")
148

149 150
          //----------------------------------------------------------------------------------------------- move handler
          //----- (main)
151
          cell-handler-mobile.main-handler.shadow-1(
152
          v-if="!cellHandler.resize.pushed",
153 154 155
          @onIntersectionChange="intersectionChanged",
          :element="'move'",
          v-touch-pan="handleMoveCell",
156 157
          :style="{left: cellHandler.move.x - 20 + 'px', top: cellHandler.move.y - 20 + 'px'}",
          :class="[{'pushed': !cellHandler.move.pushed}, {'hide': !mobileTempCell.onGrid}]")
158
            q-icon.rotate-180(name="open_with", size="22px")
christianrhansen's avatar
christianrhansen committed
159

160
          //----- (temp)
161
          //----- (when main move handler is outside of viewport)
162
          cell-handler-mobile.temp-handler.shadow-1(
163
          v-touch-pan="handleMoveCell",
164
          :doubleTap="{el: $el, type: 'scroll', oLeft: mobileTempCell.left}",
165 166
          :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'}",)
167
            q-icon.rotate-180(name="open_with", size="22px")
168

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

180 181
          //----- (temp)
          //----- (when main resize handler is outside of viewport)
182
          cell-handler-mobile.temp-handler.shadow-1(
183
          v-touch-pan="handleResizeCell",
184 185
          :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'}",)
186
            q-icon(name="signal_cellular_4_bar", size="12px", style="margin-left: -3px;")
187

christianrhansen's avatar
christianrhansen committed
188
      // ---------------------------------------------------------------------------------------------------------------
Anton's avatar
Intial  
Anton committed
189
      template(v-else)
190
        .cell-item(:style="getAnnotationStyle({x:0,y:0,width:1,height:1})", key="cell-grid-resizer")
Anton's avatar
Intial  
Anton committed
191
          div.cell-item-resize-handle(
192 193 194 195 196
          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
197

Mathias Bär's avatar
Mathias Bär committed
198
      //template(v-if="!isMobile")
199 200 201 202 203
        .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
204
      //template(v-if="isMobile")
Mathias Bär's avatar
Mathias Bär committed
205 206 207 208 209
        .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
210

211
    // ------------------------------------------------------------------------------------------ edit box (mobile only)
212

213
    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
214
    v-if="isMobile",
215
    :class="[{'show-full' : carousel.visibility && showEditingCells}, {'show-minimized' : showEditingCells}]",
216
    style="border-radius: .5rem;",
217
    position="bottom-right")
christianrhansen's avatar
christianrhansen committed
218

219
      //------------------------- buttons
220 221
      // .row.text-dark(style="background-color: rgba(0, 0, 0, .2);")
      .row.text-dark(style="background-color: rgba(255, 150, 150, .3);")
222 223 224

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

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

christianrhansen's avatar
christianrhansen committed
235
      //q-item-separator.q-ma-none
236 237 238 239 240 241

      //------------------------- 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
242 243
        // q-carousel-slide.q-py-sm
        q-carousel-slide.q-py-none
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
          .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
259 260
        // q-carousel-slide.q-py-sm
        q-carousel-slide.q-py-none
261 262 263 264 265 266 267 268 269 270 271 272 273
          .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
274 275 276 277
</template>

<script>
  import Cell from './Cell'
278 279
  import { userHasFeature } from 'mbjs-quasar/src/lib'
  import { mapGetters } from 'vuex'
280
  import GridEditorEditingCellsMobile from './/GridEditorEditingCellsMobile'
281
  import CellHandlerMobile from './CellHandlerMobile'
Anton's avatar
Intial  
Anton committed
282 283 284 285 286 287

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

  export default {
    components: {
288
      Cell,
289 290
      GridEditorEditingCellsMobile,
      CellHandlerMobile
Anton's avatar
Intial  
Anton committed
291
    },
292
    props: ['gridUuid', 'tabsAreOpen'],
Anton's avatar
Intial  
Anton committed
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
    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,
318
        annotations: undefined,
319
        tmpObjects: [],
320
        annotationUIStates: {},
Anton's avatar
Anton committed
321
        gridDimensions: { gridWidth: 0, gridHeight: 0, cellWidth: 0, cellHeight: 0 },
Anton's avatar
Intial  
Anton committed
322
        contextMenuClickPosition: {},
323
        resizingGrid: false,
christianrhansen's avatar
christianrhansen committed
324
        mobileSelectedCell: undefined,
325
        touch: {position: {top: undefined, left: undefined}},
326
        isMobile: this.$q.platform.is.mobile,
327 328 329 330 331 332 333 334 335 336 337 338
        mobileTempCell: {
          x: 0,
          y: 0,
          ox: 0,
          oy: 0,
          width: 1,
          height: 1,
          left: 0,
          show: false,
          onGrid: false,
          button: false
        },
339
        slide: undefined,
340
        modal: false,
341
        carousel: {visibility: false, icon: 'open_with', slide: 0},
christianrhansen's avatar
christianrhansen committed
342
        // cursor: {x: undefined, y: undefined},
343
        cellHandler: {
344
          size: {width: 40, height: 40},
345
          move: {x: 20, y: undefined, pushed: false, pos: undefined, inViewport: undefined, onLeft: undefined, onRight: undefined, dataLeft: undefined},
christianrhansen's avatar
christianrhansen committed
346
          resize: {x: undefined, y: undefined, pushed: false, pos: undefined}
347
        },
348
        tempHandler: {
christianrhansen's avatar
christianrhansen committed
349 350
          move: {left: undefined, intersectingMainHandler: false, side: undefined},
          resize: {left: undefined, intersectingMainHandler: false, side: undefined}
351 352
        },
        selectedCell: {type: undefined}
Anton's avatar
Intial  
Anton committed
353 354
      }
    },
355 356
    computed: {
      ...mapGetters({
christianrhansen's avatar
christianrhansen committed
357
        cachedNewCell: 'mosys/getNewCell',
358
        user: 'auth/getUserState',
359
        // isMobile: 'globalSettings/getIsMobile',
Mathias Bär's avatar
Mathias Bär committed
360
        // editingCells: 'mosys/getEditingCells'
361
        showEditingCells: 'mosys/getShowEditingCells',
362 363
        scrollPositionCache: 'mosys/getScrollPositionCache',
        editMode: 'mosys/getEditMode'
364
      }),
365 366 367 368 369 370
      newCellType () {
        if (this.cachedNewCell) {
          let type = this.cachedNewCell.component
          return type.substr(4, type.length - 4)
        }
      },
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
      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
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
      },
      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>")`
        }
409 410
      }
    },
Anton's avatar
Intial  
Anton committed
411 412
    async mounted () {
      await this.fetchData()
413
      this.resetScrollPosition()
414 415 416
    },
    beforeDestroy () {
      this.observer.disconnect()
Anton's avatar
Intial  
Anton committed
417 418
    },
    watch: {
419 420 421 422 423 424 425 426 427 428
      slide (val) {
        let icon
        switch (val) {
        case 0:
          icon = 'open_with'
          break
        case 1:
          icon = 'photo_size_select_small'
          break
        case 2:
429
          icon = 'more_horiz'
430 431 432 433 434
          break
        default:
          icon = 'open_with'
          break
        }
435 436 437
        // this.carousel.slide = val
        // this.carousel.icon = icon
        this.carousel = {slide: val, icon: icon, visibility: this.carousel.visibility}
438
      },
Anton's avatar
Anton committed
439
      annotations () {
440
        this.updateAnnotationUIStates()
Anton's avatar
Intial  
Anton committed
441 442 443 444 445 446
      },
      gridMetadata () {
        this.updateGridDimensions()
      },
      async gridUuid () {
        await this.fetchData()
Mathias Bär's avatar
Mathias Bär committed
447 448
      },
      showEditingCells (val) {
449
        // console.log('show editing cells', val)
Mathias Bär's avatar
Mathias Bär committed
450 451 452
        if (val === false) {
          this.updateAnnotationUIStates()
        }
453 454 455
      },
      tabsAreOpen () {
        this.resetScrollPosition()
Anton's avatar
Intial  
Anton committed
456 457 458
      }
    },
    methods: {
459
      intersectionChanged (obj) {
christianrhansen's avatar
christianrhansen committed
460 461
        let _offsetLeft = Math.sign(obj.offsetLeft)

462
        // -------------------- move
463
        if (obj.element === 'move') {
christianrhansen's avatar
christianrhansen committed
464
          this.tempHandler.move.intersectingMainHandler = obj.intersecting
465

christianrhansen's avatar
christianrhansen committed
466
          // behind left side
christianrhansen's avatar
christianrhansen committed
467
          if (_offsetLeft < 0) {
468
            this.tempHandler.move.side = 'left'
469
          }
470
          // intersecting
christianrhansen's avatar
christianrhansen committed
471
          else if (isNaN(_offsetLeft)) {
christianrhansen's avatar
christianrhansen committed
472
            if (this.tempHandler.move.intersectingMainHandler && this.tempHandler.move.side === 'right') this.tempHandler.resize.intersectingMainHandler = false
473
          }
christianrhansen's avatar
christianrhansen committed
474
          // behind right side
christianrhansen's avatar
christianrhansen committed
475
          else if (_offsetLeft === 1) {
476
            this.tempHandler.move.side = 'right'
christianrhansen's avatar
christianrhansen committed
477
            this.tempHandler.resize.intersectingMainHandler = true
478
          }
479
        }
480

481
        // -------------------- resize
christianrhansen's avatar
christianrhansen committed
482
        else if (obj.element === 'resize') {
christianrhansen's avatar
christianrhansen committed
483
          this.tempHandler.resize.intersectingMainHandler = obj.intersecting
484

christianrhansen's avatar
christianrhansen committed
485
          // on left side
christianrhansen's avatar
christianrhansen committed
486
          if (_offsetLeft === -1) {
487
            this.tempHandler.resize.side = 'left'
488
          }
christianrhansen's avatar
christianrhansen committed
489
          /*
490
          // intersecting
christianrhansen's avatar
christianrhansen committed
491
          else if (isNaN(Math.sign(obj.offsetLeft))) {
492
          }
christianrhansen's avatar
christianrhansen committed
493
          */
christianrhansen's avatar
christianrhansen committed
494
          // on right side
christianrhansen's avatar
christianrhansen committed
495
          else if (_offsetLeft === 1) {
496
            this.tempHandler.resize.side = 'right'
497
          }
498 499
        }
      },
christianrhansen's avatar
christianrhansen committed
500
      handleMoveCell (obj) {
501 502
        this.cellHandler.move.x = obj.position.left
        this.cellHandler.move.y = obj.position.top
503

christianrhansen's avatar
christianrhansen committed
504 505 506 507 508
        let res = this.getGridPositionForEvent(obj)

        if (obj.isFirst) {
          this.mobileTempCell.show = true
          this.mobileTempCell.button = false
509
          this.cellHandler.move.pushed = true
christianrhansen's avatar
christianrhansen committed
510
        }
511

christianrhansen's avatar
christianrhansen committed
512 513 514
        this.mobileTempCell.x = res.x
        this.mobileTempCell.y = res.y

515 516 517
        this.mobileTempCell.ox = res.ox
        this.mobileTempCell.oy = res.oy

518 519
        this.cellHandler.move.x = res.ox
        this.cellHandler.move.y = res.oy
520

christianrhansen's avatar
christianrhansen committed
521 522 523
        if (obj.isFinal) {
          this.mobileTempCell.onGrid = true
          this.mobileTempCell.button = true
524
          this.mobileTempCell.left = this.gridDimensions.full.cell.width * (res.x - 1)
525 526 527 528
          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
529

530 531
          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
532 533
        }
      },
christianrhansen's avatar
christianrhansen committed
534
      handleResizeCell (obj) {
christianrhansen's avatar
christianrhansen committed
535
        // this.cursor = {x: obj.position.left, y: obj.position.top}
536 537 538
        // 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
539

540 541 542 543 544 545
        // ---> panGrid
        let res = this.getGridPositionForEvent(obj)

        if (obj.isFirst) {
          this.mobileTempCell.show = true
          this.mobileTempCell.button = false
546
          this.cellHandler.resize.pushed = true
547 548 549 550 551
        }

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

552 553
        this.cellHandler.resize.x = res.ox
        this.cellHandler.resize.y = res.oy
554

555 556 557
        if (obj.isFinal) {
          this.mobileTempCell.onGrid = true
          this.mobileTempCell.button = true
558
          this.cellHandler.resize.pushed = false
559 560
          // this.addMobileCell(obj)
          // this.mobileTempCell.show = false
561 562
          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
563 564
        }
      },
565 566 567 568
      clearCachedCell () {
        this.$store.commit('mosys/cacheNewCell', undefined)
        this.clearTempCell()
      },
569 570 571 572
      handleCellInfoTouch (event, annotation) {
        this.touchMobileCell(event, annotation)
        this.handleModal()
      },
573 574 575 576
      getCarouselIcon (val) {
        console.log(val)
      },
      carouselVisibility () {
577 578 579 580
        console.log(this.carousel.slide)
        if (this.$refs.carousel) {
          this.$refs.carousel.goToSlide(this.carousel.slide)
        }
581 582
        this.carousel.visibility = !this.carousel.visibility
      },
583 584 585
      handleModal () {
        this.modal = !this.modal
      },
586
      clearTempCell () {
587
        this.mobileTempCell = {x: undefined, y: undefined, width: undefined, height: undefined, onGrid: false, button: false}
588
      },
589
      panGrid (obj) {
590
        if (this.cachedNewCell && !this.mobileTempCell.onGrid) {
591
          // console.log('hhhhhhhhhhhhhhhhh', obj)
592 593 594 595
          let res = this.getGridPositionForEvent(obj)

          if (obj.isFirst) {
            this.mobileTempCell.show = true
596
            this.mobileTempCell.button = false
597 598 599 600 601 602 603 604
            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) {
605
            this.mobileTempCell.onGrid = true
606
            this.mobileTempCell.button = true
607 608
            // this.addMobileCell(obj)
            // this.mobileTempCell.show = false
609 610
            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
611

612 613
            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
614
          }
615
        }
616
      },
617
      async cellHold (event, annotation) {
618 619
        this.$store.commit('mosys/setEditingCells', '')

620
        this.$q.notify({
621
          message: 'Copied.',
622
          color: 'dark',
623 624
          textColor: 'white',
          position: 'bottom-right'
625 626 627 628 629 630 631 632 633 634
        })

        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
635 636
      moveCachedCell (obj) {
        this.touch.position = {top: obj.position.top, left: obj.position.left}
637 638 639 640 641 642 643 644 645
        /*
        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
646
      },
647 648
      addMobileCell (event) {
        // console.log('addMobileCell()', event, annotation)
christianrhansen's avatar
christianrhansen committed
649
        if (this.cachedNewCell) {
650
          this.handleGridDrop(event)
christianrhansen's avatar
christianrhansen committed
651
          this.$store.commit('mosys/cacheNewCell', undefined)
652 653
          this.$q.notify({
            message: 'Cell was added.',
654 655 656
            color: 'dark',
            position: 'center',
            timeout: 50
657
          })
christianrhansen's avatar
christianrhansen committed
658 659
        }
      },
660
      touchMobileCell (event, cell) {
661 662 663 664 665 666 667 668 669 670
        if (!this.mobileTempCell.onGrid) {
          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)
        }
671
      },
christianrhansen's avatar
christianrhansen committed
672
      handleCellTouch (event, annotation) {
673 674
        if (!this.cachedNewCell) {
          this.mobileSelectedCell = annotation
675
          this.getCellType(annotation)
676
        }
christianrhansen's avatar
christianrhansen committed
677
      },
678 679 680 681 682
      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)
      },
683
      async mobileCellMove (annotation, _x, _y) {
684 685
        this.$el.scrollLeft = this.$el.scrollLeft + (this.gridDimensions.full.cell.width * _x)

686 687
        let
          parsed = annotation.target.selector.parse(),
688
          sliced = parsed.xywh.slice(0, 4),
689
          x = sliced[0],
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
          y = sliced[1],
          w = sliced[2],
          h = sliced[3]

        // ----- 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

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

705 706 707 708 709 710 711 712
        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 }
          }
        }])
      },
713
      async mobileCellResize (annotation, _w, _h) {
714 715 716
        let
          parsed = annotation.target.selector.parse(),
          [x, y, w, h] = parsed.xywh
717 718 719 720 721 722 723 724 725 726 727 728

        // ----- 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

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

729 730 731 732 733 734 735 736
        const value = { xywh: [x, y, w, h] }
        annotation.target.selector.value = value

        await this.$store.dispatch('annotations/patch', [annotation.id, { target: { selector: { value } } }])
      },
      setEditMode (mode) {
        this.$store.commit('mosys/setEditMode', mode)
      },
737 738 739 740
      //
      // DATA
      //

Anton's avatar
Intial  
Anton committed
741 742 743
      async fetchData () {
        if (this.gridUuid) {
          this.grid = await this.$store.dispatch('maps/get', this.gridUuid)
744 745 746 747 748 749 750 751
          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
752
          this.updateGridDimensions()
753 754 755 756 757 758
          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
759 760
        }
      },
761 762 763
      async updateGridMetadataStore () {
        await this.$store.dispatch('maps/patch', [this.grid.id, { config: this.grid.config }])
        this.updateGridDimensions()
Anton's avatar
Intial  
Anton committed
764
      },
765 766 767 768 769
      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
770 771
          // return _this.cells.find(c => c._uuid === k)
          return _this.annotations.find(c => c._uuid === k)
772 773
        })
        this.$store.commit('mosys/setSelectedCells', selectedCells)
Anton's avatar
Intial  
Anton committed
774
      },
Mathias Bär's avatar
Mathias Bär committed
775 776 777 778 779 780 781 782
      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)
        })
783 784 785 786 787 788 789
        /*
        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
790 791
        this.$store.commit('mosys/setEditingCells', editingCells)
      },
792 793 794 795 796
      updateAnnotationUIStates () {
        let newAnnotationUIStates = {}
        this.annotations.forEach(a => {
          newAnnotationUIStates[a._uuid] = {
            selected: false,
Mathias Bär's avatar
Mathias Bär committed
797
            editing: false,
798
            beingResized: false,
Mathias Bär's avatar
Mathias Bär committed
799
            beginDragged: false,
800
            annotation: a
Anton's avatar
Intial  
Anton committed
801
          }
802 803
        })
        this.annotationUIStates = newAnnotationUIStates
Anton's avatar
Intial  
Anton committed
804
        this.updateSelectedCells()
Mathias Bär's avatar
Mathias Bär committed
805
        this.updateEditingCells()
806
      },
807 808 809 810 811

      //
      // GRID DRAG & DROP HANDLERS
      //

812
      async handleGridDragOver (event) {
Anton's avatar
Intial  
Anton committed
813 814 815
        let _this = this
        if (this.resizingGrid) {
          const position = this.getGridPositionForEvent(event)
816 817
          this.grid.config.ratio = position.ox / (position.oy * 1.0)
          await this.updateGridMetadataStore()
Anton's avatar
Intial  
Anton committed
818 819
        }
        else {
820 821
          let annotation = this.annotations.filter(annotation => {
            if (!_this.annotationUIStates[annotation._uuid]) return false
Mathias Bär's avatar
Mathias Bär committed
822
            return _this.annotationUIStates[annotation._uuid].beingDragged ||
823
              _this.annotationUIStates[annotation._uuid].beingResized
Anton's avatar
Intial  
Anton committed
824 825
          }).shift()
          let offset, position
826 827 828 829
          if (!annotation) {
            annotation = {
              target: this.grid.get2DArea([1, 1], [1, 1])
            }
Anton's avatar
Intial  
Anton committed
830 831 832
            position = this.getGridPositionForEvent(event)
          }
          else {
833
            offset = this.annotationUIStates[annotation._uuid].draggingOffset
Anton's avatar
Intial  
Anton committed
834 835
            position = this.getGridPositionForEvent(event, offset)
          }
836 837
          if (!this.tmpObjects.length) this.tmpObjects.push(annotation)
          const parsed = annotation.target.selector.parse()
Anton's avatar
Intial  
Anton committed
838
          if (event.dataTransfer.types.includes('text/plain')) {
839 840
            parsed.xywh[0] = position.x
            parsed.xywh[1] = position.y
Anton's avatar
Intial  
Anton committed
841 842 843
            event.preventDefault()
          }
          else {
844 845
            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
846
          }
847
          annotation.target.selector.value = parsed
Anton's avatar
Intial  
Anton committed
848 849 850
        }
      },
      handleGridDragEnd () {
851
        this.tmpObjects = []
Anton's avatar
Intial  
Anton committed
852
      },
853
      async handleGridDrop (event) {
854 855 856 857 858
        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)
859 860
        if (dropData) {
          dropData = JSON.parse(dropData)
861
          let annotation = this.annotations.find(a => a.id === dropData.id)
862 863 864 865 866
          const { x, y } = this.getGridPositionForEvent(
            event,
            annotation ? this.annotationUIStates[annotation._uuid].draggingOffset : undefined
          )
          if (annotation) {
867 868 869
            const
              parsed = annotation.target.selector.parse(),
              target = this.grid.get2DArea([x, y], parsed.xywh.slice(2))
870 871 872 873 874 875
            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
876 877
          }
          else {
878 879
            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])
880 881 882 883 884 885 886 887 888 889 890
            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
                }
              },
891 892
              // target: this.grid.get2DArea([x, y], [1, 1])
              target: test
893
            })
894
            this.annotations.push(annotation)
Anton's avatar
Anton committed
895
            this.updateAnnotationUIStates()
Anton's avatar
Intial  
Anton committed
896
          }
897

898
          this.tmpObjects = []
Anton's avatar
Intial  
Anton committed
899 900
          event.preventDefault()
        }
901
        this.clearTempCell()
Anton's avatar
Intial  
Anton committed
902
      },
903 904 905 906

      //
      // CELL DRAG & DROP HANDLERS
      //
Mathias Bär's avatar
Mathias Bär committed
907 908 909
      handleCellEditClick (event, cell) {
        this.annotationUIStates[cell._uuid].editing = !this.annotationUIStates[cell._uuid].editing
        this.updateEditingCells()
910
        this.$root.$emit('mosys_saveScrollPosition')
Mathias Bär's avatar
Mathias Bär committed
911
      },
912 913 914 915 916
      handleCellClick (event, cell) {
        this.annotationUIStates[cell._uuid].selected = !this.annotationUIStates[cell._uuid].selected
        this.updateSelectedCells()
      },
      handleCellDragStart (event, annotation) {
christianrhansen's avatar
christianrhansen committed
917
        console.log('§§§§§§§§', annotation)
918 919 920 921 922 923 924 925 926 927 928 929
        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
930
          }
931
          this.tmpObjects.push(annotation)
932 933 934
        }
      },
      handleCellDragEnd (event, annotation) {
935 936 937
        if (!this.mobile) {
          this.annotationUIStates[annotation._uuid].beingDragged = false
        }
938 939 940 941
      },
      async handleCellContextMenuDelete (event, annotation) {
        this.annotationUIStates[annotation._uuid].selected = false
        this.updateSelectedCells()
Mathias Bär's avatar
Mathias Bär committed
942
        this.updateEditingCells()
943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
        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
986 987
        this.contextMenuClickPosition = this.getGridPositionForEvent(event)
      },
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
      async handleCellContextMenuEditCSS (event, annotation) {
        try {
          let styleClass = await this.$q.dialog({
            title: this.$t('forms.edit_css_class.title'),
            ok: this.$t('buttons.set_css_class'),
            cancel: this.$t('buttons.cancel'),
            prompt: {
              model: annotation.styleClass,
              type: 'text'
            }
          })
          if (styleClass) {
            if (!styleClass.length) styleClass = undefined
            else if (styleClass.indexOf('.') === 0) styleClass = styleClass.substr(1)
          }
          annotation.styleClass = styleClass
          this.$store.dispatch('annotations/patch', [annotation._uuid, { target: { styleClass: styleClass || null } }])
Anton's avatar
Intial  
Anton committed
1005
        }
1006 1007 1008 1009 1010 1011 1012 1013 1014
        catch (e) { /* dialog canceled */ }
      },

      //
      // GRID CONTEXT MENU
      //

      handleGridContextMenu (event) {
        this.contextMenuClickPosition = this.getGridPositionForEvent(event)
Anton's avatar
Intial  
Anton committed
1015 1016 1017
      },
      async handleGridContextMenuInsertColumnLeft () {
        let position = this.contextMenuClickPosition
1018 1019 1020 1021 1022 1023 1024 1025
        for (let annotation of this.annotations) {
          const parsed = annotation.target.selector.parse()
          if (parsed.xywh[0] >= position.x) {
            parsed.xywh[0] += 1
            annotation.target.selector.value = parsed
            await this.$store.dispatch('annotations/patch', [annotation.id, {
              target: { selector: { value: parsed } }
            }])
Anton's avatar
Intial  
Anton committed
1026 1027
          }
        }
1028
        this.grid.config.columns += 1
Anton's avatar
Intial  
Anton committed
1029 1030 1031 1032
        await this.updateGridMetadataStore()
      },
      async handleGridContextMenuDeleteColumn () {
        let position = this.contextMenuClickPosition
1033 1034 1035 1036 1037 1038 1039 1040
        for (let annotation of this.annotations) {
          const parsed = annotation.target.selector.parse()
          if (parsed.xywh[0] > position.x) {
            parsed.xywh[0] -= 1
            annotation.target.selector.value = parsed
            await this.$store.dispatch('annotations/patch', [annotation.id, {
              target: { selector: { value: parsed } }
            }])
Anton's avatar
Intial  
Anton committed
1041 1042
          }
        }
1043
        this.grid.config.columns -= 1
Anton's avatar
Intial  
Anton committed
1044 1045 1046 1047
        await this.updateGridMetadataStore()
      },
      async handleGridContextMenuInsertRowAbove () {
        let position = this.contextMenuClickPosition
1048 1049 1050 1051 1052 1053 1054 1055
        for (let annotation of this.annotations) {
          const parsed = annotation.target.selector.parse()
          if (parsed.xywh[1] >= position.y) {
            parsed.xywh[1] += 1
            annotation.target.selector.value = parsed
            await this.$store.dispatch('annotations/patch', [annotation.id, {
              target: { selector: { value: parsed } }
            }])
Anton's avatar
Intial  
Anton committed
1056 1057
          }
        }
1058
        this.grid.config.rows += 1
Anton's avatar
Intial  
Anton committed
1059 1060 1061 1062
        await this.updateGridMetadataStore()
      },
      async handleGridContextMenuDeleteRow () {
        let position = this.contextMenuClickPosition
1063 1064 1065 1066 1067 1068 1069 1070
        for (let annotation of this.annotations) {
          const parsed = annotation.target.selector.parse()
          if (parsed.xywh[1] > position.y) {
            parsed.xywh[1] -= 1
            annotation.target.selector.value = parsed
            await this.$store.dispatch('annotations/patch', [annotation.id, {
              target: { selector: { value: parsed } }
            }])
Anton's avatar
Intial  
Anton committed
1071 1072
          }
        }
1073
        this.grid.config.rows -= 1
Anton's avatar
Intial  
Anton committed
1074 1075
        await this.updateGridMetadataStore()
      },
1076 1077 1078 1079 1080

      //
      // NAVIGATION
      //

Anton's avatar
Intial  
Anton committed
1081
      handleGridButtonClickEdit () {
1082
        this.$store.commit('mosys/toggleSources')
Anton's avatar
Intial  
Anton committed
1083
      },
1084 1085 1086 1087 1088

      //
      // GRID HELPERS
      //