UNPKG

7.88 kBJavaScriptView Raw
1import Parse from '../parse';
2import { helperGetLastLIne } from '../helpers';
3import { isObject } from '../utils';
4
5const getUrlType = (url) => {
6 if (url.includes('guihuazhi.com')) {
7 if (url.includes('article')) {
8 return 'article';
9 } else if (url.includes('topic')) {
10 return 'topic';
11 } else {
12 return 'other';
13 }
14 } else {
15 return 'other';
16 }
17};
18
19let routes = {
20 article: {
21 route: '/app/article/detail',
22 id: 'aid'
23 },
24 topic: {
25 route: '/app/topic/detail',
26 id: 'topicId'
27 },
28 other: {
29 route: '',
30 id: 'id'
31 }
32};
33
34const getId = (url) => {
35 let str = url.split('?')[0].split('/').pop();
36 return str.slice(0, -5);
37};
38
39const textToJson = (element) => {
40 return {
41 type: 'string',
42 content: element.nodeValue
43 };
44};
45
46const strongToJson = (element) => {
47 return {
48 type: 'string',
49 bold: 1,
50 content: element.innerText
51 };
52};
53
54const aToJson = (element) => {
55 let link = element.href;
56 let type = getUrlType(link);
57 let info = routes[type];
58 return {
59 type: 'link',
60 content: element.innerText,
61 route: {
62 route: info.route,
63 webUrl: link,
64 params: {
65 [info.id]: getId(link)
66 }
67 }
68 };
69};
70
71const getValue = (element) => {
72 let elementList = element.childNodes;
73 let length = elementList.length;
74 let value = [];
75 for (let i = 0; i < length; i++) {
76 let element = elementList[i];
77 let elementType = element.nodeName;
78 let func = elementListToJsonMap[elementType];
79 if (func) {
80 let result = func(element);
81 value.push(result);
82 }
83 }
84 return value;
85};
86
87const blockElementToJson = (element) => {
88 let o = {
89 type: 'text'
90 };
91 if (element.nodeName === 'H2') {
92 o.head = 1;
93 } else if (element.nodeName === 'BLOCKQUOTE') {
94 o.block = 1;
95 }
96 if (element.classList.contains('ql-align-center')) {
97 o.center = 1;
98 }
99 o.value = getValue(element);
100 return o;
101};
102
103const hrToJson = () => {
104 return {
105 type: 'line'
106 };
107};
108
109const imageToJson = (element) => {
110 let o = {
111 type: 'image'
112 };
113 let height = element.getAttribute('height');
114 let width = element.getAttribute('width');
115 let size = element.getAttribute('size');
116 let format = element.getAttribute('format');
117 let url = element.getAttribute('url');
118 let value = element.getAttribute('value');
119 o = Object.assign(o, {height, width, size, format, url, desc: value});
120 return o;
121};
122
123const videoToJson = (element) => {
124 let o = {
125 type: 'video'
126 };
127 let result = JSON.parse(element.getAttribute('result'));
128 o = Object.assign(o, result);
129 return o;
130};
131
132const divToJson = (element) => {
133 if (element.classList.contains('huazhi-image')) {
134 return imageToJson(element);
135 } else if (element.classList.contains('huazhi-video')) {
136 return videoToJson(element);
137 }
138};
139
140const listToJson = (element) => {
141 let o = {};
142 let value = [];
143 if (element.nodeName === 'UL') {
144 o.type = 'ul'
145 } else if (element.nodeName === 'OL') {
146 o.type = 'ol'
147 }
148 let elementList = element.childNodes;
149 let length = elementList.length;
150 for (let i = 0; i < length; i++) {
151 let element = elementList[i];
152 let result = getValue(element);
153 value.push(result);
154 }
155 o.value = value;
156 return o;
157};
158
159const elementListToJsonMap = {
160 '#text': textToJson,
161 'STRONG': strongToJson,
162 'A': aToJson,
163 'P': blockElementToJson,
164 'H2': blockElementToJson,
165 'BLOCKQUOTE': blockElementToJson,
166 'HR': hrToJson,
167 'DIV': divToJson,
168 'VIDEO': videoToJson,
169 'UL': listToJson,
170 'OL': listToJson
171};
172
173const removeSpace = (json) => {
174 // 清除后换行
175 let length = json.length;
176 let count1 = 0;
177 let count2 = length;
178 for (let i = 0; i < length; i++) {
179 if (json[i].value && json[i].value.length === 0) {
180 count1 += 1;
181 } else {
182 break;
183 }
184 }
185 for (let i = length - 1; i >= 0; i--) {
186 if (json[i].value && json[i].value.length === 0) {
187 count2 -= 1;
188 } else {
189 break;
190 }
191 }
192 return json.slice(count1, count2);
193};
194
195
196class WebRich extends Parse {
197 constructor(option) {
198 super(option);
199 }
200
201 renderImage(props) {
202 // 适配quill自定义图片样式
203 let {format, height, width, size, url, desc = ''} = props;
204 let o = {format, height, width, size, url};
205 let value = desc.replace(/ /g,"&nbsp;");
206 return `<div class="huazhi-image" image=${JSON.stringify(o)} value=${value}></div>`;
207 }
208
209 renderLink(props) {
210 // return `<p><a href="${props.route.webURL}" target="_blank">${props.content}</a></p>`;
211 return `<a class="huazhi-link" target="_blank" href="${props.route.webUrl || props.route.webURL}">${props.content}</a>`;
212 }
213
214 renderVideo(props) {
215 return `<video class="huazhi-video" src="${props.url}" controls="controls" result=${JSON.stringify(props)}></video>`;
216 }
217
218
219 /**
220 * elementList => json
221 * 富文本编辑内容格式化
222 * @param {array} elementList
223 * @return {array} json结构
224 */
225 elementListToJson(elementList) {
226 let length = elementList.length;
227 let json = [];
228 for (let i = 0; i < length; i++) {
229 let element = elementList[i];
230 let elementType = element.nodeName;
231 let func = elementListToJsonMap[elementType];
232 if (func) {
233 let result = func(element);
234 json.push(result);
235 }
236 }
237 json = removeSpace(json);
238 return json;
239 };
240
241 /**
242 * ops => json
243 * 富文本编辑内容格式化
244 * @param {object} source html字符串/detail结构
245 * @param {boolean} isJSonString 是否转为json-string
246 * @return {array<object>|string} json结构
247 */
248 opsToHTML(source, isJSonString = false) {
249 let results = [];
250
251 let tmp = null;
252 for (let i = 0, l = source.length; i < l; i++) {
253 let { insert, attributes = {} } = source[i];
254 // 文本
255 if (typeof insert === 'string') {
256 const { bold, header, blockquote, link } = attributes;
257 if (!tmp) {
258 tmp = {
259 type: 'text',
260 value: []
261 };
262 }
263
264 // 标题或者引用
265 if (header === 2 || blockquote === true) {
266 let lastLine = helperGetLastLIne(tmp.value);
267
268 if (tmp.value.length) {
269 results.push(tmp);
270 }
271
272 tmp = null;
273 let block = {
274 type: 'text',
275 value: lastLine
276 };
277 if (header === 2) block.head = 1;
278
279 if (blockquote === true) block.block = 1;
280
281 results.push(block);
282 } else if (bold) {
283 tmp.value.push({ type: 'string', bold: 1, content: insert });
284 } else if (link) {
285 // 链接处理
286 let type = getUrlType(link);
287 let info = routes[type];
288 let value = {
289 type: 'link',
290 content: insert,
291 route: {
292 route: info.route,
293 webUrl: link,
294 params: {
295 [info.id]: getId(link)
296 }
297 }
298 };
299 tmp.value.push(value);
300 } else {
301 tmp.value.push({ type: 'string', content: insert });
302 }
303
304 // 非文本
305 } else if (isObject(insert)) {
306 // 清理文本
307 if (tmp && tmp.value.length) {
308 results.push(tmp);
309 tmp = null;
310 }
311
312 // 图片提取
313 if (insert.image && this.isImage(insert.image)) {
314 results.push({ ...insert.image, type: 'image' });
315 }
316
317 // 分割线
318 if (insert.hr === true) {
319 results.push({
320 type: 'line'
321 });
322 }
323
324 // 视频提取
325 if (insert.simpleVideo && insert.simpleVideo.url) {
326 results.push({ ...insert.simpleVideo, type: 'video' });
327 }
328 }
329
330 // 末尾不考虑其他因素
331 if (i === l - 1 && tmp) {
332 results.push(tmp);
333 }
334 }
335 return isJSonString ? JSON.stringify(results) : results;
336 }
337}
338
339export default WebRich;