GridEditor.vue 49.5 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
21
    // ------------------------------------------------------------------------------------------ cached new cell helper
    // q-page-sticky.z-top(v-touch-pan="moveCachedCell", v-if="cachedNewCell", position="top-right")
christianrhansen's avatar
christianrhansen committed
22
23
24
    //
      .fixed-top-right.z-top(v-touch-pan="moveCachedCell", v-if="cachedNewCell",
      // :style="{top: touch.position.top - 16 - 16 + 'px'}")
25
    // .fixed-top.z-top(v-touch-pan="moveCachedCell", v-if="cachedNewCell")
christianrhansen's avatar
christianrhansen committed
26
27
    #cell-helper.fixed-top.z-top.bg-dark.text-white.transition(:class="{'show': cachedNewCell}")
      q-item.q-px-md.q-py-none.full-height
28
        q-item-main
29
          | Place new cell
30
        q-item-side
christianrhansen's avatar
christianrhansen committed
31
32
33
34
          //
            q-btn.bg-transparent.text-white.on-right(@click.native="clearTempCell()", round, flat,
            // :disabled="!mobileTempCell.onGrid")
              q-icon(name="undo")
35
          q-btn.bg-transparent.text-white.on-right(@click.native="clearCachedCell()", round, flat)
36
            q-icon(name="delete")
37
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
          v-if="!annotationUIStates[annotation._uuid] || !annotationUIStates[annotation._uuid].beingDragged",
67
          v-touch-hold="event => {handleCellInfoTouch(event, annotation)}",
68
69
70
71
72
73
74
75
76
77
78
79
          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
80
              q-btn.edit-button.absolute-top-right(
81
82
83
84
85
86
87
88
              @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
              q-btn.edit-button.absolute.fit.bg-transparent(
              @click.prevent="event => {touchMobileCell(event, annotation)}", flat)
christianrhansen's avatar
christianrhansen committed
89

90
91
92
93
94
              //----- 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
95

96
            //----- selecting cells disabled because it has no use currently
97
98
99
100
101
102
103
104
            // 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
105
            //----- resize-handler (desktop only)
106
            .desktop-only.cell-item-resize-handle(
107
108
109
110
            draggable="true",
            @dragstart="event => {handleCellResizerDragStart(event, annotation)}",
            @dragend="event => {handleCellResizerDragEnd(event, annotation)}",
            @dragexit="event => {handleCellResizerDragEnd(event, annotation)}")
111
              q-icon.q-ma-xs(name="network cell")
112

113
114
115
            //----- context menu for cells (desktop only)
            // TODO: needs revision
            q-context-menu.desktop-only
116
117
118
119
120
121
122
              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
123

124
        //----- temporary cell when pulling a new cell into grid (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")

129
        //------------------------- temporary cell (mobile)
130
131
        // template
        template(v-if="mobileTempCell.show && cachedNewCell")
132

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

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

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

145
146
          //----------------------------------------------------------------------------------------------- move handler
          //----- (main)
147
          // v-if="mobileTempCell.onGrid && !handlerNewCell.resize.pushed",
148
149
150
151
          // :data-left="getHandlerPosition('move')",
          // ref="move",
          // .handler-new-cell.move.absolute.text-dark.justify-center.row.bg-white.shadow-6(
          cell-handler-mobile.absolute(
152
          v-if="mobileTempCell.onGrid && !handlerNewCell.resize.pushed",
153
154
155
          @onIntersectionChange="intersectionChanged",
          :element="'move'",
          v-touch-pan="handleMoveCell",
christianrhansen's avatar
christianrhansen committed
156
          :style="{left: handlerNewCell.move.x - 20 + 'px', top: handlerNewCell.move.y - 20 + 'px'}",
157
          :class="[{'pushed': !handlerNewCell.move.pushed}]")
christianrhansen's avatar
christianrhansen committed
158
159
            q-icon.self-center.rotate-180(name="open_with", size="22px")

160
          //----- (temp)
161
          //----- (when main move handler is outside of viewport)
162
          cell-handler-mobile.temp.fixed(
163
          v-touch-pan="handleMoveCell",
164
165
          :class="[(tempHandler.move.visibility || handlerNewCell.resize.pushed ? 'temp-hide': 'temp-show'), (tempHandler.move.side === 'left' ? 'left-side' : 'right-side')]",
          :style="{top: handlerNewCell.move.y + 59 - 20 + 'px'}",)
166
167
            q-icon.self-center.rotate-180(name="open_with", size="22px")

168
169
          //--------------------------------------------------------------------------------------------- resize handler
          //----- (main)
170
          // v-if="mobileTempCell.onGrid && !handlerNewCell.move.pushed",
171
172
173
174
175
          // .handler-new-cell.resize.absolute.text-dark.justify-center.row.bg-white.shadow-6(
          // v-intersection-observer="resize",
          // ref="resize",
          // :data-left="getHandlerPosition('resize')",
          cell-handler-mobile.absolute(
176
          v-if="mobileTempCell.onGrid && !handlerNewCell.move.pushed",
177
178
179
          @onIntersectionChange="intersectionChanged",
          :element="'resize'",
          v-touch-pan="handleResizeCell",
180
181
          :style="{left: handlerNewCell.resize.x - 20 + 'px', top: handlerNewCell.resize.y - 20 + 'px'}",
          :class="{'pushed': !handlerNewCell.resize.pushed}")
182
            q-icon.self-center(name="signal_cellular_4_bar", size="12px", style="margin-left: -3px;")
183

184
185
          //----- (temp)
          //----- (when main resize handler is outside of viewport)
186
          // :style="{left: tempHandler.resize.left + 'px', top: handlerNewCell.resize.y + 59 - 20 + 'px'}",)
187
          cell-handler-mobile.temp.fixed(
188
          v-touch-pan="handleResizeCell",
189
190
          :class="[(tempHandler.resize.visibility || handlerNewCell.move.pushed || handlerNewCell.resize.pushed? 'temp-hide': 'temp-show'), (tempHandler.resize.side === 'left' ? 'left-side' : 'right-side')]",
          :style="{top: handlerNewCell.resize.y + 59 - 20 + 'px'}",)
191
192
            q-icon.self-center(name="signal_cellular_4_bar", size="12px", style="margin-left: -3px;")

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

Mathias Bär's avatar
Mathias Bär committed
203
      //template(v-if="!isMobile")
204
205
206
207
208
        .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
209
      //template(v-if="isMobile")
Mathias Bär's avatar
Mathias Bär committed
210
211
212
213
214
        .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
215

christianrhansen's avatar
christianrhansen committed
216
    // ------------------------------------------------------------------------------------------ edit box (mobile only)
217

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

224
      //------------------------- buttons
225
226
      // .row.text-dark(style="background-color: rgba(0, 0, 0, .2);")
      .row.text-dark(style="background-color: rgba(255, 150, 150, .3);")
227
228
229

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

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

christianrhansen's avatar
christianrhansen committed
240
      //q-item-separator.q-ma-none
241
242
243
244
245
246

      //------------------------- 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
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
262
263
          .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
264
265
        // q-carousel-slide.q-py-sm
        q-carousel-slide.q-py-none
266
267
268
269
270
271
272
273
274
275
276
277
278
          .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
279
280
281
282
</template>

<script>
  import Cell from './Cell'
283
284
  import { userHasFeature } from 'mbjs-quasar/src/lib'
  import { mapGetters } from 'vuex'
285
  import GridEditorEditingCellsMobile from './/GridEditorEditingCellsMobile'
286
  import CellHandlerMobile from './CellHandlerMobile'
Anton's avatar
Intial  
Anton committed
287
288
289
290
291
292

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

  export default {
    components: {
293
      Cell,
294
295
      GridEditorEditingCellsMobile,
      CellHandlerMobile
Anton's avatar
Intial  
Anton committed
296
    },
297
    props: ['gridUuid', 'tabsAreOpen'],
Anton's avatar
Intial  
Anton committed
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
    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,
323
        annotations: undefined,
324
        tmpObjects: [],
325
        annotationUIStates: {},
Anton's avatar
Anton committed
326
        gridDimensions: { gridWidth: 0, gridHeight: 0, cellWidth: 0, cellHeight: 0 },
Anton's avatar
Intial  
Anton committed
327
        contextMenuClickPosition: {},
328
        resizingGrid: false,
christianrhansen's avatar
christianrhansen committed
329
        mobileSelectedCell: undefined,
330
        touch: {position: {top: undefined, left: undefined}},
331
        isMobile: this.$q.platform.is.mobile,
332
333
334
335
336
337
338
339
340
341
342
343
        mobileTempCell: {
          x: 0,
          y: 0,
          ox: 0,
          oy: 0,
          width: 1,
          height: 1,
          left: 0,
          show: false,
          onGrid: false,
          button: false
        },
344
        slide: undefined,
345
        modal: false,
346
        carousel: {visibility: false, icon: 'open_with', slide: 0},
christianrhansen's avatar
christianrhansen committed
347
        // cursor: {x: undefined, y: undefined},
christianrhansen's avatar
christianrhansen committed
348
        handlerNewCell: {
349
          size: {width: 40, height: 40},
350
          move: {x: 20, y: undefined, pushed: false, pos: undefined, inViewport: undefined, onLeft: undefined, onRight: undefined, dataLeft: undefined},
christianrhansen's avatar
christianrhansen committed
351
          resize: {x: undefined, y: undefined, pushed: false, pos: undefined}
352
        },
353
        handlerNewCellTemp: {visibility: true, left: 0},
354
        tempHandler: {
355
356
          move: {left: undefined, visibility: false, side: undefined, intersectingMainHandler: undefined},
          resize: {left: undefined, visibility: false, side: undefined, intersectingMainHandler: undefined}
357
        }
Anton's avatar
Intial  
Anton committed
358
359
      }
    },
360
361
    computed: {
      ...mapGetters({
christianrhansen's avatar
christianrhansen committed
362
        cachedNewCell: 'mosys/getNewCell',
363
        user: 'auth/getUserState',
364
        // isMobile: 'globalSettings/getIsMobile',
Mathias Bär's avatar
Mathias Bär committed
365
        // editingCells: 'mosys/getEditingCells'
366
        showEditingCells: 'mosys/getShowEditingCells',
367
368
        scrollPositionCache: 'mosys/getScrollPositionCache',
        editMode: 'mosys/getEditMode'
369
      }),
370
371
372
373
374
      /*
      handlerPositionMove (val) {
        return val * 100
      },
      */
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
      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
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
      },
      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>")`
        }
413
414
      }
    },
