{% load static %}

<link rel="stylesheet" href="{% static "css/cropper.min.css" %}">
<link rel="stylesheet" href="{% static "css/bootstrap.min.css" %}">
<link rel="stylesheet" href="{% static "css/image_crop.css" %}">
<link rel="stylesheet" href="{% static "admin/css/base.css" %}">

<script src="{% static "js/cropper.min.js" %}"></script>
<script src="{% static "js/bootstrap.min.js" %}"></script>
<script src="{% static "js/jquery-3.7.1.min.js" %}"></script>

<div class="image-crop">
  <!-- 隐藏原控件 -->
  <div class="image-field">
    <input id="image-upload"
           type="file"
           name="{{ widget.name }}"
           accept="image/*"
    />

    <label for="{{ widget.checkbox_id }}"></label>
    <input type="checkbox"
           name="{{ widget.checkbox_name }}"
           id="{{ widget.checkbox_id }}"
    />
  </div>

  <!-- 添加图片按钮 -->
  <div id="add-image">
    <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" class="bi bi-plus-lg"
         viewBox="0 0 16 16">
      <path fill-rule="evenodd"
            d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"></path>
    </svg>
  </div>

  <!-- 显示裁剪图片 -->
  <div id="show-image">
    <div id="mask">
      <i id="replaceBtn">
        <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" fill="currentColor"
             class="bi bi-arrow-left-right" viewBox="0 0 16 16">
          <path fill-rule="evenodd"
                d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5zm14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5z"></path>
        </svg>
      </i>
      &nbsp;
      <i id="deleteBtn">
        <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" fill="currentColor" class="bi bi-trash3"
             viewBox="0 0 16 16">
          <path
              d="M6.5 1h3a.5.5 0 0 1 .5.5v1H6v-1a.5.5 0 0 1 .5-.5ZM11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3A1.5 1.5 0 0 0 5 1.5v1H2.506a.58.58 0 0 0-.01 0H1.5a.5.5 0 0 0 0 1h.538l.853 10.66A2 2 0 0 0 4.885 16h6.23a2 2 0 0 0 1.994-1.84l.853-10.66h.538a.5.5 0 0 0 0-1h-.995a.59.59 0 0 0-.01 0H11Zm1.958 1-.846 10.58a1 1 0 0 1-.997.92h-6.23a1 1 0 0 1-.997-.92L3.042 3.5h9.916Zm-7.487 1a.5.5 0 0 1 .528.47l.5 8.5a.5.5 0 0 1-.998.06L5 5.03a.5.5 0 0 1 .47-.53Zm5.058 0a.5.5 0 0 1 .47.53l-.5 8.5a.5.5 0 1 1-.998-.06l.5-8.5a.5.5 0 0 1 .528-.47ZM8 4.5a.5.5 0 0 1 .5.5v8.5a.5.5 0 0 1-1 0V5a.5.5 0 0 1 .5-.5Z"></path>
        </svg>
      </i>
    </div>
    <img id="crop-image" src="" alt="{{ widget.name }}">
  </div>
</div>


<!-- Modal -->
<div class="modal fade"
     id="cropperModal"
     tabindex="-1"
     aria-labelledby="cropperModalLabel"
     aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="cropperModalLabel">图片裁剪</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <div class="proto-image">
          <img id="proto-image" src="" alt="">
        </div>

        <!-- 裁剪工具栏 -->
        <div class="cropper-tools">
          <div class="cropper-tools-item">
            <button id="crop-reset" type="button" class="btn btn-outline-primary btn-sm">
              重置图片
            </button>
          </div>

          {% if aspect_ratio|length > 0 %}
            <div class="cropper-tools-item">
              <b>裁剪比例：</b>
              <div class="btn-group btn-group-sm">
                {% for item in aspect_ratio %}
                  <button type="button" class="btn btn-outline-primary ratio-btn">
                    {{ item.0 }} : {{ item.1 }}
                  </button>
                {% endfor %}
                <button type="button" class="btn btn-outline-primary ratio-btn">
                  自由
                </button>
              </div>
            </div>
          {% endif %}

          <div class="cropper-tools-item">
            <b>图片格式：</b>
            <div>
              <select id="image-type" class="form-select form-select-sm">
                <option selected value="image/jpeg">JPG</option>
                <option value="image/png">PNG</option>
              </select>
            </div>
          </div>

          <!-- 显示裁剪大小 -->
          <div class="cropper-tools-item">
            <b>宽：</b>
            <span id="crop-w"></span>px
            &nbsp;&nbsp;&nbsp;
            <b>高：</b>
            <span id="crop-h"></span>px
          </div>

          {% if max_size %}
            <div class="cropper-tools-item">
              <b>大小限制：</b>
              {{ max_size }}kb
              <span id="crop-size"></span>
            </div>
          {% endif %}
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
        <button id="confirmBtn" type="button" class="btn btn-primary">确认</button>
      </div>
    </div>
  </div>
