Browse Source

template module

DIYgod 7 years ago
parent
commit
a8e03abf7a
8 changed files with 563 additions and 260 deletions
  1. 1 1
      demo/index.html
  2. 0 0
      dist/DPlayer.min.css
  3. 0 0
      dist/DPlayer.min.css.map
  4. 0 0
      dist/DPlayer.min.js
  5. 0 0
      dist/DPlayer.min.js.map
  6. 1 1
      package.json
  7. 215 258
      src/DPlayer.js
  8. 346 0
      src/template.js

+ 1 - 1
demo/index.html

@@ -210,7 +210,7 @@
         </script>
     </div>
 
-    <h2 id="dash-support">Live</h2>
+    <h2 id="live">Live</h2>
     <div class="example">
         <button class="btn" onclick="drawDanmaku()">假装收到 WebSocket 弹幕</button>
         <div id="dplayer11"></div>

File diff suppressed because it is too large
+ 0 - 0
dist/DPlayer.min.css


File diff suppressed because it is too large
+ 0 - 0
dist/DPlayer.min.css.map


File diff suppressed because it is too large
+ 0 - 0
dist/DPlayer.min.js


File diff suppressed because it is too large
+ 0 - 0
dist/DPlayer.min.js.map


+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "dplayer",
-  "version": "1.17.1",
+  "version": "1.17.2",
   "description": "Wow, such a lovely HTML5 danmaku video player",
   "main": "dist/DPlayer.min.js",
   "style": "dist/DPlayer.min.css",

+ 215 - 258
src/DPlayer.js

@@ -3,7 +3,7 @@ import './DPlayer.scss';
 import utils, { isMobile } from './utils';
 import handleOption from './options';
 import i18n from './i18n';
-import html from './html';
+import Template from './template';
 import SvgCollection from './svg';
 import Danmaku from './danmaku';
 import Thumbnails from './thumbnails';
@@ -52,14 +52,18 @@ class DPlayer {
             this.container.classList.add('dplayer-mobile');
         }
 
-        this.container.innerHTML = html.main(this.options, index, this.tran, this.icons);
+        this.template = new Template({
+            container: this.container,
+            options: this.options,
+            index: index,
+            tran: this.tran,
+            icons: this.icons
+        });
 
         const bar = {};
-        bar.volumeBar = this.container.getElementsByClassName('dplayer-volume-bar-inner')[0];
-        bar.playedBar = this.container.getElementsByClassName('dplayer-played')[0];
-        bar.loadedBar = this.container.getElementsByClassName('dplayer-loaded')[0];
-        const pbar = this.container.getElementsByClassName('dplayer-bar-wrap')[0];
-        const pbarTimeTips = this.container.getElementsByClassName('dplayer-bar-time')[0];
+        bar.volumeBar = this.template.volumeBar;
+        bar.playedBar = this.template.playedBar;
+        bar.loadedBar = this.template.loadedBar;
         let barWidth;
 
         /**
@@ -85,11 +89,11 @@ class DPlayer {
 
         if (this.options.danmaku) {
             this.danmaku = new Danmaku({
-                container: this.container.getElementsByClassName('dplayer-danmaku')[0],
+                container: this.template.danmaku,
                 opacity: this.user.get('opacity'),
                 callback: () => {
                     setTimeout(() => {
-                        this.container.getElementsByClassName('dplayer-danloading')[0].style.display = 'none';
+                        this.template.danmakuLoading.style.display = 'none';
 
                         // autoplay
                         if (this.options.autoplay && !isMobile) {
@@ -130,27 +134,23 @@ class DPlayer {
         }
 
         // get this video manager
-        this.video = this.container.getElementsByClassName('dplayer-video-current')[0];
+        this.video = this.template.video;
 
-        this.bezel = this.container.getElementsByClassName('dplayer-bezel-icon')[0];
-        this.bezel.addEventListener('animationend', () => {
-            this.bezel.classList.remove('dplayer-bezel-transition');
+        this.template.bezel.addEventListener('animationend', () => {
+            this.template.bezel.classList.remove('dplayer-bezel-transition');
         });
 
         // play and pause button
-        this.playButton = this.container.getElementsByClassName('dplayer-play-icon')[0];
         this.paused = true;
-        this.playButton.addEventListener('click', () => {
+        this.template.playButton.addEventListener('click', () => {
             this.toggle();
         });
 
-        const videoWrap = this.container.getElementsByClassName('dplayer-video-wrap')[0];
-        const conMask = this.container.getElementsByClassName('dplayer-controller-mask')[0];
         if (!isMobile) {
-            videoWrap.addEventListener('click', () => {
+            this.template.videoWrap.addEventListener('click', () => {
                 this.toggle();
             });
-            conMask.addEventListener('click', () => {
+            this.template.controllerMask.addEventListener('click', () => {
                 this.toggle();
             });
         }
@@ -163,8 +163,8 @@ class DPlayer {
                     this.container.classList.add('dplayer-hide-controller');
                 }
             };
-            videoWrap.addEventListener('click', toggleController);
-            conMask.addEventListener('click', toggleController);
+            this.template.videoWrap.addEventListener('click', toggleController);
+            this.template.controllerMask.addEventListener('click', toggleController);
         }
 
         let lastPlayPos = 0;
@@ -209,7 +209,7 @@ class DPlayer {
         this.animationFrame = () => {
             if (this.playedTime) {
                 this.updateBar('played', this.video.currentTime / this.video.duration, 'width');
-                this.container.getElementsByClassName('dplayer-ptime')[0].innerHTML = utils.secondToTime(this.video.currentTime);
+                this.template.ptime.innerHTML = utils.secondToTime(this.video.currentTime);
             }
             window.requestAnimationFrame(this.animationFrame);
         };
@@ -244,24 +244,24 @@ class DPlayer {
             this.initThumbnails();
         }
         this.isTimeTipsShow = true;
-        this.mouseHandler = this.mouseHandler(pbar, pbarTimeTips).bind(this);
-        pbar.addEventListener('mousemove', this.mouseHandler);
-        pbar.addEventListener('mouseenter', this.mouseHandler);
-        pbar.addEventListener('mouseleave', this.mouseHandler);
+        this.mouseHandler = this.mouseHandler(this.template.playedBarWrap, this.template.playedBarTime).bind(this);
+        this.template.playedBarWrap.addEventListener('mousemove', this.mouseHandler);
+        this.template.playedBarWrap.addEventListener('mouseenter', this.mouseHandler);
+        this.template.playedBarWrap.addEventListener('mouseleave', this.mouseHandler);
 
 
         const thumbMove = (e) => {
-            let percentage = (e.clientX - utils.getElementViewLeft(pbar)) / barWidth;
+            let percentage = (e.clientX - utils.getElementViewLeft(this.template.playedBarWrap)) / barWidth;
             percentage = percentage > 0 ? percentage : 0;
             percentage = percentage < 1 ? percentage : 1;
             this.updateBar('played', percentage, 'width');
-            this.container.getElementsByClassName('dplayer-ptime')[0].innerHTML = utils.secondToTime(percentage * this.video.duration);
+            this.template.ptime.innerHTML = utils.secondToTime(percentage * this.video.duration);
         };
 
         const thumbUp = (e) => {
             document.removeEventListener('mouseup', thumbUp);
             document.removeEventListener('mousemove', thumbMove);
-            let percentage = (e.clientX - utils.getElementViewLeft(pbar)) / barWidth;
+            let percentage = (e.clientX - utils.getElementViewLeft(this.template.playedBarWrap)) / barWidth;
             percentage = percentage > 0 ? percentage : 0;
             percentage = percentage < 1 ? percentage : 1;
             this.updateBar('played', percentage, 'width');
@@ -269,8 +269,8 @@ class DPlayer {
             this.setTime();
         };
 
-        pbar.addEventListener('mousedown', () => {
-            barWidth = pbar.clientWidth;
+        this.template.playedBarWrap.addEventListener('mousedown', () => {
+            barWidth = this.template.playedBarWrap.clientWidth;
             this.clearTime();
             document.addEventListener('mousemove', thumbMove);
             document.addEventListener('mouseup', thumbUp);
@@ -280,45 +280,41 @@ class DPlayer {
         /**
          * control volume
          */
