<template>
  <div @focus="focus" @blur="blur" tabindex="0" class="markdown-component">
    <p class="collapser-info" v-if="collapsed && !value" v-html="placeholder"></p>
    <div :class="{ collapsed, collapser: true }">
      <div :id="'wmd-button-bar' + postfix" v-show="false"></div>
      <textarea
        :id="'wmd-input' + postfix"
        :rows="minRows"
        class="wmd-input form-control"
        ref="textarea"
        @focus="focus"
        @blur="blur"
      ></textarea>

      <div class="btn-toolbar">
        <div class="btn-group mr-2">
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('nbsp')"
            @mousedown.prevent="uiManager.doClick('nbsp')"
            title="Non-breaking Space &amp;nbsp; Ctrl+Space"
          >
            <span class="icon-nbsp"></span>
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('linebreak')"
            @mousedown.prevent="uiManager.doClick('linebreak')"
            title="Line break <br>"
          >
            &larr;
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('bold')"
            @mousedown.prevent="uiManager.doClick('bold')"
            title="Strong <strong> Ctrl+B"
          >
            <span class="icon-bold"></span>
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('italic')"
            @mousedown.prevent="uiManager.doClick('italic')"
            title="Emphasis <em> Ctrl+I"
          >
            <span class="icon-italic"></span>
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('underline')"
            @mousedown.prevent="uiManager.doClick('underline')"
            title="Underline <u> Ctrl+U"
          >
            <span class="icon-underline"></span>
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('quote')"
            @mousedown.prevent="uiManager.doClick('quote')"
            title="Quote <blockquote> Ctrl+Q"
          >
            <span class="icon-quotes-right"></span>
          </button>
        </div>

        <div class="btn-group mr-2">
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('link')"
            @mousedown.prevent="doLink(false)"
            title="Externe Hyperlink <a> Ctrl+L"
          >
            <span class="icon-earth"></span><span class="icon-link decorate-icon"></span>
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('link')"
            @mousedown.prevent.stop="doLink(true)"
            title="Interne Hyperlink <a>"
            ref="internal-link-button"
          >
            <span class="icon-file-empty"></span><span class="icon-link decorate-icon"></span>
          </button>
        </div>

        <div class="btn-group mr-2">
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('list')"
            @mousedown.prevent="uiManager.doClick('olist')"
            title="Numbered List <ol> Ctrl+O"
          >
            <span class="icon-list-numbered"></span>
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('list')"
            @mousedown.prevent="uiManager.doClick('ulist')"
            title="Bulleted List <ul> Ctrl+U"
          >
            <span class="icon-list2"></span>
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('heading')"
            @mousedown.prevent="uiManager.doClick('heading')"
            title="Heading <h1>/<h2> Ctrl+H"
          >
            <span class="icon-text-height"></span>
          </button>
        </div>

        <div class="btn-group btn-group-sm">
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('undo')"
            @mousedown.prevent="uiManager.doClick('undo')"
            title="Undo - Ctrl+Z"
          >
            <span class="icon-undo"></span>
          </button>
          <button
            class="btn btn-outline-secondary btn-sm"
            v-if="shouldShowButton('redo')"
            @mousedown.prevent="uiManager.doClick('redo')"
            title="Redo - Ctrl+Y/Ctrl+Shift+Z"
          >
            <span class="icon-redo"></span>
          </button>
        </div>
      </div>

      <page-picker ref="page-picker" :custom-input="$refs['internal-link-button']" v-model="linkValue"></page-picker>
    </div>
    <div v-html="convertedText" class="wmd-preview" @focus="start" tabindex="0"></div>
  </div>
</template>

<style>
@import '../../resources/pagedown/demo.css';
</style>

<style lang="scss" scoped>
.markdown-component:focus,
.wmd-preview:focus {
  outline: none;
}

.markdown-component {
  position: relative;

  .collapser-info {
    position: absolute;
    color: #55595c; // similar to .form-control from Bootstrap
    font-size: 1rem; // similar to .form-control from Bootstrap
    left: 10px;
    top: 10px;
  }
}

.wmd-preview {
  border: 1px solid #ccc; // similar to .form-control from Bootstrap
  cursor: text;
  margin: 0; // override css from lib
  padding: 20px 0.75rem;

  &:not(:empty) {
    padding: 0.5rem 0.75rem;
  }
}

.collapser {
  transition: height 0.2s;

  + .wmd-preview {
    display: none;
  }
}

.collapsed {
  height: 0;
  overflow: hidden;

  + .wmd-preview {
    display: block;
  }
}

