zydx-plus 1.33.334 → 1.33.336
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -2
- package/src/components/editor/src/butJson.js +6 -0
- package/src/components/editor/src/editor.vue +339 -55
- package/src/components/editor2/src/editor.vue +1 -1
- package/src/components/seek/src/word.vue +1 -1
- package/src/components/tagging/src/tagging.vue +1 -1
- package/src/components/utils/html2json.js +466 -0
- package/src/components/word/src/word.vue +1 -1
- package/src/components/word2/src/word.vue +1 -1
- package/src/index.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zydx-plus",
|
|
3
|
-
"version": "1.33.
|
|
3
|
+
"version": "1.33.336",
|
|
4
4
|
"description": "Vue.js",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"snabbdom": "^3.5.1",
|
|
26
26
|
"katex": "^0.15.6",
|
|
27
27
|
"simple-mind-map": "^0.9.6",
|
|
28
|
-
"html2json": "^1.0.2",
|
|
29
28
|
"@tiptap/starter-kit": "^2.0.3",
|
|
30
29
|
"@tiptap/vue-3": "^2.0.3",
|
|
31
30
|
"@tiptap/extension-bubble-menu": "^2.1.0",
|
|
@@ -65,6 +65,12 @@ export function butJson (editor,data) {
|
|
|
65
65
|
menuKeys: [],
|
|
66
66
|
html: `<p style="text-align: center;"><span style="color: rgb(225, 60, 57);font-size: 48px;">XXXXXXX(单位)文件</span></p><p data-signId="red" style="text-align: center;"><span style="color: rgb(0, 0, 0);font-size: 16px;">xxx〔xx〕xxxx 号</span></p>`
|
|
67
67
|
},
|
|
68
|
+
// voiceInput: {
|
|
69
|
+
// name: '语音输入',
|
|
70
|
+
// flip:'关闭语音',
|
|
71
|
+
// key: 'voiceInput',
|
|
72
|
+
// menuKeys: []
|
|
73
|
+
// },
|
|
68
74
|
authorMenu: {
|
|
69
75
|
name: '作者',
|
|
70
76
|
key: 'authorMenu',
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
</label>
|
|
11
11
|
</div>
|
|
12
12
|
<div v-else class="editor-but-name" @click="butTap(item,0)">
|
|
13
|
-
<span v-html="item.name"></span>
|
|
13
|
+
<span v-if="item.key === 'voiceInput'" :class="{'but-name-color':voiceOpen}" v-html="voiceOpen?item.flip:item.name"></span>
|
|
14
|
+
<span v-else v-html="item.name"></span>
|
|
14
15
|
<img v-if="item.menuKeys.length > 0"
|
|
15
16
|
src="data:image/png;base64,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"
|
|
16
17
|
alt=""/>
|
|
@@ -28,6 +29,11 @@
|
|
|
28
29
|
</ul>
|
|
29
30
|
</div>
|
|
30
31
|
</div>
|
|
32
|
+
<div class="editor-but" >
|
|
33
|
+
<div class="editor-but-name" @click="butTap({key:'voiceInput'},0)">
|
|
34
|
+
<span :class="{'but-name-color':voiceOpen}" v-html="voiceOpen?'关闭语音':'语音输入'"></span>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
31
37
|
<!-- <div class="editor-but">-->
|
|
32
38
|
<!-- <div class="editor-but-name">-->
|
|
33
39
|
<!-- <label>-->
|
|
@@ -37,7 +43,7 @@
|
|
|
37
43
|
<!-- </div>-->
|
|
38
44
|
<!-- </div>-->
|
|
39
45
|
</div>
|
|
40
|
-
<div class="editor-content" :class="{'editor-content-show': !editableShow}">
|
|
46
|
+
<div class="editor-content" :class="{'editor-content-show': !editableShow }">
|
|
41
47
|
<div class="editing">
|
|
42
48
|
<div class="editing-header" v-if="signMenuShow">
|
|
43
49
|
<img :src="menusData('signMenu')?.ico" alt=""/>
|
|
@@ -64,8 +70,8 @@
|
|
|
64
70
|
<img :src="menusData('signMenu')?.ico" alt=""/>
|
|
65
71
|
<span>{{ menusData('signMenu')?.text }}</span>
|
|
66
72
|
</div>
|
|
67
|
-
<div class="read-only-page" @click="menusTap" :style="{height: wit * 1.
|
|
68
|
-
v-for="(item,index) in htmlArr">
|
|
73
|
+
<div class="read-only-page" @click="menusTap" :style="{height: wit * 1.6 + 'px',width: wit + 'px'}"
|
|
74
|
+
v-for="(item,index) in htmlArr" :key="index">
|
|
69
75
|
<div class="read-only-p" v-html="item"></div>
|
|
70
76
|
<div class="read-only-a">{{ index + 1 }}/{{ htmlArr.length }}</div>
|
|
71
77
|
</div>
|
|
@@ -79,13 +85,24 @@
|
|
|
79
85
|
</div>
|
|
80
86
|
</div>
|
|
81
87
|
<div class="down-html" id="test" v-html="htmlArr2"></div>
|
|
88
|
+
<div v-if="voiceOpen" class="speak"
|
|
89
|
+
@mousedown.stop="mousedown"
|
|
90
|
+
@mouseup.stop="mouseup"
|
|
91
|
+
:style="{transform: `translate(${x}px, ${y}px)`}">
|
|
92
|
+
<div class="speak-cont">
|
|
93
|
+
<svg t="1698630789078" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4553" width="15" height="15"><path d="M533.84533333 930.88426667c-13.65333333 0-24.576-10.92266667-24.576-24.576v-122.33386667c0-13.65333333 10.92266667-24.576 24.576-24.576s24.576 10.92266667 24.576 24.576v122.33386667c-0.54613333 13.65333333-11.4688 24.576-24.576 24.576zM533.84533333 686.21653333c-101.03466667 0-183.5008-82.46613333-183.5008-183.5008V258.048c0-101.03466667 82.46613333-183.5008 183.5008-183.5008s183.5008 82.46613333 183.5008 183.5008v244.66773333c0 101.03466667-82.46613333 183.5008-183.5008 183.5008z m0-563.06346666c-74.27413333 0-134.89493333 60.6208-134.89493333 134.89493333v244.66773333c0 74.27413333 60.6208 134.89493333 134.89493333 134.89493334s134.89493333-60.6208 134.89493334-134.89493334V258.048c-0.54613333-74.27413333-60.6208-134.89493333-134.89493334-134.89493333z" fill="#fff" p-id="4554"></path><path d="M533.84533333 808.5504c-168.7552 0-305.83466667-137.07946667-305.83466666-305.83466667 0-13.65333333 10.92266667-24.576 24.576-24.576s24.576 10.92266667 24.576 24.576c0 141.99466667 115.23413333 257.2288 257.2288 257.2288S790.528 644.7104 790.528 502.71573333c0-13.65333333 10.92266667-24.576 24.576-24.576s24.576 10.92266667 24.576 24.576c0 168.7552-137.07946667 305.83466667-305.83466667 305.83466667zM729.36106667 955.46026667H337.78346667c-13.65333333 0-24.576-10.92266667-24.576-24.576s10.92266667-24.576 24.576-24.576h391.5776c13.65333333 0 24.576 10.92266667 24.576 24.576s-10.92266667 24.576-24.576 24.576z" fill="#FFF" p-id="4555"></path></svg>
|
|
94
|
+
<svgs :vol="vol"></svgs>
|
|
95
|
+
<span>{{ error? '连接中...' : '正在说话...' }}</span>
|
|
96
|
+
<svg style="cursor: pointer" @click="close" t="1698630749910" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4415" width="20" height="20"><path d="M726.976 274.432a16 16 0 0 0-22.656 0L512 466.752l-192.32-192.32a16 16 0 0 0-22.624 0l-22.656 22.624a16 16 0 0 0 0 22.624l192.32 192.32-192.32 192.32a16 16 0 0 0 0 22.656l22.656 22.624a16 16 0 0 0 22.624 0l192.32-192.32 192.32 192.32a16 16 0 0 0 22.656 0l22.624-22.624a16 16 0 0 0 0-22.624L557.28 512l192.32-192.352a16 16 0 0 0 0-22.624l-22.624-22.624z" fill="#fff" p-id="4416"></path></svg>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
82
99
|
</div>
|
|
83
100
|
</template>
|
|
84
101
|
|
|
85
102
|
<script>
|
|
86
103
|
import exportWord from 'js-export-word'
|
|
87
104
|
import mammoth from './mammoth.browser.min'
|
|
88
|
-
import {html2json, json2html} from 'html2json'
|
|
105
|
+
import {html2json, json2html} from '@/components/utils/html2json.js'
|
|
89
106
|
import {butJson} from './butJson'
|
|
90
107
|
import {Editor, EditorContent} from '@tiptap/vue-3'
|
|
91
108
|
import StarterKit from '@tiptap/starter-kit'
|
|
@@ -105,12 +122,18 @@ import {Contenteditable} from "./extend/contenteditable";
|
|
|
105
122
|
import {titleId} from "./extend/title-id";
|
|
106
123
|
import {dataUrl} from "./extend/data-url";
|
|
107
124
|
import Mess from '../../tipBox/index'
|
|
125
|
+
import svgs from "@/components/editor2/src/level.vue";
|
|
126
|
+
import Recorder from 'js-audio-recorder'
|
|
108
127
|
|
|
109
128
|
export default {
|
|
110
129
|
name: 'zydx-editor',
|
|
111
|
-
components: {EditorContent},
|
|
130
|
+
components: {svgs, EditorContent},
|
|
112
131
|
beforeUnmount() {
|
|
113
132
|
this.editor.destroy()
|
|
133
|
+
this.recorder?.destroy()
|
|
134
|
+
this.ws?.send(JSON.stringify({"type":"CANCEL"}))
|
|
135
|
+
this.ws?.close()
|
|
136
|
+
this.ws = null
|
|
114
137
|
},
|
|
115
138
|
data() {
|
|
116
139
|
return {
|
|
@@ -132,7 +155,23 @@ export default {
|
|
|
132
155
|
top: '0px',
|
|
133
156
|
left: '0px'
|
|
134
157
|
},
|
|
135
|
-
menuStast: null
|
|
158
|
+
menuStast: null,
|
|
159
|
+
|
|
160
|
+
voiceOpen:false,
|
|
161
|
+
limits:false,
|
|
162
|
+
speech: {},
|
|
163
|
+
recorder: null,
|
|
164
|
+
ws: null,
|
|
165
|
+
left: 0,
|
|
166
|
+
top: 0,
|
|
167
|
+
isMove: false,
|
|
168
|
+
x: 1600,
|
|
169
|
+
y: 230,
|
|
170
|
+
vol: 0,
|
|
171
|
+
error: false,
|
|
172
|
+
appData: {},
|
|
173
|
+
audioData: [],
|
|
174
|
+
time: {}
|
|
136
175
|
}
|
|
137
176
|
},
|
|
138
177
|
props: {
|
|
@@ -202,19 +241,27 @@ export default {
|
|
|
202
241
|
deep: true
|
|
203
242
|
},
|
|
204
243
|
readOnly: {
|
|
205
|
-
handler: function (e
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
244
|
+
handler: function (e) {
|
|
245
|
+
let time = setInterval(() => {
|
|
246
|
+
if (this.editor) { // 没有时间以后 停止定时器
|
|
247
|
+
this.editor.setOptions({
|
|
248
|
+
editable: !e
|
|
249
|
+
})
|
|
250
|
+
if (this.page) {
|
|
251
|
+
this.editableShow = !e
|
|
252
|
+
setTimeout(() => {
|
|
253
|
+
this.readOnlyPage() // 只读分页
|
|
254
|
+
},300)
|
|
255
|
+
}
|
|
256
|
+
clearInterval(time) //停止计时器,清除定时器
|
|
257
|
+
}
|
|
258
|
+
}, 10)
|
|
213
259
|
},
|
|
214
|
-
deep: true
|
|
260
|
+
deep: true,
|
|
261
|
+
immediate: true
|
|
215
262
|
},
|
|
216
263
|
menusText: {
|
|
217
|
-
handler: function (
|
|
264
|
+
handler: function () {
|
|
218
265
|
this.organizeButton()
|
|
219
266
|
},
|
|
220
267
|
deep: true
|
|
@@ -283,20 +330,27 @@ export default {
|
|
|
283
330
|
],
|
|
284
331
|
injectCSS: true,
|
|
285
332
|
onBlur: () => {
|
|
333
|
+
_this.limits = false
|
|
286
334
|
_this.menuStast = null
|
|
335
|
+
_this.close()
|
|
287
336
|
_this.butDataName('outlineMenu','大纲级别')
|
|
288
337
|
_this.butDataName('textMenu','字号')
|
|
289
338
|
_this.butDataName('titleMenu','字体')
|
|
290
339
|
},
|
|
340
|
+
// 获取焦点
|
|
341
|
+
onFocus: () => {
|
|
342
|
+
this.limits = true
|
|
343
|
+
},
|
|
291
344
|
onTransaction: () => {
|
|
292
345
|
const index = _this.editor.state.selection.$anchor.path[1]
|
|
346
|
+
// console.log(index)
|
|
293
347
|
const json = _this.editor.getJSON()
|
|
294
348
|
for (let i = 0; i < json.content.length; i++) {
|
|
295
349
|
if(index === i) {
|
|
296
350
|
if(json.content[i].content === undefined) break
|
|
297
351
|
const attrs = json.content[i].attrs
|
|
298
352
|
if(attrs.titleId === 'text') {
|
|
299
|
-
_this.butDataName('正文文本')
|
|
353
|
+
_this.butDataName('outlineMenu','正文文本')
|
|
300
354
|
}
|
|
301
355
|
if(attrs.signId !== null) {
|
|
302
356
|
_this.butData.map(x => {
|
|
@@ -308,6 +362,8 @@ export default {
|
|
|
308
362
|
if(attrs.signId === 'title-4') x.name = '四级标题'
|
|
309
363
|
}
|
|
310
364
|
})
|
|
365
|
+
}else {
|
|
366
|
+
_this.butDataName('outlineMenu','大纲级别')
|
|
311
367
|
}
|
|
312
368
|
if(json.content[i].content[0].marks === undefined) break
|
|
313
369
|
const style = json.content[i].content[0].marks
|
|
@@ -344,6 +400,17 @@ export default {
|
|
|
344
400
|
}
|
|
345
401
|
})
|
|
346
402
|
_this.organizeButton()
|
|
403
|
+
this.recorderInit()
|
|
404
|
+
document.addEventListener('mousemove', (event) => {
|
|
405
|
+
if (!this.isMove) return
|
|
406
|
+
this.limits = true
|
|
407
|
+
this.x = event.clientX - this.left;
|
|
408
|
+
this.y = event.clientY - this.top;
|
|
409
|
+
})
|
|
410
|
+
// document.addEventListener('click', () => {
|
|
411
|
+
// // if(this.limits) return
|
|
412
|
+
// // this.close()
|
|
413
|
+
// })
|
|
347
414
|
},
|
|
348
415
|
emits: ['confirm', 'enclosure', 'enlDownload', 'enlSee'],
|
|
349
416
|
methods: {
|
|
@@ -515,7 +582,7 @@ export default {
|
|
|
515
582
|
const data = document.querySelectorAll('.editing-cont')[0].childNodes[0].childNodes
|
|
516
583
|
this.wit = document.getElementsByClassName('editor-content')[0].offsetWidth + 20
|
|
517
584
|
if (this.wit > 900) this.wit = 900
|
|
518
|
-
let max = this.wit * 1.
|
|
585
|
+
let max = this.wit * 1.6 - 246
|
|
519
586
|
let pHeight = 0
|
|
520
587
|
let html = ''
|
|
521
588
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -533,19 +600,19 @@ export default {
|
|
|
533
600
|
html = ''
|
|
534
601
|
}
|
|
535
602
|
}
|
|
536
|
-
let text = data[i].offsetHeight
|
|
537
603
|
if (data[i].dataset?.signid === 'ack') {
|
|
538
604
|
this.htmlArr.push(html)
|
|
539
605
|
pHeight = 0
|
|
540
606
|
html = ''
|
|
541
607
|
}
|
|
608
|
+
let text = data[i].offsetHeight
|
|
542
609
|
if ((pHeight + text) > max) {
|
|
543
610
|
const {start, end, size} = this.rows(data[i], max - pHeight)
|
|
544
|
-
html += `<p class="text"><span style="font-family:
|
|
611
|
+
html += `<p class="text"><span style="font-family: Microsoft Yahei; font-size: ${size}px">${start.data}</span></p>`
|
|
545
612
|
this.htmlArr.push(html)
|
|
546
613
|
pHeight = 0
|
|
547
614
|
html = ''
|
|
548
|
-
html += `<p class="text"><span style="font-family:
|
|
615
|
+
html += `<p class="text"><span style="font-family: Microsoft Yahei;font-size: ${size}px">${end.data}</span></p>`
|
|
549
616
|
pHeight = end.size
|
|
550
617
|
} else {
|
|
551
618
|
pHeight += text
|
|
@@ -621,7 +688,7 @@ export default {
|
|
|
621
688
|
width += 3.25;
|
|
622
689
|
num += 1
|
|
623
690
|
} else if (/[\u4e00-\u9fa5]/.test(text[i])) { //中文匹配
|
|
624
|
-
width += 10.
|
|
691
|
+
width += 10.102;
|
|
625
692
|
num += 1
|
|
626
693
|
} else if (/\(|\)/.test(text[i])) { // 括号匹配
|
|
627
694
|
width += 3.73;
|
|
@@ -835,6 +902,48 @@ export default {
|
|
|
835
902
|
}
|
|
836
903
|
})
|
|
837
904
|
},
|
|
905
|
+
cursorPosition(data, index) {
|
|
906
|
+
let num = 0
|
|
907
|
+
for (let i = 0; i < data.length; i++) {
|
|
908
|
+
num += data[i].nodeSize
|
|
909
|
+
if (i === index) break
|
|
910
|
+
}
|
|
911
|
+
return num
|
|
912
|
+
},
|
|
913
|
+
selectionPath(v, n) {
|
|
914
|
+
let num = 0
|
|
915
|
+
const path = this.editor.state.selection.$head.path[0].content.content
|
|
916
|
+
for (let i = 0; i < path.length; i++) {
|
|
917
|
+
num += path[i].nodeSize
|
|
918
|
+
if (n !== undefined) {
|
|
919
|
+
if (i === n) break
|
|
920
|
+
} else {
|
|
921
|
+
if (path[i].attrs?.signId === v) {
|
|
922
|
+
if (v === 'red') num += 1
|
|
923
|
+
break
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
return num
|
|
928
|
+
},
|
|
929
|
+
signIdData(id) {
|
|
930
|
+
return this.$nextTick(() => {
|
|
931
|
+
let state = -1
|
|
932
|
+
const json = this.editor.getJSON()
|
|
933
|
+
for (let i = 0; i < json.content.length; i++) {
|
|
934
|
+
if (json.content[i].attrs?.signId === id) {
|
|
935
|
+
state = i
|
|
936
|
+
break
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
return state
|
|
940
|
+
})
|
|
941
|
+
},
|
|
942
|
+
selection() {
|
|
943
|
+
const {from} = this.editor.state.selection
|
|
944
|
+
return from
|
|
945
|
+
},
|
|
946
|
+
|
|
838
947
|
async butTap(data, key) {
|
|
839
948
|
if(data.key === 'textMenu' && key === 0 || data.key === 'titleMenu' && key === 0) return
|
|
840
949
|
// 标志
|
|
@@ -981,51 +1090,198 @@ export default {
|
|
|
981
1090
|
this.imgPop = true
|
|
982
1091
|
}
|
|
983
1092
|
}
|
|
1093
|
+
if (data.key === 'voiceInput' ){
|
|
1094
|
+
this.voice()
|
|
1095
|
+
}
|
|
984
1096
|
setTimeout(() => {
|
|
985
1097
|
this.menuStast = null
|
|
986
1098
|
},1000)
|
|
987
1099
|
},
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1100
|
+
close() {
|
|
1101
|
+
if(this.ws === null) return
|
|
1102
|
+
this.voiceOpen = false
|
|
1103
|
+
this.ws?.send(JSON.stringify({"type":"CANCEL"}))
|
|
1104
|
+
this.ws?.close()
|
|
1105
|
+
this.ws = null
|
|
1106
|
+
this.recorder.stop() // 停止录音
|
|
1107
|
+
this.recorder.destroy()
|
|
1108
|
+
},
|
|
1109
|
+
voice() {
|
|
1110
|
+
this.voiceOpen = !this.voiceOpen
|
|
1111
|
+
this.limits = false
|
|
1112
|
+
if(this.voiceOpen) {
|
|
1113
|
+
this.recorder.start().then(() => { // 开始录音
|
|
1114
|
+
this.audioData = []
|
|
1115
|
+
this.appID()
|
|
1116
|
+
}, (err) => {
|
|
1117
|
+
Mess({
|
|
1118
|
+
type: 'text',
|
|
1119
|
+
cancelShow: false,
|
|
1120
|
+
promptContent: '录音失败,请检查麦克风是否可用'
|
|
1121
|
+
})
|
|
1122
|
+
});
|
|
1123
|
+
}else {
|
|
1124
|
+
this.close()
|
|
993
1125
|
}
|
|
994
|
-
return num
|
|
995
1126
|
},
|
|
996
|
-
|
|
997
|
-
let
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1127
|
+
appID() {
|
|
1128
|
+
let token = null
|
|
1129
|
+
let remember = localStorage.getItem('remember')
|
|
1130
|
+
if(remember === '1') {
|
|
1131
|
+
token = localStorage.getItem('sessionId')
|
|
1132
|
+
}else {
|
|
1133
|
+
token = sessionStorage.getItem('sessionId')
|
|
1134
|
+
}
|
|
1135
|
+
const xhr = new XMLHttpRequest()
|
|
1136
|
+
// xhr.open('GET', 'http://192.168.15.124:8888/zydx/voice/getDesKeyId')
|
|
1137
|
+
// xhr.setRequestHeader('Authorization', '4a7ab02c-11b7-420f-bf85-ac5549b2aa81')
|
|
1138
|
+
xhr.open('GET', '/zydx/voice/getDesKeyId')
|
|
1139
|
+
xhr.setRequestHeader('Authorization', token)
|
|
1140
|
+
this.error = true
|
|
1141
|
+
xhr.onreadystatechange = () => {
|
|
1142
|
+
if (xhr.readyState === 4) {
|
|
1143
|
+
if (xhr.status === 200) {
|
|
1144
|
+
this.appData = JSON.parse(xhr.responseText).data
|
|
1145
|
+
this.webSocketInit()
|
|
1007
1146
|
}
|
|
1008
1147
|
}
|
|
1009
1148
|
}
|
|
1010
|
-
|
|
1149
|
+
xhr.send()
|
|
1011
1150
|
},
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1151
|
+
// 初始化音频获取
|
|
1152
|
+
recorderInit(){
|
|
1153
|
+
let _this = this
|
|
1154
|
+
// 初始化录音
|
|
1155
|
+
this.recorder = new Recorder({
|
|
1156
|
+
sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
|
|
1157
|
+
sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
|
|
1158
|
+
numChannels: 1, // 声道,支持 1 或 2, 默认是1
|
|
1159
|
+
})
|
|
1160
|
+
this.recorder.onprogress = function (params) {
|
|
1161
|
+
_this.vol = params.vol
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1164
|
+
webSocketInit() {
|
|
1165
|
+
const _this = this
|
|
1166
|
+
this.ws = new WebSocket(`wss://vop.baidu.com/realtime_asr?sn=${this.getRandomCode(15)}`)
|
|
1167
|
+
this.ws.binaryType = 'arraybuffer'
|
|
1168
|
+
this.ws.onopen = function () {
|
|
1169
|
+
_this.error = false
|
|
1170
|
+
const json = {
|
|
1171
|
+
type: 'START',
|
|
1172
|
+
data: {
|
|
1173
|
+
appid: Number(_this.appData.qfClientId),
|
|
1174
|
+
appkey: _this.appData.qfClientSecret,
|
|
1175
|
+
dev_pid: 15372,
|
|
1176
|
+
cuid: 'HpURryNC91ddJmAPq7iwu26OvMDW4jMS',
|
|
1177
|
+
format: 'pcm',
|
|
1178
|
+
sample: 16000,
|
|
1020
1179
|
}
|
|
1021
1180
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1181
|
+
_this.ws.send(JSON.stringify(json))
|
|
1182
|
+
_this.getAudioSuccess()
|
|
1183
|
+
}
|
|
1184
|
+
this.ws.onmessage = function (e) {
|
|
1185
|
+
const data = JSON.parse(e.data)
|
|
1186
|
+
if(data.err_no === 0){
|
|
1187
|
+
const json = _this.editor.getJSON()
|
|
1188
|
+
const index = _this.editor.state.selection.$anchor.path[1]
|
|
1189
|
+
if(data.start_time === _this.time.start_time) {
|
|
1190
|
+
const text = json.content[index].content[0].text
|
|
1191
|
+
json.content[index].content[0].text = text.slice(0, text.length - _this.time.result.length) + data.result
|
|
1192
|
+
_this.editor.commands.setContent(json)
|
|
1193
|
+
}else {
|
|
1194
|
+
_this.editor.chain().focus().insertContentAt(_this.selection(), data.result).run()
|
|
1195
|
+
}
|
|
1196
|
+
_this.time = data
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
this.ws.onerror = function () {
|
|
1200
|
+
// 连接失败重连
|
|
1201
|
+
setTimeout(() => {
|
|
1202
|
+
_this.webSocketInit()
|
|
1203
|
+
}, 5000)
|
|
1204
|
+
}
|
|
1024
1205
|
},
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1206
|
+
getAudioSuccess() {
|
|
1207
|
+
let that = this
|
|
1208
|
+
const mediaStreamSource = that.recorder.audioInput
|
|
1209
|
+
// 创建一个音频分析对象,采样的缓冲区大小为0(自动适配),输入和输出都是单声道
|
|
1210
|
+
const scriptProcessor = that.recorder.context.createScriptProcessor(1024, 1, 1);
|
|
1211
|
+
scriptProcessor.onaudioprocess = (e) => {
|
|
1212
|
+
// 去处理音频数据
|
|
1213
|
+
const inputData = e.inputBuffer.getChannelData(0)
|
|
1214
|
+
const output = that.to16kHz(inputData, that.recorder.context.sampleRate);
|
|
1215
|
+
const audioData = that.to16BitPCM(output);
|
|
1216
|
+
that.audioData.push(...new Int8Array(audioData.buffer));
|
|
1217
|
+
if (that.audioData.length > 10240) {
|
|
1218
|
+
const audioDataArray = new Int8Array(that.audioData);
|
|
1219
|
+
that.ws.send(audioDataArray)
|
|
1220
|
+
that.audioData = [];
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
mediaStreamSource.connect(scriptProcessor);
|
|
1224
|
+
scriptProcessor.connect(that.recorder.context.destination);
|
|
1225
|
+
},
|
|
1226
|
+
speechDown(e) {
|
|
1227
|
+
this.speech = {
|
|
1228
|
+
x: e.clientX - e.offsetX,
|
|
1229
|
+
y: e.clientY - e.offsetY,
|
|
1230
|
+
}
|
|
1231
|
+
},
|
|
1232
|
+
mousedown(event) {
|
|
1233
|
+
event.preventDefault()
|
|
1234
|
+
//鼠标按下事件
|
|
1235
|
+
this.left = event.offsetX;
|
|
1236
|
+
this.top = event.offsetY;
|
|
1237
|
+
this.isMove = true
|
|
1238
|
+
},
|
|
1239
|
+
mouseup() {
|
|
1240
|
+
this.isMove = false
|
|
1241
|
+
setTimeout(() => {
|
|
1242
|
+
this.limits = false
|
|
1243
|
+
},10)
|
|
1244
|
+
},
|
|
1245
|
+
to16kHz(audioData, sampleRate = 44100) {
|
|
1246
|
+
const data = new Float32Array(audioData);
|
|
1247
|
+
const fitCount = Math.round(data.length * (16000 / sampleRate));
|
|
1248
|
+
const newData = new Float32Array(fitCount);
|
|
1249
|
+
const springFactor = (data.length - 1) / (fitCount - 1);
|
|
1250
|
+
newData[0] = data[0];
|
|
1251
|
+
for (let i = 1; i < fitCount - 1; i++) {
|
|
1252
|
+
const tmp = i * springFactor;
|
|
1253
|
+
const before = Math.floor(tmp).toFixed();
|
|
1254
|
+
const after = Math.ceil(tmp).toFixed();
|
|
1255
|
+
const atPoint = tmp - before;
|
|
1256
|
+
newData[i] = data[before] + (data[after] - data[before]) * atPoint;
|
|
1257
|
+
}
|
|
1258
|
+
newData[fitCount - 1] = data[data.length - 1];
|
|
1259
|
+
return newData;
|
|
1260
|
+
},
|
|
1261
|
+
to16BitPCM(input) {
|
|
1262
|
+
const dataLength = input.length * (16 / 8);
|
|
1263
|
+
const dataBuffer = new ArrayBuffer(dataLength);
|
|
1264
|
+
const dataView = new DataView(dataBuffer);
|
|
1265
|
+
let offset = 0;
|
|
1266
|
+
for (let i = 0; i < input.length; i++, offset += 2) {
|
|
1267
|
+
const s = Math.max(-1, Math.min(1, input[i]));
|
|
1268
|
+
dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true);
|
|
1269
|
+
}
|
|
1270
|
+
return dataView;
|
|
1028
1271
|
},
|
|
1272
|
+
getRandomCode(length) {
|
|
1273
|
+
if (length > 0) {
|
|
1274
|
+
let data = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
|
|
1275
|
+
let nums = "";
|
|
1276
|
+
for (let i = 0; i < length; i++) {
|
|
1277
|
+
let r = parseInt(Math.random() * 61);
|
|
1278
|
+
nums += data[r];
|
|
1279
|
+
}
|
|
1280
|
+
return nums.replace(/(.{4})/g, "$1-");
|
|
1281
|
+
} else {
|
|
1282
|
+
return false;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1029
1285
|
}
|
|
1030
1286
|
}
|
|
1031
1287
|
</script>
|
|
@@ -1068,7 +1324,7 @@ export default {
|
|
|
1068
1324
|
|
|
1069
1325
|
.read-only-page {
|
|
1070
1326
|
width: 100%;
|
|
1071
|
-
padding: 120px
|
|
1327
|
+
padding: 120px 0 66px 0;
|
|
1072
1328
|
background-color: #fff;
|
|
1073
1329
|
box-sizing: border-box;
|
|
1074
1330
|
position: relative;
|
|
@@ -1324,6 +1580,7 @@ li {
|
|
|
1324
1580
|
top: -9999px;
|
|
1325
1581
|
left: 0;
|
|
1326
1582
|
z-index: -1;
|
|
1583
|
+
width: 620px;
|
|
1327
1584
|
}
|
|
1328
1585
|
|
|
1329
1586
|
.editing {
|
|
@@ -1356,4 +1613,31 @@ li {
|
|
|
1356
1613
|
position: absolute;
|
|
1357
1614
|
z-index: 10;
|
|
1358
1615
|
}
|
|
1616
|
+
.but-name-color{
|
|
1617
|
+
color: #00ff00;
|
|
1618
|
+
}
|
|
1619
|
+
.speak{
|
|
1620
|
+
position: fixed;
|
|
1621
|
+
top: 0;
|
|
1622
|
+
left: 0;
|
|
1623
|
+
z-index: 50;
|
|
1624
|
+
cursor: move;
|
|
1625
|
+
}
|
|
1626
|
+
.speak-cont{
|
|
1627
|
+
background: rgba(67, 207, 124, 1);
|
|
1628
|
+
color: #fff;
|
|
1629
|
+
padding: 0 10px;
|
|
1630
|
+
height: 30px;
|
|
1631
|
+
line-height: 30px;
|
|
1632
|
+
display: inline-block;
|
|
1633
|
+
border-radius: 20px;
|
|
1634
|
+
}
|
|
1635
|
+
.speak-cont svg{
|
|
1636
|
+
vertical-align: middle;
|
|
1637
|
+
margin-top: -3px;
|
|
1638
|
+
}
|
|
1639
|
+
.speak-cont span{
|
|
1640
|
+
font-size: 14px;
|
|
1641
|
+
padding: 0 5px;
|
|
1642
|
+
}
|
|
1359
1643
|
</style>
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
</template>
|
|
100
100
|
<script>
|
|
101
101
|
import Recorder from 'js-audio-recorder'
|
|
102
|
-
import {html2json, json2html} from 'html2json'
|
|
102
|
+
import {html2json, json2html} from '@/components/utils/html2json.js'
|
|
103
103
|
import {Editor, EditorContent} from '@tiptap/vue-3'
|
|
104
104
|
import StarterKit from '@tiptap/starter-kit'
|
|
105
105
|
import Image from '@tiptap/extension-image'
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
var DEBUG = false;
|
|
2
|
+
var debug = DEBUG ? console.log.bind(console) : function() {};
|
|
3
|
+
|
|
4
|
+
// Regular Expressions for parsing tags and attributes
|
|
5
|
+
var startTag =
|
|
6
|
+
/^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
|
|
7
|
+
endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,
|
|
8
|
+
attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
|
|
9
|
+
|
|
10
|
+
// Empty Elements - HTML 5
|
|
11
|
+
var empty = makeMap(
|
|
12
|
+
"area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
|
|
13
|
+
|
|
14
|
+
// Block Elements - HTML 5
|
|
15
|
+
var block = makeMap(
|
|
16
|
+
"a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video"
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
// Inline Elements - HTML 5
|
|
20
|
+
var inline = makeMap(
|
|
21
|
+
"abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var"
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// Elements that you can, intentionally, leave open
|
|
25
|
+
// (and which close themselves)
|
|
26
|
+
var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
|
|
27
|
+
|
|
28
|
+
// Attributes that have their values filled in disabled="disabled"
|
|
29
|
+
var fillAttrs = makeMap(
|
|
30
|
+
"checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
|
|
31
|
+
|
|
32
|
+
// Special Elements (can contain anything)
|
|
33
|
+
var special = makeMap("script,style");
|
|
34
|
+
|
|
35
|
+
var HTMLParser = function(html, handler) {
|
|
36
|
+
var index, chars, match, stack = [],
|
|
37
|
+
last = html;
|
|
38
|
+
stack.last = function() {
|
|
39
|
+
return this[this.length - 1];
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
while (html) {
|
|
43
|
+
chars = true;
|
|
44
|
+
|
|
45
|
+
// Make sure we're not in a script or style element
|
|
46
|
+
if (!stack.last() || !special[stack.last()]) {
|
|
47
|
+
|
|
48
|
+
// Comment
|
|
49
|
+
if (html.indexOf("<!--") == 0) {
|
|
50
|
+
index = html.indexOf("-->");
|
|
51
|
+
|
|
52
|
+
if (index >= 0) {
|
|
53
|
+
if (handler.comment)
|
|
54
|
+
handler.comment(html.substring(4, index));
|
|
55
|
+
html = html.substring(index + 3);
|
|
56
|
+
chars = false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// end tag
|
|
60
|
+
} else if (html.indexOf("</") == 0) {
|
|
61
|
+
match = html.match(endTag);
|
|
62
|
+
|
|
63
|
+
if (match) {
|
|
64
|
+
html = html.substring(match[0].length);
|
|
65
|
+
match[0].replace(endTag, parseEndTag);
|
|
66
|
+
chars = false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// start tag
|
|
70
|
+
} else if (html.indexOf("<") == 0) {
|
|
71
|
+
match = html.match(startTag);
|
|
72
|
+
|
|
73
|
+
if (match) {
|
|
74
|
+
html = html.substring(match[0].length);
|
|
75
|
+
match[0].replace(startTag, parseStartTag);
|
|
76
|
+
chars = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (chars) {
|
|
81
|
+
index = html.indexOf("<");
|
|
82
|
+
|
|
83
|
+
var text = index < 0 ? html : html.substring(0, index);
|
|
84
|
+
html = index < 0 ? "" : html.substring(index);
|
|
85
|
+
|
|
86
|
+
if (handler.chars)
|
|
87
|
+
handler.chars(text);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
} else {
|
|
91
|
+
html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function(all, text) {
|
|
92
|
+
text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, "$1$2");
|
|
93
|
+
if (handler.chars)
|
|
94
|
+
handler.chars(text);
|
|
95
|
+
|
|
96
|
+
return "";
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
parseEndTag("", stack.last());
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (html == last)
|
|
103
|
+
throw "Parse Error: " + html;
|
|
104
|
+
last = html;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Clean up any remaining tags
|
|
108
|
+
parseEndTag();
|
|
109
|
+
|
|
110
|
+
function parseStartTag(tag, tagName, rest, unary) {
|
|
111
|
+
tagName = tagName.toLowerCase();
|
|
112
|
+
|
|
113
|
+
if (block[tagName]) {
|
|
114
|
+
while (stack.last() && inline[stack.last()]) {
|
|
115
|
+
parseEndTag("", stack.last());
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (closeSelf[tagName] && stack.last() == tagName) {
|
|
120
|
+
parseEndTag("", tagName);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
unary = empty[tagName] || !!unary;
|
|
124
|
+
|
|
125
|
+
if (!unary)
|
|
126
|
+
stack.push(tagName);
|
|
127
|
+
|
|
128
|
+
if (handler.start) {
|
|
129
|
+
var attrs = [];
|
|
130
|
+
|
|
131
|
+
rest.replace(attr, function(match, name) {
|
|
132
|
+
var value = arguments[2] ? arguments[2] :
|
|
133
|
+
arguments[3] ? arguments[3] :
|
|
134
|
+
arguments[4] ? arguments[4] :
|
|
135
|
+
fillAttrs[name] ? name : "";
|
|
136
|
+
|
|
137
|
+
attrs.push({
|
|
138
|
+
name: name,
|
|
139
|
+
value: value,
|
|
140
|
+
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
if (handler.start)
|
|
145
|
+
handler.start(tagName, attrs, unary);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function parseEndTag(tag, tagName) {
|
|
150
|
+
// If no tag name is provided, clean shop
|
|
151
|
+
if (!tagName)
|
|
152
|
+
var pos = 0;
|
|
153
|
+
|
|
154
|
+
// Find the closest opened tag of the same type
|
|
155
|
+
else
|
|
156
|
+
for (var pos = stack.length - 1; pos >= 0; pos--)
|
|
157
|
+
if (stack[pos] == tagName)
|
|
158
|
+
break;
|
|
159
|
+
|
|
160
|
+
if (pos >= 0) {
|
|
161
|
+
// Close all the open elements, up the stack
|
|
162
|
+
for (var i = stack.length - 1; i >= pos; i--)
|
|
163
|
+
if (handler.end)
|
|
164
|
+
handler.end(stack[i]);
|
|
165
|
+
|
|
166
|
+
// Remove the open elements from the stack
|
|
167
|
+
stack.length = pos;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
var HTMLtoXML = function(html) {
|
|
173
|
+
var results = "";
|
|
174
|
+
|
|
175
|
+
HTMLParser(html, {
|
|
176
|
+
start: function(tag, attrs, unary) {
|
|
177
|
+
results += "<" + tag;
|
|
178
|
+
|
|
179
|
+
for (var i = 0; i < attrs.length; i++)
|
|
180
|
+
results += " " + attrs[i].name + '="' + attrs[i].escaped + '"';
|
|
181
|
+
results += ">";
|
|
182
|
+
},
|
|
183
|
+
end: function(tag) {
|
|
184
|
+
results += "</" + tag + ">";
|
|
185
|
+
},
|
|
186
|
+
chars: function(text) {
|
|
187
|
+
results += text;
|
|
188
|
+
},
|
|
189
|
+
comment: function(text) {
|
|
190
|
+
results += "<!--" + text + "-->";
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
return results;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
var HTMLtoDOM = function(html, doc) {
|
|
198
|
+
// There can be only one of these elements
|
|
199
|
+
var one = makeMap("html,head,body,title");
|
|
200
|
+
|
|
201
|
+
// Enforce a structure for the document
|
|
202
|
+
var structure = {
|
|
203
|
+
link: "head",
|
|
204
|
+
base: "head"
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
if (!doc) {
|
|
208
|
+
if (typeof DOMDocument != "undefined")
|
|
209
|
+
doc = new DOMDocument();
|
|
210
|
+
else if (typeof document != "undefined" && document.implementation && document.implementation
|
|
211
|
+
.createDocument)
|
|
212
|
+
doc = document.implementation.createDocument("", "", null);
|
|
213
|
+
else if (typeof ActiveX != "undefined")
|
|
214
|
+
doc = new ActiveXObject("Msxml.DOMDocument");
|
|
215
|
+
|
|
216
|
+
} else
|
|
217
|
+
doc = doc.ownerDocument ||
|
|
218
|
+
doc.getOwnerDocument && doc.getOwnerDocument() ||
|
|
219
|
+
doc;
|
|
220
|
+
|
|
221
|
+
var elems = [],
|
|
222
|
+
documentElement = doc.documentElement ||
|
|
223
|
+
doc.getDocumentElement && doc.getDocumentElement();
|
|
224
|
+
|
|
225
|
+
// If we're dealing with an empty document then we
|
|
226
|
+
// need to pre-populate it with the HTML document structure
|
|
227
|
+
if (!documentElement && doc.createElement)(function() {
|
|
228
|
+
var html = doc.createElement("html");
|
|
229
|
+
var head = doc.createElement("head");
|
|
230
|
+
head.appendChild(doc.createElement("title"));
|
|
231
|
+
html.appendChild(head);
|
|
232
|
+
html.appendChild(doc.createElement("body"));
|
|
233
|
+
doc.appendChild(html);
|
|
234
|
+
})();
|
|
235
|
+
|
|
236
|
+
// Find all the unique elements
|
|
237
|
+
if (doc.getElementsByTagName)
|
|
238
|
+
for (var i in one)
|
|
239
|
+
one[i] = doc.getElementsByTagName(i)[0];
|
|
240
|
+
|
|
241
|
+
// If we're working with a document, inject contents into
|
|
242
|
+
// the body element
|
|
243
|
+
var curParentNode = one.body;
|
|
244
|
+
|
|
245
|
+
HTMLParser(html, {
|
|
246
|
+
start: function(tagName, attrs, unary) {
|
|
247
|
+
// If it's a pre-built element, then we can ignore
|
|
248
|
+
// its construction
|
|
249
|
+
if (one[tagName]) {
|
|
250
|
+
curParentNode = one[tagName];
|
|
251
|
+
if (!unary) {
|
|
252
|
+
elems.push(curParentNode);
|
|
253
|
+
}
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
var elem = doc.createElement(tagName);
|
|
258
|
+
|
|
259
|
+
for (var attr in attrs)
|
|
260
|
+
elem.setAttribute(attrs[attr].name, attrs[attr].value);
|
|
261
|
+
|
|
262
|
+
if (structure[tagName] && typeof one[structure[tagName]] != "boolean")
|
|
263
|
+
one[structure[tagName]].appendChild(elem);
|
|
264
|
+
|
|
265
|
+
else if (curParentNode && curParentNode.appendChild)
|
|
266
|
+
curParentNode.appendChild(elem);
|
|
267
|
+
|
|
268
|
+
if (!unary) {
|
|
269
|
+
elems.push(elem);
|
|
270
|
+
curParentNode = elem;
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
end: function(tag) {
|
|
274
|
+
elems.length -= 1;
|
|
275
|
+
|
|
276
|
+
// Init the new parentNode
|
|
277
|
+
curParentNode = elems[elems.length - 1];
|
|
278
|
+
},
|
|
279
|
+
chars: function(text) {
|
|
280
|
+
curParentNode.appendChild(doc.createTextNode(text));
|
|
281
|
+
},
|
|
282
|
+
comment: function(text) {
|
|
283
|
+
// create comment node
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
return doc;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
function makeMap(str) {
|
|
291
|
+
var obj = {},
|
|
292
|
+
items = str.split(",");
|
|
293
|
+
for (var i = 0; i < items.length; i++)
|
|
294
|
+
obj[items[i]] = true;
|
|
295
|
+
return obj;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function q(v) {
|
|
299
|
+
return '"' + v + '"';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function removeDOCTYPE(html) {
|
|
303
|
+
return html
|
|
304
|
+
.replace(/<\?xml.*\?>\n/, '')
|
|
305
|
+
.replace(/<!doctype.*\>\n/, '')
|
|
306
|
+
.replace(/<!DOCTYPE.*\>\n/, '');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function html2json(html) {
|
|
310
|
+
html = removeDOCTYPE(html);
|
|
311
|
+
var bufArray = [];
|
|
312
|
+
var results = {
|
|
313
|
+
node: 'root',
|
|
314
|
+
child: [],
|
|
315
|
+
};
|
|
316
|
+
HTMLParser(html, {
|
|
317
|
+
start: function(tag, attrs, unary) {
|
|
318
|
+
debug(tag, attrs, unary);
|
|
319
|
+
// node for this element
|
|
320
|
+
var node = {
|
|
321
|
+
node: 'element',
|
|
322
|
+
tag: tag,
|
|
323
|
+
};
|
|
324
|
+
if (attrs.length !== 0) {
|
|
325
|
+
node.attr = attrs.reduce(function(pre, attr) {
|
|
326
|
+
var name = attr.name;
|
|
327
|
+
var value = attr.value;
|
|
328
|
+
|
|
329
|
+
// has multi attibutes
|
|
330
|
+
// make it array of attribute
|
|
331
|
+
if (value.match(/ /)) {
|
|
332
|
+
value = value.split(' ');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// if attr already exists
|
|
336
|
+
// merge it
|
|
337
|
+
if (pre[name]) {
|
|
338
|
+
if (Array.isArray(pre[name])) {
|
|
339
|
+
// already array, push to last
|
|
340
|
+
pre[name].push(value);
|
|
341
|
+
} else {
|
|
342
|
+
// single value, make it array
|
|
343
|
+
pre[name] = [pre[name], value];
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
// not exist, put it
|
|
347
|
+
pre[name] = value;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return pre;
|
|
351
|
+
}, {});
|
|
352
|
+
}
|
|
353
|
+
if (unary) {
|
|
354
|
+
// if this tag dosen't have end tag
|
|
355
|
+
// like <img src="hoge.png"/>
|
|
356
|
+
// add to parents
|
|
357
|
+
var parent = bufArray[0] || results;
|
|
358
|
+
if (parent.child === undefined) {
|
|
359
|
+
parent.child = [];
|
|
360
|
+
}
|
|
361
|
+
parent.child.push(node);
|
|
362
|
+
} else {
|
|
363
|
+
bufArray.unshift(node);
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
end: function(tag) {
|
|
367
|
+
debug(tag);
|
|
368
|
+
// merge into parent tag
|
|
369
|
+
var node = bufArray.shift();
|
|
370
|
+
if (node.tag !== tag) console.error('invalid state: mismatch end tag');
|
|
371
|
+
|
|
372
|
+
if (bufArray.length === 0) {
|
|
373
|
+
results.child.push(node);
|
|
374
|
+
} else {
|
|
375
|
+
var parent = bufArray[0];
|
|
376
|
+
if (parent.child === undefined) {
|
|
377
|
+
parent.child = [];
|
|
378
|
+
}
|
|
379
|
+
parent.child.push(node);
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
chars: function(text) {
|
|
383
|
+
debug(text);
|
|
384
|
+
var node = {
|
|
385
|
+
node: 'text',
|
|
386
|
+
text: text,
|
|
387
|
+
};
|
|
388
|
+
if (bufArray.length === 0) {
|
|
389
|
+
results.child.push(node);
|
|
390
|
+
} else {
|
|
391
|
+
var parent = bufArray[0];
|
|
392
|
+
if (parent.child === undefined) {
|
|
393
|
+
parent.child = [];
|
|
394
|
+
}
|
|
395
|
+
parent.child.push(node);
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
comment: function(text) {
|
|
399
|
+
debug(text);
|
|
400
|
+
var node = {
|
|
401
|
+
node: 'comment',
|
|
402
|
+
text: text,
|
|
403
|
+
};
|
|
404
|
+
var parent = bufArray[0];
|
|
405
|
+
if (parent.child === undefined) {
|
|
406
|
+
parent.child = [];
|
|
407
|
+
}
|
|
408
|
+
parent.child.push(node);
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
return results;
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
function json2html(json) {
|
|
415
|
+
// Empty Elements - HTML 4.01
|
|
416
|
+
var empty = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta',
|
|
417
|
+
'param', 'embed'
|
|
418
|
+
];
|
|
419
|
+
|
|
420
|
+
var child = '';
|
|
421
|
+
if (json.child) {
|
|
422
|
+
child = json.child.map(function(c) {
|
|
423
|
+
return json2html(c);
|
|
424
|
+
}).join('');
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
var attr = '';
|
|
428
|
+
if (json.attr) {
|
|
429
|
+
attr = Object.keys(json.attr).map(function(key) {
|
|
430
|
+
var value = json.attr[key];
|
|
431
|
+
if (Array.isArray(value)) value = value.join(' ');
|
|
432
|
+
return key + '=' + q(value);
|
|
433
|
+
}).join(' ');
|
|
434
|
+
if (attr !== '') attr = ' ' + attr;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (json.node === 'element') {
|
|
438
|
+
var tag = json.tag;
|
|
439
|
+
if (empty.indexOf(tag) > -1) {
|
|
440
|
+
// empty element
|
|
441
|
+
return '<' + json.tag + attr + '/>';
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// non empty element
|
|
445
|
+
var open = '<' + json.tag + attr + '>';
|
|
446
|
+
var close = '</' + json.tag + '>';
|
|
447
|
+
return open + child + close;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (json.node === 'text') {
|
|
451
|
+
return json.text;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (json.node === 'comment') {
|
|
455
|
+
return '<!--' + json.text + '-->';
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (json.node === 'root') {
|
|
459
|
+
return child;
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
export {
|
|
464
|
+
html2json,
|
|
465
|
+
json2html
|
|
466
|
+
}
|