eplayer 1.6.7 → 1.6.9
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/docs/eplayer.js +263 -43
- package/docs/index.html +6 -1
- package/package.json +1 -1
package/docs/eplayer.js
CHANGED
|
@@ -4,10 +4,18 @@ class Eplayer extends HTMLElement {
|
|
|
4
4
|
this.doms = {}
|
|
5
5
|
this.src = this.getAttribute('src')
|
|
6
6
|
this.type = this.getAttribute('type')
|
|
7
|
+
this.cover = this.getAttribute('cover')
|
|
7
8
|
this.live = JSON.parse(this.getAttribute('live'))
|
|
8
9
|
this.danmaku = null
|
|
9
10
|
this.subs = []
|
|
10
11
|
|
|
12
|
+
// 添加长按右箭头3倍速相关状态
|
|
13
|
+
this.rightKeyHoldTimer = null
|
|
14
|
+
this.rightKeyPressTime = null
|
|
15
|
+
this.originalPlaybackRate = 1
|
|
16
|
+
this.isRightKeyPressed = false
|
|
17
|
+
this.isSpeedModeActive = false
|
|
18
|
+
|
|
11
19
|
this.init()
|
|
12
20
|
this.stream()
|
|
13
21
|
}
|
|
@@ -37,11 +45,14 @@ class Eplayer extends HTMLElement {
|
|
|
37
45
|
this.$('.time').style.display = 'inline-block'
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
|
-
if (name === '
|
|
48
|
+
if (name === 'danmu') {
|
|
41
49
|
this.danmaku.add({
|
|
42
50
|
msg: newVal
|
|
43
51
|
})
|
|
44
52
|
}
|
|
53
|
+
if (name === 'cover') {
|
|
54
|
+
this.cover = newVal
|
|
55
|
+
}
|
|
45
56
|
}
|
|
46
57
|
|
|
47
58
|
$(key) {
|
|
@@ -79,14 +90,17 @@ class Eplayer extends HTMLElement {
|
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
play() {
|
|
93
|
+
console.log(this.$('.img-container'))
|
|
82
94
|
if (this.video.paused) {
|
|
83
95
|
this.video.play()
|
|
84
96
|
this.danmaku.resume()
|
|
97
|
+
this.$('.img-container').classList.add('is-playing');
|
|
85
98
|
this.$('.is-play').setAttribute('icon-id', 'pause')
|
|
86
99
|
this.emit('play')
|
|
87
100
|
} else {
|
|
88
101
|
this.video.pause()
|
|
89
102
|
this.danmaku.pause()
|
|
103
|
+
this.$('.img-container').classList.remove('is-playing');
|
|
90
104
|
this.$('.is-play').setAttribute('icon-id', 'play')
|
|
91
105
|
this.emit('pause')
|
|
92
106
|
}
|
|
@@ -115,64 +129,143 @@ class Eplayer extends HTMLElement {
|
|
|
115
129
|
}
|
|
116
130
|
|
|
117
131
|
progress(e) {
|
|
118
|
-
|
|
119
|
-
|
|
132
|
+
const progressBarRect = this.$('.progress').getBoundingClientRect()
|
|
133
|
+
let clickX = e.clientX - progressBarRect.left
|
|
134
|
+
clickX = Math.max(0, Math.min(clickX, progressBarRect.width))
|
|
135
|
+
const offsetRatio = clickX / progressBarRect.width
|
|
136
|
+
|
|
137
|
+
this.video.currentTime = this.video.duration * offsetRatio
|
|
138
|
+
this.$('.now').innerHTML = getTimeStr(this.video.currentTime)
|
|
139
|
+
this.$('.current').style.width = offsetRatio * 100 + '%'
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
down(e) {
|
|
123
|
-
|
|
143
|
+
e.preventDefault()
|
|
124
144
|
this.moving = true
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
145
|
+
const progressBarRect = this.$('.progress').getBoundingClientRect()
|
|
146
|
+
this.progressBarWidth = progressBarRect.width
|
|
147
|
+
this.initialClientX = e.clientX
|
|
148
|
+
const initialOffsetRatio = this.video.currentTime / this.video.duration
|
|
149
|
+
this.initialOffsetPixels = initialOffsetRatio * this.progressBarWidth
|
|
150
|
+
|
|
151
|
+
document.addEventListener('pointermove', this.handleMove)
|
|
152
|
+
document.addEventListener('pointerup', this.handleUp, { once: true })
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
handleMove = (e) => {
|
|
156
|
+
if (!this.moving) return
|
|
157
|
+
|
|
158
|
+
const deltaX = e.clientX - this.initialClientX
|
|
159
|
+
let newOffsetPixels = this.initialOffsetPixels + deltaX
|
|
160
|
+
newOffsetPixels = Math.max(0, Math.min(newOffsetPixels, this.progressBarWidth))
|
|
161
|
+
|
|
162
|
+
this.$('.current').style.width = (newOffsetPixels / this.progressBarWidth) * 100 + '%'
|
|
163
|
+
|
|
164
|
+
const newTime = (newOffsetPixels / this.progressBarWidth) * this.video.duration
|
|
165
|
+
this.video.currentTime = Math.max(0, Math.min(newTime, this.video.duration))
|
|
166
|
+
|
|
167
|
+
this.$('.now').innerHTML = getTimeStr(this.video.currentTime)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
handleUp = (e) => {
|
|
171
|
+
this.moving = false
|
|
172
|
+
document.removeEventListener('pointermove', this.handleMove)
|
|
173
|
+
delete this.progressBarWidth
|
|
174
|
+
delete this.initialClientX
|
|
175
|
+
delete this.initialOffsetPixels
|
|
131
176
|
}
|
|
132
177
|
|
|
133
178
|
move(e) {
|
|
134
179
|
let offset = e.clientX - this.disX + 12
|
|
135
180
|
if (offset < 0) offset = 0
|
|
136
181
|
if (offset > this.$('.progress').clientWidth) {
|
|
137
|
-
|
|
182
|
+
offset = this.$('.progress').clientWidth
|
|
138
183
|
}
|
|
139
184
|
this.$('.current').style.width = offset + 'px'
|
|
140
185
|
this.video.currentTime = (offset / this.$('.progress').clientWidth) * this.video.duration
|
|
141
|
-
|
|
142
|
-
setTimeout((document.onpointermove = (e) => e && this.move(e)), 30)
|
|
186
|
+
this.$('.now').innerHTML = getTimeStr(this.video.currentTime)
|
|
143
187
|
}
|
|
144
188
|
|
|
145
189
|
alow() {
|
|
146
190
|
clearTimeout(this.timer)
|
|
147
191
|
this.$('.mark').style.cursor = 'default'
|
|
148
192
|
this.$('.eplayer').classList.add('hover')
|
|
149
|
-
this.
|
|
150
|
-
this
|
|
151
|
-
|
|
152
|
-
|
|
193
|
+
if (!this.cover) {
|
|
194
|
+
this.timer = setTimeout(() => {
|
|
195
|
+
this.$('.eplayer').classList.remove('hover')
|
|
196
|
+
}, 5000)
|
|
197
|
+
}
|
|
153
198
|
}
|
|
154
199
|
|
|
155
200
|
keydown(e) {
|
|
201
|
+
e.preventDefault()
|
|
156
202
|
switch (e.keyCode) {
|
|
157
|
-
case 37:
|
|
158
|
-
this.video.currentTime
|
|
203
|
+
case 37: // 左箭头 - 后退10秒
|
|
204
|
+
this.video.currentTime = Math.max(0, this.video.currentTime - 10)
|
|
159
205
|
break
|
|
160
|
-
case 39:
|
|
161
|
-
this.
|
|
206
|
+
case 39: // 右箭头 - 前进10秒 (支持长按3倍速)
|
|
207
|
+
if (!this.isRightKeyPressed) {
|
|
208
|
+
this.isRightKeyPressed = true
|
|
209
|
+
this.rightKeyPressTime = Date.now()
|
|
210
|
+
this.originalPlaybackRate = this.video.playbackRate
|
|
211
|
+
|
|
212
|
+
// 设置定时器,如果持续按住超过500ms则开启3倍速
|
|
213
|
+
this.rightKeyHoldTimer = setTimeout(() => {
|
|
214
|
+
this.isSpeedModeActive = true
|
|
215
|
+
this.video.playbackRate = 3
|
|
216
|
+
this.$('.speed').innerText = '3x'
|
|
217
|
+
this.$('.speed-indicator').style.display = 'block'
|
|
218
|
+
}, 500)
|
|
219
|
+
}
|
|
162
220
|
break
|
|
163
|
-
case 38:
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
} catch (e) { }
|
|
221
|
+
case 38: // 上箭头 - 增加音量5%
|
|
222
|
+
e.preventDefault()
|
|
223
|
+
this.video.volume = Math.min(1, this.video.volume + 0.05)
|
|
167
224
|
break
|
|
168
|
-
case 40:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
} catch (e) { }
|
|
225
|
+
case 40: // 下箭头 - 减少音量5%
|
|
226
|
+
e.preventDefault()
|
|
227
|
+
this.video.volume = Math.max(0, this.video.volume - 0.05)
|
|
172
228
|
break
|
|
173
|
-
case 32:
|
|
229
|
+
case 32: // 空格键 - 播放/暂停
|
|
230
|
+
e.preventDefault()
|
|
174
231
|
this.play()
|
|
175
232
|
break
|
|
233
|
+
case 77: // M键 - 静音/取消静音
|
|
234
|
+
this.volume()
|
|
235
|
+
break
|
|
236
|
+
default:
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
keyup(e) {
|
|
241
|
+
switch (e.keyCode) {
|
|
242
|
+
case 39: // 右箭头松开
|
|
243
|
+
if (this.isRightKeyPressed) {
|
|
244
|
+
const pressDuration = Date.now() - this.rightKeyPressTime
|
|
245
|
+
this.isRightKeyPressed = false
|
|
246
|
+
|
|
247
|
+
// 清除定时器
|
|
248
|
+
if (this.rightKeyHoldTimer) {
|
|
249
|
+
clearTimeout(this.rightKeyHoldTimer)
|
|
250
|
+
this.rightKeyHoldTimer = null
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 判断是短按还是长按
|
|
254
|
+
if (pressDuration < 500 && !this.isSpeedModeActive) {
|
|
255
|
+
// 短按:只快进10秒
|
|
256
|
+
this.video.currentTime = Math.min(this.video.duration, this.video.currentTime + 10)
|
|
257
|
+
} else if (this.isSpeedModeActive) {
|
|
258
|
+
// 长按结束:恢复原播放速度并隐藏提示
|
|
259
|
+
this.video.playbackRate = this.originalPlaybackRate
|
|
260
|
+
this.$('.speed').innerText = this.originalPlaybackRate + 'x'
|
|
261
|
+
this.$('.speed-indicator').style.display = 'none'
|
|
262
|
+
this.isSpeedModeActive = false
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 重置状态
|
|
266
|
+
this.rightKeyPressTime = null
|
|
267
|
+
}
|
|
268
|
+
break
|
|
176
269
|
default:
|
|
177
270
|
}
|
|
178
271
|
}
|
|
@@ -245,13 +338,24 @@ class Eplayer extends HTMLElement {
|
|
|
245
338
|
list-style:none;
|
|
246
339
|
}
|
|
247
340
|
.eplayer,video{
|
|
248
|
-
|
|
341
|
+
font-family:'黑体';
|
|
249
342
|
height:100%;
|
|
250
343
|
width:100%;
|
|
251
344
|
color:var(--icons,rgba(255,255,255,0.6));
|
|
252
345
|
font-size:12px;
|
|
253
|
-
background
|
|
346
|
+
background:var(--bg,#000);
|
|
254
347
|
}
|
|
348
|
+
.eplayer .cover{
|
|
349
|
+
position: absolute;
|
|
350
|
+
z-index: 1;
|
|
351
|
+
top: 0;
|
|
352
|
+
left: 0;
|
|
353
|
+
right: 0;
|
|
354
|
+
bottom: 0;
|
|
355
|
+
background:url(${this.cover || ''}) center/cover no-repeat #fff;
|
|
356
|
+
filter:blur(8px);
|
|
357
|
+
}
|
|
358
|
+
|
|
255
359
|
.eplayer{
|
|
256
360
|
user-select:none;
|
|
257
361
|
position: relative;
|
|
@@ -261,14 +365,17 @@ class Eplayer extends HTMLElement {
|
|
|
261
365
|
position:absolute;
|
|
262
366
|
left:0;
|
|
263
367
|
right:0;
|
|
264
|
-
bottom:0;
|
|
265
|
-
background:linear-gradient(transparent,rgba(0,0,0,.5));
|
|
266
|
-
transition: .3s ease-out;
|
|
267
368
|
bottom:-34px;
|
|
268
|
-
|
|
369
|
+
background:linear-gradient(transparent,rgba(0,0,0,.5));
|
|
370
|
+
transition: bottom .3s ease-out, opacity .3s ease-out;
|
|
371
|
+
opacity: 0;
|
|
372
|
+
pointer-events: none;
|
|
373
|
+
z-index:1000;
|
|
269
374
|
}
|
|
270
|
-
.hover
|
|
375
|
+
.hover .controls{
|
|
271
376
|
bottom:0;
|
|
377
|
+
opacity: 1;
|
|
378
|
+
pointer-events: auto;
|
|
272
379
|
}
|
|
273
380
|
.progress{
|
|
274
381
|
display:${this.live ? 'none' : 'block'};
|
|
@@ -395,11 +502,28 @@ class Eplayer extends HTMLElement {
|
|
|
395
502
|
bottom: 0;
|
|
396
503
|
pointer-events: none;
|
|
397
504
|
overflow: hidden;
|
|
398
|
-
z-index:
|
|
505
|
+
z-index: 0;
|
|
399
506
|
height:100%;
|
|
400
507
|
width:100%;
|
|
401
508
|
}
|
|
402
509
|
|
|
510
|
+
.speed-indicator {
|
|
511
|
+
position: absolute;
|
|
512
|
+
top: 20px;
|
|
513
|
+
left: 50%;
|
|
514
|
+
transform: translateX(-50%);
|
|
515
|
+
background: rgba(148, 108, 230, 0.9);
|
|
516
|
+
color: white;
|
|
517
|
+
padding: 8px 16px;
|
|
518
|
+
border-radius: 20px;
|
|
519
|
+
font-size: 14px;
|
|
520
|
+
font-weight: bold;
|
|
521
|
+
z-index: 999;
|
|
522
|
+
display: none;
|
|
523
|
+
pointer-events: none;
|
|
524
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
525
|
+
}
|
|
526
|
+
|
|
403
527
|
iconpark-icon{
|
|
404
528
|
margin-right:5px;
|
|
405
529
|
cursor:pointer;
|
|
@@ -413,13 +537,81 @@ class Eplayer extends HTMLElement {
|
|
|
413
537
|
margin:0 10px 0 8px;
|
|
414
538
|
cursor: pointer;
|
|
415
539
|
}
|
|
416
|
-
|
|
540
|
+
|
|
541
|
+
.eplayer .img-container{
|
|
542
|
+
position: absolute;
|
|
543
|
+
z-index: 1;
|
|
544
|
+
width:250px;
|
|
545
|
+
height:250px;
|
|
546
|
+
border-radius:125px;
|
|
547
|
+
left:50%;
|
|
548
|
+
top:50%;
|
|
549
|
+
transform:translate(-50%,-50%);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.rotate-img {
|
|
553
|
+
width: 250px;
|
|
554
|
+
height: 250px;
|
|
555
|
+
border-radius: 50%;
|
|
556
|
+
animation: rotate 10s linear infinite;
|
|
557
|
+
object-fit: cover;
|
|
558
|
+
animation-play-state: paused; /* 默认暂停 */
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.img-container::after,
|
|
562
|
+
.img-container::before {
|
|
563
|
+
content: '';
|
|
564
|
+
position: absolute;
|
|
565
|
+
top: 50%;
|
|
566
|
+
left: 50%;
|
|
567
|
+
width: 100%;
|
|
568
|
+
height: 100%;
|
|
569
|
+
border-radius: 50%;
|
|
570
|
+
transform: translate(-50%, -50%) scale(0);
|
|
571
|
+
animation: wave 2s infinite;
|
|
572
|
+
animation-play-state: paused; /* 默认暂停 */
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.img-container::after {
|
|
576
|
+
background: rgba(255, 255, 255, 0.3);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.img-container::before {
|
|
580
|
+
background: rgba(255, 255, 255, 0.2);
|
|
581
|
+
animation-delay: 1s;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/* 播放状态 */
|
|
585
|
+
.is-playing .rotate-img,
|
|
586
|
+
.is-playing::after,
|
|
587
|
+
.is-playing::before {
|
|
588
|
+
animation-play-state: running;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
@keyframes rotate {
|
|
592
|
+
from { transform: rotate(0deg); }
|
|
593
|
+
to { transform: rotate(360deg); }
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
@keyframes wave {
|
|
597
|
+
0% {
|
|
598
|
+
transform: translate(-50%, -50%) scale(0);
|
|
599
|
+
opacity: 1;
|
|
600
|
+
}
|
|
601
|
+
100% {
|
|
602
|
+
transform: translate(-50%, -50%) scale(2);
|
|
603
|
+
opacity: 0;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
417
606
|
</style>
|
|
418
607
|
|
|
419
608
|
<div class="eplayer hover">
|
|
420
609
|
<div class="danmaku"></div>
|
|
421
610
|
<video id="video" class="video" src="${this.src || ''}"></video>
|
|
611
|
+
<div class="cover"></div>
|
|
612
|
+
<div class="img-container"><img src="${this.cover || ''}" class="rotate-img"/></div>
|
|
422
613
|
<div class="mark loading"></div>
|
|
614
|
+
<div class="speed-indicator">倍速中</div>
|
|
423
615
|
<div class="controls">
|
|
424
616
|
<div class="progress">
|
|
425
617
|
<b class="bg"></b>
|
|
@@ -436,7 +628,7 @@ class Eplayer extends HTMLElement {
|
|
|
436
628
|
</span>
|
|
437
629
|
</div>
|
|
438
630
|
<div class="right">
|
|
439
|
-
<em class="speed"
|
|
631
|
+
<em class="speed">1x</em>
|
|
440
632
|
<em class="pip">画中画</em>
|
|
441
633
|
<iconpark-icon icon-id="volume-ok" size="2rem" class="is-volume"></iconpark-icon>
|
|
442
634
|
<iconpark-icon icon-id="web-fullscreen" size="2rem"></iconpark-icon>
|
|
@@ -454,6 +646,7 @@ class Eplayer extends HTMLElement {
|
|
|
454
646
|
}).appendChild(template.content.cloneNode(true))
|
|
455
647
|
|
|
456
648
|
const doms = [
|
|
649
|
+
'.img-container',
|
|
457
650
|
'.video',
|
|
458
651
|
'.mark',
|
|
459
652
|
'.playing',
|
|
@@ -475,7 +668,8 @@ class Eplayer extends HTMLElement {
|
|
|
475
668
|
'.panel',
|
|
476
669
|
'.speed',
|
|
477
670
|
'.pip',
|
|
478
|
-
'.danmaku'
|
|
671
|
+
'.danmaku',
|
|
672
|
+
'.speed-indicator'
|
|
479
673
|
]
|
|
480
674
|
|
|
481
675
|
for (const key of doms) {
|
|
@@ -503,6 +697,7 @@ class Eplayer extends HTMLElement {
|
|
|
503
697
|
'.speed': this.speed,
|
|
504
698
|
'.bg': this.progress,
|
|
505
699
|
'.buffer': this.progress,
|
|
700
|
+
'.current': this.progress,
|
|
506
701
|
'.pip': this.pip,
|
|
507
702
|
})
|
|
508
703
|
this.delegate('pointerdown', {
|
|
@@ -515,10 +710,35 @@ class Eplayer extends HTMLElement {
|
|
|
515
710
|
this.full()
|
|
516
711
|
},
|
|
517
712
|
})
|
|
518
|
-
|
|
713
|
+
|
|
714
|
+
// 使用全局键盘监听以确保按键事件能在任何地方被捕获
|
|
715
|
+
this.keydownHandler = this.keydown.bind(this)
|
|
716
|
+
this.keyupHandler = this.keyup.bind(this)
|
|
717
|
+
document.addEventListener('keydown', this.keydownHandler)
|
|
718
|
+
document.addEventListener('keyup', this.keyupHandler)
|
|
719
|
+
|
|
519
720
|
this.delegate('mousemove', this.alow)
|
|
520
721
|
}
|
|
521
722
|
|
|
723
|
+
disconnectedCallback() {
|
|
724
|
+
// 清理全局键盘事件监听器
|
|
725
|
+
if (this.keydownHandler) {
|
|
726
|
+
document.removeEventListener('keydown', this.keydownHandler)
|
|
727
|
+
}
|
|
728
|
+
if (this.keyupHandler) {
|
|
729
|
+
document.removeEventListener('keyup', this.keyupHandler)
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// 清理长按定时器和状态
|
|
733
|
+
if (this.rightKeyHoldTimer) {
|
|
734
|
+
clearTimeout(this.rightKeyHoldTimer)
|
|
735
|
+
this.rightKeyHoldTimer = null
|
|
736
|
+
}
|
|
737
|
+
this.isRightKeyPressed = false
|
|
738
|
+
this.isSpeedModeActive = false
|
|
739
|
+
this.rightKeyPressTime = null
|
|
740
|
+
}
|
|
741
|
+
|
|
522
742
|
delegate(type, map) {
|
|
523
743
|
const that = this
|
|
524
744
|
if (typeof map === 'function') {
|
|
@@ -538,7 +758,7 @@ class Eplayer extends HTMLElement {
|
|
|
538
758
|
}
|
|
539
759
|
}
|
|
540
760
|
|
|
541
|
-
emit
|
|
761
|
+
emit(name) {
|
|
542
762
|
const fn = Eplayer.subs[name]
|
|
543
763
|
fn && fn.call(this, this.shadowRoot)
|
|
544
764
|
}
|
package/docs/index.html
CHANGED
|
@@ -57,11 +57,16 @@
|
|
|
57
57
|
.wrapper a:nth-child(3) {
|
|
58
58
|
background: #1ea6e9;
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
e-player {
|
|
62
|
+
--bg:#fff
|
|
63
|
+
}
|
|
60
64
|
</style>
|
|
61
65
|
|
|
62
66
|
<div class="wrapper">
|
|
63
67
|
<e-player id="ep"
|
|
64
|
-
src="https://
|
|
68
|
+
src="https://aod.cos.tx.xmcdn.com/storages/9976-audiofreehighqps/C9/1C/GAqhF9kMsE7kACAAAAQZZzo_.wav"
|
|
69
|
+
cover="https://dd-static.jd.com/ddimgp/jfs/t20261103/331442/3/18576/2295463/68da8cdcF3f9f05fd/790caba1cab6753d.png">
|
|
65
70
|
</e-player>
|
|
66
71
|
</div>
|
|
67
72
|
<script src="https://unpkg.com/@webcomponents/webcomponentsjs"></script>
|