GridEditor.vue 51.3 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
christianrhansen's avatar
christianrhansen committed
10
    q-modal(v-model="modal", minimized, content-css="background-color: #eee; border-radius: .5rem;")
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
          .cell-item.cell-item-tmp-mobile.row.justify-center.items-center(
          ref="_mobileTempCell",
          :style="mobileTempCellStyle(mobileTempCell)")
christianrhansen's avatar
christianrhansen committed
134
            cell.absolute-top-left.q-ma-sm(:cell="cachedNewCell", :temp="true")
135

christianrhansen's avatar
christianrhansen committed
136 137
        //------------------------------------------------------------------------------------------------------ handler
        //--------------------------------------------------------------------------------------------------------- move
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
        //----- (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")

christianrhansen's avatar
christianrhansen committed
157
        //------------------------------------------------------------------------------------------------------- resize
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
        //----- (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;")
175

christianrhansen's avatar
christianrhansen committed
176
      // ---------------------------------------------------------------------------------------------------------------
Anton's avatar
Intial  
Anton committed
177
      template(v-else)
178
        .cell-item(:style="getAnnotationStyle({x:0,y:0,width:1,height:1})", key="cell-grid-resizer")
Anton's avatar
Intial  
Anton committed
179
          div.cell-item-resize-handle(
180 181 182 183 184
          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
185

Mathias Bär's avatar
Mathias Bär committed
186
      //template(v-if="!isMobile")
187 188 189 190 191
        .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
192
      //template(v-if="isMobile")
Mathias Bär's avatar
Mathias Bär committed
193 194 195 196 197
        .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
198

christianrhansen's avatar
christianrhansen committed
199
    // ------------------------------------------------------------------------------------------ edit box (mobile only)
200

201
    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
202
    v-if="isMobile",
203
    :class="[{'show-full' : carousel.visibility && showEditingCells}, {'show-minimized' : showEditingCells}]",
204
    style="border-radius: .5rem;",
205
    position="bottom-right")
christianrhansen's avatar
christianrhansen committed
206

207
      //------------------------- buttons
208 209
      // .row.text-dark(style="background-color: rgba(0, 0, 0, .2);")
      .row.text-dark(style="background-color: rgba(255, 150, 150, .3);")
210 211 212

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

217 218
        //----- toggle edit-box
        .col.text-right
christianrhansen's avatar
christianrhansen committed
219
          q-btn.q-py-none.q-pr-sm.q-mr-xs(@click="carouselVisibility()", flat, no-ripple)
christianrhansen's avatar
christianrhansen committed
220 221
            q-icon(v-if="carousel.visibility", name="keyboard_arrow_down")
            q-icon(v-else, name="keyboard_arrow_up")
222

christianrhansen's avatar
christianrhansen committed
223
      //q-item-separator.q-ma-none
224 225 226 227 228 229

      //------------------------- 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
230 231
        // q-carousel-slide.q-py-sm
        q-carousel-slide.q-py-none
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
          .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
247 248
        // q-carousel-slide.q-py-sm
        q-carousel-slide.q-py-none
249 250 251 252 253 254 255 256 257 258 259 260 261
          .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
262 263 264 265
</template>

<script>
  import Cell from './Cell'
266 267
  import { userHasFeature } from 'mbjs-quasar/src/lib'
  import { mapGetters } from 'vuex'
268
  import GridEditorEditingCellsMobile from './/GridEditorEditingCellsMobile'
269
  import CellHandlerMobile from './CellHandlerMobile'
Anton's avatar
Intial  
Anton committed
270 271 272 273 274 275

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

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

486
        // -------------------- move
487
        if (obj.element === 'move') {
christianrhansen's avatar
christianrhansen committed
488
          this.tempHandler.move.intersectingMainHandler = obj.intersecting
489

christianrhansen's avatar
christianrhansen committed
490
          // behind left side
christianrhansen's avatar
christianrhansen committed
491
          if (_offsetLeft < 0) {
492
            this.tempHandler.move.side = 'left'
493
          }
494
          // intersecting
christianrhansen's avatar
christianrhansen committed
495
          else if (isNaN(_offsetLeft)) {
christianrhansen's avatar
christianrhansen committed
496
            if (this.tempHandler.move.intersectingMainHandler && this.tempHandler.move.side === 'right') this.tempHandler.resize.intersectingMainHandler = false
497
          }
christianrhansen's avatar
christianrhansen committed
498
          // behind right side
christianrhansen's avatar
christianrhansen committed
499
          else if (_offsetLeft === 1) {
500
            this.tempHandler.move.side = 'right'
christianrhansen's avatar
christianrhansen committed
501
            this.tempHandler.resize.intersectingMainHandler = true
502
          }
503
        }
504

505
        // -------------------- resize
