GridEditor.vue 48.6 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)
christianrhansen's avatar
christianrhansen committed
147
          cell-handler-mobile.main-handler(
148
          v-if="!handlerNewCell.resize.pushed",
149
150
151
          @onIntersectionChange="intersectionChanged",
          :element="'move'",
          v-touch-pan="handleMoveCell",
christianrhansen's avatar
christianrhansen committed
152
          :style="{left: handlerNewCell.move.x - 20 + 'px', top: handlerNewCell.move.y - 20 + 'px'}",
153
          :class="[{'pushed': !handlerNewCell.move.pushed}, {'hide': !mobileTempCell.onGrid}]")
christianrhansen's avatar
christianrhansen committed
154
155
            q-icon.self-center.rotate-180(name="open_with", size="22px")

156
          //----- (temp)
157
          //----- (when main move handler is outside of viewport)
christianrhansen's avatar
christianrhansen committed
158
          cell-handler-mobile.temp-handler(
159
          v-touch-pan="handleMoveCell",
160
          :doubleTap="{el: $el, type: 'scroll', oLeft: mobileTempCell.left}",
christianrhansen's avatar
christianrhansen committed
161
          :class="[(!mobileTempCell.onGrid || tempHandler.move.intersectingMain || handlerNewCell.resize.pushed || handlerNewCell.move.pushed ? 'hide': 'show'), (tempHandler.move.side === 'left' ? 'left-side' : 'right-side')]",
162
          :style="{top: handlerNewCell.move.y + 59 - 20 + 'px'}",)
163
164
            q-icon.self-center.rotate-180(name="open_with", size="22px")

165
166
          //--------------------------------------------------------------------------------------------- resize handler
          //----- (main)
christianrhansen's avatar
christianrhansen committed
167
          cell-handler-mobile.main-handler(
168
          v-if="!handlerNewCell.move.pushed",
169
170
171
          @onIntersectionChange="intersectionChanged",
          :element="'resize'",
          v-touch-pan="handleResizeCell",
172
          :style="{left: handlerNewCell.resize.x - 20 + 'px', top: handlerNewCell.resize.y - 20 + 'px'}",
173
          :class="[{'pushed': !handlerNewCell.resize.pushed}, {'hide': !mobileTempCell.onGrid}]")
174
            q-icon.self-center(name="signal_cellular_4_bar", size="12px", style="margin-left: -3px;")
175

176
177
          //----- (temp)
          //----- (when main resize handler is outside of viewport)
christianrhansen's avatar
christianrhansen committed
178
          cell-handler-mobile.temp-handler(
179
          v-touch-pan="handleResizeCell",
christianrhansen's avatar
christianrhansen committed
180
          :class="[(!mobileTempCell.onGrid || tempHandler.resize.intersectingMain || handlerNewCell.move.pushed || handlerNewCell.resize.pushed ? 'hide': 'show'), (tempHandler.resize.side === 'left' ? 'left-side' : 'right-side')]",
181
          :style="{top: handlerNewCell.resize.y + 59 - 20 + 'px'}",)
182
183
            q-icon.self-center(name="signal_cellular_4_bar", size="12px", style="margin-left: -3px;")

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

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

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

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

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

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

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

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

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

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

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

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

452
        // -------------------- move
453
        if (obj.element === 'move') {
christianrhansen's avatar
christianrhansen committed
454
          this.tempHandler.move.intersectingMain = obj.intersecting
455

christianrhansen's avatar
christianrhansen committed
456
          // behind left side
christianrhansen's avatar
christianrhansen committed
457
          if (_offsetLeft < 0) {
458
            this.tempHandler.move.side = 'left'
459
          }
460
          // intersecting
christianrhansen's avatar
christianrhansen committed
461
          else if (isNaN(_offsetLeft)) {
462
            if (this.tempHandler.move.intersectingMain && this.tempHandler.move.side === 'right') this.tempHandler.resize.intersectingMain = false
463
          }
christianrhansen's avatar
christianrhansen committed
464
          // behind right side
christianrhansen's avatar
christianrhansen committed
465
          else if (_offsetLeft === 1) {
466
            this.tempHandler.move.side = 'right'
467
            this.tempHandler.resize.intersectingMain = true
468
          }
469
        }