-        const volumeEle = this.container.getElementsByClassName('dplayer-volume')[0];
-        const volumeBarWrapWrap = this.container.getElementsByClassName('dplayer-volume-bar-wrap')[0];
-        const volumeBarWrap = this.container.getElementsByClassName('dplayer-volume-bar')[0];
-        const volumeicon = this.container.getElementsByClassName('dplayer-volume-icon')[0].getElementsByClassName('dplayer-icon-content')[0];
         const vWidth = 35;
 
         this.switchVolumeIcon = () => {
             if (this.volume() >= 0.95) {
-                volumeicon.innerHTML = this.icons.get('volume-up');
+                this.template.volumeIcon.innerHTML = this.icons.get('volume-up');
             }
             else if (this.volume() > 0) {
-                volumeicon.innerHTML = this.icons.get('volume-down');
+                this.template.volumeIcon.innerHTML = this.icons.get('volume-down');
             }
             else {
-                volumeicon.innerHTML = this.icons.get('volume-off');
+                this.template.volumeIcon.innerHTML = this.icons.get('volume-off');
             }
         };
         const volumeMove = (event) => {
             const e = event || window.event;
-            const percentage = (e.clientX - utils.getElementViewLeft(volumeBarWrap) - 5.5) / vWidth;
+            const percentage = (e.clientX - utils.getElementViewLeft(this.template.volumeBarWrap) - 5.5) / vWidth;
             this.volume(percentage);
         };
         const volumeUp = () => {
             document.removeEventListener('mouseup', volumeUp);
             document.removeEventListener('mousemove', volumeMove);
-            volumeEle.classList.remove('dplayer-volume-active');
+            this.template.volumeButton.classList.remove('dplayer-volume-active');
         };
 