Anton's avatar
Intial  
Anton committed
415
416
    async mounted () {
      await this.fetchData()
417
      this.resetScrollPosition()
418
419
420
    },
    beforeDestroy () {
      this.observer.disconnect()
Anton's avatar
Intial  
Anton committed
421
422
    },
    watch: {
423
424
425
      handlerPositionMove (val) {
        console.log('WATCG', val)
      },
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
      intersectionChanged (obj) {
467
468
        //
        // -------------------- move
469
        if (obj.element === 'move') {
470
          this.tempHandler.move.intersectingMainHandler = obj.intersecting
471
          this.tempHandler.move.visibility = obj.intersecting
472

christianrhansen's avatar
christianrhansen committed
473
          // behind left side
474
          if (Math.sign(obj.offsetLeft) < 0) {
475
476
            // this.tempHandler.move.left = 4
            this.tempHandler.move.side = 'left'
477
          }
christianrhansen's avatar
christianrhansen committed
478
          // visible
479
          else if (Math.sign(obj.offsetLeft) === 0) {
christianrhansen's avatar
christianrhansen committed
480
            this.tempHandler.resize.visibility = true
481
          }
christianrhansen's avatar
christianrhansen committed
482
          // behind right side
483
          else if (Math.sign(obj.offsetLeft) === 1) {
484
485
            // this.tempHandler.move.left = window.innerWidth - 40 - 4
            this.tempHandler.move.side = 'right'
486
          }
487
        }
488

489
        // -------------------- resize
490
        if (obj.element === 'resize') {
491
          this.tempHandler.resize.intersectingMainHandler = obj.intersecting
christianrhansen's avatar
christianrhansen committed
492
          this.tempHandler.resize.visibility = obj.intersecting
493

christianrhansen's avatar
christianrhansen committed
494
495
          // on left side
          if (Math.sign(obj.offsetLeft) === -1) {
496
497
            // this.tempHandler.resize.left = 4
            this.tempHandler.resize.side = 'left'
498
          }
christianrhansen's avatar
christianrhansen committed
499
500
          // visible
          else if (Math.sign(obj.offsetLeft) === 0) {
501
          }
christianrhansen's avatar
christianrhansen committed
502
503
          // on right side
          else if (Math.sign(obj.offsetLeft) === 1) {
504
505
            // this.tempHandler.resize.left = window.innerWidth - 40 - 4
            this.tempHandler.resize.side = 'right'
christianrhansen's avatar
christianrhansen committed
506
            // if (this.tempHandler.move.visibility === false) this.tempHandler.resize.visibility = true
507
          }
508
509
        }
      },
christianrhansen's avatar
christianrhansen committed
510
      handleMoveCell (obj) {
511
        this.handlerNewCellTemp.left = -100
christianrhansen's avatar
christianrhansen committed
512
513
        this.handlerNewCell.move.x = obj.position.left
        this.handlerNewCell.move.y = obj.position.top
514

christianrhansen's avatar
christianrhansen committed
515
516
517
518
519
        let res = this.getGridPositionForEvent(obj)

        if (obj.isFirst) {
          this.mobileTempCell.show = true
          this.mobileTempCell.button = false
christianrhansen's avatar
christianrhansen committed
520
          this.handlerNewCell.move.pushed = true
christianrhansen's avatar
christianrhansen committed
521
        }
522

christianrhansen's avatar
christianrhansen committed
523
524
525
        this.mobileTempCell.x = res.x
        this.mobileTempCell.y = res.y

526
527
528
        this.mobileTempCell.ox = res.ox
        this.mobileTempCell.oy = res.oy

christianrhansen's avatar
christianrhansen committed
529
530
        this.handlerNewCell.move.x = res.ox
        this.handlerNewCell.move.y = res.oy
531

christianrhansen's avatar
christianrhansen committed
532
533
534
        if (obj.isFinal) {
          this.mobileTempCell.onGrid = true
          this.mobileTempCell.button = true
535
          this.mobileTempCell.left = this.gridDimensions.full.cell.width * (res.x - 1)
christianrhansen's avatar
christianrhansen committed
536
537
538
539
          this.handlerNewCell.move.pushed = false
          // this.handlerNewCell.move.y = this.gridDimensions.full.cell.height * (res.y - 1) + 8 + 59 + 20
          this.handlerNewCell.move.x = this.gridDimensions.full.cell.width * (this.mobileTempCell.x - 1) + 8 + 20
          this.handlerNewCell.move.y = this.gridDimensions.full.cell.height * (this.mobileTempCell.y - 1) + 8 + 20
540
541
542

          this.handlerNewCell.resize.x = this.gridDimensions.full.cell.width * (res.x + this.mobileTempCell.width - 1) - 8 - 20
          this.handlerNewCell.resize.y = this.gridDimensions.full.cell.height * (res.y + this.mobileTempCell.height - 1) - 8 - 20
christianrhansen's avatar
christianrhansen committed
543
544
        }
      },
christianrhansen's avatar
christianrhansen committed
545
      handleResizeCell (obj) {
christianrhansen's avatar
christianrhansen committed
546
        // this.cursor = {x: obj.position.left, y: obj.position.top}
547
548
549
550
        // this.handlerNewCell.resize = {x: obj.position.left, y: obj.position.top}
        this.handlerNewCell.resize.x = obj.position.left
        this.handlerNewCell.resize.y = obj.position.top

551
552
553
554
555
556
        // ---> panGrid
        let res = this.getGridPositionForEvent(obj)

        if (obj.isFirst) {
          this.mobileTempCell.show = true
          this.mobileTempCell.button = false
557
          this.handlerNewCell.resize.pushed = true
558
559
560
561
562
        }

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

563
564
565
        this.handlerNewCell.resize.x = res.ox
        this.handlerNewCell.resize.y = res.oy

566
567
568
        if (obj.isFinal) {
          this.mobileTempCell.onGrid = true
          this.mobileTempCell.button = true
569
          this.handlerNewCell.resize.pushed = false
570
571
          // this.addMobileCell(obj)
          // this.mobileTempCell.show = false
572
573
          this.handlerNewCell.resize.x = this.gridDimensions.full.cell.width * res.x - 8 - 20
          this.handlerNewCell.resize.y = this.gridDimensions.full.cell.height * res.y - 8 - 20
574
575
        }
      },
576
577
578
579
      clearCachedCell () {
        this.$store.commit('mosys/cacheNewCell', undefined)
        this.clearTempCell()
      },
580
581
582
583
      handleCellInfoTouch (event, annotation) {
        this.touchMobileCell(event, annotation)
        this.handleModal()
      },
584
585
586
587
      getCarouselIcon (val) {
        console.log(val)
      },
      carouselVisibility () {
588
589
590
591
        console.log(this.carousel.slide)
        if (this.$refs.carousel) {
          this.$refs.carousel.goToSlide(this.carousel.slide)
        }
592
593
        this.carousel.visibility = !this.carousel.visibility
      },
594
595
596
      handleModal () {
        this.modal = !this.modal
      },
597
      clearTempCell () {
598
        this.mobileTempCell = {x: undefined, y: undefined, width: undefined, height: undefined, onGrid: false, button: false}
599
      },
600
      panGrid (obj) {
601
        if (this.cachedNewCell && !this.mobileTempCell.onGrid) {
602
          // console.log('hhhhhhhhhhhhhhhhh', obj)
603
604
605
606
          let res = this.getGridPositionForEvent(obj)

          if (obj.isFirst) {
            this.mobileTempCell.show = true
607
            this.mobileTempCell.button = false
608
609
610
611
612
613
614
615
            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) {
616
            this.mobileTempCell.onGrid = true
617
            this.mobileTempCell.button = true
618
619
            // this.addMobileCell(obj)
            // this.mobileTempCell.show = false
christianrhansen's avatar
christianrhansen committed
620
621
            this.handlerNewCell.move.x = this.gridDimensions.full.cell.width * (this.mobileTempCell.x - 1) + 8 + 20
            this.handlerNewCell.move.y = this.gridDimensions.full.cell.height * (this.mobileTempCell.y - 1) + 8 + 20
622
623
624

            this.handlerNewCell.resize.x = this.gridDimensions.full.cell.width * res.x - 8 - 20
            this.handlerNewCell.resize.y = this.gridDimensions.full.cell.height * res.y - 8 - 20
625
          }
626
        }
627
      },
628
      async cellHold (event, annotation) {
629
630
        this.$store.commit('mosys/setEditingCells', '')

631
        this.$q.notify({
632
          message: 'Copied.',
633
          color: 'dark',
634
635
          textColor: 'white',
          position: 'bottom-right'
636
637
638
639
640
641
642
643
644
645
        })

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

690
691
        let
          parsed = annotation.target.selector.parse(),
692
          sliced = parsed.xywh.slice(0, 4),
693
          x = sliced[0],
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
          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

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

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

733
734
735
736
737
738
739
740
        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)
      },