470

471
        // -------------------- resize
christianrhansen's avatar
christianrhansen committed
472
        else if (obj.element === 'resize') {
christianrhansen's avatar
christianrhansen committed
473
          this.tempHandler.resize.intersectingMain = obj.intersecting
474

christianrhansen's avatar
christianrhansen committed
475
          // on left side
christianrhansen's avatar
christianrhansen committed
476
          if (_offsetLeft === -1) {
477
            this.tempHandler.resize.side = 'left'
478
          }
christianrhansen's avatar
christianrhansen committed
479
          /*
480
          // intersecting
christianrhansen's avatar
christianrhansen committed
481
          else if (isNaN(Math.sign(obj.offsetLeft))) {
482
          }
christianrhansen's avatar
christianrhansen committed
483
          */
christianrhansen's avatar
christianrhansen committed
484
          // on right side
christianrhansen's avatar
christianrhansen committed
485
          else if (_offsetLeft === 1) {
486
            this.tempHandler.resize.side = 'right'
487
          }
488
489
        }
      },
christianrhansen's avatar
christianrhansen committed
490
      handleMoveCell (obj) {
491
        this.handlerNewCellTemp.left = -100
christianrhansen's avatar
christianrhansen committed
492
493
        this.handlerNewCell.move.x = obj.position.left
        this.handlerNewCell.move.y = obj.position.top
494

christianrhansen's avatar
christianrhansen committed
495
496
497
498
499
        let res = this.getGridPositionForEvent(obj)

        if (obj.isFirst) {
          this.mobileTempCell.show = true
          this.mobileTempCell.button = false
christianrhansen's avatar
christianrhansen committed
500
          this.handlerNewCell.move.pushed = true
christianrhansen's avatar
christianrhansen committed
501
        }
502

christianrhansen's avatar
christianrhansen committed
503
504
505
        this.mobileTempCell.x = res.x
        this.mobileTempCell.y = res.y

506
507
508
        this.mobileTempCell.ox = res.ox
        this.mobileTempCell.oy = res.oy

christianrhansen's avatar
christianrhansen committed
509
510
        this.handlerNewCell.move.x = res.ox
        this.handlerNewCell.move.y = res.oy
511

christianrhansen's avatar
christianrhansen committed
512
513
514
        if (obj.isFinal) {
          this.mobileTempCell.onGrid = true
          this.mobileTempCell.button = true
515
          this.mobileTempCell.left = this.gridDimensions.full.cell.width * (res.x - 1)
christianrhansen's avatar
christianrhansen committed
516
517
518
519
          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
520
521
522

          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
523
524
        }
      },
christianrhansen's avatar
christianrhansen committed
525
      handleResizeCell (obj) {
christianrhansen's avatar
christianrhansen committed
526
        // this.cursor = {x: obj.position.left, y: obj.position.top}
527
528
529
530
        // 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

531
532
533
534
535
536
        // ---> panGrid
        let res = this.getGridPositionForEvent(obj)

        if (obj.isFirst) {
          this.mobileTempCell.show = true
          this.mobileTempCell.button = false
537
          this.handlerNewCell.resize.pushed = true
538
539
540
541
542
        }

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

543
544
545
        this.handlerNewCell.resize.x = res.ox
        this.handlerNewCell.resize.y = res.oy

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

          if (obj.isFirst) {
            this.mobileTempCell.show = true
587
            this.mobileTempCell.button = false
588
589
590
591
592
593
594
595
            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) {
596
            this.mobileTempCell.onGrid = true
597
            this.mobileTempCell.button = true
598
599
            // this.addMobileCell(obj)
            // this.mobileTempCell.show = false
christianrhansen's avatar
christianrhansen committed
600
601
            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
602
603
604

            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
605
          }
606
        }
607
      },