-        volumeBarWrapWrap.addEventListener('click', (event) => {
+        this.template.volumeBarWrapWrap.addEventListener('click', (event) => {
             const e = event || window.event;
-            const percentage = (e.clientX - utils.getElementViewLeft(volumeBarWrap) - 5.5) / vWidth;
+            const percentage = (e.clientX - utils.getElementViewLeft(this.template.volumeBarWrap) - 5.5) / vWidth;
             this.volume(percentage);
         });
-        volumeBarWrapWrap.addEventListener('mousedown', () => {
+        this.template.volumeBarWrapWrap.addEventListener('mousedown', () => {
             document.addEventListener('mousemove', volumeMove);
             document.addEventListener('mouseup', volumeUp);
-            volumeEle.classList.add('dplayer-volume-active');
+            this.template.volumeButton.classList.add('dplayer-volume-active');
         });
-        volumeicon.addEventListener('click', () => {
+        this.template.volumeIcon.addEventListener('click', () => {
             if (this.video.muted) {
                 this.video.muted = false;
                 this.switchVolumeIcon();
@@ -326,7 +322,7 @@ class DPlayer {
             }
             else {
                 this.video.muted = true;
-                volumeicon.innerHTML = this.icons.get('volume-off');
+                this.template.volumeIcon.innerHTML = this.icons.get('volume-off');
                 this.updateBar('volume', 0, 'width');
             }
         });
@@ -356,22 +352,14 @@ class DPlayer {
         /**
          * setting
          */
-        const settingHTML = html.setting(this.tran, this.icons);
-
         // toggle setting box
-        const settingIcon = this.container.getElementsByClassName('dplayer-setting-icon')[0];
-        const settingBox = this.container.getElementsByClassName('dplayer-setting-box')[0];
-        const mask = this.container.getElementsByClassName('dplayer-mask')[0];
-        settingBox.innerHTML = settingHTML.original;
-
         const closeSetting = () => {
-            if (settingBox.classList.contains('dplayer-setting-box-open')) {
-                settingBox.classList.remove('dplayer-setting-box-open');
-                mask.classList.remove('dplayer-mask-show');
+            if (this.template.settingBox.classList.contains('dplayer-setting-box-open')) {
+                this.template.settingBox.classList.remove('dplayer-setting-box-open');
+                this.template.mask.classList.remove('dplayer-mask-show');
                 setTimeout(() => {
-                    settingBox.classList.remove('dplayer-setting-box-narrow');
-                    settingBox.innerHTML = settingHTML.original;
-                    settingEvent();
+                    this.template.settingBox.classList.remove('dplayer-setting-box-narrow');
+                    this.template.settingBox.classList.remove('dplayer-setting-box-speed');
                 }, 300);
             }
 
@@ -380,14 +368,14 @@ class DPlayer {
         const openSetting = () => {
             this.disableHideController = true;
 
-            settingBox.classList.add('dplayer-setting-box-open');
-            mask.classList.add('dplayer-mask-show');
+            this.template.settingBox.classList.add('dplayer-setting-box-open');
+            this.template.mask.classList.add('dplayer-mask-show');
         };
 
-        mask.addEventListener('click', () => {
+        this.template.mask.addEventListener('click', () => {
             closeSetting();
         });
-        settingIcon.addEventListener('click', () => {
+        this.template.settingButton.addEventListener('click', () => {
             openSetting();
         });
 
@@ -397,126 +385,110 @@ class DPlayer {
             this.danmaku && this.danmaku.hide();
         }
         let unlimitDan = this.user.get('unlimited');
-        const settingEvent = () => {
-            // loop control
-            const loopEle = this.container.getElementsByClassName('dplayer-setting-loop')[0];
-            const loopToggle = loopEle.getElementsByClassName('dplayer-toggle-setting-input')[0];
 
-            loopToggle.checked = this.loop;
+        // loop control
+        this.template.loopToggle.checked = this.loop;
 
-            loopEle.addEventListener('click', () => {
-                loopToggle.checked = !loopToggle.checked;
-                if (loopToggle.checked) {
-                    this.loop = true;
-                }
-                else {
-                    this.loop = false;
-                }
-                closeSetting();
-            });
-
-            // show danmaku control
-            const showDanEle = this.container.getElementsByClassName('dplayer-setting-showdan')[0];
-            const showDanToggle = showDanEle.getElementsByClassName('dplayer-showdan-setting-input')[0];
+        this.template.loop.addEventListener('click', () => {
+            this.template.loopToggle.checked = !this.template.loopToggle.checked;
+            if (this.template.loopToggle.checked) {
+                this.loop = true;
+            }
+            else {
+                this.loop = false;
+            }
+            closeSetting();
+        });
 
-            showDanToggle.checked = showdan;
+        // show danmaku control
+        this.template.showDanmakuToggle.checked = showdan;
 
-            showDanEle.addEventListener('click', () => {
-                showDanToggle.checked = !showDanToggle.checked;
-                if (showDanToggle.checked) {
-                    showdan = true;
-                    if (!this.paused) {
-                        this.danmaku.show();
-                    }
-                }
-                else {
-                    showdan = false;
-                    this.danmaku.hide();
+        this.template.showDanmaku.addEventListener('click', () => {
+            this.template.showDanmakuToggle.checked = !this.template.showDanmakuToggle.checked;
+            if (this.template.showDanmakuToggle.checked) {
+                showdan = true;
+                if (!this.paused) {
+                    this.danmaku.show();
                 }
-                this.user.set('danmaku', showdan ? 1 : 0);
-                closeSetting();
-            });
-
-            // unlimited danmaku control
-            const unlimitDanEle = this.container.getElementsByClassName('dplayer-setting-danunlimit')[0];
-            const unlimitDanToggle = unlimitDanEle.getElementsByClassName('dplayer-danunlimit-setting-input')[0];
+            }
+            else {
+                showdan = false;
+                this.danmaku.hide();
+            }
+            this.user.set('danmaku', showdan ? 1 : 0);
+            closeSetting();
+        });
 
-            unlimitDanToggle.checked = unlimitDan;
+        // unlimited danmaku control
+        this.template.unlimitDanmakuToggle.checked = unlimitDan;
 
-            unlimitDanEle.addEventListener('click', () => {
-                unlimitDanToggle.checked = !unlimitDanToggle.checked;
-                if (unlimitDanToggle.checked) {
-                    unlimitDan = true;
-                    this.danmaku.unlimit(true);
-                }
-                else {
-                    unlimitDan = false;
-                    this.danmaku.unlimit(false);
-                }
-                this.user.set('unlimited', unlimitDan ? 1 : 0);
-                closeSetting();
-            });
+        this.template.unlimitDanmaku.addEventListener('click', () => {
+            this.template.unlimitDanmakuToggle.checked = !this.template.unlimitDanmakuToggle.checked;
+            if (this.template.unlimitDanmakuToggle.checked) {
+                unlimitDan = true;
+                this.danmaku.unlimit(true);
+            }
+            else {
+                unlimitDan = false;
+                this.danmaku.unlimit(false);
+            }
+            this.user.set('unlimited', unlimitDan ? 1 : 0);
+            closeSetting();
+        });
 
-            // speed control
-            const speedEle = this.container.getElementsByClassName('dplayer-setting-speed')[0];
-            speedEle.addEventListener('click', () => {
-                settingBox.classList.add('dplayer-setting-box-narrow');
-                settingBox.innerHTML = settingHTML.speed;
-
-                const speedItem = settingBox.getElementsByClassName('dplayer-setting-speed-item');
-                for (let i = 0; i < speedItem.length; i++) {
-                    speedItem[i].addEventListener('click', () => {
-                        this.video.playbackRate = speedItem[i].dataset.speed;
-                        closeSetting();
-                    });
-                }
-            });
+        // speed control
+        this.template.speed.addEventListener('click', () => {
+            this.template.settingBox.classList.add('dplayer-setting-box-narrow');
+            this.template.settingBox.classList.add('dplayer-setting-box-speed');
 
-            if (this.danmaku) {
-                // danmaku opacity
-                bar.danmakuBar = this.container.getElementsByClassName('dplayer-danmaku-bar-inner')[0];
-                const danmakuBarWrapWrap = this.container.getElementsByClassName('dplayer-danmaku-bar-wrap')[0];
-                const danmakuBarWrap = this.container.getElementsByClassName('dplayer-danmaku-bar')[0];
-                const danmakuSettingBox = this.container.getElementsByClassName('dplayer-setting-danmaku')[0];
-                const dWidth = 130;
-                this.on('danmaku_opacity', (percentage) => {
-                    this.updateBar('danmaku', percentage, 'width');
-                    this.user.set('opacity', percentage);
-                });
-                this.danmaku.opacity(this.user.get('opacity'));
-
-                const danmakuMove = (event) => {
-                    const e = event || window.event;
-                    let percentage = (e.clientX - utils.getElementViewLeft(danmakuBarWrap)) / dWidth;
-                    percentage = percentage > 0 ? percentage : 0;
-                    percentage = percentage < 1 ? percentage : 1;
-                    this.danmaku.opacity(percentage);
-                };
-                const danmakuUp = () => {
-                    document.removeEventListener('mouseup', danmakuUp);
-                    document.removeEventListener('mousemove', danmakuMove);
-                    danmakuSettingBox.classList.remove('dplayer-setting-danmaku-active');
-                };
-
-                danmakuBarWrapWrap.addEventListener('click', (event) => {
-                    const e = event || window.event;
-                    let percentage = (e.clientX - utils.getElementViewLeft(danmakuBarWrap)) / dWidth;
-                    percentage = percentage > 0 ? percentage : 0;
-                    percentage = percentage < 1 ? percentage : 1;
-                    this.danmaku.opacity(percentage);
-                });
-                danmakuBarWrapWrap.addEventListener('mousedown', () => {
-                    document.addEventListener('mousemove', danmakuMove);
-                    document.addEventListener('mouseup', danmakuUp);
-                    danmakuSettingBox.classList.add('dplayer-setting-danmaku-active');
+            for (let i = 0; i < this.template.speedItem.length; i++) {
+                this.template.speedItem[i].addEventListener('click', () => {
+                    this.video.playbackRate = this.template.speedItem[i].dataset.speed;
+                    closeSetting();
                 });
             }
-        };
-        settingEvent();
+        });
+
+        if (this.danmaku) {
+            // danmaku opacity
+            bar.danmakuBar = this.template.danmakuOpacityBar;
+            const dWidth = 130;
+            this.on('danmaku_opacity', (percentage) => {
+                this.updateBar('danmaku', percentage, 'width');
+                this.user.set('opacity', percentage);
+            });
+            this.danmaku.opacity(this.user.get('opacity'));
+
+            const danmakuMove = (event) => {
+                const e = event || window.event;
+                let percentage = (e.clientX - utils.getElementViewLeft(this.template.danmakuOpacityBarWrap)) / dWidth;
+                percentage = percentage > 0 ? percentage : 0;
+                percentage = percentage < 1 ? percentage : 1;
+                this.danmaku.opacity(percentage);
+            };
+            const danmakuUp = () => {
+                document.removeEventListener('mouseup', danmakuUp);
+                document.removeEventListener('mousemove', danmakuMove);
+                this.template.danmakuOpacityBox.classList.remove('dplayer-setting-danmaku-active');
+            };
+
+            this.template.danmakuOpacityBarWrapWrap.addEventListener('click', (event) => {
+                const e = event || window.event;
+                let percentage = (e.clientX - utils.getElementViewLeft(this.template.danmakuOpacityBarWrap)) / dWidth;
+                percentage = percentage > 0 ? percentage : 0;
+                percentage = percentage < 1 ? percentage : 1;
+                this.danmaku.opacity(percentage);
+            });
+            this.template.danmakuOpacityBarWrapWrap.addEventListener('mousedown', () => {
+                document.addEventListener('mousemove', danmakuMove);
+                document.addEventListener('mouseup', danmakuUp);
+                this.template.danmakuOpacityBox.classList.add('dplayer-setting-danmaku-active');
+            });
+        }
 
         // set duration time
         if (this.video.duration !== 1) { // compatibility: Android browsers will output 1 at first
-            this.container.getElementsByClassName('dplayer-dtime')[0].innerHTML = this.video.duration ? utils.secondToTime(this.video.duration) : '00:00';
+            this.template.dtime.innerHTML = this.video.duration ? utils.secondToTime(this.video.duration) : '00:00';
         }
 
         if (!this.danmaku) {
@@ -533,34 +505,28 @@ class DPlayer {
         /**
          * comment
          */
-        const controller = this.container.getElementsByClassName('dplayer-controller')[0];
-        const commentInput = this.container.getElementsByClassName('dplayer-comment-input')[0];
-        const commentIcon = this.container.getElementsByClassName('dplayer-comment-icon')[0];
-        const commentSettingIcon = this.container.getElementsByClassName('dplayer-comment-setting-icon')[0];
-        const commentSettingBox = this.container.getElementsByClassName('dplayer-comment-setting-box')[0];
-        const commentSendIcon = this.container.getElementsByClassName('dplayer-send-icon')[0];
 
         const closeCommentSetting = () => {
-            if (commentSettingBox.classList.contains('dplayer-comment-setting-open')) {
-                commentSettingBox.classList.remove('dplayer-comment-setting-open');
+            if (this.template.commentSettingBox.classList.contains('dplayer-comment-setting-open')) {
+                this.template.commentSettingBox.classList.remove('dplayer-comment-setting-open');
             }
         };
         const toggleCommentSetting = () => {
-            if (commentSettingBox.classList.contains('dplayer-comment-setting-open')) {
-                commentSettingBox.classList.remove('dplayer-comment-setting-open');
+            if (this.template.commentSettingBox.classList.contains('dplayer-comment-setting-open')) {
+                this.template.commentSettingBox.classList.remove('dplayer-comment-setting-open');
             }
             else {
-                commentSettingBox.classList.add('dplayer-comment-setting-open');
+                this.template.commentSettingBox.classList.add('dplayer-comment-setting-open');
             }
         };
 
         const closeComment = () => {
-            if (!controller.classList.contains('dplayer-controller-comment')) {
+            if (!this.template.controller.classList.contains('dplayer-controller-comment')) {
                 return;
             }
 
-            controller.classList.remove('dplayer-controller-comment');
-            mask.classList.remove('dplayer-mask-show');
+            this.template.controller.classList.remove('dplayer-controller-comment');
+            this.template.mask.classList.remove('dplayer-mask-show');
             this.container.classList.remove('dplayer-show-controller');
 
             closeCommentSetting();
@@ -570,76 +536,75 @@ class DPlayer {
         const openComment = () => {
             this.disableHideController = true;
 
-            if (!controller.classList.contains('dplayer-controller-comment')) {
-                controller.classList.add('dplayer-controller-comment');
-                mask.classList.add('dplayer-mask-show');
+            if (!this.template.controller.classList.contains('dplayer-controller-comment')) {
+                this.template.controller.classList.add('dplayer-controller-comment');
+                this.template.mask.classList.add('dplayer-mask-show');
                 this.container.classList.add('dplayer-show-controller');
-                commentInput.focus();
+                this.template.commentInput.focus();
             }
         };
 
-        mask.addEventListener('click', () => {
+        this.template.mask.addEventListener('click', () => {
             closeComment();
         });
-        commentIcon.addEventListener('click', () => {
+        this.template.commentButton.addEventListener('click', () => {
             openComment();
         });
-        commentSettingIcon.addEventListener('click', () => {
+        this.template.commentSettingButton.addEventListener('click', () => {
             toggleCommentSetting();
         });
 
         // comment setting box
-        const colorSetting = this.container.getElementsByClassName('dplayer-comment-setting-color')[0];
-        colorSetting.addEventListener('click', () => {
-            const sele = colorSetting.querySelector(`input:checked+span`);
+        this.template.commentColorSettingBox.addEventListener('click', () => {
+            const sele = this.template.commentColorSettingBox.querySelector(`input:checked+span`);
             if (sele) {
-                const color = colorSetting.querySelector(`input:checked`).value;
-                commentSettingIcon.getElementsByClassName('dplayer-fill')[0].style.fill = color;
-                commentInput.style.color = color;
-                commentSendIcon.getElementsByClassName('dplayer-fill')[0].style.fill = color;
+                const color = this.template.commentColorSettingBox.querySelector(`input:checked`).value;
+                this.template.commentSettingFill.style.fill = color;
+                this.template.commentInput.style.color = color;
+                this.template.commentSendFill.style.fill = color;
             }
         });
 
         const sendComment = () => {
-            commentInput.blur();
+            this.template.commentInput.blur();
 
             // text can't be empty
-            if (!commentInput.value.replace(/^\s+|\s+$/g, '')) {
+            if (!this.template.commentInput.value.replace(/^\s+|\s+$/g, '')) {
                 this.notice(this.tran('Please input danmaku content!'));
                 return;
             }
 
             this.danmaku.send({
-                text: commentInput.value,
+                text: this.template.commentInput.value,
                 color: this.container.querySelector('.dplayer-comment-setting-color input:checked').value,
                 type: this.container.querySelector('.dplayer-comment-setting-type input:checked').value
             }, () => {
-                commentInput.value = '';
+                this.template.commentInput.value = '';
                 closeComment();
             });
         };
 
-        commentInput.addEventListener('click', () => {
+        this.template.commentInput.addEventListener('click', () => {
             closeCommentSetting();
         });
-        commentInput.addEventListener('keydown', (e) => {
+        this.template.commentInput.addEventListener('keydown', (e) => {
             const event = e || window.event;
             if (event.keyCode === 13) {
                 sendComment();
             }
         });
 
-        commentSendIcon.addEventListener('click', sendComment);
+        this.template.commentSendButton.addEventListener('click', sendComment);
 
         this.fullScreen = new FullScreen(this);
 
         // browser full screen
-        this.container.getElementsByClassName('dplayer-full-icon')[0].addEventListener('click', () => {
+        this.template.browserFullButton.addEventListener('click', () => {
             this.fullScreen.toggle('browser');
         });
 
         // web full screen
-        this.container.getElementsByClassName('dplayer-full-in-icon')[0].addEventListener('click', () => {
+        this.template.webFullButton.addEventListener('click', () => {
             this.fullScreen.toggle('web');
         });
 
@@ -699,40 +664,39 @@ class DPlayer {
         /**
          * right key
          */
-        const menu = this.container.getElementsByClassName('dplayer-menu')[0];
         this.container.addEventListener('contextmenu', (e) => {
             const event = e || window.event;
             event.preventDefault();
 
-            menu.classList.add('dplayer-menu-show');
+            this.template.menu.classList.add('dplayer-menu-show');
 
             const clientRect = this.container.getBoundingClientRect();
             const menuLeft = event.clientX - clientRect.left;
             const menuTop = event.clientY - clientRect.top;
-            if (menuLeft + menu.offsetWidth >= clientRect.width) {
-                menu.style.right = clientRect.width - menuLeft + 'px';
-                menu.style.left = 'initial';
+            if (menuLeft + this.template.menu.offsetWidth >= clientRect.width) {
+                this.template.menu.style.right = clientRect.width - menuLeft + 'px';
+                this.template.menu.style.left = 'initial';
             }
             else {
-                menu.style.left = event.clientX - this.container.getBoundingClientRect().left + 'px';
-                menu.style.right = 'initial';
+                this.template.menu.style.left = event.clientX - this.container.getBoundingClientRect().left + 'px';
+                this.template.menu.style.right = 'initial';
             }
-            if (menuTop + menu.offsetHeight >= clientRect.height) {
-                menu.style.bottom = clientRect.height - menuTop + 'px';
-                menu.style.top = 'initial';
+            if (menuTop + this.template.menu.offsetHeight >= clientRect.height) {
+                this.template.menu.style.bottom = clientRect.height - menuTop + 'px';
+                this.template.menu.style.top = 'initial';
             }
             else {
-                menu.style.top = event.clientY - this.container.getBoundingClientRect().top + 'px';
-                menu.style.bottom = 'initial';
+                this.template.menu.style.top = event.clientY - this.container.getBoundingClientRect().top + 'px';
+                this.template.menu.style.bottom = 'initial';
             }
 
-            mask.classList.add('dplayer-mask-show');
+            this.template.mask.classList.add('dplayer-mask-show');
 
             this.events.trigger('contextmenu_show');
 
-            mask.addEventListener('click', () => {
-                mask.classList.remove('dplayer-mask-show');
-                menu.classList.remove('dplayer-menu-show');
+            this.template.mask.addEventListener('click', () => {
+                this.template.mask.classList.remove('dplayer-mask-show');
+                this.template.menu.classList.remove('dplayer-menu-show');
 
                 this.events.trigger('contextmenu_hide');
             });
@@ -742,7 +706,7 @@ class DPlayer {
          * Switch quality
          */
         if (this.options.video.quality) {
-            this.container.getElementsByClassName('dplayer-quality-list')[0].addEventListener('click', (e) => {
+            this.template.qualityList.addEventListener('click', (e) => {
                 if (e.target.classList.contains('dplayer-quality-item')) {
                     this.switchQuality(e.target.dataset.index);
                 }
@@ -753,16 +717,15 @@ class DPlayer {
          * Screenshot
          */
         if (this.options.screenshot) {
-            const camareIcon = this.container.getElementsByClassName('dplayer-camera-icon')[0];
-            camareIcon.addEventListener('click', () => {
+            this.template.camareButton.addEventListener('click', () => {
                 const canvas = document.createElement("canvas");
                 canvas.width = this.video.videoWidth;
                 canvas.height = this.video.videoHeight;
                 canvas.getContext('2d').drawImage(this.video, 0, 0, canvas.width, canvas.height);
 
                 const dataURL = canvas.toDataURL();
-                camareIcon.href = dataURL;
-                camareIcon.download = "DPlayer.png";
+                this.template.camareButton.href = dataURL;
+                this.template.camareButton.download = "DPlayer.png";
 
                 this.events.trigger('screenshot', dataURL);
             });
@@ -772,21 +735,18 @@ class DPlayer {
          * Toggle subtitle
          */
         if (this.options.subtitle) {
-            const subtitleIcon = this.container.getElementsByClassName('dplayer-subtitle-icon')[0];
-            const subtitleIn = subtitleIcon.getElementsByClassName('dplayer-icon-content')[0];
-
             this.events.on('subtitle_show', () => {
-                subtitleIcon.dataset.balloon = this.tran('Hide subtitle');
-                subtitleIn.style.opacity = '';
+                this.template.subtitleButton.dataset.balloon = this.tran('Hide subtitle');
+                this.template.subtitleButtonInner.style.opacity = '';
                 this.user.set('subtitle', 1);
             });
             this.events.on('subtitle_hide', () => {
-                subtitleIcon.dataset.balloon = this.tran('Show subtitle');
-                subtitleIn.style.opacity = '0.4';
+                this.template.subtitleButton.dataset.balloon = this.tran('Show subtitle');
+                this.template.subtitleButtonInner.style.opacity = '0.4';
                 this.user.set('subtitle', 0);
             });
 
-            subtitleIcon.addEventListener('click', () => {
+            this.template.subtitleButton.addEventListener('click', () => {
                 this.subtitle.toggle();
             });
         }
@@ -827,11 +787,11 @@ class DPlayer {
     play () {
         this.paused = false;
         if (this.video.paused) {
-            this.bezel.innerHTML = this.icons.get('play');
-            this.bezel.classList.add('dplayer-bezel-transition');
+            this.template.bezel.innerHTML = this.icons.get('play');
+            this.template.bezel.classList.add('dplayer-bezel-transition');
         }
 
-        this.playButton.innerHTML = this.icons.get('pause');
+        this.template.playButton.innerHTML = this.icons.get('pause');
 
         this.video.play();
         this.setTime();
@@ -856,12 +816,12 @@ class DPlayer {
         this.container.classList.remove('dplayer-loading');
 
         if (!this.video.paused) {
-            this.bezel.innerHTML = this.icons.get('pause');
-            this.bezel.classList.add('dplayer-bezel-transition');
+            this.template.bezel.innerHTML = this.icons.get('pause');
+            this.template.bezel.classList.add('dplayer-bezel-transition');
         }
 
         this.ended = false;
-        this.playButton.innerHTML = this.icons.get('play');
+        this.template.playButton.innerHTML = this.icons.get('play');
         this.video.pause();
         this.clearTime();
         this.container.classList.remove('dplayer-playing');
@@ -880,7 +840,7 @@ class DPlayer {
             percentage = percentage < 1 ? percentage : 1;
             this.updateBar('volume', percentage, 'width');
             const formatPercentage = `${(percentage * 100).toFixed(0)}%`;
-            this.container.getElementsByClassName('dplayer-volume-bar-wrap')[0].dataset.balloon = formatPercentage;
+            this.template.volumeBarWrapWrap.dataset.balloon = formatPercentage;
             if (!nostorage) {
                 this.user.set('volume', percentage);
             }
@@ -929,11 +889,11 @@ class DPlayer {
         this.video.src = video.url;
         this.initMSE(this.video, video.type || 'auto');
         if (danmakuAPI) {
-            this.container.getElementsByClassName('dplayer-danloading')[0].style.display = 'block';
+            this.template.danmakuLoading.style.display = 'block';
             this.updateBar('played', 0, 'width');
             this.updateBar('loaded', 0, 'width');
-            this.container.getElementsByClassName('dplayer-ptime')[0].innerHTML = '00:00';
-            this.container.getElementsByClassName('dplayer-danmaku')[0].innerHTML = '';
+            this.template.ptime.innerHTML = '00:00';
+            this.template.danmaku.innerHTML = '';
             if (this.danmaku) {
                 this.danmaku.reload({
                     id: danmakuAPI.id,
@@ -966,7 +926,6 @@ class DPlayer {
 
         // HTTP Live Streaming
         if (this.type === 'hls' && Hls && Hls.isSupported()) {
-            // this.container.getElementsByClassName('dplayer-time')[0].style.display = 'none';
             const hls = new Hls();
             hls.loadSource(video.src);
             hls.attachMedia(video);
@@ -997,7 +956,7 @@ class DPlayer {
         // show video time: the metadata has loaded or changed
         this.on('durationchange', () => {
             if (video.duration !== 1) {           // compatibility: Android browsers will output 1 at first
-                this.container.getElementsByClassName('dplayer-dtime')[0].innerHTML = utils.secondToTime(video.duration);
+                this.template.dtime.innerHTML = utils.secondToTime(video.duration);
             }
         });
 
@@ -1050,7 +1009,7 @@ class DPlayer {
         this.volume(this.user.get('volume'), true, true);
 
         if (this.options.subtitle) {
-            this.subtitle = new Subtitle(this.container.getElementsByClassName('dplayer-subtitle')[0], this.video, this.options.subtitle, this.events);
+            this.subtitle = new Subtitle(this.template.subtitle, this.video, this.options.subtitle, this.events);
             if (!this.user.get('subtitle')) {
                 this.subtitle.hide();
             }
@@ -1066,14 +1025,13 @@ class DPlayer {
         }
         this.switchingQuality = true;
         this.quality = this.options.video.quality[index];
-        this.container.getElementsByClassName('dplayer-quality-icon')[0].innerHTML = this.quality.name;
+        this.template.qualityButton.innerHTML = this.quality.name;
 
         const paused = this.video.paused;
         this.video.pause();
-        const videoHTML = html.video(false, null, this.options.screenshot, 'auto', this.quality.url, this.options.subtitle);
+        const videoHTML = this.template.tplVideo(false, null, this.options.screenshot, 'auto', this.quality.url, this.options.subtitle);
         const videoEle = new DOMParser().parseFromString(videoHTML, 'text/html').body.firstChild;
-        const parent = this.container.getElementsByClassName('dplayer-video-wrap')[0];
-        parent.insertBefore(videoEle, parent.getElementsByTagName('div')[0]);
+        this.template.videoWrap.insertBefore(videoEle, this.template.videoWrap.getElementsByTagName('div')[0]);
         this.prevVideo = this.video;
         this.video = videoEle;
         this.initVideo(this.video, this.quality.type || this.options.video.type);
@@ -1087,7 +1045,7 @@ class DPlayer {
                     this.seek(this.prevVideo.currentTime);
                     return;
                 }
-                parent.removeChild(this.prevVideo);
+                this.template.videoWrap.removeChild(this.prevVideo);
                 this.video.classList.add('dplayer-video-current');
                 if (!paused) {
                     this.video.play();
@@ -1164,7 +1122,7 @@ class DPlayer {
     }
 
     initThumbnails () {
-        this.thumbnails = new Thumbnails(this.container.getElementsByClassName('dplayer-bar-preview')[0], this.container.getElementsByClassName('dplayer-bar-wrap')[0].offsetWidth, this.options.video.thumbnails, this.events);
+        this.thumbnails = new Thumbnails(this.template.barPreview, this.template.barWrap.offsetWidth, this.options.video.thumbnails, this.events);
 
         this.on('loadedmetadata', () => {
             this.thumbnails.resize(160, 90);
@@ -1172,15 +1130,14 @@ class DPlayer {
     }
 
     notice (text, time = 2000, opacity = 0.8) {
-        const noticeEle = this.container.getElementsByClassName('dplayer-notice')[0];
-        noticeEle.innerHTML = text;
-        noticeEle.style.opacity = opacity;
+        this.template.notice.innerHTML = text;
+        this.template.notice.style.opacity = opacity;
         if (this.noticeTime) {
             clearTimeout(this.noticeTime);
         }
         this.events.trigger('notice_show', text);
         this.noticeTime = setTimeout(() => {
-            noticeEle.style.opacity = 0;
+            this.template.notice.style.opacity = 0;
             this.events.trigger('notice_hide');
         }, time);
     }

+ 346 - 0
src/template.js

@@ -0,0 +1,346 @@
+class Template {
+    constructor (options) {
+        this.container = options.container;
+        this.options = options.options;
+        this.index = options.index;
+        this.tran = options.tran;
+        this.icons = options.icons;
+        this.init();
+    }
+
+    init () {
+        this.container.innerHTML = this.tpl(this.options, this.index, this.tran, this.icons);
+
+        this.volumeBar = this.container.querySelector('.dplayer-volume-bar-inner');
+        this.volumeBarWrap = this.container.querySelector('.dplayer-volume-bar');
+        this.volumeBarWrapWrap = this.container.querySelector('.dplayer-volume-bar-wrap');
+        this.volumeButton = this.container.querySelector('.dplayer-volume');
+        this.volumeIcon = this.container.querySelector('.dplayer-volume-icon .dplayer-icon-content');
+        this.playedBar = this.container.querySelector('.dplayer-played');
+        this.loadedBar = this.container.querySelector('.dplayer-loaded');
+        this.playedBarWrap = this.container.querySelector('.dplayer-bar-wrap');
+        this.playedBarTime = this.container.querySelector('.dplayer-bar-time');
+        this.danmaku = this.container.querySelector('.dplayer-danmaku');
+        this.danmakuLoading = this.container.querySelector('.dplayer-danloading');
+        this.video = this.container.querySelector('.dplayer-video-current');
+        this.bezel = this.container.querySelector('.dplayer-bezel-icon');
+        this.playButton = this.container.querySelector('.dplayer-play-icon');
+        this.videoWrap = this.container.querySelector('.dplayer-video-wrap');
+        this.controllerMask = this.container.querySelector('.dplayer-controller-mask');
+        this.ptime = this.container.querySelector('.dplayer-ptime');
+        this.settingButton = this.container.querySelector('.dplayer-setting-icon');
+        this.settingBox = this.container.querySelector('.dplayer-setting-box');
+        this.mask = this.container.querySelector('.dplayer-mask');
+        this.loop = this.container.querySelector('.dplayer-setting-loop');
+        this.loopToggle = this.container.querySelector('.dplayer-setting-loop .dplayer-toggle-setting-input');
+        this.showDanmaku = this.container.querySelector('.dplayer-setting-showdan');
+        this.showDanmakuToggle = this.container.querySelector('.dplayer-showdan-setting-input');
+        this.unlimitDanmaku = this.container.querySelector('.dplayer-setting-danunlimit');
+        this.unlimitDanmakuToggle = this.container.querySelector('.dplayer-danunlimit-setting-input');
+        this.speed = this.container.querySelector('.dplayer-setting-speed');
+        this.speedItem = this.container.querySelectorAll('dplayer-setting-speed-item');
+        this.danmakuOpacityBar = this.container.querySelector('.dplayer-danmaku-bar-inner');
+        this.danmakuOpacityBarWrap = this.container.querySelector('.dplayer-danmaku-bar');
+        this.danmakuOpacityBarWrapWrap = this.container.querySelector('.dplayer-danmaku-bar-wrap');
+        this.danmakuOpacityBox = this.container.querySelector('.dplayer-setting-danmaku');
+        this.dtime = this.container.querySelector('.dplayer-dtime');
+        this.controller = this.container.querySelector('.dplayer-controller');
+        this.commentInput = this.container.querySelector('.dplayer-comment-input');
+        this.commentButton = this.container.querySelector('.dplayer-comment-icon');
+        this.commentSettingBox = this.container.querySelector('.dplayer-comment-setting-box');
+        this.commentSettingButton = this.container.querySelector('.dplayer-comment-setting-icon');
+        this.commentSettingFill = this.container.querySelector('.dplayer-comment-setting-icon .dplayer-fill');
+        this.commentSendButton = this.container.querySelector('.dplayer-send-icon');
+        this.commentSendFill = this.container.querySelector('.dplayer-send-icon .dplayer-fill');
+        this.commentColorSettingBox = this.container.querySelector('.dplayer-comment-setting-color');
+        this.svgFill = this.container.querySelector('.dplayer-fill');
+        this.browserFullButton = this.container.querySelector('.dplayer-full-icon');
+        this.webFullButton = this.container.querySelector('.dplayer-full-in-icon');
+        this.menu = this.container.querySelector('.dplayer-menu');
+        this.qualityList = this.container.querySelector('.dplayer-quality-list');
+        this.camareButton = this.container.querySelector('.dplayer-camera-icon');
+        this.subtitleButton = this.container.querySelector('.dplayer-subtitle-icon');
+        this.subtitleButtonInner = this.container.querySelector('.dplayer-subtitle-icon .dplayer-icon-content');
+        this.subtitle = this.container.querySelector('.dplayer-subtitle');
+        this.qualityButton = this.container.querySelector('.dplayer-quality-icon');
+        this.videoWrap = this.parent = this.container.querySelector('.dplayer-video-wrap');
+        this.barPreview = this.container.querySelector('.dplayer-bar-preview');
+        this.barWrap = this.container.querySelector('.dplayer-bar-wrap');
+        this.notice = this.container.querySelector('.dplayer-notice');
+    }
+
+    tpl (options, index, tran, icons) {
+        return `
+        <div class="dplayer-mask"></div>
+        <div class="dplayer-video-wrap">
+            ${this.tplVideo(true, options.video.pic, options.screenshot, options.preload, options.video.url, options.subtitle)}
+            ${options.logo ? `
+            <div class="dplayer-logo"><img src="${options.logo}"></div>
+            ` : ``}
+            <div class="dplayer-danmaku" style="${options.danmaku ? this.tplDanmakumargin(options.danmaku.margin) : ``}">
+                <div class="dplayer-danmaku-item dplayer-danmaku-item--demo"></div>
+            </div>
+            <div class="dplayer-subtitle"></div>
+            <div class="dplayer-bezel">
+                <span class="dplayer-bezel-icon"></span>
+                ${options.danmaku ? `<span class="dplayer-danloading">${tran('Danmaku is loading')}</span>` : ``}
+                <span class="diplayer-loading-icon">
+                    <svg height="100%" version="1.1" viewBox="0 0 22 22" width="100%">
+                        <svg x="7" y="1">
+                            <circle class="diplayer-loading-dot diplayer-loading-dot-0" cx="4" cy="4" r="2"></circle>
+                        </svg>
+                        <svg x="11" y="3">
+                            <circle class="diplayer-loading-dot diplayer-loading-dot-1" cx="4" cy="4" r="2"></circle>
+                        </svg>
+                        <svg x="13" y="7">
+                            <circle class="diplayer-loading-dot diplayer-loading-dot-2" cx="4" cy="4" r="2"></circle>
+                        </svg>
+                        <svg x="11" y="11">
+                            <circle class="diplayer-loading-dot diplayer-loading-dot-3" cx="4" cy="4" r="2"></circle>
+                        </svg>
+                        <svg x="7" y="13">
+                            <circle class="diplayer-loading-dot diplayer-loading-dot-4" cx="4" cy="4" r="2"></circle>
+                        </svg>
+                        <svg x="3" y="11">
+                            <circle class="diplayer-loading-dot diplayer-loading-dot-5" cx="4" cy="4" r="2"></circle>
+                        </svg>
+                        <svg x="1" y="7">
+                            <circle class="diplayer-loading-dot diplayer-loading-dot-6" cx="4" cy="4" r="2"></circle>
+                        </svg>
+                        <svg x="3" y="3">
+                            <circle class="diplayer-loading-dot diplayer-loading-dot-7" cx="4" cy="4" r="2"></circle>
+                        </svg>
+                    </svg>
+                </span>
+            </div>
+        </div>
+        <div class="dplayer-controller-mask"></div>
+        <div class="dplayer-controller">
+            <div class="dplayer-icons dplayer-comment-box">
+                <button class="dplayer-icon dplayer-comment-setting-icon" data-balloon="${tran('Setting')}" data-balloon-pos="up">
+                    <span class="dplayer-icon-content">${icons.get('pallette')}</span>
+                </button>
+                <div class="dplayer-comment-setting-box">
+                    <div class="dplayer-comment-setting-color">
+                        <div class="dplayer-comment-setting-title">${tran('Set danmaku color')}</div>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#fff" checked>
+                            <span style="background: #fff;"></span>
+                        </label>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#e54256">
+                            <span style="background: #e54256"></span>
+                        </label>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#ffe133">
+                            <span style="background: #ffe133"></span>
+                        </label>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#64DD17">
+                            <span style="background: #64DD17"></span>
+                        </label>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#39ccff">
+                            <span style="background: #39ccff"></span>
+                        </label>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#D500F9">
+                            <span style="background: #D500F9"></span>
+                        </label>
+                    </div>
+                    <div class="dplayer-comment-setting-type">
+                        <div class="dplayer-comment-setting-title">${tran('Set danmaku type')}</div>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-type-${index}" value="top">
+                            <span>${tran('Top')}</span>
+                        </label>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-type-${index}" value="right" checked>
+                            <span>${tran('Rolling')}</span>
+                        </label>
+                        <label>
+                            <input type="radio" name="dplayer-danmaku-type-${index}" value="bottom">
+                            <span>${tran('Bottom')}</span>
+                        </label>
+                    </div>
+                </div>
+                <input class="dplayer-comment-input" type="text" placeholder="${tran('Input danmaku, hit Enter')}" maxlength="30">
+                <button class="dplayer-icon dplayer-send-icon" data-balloon="${tran('Send')}" data-balloon-pos="up">
+                    <span class="dplayer-icon-content">${icons.get('send')}</span>
+                </button>
+            </div>
+            <div class="dplayer-icons dplayer-icons-left">
+                <button class="dplayer-icon dplayer-play-icon">
+                    <span class="dplayer-icon-content">${icons.get('play')}</span>
+                </button>
+                <div class="dplayer-volume">
+                    <button class="dplayer-icon dplayer-volume-icon">
+                        <span class="dplayer-icon-content">${icons.get('volume-down')}</span>
+                    </button>
+                    <div class="dplayer-volume-bar-wrap" data-balloon-pos="up">
+                        <div class="dplayer-volume-bar">
+                            <div class="dplayer-volume-bar-inner" style="background: ${options.theme};">
+                                <span class="dplayer-thumb" style="background: ${options.theme}"></span>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <span class="dplayer-time"><span class="dplayer-ptime">0:00</span> / <span class="dplayer-dtime">0:00</span></span>
+                ${options.live ? `<span class="dplayer-live-badge"><span class="dplayer-live-dot" style="background: ${options.theme};"></span>${tran('Live')}</span>` : ''}
+            </div>
+            <div class="dplayer-icons dplayer-icons-right">
+                ${options.video.quality ? `
+                <div class="dplayer-quality">
+                    <button class="dplayer-icon dplayer-quality-icon">${options.video.quality[options.video.defaultQuality].name}</button>
+                    <div class="dplayer-quality-mask">
+                        ${this.tplQualityList(options.video.quality)}
+                    </div>
+                </div>
+                ` : ``}
+                ${options.screenshot ? `
+                <a href="#" class="dplayer-icon dplayer-camera-icon" data-balloon="${tran('Screenshot')}" data-balloon-pos="up">
+                    <span class="dplayer-icon-content">${icons.get('camera')}</span>
+                </a>
+                ` : ``}
+                <div class="dplayer-comment">
+                    <button class="dplayer-icon dplayer-comment-icon" data-balloon="${tran('Send danmaku')}" data-balloon-pos="up">
+                        <span class="dplayer-icon-content">${icons.get('comment')}</span>
+                    </button>
+                </div>
+                ${options.subtitle ? `
+                <div class="dplayer-subtitle-btn">
+                    <button class="dplayer-icon dplayer-subtitle-icon" data-balloon="${tran('Hide subtitle')}" data-balloon-pos="up">
+                        <span class="dplayer-icon-content">${icons.get('subtitle')}</span>
+                    </button>
+                </div>
+                ` : ``}
+                <div class="dplayer-setting">
+                    <button class="dplayer-icon dplayer-setting-icon" data-balloon="${tran('Setting')}" data-balloon-pos="up">
+                        <span class="dplayer-icon-content">${icons.get('setting')}</span>
+                    </button>
+                    <div class="dplayer-setting-box">
+                        <div class="dplayer-setting-origin-panel">
+                            <div class="dplayer-setting-item dplayer-setting-speed">
+                                <span class="dplayer-label">${tran('Speed')}</span>
+                                <div class="dplayer-toggle">
+                                    ${icons.get('right')}
+                                </div>
+                            </div>
+                            <div class="dplayer-setting-item dplayer-setting-loop">
+                                <span class="dplayer-label">${tran('Loop')}</span>
+                                <div class="dplayer-toggle">
+                                    <input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle">
+                                    <label for="dplayer-toggle"></label>
+                                </div>
+                            </div>
+                            <div class="dplayer-setting-item dplayer-setting-showdan">
+                                <span class="dplayer-label">${tran('Show danmaku')}</span>
+                                <div class="dplayer-toggle">
+                                    <input class="dplayer-showdan-setting-input" type="checkbox" name="dplayer-toggle-dan">
+                                    <label for="dplayer-toggle-dan"></label>
+                                </div>
+                            </div>
+                            <div class="dplayer-setting-item dplayer-setting-danunlimit">
+                                <span class="dplayer-label">${tran('Unlimited danmaku')}</span>
+                                <div class="dplayer-toggle">
+                                    <input class="dplayer-danunlimit-setting-input" type="checkbox" name="dplayer-toggle-danunlimit">
+                                    <label for="dplayer-toggle-danunlimit"></label>
+                                </div>
+                            </div>
+                            <div class="dplayer-setting-item dplayer-setting-danmaku">
+                                <span class="dplayer-label">${tran('Opacity for danmaku')}</span>
+                                <div class="dplayer-danmaku-bar-wrap">
+                                    <div class="dplayer-danmaku-bar">
+                                        <div class="dplayer-danmaku-bar-inner">
+                                            <span class="dplayer-thumb"></span>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="dplayer-setting-speed-panel">
+                            <div class="dplayer-setting-speed-item" data-speed="0.5">
+                                <span class="dplayer-label">0.5</span>
+                            </div>
+                            <div class="dplayer-setting-speed-item" data-speed="0.75">
+                                <span class="dplayer-label">0.75</span>
+                            </div>
+                            <div class="dplayer-setting-speed-item" data-speed="1">
+                                <span class="dplayer-label">${tran('Normal')}</span>
+                            </div>
+                            <div class="dplayer-setting-speed-item" data-speed="1.25">
+                                <span class="dplayer-label">1.25</span>
+                            </div>
+                            <div class="dplayer-setting-speed-item" data-speed="1.5">
+                                <span class="dplayer-label">1.5</span>
+                            </div>
+                            <div class="dplayer-setting-speed-item" data-speed="2">
+                                <span class="dplayer-label">2</span>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="dplayer-full">
+                    <button class="dplayer-icon dplayer-full-in-icon" data-balloon="${tran('Web full screen')}" data-balloon-pos="up">
+                        <span class="dplayer-icon-content">${icons.get('full-in')}</span>
+                    </button>
+                    <button class="dplayer-icon dplayer-full-icon" data-balloon="${tran('Full screen')}" data-balloon-pos="up">
+                        <span class="dplayer-icon-content">${icons.get('full')}</span>
+                    </button>
+                </div>
+            </div>
+            <div class="dplayer-bar-wrap">
+                <div class="dplayer-bar-time hidden">00:00</div>
+                <div class="dplayer-bar-preview"></div>
+                <div class="dplayer-bar">
+                    <div class="dplayer-loaded" style="width: 0;"></div>
+                    <div class="dplayer-played" style="width: 0; background: ${options.theme}">
+                        <span class="dplayer-thumb" style="background: ${options.theme}"></span>
+                    </div>
+                </div>
+            </div>
+        </div>
+        ${this.tplContextmenuList(options.contextmenu, tran)}
+        <div class="dplayer-notice"></div>`;
+    }
+
+    tplDanmakumargin (margin) {
+        let result = '';
+        if (margin) {
+            for (const key in margin) {
+                result += `${key}:${margin[key]};`;
+            }
+        }
+        return result;
+    }
+
+    tplContextmenuList (contextmenu, tran) {
+        let result = '<div class="dplayer-menu">';
+        for (let i = 0; i < contextmenu.length; i++) {
+            result += `<div class="dplayer-menu-item"><a target="_blank" href="${contextmenu[i].link}">${tran(contextmenu[i].text)}</a></div>`;
+        }
+        result += '</div>';
+
+        return result;
+    }
+
+    tplQualityList (quality) {
+        let result = '<div class="dplayer-quality-list">';
+        for (let i = 0; i < quality.length; i++) {
+            result += `<div class="dplayer-quality-item" data-index="${i}">${quality[i].name}</div>`;
+        }
+        result += '</div>';
+
+        return result;
+    }
+
+    tplVideo (current, pic, screenshot, preload, url, subtitle) {
+        const enableSubtitle = subtitle && subtitle.type === 'webvtt';
+        return `
+        <video class="dplayer-video ${current ? `dplayer-video-current"` : ``}" ${pic ? `poster="${pic}"` : ``} webkit-playsinline playsinline ${screenshot || enableSubtitle ? `crossorigin="anonymous"` : ``} ${preload ? `preload="${preload}"` : ``} src="${url}">
+            ${enableSubtitle ? `<track kind="metadata" default src="${subtitle.url}"></track>` : ``}
+        </video>`;
+    }
+}
+
+module.exports = Template;

Some files were not shown because too many files changed in this diff