.btn-toolbar {
  margin: 10px 0;
}

.icon-nbsp {
  position: relative;

  &::before {
    content: '\00a0';
    position: absolute;
    bottom: 0;
    height: 5px;
    border: 1px solid currentColor;
    border-top: none;
  }

  &::after {
    content: '\00a0';
  }
}

.decorate-icon {
  font-size: 80%;
  margin-left: -0.5em;
  vertical-align: text-bottom;
  text-shadow: 0 1px 0 white, 0 -1px 0 white, 1px 0 0 white, -1px 0 0 white;
}
</style>

<script>
import autosize from 'autosize';
import store from '../../stores/';
import pagePicker from './page-picker.vue';
import { parseDynamicTags } from '../../tools/dynamic-tag-parser';

import MarkdownConverter from '../../resources/pagedown/Markdown.Converter.js';
import MarkdownEditor from '../../resources/pagedown/Markdown.Editor.js';
import MarkdownSanitizer from '../../resources/pagedown/Markdown.Sanitizer.js';

MarkdownConverter();
MarkdownEditor();
MarkdownSanitizer();

export default {
  props: {
    value: {
      required: true,
      validator: (value) => value === null || value === undefined || typeof value === 'string',
      demoValue: ' - Hallo!'
    },
    placeholder: {
      type: String,
      default: '(leeg)'
    },
    uiButtons: {
      type: Array,
      demoValue: () => ['link', 'list'],
      docs: `Optie om alleen de knoppen uit dit array te tonen.`
    },
    minRows: {
      type: Number,
      default: 2
    }
  },
  data() {
    return {
      postfix: '-' + (Math.random() + '').substr(2),
      collapsed: true,
      uiManager: null,
      linkIsInternal: false,
      linkValue: null,
      linkCb: null,
      converter: null
    };
  },
  mounted() {
    this.converter = new window.Markdown.getSanitizingConverter();
    const editor = new window.Markdown.Editor(this.converter, this.postfix);
    editor.run();
    this.uiManager = editor.uiManager;
    editor.hooks.insertLinkDialog = this.insertLinkDialog;

    // v-model can't be used because of Markdown lib, so set the value once. v-model is updated in method 'blur'
    this.$refs.textarea.value = this.value;
    autosize(this.$refs.textarea);
  },
  computed: {
    convertedText() {
      // this.value can be 'null', which breaks the converter
      if (!this.converter || !this.value) {
        return '';
      }

      const parsedMarkdown = this.converter.makeHtml(this.value);
      const parsedHtml = parseDynamicTags(parsedMarkdown, this.tags);
      return parsedHtml;
    },
    tags() {
      return store.state.data.dynamicTags;
    }
  },
  watch: {
    linkValue() {
      if (this.linkValue && this.linkCb) {
        this.linkCb('page-guid://' + this.linkValue);
        this.linkCb = null;
      }
    },
    value(val) {
      this.$refs.textarea.value = val;
      autosize.update(this.$refs.textarea);
    }
  },
  methods: {
    start() {
      if (this.collapsed) {
        this.collapsed = false;
        this.$nextTick(() => {
          this.$refs.textarea.focus();
        });
      }
    },
    focus() {
      if (this.collapseHandle) {
        window.cancelAnimationFrame(this.collapseHandle);
        this.collapseHandle = 0;
      }
      this.collapsed = false;
    },
    blur() {
      // requestAnimationFrame so we do not do this when we lose focus for a tiny instant (when clicking on UI items, for instance)
      this.collapseHandle = window.requestAnimationFrame(() => {
        // HACK: when adding a link, the textarea is updated bij setting textarea.value in the Markdown lib. This doesn't trigger an 'input'/'change' event, so v-model doesn't work or addEventListener. Therefore we update the value on 'blur' of the textarea
        this.$emit('input', this.$refs.textarea.value); // vue syntax: update prop 'value' in the parent
        this.collapsed = true;
      });
    },
    doLink(linkIsInternal) {
      this.linkIsInternal = linkIsInternal;
      this.uiManager.doClick('link');
    },
    insertLinkDialog(linkCb) {
      if (!this.linkIsInternal) {
        return false;
      }
      this.linkCb = linkCb;
      this.linkValue = null;

      this.$refs['page-picker'].showPopup(this.$refs['internal-link-button']);
      return true;
    },
    shouldShowButton(type) {
      return !this.uiButtons || this.uiButtons.indexOf(type) !== -1;
    }
  },
  components: {
    pagePicker
  }
};
</script>
