<template>
  <div class="mark-body">
    <div v-if="markStatus" class="mark-body-status">
      {{ markStatus }}
    </div>
    <div ref="dragContainer" class="mark-body-container">
      <div v-if="!store.currentTask" class="mark-body-none">
        <div>
          <img src="@/assets/image-none-task.png" />
          <p>
            {{ store.message }}
          </p>
        </div>
      </div>
      <div
        v-else-if="store.isScanImage"
        :style="{ width: answerPaperScale }"
        :class="[`rotate-board-${rotateBoard}`]"
      >
        <template
          v-for="(item, index) in sliceImagesWithTrackList"
          :key="index"
        >
          <div class="single-image-container">
            <img
              :src="item.url"
              draggable="false"
              @click="(event) => innerMakeTrack(event, item)"
              @contextmenu="showBigImage"
            />
            <MarkDrawTrack
              :trackList="item.trackList"
              :specialTagList="item.tagList"
              :sliceImageHeight="item.originalImageHeight"
              :sliceImageWidth="item.originalImageWidth"
              :dx="item.dx"
              :dy="item.dy"
              @clickSpecialtag="(event) => clickSpecialtag(event, item)"
            />
            <div
              v-if="isCustomSpecialTag"
              v-ele-move-directive.stop.prevent="{
                moveStart: (event) => specialMouseStart(event, item),
                moveElement: specialMouseMove,
                moveStop: specialMouseStop,
              }"
              class="image-canvas"
              @click="(event) => canvasClick(event, item)"
            >
              <template v-if="curSliceImagesWithTrackItem?.url === item.url">
                <div
                  v-if="store.currentSpecialTagType === 'LINE'"
                  :style="specialLenStyle"
                ></div>
                <div
                  v-else-if="store.currentSpecialTagType === 'CIRCLE'"
                  :style="specialCircleStyle"
                ></div>
                <div
                  v-else-if="store.currentSpecialTagType === 'TEXT'"
                  v-show="cacheTextTrack.id"
                  :id="`text-edit-box-${cacheTextTrack.id}`"
                  :key="cacheTextTrack.id"
                  class="text-edit-box"
                  contenteditable
                  :style="specialTextStyle"
                  @input="textTrackInput"
                  @blur="textTrackBlur"
                  @keypress.stop
                  @keydown.stop
                  @mousedown.stop
                  @mousemove.stop
                  @mouseup.stop
                ></div>
              </template>
            </div>
          </div>
          <hr class="image-seperator" />
        </template>
      </div>
      <div v-else-if="store.isMultiMedia">
        <MultiMediaMarkBody />
      </div>
      <div v-else>未知数据</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  onMounted,
  onUnmounted,
  reactive,
  watch,
  watchEffect,
  nextTick,
} from "vue";
import { store } from "@/store/store";
import MarkDrawTrack from "../mark/MarkDrawTrack.vue";
import type { SliceImage, SpecialTag, Track } from "@/types";
import { useTimers } from "@/setups/useTimers";
import { loadImage, randomCode, addHeaderTrackColorAttr } from "@/utils/utils";
import { dragImage } from "../mark/use/draggable";
import MultiMediaMarkBody from "../mark/MultiMediaMarkBody.vue";
import "viewerjs/dist/viewer.css";
import Viewer from "viewerjs";
import { message } from "ant-design-vue";
import EventBus from "@/plugins/eventBus";
import { vEleMoveDirective } from "../mark/use/eleMove";

type MakeTrack = (
  event: MouseEvent,
  item: SliceImage,
  maxSliceWidth: number,
  theFinalHeight: number
) => void | (() => void);

const {
  hasMarkResultToRender = false,
  makeTrack = () => console.debug("非评卷界面makeTrack没有意义"),
} = defineProps<{
  hasMarkResultToRender?: boolean;
  makeTrack?: MakeTrack;
}>();

const emit = defineEmits(["error"]);

const clickSpecialtag = (event: MouseEvent, item: SliceImage) => {
  // console.log(event);
  const e = {
    target: event.target.offsetParent.childNodes[0],
    offsetX: event.offsetX + event.target.offsetLeft,
    offsetY: event.offsetY + event.target.offsetTop,
  };

  makeTrack(e as MouseEvent, item, maxImageWidth, theFinalHeight);
};

