<template>
  <div class="freeleaps-editor">
    <div
      class="editor-body"
      :contenteditable="!disabled"
      spellcheck="false"
      ref="editor"
      v-html="content"
      @blur="updateAction"
      @mousedown.stop="selectionStart"
      @mouseup.stop="selectionEnd"
    />
    <div v-if="!disabled" class="editor-control" :style="editorCtrlStyle">
      <transition-group appear name="fade-transform" mode="out-in">
        <template v-if="!inputing">
          <div v-for="(item, index) in iconList" :key="index" class="editor-item">
            <button
              class="item-icon"
              :class="{
                activity: commandStates.indexOf(item.type) !== -1,
                last: index === iconList.length - 1
              }"
              :data-info="item.name"
              @click="iconClick($event, item.type)"
              :data-bs-toggle="item.drop ? 'dropdown' : ''"
              data-bs-auto-close="outside"
              aria-expanded="false"
            >
              <svg-icon :icon="item.icon" class-name="icon" />
            </button>
            <div class="dropmenu drop-style" v-if="item.type === 'style'">
              <ul>
                <li>
                  <a href="#" @click="iconClick($event, 'p', 'style')"><p>Text</p></a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'pre', 'style')"><pre>code</pre></a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'blockquote', 'style')"
                    ><blockquote>引用</blockquote></a
                  >
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'h1', 'style')"><h1>Caption 1</h1></a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'h2', 'style')"><h2>Caption 2</h2></a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'h3', 'style')"><h3>Caption 3</h3></a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'h4', 'style')"><h4>Caption 4</h4></a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'h5', 'style')"><h5>Caption 5</h5></a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'h6', 'style')"><h6>Caption 6</h6></a>
                </li>
              </ul>
            </div>
            <div class="dropmenu drop-style" v-if="item.type === 'alignjustify'">
              <ul>
                <li>
                  <a href="#" @click="iconClick($event, 'justifyCenter', 'alignjustify')">
                    <i class="iconfont icon-aligncenter"></i>
                    <span>middle</span>
                  </a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'justifyLeft', 'alignjustify')">
                    <i class="iconfont icon-alignleft"></i>
                    <span>left aligned</span>
                  </a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'justifyRight', 'alignjustify')">
                    <i class="iconfont icon-alignright"></i>
                    <span>right aligned</span>
                  </a>
                </li>
                <li>
                  <a href="#" @click="iconClick($event, 'justifyFull', 'alignjustify')">
                    <i class="iconfont icon-alignjustify"></i>
                    <span>default aligned</span>
                  </a>
                </li>
              </ul>
            </div>
          </div>
        </template>
        <template v-if="inputing">
          <div class="editor-item">
            <button class="item-icon item-icon-back" @click="backAction" data-info="back">
              <svg-icon icon="fe-back" class-name="icon" />
            </button>
          </div>
          <div class="editor-item">
            <input type="text" v-model="linkUrl" autofocus @keydown.enter="inputAction">
            <svg-icon icon="msg-enter" class-name="item-enter-icon" />
          </div>
        </template>
      </transition-group>
      
    </div>
  </div>
