Skip to content
Snippets Groups Projects
NodesLayer.vue 14.4 KiB
Newer Older
Adam Procter's avatar
Adam Procter committed
<template>
Adam Procter's avatar
Adam Procter committed
  <div ref="nodes" class="node">
    <div v-if="toolmode == 'move'">
      <div v-for="(value, index) in $options.positionsArray" v-bind:key="index">
        <div v-for="(nodes, index) in $options.myArray" v-bind:key="index">
          <draggable
            class="innernode"
            v-if="nodes.node_id == value.node_id"
            :w="value.width"
            :h="value.height"
            :x="value.x_pos"
            :y="value.y_pos"
            :z="value.z_index"
            :scale="scale"
Adam Procter's avatar
Adam Procter committed
            @activated="onActivated(nodes.node_id, value.z_index)"
            :draggable="false"
            :resizable="false"
            @dragging="onDrag"
            @resizing="onResize"
            @dragstop="onDragstop"
            @resizestop="onResizestop"
            :drag-cancel="'.drag-cancel'"
Adam Procter's avatar
Adam Procter committed
            :style="{
              border: border,
              backgroundColor: nodes.color,
            }"
            :min-width="200"
            :min-height="220"
          >
            <form class="nodes">
              <template v-if="nodes.read_mode == false">
                <textarea
                  @focus="editTrue(true)"
                  @blur="editTrue(false)"
                  autofocus
                  v-model="nodes.node_text"
                  @input="editNode"
                  :id="nodes.node_id"
                  placeholder="Type your thoughts and ideas here! (auto saved every keystroke)"
                ></textarea>
                <p class="info">*markdown supported &amp; autosaves</p>
              </template>
              <template v-else>
                <p
                  :id="nodes.node_id"
                  :inner-html.prop="nodes.node_text | marked"
                ></p>
              </template>
              <template v-if="toolmode == 'select'">
                <div class="btn-row">
                  <SvgButton
                    buttonClass="nodes"
                    @click.prevent="deleteFlag(nodes.node_id)"
                  />
                  <SvgButton2
                    buttonClass="nodes"
                    @click.prevent="readFlag(nodes.node_id, nodes.read_mode)"
                  />
                </div>
              </template>

              <div class="allemoji">
                <div
                  class="eachemoji"
                  v-for="(emojis, index) in configEmoji"
                  :key="index"
                >
                  <template v-if="emojis.node_id == nodes.node_id">{{
                    emojis.emoji_text
                  }}</template>
                </div>
Adam Procter's avatar
Adam Procter committed
              </div>
            </form>
          </draggable>
        </div>
      </div>
    </div>

    <!-- IF NOT MOVE -->

    <div v-if="toolmode != 'move'">
      <div v-for="(value, index) in $options.positionsArray" v-bind:key="index">
        <div v-for="(nodes, index) in $options.myArray" v-bind:key="index">
          <draggable
            class="innernode"
            v-if="nodes.node_id == value.node_id"
            :w="value.width"
            :h="value.height"
            :x="value.x_pos"
            :y="value.y_pos"
            :z="value.z_index"
            :scale="scale"
Adam Procter's avatar
Adam Procter committed
            @activated="onActivated(nodes.node_id, value.z_index)"
            @dragging="onDrag"
            @resizing="onResize"
            @dragstop="onDragstop"
            @resizestop="onResizestop"
            :drag-cancel="'.drag-cancel'"
Adam Procter's avatar
Adam Procter committed
            :style="{
              border: border,
              backgroundColor: nodes.color,
            }"
            :min-width="200"
            :min-height="220"
          >
            <form class="nodes">
              <template v-if="nodes.read_mode == false">
                <textarea
