<template>
  <div class="code-container">
    <div class="code-language">
      <el-button @click="codeFormat" type="text">格式化</el-button>
      <h3>{{ languages.find(item => item.value === config.language).label || config.language}}</h3>
    </div>
    <div ref="codeRef" class="code-content" />
  </div>
</template>

<script>
import * as monaco from 'monaco-editor'
export default {
  name: "LabCode",
  model: {
    prop: 'value',
    event: 'input'
  },
  props: {
    value: {
      type: [Object, Array, String],
      default: ''
    },
    config: {
      type: Object,
      default: function() {
        return { readOnly: false, language: 'javascript' }
      }
    }
  },
  watch:{
    value: {
      deep: true,
      handler: function () {
        if (!this.inputing) {
          this.setValue(this.value)
        } else {
          this.inputing = false
        }
      }
    }
  },
  data() {
    return {
      code: '',
      inputing: false,
      editorRef: null,
      languages: [
        { value: 'javascript', label: 'js' },
        { value: 'java', label: 'java' },
        { value: 'json', label: 'json' },
        { value: 'mysql', label: 'sql' },
        { value: 'html', label: 'html' },
        { value: 'xml', label: 'xml' },
        { value: 'css', label: 'css' },
        { value: 'less', label: 'less' },
        { value: 'markdown', label: 'markdown' }
      ],
      options: {
        language: 'javascript',
        theme: 'vs',
        selectOnLineNumbers: false,
        roundedSelection: false,
        cursorStyle: 'line', // 光标样式
        automaticLayout: false, // 自动布局
        fontSize: 14, // 字体大小
        autoIndent: false, // 自动布局
        readOnly: false, // 只读
        glyphMargin: true, // 字形边缘
        lineNumbersMinChars: 0, // 行号宽度
        mouseWheelZoom: false, // 鼠标滚轮缩放字体
        minimap: {
          enabled: false // 不要小地图
        }
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.setValue(this.value)
    })
  },
  methods: {
    initMonaco() {
      const $this = this
      if (this.editorRef) {
        this.editorRef.dispose()
      }
      const allConfig = Object.assign({}, { language: 'javascript' }, $this.options, $this.config)
      // 使用 - 创建 monacoEditor 对象
      this.editorRef = monaco.editor.create($this.$refs.codeRef, {
        value: $this.code,
        ...allConfig
      })

      this.editorRef.onDidChangeModelContent(() => {
        this.inputing = true
        let val = $this.editorRef.getValue()
        if ($this.config.language === 'json') {
          const valObj = $this.$Util.toObject(val)
          val = $this.$Util.toJsonStr(valObj)
          const codeStr = $this.$Util.toJsonStr($this.code)
          if (val !== codeStr) {
            this.code = valObj
            this.$emit('input', $this.$Util.toObject(val))
            this.$emit('change', $this.$Util.toObject(val))
          }
        } else if (val !== $this.code) {
          this.code = val
          this.$emit('input', this.code)
          this.$emit('change', this.code)
        }
      })
      this.$nextTick(() => {
        this.codeFormat()
      })
    },
    codeFormat() {
      this.editorRef.trigger(this.code, 'editor.action.formatDocument')
    },
    setValue(val, language) {
      language = language || this.config.language
      if (language !== this.config.language || !this.editorRef) {
        if (this.config.language === 'json') {
          this.code = this.$Util.toJsonStr(val)
        } else {
          this.code = val
        }
        this.initMonaco()
      } else if (this.editorRef) {
        if (this.config.language === 'json') {
          this.code = this.$Util.toJsonStr(val)
        } else {
          this.code = val
        }
        if (!this.$Util.isUndefined(this.code)) {
          this.editorRef.setValue(this.code)
          this.codeFormat()
        }
      }
    }
  }
}
</script>

<style scoped lang="scss">
.code-container {
  margin: 0 6px;
  height: 100%;
  position: relative;
  text-align: left;
  .code-content {
    width:100%;
    height: 100%;
    min-height: 200px;
    border: 1px solid grey;
  }
  .code-language {
    position: absolute;
    top: 20px;
    right: 20px;
    z-index: 100;
  }
}
</style>