//#region : 图片拖动。在轨迹模式下，仅当没有选择分数时可用。
const { dragContainer } = dragImage();
//#endregion : 图片拖动

const { addTimeout } = useTimers();

//#region : 缩略图定位
watch(
  () => [store.minimapScrollToX, store.minimapScrollToY],
  () => {
    const container = document.querySelector<HTMLDivElement>(
      ".mark-body-container"
    );
    addTimeout(() => {
      if (
        container &&
        typeof store.minimapScrollToX === "number" &&
        typeof store.minimapScrollToY === "number"
      ) {
        const { scrollWidth, scrollHeight } = container;
        container.scrollTo({
          top: scrollHeight * store.minimapScrollToY,
          left: scrollWidth * store.minimapScrollToX,
          behavior: "smooth",
        });
      }
    }, 10);
  }
);
//#endregion : 缩略图定位

//#region : 快捷键定位
const scrollContainerByKey = (e: KeyboardEvent) => {
  const container = document.querySelector<HTMLDivElement>(
    ".mark-body-container"
  );
  if (!container) {
    return;
  }
  if (e.key === "w") {
    container.scrollBy({ top: -100, behavior: "smooth" });
  } else if (e.key === "s") {
    container.scrollBy({ top: 100, behavior: "smooth" });
  } else if (e.key === "a") {
    container.scrollBy({ left: -100, behavior: "smooth" });
  } else if (e.key === "d") {
    container.scrollBy({ left: 100, behavior: "smooth" });
  }
};
onMounted(() => {
  document.addEventListener("keypress", scrollContainerByKey);
});
onUnmounted(() => {
  document.removeEventListener("keypress", scrollContainerByKey);
});
//#endregion : 快捷键定位

//#region : 计算裁切图和裁切图上的分数轨迹和特殊标记轨迹
let rotateBoard = $ref(0);
let sliceImagesWithTrackList: SliceImage[] = reactive([]);
let maxImageWidth = 0; // 最大的裁切块宽度，图片容器以此为准
let theFinalHeight = 0; // 最终宽度，用来定位轨迹在第几张图片，不包括image-seperator高度

watch(
  () => sliceImagesWithTrackList,
  () => {
    EventBus.emit("draw-change", sliceImagesWithTrackList);
  },
  { deep: true }
);

const colors = ["red", "blue", "green"];
let colorMap = {};
function addTrackColorAttr(tList: Track[], groupNumber: number): Track[] {
  let userIds: (number | undefined)[] = tList
    .map((v) => v.userId)
    .filter((x) => !!x);
  userIds = Array.from(new Set(userIds));
  const isByMultMark = userIds.length > 1;

  tList = tList.map((item) => {
    const uid = item.userId;
    if (item.headerMarkScore) {
      item.color = "green";
    } else {
      if (!colorMap[groupNumber]) colorMap[groupNumber] = {};
      if (!colorMap[groupNumber][uid]) {
        colorMap[groupNumber][uid] =
          colors[Object.keys(colorMap[groupNumber]).length] || "green";
      }
      item.color = colorMap[groupNumber][uid];
    }
    item.isByMultMark = isByMultMark;
    return item;
  });
  return tList;
}
function addSpecialTrackColorAttr(tList: SpecialTag[]): SpecialTag[] {
  return tList.map((item) => {
    item.color = colorMap[item.groupNumber][item.userId] || "green";
    return item;
  });
}