christianrhansen's avatar
christianrhansen committed
506
        else if (obj.element === 'resize') {
christianrhansen's avatar
christianrhansen committed
507
          this.tempHandler.resize.intersectingMainHandler = obj.intersecting
508

christianrhansen's avatar
christianrhansen committed
509
          // on left side
christianrhansen's avatar
christianrhansen committed
510
          if (_offsetLeft === -1) {
511
            this.tempHandler.resize.side = 'left'
512
          }
christianrhansen's avatar
christianrhansen committed
513
          /*
514
          // intersecting
christianrhansen's avatar
christianrhansen committed
515
          else if (isNaN(Math.sign(obj.offsetLeft))) {
516
          }
christianrhansen's avatar
christianrhansen committed
517
          */
christianrhansen's avatar
christianrhansen committed
518
          // on right side
christianrhansen's avatar
christianrhansen committed
519
          else if (_offsetLeft === 1) {
520
            this.tempHandler.resize.side = 'right'
521
          }
522 523
        }
      },
christianrhansen's avatar
christianrhansen committed
524
      handleMoveCell (obj) {
525 526
        this.cellHandler.move.x = obj.position.left
        this.cellHandler.move.y = obj.position.top
527

christianrhansen's avatar
christianrhansen committed
528 529
        let res = this.getGridPositionForEvent(obj)

530 531 532
        this.cellHandler.move.gridPosition.row = res.y
        this.cellHandler.move.gridPosition.column = res.x

christianrhansen's avatar
christianrhansen committed
533
        if (obj.isFirst) {
534
          this.activeHandler = true
christianrhansen's avatar
christianrhansen committed
535
          this.mobileTempCell.show = true
536
          // this.mobileTempCell.button = false
537
          this.cellHandler.move.pushed = true
christianrhansen's avatar
christianrhansen committed
538
        }
539

christianrhansen's avatar
christianrhansen committed
540 541 542
        this.mobileTempCell.x = res.x
        this.mobileTempCell.y = res.y

543 544 545
        this.mobileTempCell.ox = res.ox
        this.mobileTempCell.oy = res.oy

546 547
        this.cellHandler.move.x = res.ox
        this.cellHandler.move.y = res.oy
548

christianrhansen's avatar
christianrhansen committed
549
        if (obj.isFinal) {
550
          this.activeHandler = false
christianrhansen's avatar
christianrhansen committed
551
          this.mobileTempCell.onGrid = true
552
          // this.mobileTempCell.button = true
553
          this.mobileTempCell.left = this.gridDimensions.full.cell.width * (res.x - 1)
554 555 556 557
          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
558

559 560
          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
561 562
        }
      },
christianrhansen's avatar
christianrhansen committed
563
      handleResizeCell (obj) {
christianrhansen's avatar
christianrhansen committed
564
        // this.cursor = {x: obj.position.left, y: obj.position.top}
565 566 567
        // 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
568

569 570 571
        // ---> panGrid
        let res = this.getGridPositionForEvent(obj)

572 573 574
        this.cellHandler.resize.gridPosition.row = res.y
        this.cellHandler.resize.gridPosition.column = res.x

575
        if (obj.isFirst) {
576
          this.activeHandler = true
577
          this.mobileTempCell.show = true
578
          // this.mobileTempCell.button = false
579
          this.cellHandler.resize.pushed = true
580 581 582 583 584
        }

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

585 586
        this.cellHandler.resize.x = res.ox
        this.cellHandler.resize.y = res.oy
587

588
        if (obj.isFinal) {
589
          this.activeHandler = false
590
          this.mobileTempCell.onGrid = true
591
          // this.mobileTempCell.button = true
592
          this.cellHandler.resize.pushed = false
593 594
          // this.addMobileCell(obj)
          // this.mobileTempCell.show = false
595 596
          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
597 598
        }
      },
599 600
      handleCellEdit (event, annotation) {
        console.log('handleCellEdit', annotation)
601 602 603
        this.touchMobileCell(event, annotation)
        this.handleModal()
      },
604 605 606 607
      getCarouselIcon (val) {
        console.log(val)
      },
      carouselVisibility () {
608 609 610 611
        console.log(this.carousel.slide)
        if (this.$refs.carousel) {
          this.$refs.carousel.goToSlide(this.carousel.slide)
        }
612 613
        this.carousel.visibility = !this.carousel.visibility
      },
614 615 616
      handleModal () {
        this.modal = !this.modal
      },
617
      panGrid (obj) {
618
        if (this.cachedNewCell && !this.mobileTempCell.onGrid) {
619
          // console.log('hhhhhhhhhhhhhhhhh', obj)
620 621 622 623
          let res = this.getGridPositionForEvent(obj)

          if (obj.isFirst) {
            this.mobileTempCell.show = true
624
            // this.mobileTempCell.button = false
625 626 627 628 629 630 631 632
            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) {
633
            this.mobileTempCell.onGrid = true
634
            // this.mobileTempCell.button = true
635 636
            // this.addMobileCell(obj)
            // this.mobileTempCell.show = false
637 638
            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
639

640 641
            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
642
          }
643
        }
644
      },
