├── .babelrc ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .stylelintrc ├── Gruntfile.js ├── README.md ├── RELEASE.md ├── changelog.md ├── demo ├── a11y.html ├── airplay.html ├── chromecast.html ├── demo.css ├── end.html ├── favicon.ico ├── index.html ├── markers.html ├── markersrolls.html ├── mediaelement.vtt ├── mejs-a11y-icons.svg ├── mejs-controls.svg ├── mejs-jump-forward.svg ├── mejs-quality.svg ├── mejs-skip-back.svg ├── multiple1.html ├── multiple2.html ├── playlist.html ├── postroll.html ├── preview.html ├── quality.html ├── speed.html ├── vast_sample.xml └── vrview.html ├── dist ├── a11y │ ├── a11y-i18n.js │ ├── a11y.css │ ├── a11y.js │ ├── a11y.min.css │ ├── a11y.min.js │ ├── audio-description-icon.svg │ └── video-description-icon.svg ├── ads-vast-vpaid │ ├── ads-vast-vpaid.js │ └── ads-vast-vpaid.min.js ├── ads │ ├── ads-i18n.js │ ├── ads.css │ ├── ads.js │ ├── ads.min.css │ └── ads.min.js ├── airplay │ ├── airplay.css │ ├── airplay.js │ ├── airplay.min.css │ ├── airplay.min.js │ ├── airplay.png │ └── airplay.svg ├── chromecast │ ├── chromecast-i18n.js │ ├── chromecast.css │ ├── chromecast.js │ ├── chromecast.min.css │ ├── chromecast.min.js │ ├── chromecast.png │ └── chromecast.svg ├── context-menu │ ├── context-menu-i18n.js │ ├── context-menu.css │ ├── context-menu.js │ ├── context-menu.min.css │ └── context-menu.min.js ├── facebook-pixel │ ├── facebook-pixel.js │ └── facebook-pixel.min.js ├── google-analytics │ ├── google-analytics.js │ └── google-analytics.min.js ├── google-tag-manager │ ├── google-tag-manager.js │ └── google-tag-manager.min.js ├── jump-forward │ ├── jump-forward-i18n.js │ ├── jump-forward.js │ ├── jump-forward.min.js │ └── jumpforward.svg ├── loop │ ├── loop-i18n.js │ ├── loop.css │ ├── loop.js │ ├── loop.min.css │ ├── loop.min.js │ ├── loop.png │ └── loop.svg ├── markers │ ├── markers.js │ └── markers.min.js ├── markersrolls │ ├── markersrolls.js │ └── markersrolls.min.js ├── picture-in-picture │ ├── picture-in-picture-i18n.js │ └── picture-in-picture.svg ├── playlist │ ├── playlist-controls.svg │ ├── playlist-i18n.js │ ├── playlist.css │ ├── playlist.js │ ├── playlist.min.css │ └── playlist.min.js ├── postroll │ ├── postroll-i18n.js │ ├── postroll.css │ ├── postroll.js │ ├── postroll.min.css │ └── postroll.min.js ├── preview │ ├── preview.js │ └── preview.min.js ├── quality │ ├── quality-i18n.js │ ├── quality.css │ ├── quality.js │ ├── quality.min.css │ └── quality.min.js ├── skip-back │ ├── skip-back-i18n.js │ ├── skip-back.js │ ├── skip-back.min.js │ └── skipback.svg ├── snapshot │ ├── snapshot-i18n.js │ └── snapshot.png ├── source-chooser │ ├── settings.png │ ├── settings.svg │ ├── source-chooser-i18n.js │ ├── source-chooser.css │ ├── source-chooser.js │ ├── source-chooser.min.css │ └── source-chooser.min.js ├── speed │ ├── speed-i18n.js │ ├── speed.css │ ├── speed.js │ ├── speed.min.css │ └── speed.min.js ├── stop │ ├── stop-i18n.js │ ├── stop.css │ ├── stop.js │ ├── stop.min.css │ ├── stop.min.js │ └── stop.svg └── vrview │ ├── cardboard.png │ ├── cardboard.svg │ ├── vrview.css │ ├── vrview.js │ ├── vrview.min.css │ └── vrview.min.js ├── docs ├── a11y.md ├── ads-vast.md ├── ads.md ├── airplay.md ├── chromecast.md ├── context-menu.md ├── facebook-pixel.md ├── google-analytics.md ├── google-tag-manager.md ├── jump-forward.md ├── loop.md ├── markers.md ├── markersrolls.md ├── picture-in-picture.md ├── playlist.md ├── postroll.md ├── preview.md ├── quality.md ├── skip-back.md ├── snapshot.md ├── source-chooser.md ├── speed.md ├── stop.md └── vrview.md ├── package-lock.json ├── package.json └── src ├── .DS_Store ├── a11y ├── a11y-i18n.js ├── a11y.css ├── a11y.js ├── audio-description-icon.svg └── video-description-icon.svg ├── ads-vast-vpaid └── ads-vast-vpaid.js ├── ads ├── ads-i18n.js ├── ads.css └── ads.js ├── airplay ├── airplay.css ├── airplay.js ├── airplay.png └── airplay.svg ├── chromecast ├── chromecast.css ├── chromecast.js ├── chromecast.png ├── chromecast.svg └── player.js ├── context-menu ├── context-menu-i18n.js ├── context-menu.css └── context-menu.js ├── demo └── mejs-controls.svg ├── facebook-pixel └── facebook-pixel.js ├── google-analytics └── google-analytics.js ├── google-tag-manager └── google-tag-manager.js ├── header.js ├── jump-forward ├── jump-forward-i18n.js ├── jump-forward.js └── jumpforward.svg ├── loop ├── loop-i18n.js ├── loop.css ├── loop.js ├── loop.png └── loop.svg ├── markers └── markers.js ├── markersrolls └── markersrolls.js ├── picture-in-picture ├── picture-in-picture-i18n.js ├── picture-in-picture.css ├── picture-in-picture.js └── picture-in-picture.svg ├── playlist ├── playlist-controls.svg ├── playlist-i18n.js ├── playlist.css └── playlist.js ├── postroll ├── postroll-i18n.js ├── postroll.css └── postroll.js ├── preview └── preview.js ├── quality ├── quality-i18n.js ├── quality.css └── quality.js ├── skip-back ├── skip-back-i18n.js ├── skip-back.js └── skipback.svg ├── snapshot ├── Gruntfile.js ├── README.md ├── _config.yml ├── package-lock.json ├── package.json ├── snapshot-i18n.js ├── snapshot.css ├── snapshot.js └── snapshot.png ├── source-chooser ├── settings.png ├── settings.svg ├── source-chooser-i18n.js ├── source-chooser.css └── source-chooser.js ├── speed ├── speed-i18n.js ├── speed.css └── speed.js ├── stop ├── stop-i18n.js ├── stop.css ├── stop.js └── stop.svg └── vrview ├── cardboard.png ├── cardboard.svg ├── vrview.css └── vrview.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "comments": false, 3 | "presets": [ 4 | ["env", { 5 | "targets": { 6 | "browsers": ["last 5 versions", "ie > 10", "ios > 7", "android > 3"] 7 | } 8 | }] 9 | ] 10 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "browser": true, 5 | "mocha": true, 6 | "node": true, 7 | "jquery": true 8 | }, 9 | "extends": "eslint:recommended", 10 | "parserOptions": { 11 | "ecmaVersion": 6, 12 | "sourceType": "module" 13 | }, 14 | "rules": { 15 | "no-console": 0, 16 | "no-undef" : 0, 17 | "no-case-declarations": 0 18 | } 19 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.jar binary 4 | *.mp3 binary 5 | *.mp4 binary 6 | *.ogv binary 7 | *.png binary 8 | *.webm binary 9 | *.swf binary 10 | *.swc binary 11 | *.fla binary 12 | *.xap binary 13 | 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | local-build 3 | # PhpStorm/WebStorm configuration 4 | .idea/* 5 | coverage 6 | npm-debug.log 7 | tmp -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "stylelint-order" 4 | ], 5 | "rules": { 6 | "color-hex-case": ["lower"], 7 | "color-hex-length": "short", 8 | "declaration-block-no-duplicate-properties": [ 9 | true, 10 | { 11 | "ignore": [ 12 | "consecutive-duplicates-with-different-values" 13 | ] 14 | } 15 | ], 16 | "function-comma-space-after": "always-single-line", 17 | "function-comma-space-before": "never", 18 | "indentation": 4, 19 | "length-zero-no-unit": true, 20 | "number-leading-zero": "always", 21 | "number-no-trailing-zeros": true, 22 | "order/order": [ 23 | "custom-properties", 24 | "declarations" 25 | ], 26 | "order/properties-alphabetical-order": true, 27 | "property-case": "lower", 28 | "property-no-unknown": true, 29 | "selector-combinator-space-after": "always", 30 | "selector-combinator-space-before": "always", 31 | "selector-list-comma-newline-after": "always", 32 | "shorthand-property-no-redundant-values": true, 33 | "string-quotes": "single" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | 2 | Instructions for the Maintainer 3 | 4 | ********************** 5 | PREPARING A RELEASE - first steps, command line 6 | ********************** 7 | 8 | - Create a dedicated branch for the release; 9 | 10 | git checkout master 11 | git checkout -b release_4.X.X 12 | 13 | - Run basic npm security checks; 14 | 15 | npm audit fix 16 | 17 | - update version 18 | 19 | package-lock.json: "version": "2.5.x", 20 | package.json: "version": "2.5.x", 21 | 22 | - check with shell command; 23 | 24 | head -4 package*.json | grep version 25 | 26 | 27 | - Update changelog.md 28 | 29 | - Build release; 30 | 31 | grunt 32 | 33 | - add/commit/push all including build/ 34 | 35 | ``` 36 | git add --all 37 | git commit -am "release 4.X.X" 38 | git push 39 | ``` 40 | 41 | ********************** 42 | PREPARING A RELEASE - second step on github.com 43 | ********************** 44 | 45 | - prepare a new release using changelog.md 46 | 47 | ********************** 48 | PREPARING A RELEASE - third step on npmjs.com 49 | ********************** 50 | -------------------------------------------------------------------------------- /demo/a11y.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MediaElement.js 4.2 - Accessibility Plugin 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |

Accessibility Plugin

18 |

Back to Main

19 | 20 |

Video Player (w/o Voice-Over)

21 |
22 | 30 |
31 |
32 | 33 | 34 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /demo/airplay.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MediaElement.js 3.0 - AirPlay Plugin 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |

AirPlay Plugin

19 |

Back to Main

20 | 21 |

This plugin displays a button to interact with an AirPlay device, if available.

22 | 23 |

It detects if media tag has the x-webkit-airplay attribute set as allow; if not, the plugin sets it, to provide also native support.

24 | 25 |

NOTE: AirPlay only supports MP4, M(PEG)-DASH and HLS streaming natively.

26 | 27 |

Video Player

28 |
29 | 32 |
33 | 34 |

API

35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
ParameterTypeDefaultDescription
airPlayTitlestringnullAirPlay button title for ARIA purposes
53 |
54 | 55 | 56 | 61 | 62 | -------------------------------------------------------------------------------- /demo/demo.css: -------------------------------------------------------------------------------- 1 | #container { 2 | padding: 0 20px 50px; 3 | max-width: 800px; 4 | } 5 | .footnote { 6 | font-size: 0.7em; 7 | } 8 | table { 9 | border-collapse: collapse; 10 | max-width: 750px; 11 | } 12 | th, td { 13 | border-bottom: 1px solid #ddd; 14 | text-align: center; 15 | width: 120px; 16 | } 17 | th { 18 | background-color: #000; 19 | color: white; 20 | } 21 | a { 22 | overflow-wrap: break-word; 23 | word-wrap: break-word; 24 | -ms-word-break: break-all; 25 | word-break: break-all; 26 | word-break: break-word; 27 | -ms-hyphens: auto; 28 | -moz-hyphens: auto; 29 | -webkit-hyphens: auto; 30 | hyphens: auto; 31 | } 32 | td:last-child { 33 | width: 400px; 34 | text-align: left; 35 | } 36 | tr:nth-child(even) { 37 | background-color: #f2f2f2 38 | } 39 | pre { 40 | white-space: pre-wrap; 41 | tab-size: 2; 42 | background: black; 43 | color: white; 44 | max-width: 750px; 45 | } 46 | pre[data-lang]::before { 47 | content: attr(data-lang); 48 | display: block; 49 | background-color: #FFA500; 50 | background-image: -webkit-linear-gradient(top, #FFA500, #D67E21); 51 | background-image: linear-gradient(to bottom, #FFA500, #D67E21); 52 | padding: 10px; 53 | } 54 | code { 55 | font-family: "Courier New", Courier, monospace; 56 | padding: 10px 20px; 57 | display: inline-block; 58 | } -------------------------------------------------------------------------------- /demo/end.html: -------------------------------------------------------------------------------- 1 | 21 |
22 |
23 |

You have reached the end of your media.

24 |

You can insert any HTML but just consider that this is not an iframe so 25 | whatever styles you intend to use must be restricted for this HTML piece only.

26 |
27 |
28 | -------------------------------------------------------------------------------- /demo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/demo/favicon.ico -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MediaElement.js 3.0 - Plugins 7 | 8 | 9 | 10 | 11 | 12 | 13 | 60 | 61 | 62 | 63 |
64 |
65 |

66 |

Following is the list of examples of the available plugins for MediaElement player

67 |
68 |
69 |
70 | 84 |
85 |
86 | 87 |
88 | 89 | 90 | -------------------------------------------------------------------------------- /demo/mediaelement.vtt: -------------------------------------------------------------------------------- 1 | WEBVTT 2 | 3 | 0 4 | 00:00:00,1 --> 00:00:04 5 | HTML5 video and audio was supposed to be awesome, powerful, and fun. 6 | 7 | 1 8 | 00:00:04 --> 00:00:07 9 | But browser vendors couldn't agree on a codec 10 | 11 | 2 12 | 00:00:07 --> 00:00:10 13 | and older browsers don't support video at all. 14 | 15 | 3 16 | 00:00:10 --> 00:00:12 17 | This means video src="myfile.mp4" doesn't work ... 18 | 19 | 4 20 | 00:00:12 --> 00:00:14 21 | until now. 22 | 23 | 5 24 | 00:00:14 --> 00:00:18 25 | Introducing MediaElement.js, an HTML5 video and audio player 26 | 27 | 6 28 | 00:00:18 --> 00:00:21 29 | that looks and works the same in every browser (even iPhone and Android). 30 | 31 | 7 32 | 00:00:21 --> 00:00:24 33 | For older browsers, it has custom Flash plugins 34 | 35 | 8 36 | 00:00:24 --> 00:00:27 37 | that fully replicate the HTML5 MediaElement API 38 | 39 | 9 40 | 00:00:27 --> 00:00:30 41 | so you can build a consistent control UI using just HTML and CSS. 42 | 43 | 10 44 | 00:00:30 --> 00:00:33 45 | MediaElement.js even supports newer standards 46 | 47 | 11 48 | 00:00:33 --> 00:00:36 49 | like the <track> element that enables the subtitles you're reading right now. 50 | 51 | 12 52 | 00:00:36 --> 00:00:39 53 | Also, new media formats like M(PEG)-DASH and HLS can be played with MediaElement. 54 | 55 | 13 56 | 00:00:39 --> 00:00:42 57 | As a bonus, the Flash fallbacks allow you to use FLV and RTMP files. 58 | 59 | 14 60 | 00:00:42 --> 00:00:45 61 | Hope you like it. -------------------------------------------------------------------------------- /demo/mejs-jump-forward.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 30 10 | 11 | 12 | -------------------------------------------------------------------------------- /demo/mejs-skip-back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 30 10 | 11 | 12 | -------------------------------------------------------------------------------- /demo/postroll.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MediaElement.js 3.0 - Postroll Plugin 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |

Postroll Plugin

19 |

Back to Main

20 | 21 |

This plugin allows the injection of any HTML content in an independent layer once the media has ended.

22 | 23 |

Video Player

24 |
25 | 29 |
30 | 31 |

The following snippet shows the proper HTML to activate the postroll functionality.

32 | 33 |
34 |         
35 | <video width="640" height="360" preload="none" poster="/path/to/poster.jpg">
36 | 
37 |     <source src="/path/to/media.mp4" type="video/mp4">
38 |     <link href="/path/to/postroll" rel="postroll">
39 | 
40 | </video>
41 |         
42 |         
43 | 44 |

API

45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
ParameterTypeDefaultDescription
postrollCloseTextstringnullTitle for button to Postroll layer for WARIA purposes
63 |
64 | 65 | 66 | 71 | 72 | -------------------------------------------------------------------------------- /demo/speed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MediaElement.js 3.0 - Speed Plugin 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |

Speed Plugin

20 |

Back to Main

21 | 22 |

This plugin allows the generation of a menu with different video/audio speed.

23 | 24 |

Video Player

25 | 26 |
27 |

Video Player 1

28 | 31 |

Video Player 2