async function processImage() {
  if (!store.currentTask) return;
  colorMap = {};
  const images = [];
  const urls = store.currentTask.sheetUrls || [];
  for (const url of urls) {
    const image = await loadImage(url);
    images.push(image);
  }

  maxImageWidth = Math.max(...images.map((i) => i.naturalWidth));
  theFinalHeight = Math.max(...images.map((i) => i.naturalHeight));
  sliceImagesWithTrackList.splice(0);

  // let trackLists = store.currentTask.questionList
  //   .map((q) => addTrackColorAttr(q.trackList, q.groupNumber))
  //   .flat();
  const trackLists = (store.currentTask.questionList || [])
    // .map((q) => q.trackList)
    .map((q) => {
      let tList = q.trackList;
      return q.headerTrack?.length
        ? addHeaderTrackColorAttr(q.headerTrack)
        : addTrackColorAttr(tList, q.groupNumber);
    })
    .flat();
  let tagLists = store.currentTask.specialTagList ?? [];
  tagLists = addSpecialTrackColorAttr(tagLists);

  let accumTopHeight = 0;
  let accumBottomHeight = 0;
  for (const url of urls) {
    const indexInSliceUrls = urls.indexOf(url) + 1;
    const image = images[indexInSliceUrls - 1];
    accumBottomHeight += image.naturalHeight;

    const thisImageTrackList = trackLists.filter(
      (t) => t.offsetIndex === indexInSliceUrls
    );
    const thisImageTagList = tagLists.filter(
      (t) => t.offsetIndex === indexInSliceUrls
    );

    sliceImagesWithTrackList.push({
      url,
      indexInSliceUrls,
      trackList: thisImageTrackList,
      tagList: thisImageTagList,
      originalImageWidth: image.naturalWidth,
      originalImageHeight: image.naturalHeight,
      width: (image.naturalWidth / maxImageWidth) * 100 + "%",
      dx: 0,
      dy: 0,
      accumTopHeight,
    });
    accumTopHeight = accumBottomHeight;
  }
}

// should not render twice at the same time
let renderLock = false;
const renderPaperAndMark = async () => {
  // console.log("renderPagerAndMark=>store.curTask:", store.currentTask);

  if (!store.currentTask) return;
  if (!store.isScanImage) return;
  if (renderLock) {
    console.log("上个任务还未渲染完毕，稍等一秒再尝试渲染");
    await new Promise((res) => setTimeout(res, 1000));
    await renderPaperAndMark();
    return;
  }

  renderLock = true;
  try {
    store.globalMask = true;
    await processImage();
  } catch (error) {
    sliceImagesWithTrackList.splice(0);
    console.trace("render error ", error);
    // 图片加载出错，自动加载下一个任务
    emit("error");
  } finally {
    renderLock = false;
    store.globalMask = false;
  }
};

watch(
  () => store.currentTask,
  () => {
    setTimeout(renderPaperAndMark, 50);
  }
);
//#endregion : 计算裁切图和裁切图上的分数轨迹和特殊标记轨迹

//#region : 放大缩小和之后的滚动
const answerPaperScale = $computed(() => {
  // 放大、缩小不影响页面之前的滚动条定位
  let percentWidth = 0;
  let percentTop = 0;
  const container = document.querySelector(".mark-body-container");
  if (container) {
    const { scrollLeft, scrollTop, scrollWidth, scrollHeight } = container;
    percentWidth = scrollLeft / scrollWidth;
    percentTop = scrollTop / scrollHeight;
  }

  addTimeout(() => {
    if (container) {
      const { scrollWidth, scrollHeight } = container;
      container.scrollTo({
        left: scrollWidth * percentWidth,
        top: scrollHeight * percentTop,
      });
    }
  }, 10);
  const scale = store.setting.uiSetting["answer.paper.scale"];
  return scale * 100 + "%";
});
//#endregion : 放大缩小和之后的滚动

//#region : 显示评分状态和清除轨迹
let markStatus = $ref("");
if (hasMarkResultToRender) {
  watch(
    () => store.currentTask,
    () => {
      markStatus = store.getMarkStatus;
    }
  );

  // 清除分数轨迹
  watchEffect(() => {
    for (const track of store.removeScoreTracks) {
      for (const sliceImage of sliceImagesWithTrackList) {
        sliceImage.trackList = sliceImage.trackList.filter(
          (t) =>
            !(
              t.mainNumber === track.mainNumber &&
              t.subNumber === track.subNumber &&
              t.number === track.number
            )
        );
      }
    }
    // 清除后，删除，否则会影响下次切换
    store.removeScoreTracks.splice(0);
  });

  // 清除特殊标记轨迹
  watchEffect(() => {
    if (!store.currentTask) return;
    for (const sliceImage of sliceImagesWithTrackList) {
      sliceImage.tagList = sliceImage.tagList.filter((t) =>
        store.currentTaskEnsured.markResult?.specialTagList.find(
          (st) =>
            st.offsetIndex === t.offsetIndex &&
            st.offsetX === t.offsetX &&
            st.offsetY === t.offsetY
        )
      );
    }
    if (store.currentTaskEnsured.markResult?.specialTagList.length === 0) {
      for (const sliceImage of sliceImagesWithTrackList) {
        sliceImage.tagList = [];
      }
    }
  });
}
//#endregion : 显示评分状态和清除轨迹

