├── .gitignore ├── package.json ├── dilation-player.template.audio.html ├── dilation-player.template.html ├── config.js ├── plugins └── dilation-player.plugin.ads.js ├── index.html ├── README.md ├── dilation-player.css └── dilation-player.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dilation-player", 3 | "version": "1.0.0", 4 | "description": "The player for video html5", 5 | "main": "dilation-player.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/cobonla/DilationPlayer.git" 12 | }, 13 | "keywords": [ 14 | "video player", 15 | "free player", 16 | "html5 player", 17 | "free video player", 18 | "custom video player", 19 | "stream video player", 20 | "stream video" 21 | ], 22 | "author": "Cobonla", 23 | "license": "MIT license", 24 | "bugs": { 25 | "url": "https://github.com/cobonla/DilationPlayer/issues" 26 | }, 27 | "homepage": "https://github.com/cobonla/DilationPlayer#readme" 28 | } 29 | -------------------------------------------------------------------------------- /dilation-player.template.audio.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 |
26 |
27 |
28 | 29 |
30 | 31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 39 |
40 | 41 |
42 | 43 |
44 |
45 | 46 | 47 | 48 | 49 |
50 |
51 |
52 |
-------------------------------------------------------------------------------- /dilation-player.template.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 |
26 |
27 |
28 | 29 |
30 | 31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 39 |
40 | 41 |
42 | 43 |
44 |
45 | 46 | 47 | 48 | 49 |
50 |
51 |
52 |
-------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | __dp.defaultConfig = { 2 | elements: { 3 | object: null, 4 | container: '.dp', 5 | video: '.dp-video', 6 | audio: '.dp-audio', 7 | logo: '.dp-logo', 8 | progress: '.dp-progress', 9 | progressLoading: '.dp-progress .dp-loading', 10 | progressPlaying: '.dp-progress .dp-playing', 11 | progressHoverTooltipText: '.dp-progress-tooltip-text', 12 | progressHoverTooltipImage: '.dp-progress-tooltip-image', 13 | control: '.dp-control', 14 | button: '.dp-button', 15 | controlPlayPause: '.dp-btn-play', 16 | controlFullScreen: '.dp-btn-fullscreen', 17 | controlLargeScreen: '.dp-btn-largescreen', 18 | controlVolume: '.dp-btn-volume', 19 | controlVolumeTooltip: '.dp-volume-tooltip', 20 | controlVolumeRange: '.dp-volume-range', 21 | controlTimer: '.dp-timer', 22 | modal: '.dp-modal', 23 | loaderModal: '.dp-modal-loader', 24 | loaderModalIcon: '.dp-modal-loader-icon', 25 | playerModal: '.dp-modal-player', 26 | playerModalIcon: '.dp-modal-player-icon', 27 | menu: '.dp-menu', 28 | menuList: '.dp-menu-list', 29 | menuItem: '.dp-menu-item', 30 | menuItemLoop: '.dp-menu-item-loop', 31 | menuItemCopyUrl: '.dp-menu-item-copy-url', 32 | ads: '.dp-ads', 33 | adsItem: '.dp-ads .dp-ads-item', 34 | adsContent: '.dp-ads .dp-ads-content', 35 | adsClose: '.dp-ads .dp-ads-close', 36 | }, 37 | icons: { 38 | loaderModal: '', 39 | playerModal: '', 40 | fullScreen: '', 41 | actualScreen: '', 42 | largeScreen: '', 43 | smallScreen: '', 44 | pause: '', 45 | play: '', 46 | volumeMute: '', 47 | volume1: '', 48 | volume2: '', 49 | volume3: '', 50 | close: '[X]' 51 | }, 52 | volume: 100, 53 | view: { 54 | content: null, 55 | import: null 56 | }, 57 | sources: {}, 58 | logo: { 59 | height: '10%', 60 | rate: 1 61 | }, 62 | size: { 63 | width: '100%', 64 | rate: 2 / 3 65 | }, 66 | largeScreen: false, 67 | locale: 'en', 68 | menu: {}, 69 | poster: null, 70 | schedules: [], 71 | type: 'video', 72 | plugins: {}, 73 | startAt: 0, 74 | preview: {} 75 | }; -------------------------------------------------------------------------------- /plugins/dilation-player.plugin.ads.js: -------------------------------------------------------------------------------- 1 | // ==================================================== 2 | // Plugin {DPAds} 3 | // ==================================================== 4 | class DPAdsPlugin extends DPBase { 5 | /** 6 | * constructor 7 | * @param app 8 | */ 9 | constructor(app) { 10 | super(); 11 | this.app = app; 12 | this.currentSetting = {}; 13 | this.usedType = []; 14 | } 15 | 16 | /** 17 | * Run 18 | * @return {DilationPlayerPluginsAds} 19 | */ 20 | init() { 21 | let icon = this.app.config.get('icons.close'); 22 | let close = this.app.config.el('elements.adsClose'); 23 | let instance = this; 24 | let runner = this.app.config.runner(true).node(); 25 | this.isPlay = !runner.paused; 26 | this.runningAds = null; 27 | this.types = {full: 'full', line: 'line', require: 'require'}; 28 | 29 | // Event when click on button close 30 | close.listen('click', function () { 31 | instance.close(); 32 | }); 33 | 34 | close.html(icon); 35 | 36 | function __callResize(){ 37 | instance.resize(); 38 | } 39 | 40 | __dp.node(window).listen('resize', __callResize); 41 | 42 | // Event when control change 43 | this.app.event.listen('dp.control.hide', __callResize) 44 | .listen('dp.control.show', __callResize); 45 | 46 | return this; 47 | } 48 | 49 | /** 50 | * Resize 51 | */ 52 | resize(){ 53 | if (this.currentSetting.type === 'line') { 54 | let control = this.app.config.el('elements.control'); 55 | let ads = this.app.config.el('elements.ads'); 56 | 57 | if (control.hasClass('active')) { 58 | let height = control.height(); 59 | ads.css('bottom', (height + 1)+'px'); 60 | } else { 61 | ads.css('bottom', '10px'); 62 | } 63 | } 64 | } 65 | 66 | /** 67 | * Run 68 | * @return {DilationPlayerPluginsAds} 69 | */ 70 | open(content, conf) { 71 | let ads = this.app.config.el('elements.ads'); 72 | let adsClose = this.app.config.el('elements.adsClose'); 73 | let adsContent = this.app.config.el('elements.adsContent'); 74 | let runner = this.app.config.runner(true).node(); 75 | let instance = this; 76 | this.isPlay = !runner.paused; 77 | 78 | if (conf !== undefined) { 79 | this.currentSetting = this.or(conf, {}); 80 | } 81 | 82 | this.currentSetting.type = this.or(this.currentSetting.type, this.types.line); 83 | 84 | ads.removeClass(this.types.line) 85 | .removeClass(this.types.full) 86 | .removeClass(this.types.require); 87 | 88 | ads.addClass(this.currentSetting.type); 89 | ads.active(true); 90 | 91 | if (content !== undefined) { 92 | adsContent.html(content); 93 | } 94 | 95 | if (this.currentSetting.type === this.types.require) { 96 | this.app.source.pause(); 97 | adsClose.active(false); 98 | 99 | this.runningAds = window.setTimeout(function(){ 100 | instance.close(); 101 | }, this.currentSetting.time); 102 | } else if (this.currentSetting.type === this.types.full) { 103 | this.app.source.pause(); 104 | adsClose.active(true); 105 | } else { 106 | adsClose.active(true); 107 | } 108 | 109 | this.resize(); 110 | 111 | return this; 112 | } 113 | 114 | /** 115 | * Close 116 | * @return {DilationPlayerPluginsAds} 117 | */ 118 | close(){ 119 | let ads = this.app.config.el('elements.ads'); 120 | 121 | window.clearTimeout(this.runningAds); 122 | ads.active(false); 123 | 124 | if ((this.currentSetting.type === this.types.require 125 | || this.currentSetting.type === this.types.full) 126 | && this.isPlay) { 127 | this.app.source.play(); 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Video Demo 5 | 6 | 8 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 | 23 | 25 | 91 | 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DilationPlayer 2 | 3 | DilationPlayer is object, It provide methods to play video/audio. **[Video demo](https://dilationplayer.cobonla.org/)** 4 | 5 | **Using** 6 | 7 | Import file DilationPlayer.js to your html page. 8 | 9 | Html page: 10 | 11 | ``` 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 22 | 23 | ``` 24 | 25 | Then create new object. 26 | 27 | ``` 28 | var player = new DilationPlayer('#video-container', json_config); 29 | ``` 30 | 31 | Then it auto apply to your elements. If you want to custom, then change **json_config** value bellow. 32 | 33 | ``` 34 | { 35 | elements: { 36 | object: null, 37 | container: '.dp', 38 | video: '.dp-video', 39 | audio: '.dp-audio', 40 | logo: '.dp-logo', 41 | progress: '.dp-progress', 42 | progressLoading: '.dp-progress .dp-loading', 43 | progressPlaying: '.dp-progress .dp-playing', 44 | progressHoverTooltipText: '.dp-progress-tooltip-text', 45 | progressHoverTooltipImage: '.dp-progress-tooltip-image', 46 | control: '.dp-control', 47 | button: '.dp-button', 48 | controlPlayPause: '.dp-btn-play', 49 | controlFullScreen: '.dp-btn-fullscreen', 50 | controlLargeScreen: '.dp-btn-largescreen', 51 | controlVolume: '.dp-btn-volume', 52 | controlVolumeTooltip: '.dp-volume-tooltip', 53 | controlVolumeRange: '.dp-volume-range', 54 | controlTimer: '.dp-timer', 55 | modal: '.dp-modal', 56 | loaderModal: '.dp-modal-loader', 57 | loaderModalIcon: '.dp-modal-loader-icon', 58 | playerModal: '.dp-modal-player', 59 | playerModalIcon: '.dp-modal-player-icon', 60 | menu: '.dp-menu', 61 | menuList: '.dp-menu-list', 62 | menuItem: '.dp-menu-item', 63 | menuItemLoop: '.dp-menu-item-loop', 64 | menuItemCopyUrl: '.dp-menu-item-copy-url', 65 | ads: '.dp-ads', 66 | adsItem: '.dp-ads .dp-ads-item', 67 | adsContent: '.dp-ads .dp-ads-content', 68 | adsClose: '.dp-ads .dp-ads-close', 69 | }, 70 | icons: { 71 | loaderModal: '', 72 | playerModal: '', 73 | fullScreen: '', 74 | actualScreen: '', 75 | largeScreen: '', 76 | smallScreen: '', 77 | pause: '', 78 | play: '', 79 | volumeMute: '', 80 | volume1: '', 81 | volume2: '', 82 | volume3: '', 83 | close: '[X]' 84 | }, 85 | volume: 100, 86 | view: { 87 | content: null, 88 | import: null 89 | }, 90 | sources: {}, 91 | logo: { 92 | height: '10%', 93 | rate: 1 94 | }, 95 | size: { 96 | width: '100%', 97 | rate: 2 / 3 98 | }, 99 | largeScreen: false, 100 | locale: 'en', 101 | menu: {}, 102 | poster: null, 103 | schedules: [], 104 | type: 'video', 105 | plugins: {}, 106 | startAt: 0 107 | } 108 | ``` 109 | 110 | Example, you would like to show video without **logo** then: 111 | 112 | ``` 113 | var player = new DilationPlayer('#video-container', { 114 | logo: false 115 | }); 116 | ``` 117 | 118 | Or you want to show the poster before start video then: 119 | 120 | ``` 121 | var player = new DilationPlayer('#video-container', { 122 | poster: 'https://mywebsite.com/poster.png' 123 | }); 124 | ``` 125 | 126 | Full source code after config: 127 | 128 | ``` 129 | 130 | 131 | 132 | 133 | 134 | 135 |
136 | 137 | 139 | 145 | 146 | ``` 147 | 148 | OK, now it's working! 149 | -------------------------------------------------------------------------------- /dilation-player.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | padding: 0; 3 | margin: 0; 4 | height: 100%; 5 | width: 100%; 6 | position: relative; 7 | } 8 | 9 | .hidden-cursor { 10 | /*cursor: url("blank.cur"),auto !important;*/ 11 | } 12 | 13 | .notransition { 14 | -webkit-transition: none !important; 15 | -moz-transition: none !important; 16 | -o-transition: none !important; 17 | transition: none !important; 18 | } 19 | 20 | .dp { 21 | width: 100%; 22 | height: 100%; 23 | background-color: #000; 24 | position: relative; 25 | overflow: hidden; 26 | } 27 | 28 | .dp .dp-video, 29 | .dp .dp-audio{ 30 | width: 100%; 31 | height: 100%; 32 | position: absolute; 33 | top: 0 34 | } 35 | 36 | /* ============ CSS for logo =============== */ 37 | .dp .dp-logo { 38 | position: absolute; 39 | top: 4%; 40 | left: 3%; 41 | height: 7%; 42 | z-index: 9; 43 | opacity: 0.7; 44 | cursor: pointer; 45 | background-position: left; 46 | background-size: contain; 47 | background-repeat: no-repeat; 48 | display: none; 49 | } 50 | 51 | .dp .dp-logo.active{ 52 | display: block; 53 | } 54 | 55 | .dp .dp-logo:hover { 56 | opacity: 1 57 | } 58 | 59 | /* ============ CSS for menu =================*/ 60 | .dp-menu { 61 | position: absolute; 62 | top: 0; 63 | left: 0; 64 | width: 100%; 65 | height: 100%; 66 | z-index: 10; 67 | visibility: hidden; 68 | opacity: 0; 69 | transition: visibility 0.1s, opacity 0.1s, background-color 0.2s linear; 70 | } 71 | 72 | .dp-menu.active { 73 | visibility: visible; 74 | opacity: 1; 75 | } 76 | 77 | .dp-menu .dp-menu-list { 78 | background-color: rgba(51, 47, 47, 0.75); 79 | color: #fff; 80 | min-width: 100px; 81 | position: fixed; 82 | } 83 | 84 | .dp-menu .dp-menu-list .dp-menu-item { 85 | padding: 10px 10px 10px 20px; 86 | cursor: pointer 87 | } 88 | 89 | .dp-menu .dp-menu-list .dp-menu-item:hover { 90 | background-color: rgba(0, 0, 0, 0.3); 91 | } 92 | 93 | .dp-menu .dp-menu-list .dp-menu-item:before { 94 | content: "✓"; 95 | color: #fff; 96 | margin-left: -15px; 97 | margin-right: 10px; 98 | font-size: 0.8em; 99 | visibility: hidden; 100 | } 101 | 102 | .dp-menu .dp-menu-list .dp-menu-item.active:before { 103 | visibility: visible; 104 | } 105 | 106 | /* ============ CSS for controls =============== */ 107 | .dp .dp-control { 108 | position: absolute; 109 | bottom: 0; 110 | left: 0; 111 | width: 100%; 112 | z-index: 9; 113 | height: 7%; 114 | min-height: 40px; 115 | max-height: 50px; 116 | transform: translateY(88%); 117 | transition: all 0.2s ease; 118 | background-color: transparent; 119 | background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.8)); 120 | } 121 | 122 | .dp .dp-control.active { 123 | transform: translateY(0); 124 | } 125 | 126 | /* CSS for PROGRESS */ 127 | .dp .dp-control .dp-progress { 128 | width: 96%; 129 | position: relative; 130 | height: 12%; 131 | cursor: pointer; 132 | margin: 0 auto; 133 | z-index: 9; 134 | } 135 | 136 | .dp .dp-control .dp-progress .dp-line { 137 | width: 100%; 138 | height: 40%; 139 | transition: all 0.2s linear; 140 | position: absolute; 141 | bottom: 0px; 142 | left: 0px; 143 | } 144 | 145 | .dp .dp-control .dp-progress:hover .dp-line { 146 | height: 70%; 147 | } 148 | 149 | .dp .dp-control .dp-progress .dp-line > div { 150 | height: 100%; 151 | width: 100%; 152 | position: absolute; 153 | bottom: 0px; 154 | left: 0px; 155 | } 156 | 157 | .dp .dp-control .dp-progress .dp-line .dp-playing { 158 | background-color: #FF5722; 159 | z-index: 3; 160 | } 161 | 162 | .dp .dp-control .dp-progress .dp-line .dp-loading { 163 | background-color: rgba(255, 255, 255, 0.5); 164 | width: 100%; 165 | z-index: 1; 166 | } 167 | 168 | .dp .dp-control .dp-progress .dp-progress-tooltip-text { 169 | display: none; 170 | background-color: black; 171 | color: #fff; 172 | text-align: center; 173 | padding: 1px 5px; 174 | position: absolute; 175 | z-index: 1; 176 | top: -1.8em; 177 | transform: translateX(-50%); 178 | } 179 | 180 | /*.dp .dp-control .dp-progress .dp-progress-tooltip-text::after {*/ 181 | /*content: '';*/ 182 | /*display: block;*/ 183 | /*position: absolute;*/ 184 | /*top: 100%;*/ 185 | /*left: 50%;*/ 186 | /*transform: translateX(-50%);*/ 187 | /*width: 0;*/ 188 | /*height: 0;*/ 189 | /*border-style: solid;*/ 190 | /*border-width: 4px 5px 0 5px;*/ 191 | /*border-color: black transparent transparent transparent;*/ 192 | /*}*/ 193 | 194 | .dp .dp-control .dp-progress:hover .dp-progress-tooltip-text.active { 195 | display: inline-block; 196 | } 197 | 198 | .dp .dp-control .dp-progress .dp-progress-tooltip-image { 199 | display: none; 200 | background: rgba(0, 0, 0, 0.6) no-repeat center; 201 | color: #fff; 202 | text-align: center; 203 | border: 1px solid #000; 204 | position: absolute; 205 | z-index: 1; 206 | top: calc(-58px + -1.8em); 207 | transform: translateX(-50%); 208 | width: 100px; 209 | height: 80px; 210 | background-size: cover; 211 | border-radius: 2px; 212 | } 213 | 214 | .dp .dp-control .dp-progress:hover .dp-progress-tooltip-image.active { 215 | display: inline-block; 216 | } 217 | 218 | /* ======================= CSS for button ========================== */ 219 | .dp .dp-control .dp-button { 220 | height: 88%; 221 | /*background-color: rgba(0, 0, 0, 0.5);*/ 222 | width: 100%; 223 | position: relative; 224 | } 225 | 226 | .dp .dp-control .dp-button > div { 227 | height: 100%; 228 | position: relative; 229 | transition: all 0.2s linear; 230 | width: 96%; 231 | margin: auto; 232 | } 233 | 234 | .dp .dp-control .dp-button > div:after, 235 | .dp .dp-control .dp-button .dp-group:after { 236 | clear: both; 237 | content: ""; 238 | display: block; 239 | } 240 | 241 | .dp .dp-control .dp-button .dp-group { 242 | height: 100%; 243 | position: relative; 244 | float: left; 245 | display: inline-block; 246 | } 247 | 248 | .dp .dp-control .dp-button button { 249 | background-color: transparent; 250 | color: #fff; 251 | border: none; 252 | outline: 0; 253 | font-size: 1.3em; 254 | cursor: pointer; 255 | height: 100%; 256 | transition: opacity .1s cubic-bezier(0.4, 0.0, 1, 1); 257 | line-height: inherit; 258 | float: left; 259 | padding: 0; 260 | } 261 | 262 | .dp .dp-control .dp-button button path { 263 | fill: #ffffff; 264 | } 265 | 266 | .dp .dp-control .dp-button button.dp-btn-largescreen, 267 | .dp .dp-control .dp-button button.dp-btn-fullscreen { 268 | float: right; 269 | } 270 | 271 | .dp .dp-control .dp-button button.dp-timer { 272 | font-size: 0.8em; 273 | } 274 | 275 | .dp .dp-control .dp-button .dp-volume-tooltip { 276 | transition: all 0.2s linear; 277 | opacity: 0; 278 | width: 0; 279 | display: inline-block; 280 | padding-right: 5px; 281 | border-right: 1px solid #525252; 282 | height: 100%; 283 | overflow: hidden; 284 | } 285 | 286 | .dp .dp-control .dp-button .dp-group:hover .dp-volume-tooltip { 287 | width: 100px; 288 | opacity: 1; 289 | box-sizing: border-box; 290 | } 291 | 292 | /* Custom range */ 293 | .dp .dp-control .dp-button .dp-group .dp-volume-range { 294 | width: 90px; 295 | top: 40%; 296 | position: absolute; 297 | -webkit-transform: translateY(-30%); 298 | -ms-transform: translateY(-30%); 299 | transform: translateY(-30%); 300 | opacity: 0.7; 301 | -webkit-transition: .2s; 302 | transition: opacity .2s; 303 | height: 7%; 304 | background: #fff; 305 | outline: none; 306 | -webkit-appearance: none; 307 | } 308 | 309 | .dp .dp-control .dp-button .dp-group .dp-volume-range:hover { 310 | opacity: 1; 311 | } 312 | 313 | .dp .dp-control .dp-button .dp-group .dp-volume-range::-webkit-slider-thumb { 314 | -webkit-appearance: none; 315 | appearance: none; 316 | width: 10px; 317 | height: 10px; 318 | background: #FF5722; 319 | cursor: pointer; 320 | border-radius: 50%; 321 | } 322 | 323 | .dp .dp-control .dp-button .dp-group .dp-volume-range::-moz-range-thumb { 324 | width: 10px; 325 | height: 10px; 326 | background: #FF5722; 327 | cursor: pointer; 328 | border-radius: 50%; 329 | } 330 | 331 | /* CSS for purdah */ 332 | .dp .dp-modal { 333 | position: absolute; 334 | top: 0; 335 | left: 0; 336 | width: 100%; 337 | height: 100%; 338 | background-color: rgba(0, 0, 0, 0.5); 339 | z-index: 8; 340 | display: none; 341 | } 342 | 343 | .dp .dp-modal.active { 344 | display: block; 345 | } 346 | 347 | .dp .dp-modal .dp-modal-icon { 348 | text-align: center; 349 | position: relative; 350 | top: 45%; 351 | -webkit-transform: translateY(-50%); 352 | -ms-transform: translateY(-50%); 353 | transform: translateY(-50%); 354 | color: #fff; 355 | margin: auto; 356 | display: block; 357 | width: 100px; 358 | font-size: 2em; 359 | } 360 | 361 | .dp .dp-modal .dp-modal-player-icon > * { 362 | border: 2px solid #fff; 363 | border-radius: 50%; 364 | background-color: rgba(0, 0, 0, 0.3); 365 | padding: 2px 1px 2px 3px; 366 | width: 40%; 367 | color: #fff; 368 | } 369 | 370 | .dp .dp-modal path { 371 | fill: #ffffff; 372 | } 373 | 374 | /* ======================== CSS for ADS ============== */ 375 | .dp .dp-ads { 376 | z-index: 9; 377 | display: none; 378 | transition: all .2s; 379 | } 380 | 381 | .dp .dp-ads.active { 382 | display: block; 383 | } 384 | 385 | .dp .dp-ads.line { 386 | height: 17%; 387 | min-height: 40px; 388 | max-height: 100px; 389 | position: absolute; 390 | bottom: 0; 391 | left: 0; 392 | width: 100%; 393 | } 394 | 395 | .dp .dp-ads.full, 396 | .dp .dp-ads.require{ 397 | position: absolute; 398 | top: 0; 399 | left: 0; 400 | width: 100%; 401 | height: 100%; 402 | z-index: 9999; 403 | } 404 | 405 | .dp .dp-ads .dp-ads-item{ 406 | margin: auto; 407 | position: relative; 408 | display: block; 409 | max-width: 100%; 410 | height: 100%; 411 | } 412 | 413 | .dp .dp-ads.line .dp-ads-item{ 414 | width: fit-content; 415 | } 416 | 417 | .dp .dp-ads.full .dp-ads-item, 418 | .dp .dp-ads.require .dp-ads-item{ 419 | width: 100%; 420 | } 421 | 422 | .dp .dp-ads .dp-ads-content { 423 | height: 100%; 424 | } 425 | 426 | .dp .dp-ads .dp-ads-close { 427 | position: absolute; 428 | top: 0; 429 | right: 0; 430 | background-color: #ffffff; 431 | outline: 0; 432 | cursor: pointer; 433 | border: none; 434 | color: #000; 435 | display: none; 436 | height: 17px; 437 | width: 17px; 438 | padding: 0; 439 | line-height: 0 440 | } 441 | 442 | .dp .dp-ads .dp-ads-close.active { 443 | display: inline-block; 444 | } 445 | -------------------------------------------------------------------------------- /dilation-player.js: -------------------------------------------------------------------------------- 1 | let __dp = { 2 | pad: function (n, width, z) { 3 | z = z || '0'; 4 | n = n + ''; 5 | return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; 6 | }, 7 | 8 | parseTime: function (times) { 9 | if (times < 0) { 10 | times = 0; 11 | } 12 | 13 | let hours = Math.floor(times / 3600); 14 | let minutes = Math.floor((times - hours * 3600) / 60); 15 | let seconds = Math.floor(times - (minutes * 60 + hours * 3600)); 16 | let format = (hours > 0 ? (this.pad(hours, 2) + ':') : '') + this.pad(minutes, 2) + ':' + this.pad(seconds, 2); 17 | 18 | return format; 19 | }, 20 | 21 | node: function (element) { 22 | return new DPNode(element); 23 | }, 24 | 25 | ready: function (call) { 26 | this.node(window).listen('load', call); 27 | } 28 | }; 29 | __dp.defaultConfig = { 30 | elements: { 31 | object: null, 32 | container: '.dp', 33 | video: '.dp-video', 34 | audio: '.dp-audio', 35 | logo: '.dp-logo', 36 | progress: '.dp-progress', 37 | progressLoading: '.dp-progress .dp-loading', 38 | progressPlaying: '.dp-progress .dp-playing', 39 | progressHoverTooltipText: '.dp-progress-tooltip-text', 40 | progressHoverTooltipImage: '.dp-progress-tooltip-image', 41 | control: '.dp-control', 42 | button: '.dp-button', 43 | buttonIcon: '.dp-button button.dp-icon', 44 | controlPlayPause: '.dp-btn-play', 45 | controlFullScreen: '.dp-btn-fullscreen', 46 | controlLargeScreen: '.dp-btn-largescreen', 47 | controlVolume: '.dp-btn-volume', 48 | controlVolumeTooltip: '.dp-volume-tooltip', 49 | controlVolumeRange: '.dp-volume-range', 50 | controlTimer: '.dp-timer', 51 | modal: '.dp-modal', 52 | loaderModal: '.dp-modal-loader', 53 | loaderModalIcon: '.dp-modal-loader-icon', 54 | playerModal: '.dp-modal-player', 55 | playerModalIcon: '.dp-modal-player-icon', 56 | menu: '.dp-menu', 57 | menuList: '.dp-menu-list', 58 | menuItem: '.dp-menu-item', 59 | menuItemLoop: '.dp-menu-item-loop', 60 | menuItemCopyUrl: '.dp-menu-item-copy-url', 61 | ads: '.dp-ads', 62 | adsItem: '.dp-ads .dp-ads-item', 63 | adsContent: '.dp-ads .dp-ads-content', 64 | adsClose: '.dp-ads .dp-ads-close', 65 | }, 66 | icons: { 67 | loaderModal: '', 68 | playerModal: '', 69 | fullScreen: '', 70 | actualScreen: '', 71 | largeScreen: '', 72 | smallScreen: '', 73 | pause: '', 74 | play: '', 75 | volumeMute: '', 76 | volume1: '', 77 | volume2: '', 78 | volume3: '', 79 | close: '' 80 | }, 81 | volume: 100, 82 | view: { 83 | content: null, 84 | import: null 85 | }, 86 | sources: {}, 87 | logo: { 88 | height: '10%', 89 | rate: 1 90 | }, 91 | size: { 92 | width: '100%', 93 | rate: 2 / 3 94 | }, 95 | largeScreen: false, 96 | locale: 'en', 97 | menu: {}, 98 | poster: null, 99 | schedules: [], 100 | type: 'video', 101 | plugins: {}, 102 | startAt: 0, 103 | preview: {} 104 | }; 105 | __dp.translateData = { 106 | en: { 107 | menu: { 108 | loop: 'Loop this video', 109 | copy_url: 'Copy video\'s url' 110 | }, 111 | 112 | app: { 113 | loading: 'Loading...', 114 | not_support: 'This browser not support player' 115 | } 116 | }, 117 | vi: { 118 | menu: { 119 | loop: 'Lặp video này', 120 | copy_url: 'Copy đường dẫn video' 121 | }, 122 | 123 | app: { 124 | loading: 'Đang tải...', 125 | not_support: 'Trình duyệt không hỗ trợ player' 126 | } 127 | } 128 | }; 129 | 130 | // ==================================================== 131 | // Class {Base} 132 | // ==================================================== 133 | class DPBase { 134 | /** 135 | * Check if value is undefined then return or 136 | * @param value 137 | * @param or 138 | * @return mixed 139 | */ 140 | or(value, or) { 141 | return value === undefined ? or : value; 142 | } 143 | } 144 | 145 | // ==================================================== 146 | // Class {DPNode} 147 | // ==================================================== 148 | class DPNode extends DPBase { 149 | /** 150 | * Constructor 151 | * @param selector 152 | */ 153 | constructor(selector) { 154 | super(); 155 | this.setSelector(selector); 156 | } 157 | 158 | /** 159 | * Convert to array 160 | * @param selector 161 | * @return {string|Array|*[]} 162 | */ 163 | convertToArray(selector) { 164 | if (selector instanceof NodeList) { 165 | for (var a = [], l = selector.length; l--; a[l] = selector[l]) ; 166 | selector = a; 167 | } else if (typeof selector !== 'string' 168 | && !(selector instanceof Array)) { 169 | selector = [selector]; 170 | } 171 | 172 | return selector; 173 | } 174 | 175 | /** 176 | * Set selector 177 | * @param selector 178 | * @return {DPNode} 179 | */ 180 | setSelector(selector) { 181 | this.selectors = this.convertToArray(selector); 182 | 183 | return this; 184 | } 185 | 186 | /** 187 | * Get selectors 188 | * @return {*[]|NodeListOf|*} 189 | */ 190 | nodes() { 191 | if (typeof this.selectors === 'string') { 192 | let nodes = document.querySelectorAll(this.selectors); 193 | return this.convertToArray(nodes); 194 | } 195 | 196 | return this.selectors; 197 | } 198 | 199 | /** 200 | * Get selector 201 | * @return {*} 202 | */ 203 | node() { 204 | if (typeof this.selectors === 'string') { 205 | return document.querySelector(this.selectors); 206 | } 207 | 208 | return this.selectors[0]; 209 | } 210 | 211 | /** 212 | * Find elements 213 | * @param selector 214 | * @return {DPNode} 215 | */ 216 | find(selector) { 217 | let children = this.node().querySelectorAll(selector); 218 | children = this.convertToArray(children); 219 | 220 | return new DPNode(children); 221 | } 222 | 223 | /** 224 | * Get parent 225 | * @return {DPNode} 226 | */ 227 | parent() { 228 | return new DPNode(this.node().parentNode); 229 | } 230 | 231 | /** 232 | * Get/set height of element 233 | * @param value 234 | * @return {*} 235 | */ 236 | height(value) { 237 | if (value === undefined) { 238 | let node = this.node(); 239 | 240 | return node.getBoundingClientRect !== undefined ? node.getBoundingClientRect().height : (function () { 241 | var myHeight = 0; 242 | 243 | if (typeof(window.innerWidth) == 'number') { 244 | myHeight = window.innerHeight; 245 | } else if (document.documentElement && document.documentElement.clientHeight) { 246 | myHeight = document.documentElement.clientHeight; 247 | } else if (document.body && document.body.clientHeight) { 248 | myHeight = document.body.clientHeight; 249 | } 250 | 251 | return myHeight; 252 | })(); 253 | } 254 | 255 | let selectors = this.nodes(); 256 | 257 | for (var i = 0; i < selectors.length; ++i) { 258 | selectors[i].style.height = value; 259 | } 260 | 261 | return this; 262 | } 263 | 264 | /** 265 | * Get/set width of element 266 | * @return {number} 267 | * @return {*} 268 | */ 269 | width(value) { 270 | if (value === undefined) { 271 | let node = this.node(); 272 | 273 | return node.getBoundingClientRect !== undefined ? node.getBoundingClientRect().width : (function () { 274 | var myWidth = 0; 275 | 276 | if (typeof(window.innerWidth) == 'number') { 277 | myWidth = window.innerWidth; 278 | } else if (document.documentElement && document.documentElement.clientWidth) { 279 | myWidth = document.documentElement.clientWidth; 280 | } else if (document.body && document.body.clientWidth) { 281 | myWidth = document.body.clientWidth; 282 | } 283 | 284 | return myWidth; 285 | })(); 286 | } 287 | 288 | let selectors = this.nodes(); 289 | 290 | for (var i = 0; i < selectors.length; ++i) { 291 | selectors[i].style.width = value; 292 | } 293 | 294 | return this; 295 | } 296 | 297 | /** 298 | * Add class to element 299 | * @param name 300 | */ 301 | addClass(name) { 302 | let selectors = this.nodes(); 303 | 304 | for (var i = 0; i < selectors.length; ++i) { 305 | selectors[i].classList.add(name); 306 | } 307 | 308 | return this; 309 | } 310 | 311 | /** 312 | * Remove class 313 | * @param name 314 | */ 315 | removeClass(name) { 316 | let selectors = this.nodes(); 317 | 318 | for (var i = 0; i < selectors.length; ++i) { 319 | if (selectors[i].classList.contains(name)) { 320 | selectors[i].classList.remove(name); 321 | } 322 | } 323 | 324 | return this; 325 | } 326 | 327 | /** 328 | * CSS 329 | * @param key 330 | * @param value 331 | * @return {*} 332 | */ 333 | css(key, value) { 334 | // Check if is get CSS 335 | if (typeof key === 'string' && value === undefined) { 336 | return this.node().style[key]; 337 | } 338 | 339 | let selectors = this.nodes(); 340 | let values = {}; 341 | 342 | if (typeof key === 'string') { 343 | values[key] = value; 344 | } else { 345 | values = key; 346 | } 347 | 348 | for (let i = 0; i < selectors.length; i++) { 349 | for (let vKey in values) { 350 | selectors[i].style[vKey] = values[vKey]; 351 | } 352 | } 353 | 354 | return this; 355 | } 356 | 357 | /** 358 | * Get attribute 359 | * @param key 360 | * @param value 361 | * @return {*} 362 | */ 363 | attr(key, value) { 364 | // Check if is get value 365 | if (typeof key === "string" && value === undefined) { 366 | return this.node().getAttribute(key); 367 | } 368 | 369 | let selectors = this.nodes(); 370 | let values = []; 371 | 372 | if (typeof key === 'string') { 373 | let val = {}; 374 | val[key] = value; 375 | values.push(val); 376 | } else { 377 | values = key; 378 | } 379 | 380 | for (let i = 0; i < selectors.length; i++) { 381 | for (let vKey in values) { 382 | selectors[i].setAttribute(vKey, values[vKey]); 383 | } 384 | } 385 | } 386 | 387 | /*** 388 | * Get/set html 389 | * @param value 390 | * @return * 391 | */ 392 | html(value) { 393 | if (value === undefined) { 394 | return this.node().innerHTML; 395 | } 396 | 397 | let selectors = this.nodes(); 398 | 399 | for (let i = 0; i < selectors.length; i++) { 400 | selectors[i].innerHTML = value; 401 | } 402 | 403 | return this; 404 | } 405 | 406 | /** 407 | * Has Class 408 | * @param name 409 | * @return {boolean} 410 | */ 411 | hasClass(name) { 412 | return this.node().classList.contains(name); 413 | } 414 | 415 | /** 416 | * Active status 417 | * @param status 418 | * @return {DPNode} 419 | */ 420 | active(status) { 421 | let selectors = this.nodes(); 422 | 423 | for (let i = 0; i < selectors.length; i++) { 424 | if (status) { 425 | selectors[i].classList.add('active'); 426 | } else if (selectors[i].classList.contains('active')) { 427 | selectors[i].classList.remove('active'); 428 | } 429 | } 430 | 431 | return this; 432 | } 433 | 434 | /** 435 | * Is active 436 | * @return {boolean} 437 | */ 438 | isActive() { 439 | return this.hasClass('active'); 440 | } 441 | 442 | /** 443 | * Events 444 | * @param name 445 | * @param call 446 | */ 447 | listen(key, call) { 448 | let keys = key.trim().replace(/\s/gi, ',').split(','); 449 | let selectors = this.nodes(); 450 | 451 | for (let i = 0; i < selectors.length; i++) { 452 | for (let j = 0; j < keys.length; j++) { 453 | selectors[i].addEventListener(keys[j], call); 454 | } 455 | } 456 | 457 | return this; 458 | } 459 | 460 | /** 461 | * Get value 462 | * @param value 463 | * @return {DPNode} 464 | */ 465 | val(value) { 466 | if (value === undefined) { 467 | return this.node().value; 468 | } 469 | 470 | let selectors = this.nodes(); 471 | 472 | for (let i = 0; i < selectors.length; i++) { 473 | selectors[i].value = value; 474 | } 475 | 476 | return this; 477 | } 478 | 479 | /** 480 | * Get offset 481 | * @return {{}} 482 | */ 483 | offset() { 484 | let bound = this.node().getBoundingClientRect(); 485 | 486 | return { 487 | left: bound.left, 488 | top: bound.top, 489 | right: bound.right, 490 | bottom: bound.bottom 491 | }; 492 | } 493 | 494 | /** 495 | * Has 496 | * @param selector 497 | * @return {boolean} 498 | */ 499 | has(selector) { 500 | return this.node().contains(selector); 501 | } 502 | 503 | /** 504 | * is 505 | * @param selector 506 | */ 507 | is(selector) { 508 | return this.node().isSameNode(selector); 509 | } 510 | 511 | /** 512 | * Closest 513 | * @param selector 514 | * @return {*|HTMLElementTagNameMap[keyof HTMLElementTagNameMap]|Element|SVGElementTagNameMap[keyof SVGElementTagNameMap]} 515 | */ 516 | closest(selector) { 517 | return new DPNode(this.node().closest(selector)); 518 | } 519 | 520 | /** 521 | * Append child 522 | * @param node 523 | * @return {DPNode} 524 | */ 525 | append(node) { 526 | let selectors = this.nodes(); 527 | 528 | for (let i = 0; i < selectors.length; i++) { 529 | selectors[i].appendChild(node); 530 | } 531 | 532 | return this; 533 | } 534 | 535 | /** 536 | * Text 537 | * @param value 538 | * @return {*} 539 | */ 540 | text(value) { 541 | if (value === undefined) { 542 | return this.node().textContent; 543 | } 544 | 545 | let selectors = this.nodes(); 546 | 547 | for (let i = 0; i < selectors.length; i++) { 548 | selectors[i].textContent = value; 549 | } 550 | 551 | return this; 552 | } 553 | } 554 | 555 | // ==================================================== 556 | // Class {DPConfig} 557 | // ==================================================== 558 | class DPConfig extends DPBase { 559 | /** 560 | * Constructor 561 | * @param config 562 | */ 563 | constructor(config) { 564 | super(); 565 | 566 | // Set default 567 | config.logo = this.or(config.logo, {}); 568 | config.size = this.or(config.size, {}); 569 | 570 | // Config for elements 571 | this.config = { 572 | elements: this.mergeElements(config), 573 | // Config for icon 574 | icons: this.mergeIcons(config), 575 | // Config default 576 | volume: this.or(config.volume, __dp.defaultConfig.volume), 577 | view: this.mergeView(config), 578 | sources: this.or(config.sources, __dp.defaultConfig.sources), 579 | logo: this.mergeLogo(config), 580 | size: this.mergeSize(config), 581 | largeScreen: this.or(config.largeScreen, __dp.defaultConfig.largeScreen), 582 | locale: this.or(config.locale, __dp.defaultConfig.locale), 583 | menu: this.mergeMenu(config), 584 | poster: this.or(config.poster, __dp.defaultConfig.poster), 585 | schedules: this.mergeSchedules(config), 586 | type: this.or(config.type, __dp.defaultConfig.type), // audio or video 587 | plugins: this.mergePlugins(config), 588 | startAt: this.or(config.startAt, __dp.defaultConfig.startAt), 589 | preview: this.or(config.preview, __dp.defaultConfig.preview) 590 | }; 591 | 592 | // Function 593 | 594 | // Init cache 595 | this.cache = { 596 | node: {}, 597 | config: {} 598 | }; 599 | } 600 | 601 | /** 602 | * Merge menu 603 | * @return {object} 604 | */ 605 | mergeMenu(config) { 606 | if (config.menu === false) { 607 | return false; 608 | } 609 | 610 | let rs = this.or(config.menu, __dp.defaultConfig.menu); 611 | 612 | rs.loop = this.or(rs.loop, { 613 | text: 'menu.loop', 614 | element: 'menuItemLoop', 615 | execute: function (item, menu, config) { 616 | menu.execLoop(item, config); 617 | } 618 | }); 619 | 620 | rs.copyUrl = this.or(rs.copyUrl, { 621 | text: 'menu.copy_url', 622 | element: 'menuItemCopyUrl', 623 | execute: function (item, menu, config) { 624 | menu.execCopyUrl(item, config); 625 | } 626 | }); 627 | 628 | return rs; 629 | } 630 | 631 | /** 632 | * Merge Elements 633 | * @return {object} 634 | */ 635 | mergeElements(config) { 636 | config.elements = this.or(config.elements, {}); 637 | 638 | return { 639 | object: this.or(config.elements.object, __dp.defaultConfig.elements.object), 640 | container: this.or(config.elements.container, __dp.defaultConfig.elements.container), 641 | video: this.or(config.elements.video, __dp.defaultConfig.elements.video), 642 | audio: this.or(config.elements.audio, __dp.defaultConfig.elements.audio), 643 | logo: this.or(config.elements.logo, __dp.defaultConfig.elements.logo), 644 | progress: this.or(config.elements.progress, __dp.defaultConfig.elements.progress), 645 | progressLoading: this.or(config.elements.progressLoading, __dp.defaultConfig.elements.progressLoading), 646 | progressPlaying: this.or(config.elements.progressPlaying, __dp.defaultConfig.elements.progressPlaying), 647 | progressHoverTooltipText: this.or(config.elements.progressHoverTooltipText, __dp.defaultConfig.elements.progressHoverTooltipText), 648 | progressHoverTooltipImage: this.or(config.elements.progressHoverTooltipImage, __dp.defaultConfig.elements.progressHoverTooltipImage), 649 | control: this.or(config.elements.control, __dp.defaultConfig.elements.control), 650 | button: this.or(config.elements.button, __dp.defaultConfig.elements.button), 651 | buttonIcon: this.or(config.elements.buttonIcon, __dp.defaultConfig.elements.buttonIcon), 652 | controlPlayPause: this.or(config.elements.controlPlayPause, __dp.defaultConfig.elements.controlPlayPause), 653 | controlFullScreen: this.or(config.elements.controlFullScreen, __dp.defaultConfig.elements.controlFullScreen), 654 | controlLargeScreen: this.or(config.elements.controlLargeScreen, __dp.defaultConfig.elements.controlLargeScreen), 655 | controlVolume: this.or(config.elements.controlVolume, __dp.defaultConfig.elements.controlVolume), 656 | controlVolumeTooltip: this.or(config.elements.controlVolumeTooltip, __dp.defaultConfig.elements.controlVolumeTooltip), 657 | controlVolumeRange: this.or(config.elements.controlVolumeRange, __dp.defaultConfig.elements.controlVolumeRange), 658 | controlTimer: this.or(config.elements.controlTimer, __dp.defaultConfig.elements.controlTimer), 659 | modal: this.or(config.elements.modal, __dp.defaultConfig.elements.modal), 660 | loaderModal: this.or(config.elements.loaderModal, __dp.defaultConfig.elements.loaderModal), 661 | loaderModalIcon: this.or(config.elements.loaderModalIcon, __dp.defaultConfig.elements.loaderModalIcon), 662 | playerModal: this.or(config.elements.playerModal, __dp.defaultConfig.elements.playerModal), 663 | playerModalIcon: this.or(config.elements.playerModalIcon, __dp.defaultConfig.elements.playerModalIcon), 664 | menu: this.or(config.elements.menu, __dp.defaultConfig.elements.menu), 665 | menuList: this.or(config.elements.menuList, __dp.defaultConfig.elements.menuList), 666 | menuItem: this.or(config.elements.menuItem, __dp.defaultConfig.elements.menuItem), 667 | menuItemLoop: this.or(config.elements.menuItemLoop, __dp.defaultConfig.elements.menuItemLoop), 668 | menuItemCopyUrl: this.or(config.elements.menuItemCopyUrl, __dp.defaultConfig.elements.menuItemCopyUrl), 669 | ads: this.or(config.elements.ads, __dp.defaultConfig.elements.ads), 670 | adsItem: this.or(config.elements.adsItem, __dp.defaultConfig.elements.adsItem), 671 | adsContent: this.or(config.elements.adsContent, __dp.defaultConfig.elements.adsContent), 672 | adsClose: this.or(config.elements.adsClose, __dp.defaultConfig.elements.adsClose), 673 | }; 674 | } 675 | 676 | /** 677 | * Merge Icons 678 | * @return {object} 679 | */ 680 | mergeIcons(config) { 681 | config.icons = this.or(config.icons, {}); 682 | 683 | return { 684 | loaderModal: this.or(config.icons.loaderModal, __dp.defaultConfig.icons.loaderModal), 685 | playerModal: this.or(config.icons.loaderModal, __dp.defaultConfig.icons.playerModal), 686 | fullScreen: this.or(config.icons.fullScreen, __dp.defaultConfig.icons.fullScreen), 687 | actualScreen: this.or(config.icons.actualScreen, __dp.defaultConfig.icons.actualScreen), 688 | largeScreen: this.or(config.icons.largeScreen, __dp.defaultConfig.icons.largeScreen), 689 | smallScreen: this.or(config.icons.smallScreen, __dp.defaultConfig.icons.smallScreen), 690 | pause: this.or(config.icons.pause, __dp.defaultConfig.icons.pause), 691 | play: this.or(config.icons.play, __dp.defaultConfig.icons.play), 692 | volumeMute: this.or(config.icons.volumeMute, __dp.defaultConfig.icons.volumeMute), 693 | volume1: this.or(config.icons.volume1, __dp.defaultConfig.icons.volume1), 694 | volume2: this.or(config.icons.volume2, __dp.defaultConfig.icons.volume2), 695 | volume3: this.or(config.icons.volume3, __dp.defaultConfig.icons.volume3), 696 | close: this.or(config.icons.close, __dp.defaultConfig.icons.close) 697 | }; 698 | } 699 | 700 | /** 701 | * Merge logo 702 | * @return {object} 703 | */ 704 | mergeLogo(config) { 705 | // Check if logo is false, its mean is not show 706 | if (config.logo === false) { 707 | return config.logo; 708 | } 709 | 710 | // Check if logo is undefined then get default value 711 | config.logo = this.or(config.logo, {}); 712 | 713 | let rs = {}; 714 | 715 | if (config.logo.height !== undefined) { 716 | rs.height = config.logo.height; 717 | 718 | if (config.logo.width !== undefined) { 719 | rs.width = config.logo.width; 720 | } else { 721 | rs.rate = this.or(config.logo.rate, __dp.defaultConfig.logo.rate); 722 | } 723 | } else if (config.logo.width !== undefined) { 724 | rs.width = config.logo.width; 725 | 726 | if (config.logo.height !== undefined) { 727 | rs.height = config.logo.height; 728 | } else { 729 | rs.rate = this.or(config.logo.rate, __dp.defaultConfig.logo.rate); 730 | } 731 | } else { 732 | rs.height = __dp.defaultConfig.logo.height; 733 | rs.rate = __dp.defaultConfig.logo.rate; 734 | } 735 | 736 | rs.url = this.or(config.logo.url, null); 737 | 738 | return rs; 739 | } 740 | 741 | /** 742 | * Merge size 743 | * @return {object} 744 | */ 745 | mergeSize(config) { 746 | config.size = this.or(config.size, {}); 747 | let rs = {}; 748 | 749 | if (config.size.height !== undefined) { 750 | rs.height = config.size.height; 751 | 752 | if (config.size.width !== undefined) { 753 | rs.width = config.size.width; 754 | } else { 755 | rs.rate = this.or(config.size.rate, __dp.defaultConfig.size.rate); 756 | } 757 | } else if (config.size.width !== undefined) { 758 | rs.width = config.size.width; 759 | 760 | if (config.size.height !== undefined) { 761 | rs.height = config.size.height; 762 | } else { 763 | rs.rate = this.or(config.size.rate, __dp.defaultConfig.size.rate); 764 | } 765 | } else { 766 | rs.width = __dp.defaultConfig.size.width; 767 | rs.rate = __dp.defaultConfig.size.rate; 768 | } 769 | 770 | return rs; 771 | } 772 | 773 | /** 774 | * Merge view 775 | * @return {object} 776 | */ 777 | mergeView(config) { 778 | if (config.view == false 779 | || config.view == undefined) { 780 | config.view = {}; 781 | } 782 | 783 | return { 784 | content: this.or(config.view.content, __dp.defaultConfig.view.content), 785 | import: this.or(config.view.import, __dp.defaultConfig.view.import) 786 | }; 787 | } 788 | 789 | /** 790 | * Merge schedules 791 | * @param config 792 | * @return {object} 793 | */ 794 | mergeSchedules(config) { 795 | if (!config.schedules) { 796 | return []; 797 | } 798 | 799 | let rs = this.or(config.schedules, __dp.defaultConfig.schedules); 800 | 801 | return rs; 802 | } 803 | 804 | /** 805 | * Merge plugins 806 | * @param config 807 | * @return {object} 808 | */ 809 | mergePlugins(config) { 810 | return this.or(config.plugins, __dp.defaultConfig.plugins); 811 | } 812 | 813 | /** 814 | * Access array 815 | * @param key 816 | * @return {*} 817 | */ 818 | access(key) { 819 | let config = this.config; 820 | let keys = key.split('.'); 821 | 822 | for (let i in keys) { 823 | if (config[keys[i]] === undefined) { 824 | config = undefined; 825 | break; 826 | } 827 | 828 | config = config[keys[i]]; 829 | } 830 | 831 | return config; 832 | } 833 | 834 | /** 835 | * Get config 836 | * @param key 837 | * @return mixed 838 | */ 839 | get(key, cache) { 840 | cache = cache !== undefined ? cache : true; 841 | 842 | // Get config cache 843 | if (!(this.cache.config[key] !== undefined && cache)) { 844 | this.cache.config[key] = this.access(key); 845 | } 846 | 847 | return this.cache.config[key]; 848 | } 849 | 850 | /** 851 | * Get node 852 | * @param key 853 | * @param cache 854 | * @return {*|undefined} 855 | */ 856 | el(key, cache){ 857 | cache = cache !== undefined ? cache : true; 858 | let config = this.get(key, cache); 859 | 860 | // Check if is object elements 861 | if (key === 'elements.object' && (this.cache.node[key] === undefined || !cache)) { 862 | this.cache.node[key] = new DPNode(config); 863 | } 864 | // Check get dom is true and dom is created 865 | // Then return dom in cache 866 | else if (typeof config === 'string') { 867 | if (this.cache.node[key] === undefined || !cache) { 868 | this.cache.node[key] = this.cache.node['elements.object'].find(config); 869 | } 870 | } 871 | 872 | return this.cache.node[key]; 873 | } 874 | 875 | /** 876 | * Get runner 877 | * @param isDom 878 | * @return {mixed} 879 | */ 880 | runner(isDom, cache) { 881 | let type = this.get('type'); 882 | 883 | if (isDom) { 884 | return this.el('elements.' + type, cache); 885 | } 886 | 887 | return this.get('elements.' + type, cache); 888 | } 889 | } 890 | 891 | // ==================================================== 892 | // Class {DPEvent} 893 | // ==================================================== 894 | class DPEvent extends DPBase { 895 | /** 896 | * constructor 897 | */ 898 | constructor(app) { 899 | super(); 900 | this.app = app; 901 | } 902 | 903 | /** 904 | * Init 905 | */ 906 | init() { 907 | this.events = {}; 908 | this.viewEvents() 909 | .logoEvents() 910 | .menuEvents() 911 | .controlEvents() 912 | .screenEvents() 913 | .modalEvents() 914 | .sourceEvents(); 915 | } 916 | 917 | /** 918 | * View events 919 | * @return {DPEvent} 920 | */ 921 | viewEvents() { 922 | let instance = this; 923 | 924 | this.events['dp.view.rendering'] = function (parameters) { 925 | return instance.createEvent('dp.view.rendering', parameters); 926 | }; 927 | 928 | this.events['dp.view.rendered'] = function (parameters) { 929 | return instance.createEvent('dp.view.rendered', parameters); 930 | }; 931 | 932 | return this; 933 | } 934 | 935 | /** 936 | * Logo events 937 | * @return {DPEvent} 938 | */ 939 | logoEvents() { 940 | let instance = this; 941 | 942 | this.events['dp.logo.resize'] = function (parameters) { 943 | return instance.createEvent('dp.logo.resize', parameters); 944 | }; 945 | 946 | return this; 947 | } 948 | 949 | /** 950 | * Menu events 951 | * @return {DPEvent} 952 | */ 953 | menuEvents() { 954 | let instance = this; 955 | 956 | this.events['dp.menu.open'] = function (parameters) { 957 | return instance.createEvent('dp.menu.open', parameters); 958 | }; 959 | 960 | this.events['dp.menu.close'] = function (parameters) { 961 | return instance.createEvent('dp.menu.close', parameters); 962 | }; 963 | 964 | return this; 965 | } 966 | 967 | /** 968 | * Control events 969 | * @return {DPEvent} 970 | */ 971 | controlEvents() { 972 | let instance = this; 973 | 974 | this.events['dp.control.show'] = function (parameters) { 975 | return instance.createEvent('dp.control.show', parameters); 976 | }; 977 | 978 | this.events['dp.control.hide'] = function (parameters) { 979 | return instance.createEvent('dp.control.hide', parameters); 980 | }; 981 | 982 | return this; 983 | } 984 | 985 | /** 986 | * Logo events 987 | * @return {DPEvent} 988 | */ 989 | modalEvents() { 990 | let instance = this; 991 | 992 | // Event for loader 993 | this.events['dp.modal.loader.show'] = function (parameters) { 994 | return instance.createEvent('dp.modal.loader.show', parameters); 995 | }; 996 | 997 | this.events['dp.modal.loader.hide'] = function (parameters) { 998 | return instance.createEvent('dp.modal.loader.hide', parameters); 999 | }; 1000 | 1001 | // Event for player 1002 | this.events['dp.modal.player.show'] = function (parameters) { 1003 | return instance.createEvent('dp.modal.player.show', parameters); 1004 | }; 1005 | 1006 | this.events['dp.modal.player.hide'] = function (parameters) { 1007 | return instance.createEvent('dp.modal.player.hide', parameters); 1008 | }; 1009 | 1010 | return this; 1011 | } 1012 | 1013 | /** 1014 | * Screen events 1015 | * @return {DPEvent} 1016 | */ 1017 | screenEvents() { 1018 | let instance = this; 1019 | 1020 | // Event for large screen 1021 | this.events['dp.screen.large.active'] = function (parameters) { 1022 | return [ 1023 | instance.createEvent('dp.screen.large.change', parameters), 1024 | instance.createEvent('dp.screen.large.active', parameters) 1025 | ]; 1026 | }; 1027 | 1028 | this.events['dp.screen.large.inactive'] = function (parameters) { 1029 | return [ 1030 | instance.createEvent('dp.screen.large.change', parameters), 1031 | instance.createEvent('dp.screen.large.inactive', parameters) 1032 | ]; 1033 | }; 1034 | 1035 | // Event for full screen 1036 | this.events['dp.screen.full.active'] = function (parameters) { 1037 | return [ 1038 | instance.createEvent('dp.screen.full.change', parameters), 1039 | instance.createEvent('dp.screen.full.active', parameters) 1040 | ]; 1041 | }; 1042 | 1043 | this.events['dp.screen.full.inactive'] = function (parameters) { 1044 | return [ 1045 | instance.createEvent('dp.screen.full.change', parameters), 1046 | instance.createEvent('dp.screen.full.inactive', parameters) 1047 | ]; 1048 | }; 1049 | 1050 | this.events['dp.screen.change'] = function (parameters) { 1051 | return instance.createEvent('dp.screen.change', parameters); 1052 | }; 1053 | 1054 | return this; 1055 | } 1056 | 1057 | /** 1058 | * sourceEvents 1059 | * @return {DPEvent} 1060 | */ 1061 | sourceEvents() { 1062 | let instance = this; 1063 | 1064 | this.events['dp.source.play'] = function (parameters) { 1065 | return instance.createEvent('dp.source.play', parameters); 1066 | }; 1067 | 1068 | this.events['dp.source.pause'] = function (parameters) { 1069 | return instance.createEvent('dp.source.pause', parameters); 1070 | }; 1071 | 1072 | this.events['dp.source.ended'] = function (parameters) { 1073 | return instance.createEvent('dp.source.ended', parameters); 1074 | }; 1075 | 1076 | return this; 1077 | } 1078 | 1079 | /** 1080 | * Create event 1081 | * @param name 1082 | * @param parameters 1083 | */ 1084 | createEvent(name, parameters) { 1085 | return new CustomEvent(name, parameters); 1086 | } 1087 | 1088 | /** 1089 | * Trigger event 1090 | * @param name 1091 | * @param parameters 1092 | */ 1093 | trigger(name, parameters) { 1094 | let events = null; 1095 | 1096 | if (this.events[name] !== undefined) { 1097 | events = this.events[name](this.or(parameters, {})); 1098 | } else { 1099 | events = this.createEvent(name, this.or(parameters, {})); 1100 | } 1101 | 1102 | let ob = this.app.config.el('elements.object'); 1103 | let dom = ob.node(); 1104 | 1105 | if (events instanceof Array) { 1106 | events.forEach(function (item, index) { 1107 | dom.dispatchEvent(item); 1108 | }); 1109 | } else { 1110 | dom.dispatchEvent(events); 1111 | } 1112 | 1113 | return this; 1114 | } 1115 | 1116 | /** 1117 | * Trigger event 1118 | * @param name 1119 | * @param parameters 1120 | */ 1121 | listen(name, call) { 1122 | let ob = this.app.config.el('elements.object'); 1123 | let dom = ob.node(); 1124 | 1125 | dom.addEventListener(name, call); 1126 | 1127 | return this; 1128 | } 1129 | } 1130 | 1131 | // ==================================================== 1132 | // Class {DPView} 1133 | // ==================================================== 1134 | class DPView extends DPBase { 1135 | /** 1136 | * Constructor 1137 | * @param config 1138 | */ 1139 | constructor(app) { 1140 | super(); 1141 | this.app = app; 1142 | } 1143 | 1144 | /** 1145 | * Init 1146 | * @return {DPView} 1147 | */ 1148 | init() { 1149 | return this; 1150 | } 1151 | 1152 | /** 1153 | * Render view 1154 | * @return {DPView} 1155 | */ 1156 | async render() { 1157 | let elObject = this.app.config.el('elements.object'); 1158 | let viewConfig = this.app.config.get('view'); 1159 | let posterUrl = this.app.config.get('poster'); 1160 | let sizeConfig = this.app.config.get('size'); 1161 | 1162 | this.app.event.trigger('dp.view.rendering'); 1163 | 1164 | // Render size 1165 | elObject.css({maxWidth: '100%'}); 1166 | 1167 | if (sizeConfig.height !== undefined) { 1168 | elObject.css({height: sizeConfig.height}); 1169 | 1170 | if (sizeConfig.width !== undefined) { 1171 | elObject.css({width: sizeConfig.width}); 1172 | } else { 1173 | elObject.css({width: (elObject.height() / sizeConfig.rate) + 'px'}); 1174 | } 1175 | } else { 1176 | elObject.css({width: sizeConfig.width}); 1177 | 1178 | if (sizeConfig.height !== undefined) { 1179 | elObject.css({height: sizeConfig.height}); 1180 | } else { 1181 | elObject.css({height: (elObject.width() * sizeConfig.rate) + 'px'}); 1182 | } 1183 | } 1184 | 1185 | // Read content in template 1186 | if (!viewConfig.content) { 1187 | if (viewConfig.import) { 1188 | elObject.html(this.app.translate.get('app.loading')); 1189 | let response = await this.loadTemplate(); 1190 | let content = this.replace(response); 1191 | elObject.html(content); 1192 | } 1193 | } else { 1194 | let content = this.replace(viewConfig.content); 1195 | elObject.html(content); 1196 | } 1197 | 1198 | // Render the poster for video 1199 | if (this.poster) { 1200 | let runner = this.app.config.runner(true); 1201 | runner.node().poster = posterUrl; 1202 | } 1203 | 1204 | this.app.event.trigger('dp.view.rendered'); 1205 | 1206 | return true; 1207 | } 1208 | 1209 | /** 1210 | * Load template 1211 | * @return {Promise} 1212 | */ 1213 | async loadTemplate() { 1214 | let viewConfig = this.app.config.get('view'); 1215 | 1216 | return new Promise(function (resolve, reject) { 1217 | let xhr = new XMLHttpRequest(); 1218 | xhr.open('GET', viewConfig.import); 1219 | xhr.onload = function () { 1220 | if (this.status >= 200 && this.status < 300) { 1221 | resolve(xhr.response); 1222 | } else { 1223 | reject({ 1224 | status: this.status, 1225 | statusText: xhr.statusText 1226 | }); 1227 | } 1228 | }; 1229 | xhr.onerror = function () { 1230 | reject({ 1231 | status: this.status, 1232 | statusText: xhr.statusText 1233 | }); 1234 | }; 1235 | xhr.send(); 1236 | }); 1237 | } 1238 | 1239 | /** 1240 | * replace 1241 | * @return string 1242 | */ 1243 | replace(content) { 1244 | return content; 1245 | } 1246 | } 1247 | 1248 | // ==================================================== 1249 | // Class {DPTranslator} 1250 | // ==================================================== 1251 | class DPTranslator extends DPBase { 1252 | /** 1253 | * Constructor 1254 | * @param config 1255 | */ 1256 | constructor(app) { 1257 | super(); 1258 | this.app = app; 1259 | 1260 | // Get local config 1261 | let locale = this.app.config.get('locale'); 1262 | this.languages = this.or(__dp.translateData[locale], {}); 1263 | } 1264 | 1265 | /** 1266 | * Get translate 1267 | * @param key 1268 | * @param attributes 1269 | * @return mixed 1270 | */ 1271 | get(key, attributes) { 1272 | if (attributes == undefined) { 1273 | attributes = {}; 1274 | } 1275 | 1276 | var keys = key.split('.'); 1277 | var messages = this.languages; 1278 | let message = messages; 1279 | 1280 | // Get message format 1281 | for (var i in keys) { 1282 | if (message[keys[i]] == undefined) { 1283 | return key; 1284 | } 1285 | 1286 | message = message[keys[i]]; 1287 | } 1288 | 1289 | // Get attribute in message format 1290 | for (var attrKey in attributes) { 1291 | if (messages[keys[0]].attributes == undefined) { 1292 | return message; 1293 | } 1294 | 1295 | if (messages[keys[0]].attributes[attrKey] == undefined) { 1296 | return message; 1297 | } 1298 | 1299 | var fields = messages[keys[0]].attributes[attrKey]; 1300 | var attr = (fields[attributes[attrKey]] != undefined ? fields[attributes[attrKey]] : attributes[attrKey]); 1301 | var regex = new RegExp(':' + attrKey, 'g'); 1302 | message = message.replace(regex, attr); 1303 | } 1304 | 1305 | return message; 1306 | } 1307 | } 1308 | 1309 | // ==================================================== 1310 | // Class {DPMenu} 1311 | // ==================================================== 1312 | class DPMenu extends DPBase { 1313 | /** 1314 | * Constructor 1315 | * @param config 1316 | */ 1317 | constructor(app) { 1318 | super(); 1319 | this.app = app; 1320 | } 1321 | 1322 | /** 1323 | * Render menu 1324 | * @param config 1325 | * @return {DPMenu} 1326 | */ 1327 | init() { 1328 | this.status = true; 1329 | 1330 | let menuList = this.app.config.get('menu'); 1331 | let elMenuList = this.app.config.el('elements.menuList'); 1332 | 1333 | if (menuList === false) { 1334 | this.status = false; 1335 | return this; 1336 | } 1337 | 1338 | let menuItemClass = this.app.config.get('elements.menuItem').replace('.', ''); 1339 | 1340 | for (var name in menuList) { 1341 | let div = document.createElement('div'); 1342 | div.classList.add(menuItemClass); 1343 | div.setAttribute('dp-menu:name', name); 1344 | div.innerHTML = this.app.translate.get(menuList[name].text); 1345 | elMenuList.append(div); 1346 | } 1347 | 1348 | this.events(); 1349 | 1350 | return this; 1351 | } 1352 | 1353 | /** 1354 | * Open menu 1355 | * @param config 1356 | * @return {DPMenu} 1357 | */ 1358 | openMenu(event) { 1359 | if (!this.status) { 1360 | return this; 1361 | } 1362 | 1363 | let elMenu = this.app.config.el('elements.menu'); 1364 | let elMenuList = this.app.config.el('elements.menuList'); 1365 | 1366 | elMenu.active(true); 1367 | 1368 | let height = elMenuList.height(); 1369 | let width = elMenuList.width(); 1370 | 1371 | let cHeight = window.innerHeight; 1372 | let cWidth = window.innerWidth; 1373 | 1374 | let left = event.clientX; 1375 | let top = event.clientY; 1376 | 1377 | if ((cHeight - top) < height) { 1378 | top = cHeight - height; 1379 | } 1380 | 1381 | if ((cWidth - left) < width) { 1382 | left = cWidth - width; 1383 | } 1384 | 1385 | elMenuList.css({left: left + 'px', top: top + 'px'}); 1386 | 1387 | this.app.event.trigger('dp.menu.open'); 1388 | 1389 | return this; 1390 | } 1391 | 1392 | /** 1393 | * Close menu 1394 | * @param config 1395 | * @return {DPMenu} 1396 | */ 1397 | closeMenu() { 1398 | let elMenu = this.app.config.el('elements.menu'); 1399 | 1400 | if (!this.status) { 1401 | return this; 1402 | } 1403 | 1404 | elMenu.active(false); 1405 | 1406 | this.app.event.trigger('dp.menu.close'); 1407 | 1408 | return this; 1409 | } 1410 | 1411 | /** 1412 | * Event menu 1413 | * @param config 1414 | * @return {DPMenu} 1415 | */ 1416 | events() { 1417 | let instance = this; 1418 | let elMenuList = this.app.config.el('elements.menuList'); 1419 | let elMenuItem = this.app.config.el('elements.menuItem'); 1420 | let elContainer = this.app.config.el('elements.container'); 1421 | 1422 | // Event when open context menu 1423 | elContainer.listen('contextmenu', function (e) { 1424 | if (instance.status) { 1425 | instance.openMenu(e); 1426 | } 1427 | 1428 | e.preventDefault(); 1429 | }); 1430 | 1431 | // Event when click out menu 1432 | __dp.node(window).listen('click', function (event) { 1433 | if (!elMenuList.has(event.target) 1434 | && !elMenuList.is(event.target)) { 1435 | instance.closeMenu(); 1436 | } 1437 | }); 1438 | 1439 | // Event when click menu item 1440 | elMenuItem.listen('click', function () { 1441 | let name = __dp.node(this).attr('dp-menu:name'); 1442 | instance.execute(this, name); 1443 | }); 1444 | 1445 | return this; 1446 | } 1447 | 1448 | /** 1449 | * execute 1450 | * @param name 1451 | * @return {DPMenu} 1452 | */ 1453 | execute(item, name) { 1454 | if (!this.status) { 1455 | return this; 1456 | } 1457 | 1458 | let config = this.app.config.get('menu.' + name); 1459 | 1460 | if (config.execute !== undefined) { 1461 | config.execute(item, this, config); 1462 | } 1463 | 1464 | return this; 1465 | } 1466 | 1467 | /** 1468 | * Exec Loop 1469 | * @return {DPMenu} 1470 | */ 1471 | execLoop(item, config) { 1472 | if (!this.status) { 1473 | return this; 1474 | } 1475 | 1476 | let elRunner = this.app.config.runner(true); 1477 | let runner = elRunner.node(); 1478 | 1479 | if (runner.loop) { 1480 | runner.loop = false; 1481 | __dp.node(item).active(false); 1482 | } else { 1483 | runner.loop = true; 1484 | __dp.node(item).active(true); 1485 | } 1486 | 1487 | this.closeMenu(); 1488 | 1489 | return this; 1490 | } 1491 | 1492 | /** 1493 | * Exec Copy Video Url 1494 | * @return {DPMenu} 1495 | */ 1496 | execCopyUrl(item, config) { 1497 | if (!this.status) { 1498 | return this; 1499 | } 1500 | 1501 | let elRunner = this.app.config.runner(true); 1502 | let runner = elRunner.node(); 1503 | 1504 | this.closeMenu(); 1505 | 1506 | return this; 1507 | } 1508 | } 1509 | 1510 | // ==================================================== 1511 | // Class {DPLogo} 1512 | // ==================================================== 1513 | class DPLogo extends DPBase { 1514 | /** 1515 | * Constructor 1516 | * @param config 1517 | */ 1518 | constructor(app) { 1519 | super(); 1520 | this.app = app; 1521 | } 1522 | 1523 | /** 1524 | * resizeLogo 1525 | * @return {DPLogo} 1526 | */ 1527 | resize() { 1528 | if (!this.status) { 1529 | return this; 1530 | } 1531 | 1532 | let elLogo = this.app.config.el('elements.logo'); 1533 | let logoConfig = this.app.config.get('logo'); 1534 | 1535 | if (logoConfig.height !== undefined) { 1536 | elLogo.css({height: logoConfig.height}); 1537 | 1538 | if (logoConfig.width !== undefined) { 1539 | elLogo.css({width: logoConfig.width}); 1540 | } else { 1541 | elLogo.css({width: (elLogo.height() / logoConfig.rate) + 'px'}); 1542 | } 1543 | } else { 1544 | elLogo.css({width: logoConfig.width}); 1545 | 1546 | if (logoConfig.height !== undefined) { 1547 | elLogo.css({height: logoConfig.height}); 1548 | } else { 1549 | elLogo.css({height: (elLogo.width() * logoConfig.rate) + 'px'}); 1550 | } 1551 | } 1552 | 1553 | this.app.event.trigger('dp.logo.resize'); 1554 | 1555 | return this; 1556 | } 1557 | 1558 | /** 1559 | * render 1560 | * @return {DPLogo} 1561 | */ 1562 | init() { 1563 | this.status = true; 1564 | 1565 | let elLogo = this.app.config.el('elements.logo'); 1566 | let logoConfig = this.app.config.get('logo'); 1567 | let instance = this; 1568 | 1569 | // Check if logo is hidden 1570 | if (logoConfig === false) { 1571 | this.status = false; 1572 | elLogo.active(false); 1573 | return this; 1574 | } 1575 | 1576 | elLogo.active(true); 1577 | elLogo.css({backgroundImage: 'url(\'' + logoConfig.url + '\')'}); 1578 | 1579 | // Event when screen change 1580 | this.app.event.listen('dp.screen.change', function () { 1581 | instance.resize(); 1582 | }); 1583 | 1584 | // Default 1585 | instance.resize(); 1586 | 1587 | return this; 1588 | } 1589 | } 1590 | 1591 | // ==================================================== 1592 | // Class {DPModal} 1593 | // ==================================================== 1594 | class DPModal extends DPBase { 1595 | /** 1596 | * Constructor 1597 | * @param config 1598 | */ 1599 | constructor(app) { 1600 | super(); 1601 | this.app = app; 1602 | } 1603 | 1604 | /** 1605 | * Render 1606 | */ 1607 | init() { 1608 | let instance = this; 1609 | let icons = this.app.config.get('icons'); 1610 | let elLoaderIcon = this.app.config.el('elements.loaderModalIcon'); 1611 | let elPlayerIcon = this.app.config.el('elements.playerModalIcon'); 1612 | let runner = this.app.config.runner(true); 1613 | 1614 | // default 1615 | elPlayerIcon.html(icons.playerModal); 1616 | elLoaderIcon.html(icons.loaderModal); 1617 | 1618 | this.toggle({loader: false, player: false}); 1619 | 1620 | // Event when start load data 1621 | runner.listen('loadstart', function (e) { 1622 | instance.toggle({loader: true, player: false}); 1623 | }); 1624 | 1625 | // Event when runner play 1626 | runner.listen('play', function () { 1627 | instance.toggle({loader: isNaN(runner.node().duration), player: false}); 1628 | }); 1629 | 1630 | // Event when runner pause or ended 1631 | runner.listen('pause ended', function () { 1632 | instance.toggle({loader: isNaN(runner.node().duration), player: true}); 1633 | }); 1634 | 1635 | // Event when timeupdate 1636 | runner.listen('timeupdate ', function (e) { 1637 | instance.toggle({loader: false, player: runner.node().paused}); 1638 | }); 1639 | 1640 | // Event when loaded data 1641 | // Then call display information on screen 1642 | runner.listen('loadeddata', function (e) { 1643 | instance.toggle({loader: false, player: runner.node().paused}); 1644 | }); 1645 | 1646 | // Event when loading 1647 | runner.listen('waiting', function () { 1648 | instance.toggle({loader: true, player: false}); 1649 | }); 1650 | 1651 | runner.listen('seeking', function () { 1652 | instance.toggle({loader: true, player: false}); 1653 | }); 1654 | 1655 | runner.listen('seeked', function () { 1656 | instance.toggle({loader: false, player: runner.node().paused}); 1657 | }); 1658 | 1659 | return this; 1660 | } 1661 | 1662 | /** 1663 | * Show 1664 | * @param config 1665 | */ 1666 | toggle(config) { 1667 | let elLoaderModal = this.app.config.el('elements.loaderModal'); 1668 | let elPlayerModal = this.app.config.el('elements.playerModal'); 1669 | let elModal = this.app.config.el('elements.modal'); 1670 | let isLoaderActive = elLoaderModal.isActive(); 1671 | let isPlayerActive = elPlayerModal.isActive(); 1672 | 1673 | elModal.active(false); 1674 | elLoaderModal.active(config.loader === true); 1675 | elPlayerModal.active(config.player === true); 1676 | 1677 | // Check event 1678 | if (elLoaderModal.isActive() !== isLoaderActive) { 1679 | !isLoaderActive ? this.app.event.trigger('dp.modal.loader.show') : this.app.event.trigger('dp.modal.loader.hide'); 1680 | } 1681 | 1682 | if (elPlayerModal.isActive() !== isPlayerActive) { 1683 | !isPlayerActive ? this.app.event.trigger('dp.modal.player.show') : this.app.event.trigger('dp.modal.player.hide'); 1684 | } 1685 | 1686 | return this; 1687 | } 1688 | } 1689 | 1690 | // ==================================================== 1691 | // Class {DPControl} 1692 | // ==================================================== 1693 | class DPControl extends DPBase { 1694 | constructor(app) { 1695 | super(); 1696 | this.app = app; 1697 | } 1698 | 1699 | /** 1700 | * Render 1701 | */ 1702 | init() { 1703 | this.isMouseIn = false; 1704 | this.controlTime = null; 1705 | 1706 | let elRunner = this.app.config.runner(true); 1707 | let instance = this; 1708 | let runnerDom = elRunner.node(); 1709 | 1710 | // Event when hover on runner/container/control 1711 | __dp.node(this.app.config.get('elements.container') 1712 | + ',' + this.app.config.get('elements.control') 1713 | + ',' + this.app.config.runner()).listen('mousemove', function () { 1714 | instance.openControl(); 1715 | instance.isMouseIn = true; 1716 | }); 1717 | 1718 | __dp.node(window).listen('scroll', function () { 1719 | instance.openControl(); 1720 | }); 1721 | 1722 | // Event when out on runner/container/control 1723 | __dp.node(this.app.config.get('elements.container') 1724 | + ',' + this.app.config.get('elements.control') 1725 | + ',' + this.app.config.runner()).listen('mouseleave', function () { 1726 | instance.closeControl(); 1727 | instance.isMouseIn = false; 1728 | }); 1729 | 1730 | // Event when runner pause or ended 1731 | elRunner.listen('pause ended', function () { 1732 | instance.openControl(); 1733 | }); 1734 | 1735 | // Event when runner pause or ended 1736 | elRunner.listen('play', function () { 1737 | if (!instance.isMouseIn) { 1738 | instance.closeControl(); 1739 | } 1740 | }); 1741 | 1742 | // Default 1743 | runnerDom.controls = false; 1744 | 1745 | // Set size for button 1746 | let buttonIcon = this.app.config.el('elements.buttonIcon'); 1747 | let btnH = buttonIcon.height(); 1748 | buttonIcon.width(btnH + 'px'); 1749 | 1750 | return this; 1751 | } 1752 | 1753 | /** 1754 | * Hidden 1755 | */ 1756 | closeControl() { 1757 | let elRunner = this.app.config.runner(true); 1758 | let elControl = this.app.config.el('elements.control'); 1759 | let elContainer = this.app.config.el('elements.container'); 1760 | 1761 | let runner = elRunner.node(); 1762 | 1763 | if (!runner.paused) { 1764 | elControl.active(false); 1765 | this.app.event.trigger('dp.control.hide'); 1766 | 1767 | if (this.isMouseIn) { 1768 | elContainer.node().style.cursor = "none"; 1769 | //elContainer.addClass('hidden-cursor'); 1770 | } else { 1771 | elContainer.node().style.cursor = "default"; 1772 | //elContainer.removeClass('hidden-cursor'); 1773 | } 1774 | } 1775 | } 1776 | 1777 | /** 1778 | * open 1779 | */ 1780 | openControl() { 1781 | let instance = this; 1782 | 1783 | let elControl = this.app.config.el('elements.control'); 1784 | let elContainer = this.app.config.el('elements.container'); 1785 | 1786 | window.clearTimeout(this.controlTime); 1787 | elControl.active(true); 1788 | elContainer.node().style.cursor = "default"; 1789 | // elContainer.removeClass('hidden-cursor'); 1790 | this.app.event.trigger('dp.control.show'); 1791 | 1792 | this.controlTime = window.setTimeout(function () { 1793 | instance.closeControl(); 1794 | }, 2000); 1795 | } 1796 | } 1797 | 1798 | // ==================================================== 1799 | // Class {DPScreen} 1800 | // ==================================================== 1801 | class DPScreen extends DPBase { 1802 | /** 1803 | * Constructor 1804 | * @param app 1805 | */ 1806 | constructor(app) { 1807 | super(); 1808 | this.app = app; 1809 | } 1810 | 1811 | /** 1812 | * Default screen 1813 | */ 1814 | defaultScreen() { 1815 | let sizeConfig = this.app.config.get('size'); 1816 | let elObject = this.app.config.el('elements.object'); 1817 | 1818 | if (sizeConfig.height !== undefined) { 1819 | elObject.css({height: sizeConfig.height}); 1820 | 1821 | if (sizeConfig.width !== undefined) { 1822 | elObject.css({width: sizeConfig.width}); 1823 | } else { 1824 | elObject.css({width: (elObject.height() / sizeConfig.rate) + 'px'}); 1825 | } 1826 | } else { 1827 | elObject.css({width: sizeConfig.width}); 1828 | 1829 | if (sizeConfig.height !== undefined) { 1830 | elObject.css({height: sizeConfig.height}); 1831 | } else { 1832 | elObject.css({height: (elObject.width() * sizeConfig.rate) + 'px'}); 1833 | } 1834 | } 1835 | 1836 | if (!this.defaultSize) { 1837 | this.defaultSize = { 1838 | width: elObject.width(), 1839 | height: elObject.height() 1840 | }; 1841 | } 1842 | 1843 | elObject.css({maxWidth: '100%'}); 1844 | this.rateScreenSize(); 1845 | 1846 | return this; 1847 | } 1848 | 1849 | /** 1850 | * Rate screen size 1851 | */ 1852 | rateScreenSize() { 1853 | let elObject = this.app.config.el('elements.object'); 1854 | let runnerSize = 0; 1855 | let h = 0; 1856 | 1857 | if (this.isLarge) { 1858 | runnerSize = elObject.parent().width(); 1859 | elObject.css({width: runnerSize + 'px'}) 1860 | 1861 | h = (runnerSize * this.defaultSize.height / this.defaultSize.width); 1862 | let windowH = __dp.node(window).height() * 85 / 100; 1863 | 1864 | if (h > windowH) { 1865 | h = windowH; 1866 | } 1867 | } else { 1868 | runnerSize = elObject.width(); 1869 | h = (runnerSize * this.defaultSize.height / this.defaultSize.width); 1870 | } 1871 | 1872 | elObject.css({height: h + 'px'}); 1873 | this.app.event.trigger('dp.screen.change'); 1874 | 1875 | return this; 1876 | } 1877 | 1878 | /** 1879 | * Make icon 1880 | * @param isFull 1881 | */ 1882 | makeIconForFullScreen(isFull) { 1883 | let icons = this.app.config.get('icons'); 1884 | let elBtnFullScreen = this.app.config.el('elements.controlFullScreen'); 1885 | 1886 | if (isFull === undefined) { 1887 | isFull = document.fullscreenElement 1888 | || document.mozFullScreenElement 1889 | || document.webkitFullscreenElement; 1890 | } 1891 | 1892 | if (isFull) { 1893 | elBtnFullScreen.html(icons.actualScreen); 1894 | } else { 1895 | elBtnFullScreen.html(icons.fullScreen); 1896 | } 1897 | 1898 | return this; 1899 | } 1900 | 1901 | /** 1902 | * Toggle 1903 | * @param event 1904 | */ 1905 | toggleFullScreen() { 1906 | let elContainer = this.app.config.el('elements.container'); 1907 | let isFullScreen = document.webkitIsFullScreen || document.mozFullScreen || false; 1908 | let container = elContainer.node(); 1909 | let instance = this; 1910 | 1911 | container.requestFullScreen = container.requestFullScreen || container.webkitRequestFullScreen || container.mozRequestFullScreen || function () { 1912 | return false; 1913 | }; 1914 | 1915 | document.cancelFullScreen = document.cancelFullScreen || document.webkitCancelFullScreen || document.mozCancelFullScreen || function () { 1916 | return false; 1917 | }; 1918 | 1919 | isFullScreen ? (function () { 1920 | instance.app.event.trigger('dp.screen.full.inactive'); 1921 | document.cancelFullScreen(); 1922 | })() : (function () { 1923 | instance.app.event.trigger('dp.screen.full.active'); 1924 | container.requestFullScreen(); 1925 | })(); 1926 | 1927 | return this; 1928 | } 1929 | 1930 | /** 1931 | * Make icon 1932 | * @param isFull 1933 | */ 1934 | makeIconForLargeScreen(isLg) { 1935 | let icons = this.app.config.get('icons'); 1936 | let elBtnLargeScreen = this.app.config.el('elements.controlLargeScreen'); 1937 | 1938 | if (isLg === undefined) { 1939 | isLg = this.isLarge; 1940 | } 1941 | 1942 | if (isLg) { 1943 | elBtnLargeScreen.html(icons.smallScreen); 1944 | } else { 1945 | elBtnLargeScreen.html(icons.largeScreen); 1946 | } 1947 | 1948 | return this; 1949 | } 1950 | 1951 | /** 1952 | * Toggle 1953 | * @param event 1954 | */ 1955 | toggleLargeScreen() { 1956 | if (this.isLarge) { 1957 | this.isLarge = false; 1958 | this.app.event.trigger('dp.screen.large.inactive'); 1959 | this.defaultScreen(); 1960 | } else { 1961 | this.isLarge = true; 1962 | this.app.event.trigger('dp.screen.large.active'); 1963 | this.rateScreenSize(); 1964 | } 1965 | 1966 | return this; 1967 | } 1968 | 1969 | /** 1970 | * Init 1971 | * @return {DPScreen} 1972 | */ 1973 | init() { 1974 | // Defined the common variable for object 1975 | this.isLarge = false; 1976 | this.defaultSize = null; 1977 | 1978 | let elBtnFullScreen = this.app.config.el('elements.controlFullScreen'); 1979 | let elBtnLargeScreen = this.app.config.el('elements.controlLargeScreen'); 1980 | let largeScreen = this.app.config.get('largeScreen'); 1981 | let instance = this; 1982 | 1983 | // Event when click on button fullscreen 1984 | // Then call to check full or cancel 1985 | elBtnFullScreen.listen('click', function (event) { 1986 | instance.toggleFullScreen(); 1987 | }); 1988 | 1989 | // Event when click on button large 1990 | // Then call to check large or cancel 1991 | elBtnLargeScreen.listen('click', function (event) { 1992 | instance.toggleLargeScreen(); 1993 | instance.makeIconForLargeScreen(); 1994 | }); 1995 | 1996 | // Event when change screen 1997 | // Then get status and change icon 1998 | __dp.node(document).listen("fullscreenchange webkitfullscreenchange mozfullscreenchange", function () { 1999 | instance.makeIconForFullScreen(); 2000 | }); 2001 | 2002 | // Event when window resize 2003 | __dp.node(window).listen('resize', function () { 2004 | instance.rateScreenSize(); 2005 | }); 2006 | 2007 | // Call when init screen 2008 | this.defaultScreen(); 2009 | this.makeIconForFullScreen(false); 2010 | 2011 | // Check if config is setting true large as default 2012 | if (largeScreen) { 2013 | instance.toggleLargeScreen(); 2014 | } 2015 | 2016 | this.makeIconForLargeScreen(); 2017 | 2018 | return this; 2019 | } 2020 | } 2021 | 2022 | // ==================================================== 2023 | // Class {DPSchedule} 2024 | // ==================================================== 2025 | class DPSchedule extends DPBase { 2026 | constructor(app) { 2027 | super(); 2028 | this.app = app; 2029 | } 2030 | 2031 | /** 2032 | * Run 2033 | */ 2034 | init() { 2035 | // Common variable 2036 | this.helper = this.app.helper; 2037 | this.schedules = {}; 2038 | this.alias = {}; 2039 | this.lastTime = null; 2040 | 2041 | let schedules = this.app.config.get('schedules'); 2042 | let instance = this; 2043 | let runner = this.app.config.runner(true); 2044 | let runnerDom = runner.node(); 2045 | 2046 | for (var i in schedules) { 2047 | // Add schedule to progress bar 2048 | if (this.schedules[schedules[i].at] === undefined) { 2049 | this.schedules[schedules[i].at] = []; 2050 | } 2051 | 2052 | schedules[i].name = schedules[i].name || Math.random().toString(36).substring(10); 2053 | this.alias[schedules[i].name] = schedules[i]; 2054 | this.schedules[schedules[i].at].push(schedules[i]); 2055 | } 2056 | 2057 | // Event when timeupdate 2058 | runner.listen('timeupdate ', function (e) { 2059 | let current = runnerDom.currentTime; 2060 | let time = __dp.parseTime(current); 2061 | 2062 | if (this.lastTime === time) { 2063 | return; 2064 | } 2065 | 2066 | this.lastTime = time; 2067 | 2068 | let list = instance.or(instance.schedules[time], []); 2069 | 2070 | for (let i in list) { 2071 | instance.execute(list[i].name); 2072 | 2073 | if (list[i].loop !== true) { 2074 | delete instance.schedules[time][i]; 2075 | } 2076 | } 2077 | }); 2078 | } 2079 | 2080 | /** 2081 | * Execute schedule 2082 | * @param name 2083 | */ 2084 | execute(name) { 2085 | let schedule = this.alias[name]; 2086 | schedule.execute(this.app); 2087 | } 2088 | } 2089 | 2090 | // ==================================================== 2091 | // Class {DPPlugin} 2092 | // ==================================================== 2093 | class DPPlugin extends DPBase { 2094 | constructor(app) { 2095 | super(); 2096 | this.app = app; 2097 | } 2098 | 2099 | /** 2100 | * Init 2101 | * @return {Promise} 2102 | */ 2103 | async init() { 2104 | let list = this.app.config.get('plugins'); 2105 | 2106 | for (let name in list) { 2107 | this.app[name] = await eval('new ' + list[name].className + '(this.app)'); 2108 | this.app[name].init(); 2109 | } 2110 | 2111 | return this; 2112 | } 2113 | } 2114 | 2115 | // ==================================================== 2116 | // Class {DPSource} 2117 | // ==================================================== 2118 | class DPSource extends DPBase { 2119 | /** 2120 | * Constructor 2121 | */ 2122 | constructor(app) { 2123 | super(); 2124 | this.app = app; 2125 | } 2126 | 2127 | /** 2128 | * Load 2129 | * @param sources 2130 | */ 2131 | load(sources) { 2132 | if (this.app.rendered && sources !== undefined) { 2133 | let runner = this.app.config.runner(true); 2134 | 2135 | runner.html(this.app.translate.get('app.not_support')); 2136 | 2137 | // Generate video from resources 2138 | if (typeof sources === 'string') { 2139 | runner.node().src = sources; 2140 | } else if (sources.length == 1) { 2141 | runner.node().src = sources[0].src; 2142 | } else { 2143 | for (var i in sources) { 2144 | let source = document.createElement('source'); 2145 | __dp.node(source).attr({src: sources[i].src, type: sources[i].type}); 2146 | runner.append(source); 2147 | } 2148 | } 2149 | 2150 | runner.node().load(); 2151 | } 2152 | 2153 | return this; 2154 | } 2155 | 2156 | /** 2157 | * Play 2158 | * @return {DPSource} 2159 | */ 2160 | play() { 2161 | if (this.app.rendered) { 2162 | let runner = this.app.config.runner(true).node(); 2163 | runner.play(); 2164 | } 2165 | 2166 | return this; 2167 | } 2168 | 2169 | /** 2170 | * Pause 2171 | * @return {DPSource} 2172 | */ 2173 | pause() { 2174 | if (this.app.rendered) { 2175 | let runner = this.app.config.runner(true).node(); 2176 | runner.pause(); 2177 | } 2178 | 2179 | return this; 2180 | } 2181 | 2182 | /** 2183 | * Start At 2184 | * @param time 2185 | * @return {DPSource} 2186 | */ 2187 | to(time) { 2188 | let runner = this.app.config.runner(true).node(); 2189 | 2190 | if (isNaN(time)) { 2191 | time = time.split(':'); 2192 | 2193 | if (time.length === 3) { 2194 | time = time[2] * 1 + time[1] * 60 + time[0] * 3600; 2195 | } else if (time.length === 2) { 2196 | time = time[1] * 1 + time[0] * 60; 2197 | } else { 2198 | time = time[0] * 1; 2199 | } 2200 | } 2201 | 2202 | runner.currentTime = time; 2203 | 2204 | return this; 2205 | } 2206 | 2207 | /** 2208 | * Init 2209 | * @return {DPSource} 2210 | */ 2211 | init() { 2212 | // Get list of source 2213 | let sources = this.app.config.get('sources'); 2214 | let runner = this.app.config.runner(true); 2215 | let event = this.app.event; 2216 | let startAt = this.app.config.get('startAt'); 2217 | 2218 | this.load(sources); 2219 | 2220 | // Event when video play 2221 | // Event when runner play 2222 | runner.listen('play', function () { 2223 | event.trigger('dp.source.play'); 2224 | }); 2225 | 2226 | // Event when runner pause or ended 2227 | runner.listen('pause', function () { 2228 | event.trigger('dp.source.pause'); 2229 | }); 2230 | 2231 | // Event when runner pause or ended 2232 | runner.listen('ended', function () { 2233 | event.trigger('dp.source.ended'); 2234 | }); 2235 | 2236 | // Start 2237 | this.to(startAt); 2238 | 2239 | return this; 2240 | } 2241 | } 2242 | 2243 | // ==================================================== 2244 | // Class {DilationPlayer} 2245 | // ==================================================== 2246 | class DilationPlayer extends DPBase { 2247 | /** 2248 | * Constructor 2249 | * @param config 2250 | */ 2251 | constructor(object, config) { 2252 | super(); 2253 | 2254 | if (config == undefined) { 2255 | config = {}; 2256 | } 2257 | 2258 | config.elements = this.or(config.elements, {}); 2259 | config.elements.object = object; 2260 | 2261 | this.rendered = false; 2262 | this.config = new DPConfig(config); 2263 | this.event = new DPEvent(this); 2264 | this.contextEvent(); 2265 | 2266 | this.translate = new DPTranslator(this); 2267 | this.view = new DPView(this); 2268 | 2269 | this.source = new DPSource(this); 2270 | this.control = new DPControl(this); 2271 | this.screen = new DPScreen(this); 2272 | this.menu = new DPMenu(this); 2273 | this.logo = new DPLogo(this); 2274 | this.modal = new DPModal(this); 2275 | this.plugin = new DPPlugin(this); 2276 | this.schedule = new DPSchedule(this); 2277 | 2278 | this.apply(); 2279 | } 2280 | 2281 | /** 2282 | * Apply 2283 | */ 2284 | async apply() { 2285 | await this.render(); 2286 | 2287 | // Regist events 2288 | this.contextSource() 2289 | .contextModal() 2290 | .contextLogo() 2291 | .contextControl() 2292 | .contextScreen() 2293 | .playPause() 2294 | .progress() 2295 | .sound() 2296 | .contextMenu() 2297 | .contextPlugin() 2298 | .contextSchedule(); 2299 | } 2300 | 2301 | /** 2302 | * Render view 2303 | * @return {Promise} 2304 | */ 2305 | async render() { 2306 | let rendered = await this.view.init().render(); 2307 | this.rendered = rendered; 2308 | 2309 | return rendered; 2310 | } 2311 | 2312 | /** 2313 | * Toggle play pause 2314 | * @return {DilationPlayer} 2315 | */ 2316 | playPause() { 2317 | // Defined elements 2318 | let runner = this.config.runner(true); 2319 | let player = this.config.el('elements.playerModal'); 2320 | let btn = this.config.el('elements.controlPlayPause'); 2321 | let icons = this.config.get('icons'); 2322 | let runnerDom = runner.node(); 2323 | let instance = this; 2324 | 2325 | /** 2326 | * Helper 2327 | * @type {{toggle: toggle, makeIcon: makeIcon}} 2328 | */ 2329 | let helper = { 2330 | /** 2331 | * Toggle play or pause 2332 | */ 2333 | toggle: function () { 2334 | if (!isNaN(runnerDom.duration)) { 2335 | if (runnerDom.paused) { 2336 | runnerDom.play(); 2337 | } else { 2338 | runnerDom.pause(); 2339 | } 2340 | } 2341 | }, 2342 | 2343 | /** 2344 | * Make icon 2345 | */ 2346 | makeIcon: function () { 2347 | if (runnerDom.paused) { 2348 | btn.html(icons.play); 2349 | } else { 2350 | btn.html(icons.pause); 2351 | } 2352 | } 2353 | }; 2354 | 2355 | // Event when loader show/hide 2356 | this.event.listen('dp.modal.loader.show', function(){ 2357 | btn.html(icons.play); 2358 | }); 2359 | 2360 | this.event.listen('dp.modal.loader.hide', function(){ 2361 | helper.makeIcon(); 2362 | }); 2363 | 2364 | // Event when click on button play/pause 2365 | btn.listen('click', function () { 2366 | helper.toggle(); 2367 | }); 2368 | 2369 | player.listen('click', function () { 2370 | helper.toggle(); 2371 | }); 2372 | 2373 | // Event when click on runner 2374 | runner.listen('click', function () { 2375 | helper.toggle(); 2376 | }); 2377 | 2378 | // Event when runner play 2379 | runner.listen('play', function () { 2380 | helper.makeIcon(); 2381 | }); 2382 | 2383 | // Event when runner pause or ended 2384 | runner.listen('pause ended', function () { 2385 | helper.makeIcon(); 2386 | }); 2387 | 2388 | // Init display icon in button play/pause 2389 | helper.makeIcon(); 2390 | 2391 | return this; 2392 | } 2393 | 2394 | /** 2395 | * Progress 2396 | * @return {DilationPlayer} 2397 | */ 2398 | progress() { 2399 | let instance = this; 2400 | let runner = this.config.runner(true); 2401 | let runnerDom = runner.node(); 2402 | let progressBar = this.config.el('elements.progress'); 2403 | let playing = this.config.el('elements.progressPlaying'); 2404 | let timer = this.config.el('elements.controlTimer'); 2405 | let progressTimerTooltipText = this.config.el('elements.progressHoverTooltipText'); 2406 | let progressTimerTooltipImage = this.config.el('elements.progressHoverTooltipImage'); 2407 | let tooltipCanvas = progressTimerTooltipImage.find('canvas').node(); 2408 | tooltipCanvas.width = 90; 2409 | tooltipCanvas.height = 70; 2410 | 2411 | // Create preview elements 2412 | // let runnerPreview = document.createElement('video'); 2413 | 2414 | // runner.find('source').each(function (num, val) { 2415 | // var source = document.createElement('source'); 2416 | // source.src = __dp.node(this).attr('src'); 2417 | // runnerPreview.append(source); 2418 | // }); 2419 | 2420 | // runnerPreview.load(); 2421 | 2422 | /** 2423 | * Helper object 2424 | * @type {{pad: (function(*, *, *=): *), setLoaded: setLoaded, setTimer: setTimer, display: display}} 2425 | */ 2426 | let helper = { 2427 | isShowImage: this.config.get('preview'), 2428 | 2429 | /** 2430 | * Set loaded data 2431 | * @param current 2432 | * @param duration 2433 | */ 2434 | setLoaded: function (current, duration) { 2435 | playing.width((current / duration * 100) + '%'); 2436 | }, 2437 | 2438 | /** 2439 | * Set timer 2440 | * @param current 2441 | * @param duration 2442 | */ 2443 | setTimer: function (current, duration) { 2444 | current = __dp.parseTime(current); 2445 | duration = __dp.parseTime(duration); 2446 | timer.html(current + ' / ' + duration); 2447 | }, 2448 | 2449 | showImage: function(left){ 2450 | if (this.isShowImage !== false && this.isShowImage !== undefined) { 2451 | let totalWidth = progressBar.width(); 2452 | let width = progressTimerTooltipImage.width() / 2; 2453 | let iLeft = left; 2454 | if (left > (totalWidth - width)) { 2455 | iLeft = totalWidth - width; 2456 | } else if (left < width) { 2457 | iLeft = width; 2458 | } 2459 | 2460 | progressTimerTooltipImage.css('left', iLeft + 'px'); 2461 | progressTimerTooltipImage.active(true); 2462 | } else { 2463 | progressTimerTooltipImage.active(false); 2464 | } 2465 | }, 2466 | 2467 | showTime: function(left, time) { 2468 | progressTimerTooltipText.active(true); 2469 | let totalWidth = progressBar.width(); 2470 | let width = progressTimerTooltipText.width() / 2; 2471 | let tLeft = left; 2472 | 2473 | if (left > (totalWidth - width - 2)) { 2474 | tLeft = totalWidth - width - 2; 2475 | } else if (left < (width + 2)) { 2476 | tLeft = width + 2; 2477 | } 2478 | 2479 | let parseTime = __dp.parseTime(time); 2480 | progressTimerTooltipText.css('left', tLeft + 'px').text(parseTime); 2481 | }, 2482 | 2483 | /** 2484 | * Display 2485 | */ 2486 | display: function () { 2487 | if (!isNaN(runnerDom.duration)) { 2488 | let current = runnerDom.currentTime; 2489 | let duration = runnerDom.duration; 2490 | 2491 | helper.setLoaded(current, duration); 2492 | helper.setTimer(current, duration); 2493 | } 2494 | } 2495 | }; 2496 | 2497 | // Event when timeupdate 2498 | runner.listen('timeupdate ', function (e) { 2499 | helper.display(); 2500 | }); 2501 | 2502 | // Event when click on progress bar 2503 | // Then get position of mouse and count the time go to 2504 | progressBar.listen("click", function (e) { 2505 | if (!isNaN(runnerDom.duration)) { 2506 | let offset = __dp.node(this).offset(); 2507 | let left = (e.pageX - offset.left); 2508 | let totalWidth = progressBar.width(); 2509 | let percentage = (left / totalWidth); 2510 | let vidTime = runnerDom.duration * percentage; 2511 | instance.source.to(vidTime); 2512 | helper.setLoaded(left, totalWidth); 2513 | } 2514 | }); 2515 | 2516 | // Event when move on progress 2517 | // Then get position of mouse, count the time go to and get information 2518 | progressBar.listen("mousemove", function (e) { 2519 | if (!isNaN(runnerDom.duration)) { 2520 | let offset = __dp.node(this).offset(); 2521 | let left = (e.pageX - offset.left); 2522 | let totalWidth = progressBar.width(); 2523 | let percentage = (left / totalWidth); 2524 | let current = runnerDom.duration * percentage; 2525 | 2526 | // Set position for image 2527 | helper.showImage(left, current); 2528 | helper.showTime(left, current); 2529 | } else { 2530 | progressTimerTooltipText.active(false); 2531 | progressTimerTooltipImage.active(false); 2532 | } 2533 | }); 2534 | 2535 | // Event when loaded data 2536 | // Then call display information on screen 2537 | runner.listen('loadeddata', function (e) { 2538 | helper.display(); 2539 | }); 2540 | 2541 | return this; 2542 | } 2543 | 2544 | /** 2545 | * Sound 2546 | * @return {DilationPlayer} 2547 | */ 2548 | sound() { 2549 | // Defined elements 2550 | let runner = this.config.runner(true); 2551 | let runnerDom = runner.node(); 2552 | let volume = this.config.el('elements.controlVolume'); 2553 | let volumeRange = this.config.el('elements.controlVolumeRange'); 2554 | let range = this.config.get('volume'); 2555 | let icons = this.config.get('icons'); 2556 | // let instance = this; 2557 | 2558 | /** 2559 | * Helper 2560 | * @type {{makeIcon: makeIcon, setVolume: setVolume, toggleMute: toggleMute}} 2561 | */ 2562 | let helper = { 2563 | /** 2564 | * Make icon for button 2565 | */ 2566 | makeIcon: function () { 2567 | if (runnerDom.muted == true || runnerDom.volume == 0) { 2568 | volume.html(icons.volumeMute); 2569 | } else if (runnerDom.volume <= 0.5) { 2570 | volume.html(icons.volume1); 2571 | } else { 2572 | volume.html(icons.volume2); 2573 | } 2574 | }, 2575 | 2576 | /** 2577 | * Set volume for runner 2578 | * @param number 2579 | */ 2580 | setVolume: function (number) { 2581 | runnerDom.volume = number / 100; 2582 | 2583 | if (runnerDom.volume > 0) { 2584 | runnerDom.muted = false; 2585 | } 2586 | }, 2587 | 2588 | /** 2589 | * Toggle mute runner 2590 | */ 2591 | toggleMute: function () { 2592 | if (runnerDom.muted == true) { 2593 | runnerDom.muted = false; 2594 | } else if (runnerDom.volume > 0) { 2595 | runnerDom.muted = true; 2596 | } 2597 | } 2598 | }; 2599 | 2600 | 2601 | // Event click on button 2602 | volume.listen('click', function () { 2603 | helper.toggleMute(); 2604 | }); 2605 | 2606 | // Event when change input of range 2607 | // Then call change volume and icon 2608 | volumeRange.listen('change', function () { 2609 | let range = __dp.node(this).val(); 2610 | helper.setVolume(range); 2611 | }); 2612 | 2613 | // Event when volume change 2614 | runner.listen('volumechange', function () { 2615 | helper.makeIcon(); 2616 | }); 2617 | 2618 | // Set volume default 2619 | helper.setVolume(range); 2620 | volumeRange.val(range); 2621 | helper.makeIcon(); 2622 | 2623 | return this; 2624 | } 2625 | 2626 | /** 2627 | * Logo 2628 | * return {DilationPlayer} 2629 | */ 2630 | contextLogo() { 2631 | this.logo.init(); 2632 | return this; 2633 | } 2634 | 2635 | /** 2636 | * Toggle control 2637 | * @return {DilationPlayer} 2638 | */ 2639 | contextControl() { 2640 | this.control.init(); 2641 | return this; 2642 | } 2643 | 2644 | /** 2645 | * Context modal 2646 | * @return {DilationPlayer} 2647 | */ 2648 | contextModal() { 2649 | this.modal.init(); 2650 | 2651 | return this; 2652 | } 2653 | 2654 | /** 2655 | * Menu 2656 | * @return {DilationPlayer} 2657 | */ 2658 | contextMenu() { 2659 | this.menu.init(); 2660 | return this; 2661 | } 2662 | 2663 | /** 2664 | * Alarm 2665 | * @return {DilationPlayer} 2666 | */ 2667 | contextSchedule() { 2668 | this.schedule.init(); 2669 | return this; 2670 | } 2671 | 2672 | /** 2673 | * Plugin 2674 | * @return {DilationPlayer} 2675 | */ 2676 | contextPlugin() { 2677 | this.plugin.init(); 2678 | return this; 2679 | } 2680 | 2681 | /** 2682 | * Event 2683 | * @return {DilationPlayer} 2684 | */ 2685 | contextEvent() { 2686 | this.event.init(); 2687 | return this; 2688 | } 2689 | 2690 | /** 2691 | * Screen 2692 | * @return {DilationPlayer} 2693 | */ 2694 | contextScreen() { 2695 | this.screen.init(); 2696 | return this; 2697 | } 2698 | 2699 | /** 2700 | * Source 2701 | * @return {DilationPlayer} 2702 | */ 2703 | contextSource() { 2704 | this.source.init(); 2705 | return this; 2706 | } 2707 | } --------------------------------------------------------------------------------