Adam Procter's avatar
Adam Procter committed
                  class="drag-cancel"
                  @focus="editTrue(true)"
                  @blur="editTrue(false)"
                  autofocus
                  v-model="nodes.node_text"
                  @input="editNode"
                  :id="nodes.node_id"
                  placeholder="Type your thoughts and ideas here! (auto saved every keystroke)"
                ></textarea>
                <p class="info">*markdown supported &amp; autosaves</p>
              </template>
              <template v-else>
                <p
                  :id="nodes.node_id"
                  :inner-html.prop="nodes.node_text | marked"
                ></p>
              </template>
              <template v-if="toolmode == 'select'">
                <div class="btn-row">
                  <SvgButton
                    buttonClass="nodes"
                    @click.prevent="deleteFlag(nodes.node_id)"
                  />
                  <SvgButton2
                    buttonClass="nodes"
                    @click.prevent="readFlag(nodes.node_id, nodes.read_mode)"
                  />
                  <v-swatches
                    v-model="color"
                    @input="chooseColor(color, nodes.node_id)"
                    :swatches="swatches"
                    :shapes="shapes"
                    show-border
                    show-fallback
                    fallback-input-type="color"
                  >
                    <SvgButton3
                      buttonClass="nodes"
                      @click.prevent
                      slot="trigger"
                    />
                  </v-swatches>
                </div>
              </template>
              <div class="allemoji">
                <div
                  class="eachemoji"
                  v-for="(emojis, index) in configEmoji"
                  :key="index"
                >
                  <template v-if="emojis.node_id == nodes.node_id">{{
                    emojis.emoji_text
                  }}</template>
                </div>
              </div>
            </form>
          </draggable>
        </div>
Adam Procter's avatar
Adam Procter committed
      </div>
Adam Procter's avatar
Adam Procter committed
    </div>
Adam Procter's avatar
Adam Procter committed
  </div>
</template>

<script>
Adam Procter's avatar
Adam Procter committed
import { mapState } from 'vuex'
Adam Procter's avatar
Adam Procter committed
import marked from 'marked'
Adam Procter's avatar
Adam Procter committed
import SvgButton from '@/components/SvgButton'
import SvgButton2 from '@/components/SvgButton2'
import SvgButton3 from '@/components/SvgButton3'
import draggable from '@/experimental/Draggable'
Adam Procter's avatar
Adam Procter committed
import VSwatches from 'vue-swatches'
import 'vue-swatches/dist/vue-swatches.css'
var readmode
Adam Procter's avatar
Adam Procter committed