//#region : 评分
const checkTrackValid = (event: MouseEvent) => {
  const { clientWidth, clientHeight, naturalWidth, naturalHeight } =
    event.target;
  const { offsetX, offsetY } = event;
  const xLimitRate = 10 / naturalWidth;
  const yLimitRate = 10 / naturalHeight;
  const xRange = [xLimitRate * clientWidth, (1 - xLimitRate) * clientWidth];
  const yRange = [yLimitRate * clientHeight, (1 - yLimitRate) * clientHeight];

  return (
    offsetX >= xRange[0] &&
    offsetX <= xRange[1] &&
    offsetY >= yRange[0] &&
    offsetY <= yRange[1]
  );
};
const innerMakeTrack = (event: MouseEvent, item: SliceImage) => {
  if (!checkTrackValid(event)) {
    void message.warn("轨迹位置距离边界太近");
    return;
  }
  makeTrack(event, item, maxImageWidth, theFinalHeight);
};
//#endregion : 评分

//#region : 特殊标记：画线、框、文字
const isCustomSpecialTag = $computed(() => {
  return ["CIRCLE", "LINE", "TEXT"].includes(store.currentSpecialTagType);
});

let specialPoint = $ref({ x: 0, y: 0, ex: 0, ey: 0 });
let curImageTarget: HTMLElement = null;
let curSliceImagesWithTrackItem: SliceImage = $ref(null);
let cacheTextTrack = $ref({
  id: "",
  x: 0,
  y: 0,
  maxW: 0,
  maxY: 0,
  content: "",
});

const specialLenStyle = $computed(() => {
  if (specialPoint.ex <= specialPoint.x) return { display: "none" };

  const width =
    specialPoint.ex > specialPoint.x ? specialPoint.ex - specialPoint.x : 0;
  return {
    top: specialPoint.y + "px",
    left: specialPoint.x + "px",
    width: width + "px",
    position: "absolute",
    borderTop: "1px solid red",
    zIndex: 9,
  };
});
const specialCircleStyle = $computed(() => {
  if (specialPoint.ex <= specialPoint.x || specialPoint.ey <= specialPoint.y)
    return { display: "none" };

  const width =
    specialPoint.ex > specialPoint.x ? specialPoint.ex - specialPoint.x : 0;
  const height =
    specialPoint.ey > specialPoint.y ? specialPoint.ey - specialPoint.y : 0;
  return {
    top: specialPoint.y + "px",
    left: specialPoint.x + "px",
    width: width + "px",
    height: height + "px",
    position: "absolute",
    border: "1px solid red",
    borderRadius: "50%",
    zIndex: 9,
  };
});
const specialTextStyle = $computed(() => {
  return {
    top: cacheTextTrack.y + "px",
    left: cacheTextTrack.x + "px",
    minWidth: "30px",
    minHeight: "30px",
    maxWidth: curImageTarget.width - cacheTextTrack.x + "px",
    maxHeight: curImageTarget.height - cacheTextTrack.y + "px",
  };
});

