component2.tsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import { useEditor } from "@/modules/editor";
  2. import HeadlessEditor from "./EditorCustom";
  3. import { css } from "@linaria/core";
  4. import { nextTick } from "process";
  5. import { defineComponent, onMounted, onUnmounted, reactive, ref } from "vue";
  6. import { string } from "vue-types";
  7. import { useCompData } from ".";
  8. import { View } from "../View";
  9. import { before } from "lodash";
  10. export const Component = defineComponent({
  11. props: {
  12. compId: string().def(""),
  13. },
  14. setup(props) {
  15. const comp = useCompData(props.compId);
  16. const { store, actions } = useEditor();
  17. const state = reactive({
  18. editableId: "",
  19. });
  20. if (store.isEditMode) {
  21. actions.on("textFocus", function (compId, focus) {
  22. if (compId != props.compId) return;
  23. if (focus) {
  24. state.editableId = "" + Date.now();
  25. return;
  26. }
  27. state.editableId = "";
  28. });
  29. }
  30. return () => (
  31. <View
  32. class={[textStyle]}
  33. compId={props.compId}
  34. onDblclick={() => {
  35. if (store.isEditMode) {
  36. state.editableId = "" + Date.now();
  37. }
  38. }}
  39. >
  40. {state.editableId ? (
  41. <EditorComp
  42. compId={props.compId}
  43. key={state.editableId}
  44. onLost={() => {
  45. state.editableId = "";
  46. }}
  47. />
  48. ) : (
  49. <div
  50. innerHTML={comp.value}
  51. class={[textStyle, store.isEditMode && `pointer-events-none`]}
  52. />
  53. )}
  54. </View>
  55. );
  56. },
  57. });
  58. const EditorComp = defineComponent({
  59. props: {
  60. compId: string().isRequired,
  61. },
  62. emits: ["lost"],
  63. setup(props, { emit }) {
  64. let editorRefVal = ref<HeadlessEditor>().value;
  65. const comp = useCompData(props.compId);
  66. const { store, actions, helper, controls } = useEditor();
  67. let blurCanceler: any = null;
  68. onUnmounted(() => {
  69. blurCanceler?.();
  70. });
  71. const preHeight = ref<number>(0);
  72. const initHeight = () => {
  73. const dom: HTMLElement | null = document.querySelector(
  74. `#editor_${props.compId}`
  75. );
  76. if (!dom) {
  77. return false;
  78. }
  79. const h = helper.pxToDesignSize(dom.clientHeight);
  80. const isChange = Math.abs(preHeight.value - h) > 1;
  81. preHeight.value = h;
  82. actions.updateCompData(comp, "layout.size.1", preHeight.value);
  83. helper.extendStreamCard(store.currStreamCardId);
  84. if (isChange) {
  85. actions.selectObjs([]);
  86. setTimeout(() => {
  87. actions.selectObjs([props.compId]);
  88. }, 0);
  89. }
  90. };
  91. function isInCkBodyWrapper(dom: HTMLElement) {
  92. const out = {in: false, stop: true};
  93. if (editorRefVal) {
  94. const in1 =
  95. editorRefVal.ui.view.toolbar.element?.contains(dom) ||
  96. editorRefVal.ui.view.editable.element?.contains(dom);
  97. if (in1) {
  98. out.in = true;
  99. return out;
  100. }
  101. const toolbarWrapper = document.querySelector("#text_toolbar");
  102. if (toolbarWrapper === dom || toolbarWrapper?.contains(dom)) {
  103. out.in = true;
  104. out.stop = false;
  105. return out;
  106. }
  107. }
  108. let n = 0;
  109. let curr:any = dom;
  110. do {
  111. if (curr.id == "toptoolbar") {
  112. out.in = true;
  113. return out;
  114. };
  115. curr = curr.parentElement;
  116. n +=1;
  117. if (n > 10) break;
  118. }while(curr)
  119. return out;
  120. }
  121. function blurHandle() {
  122. function blur(e: MouseEvent) {
  123. const target = e.target as HTMLElement;
  124. if (!editorRefVal) return;
  125. const test = isInCkBodyWrapper(target)
  126. if (test.in) {
  127. if (test.stop) {
  128. e.stopPropagation();
  129. }
  130. return;
  131. }
  132. actions.submitUpdate();
  133. emit("lost");
  134. }
  135. document.addEventListener("mousedown", blur, {
  136. capture: true,
  137. });
  138. return () => {
  139. document.removeEventListener("mousedown", blur, { capture: true });
  140. };
  141. }
  142. const initEditor = async () => {
  143. const dom: HTMLElement | null = document.querySelector(
  144. `#editor_${props.compId}`
  145. );
  146. if (!dom) {
  147. return;
  148. }
  149. editorRefVal = await HeadlessEditor.create(dom);
  150. editorRefVal.setData(comp.value);
  151. editorRefVal.focus();
  152. const range = document.createRange();
  153. range.selectNodeContents(dom);
  154. const selection = window.getSelection();
  155. selection?.removeAllRanges();
  156. selection?.addRange(range);
  157. editorRefVal.model.document.on("change:data", () => {
  158. const value = editorRefVal?.getData();
  159. if (comp.value !== value) {
  160. actions.updateCompData(comp, "value", value);
  161. nextTick(() => {
  162. const element = editorRefVal?.ui.view.editable.element || null;
  163. if (!element) {
  164. return;
  165. }
  166. const h = helper.pxToDesignSize(element.clientHeight);
  167. const isChange = Math.abs(preHeight.value - h) > 1;
  168. preHeight.value = h;
  169. actions.updateCompDatas(
  170. comp,
  171. ["value", "layout.size.1"],
  172. [value, preHeight.value]
  173. );
  174. helper.extendStreamCard(store.currStreamCardId);
  175. if (isChange) {
  176. console.log("changing=>", isChange);
  177. actions.selectObjs([]);
  178. setTimeout(() => {
  179. actions.selectObjs([props.compId]);
  180. }, 0);
  181. }
  182. });
  183. }
  184. });
  185. controls.textEditor = editorRefVal;
  186. };
  187. onMounted(() => {
  188. initEditor();
  189. blurCanceler = blurHandle();
  190. nextTick(() => {
  191. initHeight();
  192. });
  193. });
  194. return () => {
  195. return <div class={textStyle} id={`editor_${props.compId}`}></div>;
  196. };
  197. // return () => (
  198. // <ckeditor
  199. // class={textStyle}
  200. // ref={inputRef}
  201. // editor={InlineEditor}
  202. // onInput={(value: any) => {
  203. // if (editorInstance.value && comp.value !== value) {
  204. // actions.updateCompData(comp, "value", value);
  205. // nextTick(() => {
  206. // const h = helper.pxToDesignSize(inputRef.value?.$el.clientHeight);
  207. // const isChange = Math.abs(preHeight.value - h) > 1;
  208. // preHeight.value = h;
  209. // actions.updateCompDatas(
  210. // comp,
  211. // ["value", "layout.size.1"],
  212. // [value, preHeight.value]
  213. // );
  214. // helper.extendStreamCard(store.currStreamCardId);
  215. // if (isChange) {
  216. // console.log("changing=>", isChange);
  217. // actions.selectObjs([]);
  218. // setTimeout(() => {
  219. // actions.selectObjs([props.compId]);
  220. // }, 0);
  221. // }
  222. // });
  223. // }
  224. // }}
  225. // onReady={(editor: InlineEditor) => {
  226. // editorInstance.value = editor;
  227. // console.log("editor");
  228. // editor.setData(comp.value);
  229. // editor.focus();
  230. // const range = document.createRange();
  231. // range.selectNodeContents(inputRef.value.$el);
  232. // const selection = window.getSelection();
  233. // selection?.removeAllRanges();
  234. // selection?.addRange(range);
  235. // }}
  236. // config={GetConfig()}
  237. // />
  238. // );
  239. },
  240. });
  241. const textStyle = css`
  242. font-size: 14px;
  243. width: 100%;
  244. color: #666;
  245. word-break: break-all;
  246. h2 {
  247. color: #111;
  248. font-size: 24px;
  249. font-weight: 600;
  250. }
  251. h3 {
  252. font-size: 18px;
  253. color: #333;
  254. }
  255. p {
  256. margin: 0;
  257. }
  258. .ck.ck-editor__editable_inline {
  259. cursor: text;
  260. overflow: hidden;
  261. border: none !important;
  262. > :last-child,
  263. > :first-child {
  264. margin-top: 0;
  265. margin-bottom: 0;
  266. }
  267. padding: 0 !important;
  268. }
  269. `;