645
      async cellCopy (event, annotation) {
646 647
        this.$store.commit('mosys/setEditingCells', '')

648
        this.$q.notify({
649
          message: 'Copied.',
650
          color: 'dark',
651 652
          textColor: 'white',
          position: 'bottom-right'
653 654 655 656 657 658 659 660 661 662
        })

        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
663 664
      moveCachedCell (obj) {
        this.touch.position = {top: obj.position.top, left: obj.position.left}
665 666 667 668 669 670 671 672 673
        /*
        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
674
      },
675
      addMobileCell (event) {
christianrhansen's avatar
christianrhansen committed
676
        if (this.cachedNewCell) {
677
          this.handleGridDrop(event)
christianrhansen's avatar
christianrhansen committed
678
          this.$store.commit('mosys/cacheNewCell', undefined)
679 680
          this.$q.notify({
            message: 'Cell was added.',
681 682 683
            color: 'dark',
            position: 'center',
            timeout: 50
684
          })
christianrhansen's avatar
christianrhansen committed
685 686
        }
      },
687
      touchMobileCell (event, cell) {
688
        if (!this.mobileTempCell.onGrid && cell) {
689 690 691 692 693 694 695 696 697
          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)
        }
698
      },
christianrhansen's avatar
christianrhansen committed
699
      handleCellTouch (event, annotation) {
700
        console.log('handleCellTouch', annotation)
701
        if (!this.cachedNewCell) {
702 703 704 705 706 707 708 709 710 711 712 713 714 715
          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

716
          this.mobileSelectedCell = annotation
717
          this.getCellType(annotation)
718
        }
christianrhansen's avatar
christianrhansen committed
719
      },
720 721 722 723 724
      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)
      },
725 726 727
      // async mobileCellMove (annotation, _x, _y) {
      async mobileCellMove (annotation, x, y) {
        // this.$el.scrollLeft = this.$el.scrollLeft + (this.gridDimensions.full.cell.width * _x)
728

729
        let
730 731
          parsed = annotation.target.selector.parse()
          /*
732
          sliced = parsed.xywh.slice(0, 4),
733
          x = sliced[0],
734 735 736
          y = sliced[1],
          w = sliced[2],
          h = sliced[3]
737
          */
738

739
        /*
740 741 742 743 744 745 746
        // ----- 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
747
        */
748 749 750 751

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

752 753 754 755 756 757 758 759
        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 }
          }
        }])
      },
760
      async mobileCellResize (annotation, _w, _h) {
761 762 763
        let
          parsed = annotation.target.selector.parse(),
          [x, y, w, h] = parsed.xywh
764 765
        console.log('mobileCellResize', w, h)
        /*
766 767 768 769 770 771 772
        // ----- 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
773
        */
774 775 776 777

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

778
        const value = { xywh: [x, y, _w, _h] }
779 780 781 782 783 784 785
        annotation.target.selector.value = value

        await this.$store.dispatch('annotations/patch', [annotation.id, { target: { selector: { value } } }])
      },
      setEditMode (mode) {
        this.$store.commit('mosys/setEditMode', mode)
      },
786 787 788 789
      //
      // DATA
      //

Anton's avatar
Intial  
Anton committed
790 791 792
      async fetchData () {
        if (this.gridUuid) {
          this.grid = await this.$store.dispatch('maps/get', this.gridUuid)
793 794 795 796 797 798 799 800
          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
801
          this.updateGridDimensions()
802 803 804 805 806 807
          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
808 809
        }
      },
810 811 812
      async updateGridMetadataStore () {
        await this.$store.dispatch('maps/patch', [this.grid.id, { config: this.grid.config }])
        this.updateGridDimensions()
Anton's avatar
Intial  
Anton committed
813
      },
814 815 816 817 818
      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
819 820
          // return _this.cells.find(c => c._uuid === k)
          return _this.annotations.find(c => c._uuid === k)
821 822
        })
        this.$store.commit('mosys/setSelectedCells', selectedCells)
Anton's avatar
Intial  
Anton committed
823
      },
Mathias Bär's avatar
Mathias Bär committed
824 825 826 827 828 829 830 831
      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)
        })
832 833 834 835 836 837 838
        /*
        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
839 840
        this.$store.commit('mosys/setEditingCells', editingCells)
      },
841 842 843 844 845
      updateAnnotationUIStates () {
        let newAnnotationUIStates = {}
        this.annotations.forEach(a => {
          newAnnotationUIStates[a._uuid] = {
            selected: false,
Mathias Bär's avatar
Mathias Bär committed
846
            editing: false,
847
            beingResized: false,
Mathias Bär's avatar
Mathias Bär committed
848
            beginDragged: false,
849
            annotation: a
Anton's avatar
Intial  
Anton committed
850
          }
851 852
        })
        this.annotationUIStates = newAnnotationUIStates