</template>
<script>
import SvgIcon from '@/components/SvgIcon.vue'
import { websiteValidator } from '@/utils/validator'
export default {
  name: 'FreeleapsEditor',
  props: {
    content: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  emits: ['update:content'],
  components: { SvgIcon },
  data() {
    return {
      selectedRange: '',
      editorCtrlStyle: {},
      commandStates: [],
      inputing: false,
      linkUrl: '',
      iconList: [
        // {
        //   name: 'lable', // hover name
        //   type: 'style', // click event handler
        //   icon: 'fe-paragraph', // icon style
        //   drop: true, // If there is drop menu
        //   canChoose: true, // chosen or not
        // },
        {
          name: 'bold',
          type: 'bold',
          icon: 'fe-bold',
          drop: false,
          canChoose: true
        },
        {
          name: 'italic',
          type: 'italic',
          icon: 'fe-italic',
          drop: false,
          canChoose: true
        },
        {
          name: 'underline',
          type: 'underline',
          icon: 'fe-underline',
          drop: false,
          canChoose: true
        },
        // {
        //   name: 'strike',
        //   type: 'strike',
        //   icon: 'fe-strike',
        //   drop: false,
        //   canChoose: true,
        // },
        // {
        //   name: 'clear-format',
        //   type: 'clear',
        //   icon: 'fe-clear',
        //   drop: false,
        //   canChoose: false,
        // },
        // {
        //   name: 'font-color',
        //   type: 'fontFamily',
        //   icon: 'fe-char',
        //   drop: false,
        //   canChoose: true,
        // },
        {
          name: 'unordered-list',
          type: 'unorderedlist',
          icon: 'fe-unorderedlist',
          drop: false,
          canChoose: true
        },
        {
          name: 'ordered list',
          type: 'orderedlist',
          icon: 'fe-orderedlist',
          drop: false,
          canChoose: true
        },
        {
          name: 'link',
          type: 'link',
          icon: 'fe-link',
          drop: false,
          canChoose: true
        },
        // {
        //   name: 'align-justify',
        //   type: 'alignjustify',
        //   icon: 'fe-alignjustify',
        //   drop: true,
        //   canChoose: true,
        // }
      ]
    }
  },
  methods: {
    selectionStart() {
      this.$refs.editor.blur()
    },
    selectionEnd(e) {
      const sel = window.getSelection()
      if (sel && sel.type === 'Range') {
        // this.selectedRange = sel.getRangeAt(0)
        // this.restoreSelection()
        // console.log('window.getSelection',this.selectedRange)
        // console.log('is bold ? ', this.queryCommandState(sel.getRangeAt(0), 'bold'))
        // this.iconClick(null, 'bold')
        this.editorCtrlStyle = { display: 'flex', top: `${e.layerY}px`, left: `${e.layerX}px` }
      } else {
        this.selectedRange = null
        this.editorCtrlStyle = { display: 'none' }
        this.inputing = false
        this.linkUrl = ''
        // this.commandStates = []
      }
    },
    queryCommandState(range, command) {
      const container = document.createElement('span')
      container.style.display = 'none'

      container.appendChild(range.cloneContents())
      console.log('queryCommandState', container)
      // range
      document.body.appendChild(container)
      const state = document.queryCommandState(command)
      console.log('queryCommandIndeterm ', document.queryCommandIndeterm('bold'))
      console.log('queryCommandState ', document.queryCommandState('bold'))
      // range.collapse(true);
      container.remove()
      return state
    },
    iconClick(event, type, dropType) {
      event.preventDefault()
      this.$refs.editor.focus()
      this.selectedRange = this.getSelect()
      this.restoreSelection()
      if (type === 'link') {
        this.inputing = true
        return
      }
      this.changeStyle(type)
      this.$nextTick(() => {
        if (dropType) {
          type = dropType
        }
        const i = this.commandStates.indexOf(type)
        if (i === -1) {
          this.commandStates.push(type)
        } else {
          this.commandStates.splice(i, 1)
        }
      })
    },
    backAction() {
      this.inputing = false
      this.linkUrl = ''
      this.$refs.editor.focus()
      this.restoreSelection()
    },
    inputAction() {
      const error = websiteValidator.validate(this.linkUrl)
      if (error) {
        alert(error)
        return
      }
      const a_node = document.createElement('a')
      a_node.setAttribute('href', this.linkUrl)
      this.selectedRange.surroundContents(a_node)
      this.backAction()
      this.$refs.editor.blur()
      this.linkUrl = ''
      this.editorCtrlStyle = { display: 'none' }
    },
    getSelect() {
      if (window.getSelection) {
        let sel = window.getSelection()
        if (sel.rangeCount > 0) {
          return sel.getRangeAt(0)
        }
      } else if (document.selection) {
        return document.selection.createRange()
      }
      return null
    },
    // change the selection's style
    changeStyle(type) {
      switch (type) {
        case 'bold':
          document.execCommand('bold', false)
          break
        case 'underline':
          document.execCommand('underline', false)
          break
        case 'strike':
          document.execCommand('strikeThrough', false)
          break
        case 'italic':
          document.execCommand('italic', false)
          break
        case 'clear':
          document.execCommand('removeFormat', false)
          break
        case 'unorderedlist':
          document.execCommand('insertUnorderedList', false)
          break
        case 'orderedlist':
          document.execCommand('insertorderedList', false)
          break
        case 'h1':
        case 'h2':
        case 'h3':
        case 'h4':
        case 'h5':
        case 'h6':
        case 'p':
        case 'pre':
        case 'blockquote':
          document.execCommand('formatBlock', false, type)
          break
        case 'justifyCenter':
        case 'justifyFull':
        case 'justifyLeft':
        case 'justifyRight':
          document.execCommand(type, false)
          break
        default:
          console.log('none')
      }
      this.$refs.editor.blur()
      // window.getSelection().removeAllRanges()
    },
    restoreSelection() {
      let selection = window.getSelection()
      if (this.selectedRange) {
        try {
          selection.removeAllRanges()
        } catch (ex) {
          document.body.createTextRange().select()
          document.selection.empty()
        }
        selection.addRange(this.selectedRange)
      }
    },

    updateAction($event) {
      let html = $event.target.innerHTML || ''
      this.$emit('update:content', html)
    }
  }
}
</script>

<style lang="scss" scoped>
.freeleaps-editor {
  position: relative;
  min-width: 100px;
  background-color: #fff;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  h1,
  h2,
  h3,
  h4,
  h5,
  h6,
  .h1,
  .h2,
  .h3,
  .h4,
  .h5,
  .h6,
  p,
  a {
    font-family: inherit;
    font-weight: 500;
    line-height: 1.1;
    color: inherit;
    margin: 0;
    text-decoration: none;
  }
  code,
  kbd,
  pre,
  samp {
    font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
  }
  .editor-control {
    display: none;
    width: fit-content;
    height: 26px;
    background-color: #f8f8f9;
    position: absolute;
  }
  .dropmenu {
    display: none;
    position: absolute;
    top: 32px;
    left: 0;
    min-width: 160px;
    padding: 5px 0;
    margin: 2px 0 0;
    font-size: 14px;
    text-align: left;
    list-style: none;
    background-color: #fff;
    background-clip: padding-box;
    border: 1px solid #ccc;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 4px;
    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
    ul {
      padding: 10px;
      margin-bottom: 0;
    }
    ul li {
      text-align: left;
      list-style: none;
      a {
        display: block;
        padding: 5px 10px;
        white-space: nowrap;
      }
    }
  }
  .drop-align {
    min-width: 100px;
  }
  .editor-body {
    height: 300px;
    padding: 10px;
    color: #000;
    background-color: #fff;
    overflow: auto;
    outline: none;
    text-align: left;
    border-radius: 4px;
    position: relative;
    p {
      font-size: 14px;
      color: #68747f;
      margin: 0 0 10px;
    }
  }
}

.editor-item {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  user-select: none;
  cursor: pointer;

  input {
    height: 24px;
    border: 1px solid #e1e1e1;
    box-shadow: none;
    outline: none;
    padding-left: 5px;
    padding-right: 24px;

    &:focus {
      border-color: $primary;
    }
  }

  .item-enter-icon {
    position: absolute;
    right: 2px;
    width: 16px;
    height: 16px;
    padding: 3px;
    background-color: #e1e1e1;
    border-radius: 3px;
  }

  .item-icon {
    position: relative;
    width: 50px;
    height: 16px;
    font-size: 16px;
    color: #9ea2af;
    font-weight: normal;
    white-space: nowrap;
    vertical-align: middle;
    touch-action: manipulation;
    cursor: pointer;
    user-select: none;
    outline: none;
    transition: all 0.1s ease-out;
    border: none;
    line-height: 16px;
    background: transparent;
    border-right: 1px solid #e7e8eb;
    &.last {
      border-right: 0;
    }
    &::after {
      position: absolute;
      top: 0;
      content: attr(data-info);
      top: 40px;
      left: 20px;
      padding: 5px 8px;
      border-radius: 4px;
      white-space: nowrap;
      line-height: 1.5;
      font-size: 13px;
      color: #fff;
      background: rgba(0, 0, 0, 0.8);
      -webkit-transform: translateX(-50%);
      transform: translateX(-50%);
      visibility: hidden;
      opacity: 0.9;
      letter-spacing: 1px;
      z-index: 9999;
    }
    &::before {
      position: absolute;
      content: '';
      top: 35px;
      left: 20px;
      width: 0;
      height: 0;
      margin: 0 0 0 -6px;
      font-size: 0;
      color: rgba(0, 0, 0, 0.8);
      border-bottom: 6px solid currentColor;
      border-left: 6px solid transparent;
      border-right: 6px solid transparent;
      visibility: hidden;
      opacity: 0.9;
      z-index: 9999;
    }
    &:hover,
    &.activity {
      color: black;
    }
    &:hover:after,
    &:hover:before {
      visibility: visible;
    }
    &.activity + .dropmenu {
      display: block;
    }
    &.item-icon-back {
      color: black;
    }
  }
}
</style>
<style>
.freeleaps-editor blockquote {
  padding: 10px 20px;
  font-size: 17.5px;
  border-left: 5px solid #f86466;
  background: white;
}
.freeleaps-editor pre {
  display: block;
  padding: 9.5px;
  font-size: 13px;
  line-height: 1.42857143;
  color: #333;
  word-break: break-all;
  word-wrap: break-word;
  background-color: #f5f5f5;
  border: 1px solid #ccc;
  border-radius: 4px;
}
.editor-body blockquote {
  margin-bottom: 30px;
}
.editor-body pre {
  margin-bottom: 10px;
}
.editor-body ul {
  padding-left: 40px;
  list-style-type: disc;
}
.editor-body ol {
  padding-left: 40px;
}

/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
  transition: all 300;
}

.fade-transform-enter-from {
  opacity: 0;
  transform: translateX(-50px);
}

.fade-transform-leave-to {
  opacity: 0;
  transform: translateX(50px);
}
.fade-transform-active {
  position: absolute;
}
</style>