function specialMouseStart(e: MouseEvent, item: SliceImage) {
  if (store.currentSpecialTagType === "TEXT") return;

  curImageTarget = e.target.parentElement.childNodes[0];
  curSliceImagesWithTrackItem = item;
  specialPoint.x = e.offsetX;
  specialPoint.y = e.offsetY;
}
function specialMouseMove({ left, top }) {
  if (store.currentSpecialTagType === "TEXT") return;

  specialPoint.ex = left + specialPoint.x;
  specialPoint.ey = top + specialPoint.y;
}
function specialMouseStop() {
  if (store.currentSpecialTagType === "TEXT") return;

  if (
    store.currentSpecialTagType === "LINE" &&
    specialPoint.ex <= specialPoint.x
  ) {
    return;
  }
  if (
    store.currentSpecialTagType === "CIRCLE" &&
    (specialPoint.ex <= specialPoint.x || specialPoint.ey <= specialPoint.y)
  ) {
    return;
  }

  const track: SpecialTag = {
    tagName: "",
    tagType: store.currentSpecialTagType,
    offsetIndex: curSliceImagesWithTrackItem.indexInSliceUrls,
    offsetX:
      specialPoint.x * (curImageTarget.naturalWidth / curImageTarget.width) +
      curSliceImagesWithTrackItem.dx,
    offsetY:
      specialPoint.y * (curImageTarget.naturalHeight / curImageTarget.height) +
      curSliceImagesWithTrackItem.dy,
    positionX: -1,
    positionY: -1,
    groupNumber: store.currentQuestion.groupNumber,
    color: "green",
  };
  track.positionX =
    (track.offsetX - curSliceImagesWithTrackItem.dx) / maxImageWidth;
  track.positionY =
    (track.offsetY -
      curSliceImagesWithTrackItem.dy +
      curSliceImagesWithTrackItem.accumTopHeight) /
    theFinalHeight;

  if (store.currentSpecialTagType === "LINE") {
    track.tagName = JSON.stringify({
      len:
        (specialPoint.ex - specialPoint.x) *
        (curImageTarget.naturalWidth / curImageTarget.width),
    });
  }
  if (store.currentSpecialTagType === "CIRCLE") {
    track.tagName = JSON.stringify({
      width:
        (specialPoint.ex - specialPoint.x) *
        (curImageTarget.naturalWidth / curImageTarget.width),
      height:
        (specialPoint.ey - specialPoint.y) *
        (curImageTarget.naturalHeight / curImageTarget.height),
    });
  }

  store.currentTaskEnsured.markResult.specialTagList.push(track);
  curSliceImagesWithTrackItem.tagList.push(track);
  specialPoint = { x: 0, y: 0, ex: 0, ey: 0 };
}

async function canvasClick(e: Event, item: SliceImage) {
  if (cacheTextTrack.id) {
    textTrackBlur();
  }

  curImageTarget = e.target.parentElement.childNodes[0];
  curSliceImagesWithTrackItem = item;

  cacheTextTrack.x = e.offsetX;
  cacheTextTrack.y = e.offsetY;
  cacheTextTrack.id = randomCode();
  cacheTextTrack.content = "";

  await nextTick(() => {
    document.getElementById(`text-edit-box-${cacheTextTrack.id}`).focus();
  });
}

function textTrackInput(e: Event) {
  cacheTextTrack.content = e.target.outerText;
}
function initCacheTextTrack() {
  cacheTextTrack = {
    x: 0,
    y: 0,
    maxW: 0,
    maxY: 0,
    content: "",
    id: "",
  };
}
function textTrackBlur() {
  if (!cacheTextTrack.content) {
    initCacheTextTrack();
    return;
  }
  const textBoxDom = document.getElementById(
    `text-edit-box-${cacheTextTrack.id}`
  );

  // 减去内边距所占宽高
  const tagName = JSON.stringify({
    width: textBoxDom.offsetWidth - 10,
    height: textBoxDom.offsetHeight - 10,
    content: cacheTextTrack.content,
  });

  const track: SpecialTag = {
    tagName,
    tagType: store.currentSpecialTagType,
    offsetIndex: curSliceImagesWithTrackItem.indexInSliceUrls,
    offsetX:
      cacheTextTrack.x * (curImageTarget.naturalWidth / curImageTarget.width) +
      curSliceImagesWithTrackItem.dx,
    offsetY:
      cacheTextTrack.y *
        (curImageTarget.naturalHeight / curImageTarget.height) +
      curSliceImagesWithTrackItem.dy,
    positionX: -1,
    positionY: -1,
    groupNumber: store.currentQuestion.groupNumber,
    color: "green",
  };
  track.positionX =
    (track.offsetX - curSliceImagesWithTrackItem.dx) / maxImageWidth;
  track.positionY =
    (track.offsetY -
      curSliceImagesWithTrackItem.dy +
      curSliceImagesWithTrackItem.accumTopHeight) /
    theFinalHeight;

  store.currentTaskEnsured.markResult.specialTagList.push(track);
  curSliceImagesWithTrackItem.tagList.push(track);
  initCacheTextTrack();
}
watch(
  () => store.currentSpecialTagType,
  () => {
    if (cacheTextTrack.id) {
      initCacheTextTrack();
    }
  }
);
//#endregion