608
      async cellHold (event, annotation) {
609
610
        this.$store.commit('mosys/setEditingCells', '')

611
        this.$q.notify({
612
          message: 'Copied.',
613
          color: 'dark',
614
615
          textColor: 'white',
          position: 'bottom-right'
616
617
618
619
620
621
622
623
624
625
        })

        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
626
627
      moveCachedCell (obj) {
        this.touch.position = {top: obj.position.top, left: obj.position.left}
628
629
630
631
632
633
634
635
636
        /*
        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
637
      },
638
639
      addMobileCell (event) {
        // console.log('addMobileCell()', event, annotation)
christianrhansen's avatar
christianrhansen committed
640
        if (this.cachedNewCell) {
641
          this.handleGridDrop(event)
christianrhansen's avatar
christianrhansen committed
642
          this.$store.commit('mosys/cacheNewCell', undefined)
643
644
          this.$q.notify({
            message: 'Cell was added.',
645
646
647
            color: 'dark',
            position: 'center',
            timeout: 50
648
          })
christianrhansen's avatar
christianrhansen committed
649
650
        }
      },
651
652
653
654
655
656
657
658
659
660
      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
661
      handleCellTouch (event, annotation) {
662
663
664
665
        if (!this.cachedNewCell) {
          console.log(event, annotation)
          this.mobileSelectedCell = annotation
        }
christianrhansen's avatar
christianrhansen committed
666
      },
667
      async mobileCellMove (annotation, _x, _y) {
668
669
        this.$el.scrollLeft = this.$el.scrollLeft + (this.gridDimensions.full.cell.width * _x)

670
671
        let
          parsed = annotation.target.selector.parse(),
672
          sliced = parsed.xywh.slice(0, 4),
673
          x = sliced[0],
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
          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

689
690
691
692
693
694
695
696
        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 }
          }
        }])
      },
697
      async mobileCellResize (annotation, _w, _h) {
698
699
700
        let
          parsed = annotation.target.selector.parse(),
          [x, y, w, h] = parsed.xywh
701
702
703
704
705
706
707
708
709
710
711
712

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

713
714
715
716
717
718
719
720
        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)
      },
721
722
723
724
      //
      // DATA
      //

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

      //
      // GRID DRAG & DROP HANDLERS
      //

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

882
          this.tmpObjects = []
Anton's avatar
Intial  
Anton committed
883
884
          event.preventDefault()
        }
885
        this.clearTempCell()
Anton's avatar
Intial  
Anton committed
886
      },
887
888
889
890

      //
      // CELL DRAG & DROP HANDLERS
      //
Mathias Bär's avatar
Mathias Bär committed
891
892
893
      handleCellEditClick (event, cell) {
        this.annotationUIStates[cell._uuid].editing = !this.annotationUIStates[cell._uuid].editing
        this.updateEditingCells()
894
        this.$root.$emit('mosys_saveScrollPosition')
Mathias Bär's avatar
Mathias Bär committed
895
      },
896
897
898
899
900
      handleCellClick (event, cell) {
        this.annotationUIStates[cell._uuid].selected = !this.annotationUIStates[cell._uuid].selected
        this.updateSelectedCells()
      },
      handleCellDragStart (event, annotation) {
christianrhansen's avatar
christianrhansen committed
901
        console.log('§§§§§§§§', annotation)
902
903
904
905
906
907
908
909
910
911
912
913
        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
914
          }
915
          this.tmpObjects.push(annotation)
916
917
918
        }
      },
      handleCellDragEnd (event, annotation) {
919
920
921
        if (!this.mobile) {
          this.annotationUIStates[annotation._uuid].beingDragged = false
        }
922
923
924
925
      },
      async handleCellContextMenuDelete (event, annotation) {
        this.annotationUIStates[annotation._uuid].selected = false
        this.updateSelectedCells()
Mathias Bär's avatar
Mathias Bär committed
926
        this.updateEditingCells()
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
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
        await this.$store.dispatch('cells/delete', annotation.body.source.id)
        await this.$store.dispatch('