32 | 35 |
36 |
37 | 38 | 39 | 40 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /dist/a11y/a11y-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.de !== undefined) { 4 | mejs.i18n.de['mejs.a11y-audio-description'] = 'Audio Deskription An/Aus'; 5 | mejs.i18n.de['mejs.a11y-video-description'] = 'Video Deskription An/Aus'; 6 | } 7 | 8 | if (mejs.i18n.fr !== undefined) { 9 | mejs.i18n.fr['mejs.a11y-audio-description'] = 'Audio-description étendue On/Off'; 10 | mejs.i18n.fr['mejs.a11y-video-description'] = 'Langue des signes On/Off'; 11 | } 12 | 13 | if (mejs.i18n.nl !== undefined) { 14 | mejs.i18n.nl['mejs.a11y-audio-description'] = 'Audiobeschrijving Aan/Uit'; 15 | mejs.i18n.nl['mejs.a11y-video-description'] = 'Gebarentaal Aan/Uit'; 16 | } 17 | 18 | if (mejs.i18n.tr !== undefined) { 19 | mejs.i18n.tr['mejs.a11y-audio-description'] = 'Sesli betimleme değiştir'; 20 | mejs.i18n.tr['mejs.a11y-video-description'] = 'Görüntülü betimleme değişti'; 21 | } 22 | -------------------------------------------------------------------------------- /dist/a11y/a11y.css: -------------------------------------------------------------------------------- 1 | .mejs-volume-button.hidden, 2 | .mejs__volume-button.hidden { 3 | display: none; 4 | } 5 | 6 | .mejs-audio-description-player, 7 | .mejs__audio-description-player { 8 | display: none; 9 | } 10 | -------------------------------------------------------------------------------- /dist/a11y/a11y.min.css: -------------------------------------------------------------------------------- 1 | .mejs-audio-description-player,.mejs-volume-button.hidden,.mejs__audio-description-player,.mejs__volume-button.hidden{display:none} -------------------------------------------------------------------------------- /dist/a11y/audio-description-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dist/a11y/video-description-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dist/ads/ads.css: -------------------------------------------------------------------------------- 1 | .mejs__ads > a, 2 | .mejs-ads > a { 3 | display: block; 4 | height: 100%; 5 | position: absolute; 6 | right: 0; 7 | top: 0; 8 | width: 100%; 9 | } 10 | .mejs__ads-skip-block, 11 | .mejs-ads-skip-block { 12 | background: #000; 13 | background: rgba(0, 0, 0, 0.5); 14 | color: #fff; 15 | display: block; 16 | padding: 10px; 17 | position: absolute; 18 | right: 0; 19 | top: 0; 20 | } 21 | .mejs__ads-skip-button, 22 | .mejs-ads-skip-button { 23 | cursor: pointer; 24 | } 25 | .mejs__ads-skip-button:hover, 26 | .mejs-ads-skip-button:hover { 27 | text-decoration: underline; 28 | } 29 | -------------------------------------------------------------------------------- /dist/ads/ads.min.css: -------------------------------------------------------------------------------- 1 | .mejs-ads>a,.mejs__ads>a{display:block;height:100%;position:absolute;right:0;top:0;width:100%}.mejs-ads-skip-block,.mejs__ads-skip-block{background:#000;background:rgba(0,0,0,.5);color:#fff;display:block;padding:10px;position:absolute;right:0;top:0}.mejs-ads-skip-button,.mejs__ads-skip-button{cursor:pointer}.mejs-ads-skip-button:hover,.mejs__ads-skip-button:hover{text-decoration:underline} -------------------------------------------------------------------------------- /dist/airplay/airplay.css: -------------------------------------------------------------------------------- 1 | .mejs__airplay-button > button, 2 | .mejs-airplay-button > button { 3 | background: url('airplay.svg') no-repeat 0 4px; 4 | } 5 | 6 | .mejs__airplay-button > button .fill, 7 | .mejs-airplay-button > button .fill { 8 | fill: #fff; 9 | } 10 | 11 | .mejs__airplay-button > button.active .fill, 12 | .mejs-airplay-button > button.active .fill { 13 | fill: #66a8cc; 14 | } 15 | -------------------------------------------------------------------------------- /dist/airplay/airplay.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i'; 30 | 31 | button.addEventListener('click', function () { 32 | t.media.originalNode.webkitShowPlaybackTargetPicker(); 33 | }); 34 | 35 | var acceptAirPlay = t.media.originalNode.getAttribute('x-webkit-airplay'); 36 | if (!acceptAirPlay || acceptAirPlay !== 'allow') { 37 | t.media.originalNode.setAttribute('x-webkit-airplay', 'allow'); 38 | } 39 | 40 | t.media.originalNode.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', function () { 41 | var name = t.media.originalNode.webkitCurrentPlaybackTargetIsWireless ? 'Started' : 'Stopped', 42 | status = t.media.originalNode.webkitCurrentPlaybackTargetIsWireless ? 'active' : '', 43 | icon = button.querySelector('button'), 44 | event = mejs.Utils.createEvent('airplay' + name, t.media); 45 | t.media.dispatchEvent(event); 46 | 47 | if (status === 'active') { 48 | mejs.Utils.addClass(icon, 'active'); 49 | } else { 50 | mejs.Utils.removeClass(icon, 'active'); 51 | } 52 | }); 53 | 54 | t.media.originalNode.addEventListener('webkitplaybacktargetavailabilitychanged', function (e) { 55 | if (e.availability === 'available') { 56 | t.addControlElement(button, 'airplay'); 57 | } 58 | }); 59 | } 60 | }); 61 | 62 | },{}]},{},[1]); 63 | -------------------------------------------------------------------------------- /dist/airplay/airplay.min.css: -------------------------------------------------------------------------------- 1 | .mejs-airplay-button>button,.mejs__airplay-button>button{background:url(airplay.svg) no-repeat 0 4px}.mejs-airplay-button>button .fill,.mejs__airplay-button>button .fill{fill:#fff}.mejs-airplay-button>button.active .fill,.mejs__airplay-button>button.active .fill{fill:#66a8cc} -------------------------------------------------------------------------------- /dist/airplay/airplay.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */ 12 | !function n(l,o,s){function d(t,e){if(!o[t]){if(!l[t]){var i="function"==typeof require&&require;if(!e&&i)return i(t,!0);if(c)return c(t,!0);var a=new Error("Cannot find module '"+t+"'");throw a.code="MODULE_NOT_FOUND",a}var r=o[t]={exports:{}};l[t][0].call(r.exports,function(e){return d(l[t][1][e]||e)},r,r.exports,n,l,o,s)}return o[t].exports}for(var c="function"==typeof require&&require,e=0;e',n.addEventListener("click",function(){r.media.originalNode.webkitShowPlaybackTargetPicker()});var t=r.media.originalNode.getAttribute("x-webkit-airplay");t&&"allow"===t||r.media.originalNode.setAttribute("x-webkit-airplay","allow"),r.media.originalNode.addEventListener("webkitcurrentplaybacktargetiswirelesschanged",function(){var e=r.media.originalNode.webkitCurrentPlaybackTargetIsWireless?"Started":"Stopped",t=r.media.originalNode.webkitCurrentPlaybackTargetIsWireless?"active":"",i=n.querySelector("button"),a=mejs.Utils.createEvent("airplay"+e,r.media);r.media.dispatchEvent(a),"active"===t?mejs.Utils.addClass(i,"active"):mejs.Utils.removeClass(i,"active")}),r.media.originalNode.addEventListener("webkitplaybacktargetavailabilitychanged",function(e){"available"===e.availability&&r.addControlElement(n,"airplay")})}}})},{}]},{},[1]); -------------------------------------------------------------------------------- /dist/airplay/airplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/dist/airplay/airplay.png -------------------------------------------------------------------------------- /dist/airplay/airplay.svg: -------------------------------------------------------------------------------- 1 | 7 -------------------------------------------------------------------------------- /dist/chromecast/chromecast.css: -------------------------------------------------------------------------------- 1 | .mejs__chromecast-button > button, 2 | .mejs-chromecast-button > button { 3 | --disconnected-color: #fff; 4 | background: none; 5 | display: inline-block; 6 | } 7 | .mejs__chromecast-container, 8 | .mejs-chromecast-container { 9 | background: #000; 10 | color: #fff; 11 | font-size: 10px; 12 | left: 0; 13 | padding: 5px; 14 | position: absolute; 15 | top: 0; 16 | z-index: 1; 17 | } 18 | 19 | .mejs__chromecast-layer > img, 20 | .mejs-chromecast-layer > img { 21 | left: 0; 22 | position: absolute; 23 | top: 0; 24 | z-index: 0; 25 | } 26 | 27 | .mejs__chromecast-icon, 28 | .mejs-chromecast-icon { 29 | background: url('chromecast.svg') no-repeat 0 0; 30 | display: inline-block; 31 | height: 14px; 32 | margin-right: 5px; 33 | width: 17px; 34 | } -------------------------------------------------------------------------------- /dist/chromecast/chromecast.min.css: -------------------------------------------------------------------------------- 1 | .mejs-chromecast-button>button,.mejs__chromecast-button>button{--disconnected-color:#fff;background:none;display:inline-block}.mejs-chromecast-container,.mejs__chromecast-container{background:#000;color:#fff;font-size:10px;left:0;padding:5px;position:absolute;top:0;z-index:1}.mejs-chromecast-layer>img,.mejs__chromecast-layer>img{left:0;position:absolute;top:0;z-index:0}.mejs-chromecast-icon,.mejs__chromecast-icon{background:url(chromecast.svg) no-repeat 0 0;display:inline-block;height:14px;margin-right:5px;width:17px} -------------------------------------------------------------------------------- /dist/chromecast/chromecast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/dist/chromecast/chromecast.png -------------------------------------------------------------------------------- /dist/chromecast/chromecast.svg: -------------------------------------------------------------------------------- 1 | 5 -------------------------------------------------------------------------------- /dist/context-menu/context-menu.css: -------------------------------------------------------------------------------- 1 | .mejs__contextmenu, 2 | .mejs-contextmenu { 3 | background: #fff; 4 | border: solid 1px #999; 5 | border-radius: 4px; 6 | left: 0; 7 | padding: 10px; 8 | position: absolute; 9 | top: 0; 10 | width: 150px; 11 | z-index: 9999999999; /* make sure it shows on fullscreen */ 12 | } 13 | 14 | .mejs__contextmenu-separator, 15 | .mejs-contextmenu-separator { 16 | background: #333; 17 | font-size: 0; 18 | height: 1px; 19 | margin: 5px 6px; 20 | } 21 | 22 | .mejs__contextmenu-item, 23 | .mejs-contextmenu-item { 24 | color: #333; 25 | cursor: pointer; 26 | font-size: 12px; 27 | padding: 4px 6px; 28 | } 29 | 30 | .mejs__contextmenu-item:hover, 31 | .mejs-contextmenu-item:hover { 32 | background: #2c7c91; 33 | color: #fff; 34 | } 35 | -------------------------------------------------------------------------------- /dist/context-menu/context-menu.min.css: -------------------------------------------------------------------------------- 1 | .mejs-contextmenu,.mejs__contextmenu{background:#fff;border:1px solid #999;border-radius:4px;left:0;padding:10px;position:absolute;top:0;width:150px;z-index:1}.mejs-contextmenu-separator,.mejs__contextmenu-separator{background:#333;font-size:0;height:1px;margin:5px 6px}.mejs-contextmenu-item,.mejs__contextmenu-item{color:#333;cursor:pointer;font-size:12px;padding:4px 6px}.mejs-contextmenu-item:hover,.mejs__contextmenu-item:hover{background:#2c7c91;color:#fff} -------------------------------------------------------------------------------- /dist/facebook-pixel/facebook-pixel.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 30 9 | 10 | 11 | -------------------------------------------------------------------------------- /dist/loop/loop-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.loop'] = 'Commuta Bucle'; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.loop'] = 'Přepnout smyčku'; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.loop'] = 'Wiederholung (de-)aktivieren'; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.loop'] = 'Alternar Repetición'; 14 | } 15 | if (mejs.i18n.fa !== undefined) { 16 | mejs.i18n.fa['mejs.loop'] = 'حلقه تعویض'; 17 | } 18 | if (mejs.i18n.fr !== undefined) { 19 | mejs.i18n.fr['mejs.loop'] = 'Répéter'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.loop'] = 'Uključi/isključi ponavljanje'; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.loop'] = 'Húzza át a kapcsolót'; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.loop'] = 'Passare il ciclo'; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.loop'] = 'トグルループ'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.loop'] = '루프 토글'; 35 | } 36 | if (mejs.i18n.ms !== undefined) { 37 | mejs.i18n.ms['mejs.loop'] = 'Togol ulangan'; 38 | } 39 | if (mejs.i18n.nl !== undefined) { 40 | mejs.i18n.nl['mejs.loop'] = 'Schakellus'; 41 | } 42 | if (mejs.i18n.pl !== undefined) { 43 | mejs.i18n.pl['mejs.loop'] = 'Zapętl'; 44 | } 45 | if (mejs.i18n.pt !== undefined) { 46 | mejs.i18n.pt['mejs.loop'] = 'Loop alternativo'; 47 | } 48 | if (mejs.i18n.ro !== undefined) { 49 | mejs.i18n.ro['mejs.loop'] = 'Comutați buclă'; 50 | } 51 | if (mejs.i18n.ru !== undefined) { 52 | mejs.i18n.ru['mejs.loop'] = 'Зациклить воспроизведение'; 53 | } 54 | if (mejs.i18n.sk !== undefined) { 55 | mejs.i18n.sk['mejs.loop'] = 'Prepínať slučku'; 56 | } 57 | if (mejs.i18n.sv !== undefined) { 58 | mejs.i18n.sv['mejs.loop'] = 'Repetera'; 59 | } 60 | if (mejs.i18n.tr !== undefined) { 61 | mejs.i18n.tr['mejs.loop'] = 'Döngü'; 62 | } 63 | if (mejs.i18n.uk !== undefined) { 64 | mejs.i18n.uk['mejs.loop'] = 'Повторювати'; 65 | } 66 | if (mejs.i18n.zh !== undefined) { 67 | mejs.i18n.zh['mejs.loop'] = '切換循環'; 68 | } 69 | if (mejs.i18n['zh-CN'] !== undefined) { 70 | mejs.i18n['zh-CN']['mejs.loop'] = '切换循环'; 71 | } 72 | -------------------------------------------------------------------------------- /dist/loop/loop.css: -------------------------------------------------------------------------------- 1 | .mejs__loop-button > button, 2 | .mejs-loop-button > button { 3 | background: url('loop.svg') no-repeat transparent; 4 | } 5 | .mejs__loop-off > button, 6 | .mejs-loop-off > button { 7 | background-position: -20px 1px; 8 | } 9 | 10 | .mejs__loop-on > button, 11 | .mejs-loop-on > button { 12 | background-position: 0 1px; 13 | } 14 | -------------------------------------------------------------------------------- /dist/loop/loop.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i'; 28 | 29 | t.addControlElement(loop, 'loop'); 30 | 31 | loop.addEventListener('click', function () { 32 | player.options.loop = !player.options.loop; 33 | if (player.options.loop) { 34 | mejs.Utils.removeClass(loop, t.options.classPrefix + 'loop-off'); 35 | mejs.Utils.addClass(loop, t.options.classPrefix + 'loop-on'); 36 | } else { 37 | mejs.Utils.removeClass(loop, t.options.classPrefix + 'loop-on'); 38 | mejs.Utils.addClass(loop, t.options.classPrefix + 'loop-off'); 39 | } 40 | }); 41 | } 42 | }); 43 | 44 | },{}]},{},[1]); 45 | -------------------------------------------------------------------------------- /dist/loop/loop.min.css: -------------------------------------------------------------------------------- 1 | .mejs-loop-button>button,.mejs__loop-button>button{background:url(loop.svg) no-repeat transparent}.mejs-loop-off>button,.mejs__loop-off>button{background-position:-20px 1px}.mejs-loop-on>button,.mejs__loop-on>button{background-position:0 1px} -------------------------------------------------------------------------------- /dist/loop/loop.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */ 12 | !function i(l,r,p){function a(t,o){if(!r[t]){if(!l[t]){var e="function"==typeof require&&require;if(!o&&e)return e(t,!0);if(f)return f(t,!0);var s=new Error("Cannot find module '"+t+"'");throw s.code="MODULE_NOT_FOUND",s}var n=r[t]={exports:{}};l[t][0].call(n.exports,function(o){return a(l[t][1][o]||o)},n,n.exports,i,l,r,p)}return r[t].exports}for(var f="function"==typeof require&&require,o=0;o',t.addControlElement(s,"loop"),s.addEventListener("click",function(){o.options.loop=!o.options.loop,o.options.loop?(mejs.Utils.removeClass(s,t.options.classPrefix+"loop-off"),mejs.Utils.addClass(s,t.options.classPrefix+"loop-on")):(mejs.Utils.removeClass(s,t.options.classPrefix+"loop-on"),mejs.Utils.addClass(s,t.options.classPrefix+"loop-off"))})}})},{}]},{},[1]); -------------------------------------------------------------------------------- /dist/loop/loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/dist/loop/loop.png -------------------------------------------------------------------------------- /dist/loop/loop.svg: -------------------------------------------------------------------------------- 1 | 4 -------------------------------------------------------------------------------- /dist/markers/markers.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */ 12 | !function i(a,s,l){function f(e,r){if(!s[e]){if(!a[e]){var t="function"==typeof require&&require;if(!r&&t)return t(e,!0);if(m)return m(e,!0);var o=new Error("Cannot find module '"+e+"'");throw o.code="MODULE_NOT_FOUND",o}var n=s[e]={exports:{}};a[e][0].call(n.exports,function(r){return f(a[e][1][r]||r)},n,n.exports,i,a,s,l)}return s[e].exports}for(var m="function"==typeof require&&require,r=0;r=this.media.duration||t<0)){var o=100*t/this.media.duration,i=r[s];i.style.width=this.options.markersRollsWidth+"px",i.style.left=o+"%",i.style.background=this.options.markersRollsColor,s++}}})},{}]},{},[1]); -------------------------------------------------------------------------------- /dist/picture-in-picture/picture-in-picture-i18n.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | if(mejs.i18n.es !== undefined) { 4 | mejs.i18n.es['mejs.picture-in-pictureText'] = 'Picture in picture'; 5 | } 6 | if (mejs.i18n.de !== undefined) { 7 | mejs.i18n.de['mejs.picture-in-pictureText'] = 'Bild in Bild'; 8 | } 9 | if(mejs.i18n.fr !== undefined) { 10 | mejs.i18n.fr['mejs.picture-in-pictureText'] = 'Image dans l’image'; 11 | } 12 | if(mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.picture-in-pictureText'] = 'Imagen dentro de imagen'; 14 | } 15 | 16 | 17 | // TODO Add more languages for the title attribute 18 | -------------------------------------------------------------------------------- /dist/picture-in-picture/picture-in-picture.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 19 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /dist/postroll/postroll-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.close'] = 'Tancar'; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.close'] = 'Zavřít'; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.close'] = 'Schließen'; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.close'] = 'Cerrar'; 14 | } 15 | if (mejs.i18n.fa !== undefined) { 16 | mejs.i18n.fa['mejs.close'] = 'نزدیک'; 17 | } 18 | if (mejs.i18n.fr !== undefined) { 19 | mejs.i18n.fr['mejs.close'] = 'Fermer'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.close'] = 'Zatvori'; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.close'] = 'Bezárás'; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.close'] = 'Chiudere'; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.close'] = '閉じる'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.close'] = '종료'; 35 | } 36 | if (mejs.i18n.ms !== undefined) { 37 | mejs.i18n.ms['mejs.close'] = 'Tutup'; 38 | } 39 | if (mejs.i18n.nl !== undefined) { 40 | mejs.i18n.nl['mejs.close'] = 'Sluiten'; 41 | } 42 | if (mejs.i18n.pl !== undefined) { 43 | mejs.i18n.pl['mejs.close'] = 'Zamknij'; 44 | } 45 | if (mejs.i18n.pt !== undefined) { 46 | mejs.i18n.pt['mejs.close'] = 'Fechar'; 47 | } 48 | if (mejs.i18n.ro !== undefined) { 49 | mejs.i18n.ro['mejs.close'] = 'Închide'; 50 | } 51 | if (mejs.i18n.ru !== undefined) { 52 | mejs.i18n.ru['mejs.close'] = 'Закрыть'; 53 | } 54 | if (mejs.i18n.sk !== undefined) { 55 | mejs.i18n.sk['mejs.close'] = 'Zavrieť'; 56 | } 57 | if (mejs.i18n.sv !== undefined) { 58 | mejs.i18n.sv['mejs.close'] = 'Stäng'; 59 | } 60 | if (mejs.i18n.tr !== undefined) { 61 | mejs.i18n.tr['mejs.close'] = 'Kapat'; 62 | } 63 | if (mejs.i18n.uk !== undefined) { 64 | mejs.i18n.uk['mejs.close'] = 'Закрити'; 65 | } 66 | if (mejs.i18n.zh !== undefined) { 67 | mejs.i18n.zh['mejs.close'] = '關閉'; 68 | } 69 | if (mejs.i18n['zh-CN'] !== undefined) { 70 | mejs.i18n['zh-CN']['mejs.close'] = '关闭'; 71 | } 72 | -------------------------------------------------------------------------------- /dist/postroll/postroll.css: -------------------------------------------------------------------------------- 1 | .mejs__postroll-layer, 2 | .mejs-postroll-layer { 3 | background: rgba(50, 50, 50, 0.7); 4 | bottom: 0; 5 | height: 100%; 6 | left: 0; 7 | overflow: hidden; 8 | position: absolute; 9 | width: 100%; 10 | z-index: 1000; 11 | } 12 | 13 | .mejs__postroll-layer-content, 14 | .mejs-postroll-layer-content { 15 | height: 100%; 16 | width: 100%; 17 | } 18 | .mejs__postroll-close, 19 | .mejs-postroll-close { 20 | background: rgba(50, 50, 50, 0.7); 21 | color: #fff; 22 | cursor: pointer; 23 | padding: 4px; 24 | position: absolute; 25 | right: 0; 26 | top: 0; 27 | z-index: 100; 28 | } 29 | -------------------------------------------------------------------------------- /dist/postroll/postroll.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i' + postrollTitle + '' + ('
'); 30 | player.postroll.style.display = 'none'; 31 | 32 | layers.insertBefore(player.postroll, layers.firstChild); 33 | 34 | player.postroll.querySelector('.' + t.options.classPrefix + 'postroll-close').addEventListener('click', function (e) { 35 | this.parentNode.style.display = 'none'; 36 | e.preventDefault(); 37 | e.stopPropagation(); 38 | }); 39 | 40 | t.media.addEventListener('ended', function () { 41 | mejs.Utils.ajax(postrollLink.getAttribute('href'), 'html', function (data) { 42 | layers.querySelector('.' + t.options.classPrefix + 'postroll-layer-content').innerHTML = data; 43 | }); 44 | player.postroll.style.display = 'block'; 45 | }, false); 46 | 47 | t.media.addEventListener('seeked', function () { 48 | player.postroll.style.display = 'none'; 49 | }, false); 50 | 51 | t.media.addEventListener('playing', function () { 52 | player.postroll.style.display = 'none'; 53 | }, false); 54 | } 55 | } 56 | }); 57 | 58 | },{}]},{},[1]); 59 | -------------------------------------------------------------------------------- /dist/postroll/postroll.min.css: -------------------------------------------------------------------------------- 1 | .mejs-postroll-layer,.mejs__postroll-layer{background:rgba(50,50,50,.7);bottom:0;height:100%;left:0;overflow:hidden;position:absolute;width:100%;z-index:2}.mejs-postroll-layer-content,.mejs__postroll-layer-content{height:100%;width:100%}.mejs-postroll-close,.mejs__postroll-close{background:rgba(50,50,50,.7);color:#fff;cursor:pointer;padding:4px;position:absolute;right:0;top:0;z-index:1} -------------------------------------------------------------------------------- /dist/postroll/postroll.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */ 12 | !function r(n,i,a){function p(t,e){if(!i[t]){if(!n[t]){var o="function"==typeof require&&require;if(!e&&o)return o(t,!0);if(c)return c(t,!0);var s=new Error("Cannot find module '"+t+"'");throw s.code="MODULE_NOT_FOUND",s}var l=i[t]={exports:{}};n[t][0].call(l.exports,function(e){return p(n[t][1][e]||e)},l,l.exports,r,n,i,a)}return i[t].exports}for(var c="function"==typeof require&&require,e=0;e'+l+'
',e.postroll.style.display="none",o.insertBefore(e.postroll,o.firstChild),e.postroll.querySelector("."+s.options.classPrefix+"postroll-close").addEventListener("click",function(e){this.parentNode.style.display="none",e.preventDefault(),e.stopPropagation()}),s.media.addEventListener("ended",function(){mejs.Utils.ajax(r.getAttribute("href"),"html",function(e){o.querySelector("."+s.options.classPrefix+"postroll-layer-content").innerHTML=e}),e.postroll.style.display="block"},!1),s.media.addEventListener("seeked",function(){e.postroll.style.display="none"},!1),s.media.addEventListener("playing",function(){e.postroll.style.display="none"},!1))}})},{}]},{},[1]); -------------------------------------------------------------------------------- /dist/quality/quality-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.quality-chooser']= 'Selector de qualitat'; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.quality-chooser']= 'Kvalitní výběr'; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.quality-chooser']= 'Qualitätswähler'; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.quality-chooser']= 'Selector de calidad'; 14 | } 15 | if (mejs.i18n.fa !== undefined) { 16 | mejs.i18n.fa['mejs.quality-chooser']= 'انتخاب کننده کیفیت'; 17 | } 18 | if (mejs.i18n.fr !== undefined) { 19 | mejs.i18n.fr['mejs.quality-chooser']= 'Sélecteur de qualité'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.quality-chooser']= 'Kvalitetni birač'; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.quality-chooser']= 'Minőségi választó'; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.quality-chooser']= 'Qualità scelto'; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.quality-chooser']= '品質チューザー'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.quality-chooser']= '품질 선택자'; 35 | } 36 | if (mejs.i18n.ms !== undefined) { 37 | mejs.i18n.ms['mejs.quality-chooser']= 'Pilih kualiti'; 38 | } 39 | if (mejs.i18n.nl !== undefined) { 40 | mejs.i18n.nl['mejs.quality-chooser']= 'Kwaliteit kiezer'; 41 | } 42 | if (mejs.i18n.pl !== undefined) { 43 | mejs.i18n.pl['mejs.quality-chooser']= 'Chooser jakości'; 44 | } 45 | if (mejs.i18n.pt !== undefined) { 46 | mejs.i18n.pt['mejs.quality-chooser']= 'Escolha de qualidade'; 47 | } 48 | if (mejs.i18n.ro !== undefined) { 49 | mejs.i18n.ro['mejs.quality-chooser']= 'Alegere de calitate'; 50 | } 51 | if (mejs.i18n.ru !== undefined) { 52 | mejs.i18n.ru['mejs.quality-chooser']= 'Выбор качества'; 53 | } 54 | if (mejs.i18n.sk !== undefined) { 55 | mejs.i18n.sk['mejs.quality-chooser']= 'Kvalitný výber'; 56 | } 57 | if (mejs.i18n.sv !== undefined) { 58 | mejs.i18n.sv['mejs.quality-chooser']= 'Kvalitetsvalare'; 59 | } 60 | if (mejs.i18n.tr !== undefined) { 61 | mejs.i18n.tr['mejs.quality-chooser']= 'Kalite'; 62 | } 63 | if (mejs.i18n.uk !== undefined) { 64 | mejs.i18n.uk['mejs.quality-chooser']= 'Вибір якості'; 65 | } 66 | if (mejs.i18n.zh !== undefined) { 67 | mejs.i18n.zh['mejs.quality-chooser']= '質量選擇'; 68 | } 69 | if (mejs.i18n['zh-CN'] !== undefined) { 70 | mejs.i18n['zh-CN']['mejs.quality-chooser']= '质量选择'; 71 | } 72 | -------------------------------------------------------------------------------- /dist/quality/quality.css: -------------------------------------------------------------------------------- 1 | .mejs__qualities-selector.mejs__offscreen { 2 | display: none; 3 | } 4 | 5 | .mejs__qualities-button, 6 | .mejs-qualities-button { 7 | position: relative; 8 | width: auto; 9 | } 10 | 11 | .mejs__qualities-button > button, 12 | .mejs-qualities-button > button { 13 | background: transparent; 14 | color: #fff; 15 | font-size: 0.6875rem; 16 | font-weight: 700; 17 | position: static; 18 | width: auto; 19 | } 20 | 21 | .mejs__qualities-selector, 22 | .mejs-qualities-selector { 23 | background: rgba(50, 50, 50, 0.7); 24 | border: 0.063rem solid transparent; 25 | border-radius: 0; 26 | height: 6.25rem; 27 | left: -0.625rem; 28 | overflow: hidden; 29 | padding: 0; 30 | position: absolute; 31 | top: -6.25rem; 32 | width: 3.75rem; 33 | } 34 | 35 | .mejs__qualities-selector ul, 36 | .mejs-qualities-selector ul { 37 | display: block; 38 | list-style-type: none !important; 39 | margin: 0; 40 | overflow: hidden; 41 | padding: 0; 42 | } 43 | 44 | .mejs__qualities-selector li, 45 | .mejs-qualities-selector li { 46 | border: 0.06rem solid transparent; 47 | color: #fff; 48 | cursor: pointer; 49 | display: block; 50 | list-style-type: none!important; 51 | overflow: hidden; 52 | padding: 0 0.625rem; 53 | } 54 | 55 | .mejs__qualities-selector li:hover, 56 | .mejs-qualities-selector li:hover { 57 | background-color: rgba(255, 255, 255, 0.2); 58 | cursor: pointer; 59 | } 60 | 61 | .mejs__qualities-selector li:focus-within, 62 | .mejs-qualities-selector li:focus-within { 63 | border-color: #fff; 64 | } 65 | 66 | .mejs__qualities-selector input, 67 | .mejs-qualities-selector input { 68 | clear: both; 69 | float: left; 70 | left: -62.5rem; 71 | margin: 0.188rem 0.188rem 0 0.313rem; 72 | position: absolute; 73 | } 74 | 75 | .mejs__qualities-selector label, 76 | .mejs-qualities-selector label { 77 | cursor: pointer; 78 | float: left; 79 | font-size: 0.625rem; 80 | padding: 0.375rem 0; 81 | width: 3.438rem; 82 | } 83 | 84 | .mejs__qualities-selected, 85 | .mejs-qualities-selected { 86 | color: rgba(33, 248, 248, 1); 87 | } 88 | -------------------------------------------------------------------------------- /dist/quality/quality.min.css: -------------------------------------------------------------------------------- 1 | .mejs__qualities-selector.mejs__offscreen{display:none}.mejs-qualities-button,.mejs__qualities-button{position:relative;width:auto}.mejs-qualities-button>button,.mejs__qualities-button>button{background:transparent;color:#fff;font-size:.6875rem;font-weight:700;position:static;width:auto}.mejs-qualities-selector,.mejs__qualities-selector{background:rgba(50,50,50,.7);border:.063rem solid transparent;border-radius:0;height:6.25rem;left:-.625rem;overflow:hidden;padding:0;position:absolute;top:-6.25rem;width:3.75rem}.mejs-qualities-selector ul,.mejs__qualities-selector ul{display:block;list-style-type:none!important;margin:0;overflow:hidden;padding:0}.mejs-qualities-selector li,.mejs__qualities-selector li{border:.06rem solid transparent;color:#fff;cursor:pointer;display:block;list-style-type:none!important;overflow:hidden;padding:0 .625rem}.mejs-qualities-selector li:hover,.mejs__qualities-selector li:hover{background-color:hsla(0,0%,100%,.2);cursor:pointer}.mejs-qualities-selector li:focus-within,.mejs__qualities-selector li:focus-within{border-color:#fff}.mejs-qualities-selector input,.mejs__qualities-selector input{clear:both;float:left;left:-62.5rem;margin:.188rem .188rem 0 .313rem;position:absolute}.mejs-qualities-selector label,.mejs__qualities-selector label{cursor:pointer;float:left;font-size:.625rem;padding:.375rem 0;width:3.438rem}.mejs-qualities-selected,.mejs__qualities-selected{color:#21f8f8} -------------------------------------------------------------------------------- /dist/skip-back/skip-back.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 2 | 3 | 4 | 5 | 6 | 7 | 30 8 | 9 | -------------------------------------------------------------------------------- /dist/snapshot/snapshot-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.snapshot'] = ['Retornar 1 segon', 'Retornar %1 segons']; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.snapshot'] = ['Přeskočte zpět o 1 sekundu', 'Přeskočte zpět %1 vteřiny', 'Přeskočte zpět %1 sekund']; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.snapshot'] = ['1 Sekunde zurückspulen', '%1 Sekunden zurückspulen']; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.snapshot'] = ['Rebobinar 1 segundo', 'Rebobinar %1 segundos']; 14 | } 15 | if (mejs.i18n.fr !== undefined) { 16 | mejs.i18n.fr['mejs.snapshot'] = ['Reculer de %1 seconde', 'Reculer de %1 secondes']; 17 | } 18 | if (mejs.i18n.fa !== undefined) { 19 | mejs.i18n.fa['mejs.snapshot'] = '%1 ثانیه به عقب برگردید'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.snapshot'] = ['Skoči natrag 1 sekundu', 'Skoči natrag %1 sekunde', 'Skoči natrag %1 sekundi']; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.snapshot'] = ['Menj vissza 1 másodpercig', 'Ugrás vissza %1 másodperccel']; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.snapshot'] = ['Riavvolgere 1 secondo', 'Riavvolgere %1 secondi']; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.snapshot'] = '%1秒スキップバックする'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.snapshot'] = '%1초 를 뒤로 건너뛰세요'; 35 | } 36 | if (mejs.i18n.nl !== undefined) { 37 | mejs.i18n.nl['mejs.snapshot'] = ['Sla 1 seconde terug', 'Sla %1 seconden terug']; 38 | } 39 | if (mejs.i18n.pl !== undefined) { 40 | mejs.i18n.pl['mejs.snapshot'] = ['Cofnij o 1 sekundę', 'Cofnij o %1 sekundy', 'Cofnij o %1 sekund']; 41 | } 42 | if (mejs.i18n.pt !== undefined) { 43 | mejs.i18n.pt['mejs.snapshot'] = ['Retroceder %1 segundo', 'Retroceder %1 segundos']; 44 | } 45 | if (mejs.i18n.ro !== undefined) { 46 | mejs.i18n.ro['mejs.snapshot'] = ['Treceți înapoi 1 secundă', 'Treceți înapoi în %1 secunde']; 47 | } 48 | if (mejs.i18n.ru !== undefined) { 49 | mejs.i18n.ru['mejs.snapshot'] = ['Перейти назад на %1 секунду', 'Перейти назад на %1 секунды', 'Перейти назад на %1 секунд']; 50 | } 51 | if (mejs.i18n.sk !== undefined) { 52 | mejs.i18n.sk['mejs.snapshot'] = ['Preskočte späť 1 sekundu', 'Preskočte %1 sekundy', 'Preskočte späť %1 sekúnd']; 53 | } 54 | if (mejs.i18n.sv !== undefined) { 55 | mejs.i18n.sv['mejs.snapshot'] = ['Hoppa tillbaka 1 sekund', 'Hoppa tillbaka %1 sekunder']; 56 | } 57 | if (mejs.i18n.tr !== undefined) { 58 | mejs.i18n.tr['mejs.snapshot'] = ['1 saniye geri atla', '%1 saniye geri atla']; 59 | } 60 | if (mejs.i18n.uk !== undefined) { 61 | mejs.i18n.uk['mejs.snapshot'] = ['Перейти назад на %1 секунду', 'Перейти назад на %1 секунди', 'Перейти назад на %1 секунд']; 62 | } 63 | if (mejs.i18n.zh !== undefined) { 64 | mejs.i18n.zh['mejs.snapshot'] = '跳躍式迴繞%1秒'; 65 | } 66 | if (mejs.i18n['zh-CN'] !== undefined) { 67 | mejs.i18n['zh-CN']['mejs.snapshot'] = '后退%1秒'; 68 | } 69 | -------------------------------------------------------------------------------- /dist/snapshot/snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/dist/snapshot/snapshot.png -------------------------------------------------------------------------------- /dist/source-chooser/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/dist/source-chooser/settings.png -------------------------------------------------------------------------------- /dist/source-chooser/settings.svg: -------------------------------------------------------------------------------- 1 | 3 -------------------------------------------------------------------------------- /dist/source-chooser/source-chooser-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.source-chooser']= 'Selector de font'; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.source-chooser']= 'Zdrojový výběr'; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.source-chooser']= 'Quellenauswahl'; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.source-chooser']= 'Selector de media'; 14 | } 15 | if (mejs.i18n.fa !== undefined) { 16 | mejs.i18n.fa['mejs.source-chooser']= 'انتخاب کننده منبع'; 17 | } 18 | if (mejs.i18n.fr !== undefined) { 19 | mejs.i18n.fr['mejs.source-chooser']= 'Sélecteur de média'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.source-chooser']= 'Obabir izvora'; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.source-chooser']= 'Forrásválasztó'; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.source-chooser']= 'Selezionatore di origine'; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.source-chooser']= 'ソースセレクタ'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.source-chooser']= '소스 선택기'; 35 | } 36 | if (mejs.i18n.ms !== undefined) { 37 | mejs.i18n.ms['mejs.source-chooser']= 'Pilih sumber'; 38 | } 39 | if (mejs.i18n.nl !== undefined) { 40 | mejs.i18n.nl['mejs.source-chooser']= 'Bronkeuze'; 41 | } 42 | if (mejs.i18n.pl !== undefined) { 43 | mejs.i18n.pl['mejs.source-chooser']= 'Wybór źródła'; 44 | } 45 | if (mejs.i18n.pt !== undefined) { 46 | mejs.i18n.pt['mejs.source-chooser']= 'Escolhedor de fontes'; 47 | } 48 | if (mejs.i18n.ro !== undefined) { 49 | mejs.i18n.ro['mejs.source-chooser']= 'Sursă de selecție'; 50 | } 51 | if (mejs.i18n.ru !== undefined) { 52 | mejs.i18n.ru['mejs.source-chooser']= 'Переключатель источника'; 53 | } 54 | if (mejs.i18n.sk !== undefined) { 55 | mejs.i18n.sk['mejs.source-chooser']= 'Zdroj výberu'; 56 | } 57 | if (mejs.i18n.sv !== undefined) { 58 | mejs.i18n.sv['mejs.source-chooser']= 'Välj källa'; 59 | } 60 | if (mejs.i18n.tr !== undefined) { 61 | mejs.i18n.tr['mejs.source-chooser']= 'Kaynak Seçici'; 62 | } 63 | if (mejs.i18n.uk !== undefined) { 64 | mejs.i18n.uk['mejs.source-chooser']= 'Вибір джерела'; 65 | } 66 | if (mejs.i18n.zh !== undefined) { 67 | mejs.i18n.zh['mejs.source-chooser']= '源選擇器'; 68 | } 69 | if (mejs.i18n['zh-CN'] !== undefined) { 70 | mejs.i18n['zh-CN']['mejs.source-chooser']= '源选择器'; 71 | } 72 | -------------------------------------------------------------------------------- /dist/source-chooser/source-chooser.css: -------------------------------------------------------------------------------- 1 | .mejs__sourcechooser-button, 2 | .mejs-sourcechooser-button { 3 | position: relative; 4 | } 5 | 6 | .mejs__sourcechooser-button > button, 7 | .mejs-sourcechooser-button > button { 8 | background: url('settings.svg') transparent no-repeat; 9 | background-position: 0 1px; 10 | } 11 | 12 | .mejs__sourcechooser-button .mejs__sourcechooser-selector, 13 | .mejs-sourcechooser-button .mejs-sourcechooser-selector { 14 | background: rgba(50, 50, 50, 0.7); 15 | border: solid 1px transparent; 16 | border-radius: 0; 17 | bottom: 40px; 18 | height: 100px; 19 | overflow: hidden; 20 | padding: 0; 21 | position: absolute; 22 | right: -10px; 23 | width: 130px; 24 | } 25 | 26 | .mejs__sourcechooser-selector ul, 27 | .mejs-sourcechooser-selector ul { 28 | display: block; 29 | list-style-type: none !important; 30 | margin: 0; 31 | overflow: hidden; 32 | padding: 0; 33 | } 34 | 35 | .mejs__sourcechooser-selector li, 36 | .mejs-sourcechooser-selector li { 37 | color: #fff; 38 | display: block; 39 | list-style-type: none !important; 40 | margin: 0; 41 | overflow: hidden; 42 | padding: 5px 0; 43 | } 44 | .mejs__sourcechooser-selector li:hover, 45 | .mejs-sourcechooser-selector li:hover { 46 | background-color: rgba(255, 255, 255, 0.2); 47 | cursor: pointer; 48 | } 49 | 50 | .mejs__sourcechooser-selector input, 51 | .mejs-sourcechooser-selector input { 52 | clear: both; 53 | float: left; 54 | margin: 3px 3px 0 0; 55 | } 56 | 57 | .mejs__sourcechooser-selector label, 58 | .mejs-sourcechooser-selector label { 59 | display: inline-block; 60 | float: left; 61 | font-size: 12px; 62 | line-height: 15px; 63 | padding: 4px 0 0; 64 | width: 100px; 65 | } 66 | -------------------------------------------------------------------------------- /dist/source-chooser/source-chooser.min.css: -------------------------------------------------------------------------------- 1 | .mejs-sourcechooser-button,.mejs__sourcechooser-button{position:relative}.mejs-sourcechooser-button>button,.mejs__sourcechooser-button>button{background:url(settings.svg) transparent no-repeat;background-position:0 1px}.mejs-sourcechooser-button .mejs-sourcechooser-selector,.mejs__sourcechooser-button .mejs__sourcechooser-selector{background:rgba(50,50,50,.7);border:1px solid transparent;border-radius:0;bottom:40px;height:100px;overflow:hidden;padding:0;position:absolute;right:-10px;width:130px}.mejs-sourcechooser-selector ul,.mejs__sourcechooser-selector ul{display:block;list-style-type:none!important;margin:0;overflow:hidden;padding:0}.mejs-sourcechooser-selector li,.mejs__sourcechooser-selector li{color:#fff;display:block;list-style-type:none!important;margin:0;overflow:hidden;padding:5px 0}.mejs-sourcechooser-selector li:hover,.mejs__sourcechooser-selector li:hover{background-color:hsla(0,0%,100%,.2);cursor:pointer}.mejs-sourcechooser-selector input,.mejs__sourcechooser-selector input{clear:both;float:left;margin:3px 3px 0 0}.mejs-sourcechooser-selector label,.mejs__sourcechooser-selector label{display:inline-block;float:left;font-size:12px;line-height:15px;padding:4px 0 0;width:100px} -------------------------------------------------------------------------------- /dist/speed/speed-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.speed-rate'] = 'Velocitat'; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.speed-rate'] = 'Rychlost'; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.speed-rate'] = 'Geschwindigkeitsrate'; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.speed-rate'] = 'Velocidad'; 14 | } 15 | if (mejs.i18n.fa !== undefined) { 16 | mejs.i18n.fa['mejs.speed-rate'] = 'نرخ سرعت'; 17 | } 18 | if (mejs.i18n.fr !== undefined) { 19 | mejs.i18n.fr['mejs.speed-rate'] = 'Vitesse'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.speed-rate'] = 'Brzina reprodukcije'; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.speed-rate'] = 'Sebesség'; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.speed-rate'] = 'Velocità'; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.speed-rate'] = '高速'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.speed-rate'] = '속도 속도'; 35 | } 36 | if (mejs.i18n.ms !== undefined) { 37 | mejs.i18n.ms['mejs.speed-rate'] = 'Kelajuan'; 38 | } 39 | if (mejs.i18n.nl !== undefined) { 40 | mejs.i18n.nl['mejs.speed-rate'] = 'Snelheidsgraad'; 41 | } 42 | if (mejs.i18n.pl !== undefined) { 43 | mejs.i18n.pl['mejs.speed-rate'] = 'Prędkość'; 44 | } 45 | if (mejs.i18n.pt !== undefined) { 46 | mejs.i18n.pt['mejs.speed-rate'] = 'Taxa de velocidade'; 47 | } 48 | if (mejs.i18n.ro !== undefined) { 49 | mejs.i18n.ro['mejs.speed-rate'] = 'Viteză de viteză'; 50 | } 51 | if (mejs.i18n.ru !== undefined) { 52 | mejs.i18n.ru['mejs.speed-rate'] = 'Скорость воспроизведения'; 53 | } 54 | if (mejs.i18n.sk !== undefined) { 55 | mejs.i18n.sk['mejs.speed-rate'] = 'Rýchlosť'; 56 | } 57 | if (mejs.i18n.sv !== undefined) { 58 | mejs.i18n.sv['mejs.speed-rate'] = 'Hastighet'; 59 | } 60 | if (mejs.i18n.tr !== undefined) { 61 | mejs.i18n.tr['mejs.speed-rate'] = 'Hız oranı'; 62 | } 63 | if (mejs.i18n.uk !== undefined) { 64 | mejs.i18n.uk['mejs.speed-rate'] = 'Швидкість відтворення'; 65 | } 66 | if (mejs.i18n.zh !== undefined) { 67 | mejs.i18n.zh['mejs.speed-rate'] = '速度'; 68 | } 69 | if (mejs.i18n['zh-CN'] !== undefined) { 70 | mejs.i18n['zh-CN']['mejs.speed-rate'] = '速度'; 71 | } 72 | -------------------------------------------------------------------------------- /dist/speed/speed.css: -------------------------------------------------------------------------------- 1 | .mejs__speed-button, 2 | .mejs-speed-button { 3 | position: relative; 4 | } 5 | 6 | .mejs__speed-button > button, 7 | .mejs-speed-button > button { 8 | background: transparent; 9 | color: #fff; 10 | font-size: 11px; 11 | line-height: normal; 12 | margin: 11px 0 0; 13 | width: 36px; 14 | } 15 | 16 | .mejs__speed-selector, 17 | .mejs-speed-selector { 18 | background: rgba(50, 50, 50, 0.7); 19 | border: solid 1px transparent; 20 | border-radius: 0; 21 | height: 150px; 22 | left: -10px; 23 | overflow: hidden; 24 | padding: 0; 25 | position: absolute; 26 | top: -100px; 27 | visibility: hidden; 28 | width: 60px; 29 | } 30 | 31 | .mejs__speed-selector, 32 | .mejs-speed-selector { 33 | visibility: visible; 34 | } 35 | 36 | .mejs__speed-selector-list, 37 | .mejs-speed-selector-list { 38 | display: block; 39 | list-style-type: none !important; 40 | margin: 0; 41 | overflow: hidden; 42 | padding: 0; 43 | } 44 | 45 | .mejs__speed-selector-list-item, 46 | .mejs-speed-selector-list-item { 47 | color: #fff; 48 | display: block; 49 | list-style-type: none !important; 50 | margin: 0 0 6px; 51 | overflow: hidden; 52 | padding: 0 10px; 53 | } 54 | 55 | .mejs__speed-selector-list-item:hover, 56 | .mejs-speed-selector-list-item:hover { 57 | background-color: rgb(200, 200, 200) !important; 58 | background-color: rgba(255, 255, 255, 0.4) !important; 59 | } 60 | 61 | .mejs__speed-selector-input, 62 | .mejs-speed-selector-input { 63 | clear: both; 64 | float: left; 65 | left: -1000px; 66 | margin: 3px 3px 0 5px; 67 | position: absolute; 68 | } 69 | 70 | .mejs__speed-selector-label, 71 | .mejs-speed-selector-label { 72 | color: white; 73 | cursor: pointer; 74 | float: left; 75 | font-size: 11px; 76 | line-height: 15px; 77 | margin-left: 5px; 78 | padding: 4px 0 0; 79 | width: 60px; 80 | } 81 | 82 | .mejs__speed-selected, 83 | .mejs-speed-selected { 84 | color: rgba(33, 248, 248, 1); 85 | } 86 | 87 | .mejs__speed-selector, 88 | .mejs-speed-selector { 89 | visibility: hidden; 90 | } 91 | .mejs__speed-button:hover .mejs__speed-selector, 92 | .mejs-speed-button:hover .mejs-speed-selector { 93 | visibility: visible; 94 | } 95 | -------------------------------------------------------------------------------- /dist/speed/speed.min.css: -------------------------------------------------------------------------------- 1 | .mejs-speed-button,.mejs__speed-button{position:relative}.mejs-speed-button>button,.mejs__speed-button>button{background:transparent;color:#fff;font-size:11px;line-height:normal;margin:11px 0 0;width:36px}.mejs-speed-selector,.mejs__speed-selector{background:rgba(50,50,50,.7);border:1px solid transparent;border-radius:0;height:150px;left:-10px;overflow:hidden;padding:0;position:absolute;top:-100px;width:60px;visibility:visible}.mejs-speed-selector-list,.mejs__speed-selector-list{display:block;list-style-type:none!important;margin:0;overflow:hidden;padding:0}.mejs-speed-selector-list-item,.mejs__speed-selector-list-item{color:#fff;display:block;list-style-type:none!important;margin:0 0 6px;overflow:hidden;padding:0 10px}.mejs-speed-selector-list-item:hover,.mejs__speed-selector-list-item:hover{background-color:#c8c8c8!important;background-color:hsla(0,0%,100%,.4)!important}.mejs-speed-selector-input,.mejs__speed-selector-input{clear:both;float:left;left:-1000px;margin:3px 3px 0 5px;position:absolute}.mejs-speed-selector-label,.mejs__speed-selector-label{color:#fff;cursor:pointer;float:left;font-size:11px;line-height:15px;margin-left:5px;padding:4px 0 0;width:60px}.mejs-speed-selected,.mejs__speed-selected{color:#21f8f8}.mejs-speed-selector,.mejs__speed-selector{visibility:hidden}.mejs-speed-button:hover .mejs-speed-selector,.mejs__speed-button:hover .mejs__speed-selector{visibility:visible} -------------------------------------------------------------------------------- /dist/stop/stop-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.stop'] = 'Aturar'; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.stop'] = 'Stop'; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.stop'] = 'Stop'; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.stop'] = 'Parar'; 14 | } 15 | if (mejs.i18n.fa !== undefined) { 16 | mejs.i18n.fa['mejs.stop'] = 'متوقف کردن'; 17 | } 18 | if (mejs.i18n.fr !== undefined) { 19 | mejs.i18n.fr['mejs.stop'] = 'Stop'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.stop'] = 'Zaustavi'; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.stop'] = 'Állj meg'; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.stop'] = 'Stop'; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.stop'] = '止'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.stop'] = '중지'; 35 | } 36 | if (mejs.i18n.ms !== undefined) { 37 | mejs.i18n.ms['mejs.stop'] = 'Berhenti'; 38 | } 39 | if (mejs.i18n.nl !== undefined) { 40 | mejs.i18n.nl['mejs.stop'] = 'Hou op'; 41 | } 42 | if (mejs.i18n.pl !== undefined) { 43 | mejs.i18n.pl['mejs.stop'] = 'Zatrzymaj'; 44 | } 45 | if (mejs.i18n.pt !== undefined) { 46 | mejs.i18n.pt['mejs.stop'] = 'Pare'; 47 | } 48 | if (mejs.i18n.ro !== undefined) { 49 | mejs.i18n.ro['mejs.stop'] = 'Stop'; 50 | } 51 | if (mejs.i18n.ru !== undefined) { 52 | mejs.i18n.ru['mejs.stop'] = 'Остановить'; 53 | } 54 | if (mejs.i18n.sk !== undefined) { 55 | mejs.i18n.sk['mejs.stop'] = 'Prestať'; 56 | } 57 | if (mejs.i18n.sv !== undefined) { 58 | mejs.i18n.sv['mejs.stop'] = 'Stoppa'; 59 | } 60 | if (mejs.i18n.tr !== undefined) { 61 | mejs.i18n.tr['mejs.stop'] = 'Durdur'; 62 | } 63 | if (mejs.i18n.uk !== undefined) { 64 | mejs.i18n.uk['mejs.stop'] = 'Зупинити'; 65 | } 66 | if (mejs.i18n.zh !== undefined) { 67 | mejs.i18n.zh['mejs.stop'] = '停止'; 68 | } 69 | if (mejs.i18n['zh-CN'] !== undefined) { 70 | mejs.i18n['zh-CN']['mejs.stop'] = '停止'; 71 | } 72 | -------------------------------------------------------------------------------- /dist/stop/stop.css: -------------------------------------------------------------------------------- 1 | .mejs__stop > button, 2 | .mejs-stop > button { 3 | background: url('stop.svg') 0 2px no-repeat; 4 | } 5 | -------------------------------------------------------------------------------- /dist/stop/stop.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i'; 28 | 29 | t.addControlElement(button, 'stop'); 30 | 31 | button.addEventListener('click', function () { 32 | if (typeof media.stop === 'function') { 33 | media.stop(); 34 | } else if (media.readyState > 0) { 35 | if (!media.paused) { 36 | media.pause(); 37 | } 38 | 39 | media.setSrc(''); 40 | media.load(); 41 | 42 | var playButton = controls.querySelector('.' + t.options.classPrefix + 'playpause-button'); 43 | mejs.Utils.removeClass(playButton, t.options.classPrefix + 'pause'); 44 | mejs.Utils.addClass(playButton, t.options.classPrefix + 'play'); 45 | 46 | if (t.container.querySelector('.' + t.options.classPrefix + 'cannotplay')) { 47 | t.container.querySelector('.' + t.options.classPrefix + 'cannotplay').remove(); 48 | layers.querySelector('.' + t.options.classPrefix + 'overlay-error').parentNode.style.display = 'none'; 49 | layers.querySelector('.' + t.options.classPrefix + 'overlay-error').remove(); 50 | } 51 | } 52 | 53 | var event = mejs.Utils.createEvent('timeupdate', media); 54 | media.dispatchEvent(event); 55 | }); 56 | } 57 | }); 58 | 59 | },{}]},{},[1]); 60 | -------------------------------------------------------------------------------- /dist/stop/stop.min.css: -------------------------------------------------------------------------------- 1 | .mejs-stop>button,.mejs__stop>button{background:url(stop.svg) 0 2px no-repeat} -------------------------------------------------------------------------------- /dist/stop/stop.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */ 12 | !function n(i,a,l){function p(t,e){if(!a[t]){if(!i[t]){var o="function"==typeof require&&require;if(!e&&o)return o(t,!0);if(c)return c(t,!0);var s=new Error("Cannot find module '"+t+"'");throw s.code="MODULE_NOT_FOUND",s}var r=a[t]={exports:{}};i[t][0].call(r.exports,function(e){return p(i[t][1][e]||e)},r,r.exports,n,i,a,l)}return a[t].exports}for(var c="function"==typeof require&&require,e=0;e',n.addControlElement(i,"stop"),i.addEventListener("click",function(){if("function"==typeof r.stop)r.stop();else if(04 2 | -------------------------------------------------------------------------------- /dist/vrview/cardboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/dist/vrview/cardboard.png -------------------------------------------------------------------------------- /dist/vrview/cardboard.svg: -------------------------------------------------------------------------------- 1 | 6 -------------------------------------------------------------------------------- /dist/vrview/vrview.css: -------------------------------------------------------------------------------- 1 | .mejs__vrview-button > button, 2 | .mejs-vrview-button > button { 3 | background: url('cardboard.svg') no-repeat 0 4px; 4 | } -------------------------------------------------------------------------------- /dist/vrview/vrview.min.css: -------------------------------------------------------------------------------- 1 | .mejs-vrview-button>button,.mejs__vrview-button>button{background:url(cardboard.svg) no-repeat 0 4px} -------------------------------------------------------------------------------- /docs/a11y.md: -------------------------------------------------------------------------------- 1 | # Accessibility 2 | 3 | ## Overview 4 | This plugin enables special accessibility features for adding an audio description or sign language annotated movie file. 5 | 6 | ## Keyword to use it 7 | ```javascript 8 | features: [..., 'a11y'] 9 | ``` 10 | 11 | ## API 12 | Parameter | Type | Default | Description 13 | ------ | --------- | ------- | -------- 14 | `data-video-description` | array | null | An array of video source objects like `{ src: "description.mp4", type: "video/mp4" }`. This plugin will evaluate the best matching type out of the array. 15 | `data-audio-description` | array | null | An array of audio description source objects like `{ src: "description.mp3", type: "audio/mp3" }`. This plugin will evaluate the best matching type out of the array. 16 | `data-audio-description-voiceover` | boolean | false | If set as data attribute only or with value `true` audio description will be started in voice-over mode. 17 | `iconSpritePathA11y` | string | `mejs-a11y-icons.svg` | Path for the SVG icon sprite file. 18 | 19 | #### Audio-description node 20 | The Audio description node is bound to the MediaElement.js object at `mejs.audioDescription.node`, like the original node is bound under `mejs.node`. 21 | 22 | ## Icons 23 | The sign language and audio description icon were made by [Font Awesome](https://fontawesome.com) and underlie the following [License](https://fontawesome.com/license). 24 | 25 | --- 26 | 27 | This Plugin is sponsored by [Aktion Mensch e.V.](https://www.aktion-mensch.de) 28 | 29 | --- 30 | 31 | ## German Translation 32 | 33 | ### Übersicht 34 | Dieses Plugin ermöglicht besondere Barrierefreiheit-Erweiterungen zum Hinzufügen von Audio-Deskription oder Videos mit Übersetzung in Gebärdensprache. 35 | 36 | ### Keyword zum Einbinden 37 | ```javascript 38 | features: [..., 'a11y'] 39 | ``` 40 | 41 | ### API 42 | Parameter | Type | Default | Beschreibung 43 | ------ | --------- | ------- | -------- 44 | `data-video-description` | array | null | Ein Array von Gebärden-Sprachen-Video-Source Objekten, die wie folgt auszusehen haben: `{ src: "description.mp4", type: "video/mp4" }`. Das Plugin wählt die am besten passende Video-Source aus dem Array aus. 45 | `data-audio-description` | array | null | Ein Array von Audio-Deskription-Source Objekten, die wie folgt auszusehen haben: `{ src: "description.mp3", type: "audio/mp3" }`. Das Plugin wählt die am besten passende Audio-Source aus dem Array aus. 46 | `data-audio-description-voiceover` | boolean | false | Wenn der Parameter als Data-Attribut gesetzt oder mit dem Wert `true` belegt ist, wird die Audio-Deskription als Voice-Over gestartet. 47 | 48 | ##### Audio-Deskription Node 49 | Der Audio-Deskription Node wird im MediaElement.js Objekt unter `mejs.audioDescription.node` eingebunden, so wie der eigentliche Node unter `mejs.node` eingebunden ist. 50 | 51 | ### Icons 52 | Das Gebärdensprache- und Audio-Deskriptions-Icon stammen von [Font Awesome](https://fontawesome.com) und unterliegen der folgenden [Lizenz](https://fontawesome.com/license). 53 | 54 | 55 | --- 56 | 57 | Dieses Plugin wurde gesponsert von [Aktion Mensch e.V.](https://www.aktion-mensch.de) 58 | -------------------------------------------------------------------------------- /docs/ads-vast.md: -------------------------------------------------------------------------------- 1 | # VAST/VPAID 2 | 3 | ## Overview 4 | 5 | This plugin, with the [Ads](ads.md) plugin, manages the displaying of Ads before media starts playing. 6 | 7 | It will generate the proper structures after parsing VPAID/VAST XML files to be processed by the `Ads` plugin. 8 | 9 | **NOTE**: Currently, this plugin only supports Linear elements with MP4/FLV. Support for Flash and Javascript MediaFiles coming soon. 10 | 11 | ## Keyword to use it 12 | ```javascript 13 | features: [..., 'vast'] 14 | ``` 15 | 16 | ## API 17 | 18 | Parameter | Type | Default | Description 19 | ------ | --------- | ------- | -------- 20 | vastAdTagUrl | string | __empty__ | VAST or VPAID URL 21 | vastAdsType | string | `vast` | Type of Ads (`vast` or `vpaid`) -------------------------------------------------------------------------------- /docs/ads.md: -------------------------------------------------------------------------------- 1 | # Ads 2 | 3 | ## Overview 4 | 5 | This plugin, with the [VAST/VPAID](ads-vast.md) plugin, manages the displaying of Ads before media starts playing. 6 | 7 | It will fire the proper events depending of the nature of the Ads type (`vast` or `vpaid`) and takes care of the manipulation 8 | of the user's experience in general. 9 | 10 | ## Keyword to use it 11 | ```javascript 12 | features: [..., 'ads'] 13 | ``` 14 | 15 | ## API 16 | 17 | Parameter | Type | Default | Description 18 | ------ | --------- | ------- | -------- 19 | adsPrerollMediaUrl | array | `[]` | Collection of Ads URLs 20 | adsPrerollAdUrl | array | `[]` | Collection of URLs that will be tracked through a click event when playing an Ad 21 | adsPrerollAdEnableSkip | boolean | `false` | If true, allows user to skip the pre-roll ad 22 | adsPrerollAdSkipSeconds | number | `-1` | If positive number entered, it will only allow skipping after the time has elasped 23 | indexPreroll | number | `0` | Keep track of the index for the preroll ads to be able to show more than one preroll 24 | -------------------------------------------------------------------------------- /docs/airplay.md: -------------------------------------------------------------------------------- 1 | # AirPlay 2 | 3 | ## Overview 4 | 5 | This plugin displays a button to interact with an AirPlay device, if available. 6 | 7 | It detects if media tag has the `x-webkit-airplay` attribute set as `allow`; if not, the plugin sets it, to provide also native support. 8 | 9 | ## Keyword to use it 10 | ```javascript 11 | features: [..., 'airplay'] 12 | ``` 13 | 14 | ## API 15 | 16 | Parameter | Type | Default | Description 17 | ------ | --------- | ------- | -------- 18 | airPlayTitle | string | `null` | AirPlay button title for ARIA purposes -------------------------------------------------------------------------------- /docs/chromecast.md: -------------------------------------------------------------------------------- 1 | # Chromecast 2 | 3 | ## Overview 4 | 5 | This plugin uses version 3.2 to take advantage of [Google Cast Framework](https://developers.google.com/cast/docs/developers), and creates a button to start/stop streaming. 6 | 7 | In order to get the most of this plugin, some elements must be placed in the video tag. 8 | 9 | The following snippet shows the `data-cast-*` attributes needed to achieve Chromecast best experience, **even when they are not required**. 10 | 11 | ```html 12 | 18 | 19 | 25 | ``` 26 | 27 | The `poster` or `data-cast-poster` attributes are not required as well, but most of the media players use a static image when media is being broadcast in Chromecast, 28 | so **it is recommended their use**. 29 | 30 | `data-cast-poster` is meant for **audio only** since `poster` is not supported natively for audio tag. 31 | 32 | Chromecast **ONLY** accepts **MP4, HLS and M(PEG)-DASH** formats. 33 | 34 | Also, a page can contain **ONLY ONE** sender; otherwise, an error indicating that `cast-button` has been registered will be logged. 35 | 36 | To avoid that, [this link](https://jsfiddle.net/Luuwnjfm/24/) shows a way to get away with it if you have to render your player dynamically. 37 | 38 | ## Keyword to use it 39 | ```javascript 40 | features: [..., 'chromecast'] 41 | ``` 42 | 43 | ## API 44 | 45 | Parameter | Type | Default | Description 46 | ------ | --------- | ------- | -------- 47 | castTitle | string | `null` | Chromecast button title for WARIA purposes 48 | castAppId | string | `null` | Chromecast Application ID; if `null` is provided, it will default to `chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID` 49 | castPolicy | string | `origin` | Chromecast default policy: `origin` (by default, auto connect from same appId and page origin), `tab` (auto connect from same appId, page origin, and tab) and `page` (no auto connect) 50 | castEnableTracks | boolean | `false` | Whether to load tracks or not through Chromecast. In order to process tracks correctly, `tracks` feature must be enable on the player configuration and CORS **MUST** be setup correctly. Read [this link](https://developers.google.com/cast/docs/player) for more information 51 | castIsLive | boolean | `false` | Whether the current media is a live stream or not -------------------------------------------------------------------------------- /docs/context-menu.md: -------------------------------------------------------------------------------- 1 | # Context Menu 2 | 3 | ## Overview 4 | 5 | This plugin disabled the default context menu, and generates a custom one when performing mouse left click. 6 | 7 | By default, it creates the following actions: 8 | 9 | * Turn on/off fullscreen 10 | * Turn on/off mute 11 | * Download media 12 | 13 | ## Keyword to use it 14 | ```javascript 15 | features: [..., 'contextmenu'] 16 | ``` 17 | 18 | ## API 19 | 20 | Parameter | Type | Default | Description 21 | ------ | --------- | ------- | -------- 22 | contextMenuItems | array | `[]` | An array of objects with format `{ render (player) { }, click (player) {} }` to render and perform click menu items, or `{ isSeparator: true }` to separate items -------------------------------------------------------------------------------- /docs/facebook-pixel.md: -------------------------------------------------------------------------------- 1 | # Facebook Pixel 2 | 3 | ## Overview 4 | 5 | This plugin enables [Facebook Pixel](https://developers.facebook.com/docs/facebook-pixel) to send certain events, such as play, pause, ended, etc. 6 | 7 | It requires previous configuration on Pixel to send events properly. 8 | 9 | ## Keyword to use it 10 | ```javascript 11 | features: [..., 'facebookpixel'] 12 | ``` 13 | 14 | ## API 15 | 16 | Parameter | Type | Default | Description 17 | ------ | --------- | ------- | -------- 18 | facebookPixelTitle | string | __empty__ | The title to record events through Facebook Pixel (like Google Analytics) 19 | facebookPixelCategory | string | `Videos` | The category name to record events through Facebook Pixel (like Google Analytics) -------------------------------------------------------------------------------- /docs/google-analytics.md: -------------------------------------------------------------------------------- 1 | # Google Analytics 2 | 3 | ## Overview 4 | 5 | This plugin enables [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/events) 6 | to send media events, such as `play`, `pause`, `ended`, etc. 7 | 8 | It requires Google Analytics configuration to send events properly. For more information, check 9 | [Set up Analytics tracking](https://support.google.com/analytics/answer/1008080?hl=en). 10 | 11 | ## Keyword to use it 12 | ```javascript 13 | features: [..., 'googleanalytics'] 14 | ``` 15 | 16 | ## API 17 | 18 | Parameter | Type | Default | Description 19 | ------ | --------- | ------- | -------- 20 | googleAnalyticsTitle | string | _(empty)_ | Google Analytics Title, 21 | googleAnalyticsCategory | string | `Videos` | Google Analytics Category label, 22 | googleAnalyticsEventPlay | string | `Play` | Google Analytics Play label 23 | googleAnalyticsEventPause | string | `Pause` | Google Analytics Pause label 24 | googleAnalyticsEventEnded | string | `Ended` | Google Analytics ended event label 25 | googleAnalyticsEventTime | string | `Time` | Google Analytics time event label -------------------------------------------------------------------------------- /docs/google-tag-manager.md: -------------------------------------------------------------------------------- 1 | # Google Tag Manager 2 | 3 | ## Overview 4 | 5 | This plugin enables [Google Tag Manager](https://support.google.com/tagmanager/answer/6106961?hl=en) 6 | to push dataLayer events, such as `play`, `pause`, `ended`, etc. 7 | 8 | It requires Google Tag Manager configuration to send events properly. For more information, check 9 | [Set up GTM triggers](https://support.google.com/tagmanager/answer/6102821?hl=en). 10 | 11 | ## Keyword to use it 12 | ```javascript 13 | features: [..., 'googletagmanager'] 14 | ``` 15 | 16 | ## API 17 | 18 | Parameter | Type | Default | Description 19 | ------ | --------- | ------- | -------- 20 | Play | string | `clickPlay` | Google Tag Manager Play Event, 21 | Pause | string | `clickPause` | Google Tag Manager Pause Event 22 | Ended | string | `clickEnded` | Google Tag Manager Ended Event 23 | -------------------------------------------------------------------------------- /docs/jump-forward.md: -------------------------------------------------------------------------------- 1 | # Jump Forward 2 | 3 | ## Overview 4 | 5 | This plugin creates a button to forward media a specific number of seconds. 6 | 7 | It will work even when media is not being played initially. 8 | 9 | ## Keyword to use it 10 | ```javascript 11 | features: [..., 'jumpforward'] 12 | ``` 13 | 14 | ## API 15 | 16 | Parameter | Type | Default | Description 17 | ------ | --------- | ------- | -------- 18 | jumpForwardInterval | number | `30` | Seconds to jump forward media 19 | jumpForwardText | string | `null` | Title for Jump Forward button for WARIA purposes 20 | iconSpritePathJumpForward | string | `mejs-jump-forward.svg` | Path for the SVG icon sprite file. 21 | -------------------------------------------------------------------------------- /docs/loop.md: -------------------------------------------------------------------------------- 1 | # Loop 2 | 3 | ## Overview 4 | 5 | This plugin creates a loop button in the control bar to turn on/off the loop effect. If activated, it will restart media once it finishes. 6 | 7 | This button mimics the HTML5's `loop` attribute in the `video`/`audio` tags. 8 | 9 | ## Keyword to use it 10 | ```javascript 11 | features: [..., 'loop'] 12 | ``` 13 | 14 | ## API 15 | 16 | Parameter | Type | Default | Description 17 | ------ | --------- | ------- | -------- 18 | loopText | string | `null` | Title for Loop button for WARIA purposes when loop feature is activated -------------------------------------------------------------------------------- /docs/markers.md: -------------------------------------------------------------------------------- 1 | # Markers 2 | 3 | ## Overview 4 | 5 | This plugin allows you to create Visual Cues in the progress time rail. 6 | 7 | Also, allows you to register a custom callback function that will be triggered every time the media reaches a marker. 8 | 9 | The `MediaElementPlayer` object and media's current time should be passed to the registered callback function. 10 | 11 | The marker color is configurable. 12 | 13 | ## Keyword to use it 14 | ```javascript 15 | features: [..., 'markers'] 16 | ``` 17 | 18 | ## API 19 | 20 | Parameter | Type | Default | Description 21 | ------ | --------- | ------- | -------- 22 | markerColor | string | `#E9BC3D` | Specify the color of marker in hexadecimal code 23 | markerWidth | number | `1` | Specify the width of marker in pixels 24 | markers | array | `[]` | List of numbers to specify marker times in seconds 25 | markerCallback | function | `function(media, time) {}` | Callback function invoked when a marker position is reached -------------------------------------------------------------------------------- /docs/markersrolls.md: -------------------------------------------------------------------------------- 1 | # Markers 2 | 3 | ## Overview 4 | 5 | Based in Markers and Postroll plugins. 6 | 7 | This plugin allows you to create Visual Cues in the progress time rail and inject HTML content in these markers. 8 | The HTML content will be displayed every time the media reaches a marker. 9 | 10 | Every marker answer to a URL to inject the content in the video player when the marker position is reached. 11 | 12 | Color for markers are configurable. 13 | 14 | ## Keyword to use it 15 | ```javascript 16 | features: [..., 'markersrolls'] 17 | ``` 18 | 19 | ## API 20 | 21 | Parameter | Type | Default | Description 22 | ------ | --------- | ------- | -------- 23 | markersRollsColor | string | `#E9BC3D` | Specify the color of markers in hexadecimal code 24 | markersRollsWidth | number | `1` | Specify the width of markers in pixels 25 | markersRolls | object | `{}` | Marker times in seconds associated to the URL to inject. See demo folder for examples. 26 | -------------------------------------------------------------------------------- /docs/picture-in-picture.md: -------------------------------------------------------------------------------- 1 | # Picture in Picture 2 | 3 | ## Overview 4 | 5 | This feature allows you to view a video outside of the browsers viewport. 6 | Also know as **Picture-In-Picture** or PiP 7 | 8 | ## Note 9 | 10 | + This is not a W3C standard though it supported by chrome (70 or later) and Safari (10 or later) 11 | 12 | 13 | ## Keyword 14 | 15 | ```javascript 16 | $("video").mediaelementplayer({ 17 | features: [..., 'pictureInPicture'] 18 | }); 19 | ``` 20 | 21 | ## API 22 | 23 | Parameter | Type | Default | Description 24 | ------ | ------ | ------ | ------ 25 | PiPTitle |string |`null` |alternative button title 26 | -------------------------------------------------------------------------------- /docs/playlist.md: -------------------------------------------------------------------------------- 1 | # Playlist 2 | 3 | ## Overview 4 | 5 | This plugin allows the creation of a video/audio playlist. 6 | 7 | The following table described the components that can be used with this plugin, and the keyword to be used on the `features` array configuration. 8 | 9 | Component | Keyword | Description 10 | --------- | ------- | --------------- 11 | Playlist | `playlist` | REQUIRED; The main plugin that builds the playlist 12 | Previous Track | `prevtrack` | OPTIONAL; Control to go to the previous playlist item 13 | Next Track | `nexttrack` | OPTIONAL; Control to go to the next playlist item 14 | Loop | `loop` | OPTIONAL; Control to loop the current media 15 | Shuffle | `shuffle` | OPTIONAL; Control to shuffle the playlist 16 | 17 | **NOTE:** If you plan to use Loop, it is strongly recommended NOT to use the standalone version of Loop included in the project. 18 | 19 | ## Keyword to use it 20 | ```javascript 21 | features: [..., 'playlist', 'nexttrack', 'prevtrack', 'shuffle', 'loop'] 22 | ``` 23 | 24 | ## API 25 | 26 | Parameter | Type | Default | Description 27 | ------ | --------- | ------- | -------- 28 | playlist | array | `[]` | List to be played; the array consists in a series of objects that MUST include the `src` and `title` attributes; other possible items: `data-playlist-thumbnail`, `type`, `description`. **If its empty, it will search for all the `source` elements within the video/audio tags** 29 | showPlaylist | boolean | `true` | Whether or not to display the playlist; if so, a button to toggle the playlist will be displayed 30 | autoClosePlaylist | boolean | `false` | If set to `true`, the playlist container will hide once user selects an item 31 | prevText | string | `null` | Title for Previous button for WARIA purposes 32 | nextText | string | `null` | Title for Next button for WARIA purposes 33 | loopText | string | `null` | Title for Loop button for WARIA purposes 34 | shuffleText | string | `null` | Title for Shuffle button for WARIA purposes 35 | playlistTitle | string | `null` | Title for Playlist button for WARIA purposes 36 | currentMessage | string | `null` | Message ONLY for audio, prepended to the `title` of media (i.e., _Now playing_) 37 | -------------------------------------------------------------------------------- /docs/postroll.md: -------------------------------------------------------------------------------- 1 | # Postroll 2 | 3 | ## Overview 4 | 5 | This plugin allows the injection of any HTML content in an independent layer once the media has ended. 6 | 7 | The following snippet shows the proper HTML to activate the postroll functionality. 8 | 9 | ```html 10 | 14 | ``` 15 | 16 | The `link` tag's `rel` attribute **must be `postroll` always**. 17 | 18 | ## Keyword to use it 19 | ```javascript 20 | features: [..., 'postroll'] 21 | ``` 22 | 23 | ## API 24 | 25 | Parameter | Type | Default | Description 26 | ------ | --------- | ------- | -------- 27 | postrollCloseText | string | `null` | Title for button to Postroll layer for WARIA purposes -------------------------------------------------------------------------------- /docs/preview.md: -------------------------------------------------------------------------------- 1 | # Preview 2 | 3 | ## Overview 4 | 5 | This plugin allows the creation of a preview effect on videos: playing on hover and with possibility of mute/fade-in/fade-out its audio. 6 | 7 | ## Keyword to use it 8 | ```javascript 9 | features: [..., 'preview'] 10 | ``` 11 | 12 | ## API 13 | 14 | Parameter | Type | Default | Description 15 | ------ | --------- | ------- | -------- 16 | previewMode | boolean | `false` | Media starts playing when users mouse hovers on it, and resets when leaving player area 17 | muteOnPreviewMode | boolean | `true` | When playing in preview mode, turn on/off sound 18 | fadeInAudioStart | number | `0` | If `fadeInAudioInterval` is set, time when it starts fading in 19 | fadeInAudioInterval | number | `0` | When playing media, time interval to fade in audio (must be greater than zero) 20 | fadeOutAudioStart | number | `0` | If `fadeOutAudioInterval` is set, time when it starts fading out 21 | fadeOutAudioInterval | number | `0` | When playing media, time interval to fade out audio (must be greater than zero) 22 | fadePercent | number | `0.2` | Percentage in which media will fade in/out (in decimals, where 0.2 = 20%, 1 = 100%) 23 | pauseOnlyOnPreview | boolean | `false` | Whether reset or not the media when on preview mode 24 | delayPreview | number | `0` | Delay in milliseconds to start previewing media -------------------------------------------------------------------------------- /docs/quality.md: -------------------------------------------------------------------------------- 1 | # Quality 2 | 3 | ## Overview 4 | 5 | This plugin allows the generation of a menu with different video/audio qualities, depending of the elements set 6 | in the tags, such as `title` and `data-quality` 7 | 8 | ## Keyword to use it 9 | ```javascript 10 | features: [..., 'quality'] 11 | ``` 12 | 13 | ## API 14 | 15 | Parameter | Type | Default | Description 16 | ------ | --------- | ------- | -------- 17 | defaultQuality | string | `null` | Initial media quality; if `null`, it will take the first available source 18 | qualityText | string | `null` | Title for Quality button for WARIA purposes 19 | qualityChangeCallback | callback | | Action that will be executed as soon as the user change video quality; passes 3 arguments: media (the wrapper that mimics all the native events/properties/methods for all renderers), node (the original HTML video, audio or iframe tag where the media was loaded originally and string newQuality 20 | iconPathQuality | string | `mejs-quality-icon.svg` | Path for the SVG icon file -------------------------------------------------------------------------------- /docs/skip-back.md: -------------------------------------------------------------------------------- 1 | # Skip Back 2 | 3 | ## Overview 4 | 5 | This plugin creates a button to rewind media a specific number of seconds. 6 | 7 | It will work even when media is not being played initially. 8 | 9 | ## Keyword to use it 10 | ```javascript 11 | features: [..., 'skipback'] 12 | ``` 13 | 14 | ## API 15 | 16 | Parameter | Type | Default | Description 17 | ------ | --------- | ------- | -------- 18 | skipBackInterval | number | `30` | Seconds to skip back media 19 | skipBackText | string | `null` | Title for Skip Back button for WARIA purposes 20 | iconSpritePathSkipBack | string | `mejs-skip-back.svg` | Path for the SVG icon sprite file. 21 | -------------------------------------------------------------------------------- /docs/snapshot.md: -------------------------------------------------------------------------------- 1 | # Mediaelement Snapshot 2 | 3 | * Author: Yassine Qoraiche 4 | * Website: https://codecsocean.com/ 5 | * License: MIT 6 | 7 | ## Overview 8 | 9 | Mediaelement Snapshot plugin creates a button in the player controls allows to take video snapshots with different image types (jpeg, png). 10 | 11 | ## Installation 12 | 13 | Download plugin files and place the js files after the main [Mediaelement](https://github.com/mediaelement/mediaelement/) player js `mediaelement-and-player.min.js` file: 14 | 15 | ```HTML 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ``` 24 | Place plugin main CSS style after the main player stylesheet 25 | 26 | ```HTML 27 | 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | Add plugin keyword to the features list 36 | 37 | ```Javascript 38 | features: [..., 'snapshot'] 39 | ``` 40 | 41 | That's it !. 42 | 43 | For more details about [How to Install mediaelement plugin](https://github.com/mediaelement/mediaelement-plugins#installation). 44 | 45 | ## Usage 46 | 47 | Initialize Snapshot plugin 48 | 49 | ```Javascript 50 | 51 | var player = new MediaElementPlayer(document.querySelector('video'), { 52 | 53 | features:['play', 'playpause', volume', 'progress', 'snapshot', fullscreen'], 54 | 55 | snapType:'jpeg', 56 | snapQuality: 0.5, //half quality 57 | snapShot: true, 58 | 59 | snapSuccess: function(snap){ 60 | console.log(snap.url); //return snap object 61 | }, 62 | 63 | snapError: function(){ 64 | console.log('you can not take snapshot while the player loading !'); 65 | } 66 | 67 | }); 68 | 69 | ``` 70 | 71 | ## API 72 | 73 | | Parameter | Type | Default | Description | 74 | | ----------- | -------------- | --------| ----------- 75 | | snapShot | boolean | `true` | Either to save snapshot image locally (`true`) or not (`false`) 76 | | snapType | string | `png` | Type of image `png`or `jpeg` 77 | | snapWidth | number | Default video width | Snapshot image width 78 | | snapHeight | number | Default video height | Snapshot image height 79 | | snapQuality | number or float | `1` | Snapshot image quality between `0` and `1` 80 | | snapSuccess | function() | `null` | success callback => (snapshot) accepts one parameter contains snapshot object 81 | | snapError | function() | `null` | error callback() => () accepts no parameters 82 | 83 | ## Support 84 | 85 | Having trouble with this plugin? [create an issue](https://github.com/Codecsocean/mediaelement-snapshot/issues) describing the problem that you have encountered. 86 | 87 | -------------------------------------------------------------------------------- /docs/source-chooser.md: -------------------------------------------------------------------------------- 1 | # Source Chooser 2 | 3 | ## Overview 4 | 5 | This plugin generates a button to choose between different sources, if more than one is indicated within the `video`/`audio` tags. 6 | 7 | ```html 8 | 13 | ``` 14 | 15 | ## Keyword to use it 16 | ```javascript 17 | features: [..., 'sourcechooser'] 18 | ``` 19 | 20 | ## API 21 | 22 | Parameter | Type | Default | Description 23 | ------ | --------- | ------- | -------- 24 | sourcechooserText | string | `null` | Title for Source Chooser button for WARIA purposes -------------------------------------------------------------------------------- /docs/speed.md: -------------------------------------------------------------------------------- 1 | # Speed 2 | 3 | ## Overview 4 | 5 | This plugin creates a button that allows the user to play media at different speed rates. 6 | 7 | ## Keyword to use it 8 | ```javascript 9 | features: [..., 'speed'] 10 | ``` 11 | 12 | ## API 13 | 14 | Parameter | Type | Default | Description 15 | ------ | --------- | ------- | -------- 16 | speeds | array | `['1.50', '1.25', '1.00', '0.75']` | Enable speeding media; accounts for strings or objects like `[{name: 'Slow', value: '0.75'}, {name: 'Normal', value: '1.00'}, ...]` 17 | defaultSpeed | number | `1.00` | Initial speed of media 18 | speedChar | string | `x` | Character used to stop speeding media 19 | speedText | string | `null` | Title for Speed button for WARIA purposes -------------------------------------------------------------------------------- /docs/stop.md: -------------------------------------------------------------------------------- 1 | # Stop 2 | 3 | ## Overview 4 | 5 | This plugin enables a Stop button in the control bar, which basically pauses media and loads an empty source. Once this is done, user 6 | must implement his own mechanism to resume since the reference to the original source will get lost. 7 | 8 | If a `stop` method is detected, the button will fire its functionality. 9 | 10 | ## Keyword to use it 11 | ```javascript 12 | features: [..., 'stop'] 13 | ``` 14 | 15 | ## API 16 | 17 | Parameter | Type | Default | Description 18 | ------ | --------- | ------- | -------- 19 | stopText | string | `null` | Title for Stop button for WARIA purposes -------------------------------------------------------------------------------- /docs/vrview.md: -------------------------------------------------------------------------------- 1 | # VRView 2 | 3 | ## Overview 4 | 5 | This plugin allows the interaction of [Google's VRView](https://developers.google.com/vr/concepts/vrview-web) with `MediaElement.js` to see 360 videos. 6 | 7 | Google VRView only supports MP4, M(PEG)-DASH and HLS videos. 8 | 9 | ## API 10 | 11 | Parameter | Type | Default | Description 12 | ------ | --------- | ------- | -------- 13 | vrPath | string | _empty_ | Path to load Google VRView library; by default, it will try to load `https://storage.googleapis.com/vrview/2.0/build/vrview.min.js` 14 | vrIsStereo | boolean | `true` | Indicates whether the content at the image or video URL is stereo or not 15 | vrIsAutopanOff | boolean | `true` | When true, disables the autopan introduction on desktop 16 | vrDebug | boolean | `false` | When `true`, turns on debug features like rendering hotspots ad showing the FPS meter 17 | vrDefaultYaw | number | `0` | Numeric angle in degrees of the initial heading for the 360° content. By default, the camera points at the center of the underlying image 18 | vrIsYawOnly | boolean | `false` | When `true`, prevents roll and pitch. This is intended for stereo panoramas -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mediaelement-plugins", 3 | "version": "5.0.0", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/mediaelement/mediaelement-plugins.git" 7 | }, 8 | "bugs": { 9 | "url": "https://github.com/mediaelement/mediaelement-plugins/issues" 10 | }, 11 | "private": false, 12 | "devDependencies": { 13 | "autoprefixer": "^6.7.7", 14 | "babel-cli": "^6.24.1", 15 | "babel-core": "^6.24.1", 16 | "babel-preset-env": "^1.5.0", 17 | "babel-register": "^6.24.1", 18 | "babelify": "^7.3.0", 19 | "browserify": "^13.1.1", 20 | "browserify-derequire": "^0.9.4", 21 | "bundle-collapser": "^1.2.1", 22 | "cssnano": "^3.8.0", 23 | "grunt": "^1.4.1", 24 | "grunt-babel": "^6.0.0", 25 | "grunt-browserify": "^5.0.0", 26 | "grunt-cli": "^0.1.13", 27 | "grunt-contrib-clean": "^1.1.0", 28 | "grunt-contrib-concat": "^1.0.1", 29 | "grunt-contrib-copy": "^1.0.0", 30 | "grunt-contrib-uglify": "^3.0.1", 31 | "grunt-contrib-watch": "^1.0.0", 32 | "grunt-eslint": "^19.0.0", 33 | "grunt-postcss": "^0.9.0", 34 | "grunt-remove-logging": "^0.2.0", 35 | "grunt-shell": "^2.1.0", 36 | "grunt-stylelint": "^0.8.0", 37 | "grunt-text-replace": "^0.4.0", 38 | "stylelint": "^7.10.1", 39 | "stylelint-order": "^0.4.4", 40 | "uglify-js": "^3.0.10" 41 | }, 42 | "dependencies": { 43 | "global": "^4.3.1", 44 | "mediaelement": "^5.0.1" 45 | }, 46 | "browserify": { 47 | "extensions": [ 48 | ".js" 49 | ], 50 | "transform": [ 51 | [ 52 | "babelify", 53 | { 54 | "comments": false, 55 | "presets": [ 56 | [ 57 | "env", 58 | { 59 | "targets": { 60 | "browsers": [ 61 | "last 5 versions", 62 | "ie > 10", 63 | "ios > 7", 64 | "android > 3" 65 | ] 66 | } 67 | } 68 | ] 69 | ] 70 | } 71 | ] 72 | ] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/src/.DS_Store -------------------------------------------------------------------------------- /src/a11y/a11y-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.de !== undefined) { 4 | mejs.i18n.de['mejs.a11y-audio-description'] = 'Audio Deskription An/Aus'; 5 | mejs.i18n.de['mejs.a11y-video-description'] = 'Video Deskription An/Aus'; 6 | } 7 | 8 | if (mejs.i18n.fr !== undefined) { 9 | mejs.i18n.fr['mejs.a11y-audio-description'] = 'Audio-description étendue On/Off'; 10 | mejs.i18n.fr['mejs.a11y-video-description'] = 'Langue des signes On/Off'; 11 | } 12 | 13 | if (mejs.i18n.nl !== undefined) { 14 | mejs.i18n.nl['mejs.a11y-audio-description'] = 'Audiobeschrijving Aan/Uit'; 15 | mejs.i18n.nl['mejs.a11y-video-description'] = 'Gebarentaal Aan/Uit'; 16 | } 17 | 18 | if (mejs.i18n.tr !== undefined) { 19 | mejs.i18n.tr['mejs.a11y-audio-description'] = 'Sesli betimleme değiştir'; 20 | mejs.i18n.tr['mejs.a11y-video-description'] = 'Görüntülü betimleme değişti'; 21 | } 22 | -------------------------------------------------------------------------------- /src/a11y/a11y.css: -------------------------------------------------------------------------------- 1 | .mejs-volume-button.hidden, 2 | .mejs__volume-button.hidden { 3 | display: none; 4 | } 5 | 6 | .mejs-audio-description-player, 7 | .mejs__audio-description-player { 8 | display: none; 9 | } 10 | -------------------------------------------------------------------------------- /src/a11y/audio-description-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/a11y/video-description-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/ads/ads.css: -------------------------------------------------------------------------------- 1 | .mejs__ads > a, 2 | .mejs-ads > a { 3 | display: block; 4 | height: 100%; 5 | position: absolute; 6 | right: 0; 7 | top: 0; 8 | width: 100%; 9 | } 10 | .mejs__ads-skip-block, 11 | .mejs-ads-skip-block { 12 | background: #000; 13 | background: rgba(0, 0, 0, 0.5); 14 | color: #fff; 15 | display: block; 16 | padding: 10px; 17 | position: absolute; 18 | right: 0; 19 | top: 0; 20 | } 21 | .mejs__ads-skip-button, 22 | .mejs-ads-skip-button { 23 | cursor: pointer; 24 | } 25 | .mejs__ads-skip-button:hover, 26 | .mejs-ads-skip-button:hover { 27 | text-decoration: underline; 28 | } 29 | -------------------------------------------------------------------------------- /src/airplay/airplay.css: -------------------------------------------------------------------------------- 1 | .mejs__airplay-button > button, 2 | .mejs-airplay-button > button { 3 | background: url('airplay.svg') no-repeat 0 4px; 4 | } 5 | 6 | .mejs__airplay-button > button .fill, 7 | .mejs-airplay-button > button .fill { 8 | fill: #fff; 9 | } 10 | 11 | .mejs__airplay-button > button.active .fill, 12 | .mejs-airplay-button > button.active .fill { 13 | fill: #66a8cc; 14 | } 15 | -------------------------------------------------------------------------------- /src/airplay/airplay.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Airplay button 5 | * 6 | * This feature creates an AirPlay button that enhances native AirPlay capabilities, if found 7 | */ 8 | 9 | // Feature configuration 10 | Object.assign(mejs.MepDefaults, { 11 | /** 12 | * @type {?String} 13 | */ 14 | airPlayText: null 15 | }); 16 | 17 | Object.assign(MediaElementPlayer.prototype, { 18 | /** 19 | * Feature constructor. 20 | * 21 | * Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list 22 | */ 23 | buildairplay () { 24 | 25 | // bail early if not available 26 | if (!window.WebKitPlaybackTargetAvailabilityEvent) { 27 | return; 28 | } 29 | 30 | const 31 | t = this, 32 | airPlayTitle = mejs.Utils.isString(t.options.airPlayText) ? t.options.airPlayText : 'AirPlay', 33 | button = document.createElement('div') 34 | ; 35 | 36 | button.className = `${t.options.classPrefix}button ${t.options.classPrefix}airplay-button`; 37 | button.innerHTML = ``; 38 | 39 | button.addEventListener('click', () => { 40 | t.media.originalNode.webkitShowPlaybackTargetPicker(); 41 | }); 42 | 43 | const acceptAirPlay = t.media.originalNode.getAttribute('x-webkit-airplay'); 44 | if (!acceptAirPlay || acceptAirPlay !== 'allow') { 45 | t.media.originalNode.setAttribute('x-webkit-airplay', 'allow'); 46 | } 47 | 48 | t.media.originalNode.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', () => { 49 | const 50 | name = t.media.originalNode.webkitCurrentPlaybackTargetIsWireless ? 'Started' : 'Stopped', 51 | status = t.media.originalNode.webkitCurrentPlaybackTargetIsWireless ? 'active' : '', 52 | icon = button.querySelector('button'), 53 | event = mejs.Utils.createEvent(`airplay${name}`, t.media) 54 | ; 55 | t.media.dispatchEvent(event); 56 | 57 | if (status === 'active') { 58 | mejs.Utils.addClass(icon, 'active'); 59 | } else { 60 | mejs.Utils.removeClass(icon, 'active'); 61 | } 62 | }); 63 | 64 | t.media.originalNode.addEventListener('webkitplaybacktargetavailabilitychanged', (e) => { 65 | if (e.availability === 'available') { 66 | t.addControlElement(button, 'airplay'); 67 | } 68 | }); 69 | } 70 | }); 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/airplay/airplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/src/airplay/airplay.png -------------------------------------------------------------------------------- /src/airplay/airplay.svg: -------------------------------------------------------------------------------- 1 | 7 -------------------------------------------------------------------------------- /src/chromecast/chromecast.css: -------------------------------------------------------------------------------- 1 | .mejs__chromecast-button > button, 2 | .mejs-chromecast-button > button { 3 | --disconnected-color: #fff; 4 | background: none; 5 | display: inline-block; 6 | } 7 | .mejs__chromecast-container, 8 | .mejs-chromecast-container { 9 | background: #000; 10 | color: #fff; 11 | font-size: 10px; 12 | left: 0; 13 | padding: 5px; 14 | position: absolute; 15 | top: 0; 16 | z-index: 1; 17 | } 18 | 19 | .mejs__chromecast-layer > img, 20 | .mejs-chromecast-layer > img { 21 | left: 0; 22 | position: absolute; 23 | top: 0; 24 | z-index: 0; 25 | } 26 | 27 | .mejs__chromecast-icon, 28 | .mejs-chromecast-icon { 29 | background: url('chromecast.svg') no-repeat 0 0; 30 | display: inline-block; 31 | height: 14px; 32 | margin-right: 5px; 33 | width: 17px; 34 | } -------------------------------------------------------------------------------- /src/chromecast/chromecast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/src/chromecast/chromecast.png -------------------------------------------------------------------------------- /src/chromecast/chromecast.svg: -------------------------------------------------------------------------------- 1 | 5 -------------------------------------------------------------------------------- /src/context-menu/context-menu.css: -------------------------------------------------------------------------------- 1 | .mejs__contextmenu, 2 | .mejs-contextmenu { 3 | background: #fff; 4 | border: solid 1px #999; 5 | border-radius: 4px; 6 | left: 0; 7 | padding: 10px; 8 | position: absolute; 9 | top: 0; 10 | width: 150px; 11 | z-index: 9999999999; /* make sure it shows on fullscreen */ 12 | } 13 | 14 | .mejs__contextmenu-separator, 15 | .mejs-contextmenu-separator { 16 | background: #333; 17 | font-size: 0; 18 | height: 1px; 19 | margin: 5px 6px; 20 | } 21 | 22 | .mejs__contextmenu-item, 23 | .mejs-contextmenu-item { 24 | color: #333; 25 | cursor: pointer; 26 | font-size: 12px; 27 | padding: 4px 6px; 28 | } 29 | 30 | .mejs__contextmenu-item:hover, 31 | .mejs-contextmenu-item:hover { 32 | background: #2c7c91; 33 | color: #fff; 34 | } 35 | -------------------------------------------------------------------------------- /src/facebook-pixel/facebook-pixel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Facebook Pixel Plugin 3 | * 4 | * This feature enables Facebook Pixel to send certain events, such as play, pause, ended, etc. It requires previous configuration 5 | * on Pixel to send events properly. 6 | * @see https://developers.facebook.com/docs/facebook-pixel 7 | */ 8 | 9 | // Feature configuration 10 | Object.assign(mejs.MepDefaults, { 11 | /** 12 | * @type {String} 13 | */ 14 | facebookPixelTitle: '', 15 | /** 16 | * @type {String} 17 | */ 18 | facebookPixelCategory: 'Videos' 19 | }); 20 | 21 | Object.assign(MediaElementPlayer.prototype, { 22 | 23 | /** 24 | * Feature constructor. 25 | * 26 | * Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list 27 | * @param {MediaElementPlayer} player 28 | * @param {HTMLElement} controls 29 | * @param {HTMLElement} layers 30 | * @param {HTMLElement} media 31 | */ 32 | buildfacebookpixel (player, controls, layers, media) { 33 | player.fbPixelPlay = () => { 34 | if (typeof fbq !== 'undefined') { 35 | fbq('trackCustom', player.options.facebookPixelCategory, { 36 | Event: 'Play', 37 | Title: player.options.facebookPixelTitle === '' ? player.media.currentSrc : 38 | player.options.facebookPixelTitle 39 | }); 40 | } 41 | }; 42 | player.fbPixelPause = () => { 43 | if (typeof fbq !== 'undefined') { 44 | fbq('trackCustom', player.options.facebookPixelCategory, { 45 | Event: 'Pause', 46 | Title: player.options.facebookPixelTitle === '' ? player.media.currentSrc : 47 | player.options.facebookPixelTitle 48 | }); 49 | } 50 | }; 51 | player.fbPixelEnded = () => { 52 | if (typeof fbq !== 'undefined') { 53 | fbq('trackCustom', player.options.facebookPixelCategory, { 54 | Event: 'Ended', 55 | Title: player.options.facebookPixelTitle === '' ? player.media.currentSrc : 56 | player.options.facebookPixelTitle 57 | }); 58 | } 59 | }; 60 | 61 | media.addEventListener('play', player.fbPixelPlay); 62 | media.addEventListener('pause', player.fbPixelPause); 63 | media.addEventListener('ended', player.fbPixelEnded); 64 | }, 65 | cleanfacebookpixel (player, controls, layers, media) { 66 | media.removeEventListener('play', player.fbPixelPlay); 67 | media.removeEventListener('pause', player.fbPixelPause); 68 | media.removeEventListener('ended', player.fbPixelEnded); 69 | } 70 | }); 71 | -------------------------------------------------------------------------------- /src/google-analytics/google-analytics.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Google Analytics Plugin 5 | * 6 | * This feature enables GA to send certain events, such as play, pause, ended, etc. It requires previous configuration 7 | * on GA to send events properly. 8 | * @see https://developers.google.com/analytics/devguides/collection/analyticsjs/events 9 | */ 10 | 11 | 12 | // Feature configuration 13 | Object.assign(mejs.MepDefaults, { 14 | /** 15 | * @type {String} 16 | */ 17 | googleAnalyticsTitle: '', 18 | /** 19 | * @type {String} 20 | */ 21 | googleAnalyticsCategory: 'Videos', 22 | /** 23 | * @type {String} 24 | */ 25 | googleAnalyticsEventPlay: 'Play', 26 | /** 27 | * @type {String} 28 | */ 29 | googleAnalyticsEventPause: 'Pause', 30 | /** 31 | * @type {String} 32 | */ 33 | googleAnalyticsEventEnded: 'Ended', 34 | /** 35 | * @type {String} 36 | */ 37 | googleAnalyticsEventTime: 'Time' 38 | }); 39 | 40 | 41 | Object.assign(MediaElementPlayer.prototype, { 42 | 43 | /** 44 | * Feature constructor. 45 | * 46 | * Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list 47 | * @param {MediaElementPlayer} player 48 | * @param {HTMLElement} controls 49 | * @param {HTMLElement} layers 50 | * @param {HTMLElement} media 51 | */ 52 | buildgoogleanalytics (player, controls, layers, media) { 53 | 54 | media.addEventListener('play', () => { 55 | if (typeof ga !== 'undefined') { 56 | ga('send', 'event', 57 | player.options.googleAnalyticsCategory, 58 | player.options.googleAnalyticsEventPlay, 59 | (player.options.googleAnalyticsTitle === '') ? player.media.currentSrc : player.options.googleAnalyticsTitle 60 | ); 61 | } 62 | }, false); 63 | 64 | media.addEventListener('pause', () => { 65 | if (typeof ga !== 'undefined') { 66 | ga('send', 'event', 67 | player.options.googleAnalyticsCategory, 68 | player.options.googleAnalyticsEventPause, 69 | (player.options.googleAnalyticsTitle === '') ? player.media.currentSrc : player.options.googleAnalyticsTitle 70 | ); 71 | } 72 | }, false); 73 | 74 | media.addEventListener('ended', () => { 75 | if (typeof ga !== 'undefined') { 76 | ga('send', 'event', 77 | player.options.googleAnalyticsCategory, 78 | player.options.googleAnalyticsEventEnded, 79 | (player.options.googleAnalyticsTitle === '') ? player.media.currentSrc : player.options.googleAnalyticsTitle 80 | ); 81 | } 82 | }, false); 83 | } 84 | }); -------------------------------------------------------------------------------- /src/google-tag-manager/google-tag-manager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Google Tag Manager Plugin 3 | * 4 | * This feature enables Google Tag Manager to send certain events, such as play, pause, ended, etc. It requires previous configuration 5 | * on Google Tag Manager configuration to send events properly. For more information, check 6 | * https://support.google.com/tagmanager/answer/6102821?hl=en 7 | * 8 | * @see https://developers.google.com/tag-manager/ 9 | */ 10 | 11 | // Feature configuration 12 | Object.assign(mejs.MepDefaults, { 13 | /** 14 | * @type {Array} 15 | */ 16 | dataLayer: [] 17 | }); 18 | 19 | Object.assign(MediaElementPlayer.prototype, { 20 | 21 | /** 22 | * Feature constructor. 23 | * 24 | * Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list 25 | * @param {MediaElementPlayer} player 26 | * @param {HTMLElement} controls 27 | * @param {HTMLElement} layers 28 | * @param {HTMLElement} media 29 | */ 30 | buildgoogletagmanager (player, controls, layers, media) { 31 | player.tagManagerPlay = () => { 32 | if (typeof dataLayer !== 'undefined') { 33 | dataLayer.push({'event': 'clickPlay'}); 34 | } 35 | }; 36 | player.tagManagerPause = () => { 37 | if (typeof dataLayer !== 'undefined') { 38 | dataLayer.push({'event': 'clickPause'}); 39 | } 40 | }; 41 | player.tagManagerEnded = () => { 42 | if (typeof dataLayer !== 'undefined') { 43 | dataLayer.push({'event': 'clickEnded'}); 44 | } 45 | }; 46 | 47 | media.addEventListener('play', player.tagManagerPlay); 48 | media.addEventListener('pause', player.tagManagerPause); 49 | media.addEventListener('ended', player.tagManagerEnded); 50 | }, 51 | cleangoogletagmanager (player, controls, layers, media) { 52 | media.removeEventListener('play', player.tagManagerPlay); 53 | media.removeEventListener('pause', player.tagManagerPause); 54 | media.removeEventListener('ended', player.tagManagerEnded); 55 | } 56 | }); 57 | -------------------------------------------------------------------------------- /src/header.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MediaElement.js 3 | * http://www.mediaelementjs.com/ 4 | * 5 | * Wrapper that mimics native HTML5 MediaElement (audio and video) 6 | * using a variety of technologies (pure JavaScript, Flash, iframe) 7 | * 8 | * Copyright 2010-2017, John Dyer (http://j.hn/) 9 | * License: MIT 10 | * 11 | */ -------------------------------------------------------------------------------- /src/jump-forward/jump-forward.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Jump forward button 5 | * 6 | * This feature creates a button to forward media a specific number of seconds. 7 | */ 8 | 9 | // Translations (English required) 10 | mejs.i18n.en['mejs.time-jump-forward'] = ['Jump forward 1 second', 'Jump forward %1 seconds']; 11 | 12 | Object.assign(mejs.MepDefaults, { 13 | /** 14 | * @type {Number} 15 | */ 16 | jumpForwardInterval: 30, 17 | /** 18 | * @type {?String} 19 | */ 20 | jumpForwardText: null, 21 | /** 22 | * The path where the icon sprite is located 23 | * @type {String} 24 | */ 25 | iconSpritePathJumpForward: 'mejs-jump-forward.svg', 26 | }); 27 | 28 | Object.assign(MediaElementPlayer.prototype, { 29 | /** 30 | * Feature constructor. 31 | * 32 | * Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list 33 | * @param {MediaElementPlayer} player 34 | * @param {HTMLElement} controls 35 | * @param {HTMLElement} layers 36 | * @param {HTMLElement} media 37 | */ 38 | buildjumpforward (player, controls, layers, media) { 39 | 40 | const 41 | t = this, 42 | defaultTitle = mejs.i18n.t('mejs.time-jump-forward', t.options.jumpForwardInterval), 43 | forwardTitle = mejs.Utils.isString(t.options.jumpForwardText) ? t.options.jumpForwardText.replace('%1', t.options.jumpForwardInterval) : defaultTitle, 44 | button = document.createElement('div') 45 | ; 46 | 47 | button.className = `${t.options.classPrefix}button ${t.options.classPrefix}jump-forward-button`; 48 | button.innerHTML = mejs.Utils.generateControlButton(t.id, forwardTitle, forwardTitle, t.media.options.iconSpritePathJumpForward, ['icon-jump-forward'], t.options.classPrefix); 49 | 50 | t.addControlElement(button, 'jumpforward'); 51 | 52 | // add a click toggle event 53 | button.addEventListener('click', function() { 54 | const duration = !isNaN(media.duration) ? media.duration : t.options.jumpForwardInterval; 55 | if (duration) { 56 | const current = media.currentTime === Infinity ? 0 : media.currentTime; 57 | media.setCurrentTime(Math.min(current + t.options.jumpForwardInterval, duration)); 58 | } 59 | }); 60 | } 61 | }); 62 | -------------------------------------------------------------------------------- /src/jump-forward/jumpforward.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 30 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/loop/loop-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.loop'] = 'Commuta Bucle'; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.loop'] = 'Přepnout smyčku'; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.loop'] = 'Wiederholung (de-)aktivieren'; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.loop'] = 'Alternar Repetición'; 14 | } 15 | if (mejs.i18n.fa !== undefined) { 16 | mejs.i18n.fa['mejs.loop'] = 'حلقه تعویض'; 17 | } 18 | if (mejs.i18n.fr !== undefined) { 19 | mejs.i18n.fr['mejs.loop'] = 'Répéter'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.loop'] = 'Uključi/isključi ponavljanje'; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.loop'] = 'Húzza át a kapcsolót'; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.loop'] = 'Passare il ciclo'; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.loop'] = 'トグルループ'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.loop'] = '루프 토글'; 35 | } 36 | if (mejs.i18n.ms !== undefined) { 37 | mejs.i18n.ms['mejs.loop'] = 'Togol ulangan'; 38 | } 39 | if (mejs.i18n.nl !== undefined) { 40 | mejs.i18n.nl['mejs.loop'] = 'Schakellus'; 41 | } 42 | if (mejs.i18n.pl !== undefined) { 43 | mejs.i18n.pl['mejs.loop'] = 'Zapętl'; 44 | } 45 | if (mejs.i18n.pt !== undefined) { 46 | mejs.i18n.pt['mejs.loop'] = 'Loop alternativo'; 47 | } 48 | if (mejs.i18n.ro !== undefined) { 49 | mejs.i18n.ro['mejs.loop'] = 'Comutați buclă'; 50 | } 51 | if (mejs.i18n.ru !== undefined) { 52 | mejs.i18n.ru['mejs.loop'] = 'Зациклить воспроизведение'; 53 | } 54 | if (mejs.i18n.sk !== undefined) { 55 | mejs.i18n.sk['mejs.loop'] = 'Prepínať slučku'; 56 | } 57 | if (mejs.i18n.sv !== undefined) { 58 | mejs.i18n.sv['mejs.loop'] = 'Repetera'; 59 | } 60 | if (mejs.i18n.tr !== undefined) { 61 | mejs.i18n.tr['mejs.loop'] = 'Döngü'; 62 | } 63 | if (mejs.i18n.uk !== undefined) { 64 | mejs.i18n.uk['mejs.loop'] = 'Повторювати'; 65 | } 66 | if (mejs.i18n.zh !== undefined) { 67 | mejs.i18n.zh['mejs.loop'] = '切換循環'; 68 | } 69 | if (mejs.i18n['zh-CN'] !== undefined) { 70 | mejs.i18n['zh-CN']['mejs.loop'] = '切换循环'; 71 | } 72 | -------------------------------------------------------------------------------- /src/loop/loop.css: -------------------------------------------------------------------------------- 1 | .mejs__loop-button > button, 2 | .mejs-loop-button > button { 3 | background: url('loop.svg') no-repeat transparent; 4 | } 5 | .mejs__loop-off > button, 6 | .mejs-loop-off > button { 7 | background-position: -20px 1px; 8 | } 9 | 10 | .mejs__loop-on > button, 11 | .mejs-loop-on > button { 12 | background-position: 0 1px; 13 | } 14 | -------------------------------------------------------------------------------- /src/loop/loop.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Loop button 5 | * 6 | * This feature creates a loop button in the control bar to toggle its behavior. It will restart media once finished 7 | * if activated 8 | */ 9 | 10 | // Translations (English required) 11 | mejs.i18n.en['mejs.loop'] = 'Toggle Loop'; 12 | 13 | // Feature configuration 14 | Object.assign(mejs.MepDefaults, { 15 | /** 16 | * @type {?String} 17 | */ 18 | loopText: null 19 | }); 20 | 21 | Object.assign(MediaElementPlayer.prototype, { 22 | /** 23 | * Feature constructor. 24 | * 25 | * Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list 26 | * @param {MediaElementPlayer} player 27 | */ 28 | buildloop (player) { 29 | const 30 | t = this, 31 | loopTitle = mejs.Utils.isString(t.options.loopText) ? t.options.loopText : mejs.i18n.t('mejs.loop'), 32 | loop = document.createElement('div') 33 | ; 34 | 35 | loop.className = `${t.options.classPrefix}button ${t.options.classPrefix}loop-button ${((player.options.loop) ? `${t.options.classPrefix}loop-on` : `${t.options.classPrefix}loop-off`)}`; 36 | loop.innerHTML = ``; 37 | 38 | t.addControlElement(loop, 'loop'); 39 | 40 | // add a click toggle event 41 | loop.addEventListener('click', () => { 42 | player.options.loop = !player.options.loop; 43 | if (player.options.loop) { 44 | mejs.Utils.removeClass(loop, `${t.options.classPrefix}loop-off`); 45 | mejs.Utils.addClass(loop, `${t.options.classPrefix}loop-on`); 46 | } else { 47 | mejs.Utils.removeClass(loop, `${t.options.classPrefix}loop-on`); 48 | mejs.Utils.addClass(loop, `${t.options.classPrefix}loop-off`); 49 | } 50 | }); 51 | } 52 | }); 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/loop/loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediaelement/mediaelement-plugins/6b5de466fd9676c1287fc0c34111843813bc2a77/src/loop/loop.png -------------------------------------------------------------------------------- /src/loop/loop.svg: -------------------------------------------------------------------------------- 1 | 4 -------------------------------------------------------------------------------- /src/picture-in-picture/picture-in-picture-i18n.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | if(mejs.i18n.es !== undefined) { 4 | mejs.i18n.es['mejs.picture-in-pictureText'] = 'Picture in picture'; 5 | } 6 | if (mejs.i18n.de !== undefined) { 7 | mejs.i18n.de['mejs.picture-in-pictureText'] = 'Bild in Bild'; 8 | } 9 | if(mejs.i18n.fr !== undefined) { 10 | mejs.i18n.fr['mejs.picture-in-pictureText'] = 'Image dans l’image'; 11 | } 12 | if(mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.picture-in-pictureText'] = 'Imagen dentro de imagen'; 14 | } 15 | 16 | 17 | // TODO Add more languages for the title attribute 18 | -------------------------------------------------------------------------------- /src/picture-in-picture/picture-in-picture.css: -------------------------------------------------------------------------------- 1 | #picture-in-picture-button { 2 | background-color: transparent; 3 | background-image: url(picture-in-picture.svg); 4 | background-position:center; 5 | background-repeat: no-repeat; 6 | background-size: auto; 7 | border: none; 8 | color: #fff; 9 | width: 30px; 10 | } 11 | -------------------------------------------------------------------------------- /src/picture-in-picture/picture-in-picture.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Picture in picture 5 | * 6 | * 7 | * This feature is currently supported by safari 11 and chrome (70) 8 | * 9 | * Univream - 2018 10 | */ 11 | 12 | 13 | mejs.i18n.en['mejs.picture-in-pictureText'] = "Picture in Picture"; 14 | 15 | // Feature configuration 16 | Object.assign(mejs.MepDefaults, { 17 | /** 18 | * @type {?String} PiPTitle - Hover title of pip-button 19 | */ 20 | PiPTitle: null 21 | }); 22 | 23 | 24 | Object.assign(MediaElementPlayer.prototype, { 25 | 26 | /** 27 | * Feature constructor. 28 | */ 29 | buildpictureInPicture () { 30 | 31 | const 32 | t = this, 33 | buttonWrapper = document.createElement('div'), 34 | button = document.createElement('button'), 35 | video = t.node; 36 | 37 | button.setAttribute('type', 'button'); 38 | button.setAttribute('id', 'picture-in-picture-button'); 39 | button.setAttribute('title', t.options.PiPTitle == null ? mejs.i18n.t('mejs.picture-in-pictureText') : t.options.PiPTitle); 40 | buttonWrapper.className = `${t.options.classPrefix}button ${t.options.classPrefix}picture-in-picture-button`; 41 | buttonWrapper.appendChild(button); 42 | 43 | if(video instanceof HTMLVideoElement) { 44 | // This is currently not a W3C standard (25-10-2018) 45 | // https://wicg.github.io/picture-in-picture/ 46 | if(document.pictureInPictureEnabled && !video.disablePictureInPicture) { 47 | button.addEventListener('click', () => { 48 | if(!document.pictureInPictureElement) { 49 | video.requestPictureInPicture() 50 | .catch(() => { 51 | // Handle error 52 | }); 53 | } 54 | else { 55 | document.exitPictureInPicture() 56 | .catch(() => { 57 | // Handle error 58 | }); 59 | } 60 | }); 61 | } 62 | // Safari implmentation 63 | else if (video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === "function") { 64 | // For more info https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls?language=javascript 65 | // Toggle PiP when the user clicks the button. 66 | button.addEventListener("click", function() { 67 | video.webkitSetPresentationMode(video.webkitPresentationMode === "picture-in-picture" ? "inline" : "picture-in-picture"); 68 | }); 69 | } 70 | else { 71 | return; 72 | } 73 | } 74 | 75 | t.addControlElement(buttonWrapper, 'pictureInPicture'); 76 | } 77 | }); 78 | -------------------------------------------------------------------------------- /src/picture-in-picture/picture-in-picture.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 19 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/postroll/postroll-i18n.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (mejs.i18n.ca !== undefined) { 4 | mejs.i18n.ca['mejs.close'] = 'Tancar'; 5 | } 6 | if (mejs.i18n.cs !== undefined) { 7 | mejs.i18n.cs['mejs.close'] = 'Zavřít'; 8 | } 9 | if (mejs.i18n.de !== undefined) { 10 | mejs.i18n.de['mejs.close'] = 'Schließen'; 11 | } 12 | if (mejs.i18n.es !== undefined) { 13 | mejs.i18n.es['mejs.close'] = 'Cerrar'; 14 | } 15 | if (mejs.i18n.fa !== undefined) { 16 | mejs.i18n.fa['mejs.close'] = 'نزدیک'; 17 | } 18 | if (mejs.i18n.fr !== undefined) { 19 | mejs.i18n.fr['mejs.close'] = 'Fermer'; 20 | } 21 | if (mejs.i18n.hr !== undefined) { 22 | mejs.i18n.hr['mejs.close'] = 'Zatvori'; 23 | } 24 | if (mejs.i18n.hu !== undefined) { 25 | mejs.i18n.hu['mejs.close'] = 'Bezárás'; 26 | } 27 | if (mejs.i18n.it !== undefined) { 28 | mejs.i18n.it['mejs.close'] = 'Chiudere'; 29 | } 30 | if (mejs.i18n.ja !== undefined) { 31 | mejs.i18n.ja['mejs.close'] = '閉じる'; 32 | } 33 | if (mejs.i18n.ko !== undefined) { 34 | mejs.i18n.ko['mejs.close'] = '종료'; 35 | } 36 | if (mejs.i18n.ms !== undefined) { 37 | mejs.i18n.ms['mejs.close'] = 'Tutup'; 38 | } 39 | if (mejs.i18n.nl !== undefined) { 40 | mejs.i18n.nl['mejs.close'] = 'Sluiten'; 41 | } 42 | if (mejs.i18n.pl !== undefined) { 43 | mejs.i18n.pl['mejs.close'] = 'Zamknij'; 44 | } 45 | if (mejs.i18n.pt !== undefined) { 46 | mejs.i18n.pt['mejs.close'] = 'Fechar'; 47 | } 48 | if (mejs.i18n.ro !== undefined) { 49 | mejs.i18n.ro['mejs.close'] = 'Închide'; 50 | } 51 | if (mejs.i18n.ru !== undefined) { 52 | mejs.i18n.ru['mejs.close'] = 'Закрыть'; 53 | } 54 | if (mejs.i18n.sk !== undefined) { 55 | mejs.i18n.sk['mejs.close'] = 'Zavrieť'; 56 | } 57 | if (mejs.i18n.sv !== undefined) { 58 | mejs.i18n.sv['mejs.close'] = 'Stäng'; 59 | } 60 | if (mejs.i18n.tr !== undefined) { 61 | mejs.i18n.tr['mejs.close'] = 'Kapat'; 62 | } 63 | if (mejs.i18n.uk !== undefined) { 64 | mejs.i18n.uk['mejs.close'] = 'Закрити'; 65 | } 66 | if (mejs.i18n.zh !== undefined) { 67 | mejs.i18n.zh['mejs.close'] = '關閉'; 68 | } 69 | if (mejs.i18n['zh-CN'] !== undefined) { 70 | mejs.i18n['zh-CN']['mejs.close'] = '关闭'; 71 | } 72 | -------------------------------------------------------------------------------- /src/postroll/postroll.css: -------------------------------------------------------------------------------- 1 | .mejs__postroll-layer, 2 | .mejs-postroll-layer { 3 | background: rgba(50, 50, 50, 0.7); 4 | bottom: 0; 5 | height: 100%; 6 | left: 0; 7 | overflow: hidden; 8 | position: absolute; 9 | width: 100%; 10 | z-index: 1000; 11 | } 12 | 13 | .mejs__postroll-layer-content, 14 | .mejs-postroll-layer-content { 15 | height: 100%; 16 | width: 100%; 17 | } 18 | .mejs__postroll-close, 19 | .mejs-postroll-close { 20 | background: rgba(50, 50, 50, 0.7); 21 | color: #fff; 22 | cursor: pointer; 23 | padding: 4px; 24 | position: absolute; 25 | right: 0; 26 | top: 0; 27 | z-index: 100; 28 | } 29 | -------------------------------------------------------------------------------- /src/postroll/postroll.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Postroll plugin 5 | * 6 | * This feature allows the injection of any HTML content in an independent layer once the media finished. 7 | * To activate it, one of the nodes contained in the `