export default {
  name: 'NodesLayer',
Adam Procter's avatar
Adam Procter committed
  data() {
    return {
Adam Procter's avatar
Adam Procter committed
      border: '2px dashed black',
      color: '#9bc2d8',
      shapes: 'circles',

      // swatches: [{ color: '#F493A7', showBorder: true }],
      swatches: [
        ['#EB5757', '#F2994A', '#F2C94C'],
        ['#219653', '#27AE60', '#6FCF97'],
        ['#2F80ED', '#2D9CDB', '#56CCF2'],
        ['#9B51E0', '#BB6BD9', '#E9B7FC'],
      ],
      pickupz: 1,
Adam Procter's avatar
Adam Procter committed
      localreadmode: false,
      mode: '',
      myArray: null,
      positionsArray: null,
Adam Procter's avatar
Adam Procter committed

  filters: {
Adam Procter's avatar
Adam Procter committed
    marked: marked,
Adam Procter's avatar
Adam Procter committed
  },

Adam Procter's avatar
Adam Procter committed
  // FIXME: how do we know how to focus on the newest node ?
  // FIXME: Tab between them would also be good
  // var delay = 100
  // var input
  // mounted() {
  //   setTimeout(this.setFocus, delay)
  //   input = this.$refs.nodetext
Adam Procter's avatar
Adam Procter committed
  //   // console.log(input)
Adam Procter's avatar
Adam Procter committed
  // },
  // method
  // setFocus() {
  //   this.$refs.nodetext.focus()
  // },
Adam Procter's avatar
Adam Procter committed

Adam Procter's avatar
Adam Procter committed
  computed: {
    ...mapState({
      scale: (state) => state.ui.scale,
      myNodes: (state) => state.myNodes,
      configPositions: (state) => state.configPositions,
      configConnections: (state) => state.configConnections,
      configEmoji: (state) => state.configEmoji,
      toolmode: (state) => state.ui.mode,
    }),

    nodes_filtered: function () {
      return this.myNodes.filter((nodes) => {
        // backwards compatablity fix
        if (nodes.color == undefined || '') {
          nodes.color = '#A4C2D6'
        }
Adam Procter's avatar
Adam Procter committed
        return nodes.deleted == false
      })
    },
    // this is not working correctly as dragging around moves wrong things
    positions_filtered: function () {
      return this.configPositions.filter((positions) => {
        return this.myNodes.some((node) => {
          return positions.node_id == node.node_id
Adam Procter's avatar
Adam Procter committed
  },
  // this is to stop sync chasing bug
  mounted() {
    const unwatch = this.$watch('nodes_filtered', (value) => {
      this.$options.myArray = this.nodes_filtered
      // this.$options.positionsArray = this.positions_filtered
      this.$forceUpdate()
      // ignore falsy values
      if (!value) return

      // stop watching when nodes_filtered[] is not empty
      if (value && value.length) unwatch()

      // process value here
    })

    const unwatchtwo = this.$watch('positions_filtered', (value) => {
      // this.$options.myArray = this.nodes_filtered
      this.$options.positionsArray = this.positions_filtered
      this.$forceUpdate()
      // ignore falsy values
      if (!value) return

      // stop watching when nodes_filtered[] is not empty
      if (value && value.length) unwatchtwo()

      // process value here
    })
Adam Procter's avatar
Adam Procter committed
  },

    this.$options.positionsArray = this.positions_filtered
    if (this.toolmode == 'addNode') {
      setTimeout(this.loadData, 300)
      // this.$options.myArray = this.nodes_filtered
      this.$store.commit('ui/setMode', 'select')
    }
Adam Procter's avatar
Adam Procter committed
  methods: {
Adam Procter's avatar
Adam Procter committed
    chooseColor(color, nodeid) {
      this.$store.dispatch('colorNode', { nodeid, color })
      this.$options.myArray = this.nodes_filtered
    },

    loadData() {
      this.$options.myArray = this.nodes_filtered
      this.$options.positionsArray = this.positions_filtered
      this.$forceUpdate()
    },
Adam Procter's avatar
Adam Procter committed
    onActivated(id, zindex) {
      this.zindex = zindex
      this.nodeid = id
Adam Procter's avatar
Adam Procter committed
      var zindexes = []

      for (i = 0; i < Object.keys(this.configPositions).length; i++) {
        zindexes.push(this.configPositions[i].z_index)
        if (this.configPositions[i].node_id == this.nodeid) {
          this.width = this.configPositions[i].width
          this.height = this.configPositions[i].height
          this.zindex = this.configPositions[i].z_index
        }
Adam Procter's avatar
Adam Procter committed
        // console.log(zindexes)
Adam Procter's avatar
Adam Procter committed
      }
      var topZ = Math.max(...zindexes)

      for (i = 0; i < Object.keys(this.configPositions).length; i++) {
        if (topZ > 2147483640) {
          this.configPositions[i].z_index = 0
        }

        if (this.configPositions[i].node_id == this.nodeid) {
          this.width = this.configPositions[i].width
          this.height = this.configPositions[i].height
          this.configPositions[i].z_index = topZ + 1
    onResize(x, y, width, height) {
Adam Procter's avatar
Adam Procter committed
      this.localx = x
      this.localy = y
Adam Procter's avatar
Adam Procter committed
      this.width = width
      this.height = height
    },
Adam Procter's avatar
Adam Procter committed
    onResizestop(x, y, width, height) {
      // var nodecontentHeight = document.getElementById(this.nodeid).clientHeight

      var localnodeid = this.nodeid
Adam Procter's avatar
Adam Procter committed
      var zindex
      for (i = 0; i < Object.keys(this.configPositions).length; i++) {
        if (this.configPositions[i].node_id == this.nodeid) {
          this.width = this.configPositions[i].width
          this.height = this.configPositions[i].height
Adam Procter's avatar
Adam Procter committed
          zindex = this.configPositions[i].z_index
        }
      }
      this.width = width
      this.height = height

      // if (nodecontentHeight > this.height) {
      //   height = nodecontentHeight + 150
      // }

      this.$store.dispatch('movePos', {
        localnodeid,
        x,
        y,
        width,
        height,
Adam Procter's avatar
Adam Procter committed
        zindex,
    onDrag(x, y) {
Adam Procter's avatar
Adam Procter committed
      this.localx = x
      this.localy = y
Adam Procter's avatar
Adam Procter committed
    },
Adam Procter's avatar
Adam Procter committed
    onDragstop(x, y, width, height) {
Adam Procter's avatar
Adam Procter committed
      var nodecontentHeight = document.getElementById(this.nodeid).clientHeight

      var localnodeid = this.nodeid
Adam Procter's avatar
Adam Procter committed
      var zindex
      width = this.width
      height = this.height
Adam Procter's avatar
Adam Procter committed
      var i
Adam Procter's avatar
Adam Procter committed
      if (nodecontentHeight > this.height) {
        this.height = nodecontentHeight + 150
      }
      // FIXME: What is this for loop doing ??
Adam Procter's avatar
Adam Procter committed
      for (i = 0; i < Object.keys(this.configPositions).length; i++) {
        if (this.configPositions[i].node_id == this.nodeid) {
          this.localx = this.configPositions[i].x_pos
          this.localy = this.configPositions[i].y_pos
Adam Procter's avatar
Adam Procter committed
          zindex = this.configPositions[i].z_index
Adam Procter's avatar
Adam Procter committed
        }
      }
      this.$store.dispatch('movePos', {
        localnodeid,
        x,
        y,
        width,
        height,
Adam Procter's avatar
Adam Procter committed
        zindex,
Adam Procter's avatar
Adam Procter committed

      var j
      for (j = 0; j < Object.keys(this.configConnections).length; j++) {
        if (this.configConnections[j].start_id == this.nodeid) {
          this.$store.dispatch('updateConnect', {
            localnodeid,
            x,
            y,
          })
        }
        if (this.configConnections[j].end_id == this.nodeid) {
          this.$store.dispatch('updateConnectTwo', {
            localnodeid,
            x,
            y,
          })
        }
      }
Adam Procter's avatar
Adam Procter committed
      this.$options.myArray = this.nodes_filtered
Adam Procter's avatar
Adam Procter committed
    editTrue(e) {
Adam Procter's avatar
Adam Procter committed
      this.$emit('edit-true', e)
Adam Procter's avatar
Adam Procter committed
    },
Adam Procter's avatar
Adam Procter committed
    editNode(e) {
Adam Procter's avatar
Adam Procter committed
      var nodeid = e.target.id
      var nodetext = e.target.value
      this.$store.dispatch('editNode', { nodeid, nodetext })
Adam Procter's avatar
Adam Procter committed
    },
    deleteFlag(e) {
Adam Procter's avatar
Adam Procter committed
      if (confirm('Confirm discard?')) {
        this.$store.dispatch('deleteFlag', { e })
        this.$options.myArray = this.nodes_filtered
Adam Procter's avatar
Adam Procter committed
      } else {
        // nothing happens
      }
Adam Procter's avatar
Adam Procter committed
    },
Adam Procter's avatar
Adam Procter committed
    readFlag(e, f) {
      readmode = f
      readmode = !readmode
      this.$store.dispatch('readFlag', { e, readmode })
      this.$options.myArray = this.nodes_filtered
Adam Procter's avatar
Adam Procter committed
      if (readmode == true) {
Adam Procter's avatar
Adam Procter committed
        this.mode = 'Read'
      } else {
        this.mode = 'Edit'
      }
Adam Procter's avatar
Adam Procter committed
    },
  },
  components: {
    draggable,
Adam Procter's avatar
Adam Procter committed
    SvgButton,
    SvgButton2,
Adam Procter's avatar
Adam Procter committed
    VSwatches,
Adam Procter's avatar
Adam Procter committed
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
Adam Procter's avatar
Adam Procter committed
.node {
Adam Procter's avatar
Adam Procter committed
  position: relative;
}

.vdr {
  padding: 0 0.5em;
}

Adam Procter's avatar
Adam Procter committed
.info {
  font-size: 0.8em;
Adam Procter's avatar
Adam Procter committed
  display: inline;
Adam Procter's avatar
Adam Procter committed
}

textarea {
  width: 100%;
Adam Procter's avatar
Adam Procter committed
  height: 175px;
Adam Procter's avatar
Adam Procter committed
  resize: none;
Adam Procter's avatar
Adam Procter committed
  font-size: 18px;
Adam Procter's avatar
Adam Procter committed
  box-sizing: border-box;
  font-family: 'Inter var', Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
Adam Procter's avatar
Adam Procter committed
  margin-top: 0.5em;
Adam Procter's avatar
Adam Procter committed
  border: none;
  outline: none;
  background-color: rgb(187, 227, 255);
  scrollbar-color: yellow rgb(187, 227, 255);
Adam Procter's avatar
Adam Procter committed
}

.btn-row {
  position: relative;
  margin-bottom: 5px;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  padding: 0 15px;
  border-radius: 4px;
Adam Procter's avatar
Adam Procter committed
}

.allemoji {
  font-size: 2em;
Adam Procter's avatar
Adam Procter committed
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(0, auto));

Adam Procter's avatar
Adam Procter committed
  /* float: left; */
Adam Procter's avatar
Adam Procter committed
.eachemoji p {
  margin: 0em;
}

img {
  width: 100%;
}
Adam Procter's avatar
Adam Procter committed

li {
  font-size: 6em;
}
/* .dragging {
  transform: scale(0.7);
} */
Adam Procter's avatar
Adam Procter committed
</style>