<template>
  <div class="mt-6">
    <div>
      <v-btn
        depressed
        tile
        :color="isEmpty ? null : 'primary'"
        @click="toggleReveal"
      >
        Wiki<v-icon
          right
          v-text="reveal ? '$sockiEyeSlash' : '$sockiEye'"
        ></v-icon
      ></v-btn>
    </div>
    <template v-if="reveal">
      <template v-if="!readonly">
        <div class="mt-2">
          <v-btn
            text
            :outlined="currentView == view.WIKI_VIEW"
            @click="currentView = view.WIKI_VIEW"
          >
            <v-icon>$sockiEye</v-icon>
          </v-btn>
          <v-btn
            text
            :outlined="currentView == view.DESIGN_VIEW"
            data-cy="wikiDesignView"
            @click="currentView = view.DESIGN_VIEW"
          >
            <v-icon>$sockiEdit</v-icon>
          </v-btn>
          <v-btn
            text
            :outlined="currentView == view.SPLIT_VIEW"
            @click="currentView = view.SPLIT_VIEW"
          >
            <v-icon>$sockiColumns</v-icon>
          </v-btn>
        </div>
      </template>
      <v-sheet
        v-if="currentView != view.HIDDEN_VIEW"
        elevation="2"
        class="aywiki pa-2 pa-sm-6 mt-2"
      >
        <v-row v-resize="onResize">
          <!-- BUTTONS -->
          <v-col v-if="showDesigner()" :cols="12">
            <div>
              <v-btn depressed tile @click="editClick('bold')">
                <v-icon>$sockiBold</v-icon></v-btn
              >
              <v-btn depressed tile @click="editClick('italic')">
                <v-icon>$sockiItalic</v-icon></v-btn
              >
              <v-btn depressed tile @click="editClick('strike')">
                <v-icon>$sockiStrikethrough</v-icon></v-btn
              >

              <!-- HEADINGS -->
              <v-menu offset-y>
                <template v-slot:activator="{ on }">
                  <v-btn depressed tile v-on="on">
                    <v-icon>$sockiHeading</v-icon>
                  </v-btn>
                </template>
                <v-list>
                  <v-list-item @click="editClick('heading', 1)">
                    <v-list-item-title
                      ><h1>{{ $sock.t("Heading") }} 1</h1></v-list-item-title
                    >
                  </v-list-item>
                  <v-list-item @click="editClick('heading', 2)">
                    <v-list-item-title
                      ><h2>{{ $sock.t("Heading") }} 2</h2></v-list-item-title
                    >
                  </v-list-item>
                  <v-list-item @click="editClick('heading', 3)">
                    <v-list-item-title
                      ><h3>{{ $sock.t("Heading") }} 3</h3></v-list-item-title
                    >
                  </v-list-item>
                  <v-list-item @click="editClick('heading', 4)">
                    <v-list-item-title
                      ><h4>{{ $sock.t("Heading") }} 4</h4></v-list-item-title
                    >
                  </v-list-item>
                  <v-list-item @click="editClick('heading', 5)">
                    <v-list-item-title
                      ><h5>{{ $sock.t("Heading") }} 5</h5></v-list-item-title
                    >
                  </v-list-item>
                  <v-list-item @click="editClick('heading', 6)">
                    <v-list-item-title
                      ><h6>{{ $sock.t("Heading") }} 6</h6></v-list-item-title
                    >
                  </v-list-item>
                </v-list>
              </v-menu>
              <!-- /HEADINGS -->

              <!-- MORE BUTTONS -->
              <v-btn depressed tile class="ml-1" @click="editClick('line')">
                <v-icon>$sockiMinus</v-icon></v-btn
              >
              <v-btn depressed tile @click="editClick('quote')">
                <v-icon>$sockiQuoteLeft</v-icon></v-btn
              >
              <v-btn depressed tile @click="editClick('ul')">
                <v-icon>$sockiListUl</v-icon></v-btn
              >
              <v-btn depressed tile @click="editClick('ol')">
                <v-icon>$sockiListOl</v-icon></v-btn
              >
              <v-btn depressed tile @click="editClick('task')">
                <v-icon>$sockiCheckSquare</v-icon></v-btn
              >

              <!-- TABLES -->
              <v-menu
                v-model="tableMenu"
                :close-on-content-click="false"
                offset-y
              >
                <template v-slot:activator="{ on }">
                  <v-btn depressed tile class="ml-1" v-on="on">
                    <v-icon>$sockiTable</v-icon>
                  </v-btn>
                </template>
                <v-card width="300">
                  <v-card-title>{{ $sock.t("Table") }}</v-card-title>

                  <div class="ma-8">
                    <v-slider
                      v-model="tableMenuColumns"
                      thumb-size="24"
                      thumb-label="always"
                      min="1"
                      max="10"
                      prepend-icon="$sockiArrowsAltH"
                    ></v-slider>

                    <v-slider
                      v-model="tableMenuRows"
                      prepend-icon="$sockiArrowsAltV"
                      class="mt-8"
                      thumb-size="24"
                      thumb-label="always"
                      min="1"
                      max="15"
                    ></v-slider>
                  </div>

                  <v-card-actions>
                    <v-spacer></v-spacer>

                    <v-btn text @click="tableMenu = false">{{
                      $sock.t("Cancel")
                    }}</v-btn>
                    <v-btn color="primary" text @click="editClick('table')">{{
                      $sock.t("OK")
                    }}</v-btn>
                  </v-card-actions>
                </v-card>
              </v-menu>
              <!-- /TABLES -->

              <!-- LINK -->
              <v-btn depressed tile @click="openLinkMenu">
                <v-icon>$sockiLink</v-icon>
              </v-btn>
              <v-menu
                v-model="linkMenu"
                min-width="300"
                :close-on-content-click="false"
                offset-y
                :position-x="menuX"
                :position-y="menuY"
                absolute
              >
                <v-card width="300">
                  <v-card-title>{{ $sock.t("InsertLink") }}</v-card-title>

                  <div class="ma-8">
                    <v-text-field
                      v-model="linkUrl"
                      :label="$sock.t('LinkUrl')"
                    ></v-text-field>
                    <v-text-field
                      v-model="linkText"
                      :label="$sock.t('LinkText')"
                    ></v-text-field>
                  </div>

                  <v-card-actions>
                    <v-spacer></v-spacer>

                    <v-btn text @click="linkMenu = false">{{
                      $sock.t("Cancel")
                    }}</v-btn>
                    <v-btn color="primary" text @click="editClick('link')">{{
                      $sock.t("OK")
                    }}</v-btn>
                  </v-card-actions>
                </v-card>
              </v-menu>
              <!-- /LINKS -->

              <!-- IMAGE -->

              <v-btn depressed tile @click="openImageMenu">
                <v-icon>$sockiImage</v-icon>
              </v-btn>
              <v-menu
                v-model="imageMenu"
                min-width="360"
                :close-on-content-click="false"
                offset-y
                :position-x="menuX"
                :position-y="menuY"
                absolute
              >
                <v-card>
                  <v-card-title>{{ $sock.t("InsertImage") }}</v-card-title>
                  <div>
                    <v-tabs v-model="imageTab" grow color="primary">
                      <v-tab key="url">URL</v-tab>
                      <v-tab key="file">{{ $sock.t("Attachments") }}</v-tab>
                      <v-tabs-items v-model="imageTab">
                        <v-tab-item key="url"
                          ><div class="ma-6">
                            <v-text-field
                              v-model="imageUrl"
                              :label="$sock.t('ImageUrl')"
                            ></v-text-field>
                            <v-text-field
                              v-model="imageText"
                              :label="$sock.t('ImageDescription')"
                            ></v-text-field></div
                        ></v-tab-item>
                        <v-tab-item key="file"
                          ><div class="ma-6">
                            <v-select
                              v-model="selectedImageAttachment"
                              :label="$sock.t('Attachments')"
                              :items="attachments"
                              item-text="name"
                              item-value="id"
                              return-object
                              @click="getAttachments"
                            ></v-select>

                            <v-text-field
                              v-model="imageText"
                              :label="$sock.t('ImageDescription')"
                            ></v-text-field></div
                        ></v-tab-item>
                      </v-tabs-items>
                    </v-tabs>
                  </div>
                  <v-card-actions>
                    <v-spacer></v-spacer>
                    <v-btn text @click="imageMenu = false">{{
                      $sock.t("Cancel")
                    }}</v-btn>
                    <v-btn
                      color="primary"
                      text
                      @click="editClick('image', imageTab)"
                      >{{ $sock.t("OK") }}</v-btn
                    >
                  </v-card-actions>
                </v-card>
              </v-menu>

              <!-- /IMAGE -->

              <!-- CODE -->
              <v-btn depressed tile class="ml-1" @click="editClick('code')">
                <v-icon>$sockiCode</v-icon></v-btn
              >
              <v-btn depressed tile @click="editClick('codeblock')">
                <v-icon>$sockiSquareFull</v-icon></v-btn
              >

              <!-- HELP -->
              <v-btn depressed tile class="ml-1" @click="goHelp()">
                <v-icon>$sockiQuestionCircle</v-icon></v-btn
              >
              <!-- END OF BUTTONS -->
            </div>
          </v-col>
          <!-- DESIGNER -->
          <v-col
            v-if="showDesigner()"
            :cols="currentView == view.SPLIT_VIEW ? 6 : 12"
          >
            <div :style="editStyle()">
              <v-textarea
                v-cloak
                ref="editArea"
                v-model="localVal"
                solo
                no-resize
                :height="editAreaHeight"
                data-cy="wikiEditor"
                @drop.prevent="onDrop"
                @dragover.prevent
                @input="handleInput"
                @dblclick="handleDoubleClick"
              ></v-textarea>
            </div>
          </v-col>
          <!-- WIKI  auto-grow-->
          <v-col
            v-if="showWiki()"
            :cols="currentView == view.SPLIT_VIEW ? 6 : 12"
          >
            <!-- eslint-disable vue/no-v-html -->
            <div
              :style="wikiStyle()"
              class="markdown-body"
              v-html="compiledOutput()"
            ></div>
          </v-col>
        </v-row>
        <v-btn depressed tile @click="toggleReveal">
          Wiki<v-icon
            right
            v-text="reveal ? '$sockiEyeSlash' : '$sockiEye'"
          ></v-icon
        ></v-btn>
      </v-sheet>
    </template>
  </div>