</div>

<script>
  /**
   * 上传图片input实例
   */
  const imageUpload = $("#image-upload")

  /**
   * 图片input实例<input id="image-input" type="file"/>
   */
  const imageInput = $('<input id="image-input" type="file"/>')

  /**
   * 清除按钮实例
   */
  const clearInput = $("#{{ widget.checkbox_id }}")

  /**
   * 图片显示容器实例
   */
  const showImage = $("#show-image")
  showImage.hide()

  /**
   * 裁剪前的图片实例
   */
  const protoImage = $("#proto-image")

  /**
   * 裁剪后的图片实例
   */
  const cropImage = $("#crop-image")

  // 模态框实例
  const cropperModal = $("#cropperModal")

  /**
   * 添加图片按钮实例
   */
  const addImage = $("#add-image")
  addImage.hide()

  /**
   * 大小限制
   */
  const cropSize = $("#crop-size")

  /**
   * 打开文件管理器
   */
  const openFileMange = () => {
    // 重置files
    imageInput[0].files = new DataTransfer().files
    imageInput && imageInput.click()
  }

  /**
   * 打开文件管理器
   */
  addImage.on("click", () => openFileMange())

  $("#replaceBtn").on("click", () => openFileMange())

  /**
   * 选择图片后，显示图片裁剪模态框
   */
  let cropper
  imageInput.on("change", () => {
    const files = imageInput.prop("files")

    if (files.length > 0) {
      const image = files[0]

      protoImage.attr("alt", image.name)
      protoImage.attr("src", URL.createObjectURL(image))

      setTimeout(() => {
        cropper = new Cropper(protoImage[0], {
          autoCropArea: 1,
          maxWidth: 235,
          maxHeight: 235,
          crop(event) {
            $("#crop-w")[0].innerHTML = event.detail.width | 0
            $("#crop-h")[0].innerHTML = event.detail.height | 0
          },
        })
      }, 250)

      cropperModal.modal("show")
    }
  })

  /**
   * 模态框确认按钮事件
   */
  $("#confirmBtn").on("click", () => cropper && saveImage())

  /**
   * base64转files
   */
  const base64ToFile = (base64, fileName) => {
    const arr = base64.split(",");
    const mime = arr[0].match(/:(.*?);/)[1];
    const bStr = atob(arr[1]);
    let n = bStr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bStr.charCodeAt(n);
    }
    return new File([u8arr], fileName, {type: mime});
  }

  // 创建definePropertyFn来挟持数据
  function definePropertyFn() {
    let obj = {}
    let val = null

    Object.defineProperties(obj, {
      val: {
        set(newV) {
          if (/data:image\/(png|jpeg);base64/.test(newV) || newV === '') {
            val = newV
          } else if (newV === "None") {
            val = ''
          } else {
            val = `/media/${newV}`
          }

          // 图片显示状态
          if (val) {
            showImage.show()
            addImage.hide()
            clearInput[0].checked = false
          } else {
            showImage.hide()
            addImage.show()
            clearInput[0].checked = true
          }

          cropImage.attr("src", val)
        }
      }
    })

    return obj
  }

  let cropImageObj = definePropertyFn()
  cropImage[0].src = cropImageObj.val

  cropImageObj.val = "{{ widget.value }}"

  /**
   * 保存裁剪的图片，待上传
   */
  const saveImage = () => {
    const imageType = $("#image-type")[0].value

    const base64Image = cropper.getCroppedCanvas().toDataURL(imageType)
    const imageFile = base64ToFile(base64Image, protoImage.prop("alt"))

    const fileKb = imageFile.size / 1024

    if ('{{ max_size }}' === 'None' || parseInt('{{ max_size }}') > fileKb) {
      let fileList = new DataTransfer()
      fileList.items.add(imageFile)
      imageUpload[0].files = fileList.files

      cropImageObj.val = base64Image
      cropperModal.modal("hide")
    } else {
      if (cropSize[0]) cropSize[0].innerHTML = `（${parseInt(`${fileKb}`)}kb）`
    }
  }

  $("#deleteBtn").on("click", () => {
    cropImageObj.val = ''
    imageUpload[0].files = new DataTransfer().files
  })

  $(".ratio-btn").each(function () {
    $(this).on('click', function () {
      const [x, y] = $(this).text().replaceAll(' ', '').split(":")
      try {
        cropper.setAspectRatio(parseInt(x) / parseInt(y))
      } catch (e) {
        cropper.setAspectRatio(null)
      }
    })
  })

  $("#crop-reset").on("click", () => cropper.reset())

  cropperModal.on("hide.bs.modal", () => {
    if (cropSize[0]) cropSize[0].innerHTML = ''
    // 存在则删除cropper实例
    cropper && cropper.destroy()
  })
</script>
