component.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import { useEditor } from "@/modules/editor";
  2. import { Alignment } from "@ckeditor/ckeditor5-alignment";
  3. import { Bold, Italic } from "@ckeditor/ckeditor5-basic-styles";
  4. import { InlineEditor } from "@ckeditor/ckeditor5-editor-inline";
  5. import { Essentials } from "@ckeditor/ckeditor5-essentials";
  6. import { FontColor, FontFamily, FontSize } from "@ckeditor/ckeditor5-font";
  7. import LineHeight from "ckeditor5-line-height-latest/src/lineheight";
  8. import { Link } from "@ckeditor/ckeditor5-link";
  9. import { Paragraph } from "@ckeditor/ckeditor5-paragraph";
  10. import { css } from "@linaria/core";
  11. import {
  12. defineComponent,
  13. onUnmounted,
  14. watch,
  15. watchEffect,
  16. ref,
  17. reactive,
  18. onMounted,
  19. } from "vue";
  20. import { string } from "vue-types";
  21. import { useCompData } from ".";
  22. import { View } from "../View";
  23. import { nextTick } from "process";
  24. import { settingsStore } from "@queenjs-modules/queditor/module/stores/settings";
  25. function GetConfig() {
  26. const fontSizeOptions = [];
  27. const list = [12, 14, 16, 18, 20, 24, 28, 32, 38, 42, 46, 52, 60];
  28. for (const s of list) {
  29. fontSizeOptions.push({ title: s + "", model: s + "px" });
  30. }
  31. const fontFamilyOptions = [
  32. { title: "默认字体", model: "" },
  33. { title: "宋体", model: "宋体,Songti,STSong,serif" },
  34. { title: "黑体", model: "黑体,Heiti,STHeiti,sans-serif" },
  35. { title: "仿宋", model: "仿宋,FangSong,STFangsong,serif" },
  36. { title: "楷体", model: "楷体,KaiTi,STKaiti,sans-serif" },
  37. ];
  38. const config = {
  39. // updateSourceElementOnDestroy: true,
  40. language: "zh-cn",
  41. plugins: [
  42. Essentials,
  43. Bold,
  44. Italic,
  45. Link,
  46. Paragraph,
  47. FontColor,
  48. FontSize,
  49. FontFamily,
  50. Alignment,
  51. LineHeight,
  52. ],
  53. fontSize: {
  54. options: fontSizeOptions,
  55. supportAllValues: true,
  56. },
  57. fontFamily: {
  58. options: fontFamilyOptions,
  59. supportAllValues: true,
  60. },
  61. lineHeight: {
  62. options: [1, 1.5, 2, 2.5, 3],
  63. },
  64. toolbar: {
  65. items: [
  66. // "undo",
  67. // "redo",
  68. // "|",
  69. "fontColor",
  70. "fontFamily",
  71. "fontSize",
  72. "lineHeight",
  73. "bold",
  74. "italic",
  75. "|",
  76. "alignment",
  77. // "|",
  78. // "link",
  79. ],
  80. },
  81. };
  82. return config;
  83. }
  84. export const Component = defineComponent({
  85. props: {
  86. compId: string().def(""),
  87. },
  88. setup(props) {
  89. const comp = useCompData(props.compId);
  90. const { store, actions } = useEditor();
  91. const state = reactive({
  92. editableId: "",
  93. });
  94. if (store.isEditMode) {
  95. actions.on("textFocus", function (compId, focus) {
  96. if (compId != props.compId) return;
  97. if (focus) {
  98. state.editableId = "" + Date.now();
  99. return;
  100. }
  101. state.editableId = "";
  102. });
  103. }
  104. return () => (
  105. <View
  106. class={[textStyle]}
  107. compId={props.compId}
  108. onDblclick={() => {
  109. if (store.isEditMode) {
  110. state.editableId = "" + Date.now();
  111. }
  112. }}
  113. >
  114. {state.editableId ? (
  115. <EditorComp
  116. compId={props.compId}
  117. key={state.editableId}
  118. onLost={() => {
  119. state.editableId = "";
  120. }}
  121. />
  122. ) : (
  123. <div innerHTML={comp.value} class={readOnlyText} />
  124. )}
  125. </View>
  126. );
  127. },
  128. });
  129. const EditorComp = defineComponent({
  130. props: {
  131. compId: string().isRequired,
  132. },
  133. emits: ["lost"],
  134. setup(props, { emit }) {
  135. const inputRef = ref();
  136. let editorInstance = ref<InlineEditor>();
  137. const comp = useCompData(props.compId);
  138. const { store, actions, helper, controls } = useEditor();
  139. let blurCanceler: any = null;
  140. onMounted(() => {
  141. blurCanceler = blurHandle();
  142. });
  143. onUnmounted(() => {
  144. blurCanceler?.();
  145. });
  146. function blurHandle() {
  147. function blur(e: MouseEvent) {
  148. const target = e.target as HTMLElement;
  149. if (!editorInstance.value) return;
  150. if (
  151. editorInstance.value.ui.view.toolbar.element?.contains(target) ||
  152. editorInstance.value.ui.view.editable.element?.contains(target)
  153. ) {
  154. e.stopPropagation();
  155. return;
  156. }
  157. actions.submitUpdate();
  158. emit("lost");
  159. }
  160. document.addEventListener("mousedown", blur, {
  161. capture: true,
  162. });
  163. return () => {
  164. document.removeEventListener("mousedown", blur, { capture: true });
  165. };
  166. }
  167. const preHeight = ref<number>(0);
  168. return () => (
  169. <ckeditor
  170. class={textStyle}
  171. ref={inputRef}
  172. editor={InlineEditor}
  173. onInput={(value: any) => {
  174. if (editorInstance.value && comp.value !== value) {
  175. actions.updateCompData(comp, "value", value);
  176. nextTick(() => {
  177. const h = helper.pxToDesignSize(inputRef.value?.$el.clientHeight);
  178. const isChange = Math.abs(preHeight.value - h) > 1;
  179. preHeight.value = h;
  180. actions.updateCompDatas(
  181. comp,
  182. ["value", "layout.size.1"],
  183. [value, preHeight.value]
  184. );
  185. helper.extendStreamCard(store.currStreamCardId);
  186. if (isChange) {
  187. console.log("changing=>", isChange);
  188. actions.selectObjs([]);
  189. setTimeout(() => {
  190. actions.selectObjs([props.compId]);
  191. }, 0);
  192. }
  193. });
  194. }
  195. }}
  196. onReady={(editor: InlineEditor) => {
  197. editorInstance.value = editor;
  198. console.log("editor");
  199. editor.setData(comp.value);
  200. editor.focus();
  201. const range = document.createRange();
  202. range.selectNodeContents(inputRef.value.$el);
  203. const selection = window.getSelection();
  204. selection?.removeAllRanges();
  205. selection?.addRange(range);
  206. }}
  207. config={GetConfig()}
  208. />
  209. );
  210. },
  211. });
  212. const readOnlyText = css`
  213. pointer-events: none;
  214. word-break: break-all;
  215. `;
  216. const textStyle = css`
  217. font-size: 12px;
  218. width: 100%;
  219. color: #666;
  220. word-break: break-all;
  221. p {
  222. margin: 0;
  223. }
  224. .ck.ck-editor__editable_inline {
  225. cursor: text;
  226. overflow: hidden;
  227. > :last-child,
  228. > :first-child {
  229. margin-top: 0;
  230. margin-bottom: 0;
  231. }
  232. padding: 0 !important;
  233. }
  234. `;