741
742
743
744
      //
      // DATA
      //

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

      //
      // GRID DRAG & DROP HANDLERS
      //

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

902
          this.tmpObjects = []
Anton's avatar
Intial  
Anton committed
903
904
          event.preventDefault()
        }
905
        this.clearTempCell()
Anton's avatar
Intial  
Anton committed
906
      },
907
908
909
910

      //
      // CELL DRAG & DROP HANDLERS
      //
Mathias Bär's avatar
Mathias Bär committed
911
912
913
      handleCellEditClick (event, cell) {
        this.annotationUIStates[cell._uuid].editing = !this.annotationUIStates[cell._uuid].editing
        this.updateEditingCells()
914
        this.$root.$emit('mosys_saveScrollPosition')
Mathias Bär's avatar
Mathias Bär committed
915
      },
916
917
918
919
920
      handleCellClick (event, cell) {
        this.annotationUIStates[cell._uuid].selected = !this.annotationUIStates[cell._uuid].selected
        this.updateSelectedCells()
      },
      handleCellDragStart (event, annotation) {
christianrhansen's avatar
christianrhansen committed
921
        console.log('§§§§§§§§', annotation)
922
923
924
925
926
927
928
929
930
931
932
933
        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
934
          }
935
          this.tmpObjects.push(annotation)
936
937
938
        }
      },
      handleCellDragEnd (event, annotation) {
939
940
941
        if (!this.mobile) {
          this.annotationUIStates[annotation._uuid].beingDragged = false
        }
942
943
944
945
      },
      async handleCellContextMenuDelete (event, annotation) {
        this.annotationUIStates[annotation._uuid].selected = false
        this.updateSelectedCells()
Mathias Bär's avatar
Mathias Bär committed
946
        this.updateEditingCells()
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967