mirror of
				https://github.com/videojs/video.js.git
				synced 2025-10-31 00:08:01 +02:00 
			
		
		
		
	feat: Add useSVGIcons option (#8260)
This commit is contained in:
		| @@ -143,7 +143,7 @@ Video.js is [licensed][license] under the Apache License, Version 2.0. | ||||
|  | ||||
| [npm-link]: https://nodei.co/npm/video.js/ | ||||
|  | ||||
| [options]: docs/guides/options.md | ||||
| [options]: https://videojs.com/guides/options/ | ||||
|  | ||||
| [plugins]: https://videojs.com/plugins/ | ||||
|  | ||||
|   | ||||
| @@ -22,6 +22,9 @@ sh.rm('-rf', deployDir); | ||||
| // make sure the directory exists | ||||
| sh.mkdir('-p', deployDir); | ||||
|  | ||||
| // create sub-directory for images | ||||
| sh.mkdir('-p', `${deployDir}/src`); | ||||
|  | ||||
| // create nested directories | ||||
| files | ||||
|   .map((file) => path.dirname(file)) | ||||
| @@ -29,7 +32,7 @@ files | ||||
|  | ||||
| // copy files/folders to deploy dir | ||||
| files | ||||
|   .concat('dist', 'index.html', 'sandbox', 'docs') | ||||
|   .concat('dist', 'index.html', 'sandbox', 'docs', 'src/images') | ||||
|   .forEach((file) => sh.cp('-r', file, path.join(deployDir, file))); | ||||
|  | ||||
| sh.rm(path.join(deployDir, 'dist', `video-js-${pkg.version}.zip`)); | ||||
|   | ||||
| @@ -14,6 +14,8 @@ | ||||
|     <li><a href="sandbox/responsive.html">Responsive Demo</a></li> | ||||
|     <li><a href="sandbox/middleware-play.html">Middleware Play Demo</a></li> | ||||
|     <li><a href="sandbox/icons.html">Icons Demo</a></li> | ||||
|     <li><a href="sandbox/svg-icons.html">SVG Icons Directory</a></li> | ||||
|     <li><a href="sandbox/svg-icons-enabled.html">SVG Icons Demo</a></li> | ||||
|     <li><a href="sandbox/focus-visible.html">Focus Visible Demo</a></li> | ||||
|     <li><a href="sandbox/embeds.html">Embeds Demo</a></li> | ||||
|     <li><a href="sandbox/descriptions.html">Descriptions Demo</a></li> | ||||
|   | ||||
							
								
								
									
										750
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										750
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -104,6 +104,7 @@ | ||||
|     "@babel/core": "^7.9.0", | ||||
|     "@babel/plugin-transform-runtime": "^7.9.0", | ||||
|     "@babel/preset-env": "^7.9.0", | ||||
|     "@rollup/plugin-image": "^3.0.2", | ||||
|     "@rollup/plugin-replace": "^2.4.1", | ||||
|     "@types/node": "^18.8.3", | ||||
|     "access-sniff": "^3.2.0", | ||||
| @@ -155,6 +156,7 @@ | ||||
|     "rollup-plugin-node-resolve": "^4.2.4", | ||||
|     "rollup-plugin-progress": "^1.1.2", | ||||
|     "rollup-plugin-stub": "^1.2.0", | ||||
|     "rollup-plugin-svg": "^2.0.0", | ||||
|     "sass": "^1.34.0", | ||||
|     "semver": "^5.7.0", | ||||
|     "shelljs": "^0.8.5", | ||||
|   | ||||
| @@ -13,8 +13,10 @@ import multiEntry from 'rollup-plugin-multi-entry'; | ||||
| import stub from 'rollup-plugin-stub'; | ||||
| import isCI from 'is-ci'; | ||||
| import replace from '@rollup/plugin-replace'; | ||||
| import image from '@rollup/plugin-image'; | ||||
| import istanbul from 'rollup-plugin-istanbul'; | ||||
| import externalGlobals from 'rollup-plugin-external-globals'; | ||||
| import svg from 'rollup-plugin-svg'; | ||||
|  | ||||
| const excludeCoverage = [ | ||||
|   'test/**', | ||||
| @@ -151,6 +153,7 @@ export default cliargs => [ | ||||
|       primedExternalGlobals, | ||||
|       primedCjs, | ||||
|       primedBabel, | ||||
|       svg(), | ||||
|       cliargs.progress !== false ? progress() : {} | ||||
|     ], | ||||
|     onwarn, | ||||
| @@ -176,6 +179,7 @@ export default cliargs => [ | ||||
|       primedExternalGlobals, | ||||
|       primedCjs, | ||||
|       primedBabel, | ||||
|       svg(), | ||||
|       cliargs.progress !== false ? progress() : {} | ||||
|     ], | ||||
|     onwarn, | ||||
| @@ -201,6 +205,7 @@ export default cliargs => [ | ||||
|       primedCjs, | ||||
|       CI_TEST_TYPE === 'coverage' ? istanbul({exclude: excludeCoverage}) : {}, | ||||
|       primedBabel, | ||||
|       image(), | ||||
|       cliargs.progress !== false ? progress() : {} | ||||
|  | ||||
|     ], | ||||
| @@ -238,6 +243,7 @@ export default cliargs => [ | ||||
|       }), | ||||
|       json(), | ||||
|       primedBabel, | ||||
|       svg(), | ||||
|       cliargs.progress !== false ? progress() : {} | ||||
|     ], | ||||
|     onwarn, | ||||
| @@ -264,6 +270,7 @@ export default cliargs => [ | ||||
|       primedExternalGlobals, | ||||
|       primedCjs, | ||||
|       primedBabel, | ||||
|       svg(), | ||||
|       cliargs.progress !== false ? progress() : {} | ||||
|     ], | ||||
|     onwarn, | ||||
| @@ -289,6 +296,7 @@ export default cliargs => [ | ||||
|     plugins: [ | ||||
|       json(), | ||||
|       primedBabel, | ||||
|       svg(), | ||||
|       cliargs.progress !== false ? progress() : {} | ||||
|     ], | ||||
|     onwarn, | ||||
| @@ -311,6 +319,7 @@ export default cliargs => [ | ||||
|       primedExternalGlobals, | ||||
|       primedCjs, | ||||
|       primedBabel, | ||||
|       svg(), | ||||
|       cliargs.progress !== false ? progress() : {} | ||||
|     ], | ||||
|     onwarn, | ||||
| @@ -334,6 +343,7 @@ export default cliargs => [ | ||||
|       primedExternalGlobals, | ||||
|       primedCjs, | ||||
|       primedBabel, | ||||
|       svg(), | ||||
|       cliargs.progress !== false ? progress() : {} | ||||
|     ], | ||||
|     onwarn, | ||||
|   | ||||
							
								
								
									
										36
									
								
								sandbox/svg-icons-enabled.html.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								sandbox/svg-icons-enabled.html.example
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <meta charset="utf-8" /> | ||||
|   <title>Video.js Sandbox</title> | ||||
|   <link href="../dist/video-js.css" rel="stylesheet" type="text/css"> | ||||
|   <script src="../dist/video.js"></script> | ||||
| </head> | ||||
| <body> | ||||
|   <div style="background-color:#eee; border: 1px solid #777; padding: 10px; margin-bottom: 20px; font-size: .8em; line-height: 1.5em; font-family: Verdana, sans-serif;"> | ||||
|     <p>You can use /sandbox/ for writing and testing your own code. Nothing in /sandbox/ will get checked into the repo, except files that end in .example (so don't edit or add those files). To get started run `npm start` and open the svg-icons-enabled.html</p> | ||||
|     <pre>npm start</pre> | ||||
|     <pre>open http://localhost:9999/sandbox/svg-icons-enabled.html</pre> | ||||
|   </div> | ||||
|  | ||||
|   <video-js | ||||
|     id="vid1" | ||||
|     controls | ||||
|     preload="auto" | ||||
|     width="640" | ||||
|     height="264" | ||||
|     poster="https://vjs.zencdn.net/v/oceans.png"> | ||||
|     <source src="https://vjs.zencdn.net/v/oceans.mp4" type="video/mp4"> | ||||
|     <source src="https://vjs.zencdn.net/v/oceans.webm" type="video/webm"> | ||||
|     <source src="https://vjs.zencdn.net/v/oceans.ogv" type="video/ogg"> | ||||
|     <track kind="captions" src="../docs/examples/shared/example-captions.vtt" srclang="en" label="English"> | ||||
|     <p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p> | ||||
|   </video-js> | ||||
|  | ||||
|   <script> | ||||
|     var vid = document.getElementById('vid1'); | ||||
|     var player = videojs(vid, {experimentalSvgIcons: true}); | ||||
|   </script> | ||||
|  | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										414
									
								
								sandbox/svg-icons.html.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								sandbox/svg-icons.html.example
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,414 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <meta charset="UTF-8"> | ||||
|   <title>VideoJS</title> | ||||
|   <link href="../../dist/video-js.css" rel="stylesheet" type="text/css"> | ||||
|   <style> | ||||
|     body { | ||||
|       text-align: center; | ||||
|     } | ||||
|  | ||||
|     .container-class { | ||||
|       display: flex; | ||||
|       flex-wrap: wrap; | ||||
|     } | ||||
|  | ||||
|     /* Overwrite default height and width */ | ||||
|     .vjs-svg-icon { | ||||
|       width: 24px; | ||||
|       height: 24px; | ||||
|     } | ||||
|  | ||||
|     div:not(.container-class) { | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       align-items: center; | ||||
|       border: 1px solid #ccc; | ||||
|       width: 150px; | ||||
|       margin: 10px; | ||||
|       padding: 10px; | ||||
|       background-color: #5A5A5A; | ||||
|     } | ||||
|  | ||||
|     div span:nth-of-type(2) { | ||||
|         color: white; | ||||
|     } | ||||
|   </style> | ||||
| </head> | ||||
| <body> | ||||
|   <h1>VideoJS SVG Icons</h1> | ||||
|   <p>In order to use SVG icons, the <code>experimentalSvgIcons</code> option must be enabled on the player. See: <a href="https://videojs.com/guides/options/#experimentalsvgicons">experimentalSvgIcons</a></p> | ||||
|   <p>SVG Icons are expected to be added to the player through components. Example: <code>myButton.setIcon('play');</code></p> | ||||
|   <div class="container-class vjs-svg-icons-enabled"> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-play" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>play</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-play-circle" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>play-circle</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-pause" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>pause</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-volume-mute" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>volume-mute</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-volume-low" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>volume-low</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-volume-medium" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>volume-medium</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-volume-high" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>volume-high</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-fullscreen-enter" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>fullscreen-enter</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-fullscreen-exit" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>fullscreen-exit</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-spinner" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>spinner</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-subtitles" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>subtitles</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-captions" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>captions</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-hd" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>hd</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-chapters" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>chapters</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-downloading" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>downloading</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-file-download" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>file-download</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-file-download-done" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>file-download-done</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-file-download-off" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>file-download-off</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-share" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>share</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-cog" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>cog</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-square" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>square</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-circle" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>circle</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-circle-outline" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>circle-outline</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-circle-inner-circle" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>circle-inner-circle</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-cancel" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>cancel</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-repeat" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>repeat</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-replay" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>replay</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-replay-5" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>replay-5</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-replay-10" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>replay-10</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-replay-30" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>replay-30</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-forward-5" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>forward-5</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-forward-10" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>forward-10</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-forward-30" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>forward-30</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-audio" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>audio</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-next-item" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>next-item</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-previous-item" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>previous-item</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-shuffle" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>shuffle</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-cast" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>cast</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-picture-in-picture-enter" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>picture-in-picture-enter</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-picture-in-picture-exit" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>picture-in-picture-exit</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-facebook" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>facebook</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-linkedin" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>linkedin</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-twitter" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>twitter</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-tumblr" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>tumblr</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-pinterest" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>pinterest</span> | ||||
|     </div> | ||||
|     <div> | ||||
|       <span class="vjs-icon-placeholder vjs-svg-icon"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> | ||||
|           <use xmlns="http://www.w3.org/2000/svg" href="../src/images/icons.svg#vjs-icon-audio-description" /> | ||||
|         </svg> | ||||
|       </span> | ||||
|       <span>audio-description</span> | ||||
|     </div>   | ||||
|   </div> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										29
									
								
								src/css/_icons.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/css/_icons.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| // CSS styles for SVG icons used throughout video.js. | ||||
| // | ||||
| // The goal is to replace all icons from the font family pulled from videojs/font entirely. | ||||
| // This project currently uses fonts. We want to replace this with SVGs from | ||||
| // images/icons.svg. This will ensure consitency between versions, as well as simplified | ||||
| // and straight-forward customization. | ||||
|  | ||||
| // Default styling for all SVG icons | ||||
| .vjs-svg-icon { | ||||
|   display: inline-block; | ||||
|   background-repeat: no-repeat; | ||||
|   background-position: center; | ||||
|  | ||||
|   fill: #FFFFFF; | ||||
|   height: 1.5em; | ||||
|   width: 1.5em; | ||||
|  | ||||
|   // Overwrite any font content | ||||
|   &:before { | ||||
|     content: none !important; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // SVG shadow on hover and focus | ||||
| .vjs-svg-icon:hover, | ||||
| .vjs-control:focus .vjs-svg-icon { | ||||
|   -webkit-filter: drop-shadow(0 0 0.25em #fff); | ||||
|   filter: drop-shadow(0 0 0.25em #fff); | ||||
| } | ||||
| @@ -30,6 +30,11 @@ | ||||
|   } | ||||
| } | ||||
|  | ||||
| .vjs-big-play-button .vjs-svg-icon { | ||||
|   width: 0.75em; | ||||
|   height: 0.75em; | ||||
| } | ||||
|  | ||||
| .video-js:hover .vjs-big-play-button, | ||||
| .video-js .vjs-big-play-button:focus { | ||||
|   border-color: $primary-foreground-color; | ||||
|   | ||||
| @@ -25,7 +25,11 @@ | ||||
| } | ||||
|  | ||||
| .vjs-button > .vjs-icon-placeholder { | ||||
|     display: block; | ||||
|   display: block; | ||||
| } | ||||
|  | ||||
| .vjs-button > .vjs-svg-icon { | ||||
|   display: inline-block; | ||||
| } | ||||
|  | ||||
| // Replacement for focus outline | ||||
|   | ||||
| @@ -46,7 +46,21 @@ | ||||
|   color: #888; | ||||
| } | ||||
|  | ||||
| .vjs-svg-icons-enabled .vjs-seek-to-live-control { | ||||
|   line-height: 0; | ||||
| } | ||||
|  | ||||
| .vjs-seek-to-live-control .vjs-svg-icon { | ||||
|   width: 1em; | ||||
|   height: 1em; | ||||
|   pointer-events: none; | ||||
|   fill: #888888; | ||||
| } | ||||
|  | ||||
| // make the live circle red when at the live edge | ||||
| .vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-icon-placeholder { | ||||
|   color: red; | ||||
| } | ||||
| .vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-svg-icon { | ||||
|   fill: red; | ||||
| } | ||||
|   | ||||
| @@ -80,6 +80,23 @@ | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Remove content from play-progress when using SVGs. | ||||
| .vjs-svg-icons-enabled .vjs-play-progress { | ||||
|   &:before { | ||||
|     content: none !important; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .vjs-play-progress .vjs-svg-icon { | ||||
|   position: absolute; | ||||
|   top: -0.35em; | ||||
|   right: -0.4em; | ||||
|   width: 1em; | ||||
|   height: 1em; | ||||
|   pointer-events: none; | ||||
|   line-height: 0.15em; | ||||
| } | ||||
|  | ||||
| .video-js .vjs-load-progress { | ||||
|   background: rgba($secondary-background-color, $secondary-background-transparency); | ||||
| } | ||||
| @@ -120,6 +137,15 @@ | ||||
|   z-index: 1; | ||||
| } | ||||
|  | ||||
| // Update the size of the progress circle when using SVG icons | ||||
| .vjs-progress-control:hover .vjs-progress-holder .vjs-play-progress .vjs-svg-icon { | ||||
|   width: 0.8em; | ||||
|   height: 0.8em; | ||||
|   top: -0.25em; | ||||
|   right: -0.5em; | ||||
|   line-height: 0.35em; | ||||
| } | ||||
|  | ||||
| .video-js .vjs-progress-holder:focus .vjs-time-tooltip { | ||||
|   display: none; | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,20 @@ | ||||
| .video-js .vjs-skip-forward-5 { | ||||
|   cursor: pointer; | ||||
|   & .vjs-icon-placeholder { | ||||
|   @extend .vjs-icon-forward-5; | ||||
|     @extend .vjs-icon-forward-5; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .video-js .vjs-skip-forward-10 { | ||||
|   cursor: pointer; | ||||
|   & .vjs-icon-placeholder { | ||||
|   @extend .vjs-icon-forward-10; | ||||
|     @extend .vjs-icon-forward-10; | ||||
|   } | ||||
| } | ||||
| .video-js .vjs-skip-forward-30 { | ||||
|   cursor: pointer; | ||||
|   & .vjs-icon-placeholder { | ||||
|   @extend .vjs-icon-forward-30; | ||||
|     @extend .vjs-icon-forward-30; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -37,4 +37,4 @@ | ||||
|   & .vjs-icon-placeholder { | ||||
|     @extend .vjs-icon-replay-30; | ||||
|   } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -14,6 +14,10 @@ | ||||
|   @extend .vjs-icon-subtitles; | ||||
| } | ||||
|  | ||||
| .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-svg-icon { | ||||
|   margin-left: 0.3em; | ||||
| } | ||||
|  | ||||
| .video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder { | ||||
|   vertical-align: middle; | ||||
|   display: inline-block; | ||||
|   | ||||
| @@ -134,6 +134,28 @@ | ||||
|     z-index: 1; | ||||
|   } | ||||
| } | ||||
| // Remove content from volume-level when using SVGs. | ||||
| .vjs-svg-icons-enabled .vjs-volume-level { | ||||
|   &:before { | ||||
|     content: none; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .vjs-volume-level .vjs-svg-icon { | ||||
|   position: absolute; | ||||
|   width: 0.6em; | ||||
|   height: 0.6em; | ||||
|   top: -0.55em; | ||||
|   pointer-events: none; | ||||
| } | ||||
|  | ||||
| // Due to this icon from Material UI being a bit smaller than the others, | ||||
| // we will adjust the height and width | ||||
| .vjs-mute-control .vjs-svg-icon { | ||||
|   width: 1.75em; | ||||
|   height: 1.75em; | ||||
| } | ||||
|  | ||||
| .vjs-slider-horizontal .vjs-volume-level { | ||||
|   height: 0.3em; | ||||
|  | ||||
| @@ -144,6 +166,18 @@ | ||||
|   } | ||||
| } | ||||
|  | ||||
| // here | ||||
| // Update placement of circle icon when using SVG icons | ||||
| .vjs-slider-horizontal .vjs-volume-level .vjs-svg-icon { | ||||
|   top: -0.15em; | ||||
|   right: -0.3em; | ||||
|   line-height: 0.05em; | ||||
| } | ||||
| .vjs-slider-vertical .vjs-volume-level .vjs-svg-icon { | ||||
|   top: -0.9em; | ||||
|   right: -0.15em; | ||||
| } | ||||
|  | ||||
| .video-js .vjs-volume-panel.vjs-volume-panel-vertical { | ||||
|   width: 4em; | ||||
| } | ||||
|   | ||||
| @@ -33,6 +33,8 @@ | ||||
| } | ||||
|  | ||||
| .vjs-menu li { | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   list-style: none; | ||||
|   margin: 0; | ||||
|   padding: 0.2em 0; | ||||
| @@ -54,6 +56,11 @@ | ||||
| .js-focus-visible .vjs-menu li.vjs-selected:hover { | ||||
|   background-color: $primary-foreground-color; | ||||
|   color: $primary-background-color; | ||||
|  | ||||
|   // Change the SVG color when an item is selected | ||||
|   .vjs-svg-icon { | ||||
|     fill: #000000; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .video-js .vjs-menu *:not(.vjs-selected):focus:not(:focus-visible), | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| @import "icons"; | ||||
| @import "variables"; | ||||
| @import "private-variables"; | ||||
| @import "utilities"; | ||||
|   | ||||
							
								
								
									
										142
									
								
								src/images/icons.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/images/icons.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg"> | ||||
|   <defs> | ||||
|     <symbol viewBox="0 0 16 16" id="vjs-icon-play"> | ||||
|       <path d="M2 1v14l12-7z"></path> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-pause"> | ||||
|        <path d="M10 4H5v16h5V4zm9 0h-5v16h5V4z"/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-audio"> | ||||
|       <g><rect fill='none' height='24' width='24'/></g><g><path d='M12,3c-4.97,0-9,4.03-9,9v7c0,1.1,0.9,2,2,2h4v-8H5v-1c0-3.87,3.13-7,7-7s7,3.13,7,7v1h-4v8h4c1.1,0,2-0.9,2-2v-7 C21,7.03,16.97,3,12,3z'/></g> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 576 512" id="vjs-icon-captions"> | ||||
|       <path d='M0 96C0 60.7 28.7 32 64 32H512c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM200 208c14.2 0 27 6.1 35.8 16c8.8 9.9 24 10.7 33.9 1.9s10.7-24 1.9-33.9c-17.5-19.6-43.1-32-71.5-32c-53 0-96 43-96 96s43 96 96 96c28.4 0 54-12.4 71.5-32c8.8-9.9 8-25-1.9-33.9s-25-8-33.9 1.9c-8.8 9.9-21.6 16-35.8 16c-26.5 0-48-21.5-48-48s21.5-48 48-48zm144 48c0-26.5 21.5-48 48-48c14.2 0 27 6.1 35.8 16c8.8 9.9 24 10.7 33.9 1.9s10.7-24 1.9-33.9c-17.5-19.6-43.1-32-71.5-32c-53 0-96 43-96 96s43 96 96 96c28.4 0 54-12.4 71.5-32c8.8-9.9 8-25-1.9-33.9s-25-8-33.9 1.9c-8.8 9.9-21.6 16-35.8 16c-26.5 0-48-21.5-48-48z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-subtitles"> | ||||
|       <path d='M0 0h24v24H0z' fill='none'/><path d='M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM4 12h4v2H4v-2zm10 6H4v-2h10v2zm6 0h-4v-2h4v2zm0-4H10v-2h10v2z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 448 512" id="vjs-icon-fullscreen-enter"> | ||||
|       <path d='M0 180V56c0-13.3 10.7-24 24-24h124c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H64v84c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12zM288 44v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12V56c0-13.3-10.7-24-24-24H300c-6.6 0-12 5.4-12 12zm148 276h-40c-6.6 0-12 5.4-12 12v84h-84c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24V332c0-6.6-5.4-12-12-12zM160 468v-40c0-6.6-5.4-12-12-12H64v-84c0-6.6-5.4-12-12-12H12c-6.6 0-12 5.4-12 12v124c0 13.3 10.7 24 24 24h124c6.6 0 12-5.4 12-12z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-fullscreen-exit"> | ||||
|       <path d="M16,9h5a1,1,0,0,0,0-2H17V3a1,1,0,0,0-2,0V8A1,1,0,0,0,16,9ZM8,15H3a1,1,0,0,0,0,2H7v4a1,1,0,0,0,2,0V16A1,1,0,0,0,8,15ZM8,2A1,1,0,0,0,7,3V7H3A1,1,0,0,0,3,9H8A1,1,0,0,0,9,8V3A1,1,0,0,0,8,2ZM21,15H16a1,1,0,0,0-1,1v5a1,1,0,0,0,2,0V17h4a1,1,0,0,0,0-2Z"/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 512 512" id="vjs-icon-play-circle"> | ||||
|       <path d='M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9V168c0-8.7 4.7-16.7 12.3-20.9z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-volume-mute"> | ||||
|       <path d='M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-volume-low"> | ||||
|       <path d="M0 0h24v24H0z" fill="none"/><path d="M7 9v6h4l5 5V4l-5 5H7z"/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-volume-medium"> | ||||
|       <path d="M0 0h24v24H0z" fill="none"/><path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-volume-high"> | ||||
|       <path d="M0 0h24v24H0z" fill="none"/><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 512 512" id="vjs-icon-spinner"> | ||||
|       <path d='M304 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zm0 416a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM48 304a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm464-48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM142.9 437A48 48 0 1 0 75 369.1 48 48 0 1 0 142.9 437zm0-294.2A48 48 0 1 0 75 75a48 48 0 1 0 67.9 67.9zM369.1 437A48 48 0 1 0 437 369.1 48 48 0 1 0 369.1 437z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-hd"> | ||||
|       <path d='M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-8 12H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm2-6h4c.55 0 1 .45 1 1v4c0 .55-.45 1-1 1h-4V9zm1.5 4.5h2v-3h-2v3z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-chapters"> | ||||
|       <path d='M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-downloading"> | ||||
|       <path d='M18.32,4.26C16.84,3.05,15.01,2.25,13,2.05v2.02c1.46,0.18,2.79,0.76,3.9,1.62L18.32,4.26z M19.93,11h2.02 c-0.2-2.01-1-3.84-2.21-5.32L18.31,7.1C19.17,8.21,19.75,9.54,19.93,11z M18.31,16.9l1.43,1.43c1.21-1.48,2.01-3.32,2.21-5.32 h-2.02C19.75,14.46,19.17,15.79,18.31,16.9z M13,19.93v2.02c2.01-0.2,3.84-1,5.32-2.21l-1.43-1.43 C15.79,19.17,14.46,19.75,13,19.93z M15.59,10.59L13,13.17V7h-2v6.17l-2.59-2.59L7,12l5,5l5-5L15.59,10.59z M11,19.93v2.02 c-5.05-0.5-9-4.76-9-9.95s3.95-9.45,9-9.95v2.02C7.05,4.56,4,7.92,4,12S7.05,19.44,11,19.93z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-file-download"> | ||||
|       <path d='M18,15v3H6v-3H4v3c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-3H18z M17,11l-1.41-1.41L13,12.17V4h-2v8.17L8.41,9.59L7,11l5,5 L17,11z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-file-download-done"> | ||||
|       <polygon points='20.13,5.41 18.72,4 9.53,13.19 5.28,8.95 3.87,10.36 9.53,16.02'/><rect height='2' width='14' x='5' y='18'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-file-download-off"> | ||||
|       <path d='M18,15.17V15h2v2.17L18,15.17z M15.41,12.59L17,11l-1.41-1.41L14,11.17L15.41,12.59z M13,10.17V4h-2v4.17L13,10.17z M21.19,21.19l-1.78-1.78L2.81,2.81L1.39,4.22l6.19,6.19L7,11l5,5l0.59-0.59L15.17,18H6v-3H4v3c0,1.1,0.9,2,2,2h11.17l2.61,2.61 L21.19,21.19z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-share"> | ||||
|       <path d='M0 0h24v24H0z' fill='none'/><path d='M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-cog"> | ||||
|       <path d='M0,0h24v24H0V0z' fill='none'/><path d='M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 448 512" id="vjs-icon-square"> | ||||
|       <path d='M384 80c8.8 0 16 7.2 16 16V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V96c0-8.8 7.2-16 16-16H384zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 512 512" id="vjs-icon-circle"> | ||||
|       <path d='M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-circle-outline"> | ||||
|       <path d='M12,2C6.47,2,2,6.47,2,12c0,5.53,4.47,10,10,10s10-4.47,10-10C22,6.47,17.53,2,12,2z M12,20c-4.42,0-8-3.58-8-8 c0-4.42,3.58-8,8-8s8,3.58,8,8C20,16.42,16.42,20,12,20z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-circle-inner-circle"> | ||||
|       <path d='M12 2C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3-8c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-cancel"> | ||||
|       <path d='M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-repeat"> | ||||
|       <path d='M0 0h24v24H0z' fill='none'/><path d='M7 7h10v3l4-4-4-4v3H5v6h2V7zm10 10H7v-3l-4 4 4 4v-3h12v-6h-2v4z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-replay"> | ||||
|       <path d='M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 96 48 48" id="vjs-icon-replay-5"> | ||||
|       <path d='m17.68852 98-8.69633 8.69633 8.69633 8.69634 2.48665-2.48434-4.31928-4.31928h1.3011c4.93015 0 9.07149 1.72189 12.42399 5.16511 3.35251 3.44322 5.02876 7.63753 5.02876 12.58345h3.54972c0-2.95809-.55264-5.7293-1.657-8.3127-1.10435-2.5834-2.62238-4.84095-4.555-6.77357-1.93262-1.93262-4.19017-3.45065-6.77357-4.55501-2.5834-1.10435-5.35462-1.65699-8.31271-1.65699H15.5l4.61508-4.61509zm-8.07929 21.65879v13.86144h11.35631v5.00796H9.60923V143h12.699c.83466 0 1.55075-.29818 2.14693-.89436.59619-.59619.89436-1.30996.89436-2.14462v-7.78117c0-.83466-.29817-1.55075-.89436-2.14693-.59618-.59618-1.31227-.89436-2.14693-.89436h-8.22719v-5.09578h11.26848v-4.38399z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 96 48 48" id="vjs-icon-replay-10"> | ||||
|       <path d='M42.314792 125.62978c0-4.99676-1.693476-9.23445-5.080438-12.71305-3.386962-3.47861-7.570851-5.21791-12.551676-5.21791h-1.314946l4.363203 4.3632-2.510335 2.51034-8.786174-8.78619L25.2206 97l2.450567 2.45057-4.662053 4.66205h1.374714c2.988489 0 5.787713.55785 8.397671 1.67355 2.609949 1.11571 4.891163 2.64981 6.843654 4.60229 1.952481 1.95248 3.486576 4.2337 4.602275 6.84365 1.115709 2.60995 1.673563 5.40917 1.673563 8.39767zM8.1829433 142v-19.65677H3.17603v-4.5433h9.642939V142Zm13.6299297 0c-1.155923 0-2.126398-.39251-2.911424-1.17755-.778861-.77885-1.168286-1.74624-1.168286-2.90215v-16.04066c0-1.15593.392524-2.1264 1.17755-2.91144.77886-.77885 1.746237-1.16827 2.90216-1.16827h7.695814c1.155914 0 2.126388.39251 2.911425 1.17755.77885.77886 1.168275 1.74623 1.168275 2.90216v16.04066c0 1.15591-.392513 2.12639-1.177549 2.91142-.778851.77885-1.746237 1.16828-2.902151 1.16828Zm.556316-4.63603h6.583172v-15.02074h-6.583172z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 96 48 48" id="vjs-icon-replay-30"> | ||||
|       <path d='m26.046875 97-8.732422 8.73242 8.732422 8.73242 2.496094-2.49414-4.335938-4.33789h1.306641c4.950749 0 9.108097 1.72991 12.474609 5.1875 3.366504 3.4576 5.050781 7.66818 5.050781 12.63477h3.564454c0-2.97045-.555098-5.75152-1.664063-8.3457-1.108965-2.59419-2.633522-4.86205-4.574219-6.80274-1.940688-1.94069-4.208545-3.46525-6.802734-4.57422-2.59419-1.10897-5.375262-1.66406-8.345703-1.66406h-1.367188l4.634766-4.63477zM2.5546875 117.53125v4.6875H12.851562v5.25H5.8730469v4.6875h6.9785151v5.15625H2.5546875V142H13.361328c1.06088 0 1.950319-.39495 2.667969-1.18555.71765-.79059 1.076172-1.7727 1.076172-2.9414v-16.2168c0-1.1687-.358522-2.14886-1.076172-2.93945-.71765-.79059-1.607089-1.18555-2.667969-1.18555zm22.4824215.14063c-1.148936 0-2.110612.38991-2.884765 1.16406-.780292.78029-1.171875 1.74365-1.171875 2.89258v15.94336c0 1.14892.387966 2.1106 1.162109 2.88476.780302.78029 1.745595 1.17188 2.894531 1.17188h7.648438c1.148936 0 2.110613-.38795 2.884765-1.16211.780294-.78029 1.169922-1.74561 1.169922-2.89453v-15.94336c0-1.14893-.386013-2.11061-1.160156-2.88477-.780293-.78029-1.745595-1.17187-2.894531-1.17187zm.552735 4.51757h6.544922v14.92969h-6.544922z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 96 48 48" id="vjs-icon-forward-5"> | ||||
|       <path d='m29.50843 97-2.43193 2.42962 4.6253 4.6253h-1.3642c-2.96464 0-5.74198.55386-8.3311 1.66066-2.58912 1.1068-4.85167 2.62819-6.78857 4.56508-1.93689 1.9369-3.45828 4.19945-4.56508 6.78857-1.1068 2.58911-1.66066 5.36646-1.66066 8.3311h3.55757c0-4.95687 1.67996-9.16047 5.03989-12.6113 3.35992-3.45084 7.51042-5.17654 12.45149-5.17654h1.30398l-4.32653 4.32883 2.48984 2.48984 8.71558-8.71558zm-9.78332 21.60945v13.8898h11.38144v5.01905H19.72511V142h12.72711c.83651 0 1.55186-.29884 2.14937-.89634.5975-.59751.89634-1.31286.89634-2.14936v-7.7984c0-.83651-.29884-1.55418-.89634-2.15168-.59751-.5975-1.31286-.89634-2.14937-.89634h-8.2454v-5.10706h11.29111v-4.39137z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 96 48 48" id="vjs-icon-forward-10"> | ||||
|       <path d='m23.118923 97-2.385761 2.38349 4.537491 4.53749h-1.338298c-2.908354 0-5.632974.54335-8.172936 1.62913-2.539963 1.08579-4.759558 2.57829-6.659682 4.47842-1.900125 1.90012-3.39263 4.11972-4.478415 6.65968-1.085785 2.53996-1.629134 5.26458-1.629134 8.17294h3.490028c0-4.86277 1.648071-8.98656 4.944206-12.37188 3.296134-3.38532 7.367841-5.07826 12.215097-5.07826h1.279222l-4.244383 4.24665 2.442565 2.44257 8.550114-8.55012zm-9.520322 21.44913v4.42161h4.871497V142h4.512496v-23.55087zm18.136328 0c-1.124919 0-2.06632.37811-2.824287 1.13608-.763982.76398-1.147437 1.70845-1.147437 2.83337v15.61197c0 1.12492.380382 2.06631 1.138349 2.82428.763983.76398 1.708456 1.14517 2.833375 1.14517h7.489021c1.12492 0 2.06632-.37811 2.82428-1.13608.76399-.76398 1.14517-1.70845 1.14517-2.83337v-15.61197c0-1.12492-.37811-2.06632-1.13608-2.82429-.76398-.76398-1.70845-1.14516-2.83337-1.14516zm.540773 4.42161h6.407468v14.61676h-6.407468z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 96 48 48" id="vjs-icon-forward-30"> | ||||
|       <path d='m25.548631 97-2.436697 2.43438 4.634367 4.63436H26.37943c-2.970448 0-5.753239.55495-8.347429 1.66392-2.594191 1.10897-4.861176 2.63334-6.801867 4.57403-1.940693 1.94069-3.465063 4.20767-4.57403 6.80187-1.108967 2.59419-1.663916 5.37698-1.663916 8.34742h3.56454c0-4.96658 1.683258-9.17841 5.049766-12.63601 3.366507-3.4576 7.525145-5.18669 12.475891-5.18669h1.306534l-4.335002 4.33733 2.494714 2.49471 8.73266-8.73266zm-11.552266 20.53092v4.68774h10.296787v5.24934h-6.978237v4.68774h6.978237v5.15652H13.996365V142h10.807333c1.060879 0 1.94879-.39527 2.666443-1.18586.717653-.79059 1.076789-1.77158 1.076789-2.94028v-16.2168c0-1.1687-.359136-2.14969-1.076789-2.94028-.717653-.79059-1.605564-1.18586-2.666443-1.18586zm21.173741.16708c-1.148937 0-2.110436.38851-2.884586 1.16266-.780294.78029-1.171935 1.74493-1.171935 2.89387v15.94296c0 1.14894.388502 2.11043 1.162652 2.88458.780294.78029 1.744932 1.16962 2.893869 1.16962h7.648904c1.14894 0 2.11044-.38619 2.88459-1.16033.78029-.7803 1.16961-1.74493 1.16961-2.89387v-15.94296c0-1.14894-.38618-2.11044-1.16033-2.88459-.78029-.78029-1.74493-1.17194-2.89387-1.17194zm.552317 4.51602h6.541957v14.93115h-6.541957z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 512 512" xmlns:sketch='http://www.bohemiancoding.com/sketch/ns' id="vjs-icon-audio-description"> | ||||
|       <g id='Page-1' stroke='none' stroke-width='1' sketch:type='MSPage'><g id='AD' sketch:type='MSArtboardGroup'><g id='g24' sketch:type='MSLayerGroup' transform='translate(226.904216, 162.124958)'><path d='M0.385466989,219.226204 L0.385466989,0.867948105 C50.7660025,-0.149278544 89.4938709,-2.16027378 118.016886,17.9940357 C145.39121,37.3362698 166.750707,74.9591545 162.906445,123.318579 C158.839382,174.474203 121.571663,217.457893 73.1311827,221.793795 C49.0460488,223.949377 1.1583283,221.793795 1.1583283,221.793795 C1.1583283,221.793795 0.318395733,220.441758 0.385466989,219.226204 M49.1404882,164.421786 C80.5703101,165.681697 102.34881,147.788744 105.636072,119.036417 C110.038491,80.5268177 84.4473371,55.4838492 47.5943801,58.2399576 L47.5943801,161.852062 C47.5585317,163.318404 48.1702678,164.071194 49.1404882,164.421786' id='path26' sketch:type='MSShapeGroup'></path></g><g id='g28' sketch:type='MSLayerGroup' transform='translate(383.779991, 168.926023)'><path d='M0,212.402042 C13.3360014,216.111401 17.386874,201.342635 23.2151349,190.99422 C35.936702,168.422877 45.5086182,139.400143 45.6604922,106.220214 C45.8813648,58.6259492 27.3172746,23.7033002 10.059532,0.0383859113 L1.54919183,0.0383859113 C0.96289654,3.91152436 3.77564916,7.35260805 5.41542574,10.3142944 C18.5814362,34.0755999 30.7818519,66.8674044 30.9556975,104.507776 C31.1545985,147.683822 16.7932549,183.786198 0,212.402042' id='path30' sketch:type='MSShapeGroup'></path></g><g id='g32' sketch:type='MSLayerGroup' transform='translate(425.153705, 168.926023)'><path d='M0,212.402042 C13.3360014,216.111401 17.3841758,201.340502 23.2151349,190.99422 C35.936702,168.422877 45.5066909,139.400143 45.6604922,106.220214 C45.8813648,58.6259492 27.3172746,23.7033002 10.059532,0.0383859113 L1.54919183,0.0383859113 C0.96289654,3.91152436 3.77487823,7.35346107 5.41542574,10.3142944 C18.5814362,34.0755999 30.7822374,66.8674044 30.9556975,104.507776 C31.1545985,147.683822 16.7932549,183.786198 0,212.402042' id='path34' sketch:type='MSShapeGroup'></path></g><g id='g36' sketch:type='MSLayerGroup' transform='translate(466.260868, 168.926023)'><path d='M0,212.402042 C13.3360014,216.111401 17.3841758,201.340502 23.2151349,190.99422 C35.936702,168.422877 45.5066909,139.400143 45.6604922,106.220214 C45.8813648,58.6259492 27.3172746,23.7033002 10.059532,0.0383859113 L1.54919183,0.0383859113 C0.96289654,3.91152436 3.77487823,7.35303456 5.41542574,10.3142944 C18.5814362,34.0755999 30.7818519,66.8674044 30.9556975,104.507776 C31.1545985,147.683822 16.7932549,183.786198 0,212.402042' id='path38' sketch:type='MSShapeGroup'></path></g><path d='M4.4765625,383.005158 L72.5800993,383.005158 L91.1530552,354.521486 L155.321745,354.386058 C155.321745,354.386058 155.386889,373.799083 155.386889,383.005158 L204.142681,383.005158 L204.142681,160.308263 L145.326586,160.308263 C139.673713,169.845383 4.4765625,383.005158 4.4765625,383.005158 L4.4765625,383.005158 Z M157.144233,237.722611 L157.144233,308.881058 L116.6914,308.610203 L157.144233,237.722611 L157.144233,237.722611 Z' id='path22' sketch:type='MSShapeGroup'></path></g></g> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-next-item"> | ||||
|       <path d='M0 0h24v24H0z' fill='none'/><path d='M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-previous-item"> | ||||
|       <path d='M0 0h24v24H0z' fill='none'/><path d='M6 6h2v12H6zm3.5 6l8.5 6V6z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-shuffle"> | ||||
|       <path d='M0 0h24v24H0z' fill='none'/><path d='M10.59 9.17L5.41 4 4 5.41l5.17 5.17 1.42-1.41zM14.5 4l2.04 2.04L4 18.59 5.41 20 17.96 7.46 20 9.5V4h-5.5zm.33 9.41l-1.41 1.41 3.13 3.13L14.5 20H20v-5.5l-2.04 2.04-3.13-3.13z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-cast"> | ||||
|       <path d='M0 0h24v24H0z' fill='none'/><path d='M0 0h24v24H0z' fill='none' opacity='.1'/><path d='M21 3H3c-1.1 0-2 .9-2 2v3h2V5h18v14h-7v2h7c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM1 18v3h3c0-1.66-1.34-3-3-3zm0-4v2c2.76 0 5 2.24 5 5h2c0-3.87-3.13-7-7-7zm0-4v2c4.97 0 9 4.03 9 9h2c0-6.08-4.93-11-11-11z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 24 24" id="vjs-icon-picture-in-picture-enter"> | ||||
|       <path d='M0 0h24v24H0V0z' fill='none'/><path d='M19 11h-8v6h8v-6zm4 8V4.98C23 3.88 22.1 3 21 3H3c-1.1 0-2 .88-2 1.98V19c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2zm-2 .02H3V4.97h18v14.05z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 22 18" id="vjs-icon-picture-in-picture-exit"> | ||||
|       <path d='M18 4H4v10h14V4zm4 12V1.98C22 .88 21.1 0 20 0H2C.9 0 0 .88 0 1.98V16c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2zm-2 .02H2V1.97h18v14.05z'/><path fill='none' d='M-1-3h24v24H-1z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 320 512" id="vjs-icon-facebook"> | ||||
|       <path d='M279.14 288l14.22-92.66h-88.91v-60.13c0-25.35 12.42-50.06 52.24-50.06h40.42V6.26S260.43 0 225.36 0c-73.22 0-121.08 44.38-121.08 124.72v70.62H22.89V288h81.39v224h100.17V288z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 448 512" id="vjs-icon-linkedin"> | ||||
|       <path d='M100.28 448H7.4V148.9h92.88zM53.79 108.1C24.09 108.1 0 83.5 0 53.8a53.79 53.79 0 0 1 107.58 0c0 29.7-24.1 54.3-53.79 54.3zM447.9 448h-92.68V302.4c0-34.7-.7-79.2-48.29-79.2-48.29 0-55.69 37.7-55.69 76.7V448h-92.78V148.9h89.08v40.8h1.3c12.4-23.5 42.69-48.3 87.88-48.3 94 0 111.28 61.9 111.28 142.3V448z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 512 512" id="vjs-icon-twitter"> | ||||
|       <path d='M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 320 512" id="vjs-icon-tumblr"> | ||||
|       <path d='M309.8 480.3c-13.6 14.5-50 31.7-97.4 31.7-120.8 0-147-88.8-147-140.6v-144H17.9c-5.5 0-10-4.5-10-10v-68c0-7.2 4.5-13.6 11.3-16 62-21.8 81.5-76 84.3-117.1.8-11 6.5-16.3 16.1-16.3h70.9c5.5 0 10 4.5 10 10v115.2h83c5.5 0 10 4.4 10 9.9v81.7c0 5.5-4.5 10-10 10h-83.4V360c0 34.2 23.7 53.6 68 35.8 4.8-1.9 9-3.2 12.7-2.2 3.5.9 5.8 3.4 7.4 7.9l22 64.3c1.8 5 3.3 10.6-.4 14.5z'/> | ||||
|     </symbol> | ||||
|     <symbol viewBox="0 0 496 512" id="vjs-icon-pinterest"> | ||||
|       <path d='M496 256c0 137-111 248-248 248-25.6 0-50.2-3.9-73.4-11.1 10.1-16.5 25.2-43.5 30.8-65 3-11.6 15.4-59 15.4-59 8.1 15.4 31.7 28.5 56.8 28.5 74.8 0 128.7-68.8 128.7-154.3 0-81.9-66.9-143.2-152.9-143.2-107 0-163.9 71.8-163.9 150.1 0 36.4 19.4 81.7 50.3 96.1 4.7 2.2 7.2 1.2 8.3-3.3.8-3.4 5-20.3 6.9-28.1.6-2.5.3-4.7-1.7-7.1-10.1-12.5-18.3-35.3-18.3-56.6 0-54.7 41.4-107.6 112-107.6 60.9 0 103.6 41.5 103.6 100.9 0 67.1-33.9 113.6-78 113.6-24.3 0-42.6-20.1-36.7-44.8 7-29.5 20.5-61.3 20.5-82.6 0-19-10.2-34.9-31.4-34.9-24.9 0-44.9 25.7-44.9 60.2 0 22 7.4 36.8 7.4 36.8s-24.5 103.8-29 123.2c-5 21.4-3 51.6-.9 71.2C65.4 450.9 0 361.1 0 256 0 119 111 8 248 8s248 111 248 248z'/> | ||||
|     </symbol> | ||||
|   </defs> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 22 KiB | 
| @@ -17,6 +17,8 @@ class BigPlayButton extends Button { | ||||
|  | ||||
|     this.mouseused_ = false; | ||||
|  | ||||
|     this.setIcon('play'); | ||||
|  | ||||
|     this.on('mousedown', (e) => this.handleMouseDown(e)); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -46,11 +46,13 @@ class Button extends ClickableComponent { | ||||
|  | ||||
|     const el = createEl(tag, props, attributes); | ||||
|  | ||||
|     el.appendChild(createEl('span', { | ||||
|       className: 'vjs-icon-placeholder' | ||||
|     }, { | ||||
|       'aria-hidden': true | ||||
|     })); | ||||
|     if (!this.player_.options_.experimentalSvgIcons) { | ||||
|       el.appendChild(createEl('span', { | ||||
|         className: 'vjs-icon-placeholder' | ||||
|       }, { | ||||
|         'aria-hidden': true | ||||
|       })); | ||||
|     } | ||||
|  | ||||
|     this.createControlTextEl(el); | ||||
|  | ||||
|   | ||||
| @@ -85,11 +85,13 @@ class ClickableComponent extends Component { | ||||
|  | ||||
|     const el = Dom.createEl(tag, props, attributes); | ||||
|  | ||||
|     el.appendChild(Dom.createEl('span', { | ||||
|       className: 'vjs-icon-placeholder' | ||||
|     }, { | ||||
|       'aria-hidden': true | ||||
|     })); | ||||
|     if (!this.player_.options_.experimentalSvgIcons) { | ||||
|       el.appendChild(Dom.createEl('span', { | ||||
|         className: 'vjs-icon-placeholder' | ||||
|       }, { | ||||
|         'aria-hidden': true | ||||
|       })); | ||||
|     } | ||||
|  | ||||
|     this.createControlTextEl(el); | ||||
|  | ||||
|   | ||||
| @@ -24,6 +24,7 @@ class CloseButton extends Button { | ||||
|   */ | ||||
|   constructor(player, options) { | ||||
|     super(player, options); | ||||
|     this.setIcon('cancel'); | ||||
|     this.controlText(options && options.controlText || this.localize('Close')); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
|  * | ||||
|  * @file component.js | ||||
|  */ | ||||
| import document from 'global/document'; | ||||
| import window from 'global/window'; | ||||
| import evented from './mixins/evented'; | ||||
| import stateful from './mixins/stateful'; | ||||
| @@ -527,6 +528,57 @@ class Component { | ||||
|     return currentChild; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Adds an SVG icon element to another element or component. | ||||
|    * | ||||
|    * @param {string} iconName | ||||
|    *        The name of icon. A list of all the icon names can be found at 'sandbox/svg-icons.html' | ||||
|    * | ||||
|    * @param {Element} [el=this.el()] | ||||
|    *        Element to set the title on. Defaults to the current Component's element. | ||||
|    * | ||||
|    * @return {Element} | ||||
|    *        The newly created icon element. | ||||
|    */ | ||||
|   setIcon(iconName, el = this.el()) { | ||||
|     // TODO: In v9 of video.js, we will want to remove font icons entirely. | ||||
|     // This means this check, as well as the others throughout the code, and | ||||
|     // the unecessary CSS for font icons, will need to be removed. | ||||
|     // See https://github.com/videojs/video.js/pull/8260 as to which components | ||||
|     // need updating. | ||||
|     if (!this.player_.options_.experimentalSvgIcons) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     const xmlnsURL = 'http://www.w3.org/2000/svg'; | ||||
|  | ||||
|     // The below creates an element in the format of: | ||||
|     // <span><svg><use>....</use></svg></span> | ||||
|     const iconContainer = Dom.createEl('span', { | ||||
|       className: 'vjs-icon-placeholder vjs-svg-icon' | ||||
|     }, {'aria-hidden': 'true'}); | ||||
|  | ||||
|     const svgEl = document.createElementNS(xmlnsURL, 'svg'); | ||||
|  | ||||
|     svgEl.setAttributeNS(null, 'viewBox', '0 0 512 512'); | ||||
|     const useEl = document.createElementNS(xmlnsURL, 'use'); | ||||
|  | ||||
|     svgEl.appendChild(useEl); | ||||
|     useEl.setAttributeNS(null, 'href', `#vjs-icon-${iconName}`); | ||||
|     iconContainer.appendChild(svgEl); | ||||
|  | ||||
|     // Replace a pre-existing icon if one exists. | ||||
|     if (this.iconIsSet_) { | ||||
|       el.replaceChild(iconContainer, el.querySelector('.vjs-icon-placeholder')); | ||||
|     } else { | ||||
|       el.appendChild(iconContainer); | ||||
|     } | ||||
|  | ||||
|     this.iconIsSet_ = true; | ||||
|  | ||||
|     return iconContainer; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Add a child `Component` inside the current `Component`. | ||||
|    * | ||||
|   | ||||
| @@ -25,6 +25,8 @@ class AudioTrackButton extends TrackButton { | ||||
|     options.tracks = player.audioTracks(); | ||||
|  | ||||
|     super(player, options); | ||||
|  | ||||
|     this.setIcon('audio'); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|   | ||||
| @@ -23,6 +23,7 @@ class FullscreenToggle extends Button { | ||||
|    */ | ||||
|   constructor(player, options) { | ||||
|     super(player, options); | ||||
|     this.setIcon('fullscreen-enter'); | ||||
|     this.on(player, 'fullscreenchange', (e) => this.handleFullscreenChange(e)); | ||||
|  | ||||
|     if (document[player.fsApi_.fullscreenEnabled] === false) { | ||||
| @@ -52,8 +53,10 @@ class FullscreenToggle extends Button { | ||||
|   handleFullscreenChange(event) { | ||||
|     if (this.player_.isFullscreen()) { | ||||
|       this.controlText('Exit Fullscreen'); | ||||
|       this.setIcon('fullscreen-exit'); | ||||
|     } else { | ||||
|       this.controlText('Fullscreen'); | ||||
|       this.setIcon('fullscreen-enter'); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -98,6 +98,8 @@ class MuteToggle extends Button { | ||||
|     const vol = this.player_.volume(); | ||||
|     let level = 3; | ||||
|  | ||||
|     this.setIcon('volume-high'); | ||||
|  | ||||
|     // in iOS when a player is loaded with muted attribute | ||||
|     // and volume is changed with a native mute button | ||||
|     // we want to make sure muted state is updated | ||||
| @@ -106,10 +108,13 @@ class MuteToggle extends Button { | ||||
|     } | ||||
|  | ||||
|     if (vol === 0 || this.player_.muted()) { | ||||
|       this.setIcon('volume-mute'); | ||||
|       level = 0; | ||||
|     } else if (vol < 0.33) { | ||||
|       this.setIcon('volume-low'); | ||||
|       level = 1; | ||||
|     } else if (vol < 0.67) { | ||||
|       this.setIcon('volume-medium'); | ||||
|       level = 2; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -28,6 +28,8 @@ class PictureInPictureToggle extends Button { | ||||
|   constructor(player, options) { | ||||
|     super(player, options); | ||||
|  | ||||
|     this.setIcon('picture-in-picture-enter'); | ||||
|  | ||||
|     this.on(player, ['enterpictureinpicture', 'leavepictureinpicture'], (e) => this.handlePictureInPictureChange(e)); | ||||
|     this.on(player, ['disablepictureinpicturechanged', 'loadedmetadata'], (e) => this.handlePictureInPictureEnabledChange(e)); | ||||
|     this.on(player, ['loadedmetadata', 'audioonlymodechange', 'audiopostermodechange'], () => this.handlePictureInPictureAudioModeChange()); | ||||
| @@ -101,8 +103,10 @@ class PictureInPictureToggle extends Button { | ||||
|    */ | ||||
|   handlePictureInPictureChange(event) { | ||||
|     if (this.player_.isInPictureInPicture()) { | ||||
|       this.setIcon('picture-in-picture-exit'); | ||||
|       this.controlText('Exit Picture-in-Picture'); | ||||
|     } else { | ||||
|       this.setIcon('picture-in-picture-enter'); | ||||
|       this.controlText('Picture-in-Picture'); | ||||
|     } | ||||
|     this.handlePictureInPictureEnabledChange(); | ||||
|   | ||||
| @@ -95,6 +95,7 @@ class PlayToggle extends Button { | ||||
|     this.removeClass('vjs-ended', 'vjs-paused'); | ||||
|     this.addClass('vjs-playing'); | ||||
|     // change the button text to "Pause" | ||||
|     this.setIcon('pause'); | ||||
|     this.controlText('Pause'); | ||||
|   } | ||||
|  | ||||
| @@ -110,6 +111,7 @@ class PlayToggle extends Button { | ||||
|     this.removeClass('vjs-playing'); | ||||
|     this.addClass('vjs-paused'); | ||||
|     // change the button text to "Play" | ||||
|     this.setIcon('play'); | ||||
|     this.controlText('Play'); | ||||
|   } | ||||
|  | ||||
| @@ -125,6 +127,7 @@ class PlayToggle extends Button { | ||||
|     this.removeClass('vjs-playing'); | ||||
|     this.addClass('vjs-ended'); | ||||
|     // change the button text to "Replay" | ||||
|     this.setIcon('replay'); | ||||
|     this.controlText('Replay'); | ||||
|  | ||||
|     // on the next seek remove the replay button | ||||
|   | ||||
| @@ -26,6 +26,7 @@ class PlayProgressBar extends Component { | ||||
|    */ | ||||
|   constructor(player, options) { | ||||
|     super(player, options); | ||||
|     this.setIcon('circle'); | ||||
|     this.update = Fn.throttle(Fn.bind_(this, this.update), Fn.UPDATE_REFRESH_INTERVAL); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -43,6 +43,8 @@ class SeekToLive extends Button { | ||||
|       className: 'vjs-seek-to-live-control vjs-control' | ||||
|     }); | ||||
|  | ||||
|     this.setIcon('circle', el); | ||||
|  | ||||
|     this.textEl_ = Dom.createEl('span', { | ||||
|       className: 'vjs-seek-to-live-text', | ||||
|       textContent: this.localize('LIVE') | ||||
|   | ||||
| @@ -17,6 +17,7 @@ class SkipBackward extends Button { | ||||
|     this.skipTime = this.getSkipBackwardTime(); | ||||
|  | ||||
|     if (this.skipTime && this.validOptions.includes(this.skipTime)) { | ||||
|       this.setIcon(`replay-${this.skipTime}`); | ||||
|       this.controlText(this.localize('Skip backward {1} seconds', [this.skipTime])); | ||||
|       this.show(); | ||||
|     } else { | ||||
|   | ||||
| @@ -17,6 +17,7 @@ class SkipForward extends Button { | ||||
|     this.skipTime = this.getSkipForwardTime(); | ||||
|  | ||||
|     if (this.skipTime && this.validOptions.includes(this.skipTime)) { | ||||
|       this.setIcon(`forward-${this.skipTime}`); | ||||
|       this.controlText(this.localize('Skip forward {1} seconds', [this.skipTime])); | ||||
|       this.show(); | ||||
|     } else { | ||||
|   | ||||
| @@ -26,6 +26,8 @@ class CaptionsButton extends TextTrackButton { | ||||
|    */ | ||||
|   constructor(player, options, ready) { | ||||
|     super(player, options, ready); | ||||
|  | ||||
|     this.setIcon('captions'); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|   | ||||
| @@ -30,6 +30,8 @@ class ChaptersButton extends TextTrackButton { | ||||
|   constructor(player, options, ready) { | ||||
|     super(player, options, ready); | ||||
|  | ||||
|     this.setIcon('chapters'); | ||||
|  | ||||
|     this.selectCurrentItem_ = () => { | ||||
|       this.items.forEach(item => { | ||||
|         item.selected(this.track_.activeCues[0] === item.cue); | ||||
|   | ||||
| @@ -27,6 +27,8 @@ class DescriptionsButton extends TextTrackButton { | ||||
|   constructor(player, options, ready) { | ||||
|     super(player, options, ready); | ||||
|  | ||||
|     this.setIcon('audio-description'); | ||||
|  | ||||
|     const tracks = player.textTracks(); | ||||
|     const changeHandler = Fn.bind_(this, this.handleTracksChange); | ||||
|  | ||||
|   | ||||
| @@ -32,8 +32,10 @@ class SubsCapsButton extends TextTrackButton { | ||||
|     // Although North America uses "captions" in most cases for | ||||
|     // "captions and subtitles" other locales use "subtitles" | ||||
|     this.label_ = 'subtitles'; | ||||
|     this.setIcon('subtitles'); | ||||
|     if (['en', 'en-us', 'en-ca', 'fr-ca'].indexOf(this.player_.language_) > -1) { | ||||
|       this.label_ = 'captions'; | ||||
|       this.setIcon('captions'); | ||||
|     } | ||||
|     this.menuButton_.controlText(toTitleCase(this.label_)); | ||||
|   } | ||||
|   | ||||
| @@ -18,11 +18,15 @@ class SubsCapsMenuItem extends TextTrackMenuItem { | ||||
|     const parentSpan = el.querySelector('.vjs-menu-item-text'); | ||||
|  | ||||
|     if (this.options_.track.kind === 'captions') { | ||||
|       parentSpan.appendChild(createEl('span', { | ||||
|         className: 'vjs-icon-placeholder' | ||||
|       }, { | ||||
|         'aria-hidden': true | ||||
|       })); | ||||
|       if (this.player_.options_.experimentalSvgIcons) { | ||||
|         this.setIcon('captions', el); | ||||
|       } else { | ||||
|         parentSpan.appendChild(createEl('span', { | ||||
|           className: 'vjs-icon-placeholder' | ||||
|         }, { | ||||
|           'aria-hidden': true | ||||
|         })); | ||||
|       } | ||||
|       parentSpan.appendChild(createEl('span', { | ||||
|         className: 'vjs-control-text', | ||||
|         // space added as the text will visually flow with the | ||||
|   | ||||
| @@ -25,6 +25,8 @@ class SubtitlesButton extends TextTrackButton { | ||||
|    */ | ||||
|   constructor(player, options, ready) { | ||||
|     super(player, options, ready); | ||||
|  | ||||
|     this.setIcon('subtitles'); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|   | ||||
| @@ -21,6 +21,8 @@ class VolumeLevel extends Component { | ||||
|       className: 'vjs-volume-level' | ||||
|     }); | ||||
|  | ||||
|     this.setIcon('circle', el); | ||||
|  | ||||
|     el.appendChild(super.createEl('span', { | ||||
|       className: 'vjs-control-text' | ||||
|     })); | ||||
|   | ||||
| @@ -160,6 +160,17 @@ class MenuButton extends Component { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Overwrites the `setIcon` method from `Component`. | ||||
|    * In this case, we want the icon to be appended to the menuButton. | ||||
|    * | ||||
|    * @param {string} name | ||||
|    *         The icon name to be added. | ||||
|    */ | ||||
|   setIcon(name) { | ||||
|     super.setIcon(name, this.menuButton_.el_); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Allow sub components to stack CSS class names for the wrapper element | ||||
|    * | ||||
|   | ||||
| @@ -69,10 +69,17 @@ class MenuItem extends ClickableComponent { | ||||
|     }, props), attrs); | ||||
|  | ||||
|     // swap icon with menu item text. | ||||
|     el.replaceChild(createEl('span', { | ||||
|     const menuItemEl = createEl('span', { | ||||
|       className: 'vjs-menu-item-text', | ||||
|       textContent: this.localize(this.options_.label) | ||||
|     }), el.querySelector('.vjs-icon-placeholder')); | ||||
|     }); | ||||
|  | ||||
|     // If using SVG icons, the element with vjs-icon-placeholder will be added separately. | ||||
|     if (this.player_.options_.experimentalSvgIcons) { | ||||
|       el.appendChild(menuItemEl); | ||||
|     } else { | ||||
|       el.replaceChild(menuItemEl, el.querySelector('.vjs-icon-placeholder')); | ||||
|     } | ||||
|  | ||||
|     return el; | ||||
|   } | ||||
|   | ||||
| @@ -35,6 +35,7 @@ import {getMimetype, findMimetype} from './utils/mimetypes'; | ||||
| import {hooks} from './utils/hooks'; | ||||
| import {isObject} from './utils/obj'; | ||||
| import keycode from 'keycode'; | ||||
| import icons from '../images/icons.svg'; | ||||
|  | ||||
| // The following imports are used only to ensure that the corresponding modules | ||||
| // are always included in the video.js package. Importing the modules will | ||||
| @@ -307,6 +308,7 @@ class Player extends Component { | ||||
|    */ | ||||
|   constructor(tag, options, ready) { | ||||
|     // Make sure tag ID exists | ||||
|     // also here.. probably better | ||||
|     tag.id = tag.id || options.id || `vjs_video_${Guid.newGUID()}`; | ||||
|  | ||||
|     // Set Options | ||||
| @@ -516,6 +518,25 @@ class Player extends Component { | ||||
|  | ||||
|     this.playbackRates(options.playbackRates); | ||||
|  | ||||
|     if (options.experimentalSvgIcons) { | ||||
|       // Add SVG Sprite to the DOM | ||||
|       const parser = new window.DOMParser(); | ||||
|       const parsedSVG = parser.parseFromString(icons, 'image/svg+xml'); | ||||
|       const errorNode = parsedSVG.querySelector('parsererror'); | ||||
|  | ||||
|       if (errorNode) { | ||||
|         log.warn('Failed to load SVG Icons. Falling back to Font Icons.'); | ||||
|         this.options_.experimentalSvgIcons = null; | ||||
|       } else { | ||||
|         const sprite = parsedSVG.documentElement; | ||||
|  | ||||
|         sprite.style.display = 'none'; | ||||
|         this.el_.appendChild(sprite); | ||||
|  | ||||
|         this.addClass('vjs-svg-icons-enabled'); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this.initChildren(); | ||||
|  | ||||
|     // Set isAudio based on whether or not an audio tag was used | ||||
|   | ||||
| @@ -28,6 +28,11 @@ QUnit.module('Component', { | ||||
|     Component.registerComponent('TestComponent2', TestComponent2); | ||||
|     Component.registerComponent('TestComponent3', TestComponent3); | ||||
|     Component.registerComponent('TestComponent4', TestComponent4); | ||||
|  | ||||
|     sinon.stub(window.DOMParser.prototype, 'parseFromString').returns({ | ||||
|       querySelector: () => false, | ||||
|       documentElement: document.createElement('span') | ||||
|     }); | ||||
|   }, | ||||
|   beforeEach() { | ||||
|     this.clock = sinon.useFakeTimers(); | ||||
| @@ -42,6 +47,8 @@ QUnit.module('Component', { | ||||
|     delete Component.components_.TestComponent2; | ||||
|     delete Component.components_.TestComponent3; | ||||
|     delete Component.components_.TestComponent4; | ||||
|  | ||||
|     window.DOMParser.prototype.parseFromString.restore(); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| @@ -176,6 +183,90 @@ QUnit.test('should allow for children that are elements', function(assert) { | ||||
|   /* eslint-enable no-unused-vars */ | ||||
| }); | ||||
|  | ||||
| QUnit.test('setIcon should not do anything when experimentalSvgIcons is not set', function(assert) { | ||||
|   const comp = new Component(this.player); | ||||
|   const iconName = 'test'; | ||||
|  | ||||
|   assert.equal(comp.setIcon(iconName), null, 'we should not return anything'); | ||||
|  | ||||
|   comp.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('setIcon should return the correct SVG', function(assert) { | ||||
|   const player = TestHelpers.makePlayer({experimentalSvgIcons: true}); | ||||
|  | ||||
|   const comp = new Component(player); | ||||
|   const iconName = 'test'; | ||||
|  | ||||
|   // Elements and children of the icon. | ||||
|   const spanEl = comp.setIcon(iconName); | ||||
|   const svgEl = spanEl.childNodes[0]; | ||||
|   const useEl = svgEl.childNodes[0]; | ||||
|  | ||||
|   // Ensure all elements are of the correct type. | ||||
|   assert.equal(spanEl.nodeName.toLowerCase(), 'span', 'parent element should be a <span>'); | ||||
|   assert.equal(svgEl.nodeName.toLowerCase(), 'svg', 'first child element should be a <svg>'); | ||||
|   assert.equal(useEl.nodeName.toLowerCase(), 'use', 'second child element should be a <use>'); | ||||
|  | ||||
|   // Ensure the classname and attributes are set correctly on the elements. | ||||
|   assert.equal(spanEl.className, 'vjs-icon-placeholder vjs-svg-icon', 'span should have icon class'); | ||||
|   assert.equal(svgEl.getAttribute('viewBox'), '0 0 512 512', 'svg should have viewBox set'); | ||||
|   assert.equal(useEl.getAttribute('href'), '#vjs-icon-test', 'use should have an href set with the correct icon url'); | ||||
|  | ||||
|   assert.equal(comp.iconIsSet_, true, 'the component iconIsSet_ property is set to true'); | ||||
|  | ||||
|   player.dispose(); | ||||
|   comp.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('setIcon should call replaceChild if an icon already exists', function(assert) { | ||||
|   const player = TestHelpers.makePlayer({experimentalSvgIcons: true}); | ||||
|  | ||||
|   const comp = new Component(player); | ||||
|  | ||||
|   const appendSpy = sinon.spy(comp.el(), 'appendChild'); | ||||
|   const replaceSpy = sinon.spy(comp.el(), 'replaceChild'); | ||||
|  | ||||
|   // Elements and children of the icon. | ||||
|   let spanEl = comp.setIcon('test-1'); | ||||
|   let svgEl = spanEl.childNodes[0]; | ||||
|   let useEl = svgEl.childNodes[0]; | ||||
|  | ||||
|   // ensure first setIcon call works correctly | ||||
|   assert.equal(useEl.getAttribute('href'), '#vjs-icon-test-1', 'use should have an href set with the correct icon url'); | ||||
|   assert.ok(appendSpy.calledOnce, '`appendChild` has been called'); | ||||
|  | ||||
|   spanEl = comp.setIcon('test-2'); | ||||
|   svgEl = spanEl.childNodes[0]; | ||||
|   useEl = svgEl.childNodes[0]; | ||||
|  | ||||
|   assert.equal(useEl.getAttribute('href'), '#vjs-icon-test-2', 'use should have an href set with the correct icon url'); | ||||
|   assert.ok(replaceSpy.calledOnce, '`replaceChild` has been called'); | ||||
|  | ||||
|   appendSpy.restore(); | ||||
|   replaceSpy.restore(); | ||||
|  | ||||
|   player.dispose(); | ||||
|   comp.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('setIcon should append a child to the element passed into the method', function(assert) { | ||||
|   const player = TestHelpers.makePlayer({experimentalSvgIcons: true}); | ||||
|  | ||||
|   const comp = new Component(player); | ||||
|   const el = document.createElement('div'); | ||||
|  | ||||
|   comp.setIcon('test', el); | ||||
|   const spanEl = el.childNodes[0]; | ||||
|   const svgEl = spanEl.childNodes[0]; | ||||
|   const useEl = svgEl.childNodes[0]; | ||||
|  | ||||
|   assert.equal(useEl.getAttribute('href'), '#vjs-icon-test', 'href set on the element passed in'); | ||||
|  | ||||
|   player.dispose(); | ||||
|   comp.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('addChild should throw if the child does not exist', function(assert) { | ||||
|   const comp = new Component(this.player); | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,8 @@ import MenuItem from '../../src/js/menu/menu-item.js'; | ||||
| import TestHelpers from './test-helpers.js'; | ||||
| import * as Events from '../../src/js/utils/events.js'; | ||||
| import sinon from 'sinon'; | ||||
| import window from 'global/window'; | ||||
| import document from 'global/document'; | ||||
|  | ||||
| QUnit.module('MenuButton'); | ||||
|  | ||||
| @@ -156,6 +158,33 @@ QUnit.test('should add or remove role menu for accessibility purpose', function( | ||||
|   player.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('setIcon should apply a child to the Button component', function(assert) { | ||||
|   // Stub a successful parsing of the SVG sprite. | ||||
|   sinon.stub(window.DOMParser.prototype, 'parseFromString').returns({ | ||||
|     querySelector: () => false, | ||||
|     documentElement: document.createElement('span') | ||||
|   }); | ||||
|  | ||||
|   const player = TestHelpers.makePlayer({experimentalSvgIcons: true}); | ||||
|   const menuButton = new MenuButton(player); | ||||
|  | ||||
|   menuButton.createItems = () => []; | ||||
|   menuButton.update(); | ||||
|  | ||||
|   menuButton.setIcon('test'); | ||||
|  | ||||
|   const buttonEl = menuButton.menuButton_.el_; | ||||
|   const spanEl = buttonEl.getElementsByClassName('vjs-svg-icon')[0]; | ||||
|   const svgEl = spanEl.childNodes[0]; | ||||
|   const useEl = svgEl.childNodes[0]; | ||||
|  | ||||
|   assert.equal(useEl.getAttribute('href'), '#vjs-icon-test', 'use should have an href set with the correct icon url'); | ||||
|  | ||||
|   window.DOMParser.prototype.parseFromString.restore(); | ||||
|   menuButton.dispose(); | ||||
|   player.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('should remove old event listeners when the menu item adds to the new menu', function(assert) { | ||||
|   const player = TestHelpers.makePlayer(); | ||||
|   const menuButton = new MenuButton(player, {}); | ||||
|   | ||||
| @@ -967,6 +967,39 @@ QUnit.test('should add a touch-enabled classname when touch is supported', funct | ||||
|   player.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('should add a svg-icons-enabled classname when svg icons are supported', function(assert) { | ||||
|   // Stub a successful parsing of the SVG sprite. | ||||
|   sinon.stub(window.DOMParser.prototype, 'parseFromString').returns({ | ||||
|     querySelector: () => false, | ||||
|     documentElement: document.createElement('span') | ||||
|   }); | ||||
|  | ||||
|   assert.expect(1); | ||||
|  | ||||
|   const player = TestHelpers.makePlayer({experimentalSvgIcons: true}); | ||||
|  | ||||
|   assert.ok(player.hasClass('vjs-svg-icons-enabled'), 'svg-icons-enabled classname added'); | ||||
|  | ||||
|   window.DOMParser.prototype.parseFromString.restore(); | ||||
|   player.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('should revert to font icons if the SVG sprite cannot be loaded', function(assert) { | ||||
|   // Stub an unsuccessful parsing of the SVG sprite. | ||||
|   sinon.stub(window.DOMParser.prototype, 'parseFromString').returns({ | ||||
|     querySelector: () => true | ||||
|   }); | ||||
|  | ||||
|   assert.expect(1); | ||||
|  | ||||
|   const player = TestHelpers.makePlayer({experimentalSvgIcons: true}); | ||||
|  | ||||
|   assert.ok(!player.hasClass('vjs-svg-icons-enabled'), 'svg-icons-enabled classname was not added'); | ||||
|  | ||||
|   window.DOMParser.prototype.parseFromString.restore(); | ||||
|   player.dispose(); | ||||
| }); | ||||
|  | ||||
| QUnit.test('should not add a touch-enabled classname when touch is not supported', function(assert) { | ||||
|   assert.expect(1); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user