//#region : 显示大图，供查看和翻转
const showBigImage = (event: MouseEvent) => {
  event.preventDefault();
  // console.log(event);
  let viewer: Viewer = null as unknown as Viewer;
  viewer && viewer.destroy();
  viewer = new Viewer(event.target as HTMLElement, {
    // inline: true,
    viewed() {
      viewer.zoomTo(1);
    },
    hidden() {
      viewer.destroy();
    },
    zIndex: 1000000,
  });
  viewer.show();
};
//#endregion : 显示大图，供查看和翻转

// onRenderTriggered(({ key, target, type }) => {
//   console.log({ key, target, type });
// });
let topKB = $ref(10);
// const topKBStyle = $computed(() => topKB + "%");
let leftKB = $ref(10);
// const leftKBStyle = $computed(() => leftKB + "%");
function moveCicle(event: KeyboardEvent) {
  // query mark-body-container and body to calc max/min topKB and max leftKB
  if (event.key === "k") {
    if (topKB > 1) topKB--;
  }
  if (event.key === "j") {
    if (topKB < 99) topKB++;
  }
  if (event.key === "h") {
    if (leftKB > 1) leftKB--;
  }
  if (event.key === "l") {
    if (leftKB < 99) leftKB++;
  }
  if (event.key === "c") {
    topKB = 50;
    leftKB = 50;
  }
}
function giveScoreCicle(event: KeyboardEvent) {
  // console.log(event.key);
  event.preventDefault();
  // console.log(store.currentScore);
  // 接收currentScore间隔时间外才会进入此事件
  if (event.key === " " && typeof store.currentScore === "number") {
    // topKB--;
    const circleElement = document.querySelector(".kb-circle");
    let { top, left } = circleElement.getBoundingClientRect();
    top = top + 45;
    left = left + 45;
    // console.log(top, left);
    // getBoundingClientRect().top left
    // capture => to the specific image
    const me = new MouseEvent("click", {
      bubbles: true,
      cancelable: true,
      view: window,
      clientY: top,
      clientX: left,
    });
    const eles = document.elementsFromPoint(left, top);
    // console.log(eles);
    let ele: Element;
    // if (eles[0].className === "kb-circle") {
    //   if (eles[1].tagName == "IMG") {
    //     ele = eles[1];
    //   }
    // } else
    if (eles[0].tagName == "IMG") {
      ele = eles[0];
    }
    if (ele) {
      ele.dispatchEvent(me);
    }
  }
}
onMounted(() => {
  document.addEventListener("keypress", moveCicle);
  document.addEventListener("keypress", giveScoreCicle);
});
onUnmounted(() => {
  document.removeEventListener("keypress", moveCicle);
  document.removeEventListener("keypress", giveScoreCicle);
});
// setInterval(() => {
//   _topKB++;
//   console.log(topKB);
// }, 1000);

//#region autoScroll自动跳转
let oldFirstScoreContainer: HTMLDivElement | null;
watch(
  () => store.currentTask,
  () => {
    if (store.setting.autoScroll) {
      // 给任务清理和动画留一点时间
      oldFirstScoreContainer =
        document.querySelector<HTMLDivElement>(".score-container");
      oldFirstScoreContainer?.scrollIntoView({ behavior: "smooth" });
      addTimeout(scrollToFirstScore, 1000);
    } else {
      const container = document.querySelector<HTMLDivElement>(
        ".mark-body-container"
      );
      container?.scrollTo({ top: 0, left: 0, behavior: "smooth" });
    }
  }
);
function scrollToFirstScore() {
  if (renderLock) {
    window.requestAnimationFrame(scrollToFirstScore);
  }
  addTimeout(() => {
    const firstScore =
      document.querySelector<HTMLDivElement>(".score-container");
    firstScore?.scrollIntoView({ behavior: "smooth" });
  }, 1000);
}
//#endregion
</script>

<style scoped>
.image-canvas {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9;
}
.text-edit-box {
  position: absolute;
  border: 1px solid #ff0000;
  line-height: 24px;
  padding: 5px;
  font-size: 20px;
  border-radius: 4px;
  margin: -15px 0 0 -5px;
  outline: none;
  z-index: 9;
  font-family: 黑体, arial, sans-serif;
  color: #ff0000;
}
.text-edit-box:focus {
  border-color: #ff5050;
}
</style>