</template>
<script>
import marked from "marked";
import DOMPurify from "dompurify";
export default {
  props: {
    value: { type: String, default: "" },
    sockType: { type: Number, default: null },
    sockId: { type: Number, default: null },
    readonly: Boolean
  },
  data() {
    return {
      localVal: this.value,
      currentView: 0,
      reveal: false,
      selection: {
        start: 0,
        end: 0,
        startOfBlock: 0, //block meaning first character after last linefeed before or at start of selection
        endOfBlock: 0, //end of block meaning selection expanded to end of line (unless there isn't one)
        hasSelection: false
      },
      editAreaHeight: 300,
      view: {
        HIDDEN_VIEW: 0,
        SPLIT_VIEW: 1,
        WIKI_VIEW: 2,
        DESIGN_VIEW: 3
      },
      tableMenu: false,
      tableMenuColumns: 2,
      tableMenuRows: 2,
      linkMenu: false,
      menuX: 10,
      menuY: 10,
      linkUrl: "",
      linkText: "",
      imageMenu: false,
      imageTab: null,
      imageUrl: "",
      imageText: "",
      attachments: [],
      selectedImageAttachment: null,
      notes: null, //attachment upload notes
      uploadFiles: [] //attachment upload files
    };
  },
  computed: {
    isEmpty() {
      return this.value == null;
    }
  },
  watch: {
    value(value) {
      this.localVal = value ?? "";
    }
  },
  created() {
    // Add a hook to make all links open a new window
    //https://github.com/cure53/DOMPurify/blob/master/demos/hooks-target-blank-demo.html
    DOMPurify.addHook("afterSanitizeAttributes", function(node) {
      // set all elements owning target to target=_blank
      if ("target" in node) {
        node.setAttribute("target", "_blank");
        // prevent https://www.owasp.org/index.php/Reverse_Tabnabbing
        node.setAttribute("rel", "noopener noreferrer");
      }
      // set non-HTML/MathML links to xlink:show=new
      if (
        !node.hasAttribute("target") &&
        (node.hasAttribute("xlink:href") || node.hasAttribute("href"))
      ) {
        node.setAttribute("xlink:show", "new");
      }
    });
  },
  beforeDestroy() {
    DOMPurify.removeAllHooks();
  },
  methods: {
    goHelp() {
      window.open(window.$gz.api.helpUrl() + "sock-start-form-wiki", "_blank");
    },
    compiledOutput() {
      if (!this.localVal) {
        return "";
      }
      //replace attachment urls with tokenized local urls
      const src = this.localVal.replace(/\[ATTACH:(.*)\]/g, function(
        match,
        p1
      ) {
        return window.$gz.api.attachmentDownloadUrl(p1);
      });

      return DOMPurify.sanitize(marked(src, { breaks: true }));
    },
    onResize() {
      this.editAreaHeight = window.innerHeight * 0.8;
    },
    toggleReveal() {
      this.reveal = !this.reveal;
      if (this.reveal) {
        this.currentView = this.view.WIKI_VIEW;
      }
    },
    editStyle() {
      if (this.currentView == this.view.SPLIT_VIEW) {
        return "height: " + this.editAreaHeight + "px;";
      } else {
        return false; //false attributes don't get rendered
      }
    },
    wikiStyle() {
      if (this.currentView == this.view.SPLIT_VIEW) {
        return "height: " + this.editAreaHeight + "px;overflow-y:auto;";
      } else {
        return false; //false attributes don't get rendered
      }
    },
    getSelectedRange(forceBlock) {
      const bodyTextArea = this.$refs.editArea.$el.querySelector("textarea");
      this.selection.start = bodyTextArea.selectionStart;
      this.selection.end = bodyTextArea.selectionEnd;
      //some edits only work on a block so if user is just clicked on a line then add make a selection
      if (forceBlock) {
        //add a character to selection forward if possible but if not then go backward one
        if (this.selection.end < this.localVal.length) {
          this.selection.end++;
        } else {
          if (this.selection.start > 0) {
            this.selection.start--;
          }
        }
      }
      this.selection.hasSelection = this.selection.start != this.selection.end;

      //block selection
      //start of block...
      //default
      this.selection.startOfBlock = this.selection.start;
      if (this.selection.start > 0) {
        //find linefeed prior to current start
        const indexOfLineFeed = this.localVal.lastIndexOf(
          "\n",
          this.selection.start
        );
        if (indexOfLineFeed != -1) {
          this.selection.startOfBlock = indexOfLineFeed + 1;
        } else {
          //this may be wrong but if it's the first line then I think the block should be the first character
          this.selection.startOfBlock = 0;
        }
      }

      //end of block
      //default
      this.selection.endOfBlock = this.selection.end;
      if (this.selection.end > 0) {
        //find linefeed prior to current start
        const indexOfLineFeed = this.localVal.indexOf("\n", this.selection.end);
        if (indexOfLineFeed != -1) {
          this.selection.endOfBlock = indexOfLineFeed;
        }
      }
    },
    setSelectedRange(start, end) {
      const bodyTextArea = this.$refs.editArea.$el.querySelector("textarea");
      bodyTextArea.setSelectionRange(start, end);
    },
    getSelectedText() {
      let selectedText = "";
      if (this.selection.hasSelection) {
        selectedText = this.localVal.substring(
          this.selection.start,
          this.selection.end
        );
      }
      return selectedText;
    },
    replaceSelectedText(newString) {
      this.localVal = window.$gz.util.stringSplice(
        this.localVal,
        this.selection.start,
        this.selection.end - this.selection.start,
        newString
      );
      //emit input event to parent form for dirty tracking
      this.handleInput(this.localVal);
    },
    getSelectedBlock() {
      let selectedText = "";
      if (this.selection.hasSelection) {
        selectedText = this.localVal.substring(
          this.selection.startOfBlock,
          this.selection.endOfBlock
        );
      }
      return selectedText; //.trim();
    },
    replaceSelectedBlock(newString) {
      this.localVal = window.$gz.util.stringSplice(
        this.localVal,
        this.selection.startOfBlock,
        this.selection.endOfBlock - this.selection.startOfBlock,
        newString
      );
      //emit input event to parent form for dirty tracking
      this.handleInput(this.localVal);
    },
    handleDoubleClick() {
      //the purpose of this is only to change the selection if it's got an extra space to the right
      //because double clicking on a word with another word after it causes the space to be included
      this.getSelectedRange();
      const temp = this.getSelectedText();
      const tempTrimmed = temp.trimEnd();
      const diff = temp.length - tempTrimmed.length;
      if (diff != 0) {
        //there were some spaces so update the selection range
        //force selection to be shorter by diff
        this.setSelectedRange(this.selection.start, this.selection.end - diff);
      }
    },
    handleInput(val) {
      this.$emit("input", val);
      this.localVal = val;
    },
    switchViewIcon() {
      //return the icon that indicates what it will change to if you click it
      //mirror of switchview below

      if (this.readonly) {
        if (this.currentView == this.view.HIDDEN_VIEW) {
          return "$sockiEye";
        } else {
          return "$sockiEyeSlash";
        }
      }

      switch (this.currentView) {
        case this.view.HIDDEN_VIEW:
          return "$sockiEye";
        case this.view.WIKI_VIEW:
          return "$sockiColumns";
        case this.view.SPLIT_VIEW:
          return "$sockiFeather";
        case this.view.DESIGN_VIEW:
          return "$sockiEye";
      }
    },
    showWiki() {
      return (
        this.currentView == this.view.WIKI_VIEW ||
        this.currentView == this.view.SPLIT_VIEW
      );
    },
    showDesigner() {
      return (
        this.currentView == this.view.DESIGN_VIEW ||
        this.currentView == this.view.SPLIT_VIEW
      );
    },
    switchView() {
      //if user can't edit then cycle between hidden and wiki view
      if (this.readonly) {
        if (this.currentView == this.view.HIDDEN_VIEW) {
          this.currentView = this.view.WIKI_VIEW;
        } else {
          this.currentView = this.view.HIDDEN_VIEW;
        }
        return;
      }
      //user can edit so switch OUT of hidden view but never into it
      //and cycle between design, split and wiki views only
      //never goes into hidden
      switch (this.currentView) {
        case this.view.HIDDEN_VIEW:
          this.currentView = this.view.WIKI_VIEW;
          break;
        case this.view.WIKI_VIEW:
          this.currentView = this.view.SPLIT_VIEW;
          break;
        case this.view.SPLIT_VIEW:
          this.currentView = this.view.DESIGN_VIEW;
          break;
        case this.view.DESIGN_VIEW:
          this.currentView = this.view.WIKI_VIEW;
          break;
      }
    },
    visibleIcon() {
      return this.wikiVisible ? "$sockiEyeSlash" : "$sockiEye";
    },
    //EDITING
    editClick(editType, ex) {
      if (editType != "heading") {
        this.getSelectedRange();
      }
      switch (editType) {
        case "bold":
          this.replaceSelectedText("**" + this.getSelectedText() + "**");
          break;
        case "italic":
          this.replaceSelectedText("*" + this.getSelectedText() + "*");
          break;
        case "strike":
          this.replaceSelectedText("~~" + this.getSelectedText() + "~~");
          break;
        case "line":
          this.replaceSelectedText("***");
          break;
        case "heading":
          {
            this.getSelectedRange(true); //special forces
            const prepend = "#".repeat(ex) + " ";
            let s = this.getSelectedBlock();
            s = s.replace(/\n/gi, "\n" + prepend);
            if (s.length > 0 && s[0] != "\n") {
              s = prepend + s;
            }
            this.replaceSelectedBlock(s);
          }
          break;
        case "code":
          this.replaceSelectedText("`" + this.getSelectedText() + "`");
          break;
        case "codeblock":
          this.replaceSelectedBlock(
            "\n```\n" + this.getSelectedBlock() + "\n```\n"
          );
          break;
        case "quote":
          if (this.selection.hasSelection) {
            this.replaceSelectedBlock("\n>" + this.getSelectedBlock() + "\n");
          } else {
            this.replaceSelectedText("\n>");
          }
          break;
        case "ul":
          {
            if (this.selection.hasSelection) {
              let s = this.getSelectedBlock();
              s = s.replace(/\n/gi, "\n* ");
              if (s.length > 0 && s[0] != "\n") {
                s = "* " + s;
              }
              s = s + "\n";
              this.replaceSelectedBlock(s);
            } else {
              this.replaceSelectedText("\n* ");
            }
          }
          break;
        case "ol":
          {
            if (this.selection.hasSelection) {
              const s = this.getSelectedBlock();
              let ret = "\n1. ";
              let listItem = 1;
              for (let i = 0; i < s.length; i++) {
                if (s[i] == "\n") {
                  ++listItem;
                  ret += "\n" + listItem + ". ";
                } else {
                  ret += s[i];
                }
              }
              ret += "\n\n";
              this.replaceSelectedBlock(ret);
            } else {
              this.replaceSelectedText("\n1. ");
            }
          }
          break;
        case "task":
          {
            if (this.selection.hasSelection) {
              let s = this.getSelectedBlock();
              s = s.replace(/\n/gi, "\n* [ ]  ");
              if (s.length > 0 && s[0] != "\n") {
                s = "* [ ]  " + s;
              }
              s = s + "\n";
              this.replaceSelectedBlock(s);
            } else {
              this.replaceSelectedText("\n* [ ]  ");
            }
          }
          break;
        case "table":
          {
            this.tableMenu = false;
            //| Column 1 | Column 2 | Column 3 |
            //| -------- | -------- | -------- |
            //| John     | Doe      | Male     |
            //| Mary     | Smith    | Female   |
            this.getSelectedRange();

            let t = "\n";

            //Header
            //| CCC | CCC | CCC |
            for (let c = 0; c < this.tableMenuColumns; c++) {
              t += "| CCC ";
            }
            t += "|\n";

            //Divider
            //| --- | --- | --- |
            for (let c = 0; c < this.tableMenuColumns; c++) {
              t += "| --- ";
            }
            t += "|\n";

            //Rows
            //| XXX | XXX | XXX |
            for (let r = 0; r < this.tableMenuRows; r++) {
              for (let c = 0; c < this.tableMenuColumns; c++) {
                t += "| XXX ";
              }
              t += "|\n";
            }

            this.replaceSelectedText(t);
          }
          break;
        case "link":
          {
            this.linkMenu = false;
            let url = this.linkUrl;
            if (!url) {
              return;
            }
            //force it to a full url so it doesn't attempt to open it as a SPA window
            if (!url.includes(":")) {
              url = "https://" + url;
            }
            const t = "[" + this.linkText + "](" + url + ")";
            // [MY Awesome LINK](www.ayanova.com)
            this.replaceSelectedText(t);
          }
          break;
        case "image":
          //![alttexthere](https://www.ayanova.com/images/SockeyeIcon256.png "title text here (tooltip)")
          {
            this.imageMenu = false;

            let url = null;
            if (ex == 1) {
              if (
                !this.selectedImageAttachment ||
                !this.selectedImageAttachment.url
              ) {
                return;
              }
              //it's an attachment
              url = this.selectedImageAttachment.url;
              if (!this.imageText) {
                this.imageText = this.selectedImageAttachment.name;
              }
            } else {
              //it's a url paste / manual entry
              url = this.imageUrl;
            }

            if (!url) {
              return;
            }

            const txt = this.imageText;
            //force it to a full url so it doesn't attempt to open it as a SPA window
            if (!url.includes(":")) {
              url = "https://" + url;
            }

            if (txt) {
              this.replaceSelectedText(
                "![" + txt + "](" + url + ' "' + txt + '") \n' + txt //keep original selected text otherwise it will vanish
              );
            } else {
              this.replaceSelectedText("![](" + url + ")");
            }
            this.selectedImageAttachment = null;
          }
          break;
        default:
          throw new Error(`wiki-control: ${editType} NOT IMPLEMENTED`);
      }
    },
    openLinkMenu(e) {
      e.preventDefault();
      this.linkMenu = false;
      this.getSelectedRange();
      this.linkText = this.getSelectedText();
      this.menuX = e.clientX;
      this.menuY = e.clientY;
      this.$nextTick(() => {
        this.linkMenu = true;
      });
    },
    openImageMenu(e) {
      e.preventDefault();
      this.imageMenu = false;
      this.getSelectedRange();
      this.imageText = this.getSelectedText();
      this.menuX = e.clientX;
      this.menuY = e.clientY;
      this.$nextTick(() => {
        this.imageMenu = true;
      });
    },
    async getAttachments() {
      const vm = this;
      try {
        vm.attachments = [];
        const res = await window.$gz.api.get(
          "attachment/list?socktype=" + vm.sockType + "&ayaid=" + vm.sockId
        );
        if (res.error) {
          window.$gz.errorHandler.handleFormError(res.error);
        } else {
          const ret = [];
          for (let i = 0; i < res.data.length; i++) {
            const o = res.data[i];

            if (
              window.$gz.util.isImageAttachment(
                o.displayFileName,
                o.contentType
              )
            ) {
              //attach url
              //![]([ATTACH:4])
              ret.push({
                id: o.id,
                url: "[ATTACH:" + o.id + "]",
                name: o.displayFileName
              });
            }
          }
          vm.attachments = ret;
        }
      } catch (error) {
        window.$gz.errorHandler.handleFormError(error);
      }
    },
    async upload() {
      //similar code in attachment-control upload
      const vm = this;
      const at = {
        sockId: vm.sockId,
        sockType: vm.sockType,
        files: vm.uploadFiles,
        notes: ""
      };
      try {
        const res = await window.$gz.api.uploadAttachment(at);

        if (res.error) {
          window.$gz.errorHandler.handleFormError(res.error);
        } else {
          const ret = [];
          for (let i = 0; i < res.data.length; i++) {
            const o = res.data[i];

            //let them attach any file type to the wiki since it supports it anyway
            ret.push({
              id: o.id,
              url: window.$gz.api.attachmentDownloadUrl(o.id, o.contentType),
              name: o.displayFileName
            });
            //}
          }
          //put into attachments list
          vm.attachments = ret;
          //NOW iterate upload files list and insert into wiki based on attachments
          //insert into wiki
          for (let i = 0; i < vm.uploadFiles.length; i++) {
            const upFile = vm.uploadFiles[i];
            for (let j = 0; j < vm.attachments.length; j++) {
              const atFile = vm.attachments[j];
              if (upFile.name == atFile.name) {
                //found it
                this.insertUrl(atFile.url, atFile.name);
                break;
              }
            }
          }
          //finally, clear the upload files
          vm.uploadFiles = [];
        }
      } catch (error) {
        window.$gz.errorHandler.handleFormError(error);
      }
    },
    onDrop(ev) {
      //Drop image file
      let files = Array.from(ev.dataTransfer.files);
      if (files.length > 0) {
        //handle file drop
        files = Array.from(ev.dataTransfer.files);
        if (files.length > 0) {
          this.uploadFiles = files;
          this.upload();
        }
        //if an image then put it directly in viewable, if not an image then make a link and keep as an attach
      } else {
        //maybe an url?
        const url = ev.dataTransfer.getData("text");
        this.insertUrl(url);
      }
    },
    insertUrl(url, name) {
      if (url) {
        let isImageUrl = false;
        //attachment?
        if (url.includes("attachment/download/")) {
          //it's an attachment url so fixup accordingly
          //i paramter added by gzapi::attachmentDownloadUrl function
          isImageUrl = url.includes("&i=");
          const m = url.match(/attachment\/download\/(.*)\?t=/);
          if (m.length > 1) {
            url = "[ATTACH:" + m[1] + "]";
          } else {
            url = null;
          }
        } else {
          //External url, sniff out if it's an image
          isImageUrl = window.$gz.util.isImageAttachment(url);
        }
        if (url != null) {
          //insert into textarea
          let txt = this.getSelectedText();
          if (!txt) {
            txt = name;
          }
          if (txt) {
            if (isImageUrl) {
              this.replaceSelectedText(
                "![" + txt + "](" + url + ' "' + txt + '") \n' + txt + "\n" //keep original selected text otherwise it will vanish
              );
            } else {
              //regular url not image
              this.replaceSelectedText(
                "[" + txt + "](" + url + ' "' + txt + '")\n'
              );
            }
          } else {
            //No selected text
            if (isImageUrl) {
              this.replaceSelectedText("![](" + url + ")\n");
            } else {
              //regular no text non image url
              this.replaceSelectedText("<" + url + ">\n");
            }
          }
        }
      }
    }
  }
};
</script>
