├── .gitignore
├── LICENSE.md
├── README.md
├── addThis
├── README.md
├── index.html
├── video-js.min.css
├── video.dev.js
├── videojs.addThis.css
└── videojs.addThis.js
├── automute
├── automute.js
└── automute.less
├── callToAction
├── callToAction.js
└── callToAction.less
├── dimTheLights
├── README.md
├── dimTheLights.css
└── dimTheLights.js
├── googleAnalytics
└── videojs.ga.js
├── hideControlsOnPause
└── videojs.hideControlsOnPause.js
├── logo
├── Readme.md
├── logo.css
└── logo.js
├── playlist
├── playlist-caption.js
├── playlist-controls.js
├── playlist-item.js
├── playlist-slider.js
├── playlist.js
├── playlist.less
├── responsive.css
└── scroll-indicator.js
├── replayState
├── replayState.css
└── replayState.js
├── resize
├── videojs.resize.css
└── videojs.resize.js
├── showPosterAtEnd
└── videojs.showPosterAtEnd.js
├── socialOverlay
├── README.md
├── socialOverlay.css
└── socialOverlay.js
└── themeLoader
└── videojs.themeLoader.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /.DS_Store
2 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Brian Kelley
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | video-js-4-plugins
2 | ==================
3 |
4 | A collection of plugins for Video.js 4.x
5 |
6 |
7 | Just starting to throw these up, each will have a readme with links to a demo and how-to.
8 |
--------------------------------------------------------------------------------
/addThis/README.md:
--------------------------------------------------------------------------------
1 | #addThis Video.js Plugin#
2 | This creates a "share" menu in the control bar for video.js. Currently it only supports creating links for the some of the more popular sites, and a "more" link that opens a new window with the entire list of shareable sites.
3 |
4 | ##Usage##
5 | #####This plugin requires you to use the unminified dev build#####
6 | Just include the `addThis: {}` item in the `plugins` object for the default config. In the examples below, reddit and delicious have been disabled due to font-awesome not having icons for them. I reccomend using the Font-Awesome-More set here: https://github.com/gregoryloucas/Fontstrap
7 |
8 | ####HTML####
9 | ````html
10 |
11 |
12 |
13 |
14 | HTML5 Video Player
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 | Video Playback Not Supported
31 |
32 |
33 |
34 |
35 | ````
36 | ####Javascript####
37 | ````html
38 |
39 |
40 |
41 |
42 | HTML5 Video Player
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
78 |
79 |
80 | ````
81 |
82 | ##Options##
83 | ####Enable links: ####
84 | - **facebook** *(boolean)*
85 | - **twitter** *(boolean)*
86 | - **googleplus** *(boolean)*
87 | - **linkedin** *(boolean)*
88 | - **pinterest** *(boolean)*
89 | - **delicious** *(boolean)*
90 | - **reddit** *(boolean)*
91 | - **email** *(boolean)*
92 | - **embed** *(boolean)* *Custom*
93 | - **more** *(boolean)*
94 | - **website_url** *(string)* must start with http(s)://
95 |
96 | ####Configuration: ####
97 | - **pubid** *(string)* Your publisher profile ID (analytics). (NOT REQUIRED to use this plugin)
98 | - **ct** *(string)* Enable click tracking (shared page must have AddThis client code to measure clicks)
99 | - **email_template** *(string)* Email template to use for email sharing (requires pubid param)
100 | - **share_url** *(string)* To share a different url than the current page, specify here.
101 |
102 | ##Useful Links##
103 | Available Services - http://www.addthis.com/services/list
104 |
105 | AddThis Endpoints - http://support.addthis.com/customer/portal/articles/381265-addthis-sharing-endpoints
106 |
107 |
--------------------------------------------------------------------------------
/addThis/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | HTML5 Video Player
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | videojs version: 4.9.0
17 |
18 |
19 |
20 |
21 |
22 |
23 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/addThis/video-js.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Video.js Default Styles (http://videojs.com)
3 | Version 4.2.1
4 | Create your own skin at http://designer.videojs.com
5 | */.vjs-default-skin{color:#ccc}@font-face{font-family:VideoJS;src:url(font/vjs.eot);src:url(font/vjs.eot?) format('embedded-opentype')}@font-face{font-family:VideoJS;src:url(data:application/x-font-woff;charset=utf-8;base64,d09GRk9UVE8AAAp0AAsAAAAAETwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAABCAAABzoAAAxJNB+TVEZGVE0AAAhEAAAAGgAAABxnm1nIR0RFRgAACGAAAAAdAAAAIAA8AARPUy8yAAAIgAAAAEsAAABgL9/cT2NtYXAAAAjMAAAAPQAAAVLgK/LMaGVhZAAACQwAAAAuAAAANv0r97JoaGVhAAAJPAAAAB4AAAAkBMAAnGhtdHgAAAlcAAAAIgAAADwczwFcbWF4cAAACYAAAAAGAAAABgAPUABuYW1lAAAJiAAAAOAAAAGDiJM4OHBvc3QAAApoAAAADAAAACAAAwAAeJyVVg1QVFUUPg922dcCC9IukvGzGSqKGgmitmggaE41jeVqWFlGJGNOZoRmPwpaDeYTI6MyhxqiyczKrBzDUEyFQjHLv6Sg/EnLoAErcx/s4um77+0+s8xyZ/acc8+595zznXvfvUcik4kkSZKnzMy//6EbJ5EURBKNUQcGqYOC1RiTEhashJnirXTFpChWFEMIsygFXTlqkTmW2iNiiSJjJblXLIXHWhOjKFL4kCmCoimOEimZhtEoyqQb6BaaTHfRffQAPTx39sxxKSkpOrtWZ8N0lqqzNJ0N11m6zkbobKTORuksS2djdZYNNh6u/YgCwIikUmmJ9Ky0VFKkZVKZtFx6TiqXnpdWSC9IFRQhcg6iXhRPqZSFLJ+W1ki1pmOmDtkmx8mdcrdNrVCLHE6rd4PX7rjKamtX0xyKz+454HGbbU0YQE5T7ZamaL9gY2pcW8xSzdqFjr5WG0tRi8uZHlwwx3G1lXnjgE6Wbhpi000FO5qZMjMGOhJhWltXwzQka8I/5hWwtMUczxTVfdTBFJJ4B2s/TaKg279kMr1fLcgRprRj5YLsY4pzZjKNn+hUmG7cVazR0czHDm8W2nzmprhCMfMr5jNV9UyX3ZPBfOqLFYo+Pp8owrTPP+lM1dNMyXvXMh8YameK6RvG3LBlDuZst5ySNbaO+afvTgv1h2KWG2TIfsPdU8LdHvtf3Ync2TsxT4CKYe5Zc62QKhVZlOUTvSwXrZFH7JInzVvh1f6eCrPtjFpk4h5fE3HQ+0lFHBQ8nCzMW1esR+necDtQwX5VzG+qkcy+F4m5ua6bue0dpHg8ByX2JanMXa+sYla3Is2eYKDoDjmJNGt/Ym7vjcKdSi9lfvUhTO4+OoG57K3Zwmk1pNWJTPTt3cwr4ZTM8TVY8UwCU8TOx4TTV4A45wp43nIaO+h7F043dwDxjBmYF93IdGXtaoQ0VTINyAphPltzG9MdqC6TdMM6iCFrsM6bD/PYMCb7zyPFkpPwmh2FcF3RTBZhCJ75ifBa4DfYHz+KFKZh3wvglcxLP2UqnNqKs1GYi42nvHJE7Z6Lc2M/mQJ41cuFsxh/dpZMlMb30ni4PSSLWrQxOdwZolwx0M0SJRR46NvpKGtXrsxnWwuRbO+JeSh27fZyAOn5HuWIfa4P86/rVjJFTsein+cuEvv848ZGhGxIgD8PatsUeYL5m6XbkP9Hc5lb9q1nSizbjxr2HpCMXK2eMqQ59BvUYcscpj7j+6E44/qvQZCuVceYNw3GKTv0BPbr4NQW5s/ifhdBPi5egLPYF9/IiJcBbuqVfZlyN+UypVy1C7oRNzONvq4KQbLNxxGk36M4Zl8vFFu4C0A3ldkQpOPg4mjg2dGs4VEDeN5bYeDJ1PDU4GCdqo+5AJ55ATzLmzU8gzU8ywJ4Ng86h6dNw1MVwPNkUgBPfLeO58l/weOsD+BxrRZ4TJUCz3x3AE/jaR2P/w5T7eLq8rgxYLp6kkD1ruwn2tDQ8Q+QuFVIrcbwAjpjLW6uUtxz/PmOZvHR8VnDmfXcJCVAAyEUzRVkVpMslxAqNwMlmp9DgNHrbR+TbYrJT7ShoeNfIXGHkDqM4QV0xtp4DQF847oWih7Dt/kCvr2aC6zB92S5hBDzMx5AnJ15/zt9EcLX/9JCJDGNzAx2oNoU7DOfD+Y/IpksWESpUEzeZ4Q7IIZ7FW2Wci6gonmRn2ApYolVi2Y6gmh9xPlzLArxE21o6LgNEp9YFCKieZ1atDFQlDT6TW0LG7Whos1SdK1YqmhecCL273hJgFyJEl5+2IWPUnwKkc4GMczwE6HjTlj5Fxh00glDQFfvJ536ZG2tK97mKfK40Qt4Nqhu0Qvg0RHvSOGrc3Dl55UzVx/B91/mpATkVbdpFT44vNvcsG0C06gTx/H9f58GQB/hAHtvxSbQvQDsTR+H2d6EBaDfhU/EE51TyXx0VjaGtXinO9PNAPXb0m2oxfXzSvECFOLqyKrei/ezdRZTes81fhIuNeHrysVTET5pI8qHh5nCX1BxT5DIjkSeNC2hDtKRsYKQnjZNc5KGIsHma8aj6atQKyzoe+xqs0MJs6K/u5zMolGKJCfNk64JsnrzlRZXcnLtne3tLS5z6J21ycmuFsWb78lXXC3mUObSyYsEWexSFK+7BVszHy0RFNux/2EHS5h/H1SCO6+E8DJNzYU9qv8MWR1m0SXmP3TLKjGxWJCFcqjW8ChG2/OV6BpeE+QuJld2syCHYJ4+ezJz/eYkXYn2YnGgudljV/R2w2hE/tbcLPB3I0nLduOufaRI7KL5XiGmCZJqrNE7GIex5inZaGHuM1qYFH8LE+pPGa3o+T1bpSCHEW63VRD4iH50D/ZyzHDAGPXBL4J+OBQPypJh0I7+DTmk4rJLamr8W88mbtW6AKrXQy7Wt2WVwFJXnAHLi7OCNFEQl3x+d/bFfmNRw0W6s9A/AeRGm6MAAHicY2BgYGQAgjO2i86D6LPrbtfAaABTPwggAAB4nGNgZGBg4ANiCQYQYGJgBEI+IGYB8xgABOQAQQAAAHicY2Bm4mecwMDKwMHow5jGwMDgDqW/MkgytDAwMDGwMjPAgQCCyRCQ5prC4PCA4QMD44P/Dxj0GB8wKDcwMDDCFSgAISMAFe4MMQB4nGNgYGBmgGAZBkYGEPAB8hjBfBYGAyDNAYRMIIkHPB8Y/v8HsxggLAVGAT6oLjBgZGNA5o5IAADj5AjGAAAAeJxjYGRgYADiTR2tPvH8Nl8ZuJkYQODsuts1CPr/Xab1jA+AXA4GsDQAWYYM1gAAeJxjYGRgYHzw/y6DHtN6BoZ/DEASKIIC+AGLsAVdAAB4nGNiYGBgguAEIHZgQvAZmBSg4uvBNEhOBiYHAgBEOQJIAAAAAFAAAA8AAHicdY5BasJAFIa/aLSUltJVcTl01U1CkiKC6+LCpUL2gkMISAZG7VEKPUKXPUYP4BG8R//Yt+nCgWG++eZ/7w1wzwcJ/Uq44dF4IH4xHvLMu3Eq/2U84o4f47H8WckkvZV5uFT1PBBPjIe8URin8p/GI574Nh7Ln6hp2eIJLFlD3W59WApWcg1HdmyIuvrmuNsIFkp2HC5nVMLjqMg1zTHX/t/vz83ImGpXSpW8qknoDosQG++qvHBzZ1NFs2yaVUWpzLWP1XKRvV77jzg17IdT+7hvQ+fKvLha+wsjPDZieJxjYGbACwAAfQAE) format('woff'),url(fonts/vjs.ttf) format('truetype');font-weight:400;font-style:normal}.vjs-default-skin .vjs-slider{outline:0;position:relative;cursor:pointer;padding:0;background-color:#333;background-color:rgba(51,51,51,.9)}.vjs-default-skin .vjs-slider:focus{-webkit-box-shadow:0 0 2em #fff;-moz-box-shadow:0 0 2em #fff;box-shadow:0 0 2em #fff}.vjs-default-skin .vjs-slider-handle{position:absolute;left:0;top:0}.vjs-default-skin .vjs-slider-handle:before{content:"\e009";font-family:VideoJS;font-size:1em;line-height:1;text-align:center;text-shadow:0 0 1em #fff;position:absolute;top:0;left:0;-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}.vjs-default-skin .vjs-control-bar{display:none;position:absolute;bottom:0;left:0;right:0;height:3em;background-color:#07141e;background-color:rgba(7,20,30,.7)}.vjs-default-skin.vjs-has-started .vjs-control-bar{display:block;visibility:visible;opacity:1;-webkit-transition:visibility .1s,opacity .1s;-moz-transition:visibility .1s,opacity .1s;-o-transition:visibility .1s,opacity .1s;transition:visibility .1s,opacity .1s}.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{display:block;visibility:hidden;opacity:0;-webkit-transition:visibility 1s,opacity 1s;-moz-transition:visibility 1s,opacity 1s;-o-transition:visibility 1s,opacity 1s;transition:visibility 1s,opacity 1s}.vjs-default-skin.vjs-controls-disabled .vjs-control-bar{display:none}.vjs-default-skin.vjs-using-native-controls .vjs-control-bar{display:none}@media \0screen{.vjs-default-skin.vjs-user-inactive.vjs-playing .vjs-control-bar :before{content:""}}.vjs-default-skin .vjs-control{outline:0;position:relative;float:left;text-align:center;margin:0;padding:0;height:3em;width:4em}.vjs-default-skin .vjs-control:before{font-family:VideoJS;font-size:1.5em;line-height:2;position:absolute;top:0;left:0;width:100%;height:100%;text-align:center;text-shadow:1px 1px 1px rgba(0,0,0,.5)}.vjs-default-skin .vjs-control:focus:before,.vjs-default-skin .vjs-control:hover:before{text-shadow:0 0 1em #fff}.vjs-default-skin .vjs-control:focus{}.vjs-default-skin .vjs-control-text{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.vjs-default-skin .vjs-play-control{width:5em;cursor:pointer}.vjs-default-skin .vjs-play-control:before{content:"\e001"}.vjs-default-skin.vjs-playing .vjs-play-control:before{content:"\e002"}.video-js .vjs-volume-container{float:right}.video-js .vjs-volume-container-linear{width:9em;padding-right:1em}.vjs-default-skin .vjs-mute-control,.vjs-default-skin .vjs-volume-menu-button{cursor:pointer;float:right}.vjs-default-skin .vjs-mute-control:before,.vjs-default-skin .vjs-volume-menu-button:before{content:"\e006"}.vjs-default-skin .vjs-mute-control.vjs-vol-0:before,.vjs-default-skin .vjs-volume-menu-button.vjs-vol-0:before{content:"\e003"}.vjs-default-skin .vjs-mute-control.vjs-vol-1:before,.vjs-default-skin .vjs-volume-menu-button.vjs-vol-1:before{content:"\e004"}.vjs-default-skin .vjs-mute-control.vjs-vol-2:before,.vjs-default-skin .vjs-volume-menu-button.vjs-vol-2:before{content:"\e005"}.vjs-default-skin .vjs-volume-control{width:5em;float:right}.vjs-default-skin .vjs-volume-bar{width:5em;height:.6em;margin:1.1em auto 0}.vjs-default-skin .vjs-volume-menu-button .vjs-menu-content{height:2.9em}.vjs-default-skin .vjs-volume-level{position:absolute;top:0;left:0;height:.5em;background:#66a8cc url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAP0lEQVQIHWWMAQoAIAgDR/QJ/Ub//04+w7ZICBwcOg5FZi5iBB82AGzixEglJrd4TVK5XUJpskSTEvpdFzX9AB2pGziSQcvAAAAAAElFTkSuQmCC) -50% 0 repeat}.vjs-default-skin .vjs-volume-bar .vjs-volume-handle{width:.5em;height:.5em}.vjs-default-skin .vjs-volume-handle:before{font-size:.9em;top:-.2em;left:-.2em;width:1em;height:1em}.vjs-default-skin .vjs-volume-menu-button .vjs-menu .vjs-menu-content{width:6em;left:-4em}.vjs-default-skin .vjs-volume-menu-vertical .vjs-menu-content{left:-2em!important;width:4em!important;height:8em;padding-top:.5em}.vjs-default-skin .vjs-volume-menu-vertical .vjs-volume-bar{width:.6em;height:5em;margin:1.1em auto 0}.vjs-default-skin .vjs-volume-menu-vertical .vjs-volume-level{height:8em;width:100%;bottom:0;top:auto;background:#66a8cc url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAP0lEQVQIHWWMAQoAIAgDR/QJ/Ub//04+w7ZICBwcOg5FZi5iBB82AGzixEglJrd4TVK5XUJpskSTEvpdFzX9AB2pGziSQcvAAAAAAElFTkSuQmCC) -50% 0 repeat}.vjs-default-skin .vjs-progress-control{position:absolute;left:0;right:0;width:auto;font-size:.3em;height:1em;top:-1em;-webkit-transition:all .4s;-moz-transition:all .4s;-o-transition:all .4s;transition:all .4s}.vjs-default-skin:hover .vjs-progress-control{font-size:.9em;-webkit-transition:all .2s;-moz-transition:all .2s;-o-transition:all .2s;transition:all .2s}.vjs-default-skin .vjs-progress-holder{height:100%}.vjs-default-skin .vjs-progress-holder .vjs-play-progress,.vjs-default-skin .vjs-progress-holder .vjs-load-progress{position:absolute;display:block;height:100%;margin:0;padding:0;left:0;top:0}.vjs-default-skin .vjs-play-progress{background:#66a8cc url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAP0lEQVQIHWWMAQoAIAgDR/QJ/Ub//04+w7ZICBwcOg5FZi5iBB82AGzixEglJrd4TVK5XUJpskSTEvpdFzX9AB2pGziSQcvAAAAAAElFTkSuQmCC) -50% 0 repeat}.vjs-default-skin .vjs-load-progress{background:#646464;background:rgba(255,255,255,.4)}.vjs-default-skin .vjs-seek-handle{width:1.5em;height:100%}.vjs-default-skin .vjs-seek-handle:before{padding-top:.1em}.vjs-default-skin .vjs-time-controls{font-size:1em;line-height:3em}.vjs-default-skin .vjs-current-time{float:left}.vjs-default-skin .vjs-duration{float:left}.vjs-default-skin .vjs-remaining-time{display:none;float:left}.vjs-time-divider{float:left;line-height:3em}.vjs-default-skin .vjs-fullscreen-control{width:3.8em;cursor:pointer;float:right}.vjs-default-skin .vjs-fullscreen-control:before{content:"\e000"}.vjs-default-skin.vjs-fullscreen .vjs-fullscreen-control:before{content:"\e00b"}.vjs-default-skin .vjs-big-play-button{left:.5em;top:.5em;font-size:3em;display:block;z-index:2;position:absolute;width:4em;height:2.6em;text-align:center;vertical-align:middle;cursor:pointer;opacity:1;background-color:#07141e;background-color:rgba(7,20,30,.7);border:.1em solid #3b4249;-webkit-border-radius:.8em;-moz-border-radius:.8em;border-radius:.8em;-webkit-box-shadow:0 0 1em rgba(255,255,255,.25);-moz-box-shadow:0 0 1em rgba(255,255,255,.25);box-shadow:0 0 1em rgba(255,255,255,.25);-webkit-transition:all .4s;-moz-transition:all .4s;-o-transition:all .4s;transition:all .4s}.vjs-default-skin.vjs-controls-disabled .vjs-big-play-button{display:none}.vjs-default-skin.vjs-has-started .vjs-big-play-button{display:none}.vjs-default-skin.vjs-using-native-controls .vjs-big-play-button{display:none}.vjs-default-skin:hover .vjs-big-play-button,.vjs-default-skin .vjs-big-play-button:focus{outline:0;border-color:#fff;background-color:#505050;background-color:rgba(50,50,50,.75);-webkit-box-shadow:0 0 3em #fff;-moz-box-shadow:0 0 3em #fff;box-shadow:0 0 3em #fff;-webkit-transition:all 0s;-moz-transition:all 0s;-o-transition:all 0s;transition:all 0s}.vjs-default-skin .vjs-big-play-button:before{content:"\e001";font-family:VideoJS;line-height:2.6em;text-shadow:.05em .05em .1em #000;text-align:center;position:absolute;left:0;width:100%;height:100%}.vjs-loading-spinner{display:none;position:absolute;top:50%;left:50%;font-size:5em;line-height:1;width:1em;height:1em;margin-left:-.5em;margin-top:-.5em;opacity:.75;-webkit-animation:spin 1.5s infinite linear;-moz-animation:spin 1.5s infinite linear;-o-animation:spin 1.5s infinite linear;animation:spin 1.5s infinite linear}.vjs-default-skin .vjs-loading-spinner:before{content:"\e00a";font-family:VideoJS;position:absolute;top:0;left:0;width:1em;height:1em;text-align:center;text-shadow:0 0 .1em #000}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.vjs-default-skin .vjs-menu-button{float:right;cursor:pointer}.vjs-default-skin .vjs-menu{display:none;position:absolute;bottom:0;left:0;width:0;height:0;margin-bottom:3em;border-left:2em solid transparent;border-right:2em solid transparent;border-top:1.55em solid #000;border-top-color:rgba(7,40,50,.5)}.vjs-default-skin .vjs-menu-button .vjs-menu .vjs-menu-content{display:block;padding:0;margin:0;position:absolute;width:10em;bottom:1.5em;max-height:15em;overflow:auto;left:-5em;background-color:#07141e;background-color:rgba(7,20,30,.7);-webkit-box-shadow:-.2em -.2em .3em rgba(255,255,255,.2);-moz-box-shadow:-.2em -.2em .3em rgba(255,255,255,.2);box-shadow:-.2em -.2em .3em rgba(255,255,255,.2)}.vjs-default-skin .vjs-menu-button:hover .vjs-menu{display:block}.vjs-default-skin .vjs-menu-button ul li{list-style:none;margin:0;padding:.3em 0;line-height:1.4em;font-size:1.2em;text-align:center;text-transform:lowercase}.vjs-default-skin .vjs-menu-button ul li.vjs-selected{background-color:#000}.vjs-default-skin .vjs-menu-button ul li:focus,.vjs-default-skin .vjs-menu-button ul li:hover,.vjs-default-skin .vjs-menu-button ul li.vjs-selected:focus,.vjs-default-skin .vjs-menu-button ul li.vjs-selected:hover{outline:0;color:#111;background-color:#fff;background-color:rgba(255,255,255,.75);-webkit-box-shadow:0 0 1em #fff;-moz-box-shadow:0 0 1em #fff;box-shadow:0 0 1em #fff}.vjs-default-skin .vjs-menu-button ul li.vjs-menu-title{text-align:center;text-transform:uppercase;font-size:1em;line-height:2em;padding:0;margin:0 0 .3em;font-weight:700;cursor:default}.vjs-default-skin .vjs-subtitles-button:before{content:"\e00c"}.vjs-default-skin .vjs-captions-button:before{content:"\e008"}.vjs-default-skin .vjs-captions-button:focus .vjs-control-content:before,.vjs-default-skin .vjs-captions-button:hover .vjs-control-content:before{-webkit-box-shadow:0 0 1em #fff;-moz-box-shadow:0 0 1em #fff;box-shadow:0 0 1em #fff}.video-js{background-color:#000;position:relative;padding:0;font-size:10px;vertical-align:middle;font-weight:400;font-style:normal;font-family:Arial,sans-serif;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.video-js .vjs-tech{position:absolute;top:0;left:0;width:100%;height:100%}.video-js:-moz-full-screen{position:absolute}body.vjs-full-window{padding:0;margin:0;height:100%;overflow-y:auto}.video-js.vjs-fullscreen{position:fixed;overflow:hidden;z-index:1000;left:0;top:0;bottom:0;right:0;width:100%!important;height:100%!important;_position:absolute}.video-js:-webkit-full-screen{width:100%!important;height:100%!important}.video-js.vjs-fullscreen.vjs-user-inactive{cursor:none}.vjs-poster{background-repeat:no-repeat;background-position:50% 50%;background-size:contain;cursor:pointer;height:100%;margin:0;padding:0;position:relative;width:100%}.vjs-poster img{display:block;margin:0 auto;max-height:100%;padding:0;width:100%}.video-js.vjs-using-native-controls .vjs-poster{display:none}.video-js .vjs-text-track-display{text-align:center;position:absolute;bottom:4em;left:1em;right:1em}.video-js .vjs-text-track{display:none;font-size:1.4em;text-align:center;margin-bottom:.1em;background-color:#000;background-color:rgba(0,0,0,.5)}.video-js .vjs-subtitles{color:#fff}.video-js .vjs-captions{color:#fc6}.vjs-tt-cue{display:block}.vjs-default-skin .vjs-hidden{display:none}.vjs-lock-showing{display:block!important;opacity:1;visibility:visible}
--------------------------------------------------------------------------------
/addThis/videojs.addThis.css:
--------------------------------------------------------------------------------
1 |
2 | .video-js .vjs-menu-button ul li {
3 | padding: 4px 0;
4 | list-style: none;
5 | }
6 |
7 | .video-js .vjs-control[class^="icon-"]:before,
8 | .video-js .vjs-control[class*=" icon-"]:before {
9 | font-family:'FontAwesome';
10 |
11 | }
12 |
13 |
14 | .video-js .vjs-social-button .vjs-menu .vjs-menu-content {
15 |
16 | height: auto;
17 | max-height: none;
18 | }
19 | .video-js .vjs-social-button .vjs-menu .vjs-menu-content li.vjs-menu-item {
20 | width: 2.775em;
21 | float: left;
22 | font-size: 1.8em;
23 | padding: 5px 0;
24 | }
25 |
26 | .video-js .vjs-embed-window {
27 | position: fixed;
28 | z-index: 100;
29 |
30 | left: 35%;
31 | top: 40%;
32 |
33 | width: 30%;
34 | height: 20%;
35 |
36 | background: rgba(7, 40, 50, 0.7);
37 | -webkit-box-shadow: 0 0 1em rgba(255, 255, 255, 1);
38 | -moz-box-shadow: 0 0 1em rgba(255, 255, 255, 1);
39 | box-shadow: 0 0 1em rgba(255, 255, 255, 1);
40 |
41 | /* Fade */
42 |
43 | -webkit-transition: visibility 0.5s, opacity 0.5s;
44 | -moz-transition: visibility 0.5s, opacity 0.5s;
45 | -ms-transition: visibility 0.5s, opacity 0.5s;
46 | -o-transition: visibility 0.5s, opacity 0.5s;
47 | transition: visibility 0.5s, opacity 0.5s;
48 | }
49 |
50 | /* Fading sytles, used to fade embed window. */
51 | .video-js .vjs-embed-window.vjs-fade-in {
52 | display: block !important;
53 | visibility: visible; /* Needed to make sure things hide in older browsers too. */
54 | opacity: 1;
55 | }
56 | .video-js .vjs-embed-window.vjs-fade-out {
57 | display: block !important;
58 | visibility: hidden;
59 | opacity: 0;
60 | }
61 |
62 | .video-js .vjs-embed-window .vjs-embed-title {
63 | margin-top: 0;
64 | padding: 5px 7px;
65 | background: rgba(16, 108, 136, 0.7);
66 | border-bottom: 2px solid rgba(27,201,255,0.7);
67 | color: #fff;
68 | }
69 |
70 | .video-js .vjs-embed-window textarea {
71 | width: 92%;
72 | height: 60%;
73 | margin: 0 2% 5px;
74 | padding: 2%;
75 | border: 0;
76 | background: rgba(27,201,255,0.5);
77 | color: #fff;
78 | }
79 |
80 | .video-js .vjs-embed-window .icon-remove-sign {
81 | position: absolute;
82 | top: 3px;
83 | right: 7px;
84 |
85 | cursor: pointer;
86 |
87 | font-size: 1.5em;
88 | color: #fff;
89 | }
90 |
--------------------------------------------------------------------------------
/addThis/videojs.addThis.js:
--------------------------------------------------------------------------------
1 | //
2 | // Author: Brian Kelley
3 | // Description: Creates a "share" menu in the control bar. See the readme on github.
4 | // https://github.com/brianpkelley/video-js-4-plugins/blob/master/addThis/README.md
5 | //
6 |
7 | (function() {
8 |
9 | // AddThis optional parameters
10 | var pubid = false;
11 | var ct = false;
12 | var email_template = false;
13 | var share_url = false;
14 | var website_url = false;
15 | /***********************************************
16 | * Social Item
17 | ***********************************************/
18 | videojs.SocialItem = videojs.MenuItem.extend({
19 | init: function(player, options){
20 |
21 | videojs.MenuItem.call(this, player, options);
22 | if ( "embed" == options.kind ) {
23 | this.embedEl_ = new videojs.EmbedWindow(this.player(), {});
24 | this.player().el().appendChild( this.embedEl_.el() );
25 | }
26 | }
27 | });
28 |
29 | videojs.SocialItem.prototype.createEl = function(type, props) {
30 | return vjs.Button.prototype.createEl.call(this, 'li', vjs.obj.merge({
31 | className: 'vjs-menu-item',
32 | innerHTML: ' '
33 | }, props));
34 | };
35 |
36 | videojs.SocialItem.prototype.onClick = function() {
37 | var serialize = function(obj) {
38 | var str = [];
39 | for(var p in obj) {
40 | str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
41 | }
42 | return str.join("&");
43 | }
44 |
45 |
46 | // Send this to AddThis.com
47 | // Available Services - http://www.addthis.com/services/list
48 | // http://support.addthis.com/customer/portal/articles/381265-addthis-sharing-endpoints
49 | // URL - http://api.addthis.com/oexchange/0.8/forward/SERVICE_TAG/offer?OPTIONS
50 | // Name Description Type Required? Example
51 | // url URL of the page being shared. string yes http://addthis.com
52 | // title Title of the page being shared. string no AddThis Home Page
53 | // description Short description of the page being shared. string no AddThis: One button. Your content everywhere.
54 | // pubid Your publisher profile ID (analytics). string no addthis
55 | // email_template Email template to use for email sharing (requires pubid param) string no my_template
56 | // ct Enable click tracking (shared page must have AddThis client code to measure clicks) string no ct=1
57 |
58 | var send = {
59 | 'url': share_url || document.location.href,
60 | 'title': document.title,
61 | 'description': 'Check out this cool video at '+document.location.href,
62 | 'pubid': pubid || null,
63 | 'email_template': email_template || null,
64 | 'ct': ct || null
65 | };
66 | var width;
67 | var height;
68 | var kind = this.options().kind;
69 |
70 | var deserialize = function (s) {
71 | var query = {};
72 |
73 | s.replace(/\b([^&=]*)=([^&=]*)\b/g, function (m, a, d) {
74 | if (typeof query[a] != 'undefined') {
75 | query[a] += ',' + d;
76 | } else {
77 | query[a] = d;
78 | }
79 | });
80 |
81 | return query;
82 | }
83 |
84 | var src = this.player().currentSrc();
85 |
86 |
87 | switch ( kind ) {
88 | // Special Cases
89 | /////////////////////////////
90 | case 'embed':
91 |
92 | // Get current theme
93 |
94 | var pluginObj = this.player().options().plugins;
95 | var pluginStr = JSON.stringify( pluginObj );
96 |
97 | // Change this code to suit your needs
98 | var embedCode = [
99 | ' ',
100 | '',
101 | '',
102 | '\t ',
103 | '\tVideo Playback Not Supported
',
104 | ' '
105 | ].join('\n');
106 | // Create Elements
107 | this.embedEl_.setEmbedCode( embedCode );
108 | this.embedEl_.show();
109 |
110 | [].slice.call( this.embedEl_.el().getElementsByTagName('textarea') )[0].select();
111 |
112 | break;
113 | case 'link':
114 | if ( website_url ) {
115 | window.open(website_url, 'Website');
116 | }
117 | break;
118 | case 'more':
119 | width = width || 550;
120 | height = height || 450;
121 | window.open('http://api.addthis.com/oexchange/0.8/offer??'+serialize(send), 'AddThis', 'height='+height+',width='+width+',modal=yes,alwaysRaised=yes');
122 | break;
123 |
124 |
125 |
126 |
127 | // AddThis.com Forward Share API
128 | ////////////////////////////////////////
129 |
130 | case 'facebook':
131 | width = width || 550;
132 | height = height || 270;
133 | // Fall through
134 | case 'twitter':
135 | width = width || 550;
136 | height = height || 260;
137 | send.text = send.description.replace(/\shttp\:\/\/.*$/gi, '');
138 | // Fall through
139 | case 'email':
140 | width = width || 550;
141 | height = height || 700;
142 | // Fall through
143 | default:
144 | width = width || 550;
145 | height = height || 450;
146 | window.open('http://api.addthis.com/oexchange/0.8/forward/'+kind+'/offer?'+serialize(send), 'AddThis', 'height='+height+',width='+width+',modal=yes,alwaysRaised=yes');
147 | // http://support.addthis.com/customer/portal/articles/381265-addthis-sharing-endpoints
148 | // http://www.addthis.com/services/list
149 | }
150 |
151 | // This can be and is caught in the googleAnalytics Plugin
152 | videojs.trigger(this.player().el(),{type: 'socialclick', target: this.player().el(), kind: kind});
153 |
154 | };
155 |
156 | /***********************************************
157 | * Social Menu Button
158 | ***********************************************/
159 | videojs.SocialButton = videojs.MenuButton.extend({
160 | init: function(player, options){
161 | videojs.MenuButton.call(this, player, options);
162 |
163 | if ( this.items.length > 4 ) {
164 | this.menu.contentEl().style.width = "15em";
165 | this.menu.contentEl().style.left = "-7.5em";
166 | }
167 |
168 |
169 | this.on('click', this.onClick);
170 | }
171 | });
172 |
173 |
174 | videojs.SocialButton.prototype.options_ = {
175 | facebook: true,
176 | twitter: true,
177 | googleplus: true,
178 | linkedin: true,
179 | pinterest: true,
180 | delicious: false,
181 | reddit: false,
182 | email: true,
183 | embed: false,
184 | //link: false,
185 | more: true
186 | };
187 |
188 | videojs.SocialButton.prototype.available = {
189 | facebook: {
190 | 'label': 'Facebook',
191 | 'kind': 'facebook',
192 | 'iconClass': 'facebook'
193 | },
194 | twitter: {
195 | 'label': 'Twitter',
196 | 'kind': 'twitter',
197 | 'iconClass': 'twitter'
198 | },
199 | googleplus: {
200 | 'label': 'Google+',
201 | 'kind': 'google_plusone_share',
202 | 'iconClass': 'google-plus'
203 | },
204 | linkedin: {
205 | 'label': 'LinkedIn+',
206 | 'kind': 'linkedin',
207 | 'iconClass': 'linkedin'
208 | },
209 | pinterest: {
210 | 'label': 'Pinterest+',
211 | 'kind': 'pinterest',
212 | 'iconClass': 'pinterest'
213 | },
214 | delicious: {
215 | 'label': 'Delicious',
216 | 'kind': 'delicious',
217 | 'iconClass': 'delicious'
218 | },
219 | reddit: {
220 | 'label': 'Reddit',
221 | 'kind': 'reddit',
222 | 'iconClass': 'reddit'
223 | },
224 | more: {
225 | 'label': 'More Services',
226 | 'kind': 'more',
227 | 'iconClass': 'plus'
228 | },
229 | email: {
230 | 'label': 'Email',
231 | 'kind': 'email',
232 | 'iconClass': 'envelope'
233 | },
234 | embed: {
235 | 'label': 'Embed',
236 | 'kind': 'embed',
237 | 'iconClass': 'code'
238 | },
239 | website_url: {
240 | 'label': 'Link',
241 | 'kind': 'link',
242 | 'iconClass': 'globe'
243 | },
244 | };
245 |
246 | videojs.SocialButton.prototype.buttonText = 'Social';
247 | /*videojs.SocialButton.prototype.createEl = function( props ) {
248 | return videojs.Component.prototype.createEl('div', {
249 | //className: 'vjs-social-button vjs-control vjs-menu-button '',
250 | //innerHTML: '' + ('Social') + '
',
251 | role: 'button',
252 | 'aria-live': 'polite', // let the screen reader user know that the text of the button may change
253 | tabIndex: 0
254 | });
255 | };*/
256 | vjs.SocialButton.prototype.buildCSSClass = function(){
257 | return 'vjs-social-button vjs-control icon-share ' + vjs.MenuButton.prototype.buildCSSClass.call(this);
258 | };
259 |
260 |
261 | /**
262 | * Override default
263 | */
264 | videojs.SocialButton.prototype.onClick = function() {};
265 |
266 | /**
267 | * Responsible for creating the vjs.SocialItems to add to the menu
268 | */
269 | videojs.SocialButton.prototype.createItems = function(){
270 | var items = [], track;
271 | var options = this.options();
272 |
273 | for ( var item in this.available ) {
274 | if ( this.available.hasOwnProperty( item ) && options[item] ) {
275 | items.push(new videojs.SocialItem(this.player_, this.available[item] ));
276 | }
277 | }
278 |
279 | return items;
280 | };
281 |
282 |
283 | /***********************************************
284 | * Embed window to grab the code
285 | ***********************************************/
286 | videojs.EmbedWindow = videojs.Component.extend({
287 | /** @constructor */
288 | init: function(player, options){
289 | videojs.Component.call(this, player, options);
290 | this.hide();
291 |
292 | this.exitEl_ = new videojs.ExitButton(player,{});
293 | this.exitEl_.on('click', videojs.bind(this, function() {
294 | this.hide();
295 | }));
296 | this.el_.appendChild( this.exitEl_.el() );
297 |
298 | this.textAreaEl_ = document.createElement('textarea');
299 | this.textAreaEl_.style.fontSize = "10px";
300 | if ( options.embedCode ) {
301 | this.setEmbedCode( options.embedCode );
302 | }
303 |
304 | this.el_.appendChild( this.textAreaEl_ );
305 | },
306 |
307 | setEmbedCode: function(embedCode) {
308 | this.textAreaEl_.value = embedCode || "";
309 | }
310 | });
311 |
312 | videojs.EmbedWindow.prototype.createEl = function(player,options) {
313 | return videojs.Component.prototype.createEl(player, {
314 | className: 'vjs-embed-window ',
315 | innerHTML: ' Embed Code ',
316 | 'aria-live': 'polite', // let the screen reader user know that the text of the button may change
317 | tabIndex: 0
318 | });
319 | }
320 |
321 | videojs.ExitButton = videojs.Button.extend({
322 | /** @constructor */
323 | init: function(player, options){
324 | videojs.Component.call(this, player, options);
325 | }
326 | });
327 |
328 | videojs.ExitButton.prototype.createEl = function(player,options) {
329 | return videojs.Component.prototype.createEl(player,{
330 | className: 'vjs-button icon-remove-sign',
331 | innerHTML: '',
332 | role: 'button',
333 | 'aria-live': 'polite', // let the screen reader user know that the text of the button may change
334 | tabIndex: 0,
335 | style: 'font-size: 10px'
336 | });
337 | }
338 | videojs.ExitButton.prototype.onClick = function() {};
339 |
340 |
341 |
342 |
343 |
344 | // Note that we're not doing this in prototype.createEl() because
345 | // it won't be called by Component.init (due to name obfuscation).
346 | var createSocialButton = function(options) {
347 | var props = {
348 | className: 'vjs-social-button vjs-control vjs-menu-button icon-share',
349 | innerHTML: '' + ('Social') + '
',
350 | role: 'button',
351 | 'aria-live': 'polite', // let the screen reader user know that the text of the button may change
352 | tabIndex: 0
353 | };
354 | return videojs.Component.prototype.createEl(null, props);
355 | };
356 |
357 | var social;
358 | videojs.plugin('addThis', function(options) {
359 | options = options || {};
360 |
361 | if ( options.includeFontAwesome || options.includeFontAwesome === undefined ) {
362 | var tempLink = document.createElement('link');
363 | tempLink.href = '//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css';
364 | tempLink.rel = 'stylesheet';
365 | document.getElementsByTagName('head')[0].appendChild( tempLink );
366 | }
367 |
368 | if ( options.pubid ) {
369 | pubid = options.pubid;
370 | }
371 | if ( options.ct ) {
372 | ct = options.ct;
373 | }
374 | if ( options.email_template ) {
375 | email_template = options.email_template;
376 | }
377 | if ( options.share_url ) {
378 | share_url = options.share_url;
379 | }
380 | if ( options.website_url && options.website_url != /http(s)?:\/\//.test(options.website_url) && options.website_url != "") {
381 | website_url = options.website_url;
382 | } else {
383 | delete options.website_url;
384 | }
385 |
386 | var optionsClone = JSON.parse(JSON.stringify(options));
387 | optionsClone.el = createSocialButton(options);
388 |
389 |
390 | social = this.controlBar.addChild( 'socialButton', options );
391 | });
392 | })();
--------------------------------------------------------------------------------
/automute/automute.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Automute/restart auto plays the player but muted.
3 | * @author Brian Kelley
4 | */
5 |
6 |
7 | (function() {
8 | videojs.plugin('automute', automute);
9 |
10 | /** @namespace plugins.autoMuteRestart */
11 | /**
12 | * Function responsible for auto playing and muting the player when a video loads.
13 | * Applies the classes "vjs-automute" and "vjs-automute-restart" to the videojs.bigPlayButton.
14 | * Once a user interacts with the player either by click on the bigPlayButton or by loading a new video, these classes are removed.
15 | *
16 | * @plugindesc Auto plays the plugin in a muted state. Can either play from current location or restart upon user interaction.
17 | *
18 | * @function automute
19 | * @memberof plugins.autoMuteRestart
20 | * @param {Object} [options] Specifies the options to overwrite.
21 | * @param {Boolean} [options.restart=false] Should the player restart when unmuted / played.
22 | */
23 | function automute( options ) {
24 |
25 | options = videojs.obj.merge( { restart: false }, options );
26 |
27 | var unMute, onLoadFn, onPauseFn, playFn, initialized;
28 |
29 | initialized = false;
30 |
31 | function removeAutomute () {
32 | //console.log( "begin removeAutomute" );
33 | setTimeout(videojs.bind( this, function() { this.muted(false); } ), 0 );
34 | videojs.addClass( this.el(), 'vjs-has-started' );
35 | videojs.removeClass( this.bigPlayButton.el(), 'vjs-automute' );
36 | videojs.removeClass( this.bigPlayButton.el(), 'vjs-automute-restart' );
37 | this.bigPlayButton.hide();
38 |
39 | this.off( 'play', playFn );
40 | this.off( 'loadstart', unMute );
41 | //this.off( 'pause', onPauseFn );
42 | this.bigPlayButton.off( 'click', onPauseFn );
43 | this.tech.off( 'mousedown', onPauseFn );
44 | // Clear off any events that may be left over
45 | this.tech.off( 'mousedown', this.tech.onClick );
46 | this.tech.on( 'mousedown', this.tech.onClick );
47 | // console.log( "end removeAutomute" );
48 | }
49 |
50 | onPauseFn = videojs.bind( this, function( e ) {
51 | // console.log( "onPause" );
52 | e.stopImmediatePropagation();
53 | if ( this.currentTime() == this.duration() ) {
54 | return;
55 | }
56 |
57 |
58 | if ( options.restart ) {
59 | this.trigger({type:'restartunmute'});
60 | this.currentTime(0);
61 | } else {
62 | this.trigger({type:'autoplayunmute'});
63 | }
64 |
65 | //this.play();
66 | unMute();
67 | });
68 |
69 | // Setup the actions to un-automute the player only once the automute has been established
70 | unMute = videojs.bind( this, removeAutomute );
71 |
72 | onLoadFn = videojs.bind( this, function() {
73 | // console.log( "onLoad" );
74 | unMute();
75 | });
76 |
77 |
78 |
79 | playFn = videojs.bind(this, function() {
80 |
81 | this.muted(true);
82 |
83 | videojs.removeClass( this.el(), 'vjs-has-started' );
84 | videojs.removeClass( this.el(), 'vjs-playing' );
85 |
86 |
87 | this.bigPlayButton.show();
88 |
89 | videojs.addClass( this.bigPlayButton.el(), 'vjs-automute' );
90 | if ( options.restart ) {
91 | videojs.addClass( this.bigPlayButton.el(), 'vjs-automute-restart' );
92 | }
93 |
94 | if ( initialized ) {
95 | return;
96 | }
97 |
98 | initialized = true;
99 |
100 | // They clicked the big play button
101 | this.bigPlayButton.one( 'click', onPauseFn);
102 | // Which paused it
103 | this.tech.one('mousedown', onPauseFn);
104 | this.tech.off('mousedown', this.tech.onClick );
105 |
106 |
107 | // Will the playlist auto load the next item?
108 | if ( typeof this.playlist === 'object' && this.playlist.options().autoAdvance ) {
109 | //this.one( 'ended', function() {console.log( 'ended' ); });
110 | this.one( 'playlistload', unMute );
111 | } else {
112 | this.one( 'loadstart', unMute );
113 | }
114 |
115 | });
116 |
117 | this.on( 'play', playFn );
118 |
119 | // Set autoplay and mute
120 | this.options_.autoplay = true;
121 | this.options_.automute = true;
122 | if ( options.restart ) {
123 | this.options_.automuterestart = true;
124 | }
125 | this.autoplay( true );
126 |
127 |
128 | }
129 | })();
--------------------------------------------------------------------------------
/automute/automute.less:
--------------------------------------------------------------------------------
1 | .video-js .vjs-big-play-button.vjs-automute:before {
2 | content: "\e006";
3 | font-size: .8em;
4 | line-height: 3.3em;
5 | z-index: 100;
6 | }
7 |
8 | .video-js .vjs-big-play-button.vjs-automute-restart:after {
9 | font-family: FontAwesome;
10 | font-weight: normal;
11 | font-style: normal;
12 | text-decoration: inherit;
13 | -webkit-font-smoothing: antialiased;
14 | content: "\f021";
15 |
16 | height: 100%;
17 | width: 100%;
18 | line-height: 1.13em;
19 | font-size: 2.35em;
20 | opacity: .3;
21 | z-index: 50;
22 | }
--------------------------------------------------------------------------------
/callToAction/callToAction.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | videojs.CallToAction = videojs.Component.extend({
5 | init: function( player, options ) {
6 | var addButton = false;
7 | if ( options.el && options.el.nodeType === 1) {
8 | this.contentEl_ = options.el;
9 | delete options.el;
10 | } else {
11 | addButton = true;
12 | }
13 |
14 | videojs.Component.call( this, player, options );
15 |
16 | if ( addButton ) {
17 | this.contentEl_ = this.callToActionContainer_;
18 | this.callToAction_ = this.addChild( 'callToActionButton', this.options_.link );
19 | this.exitButton.on( 'click', videojs.bind( this, function() {
20 | this.player_.trigger({type: 'calltoactionclose', actionTime: this.getTime() });
21 | this.conceal();
22 | }) );
23 |
24 | this.callToAction_.on('click', videojs.bind(this, function() {
25 | this.player_.trigger({type: 'calltoaction', actionTime: this.getTime() });
26 | }));
27 | }
28 |
29 | this.timerDisplay.length( this.options_.timer );
30 |
31 | this.player_.on( 'ended', videojs.bind( this, this.reveal ) );
32 |
33 |
34 | this.on('click', function(e) {
35 | e.stopImmediatePropagation();
36 | });
37 |
38 | // Do we have a playlist and does it autoAdvance?
39 | this.playlistAutoAdvance = false;
40 | this.playlistCheckTimer = setTimeout( videojs.bind( this, this.playlistCheck ), 1 );
41 | }
42 | });
43 |
44 |
45 | videojs.CallToAction.prototype.createEl = function() {
46 | var el = videojs.Component.prototype.createEl(null, {
47 | className: 'vjs-call-to-action ',
48 | });
49 |
50 | if ( this.contentEl_ && this.contentEl_.nodeType === 1 ) {
51 | el.appendChild( this.contentEl_ );
52 | } else {
53 | this.title_ = videojs.createEl('h2',{
54 | innerHTML: this.options_.title
55 | });
56 | this.message_ = videojs.createEl('p',{
57 | innerHTML: this.options_.text
58 | });
59 | this.callToActionContainer_ = videojs.createEl('div', {
60 | className: 'link-container'
61 | });
62 | /*this.callToAction_ = videojs.createEl('a',{
63 | innerHTML: this.options_.link.text,
64 | href: this.options_.link.url,
65 | target: '_blank',
66 | name: 'callToAction'
67 | });*/
68 |
69 | //this.callToActionContainer_.appendChild( this.callToAction_ );
70 |
71 | el.appendChild( this.title_ );
72 | el.appendChild( this.message_ );
73 | el.appendChild( this.callToActionContainer_ );
74 | }
75 |
76 |
77 | return el;
78 | };
79 |
80 | videojs.CallToAction.prototype.options_ = {
81 | title: '',
82 | text: '',
83 | link: {
84 | url: '',
85 | text: ''
86 | },
87 | el: null,
88 | timer: 30,
89 | children: {
90 | exitButton: {},
91 | timerDisplay: {
92 | descriptionText: "Time till next item:",
93 | timeLabel: "s"
94 | }
95 | }
96 | };
97 |
98 | videojs.CallToAction.prototype.playlistCheck = function() {
99 | if ( this.player_.playlist && this.player_.playlist.autoAdvanceFn ) {
100 | this.playlistAutoAdvance = true;
101 | this.autoAdvanceFn = this.player_.playlist.autoAdvanceFn;
102 |
103 | videojs.off( this.player().el(), 'ended', this.player_.playlist.autoAdvanceFn );
104 |
105 | this.timerDisplay.on( 'complete', videojs.bind( this, this.timerComplete ) );
106 | //this.player_.autoplay( false );
107 | } else {
108 | this.timerDisplay.hide();
109 | }
110 |
111 | };
112 |
113 | videojs.CallToAction.prototype.reveal = function () {
114 | this.show();
115 |
116 | if ( this.playlistAutoAdvance ) {
117 | // Load next item
118 | //this.player_.playlist.loadNext();
119 | this.player_.pause();
120 | // Show the timer
121 | this.timerDisplay.show();
122 | // Start the display timer
123 | this.timerDisplay.start();
124 | /*
125 | this.displayTime = this.options_.timer;
126 | this.displayTimerEl_.innerHTML = this.displayTime + " seconds";
127 | */
128 | }
129 | };
130 |
131 |
132 |
133 | videojs.CallToAction.prototype.conceal = function() {
134 | this.hide();
135 | this.timerDisplay.cancel();
136 | };
137 |
138 |
139 | videojs.CallToAction.prototype.timerComplete = function() {
140 | this.hide();
141 | videojs.bind( this.player_.playlist, this.autoAdvanceFn )();
142 | };
143 |
144 | videojs.CallToAction.prototype.getTime = function() {
145 | this.timerDisplay.time_;
146 | };
147 |
148 |
149 |
150 |
151 |
152 | videojs.CallToActionButton = videojs.Button.extend({
153 | init: function( player, options ) {
154 | videojs.Button.call(this, player, options);
155 | this.name_ = "callToActionButton";
156 | }
157 | });
158 | videojs.CallToActionButton.prototype.createEl = function() {
159 | var props = {
160 | className: '',
161 | innerHTML: this.options_.text,
162 | role: 'button',
163 | 'aria-live': 'polite', // let the screen reader user know that the text of the button may change
164 | tabIndex: 0
165 | };
166 | var el = videojs.Component.prototype.createEl('a', props);
167 |
168 | el.style.cursor = "pointer";
169 |
170 | return el;
171 | };
172 | videojs.CallToActionButton.prototype.onClick = function() {
173 | if ( this.options_.url ) {
174 | window.open(this.options_.url, 'CallToAction');
175 | }
176 | };
177 |
178 |
179 |
180 |
181 |
182 |
183 | if ( !videojs.ExitButton ) {
184 | /**
185 | * Exit button.
186 | * @class
187 | * @construtor
188 | * @param {vjs.Player|Object} player
189 | * @param {Object} options
190 | * @extends vjs.Button
191 | */
192 | videojs.ExitButton = videojs.Button.extend({
193 | init: function(player, options){
194 |
195 | videojs.Component.call(this, player, options);
196 | }
197 | });
198 | videojs.ExitButton.prototype.buttonText = "Exit";
199 | videojs.ExitButton.prototype.buildCSSClass = function(){
200 | // TODO: Change vjs-control to vjs-button?
201 | return 'vjs-control vjs-exit-button icon-remove-sign ' + vjs.Component.prototype.buildCSSClass.call(this);
202 | };
203 | videojs.ExitButton.prototype.onClick = function() {};
204 | }
205 |
206 | if ( !videojs.PauseButton ) {
207 | /**
208 | * Pause button.
209 | * @class
210 | * @construtor
211 | * @param {vjs.Player|Object} player
212 | * @param {Object} options
213 | * @extends vjs.Button
214 | */
215 | videojs.PauseButton = videojs.Button.extend({
216 | init: function(player, options){
217 | videojs.Component.call(this, player, options);
218 | }
219 | });
220 | videojs.PauseButton.prototype.buttonText = "Pause";
221 | videojs.PauseButton.prototype.buildCSSClass = function(){
222 | // TODO: Change vjs-control to vjs-button?
223 | return 'vjs-control vjs-pause-button icon-pause ' + vjs.Component.prototype.buildCSSClass.call(this);
224 | };
225 | videojs.PauseButton.prototype.onClick = function() {};
226 | }
227 |
228 |
229 | /**
230 | * Timer Display.
231 | * @class
232 | * @construtor
233 | * @param {vjs.Player|Object} player
234 | * @param {Object} options
235 | * @extends vjs.Component
236 | */
237 | videojs.TimerDisplay = videojs.Component.extend({
238 | init: function(player, options){
239 | videojs.Component.call(this, player, options);
240 | this.pauseButton.on( 'click', videojs.bind( this, this.cancel ) );
241 | }
242 | });
243 |
244 | videojs.TimerDisplay.prototype.options_ = {
245 | descriptionText: '',
246 | timeLabel: 'seconds',
247 | children: {
248 | pauseButton: {}
249 | }
250 | };
251 |
252 | videojs.TimerDisplay.prototype.createEl = function() {
253 |
254 | var el = videojs.Component.prototype.createEl(null, {
255 | className: this.buildCSSClass()
256 | });
257 |
258 | this.descriptionText_ = videojs.Component.prototype.createEl( 'span', {
259 | innerHTML: this.options_.descriptionText
260 | });
261 |
262 | this.timerText_ = videojs.Component.prototype.createEl( 'span', {
263 | className: 'vjs-time-left'
264 | });
265 |
266 | el.appendChild( this.descriptionText_ );
267 | el.appendChild( this.timerText_ );
268 | return el;
269 | };
270 | videojs.TimerDisplay.prototype.buildCSSClass = function(){
271 | // TODO: Change vjs-control to vjs-button?
272 | return 'vjs-display-timer ' + vjs.Component.prototype.buildCSSClass.call(this);
273 | };
274 |
275 | videojs.TimerDisplay.prototype.length = function() {
276 | if ( arguments.length ) {
277 | this.options_.length = arguments[0];
278 | }
279 | return this.options_.length;
280 | };
281 |
282 | videojs.TimerDisplay.prototype.start = function() {
283 | this.clear();
284 | this.time_ = this.options_.length;
285 | this.play();
286 | };
287 | videojs.TimerDisplay.prototype.play = function() {
288 | this.update();
289 | this.timer_ = setInterval( videojs.bind( this, this.update ), 1000 );
290 | };
291 | videojs.TimerDisplay.prototype.pause = function() {
292 | this.clear();
293 | };
294 | videojs.TimerDisplay.prototype.cancel = function() {
295 | this.clear();
296 | this.time_ = 0;
297 | this.hide();
298 | };
299 |
300 | videojs.TimerDisplay.prototype.clear = function() {
301 | clearInterval( this.timer_ );
302 | };
303 |
304 | videojs.TimerDisplay.prototype.update = function() {
305 | this.timerText_.innerHTML = this.time_ + this.options_.timeLabel;
306 | this.time_--;
307 |
308 | if ( this.time_ <= 0 ) {
309 | this.clear();
310 | this.trigger( 'complete', {} );
311 | }
312 |
313 | };
314 | })();
315 |
316 |
317 | /**
318 | * @namespace plugins.callToAction
319 | */
320 | /**
321 | * Displays a logo as a control bar button. Can be used to open a link in a new window.
322 | *
323 | * @memberof plugins.callToAction
324 | * @function callToAction
325 | * @param {Object} options Options object.
326 | * @param {String} [options.title] Title of the call to action slide.
327 | * @param {String} [options.text] A short message to include on the call to action slide.
328 | * @param {Object} [options.link] Object containing the link url and text.
329 | * @param {String} [options.link.url] The url for the call to action link.
330 | * @param {String} [options.link.text] The text to display on the call to action button.
331 | * @param {String|Element} [options.el] Either the id of the an element to use as the call to action slide, or a reference to the element.
332 | */
333 | (function() {
334 | videojs.plugin('callToAction', function( options ) {
335 |
336 | options = options || {};
337 | if ( (!options.link || !options.title) && !options.el ) {
338 | return;
339 | }
340 |
341 | if ( options.el ) {
342 | if ( typeof options.el === "string" && document.getElementById( options.el.replace('#','') ) ) {
343 | options.el = document.getElementById( options.el.replace('#','') );
344 | this.callToAction = this.addChild('callToAction', options );
345 | } else if ( options.el.nodeType === 1) {
346 | // We have a node, this node will be shown at the end of the video.
347 | this.callToAction = this.addChild('callToAction', options );
348 | } else {
349 | console.warn( "VideoJs.CallToAction Aborting: Invalid element specified, neither html element or element id" );
350 | }
351 | } else {
352 | // We don't have a node, we need to create one
353 | this.callToAction = this.addChild('callToAction', options );
354 | }
355 |
356 |
357 |
358 |
359 | });
360 | })();
361 |
--------------------------------------------------------------------------------
/callToAction/callToAction.less:
--------------------------------------------------------------------------------
1 | .vjs-call-to-action {
2 | background: rgba(25,25,25,.6);
3 | display: none;
4 |
5 | width: 100%;
6 | height: 100%;
7 |
8 | z-index: 1000;
9 | position: absolute;
10 | top: 0;
11 | left: 0;
12 |
13 |
14 |
15 | h2 {
16 | font-size: 32px;
17 | color: #fff;
18 | text-align: center;
19 | }
20 |
21 | p {
22 | margin: 1em;
23 | font-size: 18px;
24 | text-align: center;
25 | }
26 |
27 | .link-container {
28 | text-align: center;
29 | width: 100%;
30 |
31 | position: absolute;
32 | bottom: 75px;
33 |
34 | a {
35 | display: inline-block;
36 |
37 | padding: .5em 1em;
38 |
39 | font-size: 3em;
40 | font-weight: bold;
41 |
42 | text-align: center;
43 | text-decoration: none;
44 |
45 | color: #fff;
46 |
47 | background: #e48f2f;
48 |
49 | -webkit-box-shadow: 0 5px 0 0 rgba(234, 98, 1, 1), 0 5px 15px 0 rgba(0,0,0,1);
50 | box-shadow: 0 5px 0 0 rgba(234, 98, 1, 1), 0 5px 15px 0 rgba(0,0,0,1);
51 |
52 | border-radius: 15px;
53 |
54 | &:hover {
55 | margin-top: 1px;
56 | -webkit-box-shadow: 0 4px 0 0 rgba(234, 98, 1, 1), 0 4px 13px 0 rgba(0,0,0,1);
57 | box-shadow: 0 4px 0 0 rgba(234, 98, 1, 1), 0 4px 13px 0 rgba(0,0,0,1);
58 | }
59 | }
60 | }
61 |
62 |
63 | .vjs-control {
64 |
65 | width: 2em;
66 | height: 1.5em;
67 |
68 | &.vjs-exit-button {
69 | position: absolute;
70 | top: 10px;
71 | right: 10px;
72 | font-size: 20px;
73 | cursor: pointer;
74 | color: #fff;
75 | }
76 |
77 | &.vjs-pause-button {
78 | float: none;
79 | display: inline-block;
80 | &:before {
81 | position: static;
82 | display: inline-block;
83 | width: auto;
84 | height: auto;
85 | }
86 | }
87 | }
88 |
89 |
90 |
91 | .vjs-display-timer {
92 | position: absolute;
93 | bottom: 30px;
94 | right: 10px;
95 | color: #aaa;
96 |
97 | span {
98 | font-weight: normal;
99 | font-size: 14px;
100 | }
101 |
102 | .vjs-time-left {
103 | font-weight: bold;
104 | font-size: 20px;
105 | color: #fff;
106 | width: 50px;
107 | text-align: right;
108 | display: inline-block;
109 | }
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/dimTheLights/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Usage
3 |
4 | ### HTML:
5 | ```
6 |
7 | ```
8 |
9 | ### Javascript:
10 | ```
11 | videojs('VIDEO_ID', {plugins: {dimTheLights: {}}});
12 | ```
13 |
--------------------------------------------------------------------------------
/dimTheLights/dimTheLights.css:
--------------------------------------------------------------------------------
1 | .vjs-dim-the-lights {
2 | cursor: pointer;
3 | float: right !important;
4 | }
5 |
6 | .vjs-dim-the-lights.vjs-dim-toggle {
7 | opacity: .5;
8 | }
9 |
10 |
11 | .vjs-dim-overlay {
12 | position: fixed;
13 | top: 0;
14 | left: 0;
15 | z-index: 10000;
16 | height: 100%;
17 | width: 100%;
18 | background: #000;
19 | opacity: .0;
20 | display: none;
21 |
22 | -webkit-transition: opacity .35s ease-in;
23 | -moz-transition: opacity .35s ease-in;
24 | -ms-transition: opacity .35s ease-in;
25 | -o-transition: opacity .35s ease-in;
26 | transition: opacity .35s ease-in;
27 |
28 | }
29 |
30 | .vjs-dim-overlay.vjs-dim-off {
31 |
32 | opacity: .8;
33 | }
34 |
35 | .vjs-dim-focus {
36 | position: absolute;
37 | z-index: 20000;
38 | }
--------------------------------------------------------------------------------
/dimTheLights/dimTheLights.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 |
4 | videojs.DimTheLightsToggle = videojs.Button.extend({
5 | init: function( player, options ) {
6 | videojs.Button.call( this, player, options );
7 |
8 | var playerEl = this.player_.el();
9 | /* if ( playerEl.parentNode.className.indexOf( 'video-js-responsive-container') > -1 ) {
10 | this.mainEl_ = playerEl.parentNode.parentNode;
11 | } else {*/
12 | this.mainEl_ = playerEl;
13 | //}
14 |
15 | this.mainEl_.parentNode.appendChild( this.overlay_ );
16 |
17 |
18 | }
19 | });
20 |
21 | videojs.DimTheLightsToggle.prototype.isDim = false;
22 | videojs.DimTheLightsToggle.prototype.buttonText = "Dim The Lights";
23 |
24 | videojs.DimTheLightsToggle.prototype.createEl = function(type, props){
25 |
26 | this.overlay_ = videojs.createEl('div', {
27 | className: 'vjs-dim-overlay'
28 | });
29 |
30 |
31 | return vjs.Button.prototype.createEl.call(this, type, props);
32 | };
33 |
34 | videojs.DimTheLightsToggle.prototype.buildCSSClass = function() {
35 | return 'vjs-dim-the-lights icon-lightbulb ' + vjs.Button.prototype.buildCSSClass.call(this);
36 | };
37 |
38 | videojs.DimTheLightsToggle.prototype.onClick = function() {
39 | if ( !this.isDim ) {
40 | this.dimTheLights();
41 |
42 | videojs.one( document, 'keyup', videojs.bind(this, function(evt) {
43 | if ( evt.keyCode == 27 ) {
44 | this.raiseTheLights();
45 | }
46 | }) );
47 |
48 | } else {
49 | this.raiseTheLights();
50 |
51 | }
52 | };
53 |
54 | videojs.DimTheLightsToggle.prototype.dimTheLights = function() {
55 | this.isDim = true;
56 | this.mainEl_.className += ' vjs-dim-focus';
57 |
58 | this.overlay_.style.display = 'block';
59 | setTimeout( videojs.bind( this, function() { this.overlay_.className += ' vjs-dim-off'; } ), 10 );
60 |
61 | this.el_.className += ' vjs-dim-toggle';
62 | };
63 |
64 | videojs.DimTheLightsToggle.prototype.raiseTheLights = function() {
65 | this.isDim = false;
66 | this.mainEl_.className = this.mainEl_.className.replace(/\s?vjs\-dim\-focus/gi, '');
67 |
68 | this.overlay_.style.display = 'none';
69 | this.overlay_.className = this.overlay_.className.replace(/\s?vjs\-dim\-off/gi, '');
70 |
71 | this.el_.className = this.el_.className.replace(/\s?vjs\-dim\-toggle/gi, '');
72 | };
73 |
74 |
75 | /** @namespace plugins.dimTheLights */
76 | /**
77 | * Adds an overlay to the page that will darken the surrounding areas.
78 | *
79 | * @function dimTheLights
80 | * @memberof plugins.dimTheLights
81 | *
82 | */
83 | videojs.plugin('dimTheLights',function( options ) {
84 | this.controlBar.addChild( 'dimTheLightsToggle', {
85 | //Options
86 | });
87 | });
88 | })();
89 |
--------------------------------------------------------------------------------
/googleAnalytics/videojs.ga.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | var gaChecks = 0;
3 | var gaType = 0;
4 |
5 | var queue = [];
6 |
7 | var videojsRef = null; // reference to the videojs object from the plugin function
8 | var lastReportedTime = 0; // avoid duplicates
9 | var loadedAllData = false;
10 | var seeking = false;
11 |
12 | var eventLimits = {
13 | loadstart: false, // begin looking for data --- extra, is it needed?
14 | loadedmetadata: false, // duration and dimensions loaded
15 | loadeddata: false, // data at current playback position loaded --- I hope it would be if we are playing
16 | loadedalldata: false, // completely loaded
17 | play: true, // we're playing
18 | pause: true, // we're not playing
19 | timeupdate: true, // player progression ( ever 15-250 ms when playing )
20 | ended: true, // we're finished playing
21 | durationchange: false, // duration changed, or is known for the first time
22 | progress: false, // download progress --- This will be fired A LOT, not needed
23 | resize: true, // video playback size has changed
24 | volumechange: true, // Too Loud? Too OLD!
25 | error: true, // Playback error
26 | fullscreenchange: true, // Goin blind?
27 | mute: true, // No Sound?
28 |
29 | seekend: true, // Mouse up on the seekbar / handle
30 |
31 | socialclick: true // Click event for better video social plugin
32 | }
33 |
34 |
35 | var defaults = {
36 | eventLimits: eventLimits,
37 | primaryGA: null,
38 | secondaryGA: null
39 | }
40 | var options = {};
41 |
42 |
43 | var debug = 0;
44 |
45 |
46 |
47 | /***********************************************
48 | * Events
49 | ***********************************************/
50 | // begin looking for data
51 | function onLoadStart( e ) {
52 | loadedAllData = false;
53 | if ( ! options.eventLimits.loadstart ) return; // Disable this report
54 |
55 | videoData = getVideoData();
56 | doTracking({
57 | 'category': videoData.cid,
58 | 'action': videoData.vid,
59 | 'label': 'View',
60 | 'value': null
61 | });
62 | }
63 |
64 | // duration and dimensions loaded
65 | function onLoadedMetaData( e ) {
66 | if ( ! options.eventLimits.loadedmetadata ) return; // Disable this report
67 |
68 | videoData = getVideoData();
69 | doTracking({
70 | 'category': videoData.cid,
71 | 'action': videoData.vid,
72 | 'label': 'Meta Data Loaded',
73 | 'value': null
74 | });
75 | }
76 |
77 | // data at current playback position loaded
78 | function onLoadedData( e ) {
79 | if ( ! options.eventLimits.loadeddata ) return; // Disable this report
80 |
81 | videoData = getVideoData();
82 | doTracking({
83 | 'category': videoData.cid,
84 | 'action': videoData.vid,
85 | 'label': 'Video Data Loading',
86 | 'value': null
87 | });
88 | }
89 |
90 | // completely loaded
91 | function onLoadedAllData( e ) {
92 | if ( ! options.eventLimits.loadedalldata || loadedAllData ) return; // Disable this report
93 | loadedAllData = true;
94 | videoData = getVideoData();
95 | doTracking({
96 | 'category': videoData.cid,
97 | 'action': videoData.vid,
98 | 'label': 'All Video Data Loaded',
99 | 'value': null
100 | });
101 | }
102 |
103 | // we're playing
104 | function onPlay( e ) {
105 | if ( ! options.eventLimits.play || seeking ) { seeking = false; return; } // Disable this report
106 |
107 | videoData = getVideoData();
108 | doTracking({
109 | 'category': videoData.cid,
110 | 'action': videoData.vid,
111 | 'label': 'Play',
112 | 'value': null
113 | });
114 |
115 | }
116 |
117 | // we're not playing
118 | function onPause( e ) {
119 | if ( ! options.eventLimits.pause || seeking ) return; // Disable this report
120 |
121 | videoData = getVideoData();
122 | doTracking({
123 | 'category': videoData.cid,
124 | 'action': videoData.vid,
125 | 'label': 'Pause',
126 | 'value': getTime()
127 | });
128 | }
129 | function onSeekBegin( e ) {
130 | seeking = true;
131 | // Add mouse up listener
132 | videojs.one(document,'mouseup',onSeekEnd);
133 | }
134 |
135 | function onSeekEnd( e ) {
136 | if ( ! options.eventLimits.seekend ) return; // Disable this report
137 | videoData = getVideoData();
138 | doTracking({
139 | 'category': videoData.cid,
140 | 'action': videoData.vid,
141 | 'label': 'Seek',
142 | 'value': getTime()
143 | });
144 | }
145 |
146 | function onVolumeBegin( e ) {
147 | // Add mouse up listener
148 | videojs.one(document,'mouseup',onVolumeEnd);
149 | }
150 |
151 | function onVolumeEnd( e ) {
152 | if ( ! options.eventLimits.volumechange ) return; // Disable this report
153 | videoData = getVideoData();
154 | doTracking({
155 | 'category': videoData.cid,
156 | 'action': videoData.vid,
157 | 'label': 'Volume Change',
158 | 'value': getVolume()
159 | });
160 | }
161 |
162 | function onMute( e ) {
163 | if ( ! options.eventLimits.volumechange ) return; // Disable this report
164 | videoData = getVideoData();
165 | doTracking({
166 | 'category': videoData.cid,
167 | 'action': videoData.vid,
168 | 'label': 'Muted',
169 | 'value': videojsRef.muted()
170 | });
171 | }
172 |
173 | // player progression ( 25, 50, 75 percent )
174 | function onTimeUpdate( e ) {
175 | if ( ! options.eventLimits.timeupdate || seeking ) return; // Disable this report
176 |
177 | // Need to limit this
178 | var currentTime = Math.floor( videojsRef.currentTime() )
179 |
180 | var percent = Math.floor( (currentTime / videojsRef.duration()) * 100 ) ;
181 |
182 | if ( currentTime && lastReportedTime != currentTime && ( percent == 25 || percent == 50 || percent == 75 ) ) {
183 |
184 | lastReportedTime = currentTime;
185 | videoData = getVideoData();
186 | doTracking({
187 | 'category': videoData.cid,
188 | 'action': videoData.vid,
189 | 'label': 'Progress - ' + percent +'%',
190 | 'value': null
191 |
192 | });
193 | }
194 |
195 | }
196 |
197 | // we're finished playing
198 | function onEnded( e ) {
199 | if ( ! options.eventLimits.ended ) return; // Disable this report
200 |
201 | videoData = getVideoData();
202 | doTracking({
203 | 'category': videoData.cid,
204 | 'action': videoData.vid,
205 | 'label': 'Ended',
206 | 'value': null
207 | });
208 | }
209 |
210 | // duration changed, or is known for the first time
211 | function onDurationChange( e ) {
212 | if ( ! options.eventLimits.durationchange ) return; // Disable this report
213 |
214 | videoData = getVideoData();
215 | doTracking({
216 | 'category': videoData.cid,
217 | 'action': videoData.vid,
218 | 'label': 'Duration Changed',
219 | 'value': null
220 | });
221 | }
222 |
223 | // download progress
224 | function onProgress( e ) {
225 | if ( ! options.eventLimits.progress ) return; // Disable this report
226 |
227 | videoData = getVideoData();
228 | doTracking({
229 | 'category': videoData.cid,
230 | 'action': videoData.vid,
231 | 'label': 'Download Progress',
232 | 'value': null
233 | });
234 | }
235 |
236 | // video playback size has changed
237 | function onResize( e ) {
238 | if ( ! options.eventLimits.resize ) return; // Disable this report
239 |
240 | videoData = getVideoData();
241 | doTracking({
242 | 'category': videoData.cid,
243 | 'action': videoData.vid,
244 | 'label': 'Resize',
245 | 'value': null
246 | });
247 | }
248 |
249 | // Too Loud? Too OLD!
250 | function onVolumeChange( e ) {
251 | if ( ! options.eventLimits.volumechange ) return; // Disable this report
252 |
253 | videoData = getVideoData();
254 | doTracking({
255 | 'category': videoData.cid,
256 | 'action': videoData.vid,
257 | 'label': 'Volume Change',
258 | 'value': null
259 | });
260 | }
261 |
262 | // Playback error
263 | function onError( e ) {
264 | if ( ! options.eventLimits.error ) return; // Disable this report
265 |
266 | videoData = getVideoData();
267 | doTracking({
268 | 'category': videoData.cid,
269 | 'action': videoData.vid,
270 | 'label': 'Playback Error',
271 | 'value': null
272 | });
273 | }
274 |
275 | // Goin blind?
276 | function onFullScreenChange( e ) {
277 | if ( ! options.eventLimits.fullscreen ) return; // Disable this report
278 |
279 | videoData = getVideoData();
280 | doTracking({
281 | 'category': videoData.cid,
282 | 'action': videoData.vid,
283 | 'label': 'Fullscreen',
284 | 'value': null
285 | });
286 | }
287 |
288 | // Social Plugin
289 | function onSocialClick( e ) {
290 | if ( ! options.eventLimits.socialclick ) return; // Disable this report
291 |
292 | videoData = getVideoData();
293 | doTracking({
294 | 'category': videoData.cid,
295 | 'action': videoData.vid,
296 | 'label': 'Social - '+e.kind,
297 | 'value': null
298 | });
299 | }
300 |
301 |
302 | function processQueue() {
303 | if ( gaType ) {
304 | var tempTracking
305 | while( tempTracking = queue.pop() ) {
306 | doTracking( tempTracking );
307 | }
308 | }
309 | }
310 |
311 | function doTracking( opt ) {
312 |
313 | if ( gaType ) {
314 | // Send to google
315 | googleTrack( opt );
316 | } else {
317 | queue.push( opt );
318 | }
319 | }
320 |
321 |
322 | /***********************************************
323 | * Google Code
324 | ***********************************************/
325 | function googleTrack(opt) {
326 | if ( gaType ) {
327 | switch( gaType ) {
328 | case 1: // UA Style
329 | if ( debug ) { console.log( "[BV Reporting]", gaType, opt ); }
330 | ga('bv.send', 'event', opt.category, opt.action, opt.label, opt.value);
331 | if ( options.secondaryGA ) {
332 | ga('bvSecondary.send', 'event', opt.category, opt.action, opt.label, opt.value);
333 | }
334 | break;
335 | case 2: // GA Async Style
336 | if ( debug ) { console.log( "[BV Reporting]", gaType, opt ); }
337 | _gaq.push(['bv._trackEvent', opt.category, opt.action, opt.label, opt.value]);
338 | if ( options.secondaryGA ) {
339 | _gaq.push(['bvSecondary._trackEvent', opt.category, opt.action, opt.label, opt.value]);
340 | }
341 | break;
342 | case 3: // GA Sync Style
343 | if ( debug ) { console.log( "[BV Reporting]", gaType, opt ); }
344 |
345 | break;
346 | }
347 | }
348 | }
349 |
350 | function checkIfAnalyticsLoaded() {
351 | // Test for all variations of google analytics
352 | if ( window.ga && window.ga.getAll ) {
353 | // Do tracking with analytics.js
354 | gaType = 1;
355 | ga('create', options.primaryGA, {'name':'bv'});
356 | if ( options.secondaryGA ) {
357 | ga('create', options.secondaryGA, {'name':'bvSecondary'});
358 | }
359 | processQueue();
360 | } else if (window._gat && window._gat._getTracker) {
361 | // Do tracking with async old-style analytics
362 | gaType = 2;
363 | _gat._createTracker(options.primaryGA,'bv');
364 | if ( options.secondaryGA ) {
365 | _gat._createTracker(options.secondaryGA,'bvSecondary');
366 | }
367 | processQueue();
368 | } else if (window.urchinTracker) {
369 | // Do tracking with sync old-style analytics
370 | gaType = 3;
371 | // Need to find this code ?
372 | //processQueue();
373 | } else {
374 | if ( gaChecks < 10 ) { // 5s, it its not loaded yet... when will it be?
375 | gaChecks++;
376 | setTimeout(checkIfAnalyticsLoaded, 500);
377 | } else {
378 | // Include ga.js
379 | gaType = 1;
380 |
381 |
382 |
383 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
384 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
385 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
386 | })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
387 |
388 |
389 |
390 | ga('create', 'UA-42516461-1', {'name':'bv'});
391 | if ( options.secondaryGA ) {
392 | ga('create', options.secondaryGA, {'name':'bvSecondary'});
393 | }
394 |
395 | processQueue();
396 | }
397 | }
398 | }
399 |
400 | /***********************************************
401 | * Helper code
402 | ***********************************************/
403 | function getTime() {
404 | return Math.round( videojsRef.currentTime() );
405 | }
406 | function getVolume() {
407 | return Math.round( videojsRef.volume() * 100 );
408 | }
409 | function getVideoData() {
410 | var src;
411 | if ( videojsRef.el().querySelector('video') !== undefined ) { // HTML5
412 | var video = videojsRef.el().querySelector('video');
413 | src = video.src || video.currentSrc;
414 |
415 | } else { // FLASH
416 | var values = deserializeFromQuery( videojsRef.el().querySelector('param[name=flashvars]').value )
417 | src = decodeURIComponent( values.src );
418 | }
419 | var srcSplit = src.split('/');
420 |
421 | var filename = srcSplit[srcSplit.length-1];
422 | var filenameSplit = filename.split('.');
423 |
424 | var cid = filenameSplit[0];
425 | var vid = filenameSplit[1];
426 | var type = filenameSplit[2];
427 |
428 | var returnObj = {
429 | 'cid': cid,
430 | 'vid': vid,
431 | 'filename': filename
432 | };
433 |
434 | return returnObj;
435 | }
436 |
437 | function serializeToJSON( obj ) {
438 | return JSON.stringify(obj,undefined);
439 | }
440 | function deserializeFromJSON(s) {
441 | return JSON.parse(s);
442 | }
443 | function serializeToQuery( obj ) {
444 | var str = [];
445 | for(var p in obj)
446 | str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
447 | return str.join("&");
448 | }
449 |
450 | function deserializeFromQuery(s) {
451 | var query = {};
452 |
453 | s.replace(/\b([^&=]*)=([^&=]*)\b/g, function (m, a, d) {
454 | if (typeof query[a] != 'undefined') {
455 | query[a] += ',' + d;
456 | } else {
457 | query[a] = d;
458 | }
459 | });
460 |
461 | return query;
462 | }
463 |
464 |
465 |
466 | /***********************************************
467 | * Plugin code
468 | ***********************************************/
469 |
470 |
471 |
472 | videojs.plugin('googleAnalytics', function(userOptions){
473 | options = vjs.obj.merge(defaults, userOptions);
474 | // Initializing
475 | videojsRef = this;
476 |
477 | checkIfAnalyticsLoaded();
478 |
479 | // Lets Play Catch ... the event!
480 | // Native Video.js Events
481 |
482 | this.on('loadstart',onLoadStart); // begin looking for data
483 | this.on('loadedmetadata',onLoadedMetaData); // duration and dimensions loaded
484 | this.on('loadeddata',onLoadedData); // data at current playback position loaded
485 | this.on('loadedalldata',onLoadedAllData); // completely loaded
486 | this.on('play',onPlay); // we're playing
487 | this.on('pause',onPause); // we're not playing
488 | this.on('timeupdate',onTimeUpdate); // player progression ( ever 15-250 ms when playing )
489 | this.on('ended',onEnded); // we're finished playing
490 | this.on('durationchange',onDurationChange); // duration changed, or is known for the first time
491 | this.on('progress',onProgress); // download progress
492 | this.on('resize',onResize); // video playback size has changed
493 | this.on('error',onError); // Playback error
494 | this.on('fullscreenchange',onFullScreenChange); // Goin blind?
495 |
496 | this.controlBar.progressControl.seekBar.on('mousedown',onSeekBegin);
497 | this.controlBar.volumeControl.volumeBar.on('mousedown',onVolumeBegin);
498 | this.controlBar.muteToggle.on('mouseup',onMute);
499 |
500 | // this.controlBar.volumeControl.volumeSlider.volumeBar.on('mousedown',onVolumeBegin);
501 | // this.controlBar.volumeControl.muteToggle.on('mouseup',onMute);
502 |
503 | // BetterVideo Events
504 | if( videojs.SocialItem ) { // Check if the social items exists
505 | this.on('socialclick',onSocialClick);
506 | }
507 |
508 |
509 | });
510 | })();
511 |
512 |
513 |
--------------------------------------------------------------------------------
/hideControlsOnPause/videojs.hideControlsOnPause.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | videojs.plugin('bvHideControlBarOnPause', function(){
3 | this.on('pause', function() {
4 | setTimeout( videojs.bind(this, videojs.ControlBar.unlockShowing), 10 );
5 | });
6 | });
7 | })();
--------------------------------------------------------------------------------
/logo/Readme.md:
--------------------------------------------------------------------------------
1 | ```html
2 |
3 |
4 |
5 |
6 |
7 | ```
8 |
9 | ```javascript
10 |
27 | ```
28 |
29 | View this demo:
30 | https://jsfiddle.net/3n1gm4/ez9vzjo3/
31 |
--------------------------------------------------------------------------------
/logo/logo.css:
--------------------------------------------------------------------------------
1 | .video-js .vjs-control.vjs-logo-control {
2 | background-repeat: no-repeat;
3 | background-position: center 3px;
4 | float: right !important;
5 |
6 | min-width: 35px;
7 |
8 | /*cursor: pointer;*/
9 | }
10 |
--------------------------------------------------------------------------------
/logo/logo.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var website_url;
3 |
4 |
5 | videojs.Logo = videojs.Button.extend({
6 | init: function( player, options ) {
7 | videojs.Button.call(this, player, options);
8 | this.name_ = "logoButton";
9 | }
10 | });
11 | videojs.Logo.prototype.createEl = function() {
12 | var props = {
13 | className: ' vjs-logo-control vjs-control',
14 | role: 'button',
15 | 'aria-live': 'polite', // let the screen reader user know that the text of the button may change
16 | tabIndex: 0
17 | };
18 | var el = videojs.Component.prototype.createEl(null, props);
19 |
20 | this.contentEl_ = videojs.Component.prototype.createEl( 'div', {
21 | className: 'vjs-control-content',
22 | innerHTML: '' + (this.options_.alt) + ' '
23 | });
24 |
25 | this.contentEl_.appendChild( videojs.Component.prototype.createEl('img', {
26 | src: this.options_.src
27 | }));
28 |
29 | if ( this.options_.url && this.options_.url !== "" ) {
30 | el.style.cursor = "pointer";
31 | }
32 | el.style.width = "auto";
33 | el.appendChild( this.contentEl_ );
34 |
35 | return el;
36 | };
37 | videojs.Logo.prototype.onClick = function() {
38 | if ( this.options_.url ) {
39 | window.open(this.options_.url, 'Website');
40 | this.player_.trigger({type: 'logo'});
41 | }
42 | };
43 |
44 |
45 | /**
46 | * @namespace plugins.logo
47 | */
48 | /**
49 | * Displays a logo as a control bar button. Can be used to open a link in a new window.
50 | *
51 | * @memberof plugins.logo
52 | * @function logo
53 | * @param {Object} options Options object.
54 | * @param {String} options.src The absolute URL to the logo image.
55 | * @param {String} options.alt The alternate text to use if the image can not be found, or to display on hover.
56 | * @param {String} [options.url] The url to a website that will open in a new window.
57 | * @param {String} options.width The CSS width value with the units. Example: 120px
58 | */
59 |
60 | videojs.plugin('logo', function(options) {
61 | var player = this.el();
62 | //options = options || {};
63 |
64 |
65 | //var optionsClone = JSON.parse(JSON.stringify(options)); // clone
66 | //optionsClone.el = createLogoButton( options );
67 |
68 | // = new videojs.Logo(this, optionsClone);
69 | //;
70 | var logo = this.controlBar.addChild( 'logo', options );
71 | // move it to the first float right item
72 | this.controlBar.el().insertBefore(logo.el(), this.controlBar.el().childNodes[0]);
73 | });
74 | })();
--------------------------------------------------------------------------------
/playlist/playlist-caption.js:
--------------------------------------------------------------------------------
1 | /********************************/
2 | /** Playlist Caption **/
3 | /********************************/
4 | videojs.PlaylistCaption = videojs.Component.extend({
5 | init: function( player, options ) {
6 | videojs.Component.call(this, player, options);
7 | }
8 | });
9 |
10 | videojs.PlaylistCaption.prototype.createEl = function( type, props ) {
11 | var el = vjs.Button.prototype.createEl.call(this, 'div', vjs.obj.merge({
12 | className: 'vjs-playlist-caption',
13 | innerHTML: ''
14 | }, props));
15 |
16 | return el;
17 | };
18 |
19 | videojs.PlaylistCaption.prototype.showCaption = function( vertical ) {
20 | if ( vertical && false ) {
21 | videojs.addClass( this.player().el(), 'vjs-has-playlist-caption' );
22 | this.player().el().appendChild( this.el_ );
23 | } else {
24 | videojs.addClass( this.player().el(), 'vjs-has-playlist-caption' );
25 | }
26 |
27 | };
28 |
29 | videojs.PlaylistCaption.prototype.setCaption = function( text ) {
30 | this.el_.innerHTML = text;
31 |
32 | };
33 |
--------------------------------------------------------------------------------
/playlist/playlist-controls.js:
--------------------------------------------------------------------------------
1 |
2 | /*********************************/
3 | /* Previous */
4 | /*********************************/
5 | videojs.PlaylistPrevious = videojs.Button.extend({
6 | init: function( player, options ) {
7 | videojs.Button.call(this, player, options);
8 |
9 | this.on( 'mousedown', videojs.bind( this, this.onMouseDown ) );
10 |
11 | }
12 | });
13 |
14 | videojs.PlaylistPrevious.prototype.createEl = function(type, props) {
15 | return vjs.Button.prototype.createEl.call(this, 'div', vjs.obj.merge({
16 | className: 'vjs-playlist-previous',
17 | innerHTML: ' '
18 | }, props));
19 | };
20 |
21 | videojs.PlaylistPrevious.prototype.onMouseDown = function() {
22 | videojs.one( document.body, 'mouseup', videojs.bind( this, this.onMouseUp ) );
23 | this.moveIncrement_ = -4;
24 | this.clickAndHoldTimer_ = setTimeout( videojs.bind(this, this.onClickAndHold ), 100 );
25 | this.player().playlist.userInteraction( true );
26 | };
27 |
28 | videojs.PlaylistPrevious.prototype.onMouseUp = function() {
29 | clearTimeout( this.clickAndHoldTimer_ );
30 | clearTimeout( this.moveTimer_ );
31 | clearTimeout( this.moveIncrementTimer_ );
32 | };
33 |
34 | videojs.PlaylistPrevious.prototype.onClickAndHold = function() {
35 | this.clickAndHold = true;
36 | this.moveIncrementTimer_ = setTimeout( videojs.bind( this, function() { this.moveIncrement_ = -8; } ), 5000 );
37 | this.doClickAndHold_();
38 |
39 | };
40 |
41 | videojs.PlaylistPrevious.prototype.doClickAndHold_ = function() {
42 | this.player().playlist.moveBy( this.moveIncrement_ );
43 |
44 | this.moveTimer_ = setTimeout( videojs.bind( this, this.doClickAndHold_), 10 );
45 | };
46 |
47 | videojs.PlaylistPrevious.prototype.onClick = function() {
48 | if ( !this.clickAndHold_ ) {
49 | this.player().playlist.moveToPrevious();
50 | }
51 | this.clickAndHold = false;
52 | };
53 |
54 | /*****************************/
55 | /* Next */
56 | /*****************************/
57 | videojs.PlaylistNext = videojs.Button.extend({
58 | init: function( player, options ) {
59 | videojs.Button.call(this, player, options);
60 |
61 | this.on( 'mousedown', videojs.bind( this, this.onMouseDown ) );
62 | }
63 | });
64 |
65 | videojs.PlaylistNext.prototype.createEl = function(type, props) {
66 | return vjs.Button.prototype.createEl.call(this, 'div', vjs.obj.merge({
67 | className: 'vjs-playlist-next',
68 | innerHTML: ' '
69 | }, props));
70 | };
71 |
72 | videojs.PlaylistNext.prototype.onMouseDown = function() {
73 | videojs.one( document.body, 'mouseup', videojs.bind( this, this.onMouseUp ) );
74 | this.moveIncrement_ = 4;
75 | this.clickAndHoldTimer_ = setTimeout( videojs.bind(this, this.onClickAndHold ), 100 );
76 | this.player().playlist.userInteraction( true );
77 | };
78 |
79 | videojs.PlaylistNext.prototype.onMouseUp = function() {
80 | clearTimeout( this.clickAndHoldTimer_ );
81 | clearTimeout( this.moveTimer_ );
82 | clearTimeout( this.moveIncrementTimer_ );
83 | };
84 |
85 | videojs.PlaylistNext.prototype.onClickAndHold = function() {
86 | this.clickAndHold = true;
87 | this.moveIncrementTimer_ = setTimeout( videojs.bind( this, function() { this.moveIncrement_ = 8; } ), 5000 );
88 | this.doClickAndHold_();
89 |
90 | };
91 |
92 | videojs.PlaylistNext.prototype.doClickAndHold_ = function() {
93 | this.player().playlist.moveBy( this.moveIncrement_ );
94 |
95 | this.moveTimer_ = setTimeout( videojs.bind( this, this.doClickAndHold_ ), 10 );
96 | };
97 |
98 | videojs.PlaylistNext.prototype.onClick = function() {
99 | if ( !this.clickAndHold_ ) {
100 | this.player().playlist.moveToNext();
101 | }
102 | this.clickAndHold = false;
103 | };
104 |
105 |
106 |
107 |
108 |
109 |
110 | /**
111 | * Move to the next Item video
112 | * @param {vjs.Player|Object} player
113 | * @param {Object=} options
114 | * @class
115 | * @extends vjs.Button
116 | */
117 | vjs.AdvancePlaylist = vjs.Button.extend({
118 | /**
119 | * @constructor
120 | * @memberof vjs.AdvancePlaylist
121 | * @instance
122 | */
123 | init: function(player, options){
124 | vjs.Button.call(this, player, options);
125 | }
126 | });
127 |
128 | vjs.AdvancePlaylist.prototype.buttonText = 'Next Item';
129 |
130 | vjs.AdvancePlaylist.prototype.buildCSSClass = function(){
131 | return 'icon-step-forward ' + vjs.Button.prototype.buildCSSClass.call(this);
132 | };
133 |
134 | vjs.AdvancePlaylist.prototype.onClick = function(){
135 | this.player().playlist.loadNext();
136 | };
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | /**
146 | * Move to the previous Item video
147 | * @param {vjs.Player|Object} player
148 | * @param {Object=} options
149 | * @class
150 | * @extends vjs.Button
151 | */
152 | vjs.RegressPlaylist = vjs.Button.extend({
153 | /**
154 | * @constructor
155 | * @memberof vjs.RegressPlaylist
156 | * @instance
157 | */
158 | init: function(player, options){
159 | vjs.Button.call(this, player, options);
160 | }
161 | });
162 |
163 | vjs.RegressPlaylist.prototype.buttonText = 'Previous Item';
164 |
165 | vjs.RegressPlaylist.prototype.buildCSSClass = function(){
166 | return 'icon-step-backward ' + vjs.Button.prototype.buildCSSClass.call(this);
167 | };
168 |
169 | vjs.RegressPlaylist.prototype.onClick = function(){
170 | this.player().playlist.loadPrevious();
171 | };
172 |
173 |
174 |
175 |
176 | /**
177 | * Empty button for play toggle placeholder
178 | * @param {vjs.Player|Object} player
179 | * @param {Object=} options
180 | * @class
181 | * @extends vjs.Button
182 | */
183 | vjs.PlaceholderButton = vjs.Button.extend({
184 | /**
185 | * @constructor
186 | * @memberof vjs.RegressPlaylist
187 | * @instance
188 | */
189 | init: function(player, options){
190 | vjs.Button.call(this, player, options);
191 | this.el_.style.opacity = 0;
192 | }
193 | });
194 |
195 | vjs.PlaceholderButton.prototype.buttonText = '';
196 |
197 | vjs.PlaceholderButton.prototype.buildCSSClass = function(){
198 | return 'vjs-empty-button ' + vjs.Button.prototype.buildCSSClass.call(this);
199 | };
200 |
201 | vjs.PlaceholderButton.prototype.onClick = function(){
202 |
203 | };
204 |
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/playlist/playlist-item.js:
--------------------------------------------------------------------------------
1 | videojs.PlaylistItem = videojs.Button.extend({
2 | init: function( player, options ) {
3 | videojs.Component.call(this, player, options);
4 |
5 | // Once loaded we change this to true to avoid double-loading
6 | this.loaded = false;
7 |
8 |
9 | var touchstart = false;
10 | this.on('touchstart', function(event) {
11 | // Stop click and other mouse events from triggering also
12 | //event.preventDefault();
13 | touchstart = true;
14 | });
15 | this.on('touchmove', function() {
16 | touchstart = false;
17 | });
18 | var self = this;
19 | this.on('touchend', function(event) {
20 | if (touchstart) {
21 | self.onClick(event);
22 | }
23 | event.preventDefault();
24 | });
25 |
26 | this.on('click', this.onClick);
27 | this.on('focus', this.onFocus);
28 | this.on('blur', this.onBlur);
29 |
30 |
31 | this.addClass( this.options_.type.substr( 0, this.options_.type.indexOf('/') ) );
32 | }
33 | });
34 |
35 | videojs.PlaylistItem.prototype.createEl = function(type, props) {
36 | var el = vjs.Button.prototype.createEl.call(this, 'li', vjs.obj.merge({
37 | className: 'vjs-playlist-item vjs-item-placeholder ',
38 | innerHTML: ''
39 | }, props));
40 |
41 | this.image_ = vjs.Component.prototype.createEl.call( this, 'img', {
42 | src: "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
43 | });
44 | this.caption_ = videojs.Component.prototype.createEl.call( this, 'div', {
45 | className: 'vjs-playlist-item-caption',
46 | innerHTML: this.options_.caption
47 | });
48 |
49 | el.appendChild( this.image_ );
50 | el.appendChild( this.caption_ );
51 |
52 | return el;
53 | };
54 |
55 | videojs.PlaylistItem.prototype.onClick = function( e ) {
56 | this.player_.playlist.loadItem( this.options_.index );
57 | videojs.trigger(this.el_.parentNode, {type: 'playlistitemclick', index: this.options_.index });
58 | };
59 |
60 | videojs.PlaylistItem.prototype.preload = function() {
61 | if ( !this.loaded ) {
62 | this.image_.src = this.options_.thumbnail;
63 | videojs.on( this.image_, 'load', videojs.bind( this, function () {
64 | this.loaded = true;
65 | this.removeClass('vjs-item-placeholder');
66 | }) );
67 | }
68 | };
69 |
70 | videojs.PlaylistItem.prototype.setIndex = function( index ) {
71 | this.options_.index = index;
72 | };
73 |
74 | videojs.PlaylistItem.prototype.getPosition = function() {
75 | return {
76 | top: this.el_.offsetTop,
77 | bottom: this.el_.offsetTop + this.el_.offsetHeight,
78 | left: this.el_.offsetLeft,
79 | right: this.el_.offsetLeft + this.el_.offsetWidth
80 | };
81 | };
--------------------------------------------------------------------------------
/playlist/playlist-slider.js:
--------------------------------------------------------------------------------
1 | videojs.PlaylistSlider = videojs.Component.extend({
2 | init: function( player, options) {
3 |
4 | // Which orientation are we in
5 | options.vertical = player.el().className.indexOf( 'vjs-vertical-playlist' ) != -1;
6 |
7 | // Initialize
8 | videojs.Component.call(this, player, options);
9 |
10 | // These track which elements are visible.
11 | // Used for when we click on the bottom scroll button,
12 | // we grab the next/previous siblings and move them into view
13 | this.firstVisible_ = false;
14 | this.lastVisible_ = false;
15 |
16 | // Setup events
17 | videojs.on(this.slidePaneEl_, 'scroll', videojs.bind( this, this.onScroll ) );
18 | this.scrollIndicator.on( 'dragscroll', videojs.bind( this, this.onDragScroll ) );
19 | this.on('mousewheel', videojs.bind( this, function() {
20 | this.player().playlist.userInteraction( true );
21 | }));
22 | this.isDragging_ = false;
23 | }
24 | });
25 |
26 | videojs.PlaylistSlider.prototype.createEl = function( type, props ) {
27 | // Overal container div
28 | var el = vjs.createEl( 'div', {
29 | className: 'vjs-playlist-slide-container'
30 | });
31 | // Div to hold the ul and scroll up/down or left/right (ul don't like to scroll nicely)
32 | this.slidePaneEl_ = vjs.Component.prototype.createEl.call(this, 'div', vjs.obj.merge({
33 | className: 'vjs-playlist-slide-pane',
34 | innerHTML: ''
35 | }, props));
36 |
37 | // UL to hold the children
38 | this.contentEl_ = vjs.Component.prototype.createEl.call( this, 'ul', {});
39 |
40 | this.slidePaneEl_.appendChild( this.contentEl_ );
41 | el.appendChild( this.slidePaneEl_ );
42 |
43 | // Set up the indicator
44 | this.scrollIndicator = new videojs.ScrollIndicator(this.player(), {
45 | linkEl: this.slidePaneEl_,
46 | vertical: this.options_.vertical
47 | });
48 |
49 | el.appendChild( this.scrollIndicator.el() );
50 |
51 | return el;
52 | };
53 |
54 | videojs.PlaylistSlider.prototype.slidePaneEl = function() {
55 | return this.slidePaneEl_;
56 | };
57 |
58 | videojs.PlaylistSlider.prototype.options_ = {
59 | "children": { }
60 | };
61 |
62 | videojs.PlaylistSlider.prototype.addChild = function () {
63 | var child = videojs.Component.prototype.addChild.apply(this, arguments);
64 | if ( child.el_.tagName !== 'LI' ) {
65 |
66 | throw new Error("Type Error: Child Elements Must Be LI");
67 | }
68 | child.setIndex( this.children_.length - 1 );
69 | return child;
70 | };
71 |
72 | // Set Size
73 | videojs.PlaylistSlider.prototype.setSize = function( size ) {
74 | this.options_.vertical ? this.setSizeY_( size ) : this.setSizeX_( size );
75 |
76 | videojs.trigger( this.slidePaneEl_, 'resize' );
77 |
78 | if ( size >= this.getScrollSize() ) {
79 | this.scrollIndicator.hide();
80 | } else {
81 | this.scrollIndicator.show();
82 | }
83 | };
84 |
85 | videojs.PlaylistSlider.prototype.setSizeY_ = function( size ) {
86 | this.el_.style.height = size + "px";
87 | };
88 |
89 | videojs.PlaylistSlider.prototype.setSizeX_ = function( size ) {
90 | this.el_.style.width = size + "px";
91 | };
92 |
93 |
94 | // Get Max Scroll
95 | videojs.PlaylistSlider.prototype.getMaxScroll = function() {
96 | return this.options_.vertical ? this.getMaxScrollY_() : this.getMaxScrollX_();
97 | };
98 |
99 | videojs.PlaylistSlider.prototype.getMaxScrollY_ = function() {
100 | return this.slidePaneEl_.scrollHeight - this.slidePaneEl_.offsetHeight;
101 | };
102 |
103 | videojs.PlaylistSlider.prototype.getMaxScrollX_ = function() {
104 | return this.slidePaneEl_.scrollWidth - this.slidePaneEl_.offsetWidth;
105 | };
106 |
107 | // Get Scroll Size
108 | videojs.PlaylistSlider.prototype.getScrollSize = function() {
109 | return this.options_.vertical ? this.getScrollSizeY_() : this.getScrollSizeX_();
110 | };
111 |
112 | videojs.PlaylistSlider.prototype.getScrollSizeY_ = function() {
113 | return this.slidePaneEl_.scrollHeight;
114 | };
115 |
116 | videojs.PlaylistSlider.prototype.getScrollSizeX_ = function() {
117 | return this.slidePaneEl_.scrollWidth;
118 | };
119 |
120 | // Get Scroll Position
121 | videojs.PlaylistSlider.prototype.getScroll = function() {
122 | return this.options_.vertical ? this.getScrollY_() : this.getScrollX_();
123 | };
124 |
125 | videojs.PlaylistSlider.prototype.getScrollY_ = function() {
126 | return this.slidePaneEl_.scrollTop;
127 | };
128 |
129 | videojs.PlaylistSlider.prototype.getScrollX_ = function() {
130 | return this.slidePaneEl_.scrollLeft;
131 | };
132 |
133 |
134 | // Scroll the pane
135 | videojs.PlaylistSlider.prototype.setScroll = function( scroll ) {
136 | this.options_.vertical ? this.setScrollY_( scroll ) : this.setScrollX_( scroll );
137 | this.setVisible();
138 | };
139 |
140 | videojs.PlaylistSlider.prototype.setScrollY_ = function( scroll ) {
141 | this.slidePaneEl_.scrollTop = scroll;
142 | };
143 |
144 | videojs.PlaylistSlider.prototype.setScrollX_ = function( scroll ) {
145 | this.slidePaneEl_.scrollLeft = scroll;
146 | };
147 |
148 | videojs.PlaylistSlider.prototype.scrollToChild = function( index ) {
149 | //console.log( "ScrollToChild", index );
150 | if ( index.index ) {
151 | index = index.index;
152 | }
153 |
154 | var targetChild = this.children_[index];
155 |
156 | if ( !targetChild ) {
157 | return false;
158 | }
159 | var childPosition = this.childPosition( index );
160 | var childSize = childPosition.lower - childPosition.upper;
161 | var currentPosition = this.getPosition();
162 | var maxScroll = this.getMaxScroll();
163 |
164 |
165 | if ( childPosition.upper >= currentPosition.upper && childPosition.lower <= currentPosition.lower ) {
166 | this.setVisible();
167 | return true;
168 | }
169 |
170 | var targetPosition;
171 |
172 | if ( childPosition.upper < currentPosition.upper + currentPosition.total / 2 ) {
173 | targetPosition = maxScroll - ( maxScroll - childPosition.upper + 5 );
174 | } else {
175 | targetPosition = currentPosition.upper + ( childPosition.lower - ( currentPosition.lower - 5 ) );
176 | }
177 |
178 | //console.log( "ScrollToChild", targetPosition );
179 | this.smoothScroll( targetPosition );
180 |
181 |
182 | return true;
183 | };
184 |
185 | videojs.PlaylistSlider.prototype.smoothScroll = function ( pos ) {
186 | clearTimeout( this.animationTimer );
187 | //console.log( "smoothScroll" );
188 | var y = this.getScroll();
189 | y += Math.round( (pos - y) * 0.3 );
190 |
191 | if (Math.abs(y-pos) < 2)
192 | {
193 | this.moveToChild_ = false;
194 | this.setScroll( pos );
195 | return;
196 | }
197 | this.setScroll( y );
198 | this.animationTimer = setTimeout(videojs.bind( this, this.smoothScroll ), 40, pos);
199 | };
200 |
201 | videojs.PlaylistSlider.prototype.scrollBy = function( amount ) {
202 | this.setScroll( this.getScroll() + amount );
203 | };
204 |
205 | // Events
206 | videojs.PlaylistSlider.prototype.onScroll = function( e ) {
207 | this.firstVisible_ = false;
208 | this.lastVisible_ = false;
209 | this.setVisible();
210 | };
211 |
212 | videojs.PlaylistSlider.prototype.onDragScroll = function( e ) {
213 | var maxScroll = this.getMaxScroll();
214 | var visible = this.scrollIndicator.getSize();
215 |
216 | var newScrollPosition = ( e.position / visible.to ) * maxScroll;
217 |
218 | this.setScroll( newScrollPosition );
219 |
220 | // Set "isDragging_" to true to avoid moving the playlist on the next item if the user
221 | // recently dragged the slider. After 20s the default behaviour will continue.
222 | this.isDragging_ = true;
223 | if ( this.isDraggingCheck_ ) {
224 | clearTimeout( this.isDragginCheck_ );
225 | }
226 | this.isDraggingCheck_ = setTimeout( videojs.bind( this, function() {
227 | this.isDragging_ = false;
228 | clearTimeout( this.isDraggingCheck_ );
229 | this.isDraggingCheck_ = false;
230 | }), 20000 );
231 |
232 | this.player().playlist.userInteraction( true );
233 | };
234 |
235 | videojs.PlaylistSlider.prototype.isDragging = function() {
236 | return this.isDragging_;
237 | };
238 |
239 |
240 | // Selection
241 | videojs.PlaylistSlider.prototype.select = function( index, moveAfterSelection ) {
242 | //console.log("Selected", index, moveAfterSelection );
243 | for ( var x = 0; x < this.children_.length; x++ ) {
244 | videojs.removeClass( this.children_[x].el(), 'vjs-playlist-selected' );
245 | }
246 |
247 | videojs.addClass( this.children_[index].el(), 'vjs-playlist-selected' );
248 |
249 | if ( moveAfterSelection) {
250 | this.moveToSelected();
251 | }
252 | };
253 |
254 | // Positioning
255 | videojs.PlaylistSlider.prototype.getPosition = function() {
256 | var viewPane = this.slidePaneEl_;
257 |
258 | if ( this.options_.vertical ) {
259 | return {
260 | upper: viewPane.scrollTop,
261 | lower: viewPane.scrollTop + viewPane.offsetHeight,
262 | total: viewPane.offsetHeight
263 | };
264 | } else {
265 | return {
266 | upper: viewPane.scrollLeft,
267 | lower: viewPane.scrollLeft + viewPane.offsetWidth,
268 | total: viewPane.offsetWidth
269 | };
270 | }
271 | };
272 |
273 | videojs.PlaylistSlider.prototype.childPosition = function( index ) {
274 | if ( !this.children_ && !this.children_[index] ) {
275 | return false;
276 | }
277 | var childData = this.children_[index].getPosition();
278 | var childPosition = this.options_.vertical ? { upper: childData.top, lower: childData.bottom } : { upper: childData.left, lower: childData.right };
279 | return childPosition;
280 | };
281 |
282 | // Visibility
283 | videojs.PlaylistSlider.prototype.isVisible = function( index ) {
284 | var currentPosition = this.getPosition();
285 | var itemPosition = this.childPosition( index );
286 |
287 | //console.log( "isVisible: ", currentPosition, itemPosition );
288 | //console.trace();
289 | if ( itemPosition.upper >= currentPosition.upper && itemPosition.lower <= currentPosition.lower ) {
290 | return true; // Return === true to signify item is wholly visible
291 | } else if ( itemPosition.lower > currentPosition.upper && itemPosition.upper < currentPosition.lower ) {
292 | return 1; // Return truthy to signify it is visible but not wholly in the view pane
293 | } else if ( ( itemPosition.upper < currentPosition.lower + 100 && itemPosition.upper > currentPosition.lower - 100 ) || ( itemPosition.lower > currentPosition.upper + 100 && itemPosition.lower < currentPosition.upper + 100 ) ) {
294 | return 0; // Item will be visible shortly
295 | } else {
296 | return false; // Item is well outside the view pane
297 | }
298 |
299 | };
300 |
301 | videojs.PlaylistSlider.prototype.setVisible = function() {
302 | //console.log( "Setting Visible Items", arguments.callee.caller.toString() );
303 | var item = null;
304 | var isVisible = null;
305 |
306 | this.firstVisible_ = false;
307 | this.lastVisible_ = false;
308 |
309 | for ( var x = 0; x < this.children_.length; x++ ) {
310 | isVisible = this.isVisible( x );
311 | item = this.children_[x];
312 |
313 | if ( isVisible ) { // Partially or wholly on screen
314 | if ( isVisible === true ) { // wholly visible
315 | if ( this.firstVisible_ === false ) {
316 | this.firstVisible_ = x;
317 | }
318 | this.lastVisible_ = x;
319 | }
320 | item.addClass( 'visible' );
321 |
322 |
323 | } else {
324 | item.removeClass( 'visible' );
325 | }
326 |
327 | if ( isVisible === 0 || isVisible ) { // Is it visible or upcoming? Make sure the image is loaded.
328 | item.preload();
329 | }
330 |
331 | }
332 |
333 |
334 | };
335 |
336 | // Movement
337 | videojs.PlaylistSlider.prototype.moveToNext = function( isClick ) {
338 | //console.log( "isClick:", isClick, "lastVisible_:", this.lastVisible_, "moveToChild_:", this.moveToChild_ );
339 | if ( isClick ) {
340 | var next = this.lastVisible_+1;
341 | if ( next == this.moveToChild_ ) {
342 | next++;
343 | }
344 | this.moveToChild_ = next;
345 | this.scrollToChild( this.moveToChild_ );
346 | } else {
347 | this.scrollToChild( this.lastVisible_+1 );
348 | }
349 | };
350 |
351 | videojs.PlaylistSlider.prototype.moveToPrevious = function( isClick ) {
352 | if ( isClick ) {
353 | var next = this.firstVisible_-1;
354 | if ( next == this.moveToChild_ ) {
355 | next--;
356 | }
357 | this.moveToChild_ = next;
358 | this.scrollToChild( this.moveToChild_ );
359 | } else {
360 | this.scrollToChild( this.firstVisible_-1 );
361 | }
362 | };
363 |
364 | videojs.PlaylistSlider.prototype.moveToSelected = function( index ) {
365 | //console.log( "moveToSelected" );
366 | var visible = this.getPosition();
367 | var itemDims = null;
368 | var selected = null;
369 |
370 | if ( index ) {
371 | selected = this.children_[item];
372 | } else {
373 | for ( var x = 0; x < this.children_.length; x++ ) {
374 | if ( this.children_[x].el().className.match('vjs-playlist-selected') !== null ){
375 | selected = this.children_[x];
376 | index = x;
377 | break;
378 | }
379 | }
380 | }
381 |
382 | itemDims = selected.getPosition();
383 |
384 | var nextIndex;
385 | if ( itemDims.upper - itemDims.total < visible.upper ) {
386 | nextIndex = this.children_[index-1] ? index-1 : index;
387 | } else if ( itemDims.lower + itemDims.total > visible.lower ) {
388 | nextIndex = this.children_[index+1] ? index+1 : index;
389 | } else {
390 | nextIndex = index;
391 | }
392 | //console.log( nextIndex );
393 | this.scrollToChild( nextIndex );
394 | };
395 |
396 |
397 |
398 |
399 |
400 |
--------------------------------------------------------------------------------
/playlist/playlist.js:
--------------------------------------------------------------------------------
1 | /********************************/
2 | /** Playlist Container **/
3 | /********************************/
4 | videojs.Playlist = videojs.Component.extend({
5 | init: function( player, options) {
6 |
7 | /*
8 | * We need to set up the class names as child compontents use this to know which orientation they are in
9 | */
10 | videojs.addClass(player.el(), 'vjs-has-playlist');
11 | var parentNode = player.el().parentNode;
12 |
13 |
14 | if ( options.vertical ) {
15 | videojs.addClass(player.el(), 'vjs-vertical-playlist');
16 | if ( parentNode.className.indexOf('video-js-responsive-container') >= 0 ) {
17 | videojs.addClass(parentNode, 'vjs-vertical-playlist');
18 | }
19 | } else {
20 | videojs.addClass(player.el(), 'vjs-horizontal-playlist');
21 | if ( parentNode.className.indexOf('video-js-responsive-container') >= 0 ) {
22 | videojs.addClass(parentNode, 'vjs-horizontal-playlist');
23 | }
24 | }
25 |
26 | // Call the base init
27 | videojs.Component.call(this, player, options);
28 |
29 | this.setupPlaylist();
30 |
31 | // Process queue when playlist is loaded
32 | this.on( 'playlistLoaded', videojs.bind( this, this.playlistLoaded ) );
33 |
34 | videojs.on( this.playlistSlider.contentEl(), 'playlistitemclick', videojs.bind( this, function(e) {
35 | this.userInteraction(false);
36 | this.player().play();
37 | this.player().trigger({type: 'playlistload', item: this.items_[e.index]});
38 | }) );
39 |
40 | videojs.on( window, 'resize', videojs.bind( this, this.onResize ) );
41 |
42 | // Auto advance
43 | if ( this.options_.autoAdvance ) {
44 | this.autoAdvanceFn = videojs.bind( this, function() {
45 | setTimeout( videojs.bind(this, function() {
46 | this.loadNext();
47 | this.player().trigger({type: 'playlistautoload'});
48 | this.player().play();
49 | console.log( "auto load" );
50 |
51 | }, 50) );
52 | });
53 | videojs.on( this.player().el(), 'ended', this.autoAdvanceFn );
54 | }
55 |
56 | this.playlistCaption.showCaption( this.options_.vertical );
57 |
58 | this.on('click', function(e) {
59 | e.stopImmediatePropagation();
60 | });
61 | }
62 | });
63 | videojs.Playlist.prototype.createEl = function() {
64 | var props = {
65 | className: 'vjs-playlist',
66 | innerHTML: '',
67 | 'aria-live': 'polite', // let the screen reader user know that the text of the button may change
68 | tabIndex: 0
69 | };
70 | return videojs.createEl('div', props);
71 | };
72 |
73 | videojs.Playlist.prototype.options_ = {
74 | "children": {
75 | "playlistCaption": {},
76 | "playlistPrevious": {},
77 | "playlistSlider":{},
78 | "playlistNext": {}
79 | }
80 | };
81 |
82 | videojs.Playlist.prototype.items_ = [];
83 | videojs.Playlist.prototype.hasPlaylistLoaded_ = false;
84 | videojs.Playlist.prototype.playlistLoadQueue = [];
85 |
86 | // Setup
87 | videojs.Playlist.prototype.setupPlaylist = function() {
88 | if ( this.options_.url ) {
89 | var separator = "?";
90 | if ( this.options_.url.indexOf( '?' ) > 0 ) {
91 | separator = "&";
92 | }
93 |
94 | videojs.JSONP( this.options_.url + separator + "callback={callback}", videojs.bind( this, function( data ) {
95 | this.options_.items = data;
96 | this.createItems();
97 | }));
98 | } else { // Not a URL
99 |
100 | this.createItems();
101 | }
102 | };
103 |
104 | videojs.Playlist.prototype.createItems = function() {
105 | var items = this.options_.items;
106 | var temp = null;
107 | this.items_ = [];
108 |
109 | for ( var x = 0; x < items.length; x++ ) {
110 | if ( items[x] ) {
111 | this.items_[x] = this.playlistSlider.addChild('playlistItem', items[x] );
112 | }
113 | }
114 |
115 | this.trigger({type:'playlistLoaded', items: this.items_ });
116 |
117 | // Load the first item in the playlist
118 | setTimeout( videojs.bind( this,function() { this.onResize(); this.loadItem(0); } ), 1000 );
119 | };
120 |
121 | // Playlist Load
122 | videojs.Playlist.prototype.playlistLoaded = function(e) {
123 | this.hasPlaylistLoaded = true;
124 | this.processPlaylistLoad();
125 | };
126 |
127 | videojs.Playlist.prototype.processPlaylistLoad = function() {
128 | var nextFn;
129 | while ( ( nextFn = this.playlistLoadQueue.pop() ) !== undefined ) {
130 | nextFn( this.items_ );
131 | }
132 | };
133 |
134 | videojs.Playlist.prototype.onPlaylistLoad = function( fn ) {
135 | if ( this.hasPlaylistLoaded ) {
136 | fn( this.items_ );
137 | } else {
138 | this.playlistLoadQueue.push( fn );
139 | }
140 | };
141 |
142 |
143 |
144 | /** Actions **/
145 |
146 |
147 | videojs.Playlist.prototype.userInteraction = function( set ) {
148 | if ( set !== undefined ) {
149 | this.userInteraction_ = set;
150 |
151 |
152 | if ( this.interactionCheck_ ) {
153 | clearTimeout( this.interactionCheck_ );
154 | }
155 | this.interactionCheck_ = setTimeout( videojs.bind( this, function() {
156 | this.userInteraction_ = false;
157 | clearTimeout( this.interactionCheck_ );
158 | this.interactionCheck_ = false;
159 | }), 20000 );
160 |
161 | }
162 |
163 | return this.userInteraction_;
164 | };
165 |
166 | /** Loading Items **/
167 |
168 |
169 | videojs.Playlist.prototype.loadNext = function() {
170 | var nextItem = this.currentItem + 1;
171 |
172 | if ( nextItem < this.items_.length ) {
173 | this.loadItem( nextItem );
174 | } else if ( this.options_.loop ) {
175 | this.loadItem( 0 );
176 | }
177 | //this.player().play
178 | };
179 |
180 | videojs.Playlist.prototype.loadPrevious = function() {
181 |
182 | var previousItem = this.currentItem - 1;
183 |
184 | if ( previousItem < 0 ) {
185 | previousItem = this.items_.length - 1;
186 | }
187 | this.loadItem( previousItem );
188 |
189 | };
190 |
191 | videojs.Playlist.prototype.loadItem = function( item ) {
192 |
193 | var index;
194 | if ( typeof item === "object" && item.index !== undefined ) {
195 | index = item.index;
196 | } else {
197 | index = item;
198 | }
199 | this.currentItem = index;
200 |
201 | this.playlistSlider.select( this.currentItem, !this.userInteraction() );
202 |
203 | // Set the new video source
204 | this.player().src( { src: this.items_[index].options().src, type: this.items_[index].options().type } );
205 | // Set the poster... yes all 3
206 | // set the custom element
207 | this.player().posterImage.el().style.backgroundImage = 'url('+this.items_[index].options().poster+')';
208 | // set the poster on the video element
209 | if ( this.player().tech.el().tagName === "VIDEO" ) {
210 | this.player().tech.el().poster = this.items_[index].options().poster;
211 | }
212 | // future proof
213 | this.player().poster( this.items_[index].options().poster );
214 |
215 | this.playlistCaption.setCaption( this.items_[index].options().caption );
216 |
217 | //this.trigger({type: 'playlistload', item: this.items_[index]});
218 | };
219 |
220 |
221 | /** Events **/
222 | videojs.Playlist.prototype.onScroll = function(e) {
223 |
224 | this.firstVisible_ = false;
225 | this.lastVisible_ = false;
226 | this.setVisible();
227 |
228 | };
229 |
230 | videojs.Playlist.prototype.onResize = function( e ) {
231 | var newSize = this.slidePaneSize();
232 | // this needs to be set before we can get the maxScroll Size
233 | this.playlistSlider.setSize( newSize );
234 |
235 | var maxScroll = this.playlistSlider.getMaxScroll();
236 |
237 | // We just potentially resized the view pane, so double check the visible objects to preload them.
238 | this.playlistSlider.setVisible();
239 |
240 | if ( maxScroll <= 0 ) {
241 | this.playlistNext.hide();
242 | this.playlistPrevious.hide();
243 | } else {
244 | this.playlistNext.show();
245 | this.playlistPrevious.show();
246 | }
247 |
248 | };
249 |
250 |
251 | /** Positioning **/
252 | videojs.Playlist.prototype.slidePaneSize = function() {
253 | var newSlidPaneSize;
254 |
255 | this.playlistPrevious.show();
256 | this.playlistNext.show();
257 |
258 | if ( this.options_.vertical ) {
259 | newSlidPaneSize = this.el_.offsetHeight - this.playlistPrevious.el().offsetHeight - this.playlistNext.el().offsetHeight;
260 | } else {
261 | newSlidPaneSize = this.el_.offsetWidth - this.playlistPrevious.el().offsetWidth - this.playlistNext.el().offsetWidth;
262 | }
263 |
264 | return newSlidPaneSize;
265 | };
266 |
267 |
268 | /** Movement **/
269 |
270 | videojs.Playlist.prototype.moveToNext = function() {
271 | this.playlistSlider.moveToNext( true );
272 | };
273 |
274 | videojs.Playlist.prototype.moveToPrevious = function() {
275 | this.playlistSlider.moveToPrevious( true );
276 | };
277 |
278 | videojs.Playlist.prototype.moveToSelected = function( index ) {
279 | this.playlistSlider.moveToSelected( index );
280 | };
281 |
282 | videojs.Playlist.prototype.moveBy = function( pos ) {
283 | this.playlistSlider.scrollBy( pos );
284 | };
285 |
286 |
287 |
288 |
289 |
290 |
291 | if ( !videojs.JSONP ) {
292 | videojs.JSONP = function (url, callback) {
293 | var docHead = document.getElementsByTagName('head')[0];
294 | function rand() {
295 | var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
296 | c = '', i = -1;
297 | while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
298 | return c;
299 | }
300 |
301 | function create(url) {
302 | var e = url.match(/callback=jsonp.(\w+)/),
303 | c = e ? e[1] : rand();
304 | videojs.JSONP[c] = function(data) {
305 | callback(data);
306 | delete videojs.JSONP[c];
307 | docHead.removeChild(script);
308 | };
309 | return 'videojs.JSONP.' + c;
310 | }
311 |
312 | var cb = create(url),
313 | script = document.createElement('script');
314 | script.type = 'text/javascript';
315 |
316 | script.src = url.replace(/(\{|%7B)callback(\}|%7D)/ig, cb);
317 | docHead.appendChild(script);
318 |
319 | };
320 | }
321 |
322 |
323 |
324 | /********************************/
325 | /** PLUGIN **/
326 | /********************************/
327 | /**
328 | * @typedef {Object} PlaylistItem
329 | * @property {String} thumbnail Url to the thumbnail to be displayed in the playlist.
330 | * @property {String} poster Url to the poster image displayed by the player before playback starts.
331 | * @property {String} src Url to the itme to be played.
332 | * @property {String} type Type of item to be played. Example: "video/mp4" "image/jpg"
333 | * @property {String} caption Caption to be displayed over the thumbnail or between the playlist and player on horizontal playlists.
334 | */
335 | /**
336 | * @namespace plugins.playlist
337 | */
338 | /**
339 | * Creates a playlist container displayed either below or besides the main player. Core Functionality is based in {@link videojs.Playlist}
340 | * You can either specify a url to a JSON encoded playlist or an Object that contains it.
341 | * @function playlist
342 | * @memberof plugins.playlist
343 | * @param {Object} options Options object.
344 | * @param {Boolean} [options.vertical=false] Tells the player to render a horizontal and beneath playlist or a vertical and to the right playlist.
345 | * @param {Boolean} [options.autoAdvance=false] Should the player advance to the next item in the playlist once the current item has ended.
346 | * @param {Boolean} [options.loop=false] If autoAdvance is selected, should the player loop to the first item once the last item has ended.
347 | * @param {PlaylistItem[]} [options.items] The set of playlist objects.
348 | * @param {String} [options.url] A url pointing to a JSON encoded playlist file.
349 | */
350 |
351 | /*
352 | "playlist":{
353 | "vertical": false,
354 | "autoAdvance": true,
355 | "loop": true,
356 | "items": [
357 | {
358 | "thumbnail": "http://video2.bettervideo.com/video/WHI/JPG120x90/10.12908667.jpg",
359 | "poster": "",
360 | "src": "http://www.designbolts.com/wp-content/uploads/2013/07/Turbo-Wallpaper1.jpg",
361 | "type": "image/jpg",
362 | "caption": "Video 3"
363 | },{
364 | "thumbnail": "http://video2.bettervideo.com/video/WHI/JPG120x90/10.12908669.jpg",
365 | "poster": "http://video2.bettervideo.com/video/WHI/JPG120x90/10.12908669.jpg",
366 | "src": "http://video2.bettervideo.com/video/WHI/MP4480x360/10.12908669.mp4",
367 | "type": "video/mp4",
368 | "caption": "Video 1"
369 | },{
370 | "thumbnail": "http://video2.bettervideo.com/video/WHI/JPG120x90/10.12908667.jpg",
371 | "poster": "",
372 | "src": "http://1.bp.blogspot.com/-aiGt2nvsZS8/Ub754c4Z_jI/AAAAAAAAAF8/eiJPbnzM1FE/s1600/turbo%2Bsnail%2Bmovie.jpg",
373 | "type": "image/jpg",
374 | "caption": "Video 3"
375 | },{
376 | "thumbnail": "http://video2.bettervideo.com/video/WHI/JPG120x90/10.12914505.jpg",
377 | "poster": "",
378 | "src": "http://video2.bettervideo.com/video/WHI/MP4480x360/10.12914505.mp4",
379 | "type": "video/mp4",
380 | "caption": "Video 2"
381 | }
382 |
383 |
384 | ]
385 | }
386 | */
387 | videojs.plugin('playlist', function(options) {
388 | this.playlist = this.addChild('playlist', options);
389 |
390 | if ( options.addControls ) {
391 | this.playlist.advancePlaylistButton = this.controlBar.addChild('advancePlaylist');
392 | this.playlist.regressPlaylistButton = this.controlBar.addChild('regressPlaylist');
393 |
394 |
395 | this.playlist.placeholderButton = this.controlBar.addChild('placeholderButton');
396 |
397 | var controlBarChildren = this.controlBar.el().childNodes;
398 | var playToggleLocation = 0;
399 |
400 | var playLocation = function() {
401 | var loc = -1;
402 | for ( var x = 0; x < controlBarChildren.length; x++ ) {
403 | if ( controlBarChildren[x].className.indexOf('vjs-play-control') != -1) {
404 | loc = x;
405 | break;
406 | }
407 | }
408 | return loc;
409 | };
410 |
411 |
412 | playToggleLocation = playLocation();
413 |
414 | this.controlBar.el().insertBefore( this.playlist.regressPlaylistButton.el(), this.controlBar.el().childNodes[playToggleLocation] );
415 |
416 | playToggleLocation = playLocation();
417 |
418 | this.controlBar.el().insertBefore( this.playlist.advancePlaylistButton.el(), this.controlBar.el().childNodes[playToggleLocation+1] );
419 |
420 | //playToggleLocation = playLocation();
421 |
422 | //this.controlBar.el().insertBefore( this.playlist.placeholderButton.el(), this.controlBar.el().childNodes[playToggleLocation] );
423 | //this.playlist.placeholderButton.hide();
424 | }
425 |
426 | });
--------------------------------------------------------------------------------
/playlist/playlist.less:
--------------------------------------------------------------------------------
1 | @horizontal-playlist-height: 110px;
2 | @vertical-playlist-width: 150px;
3 | @button-size: 20px;
4 | @captions-height: 15px;
5 |
6 | .video-js.vjs-fullscreen {
7 | overflow: visible !important;
8 | }
9 |
10 | .video-js .vjs-play-control,
11 | .video-js .icon-step-forward,
12 | .video-js .icon-step-backward,
13 | .video-js .vjs-fullscreen-control,
14 | .video-js .vjs-mute-control,
15 | .video-js .vjs-empty-button {
16 | width: 3em;
17 | }
18 |
19 | .video-js .vjs-volume-container-linear {
20 | // width: 8em;
21 | }
22 | .video-js .icon-step-forward,
23 | .video-js .icon-step-backward {
24 | cursor: pointer;
25 | }
26 | /*.video-js .vjs-progress-control {
27 | width: 100%;
28 | }*/
29 |
30 | .video-js.vjs-has-playlist.vjs-horizontal-playlist {
31 | margin-bottom: @horizontal-playlist-height;
32 |
33 | .vjs-playlist {
34 | position: absolute;
35 | bottom: -@horizontal-playlist-height;
36 | left: 0;
37 | width: 100%;
38 | height: @horizontal-playlist-height;
39 |
40 | .vjs-playlist-previous, .vjs-playlist-next {
41 | height: 100%;
42 | width: @button-size;
43 |
44 | text-align: center;
45 |
46 | [class*='icon-'] {
47 | position: absolute;
48 | font-size: 16px;
49 | top: 50%;
50 | left: 50%;
51 | margin-top: -8px;
52 | margin-left: -1 * (@button-size / 4);
53 | }
54 | }
55 |
56 | .vjs-playlist-previous {
57 | top: 0;
58 | left: 0;
59 |
60 | span[class*="icon-"]::before {
61 | content: "\f053";
62 | }
63 | }
64 | .vjs-playlist-next {
65 | top: 0;
66 | right: 0;
67 |
68 | span[class*="icon-"]::before {
69 | content: "\f054";
70 | }
71 | }
72 |
73 | .vjs-playlist-slide-container {
74 |
75 | margin: 0 20px;
76 | height: 100%;
77 | overflow: hidden;
78 |
79 | .vjs-playlist-slide-pane {
80 | overflow-y: hidden;
81 | height: 115%;
82 | width: auto;
83 | margin: 5px 0;
84 |
85 | padding: 0;
86 |
87 | white-space: nowrap;
88 | ul {
89 | .inline-block();
90 |
91 |
92 |
93 | .vjs-playlist-item {
94 | margin: 10px 5px;
95 | height: 80px;
96 | .inline-block();
97 |
98 | &:first-child { margin-left: 3px; }
99 | &:last-child { margin-right: 3px; }
100 | &.vjs-playlist-selected {
101 | margin: 7px 2px;
102 | &:first-child { margin-left: 0px; }
103 | &:last-child { margin-right: 0px; }
104 | }
105 | }
106 | }
107 | }
108 |
109 | .vjs-playlist-scroll-indicator {
110 | top: @horizontal-playlist-height - 13px;
111 | //bottom: 5px;
112 | //margin-left: @button-size;
113 |
114 | width: 20%;
115 | height: 4px;
116 | }
117 | }
118 | }
119 |
120 | /**** captions ****/
121 | &.vjs-has-playlist-caption {
122 | margin-bottom: @horizontal-playlist-height + @captions-height;
123 |
124 | .vjs-playlist {
125 | height: @horizontal-playlist-height + @captions-height;
126 | bottom: -1 * (@horizontal-playlist-height + @captions-height);
127 |
128 | .vjs-playlist-caption {
129 | height: @captions-height;
130 | width: 100%;
131 | margin-top: 5px;
132 |
133 | line-height: @captions-height;
134 | font-size: 12px;
135 | font-weight: bold;
136 | text-align: center;
137 |
138 | outline: 0;
139 | }
140 |
141 | .vjs-playlist-slide-pane {
142 | margin-top: 0;
143 | }
144 | }
145 | }
146 | }
147 |
148 | .video-js.vjs-has-playlist.vjs-vertical-playlist {
149 | margin-right: @vertical-playlist-width;
150 |
151 | .vjs-playlist {
152 | position: absolute;
153 | right: -@vertical-playlist-width;
154 | top: 0;
155 | width: @vertical-playlist-width;
156 | height: 100%;
157 |
158 |
159 | .vjs-playlist-previous, .vjs-playlist-next {
160 | height: @button-size;
161 | width: 100%;
162 |
163 | text-align: center;
164 |
165 | [class*='icon-'] {
166 | font-size: 16px;
167 | }
168 | }
169 |
170 | .vjs-playlist-previous {
171 | top: 0;
172 | left: 0;
173 |
174 | span[class*="icon-"] {
175 | content: "\f077";
176 | }
177 | }
178 | .vjs-playlist-next {
179 | bottom: 0;
180 | left: 0;
181 |
182 | span[class*="icon-"] {
183 | content: "\f078";
184 | }
185 | }
186 |
187 |
188 | .vjs-playlist-slide-pane {
189 | overflow-x: hidden;
190 | margin: @button-size 5px;
191 | padding: 0;
192 | width: 115%;
193 |
194 | .vjs-playlist-item {
195 | clear:both;
196 | margin: 5px 10px;
197 | width: 120px;
198 |
199 | .inline-block();
200 |
201 | &:first-child { margin-top: 3px; }
202 | &:last-child { margin-bottom: 3px; }
203 | &.vjs-playlist-selected {
204 | margin: 2px 7px;
205 | &:first-child { margin-top: 0px; }
206 | &:last-child { margin-bottom: 0px; }
207 | }
208 | }
209 | }
210 | .vjs-playlist-scroll-indicator {
211 |
212 | top: 0px;
213 | left: @vertical-playlist-width - 10px;
214 |
215 | width: 4px;
216 | min-height: 20%;
217 | }
218 |
219 | }
220 |
221 |
222 | /**** captions ****/
223 | &.vjs-has-playlist-caption {
224 | //margin-bottom: (@captions-height + 5px);
225 |
226 |
227 |
228 | .vjs-playlist-caption {
229 | position: absolute;
230 | bottom: -1 * (@captions-height + 5px); // 5px for padding
231 | height: @captions-height;
232 | width: 100%;
233 | padding-top: 5px;
234 |
235 | line-height: @captions-height;
236 | font-size: 12px;
237 | font-weight: bold;
238 | text-align: center;
239 |
240 | .background-color-with-alpha(@control-bg-color, @control-bg-alpha);
241 |
242 | outline: 0;
243 | }
244 |
245 |
246 | }
247 | }
248 |
249 |
250 |
251 | .vjs-playlist {
252 | outline: 0;
253 | overflow: hidden;
254 |
255 |
256 | .background-color-with-alpha(@control-bg-color, @control-bg-alpha);
257 |
258 | .vjs-playlist-previous, .vjs-playlist-next {
259 | position: absolute;
260 | outline: 0;
261 | cursor: pointer;
262 | }
263 | .vjs-playlist-slide-container {
264 | position: relative;
265 |
266 | .vjs-playlist-scroll-indicator {
267 | position: absolute;
268 | .background-color-with-alpha( @main-font-color, .5 );
269 | border-radius: 3px;
270 |
271 | cursor: pointer;
272 |
273 | -webkit-touch-callout: none;
274 | -webkit-user-select: none;
275 | -khtml-user-select: none;
276 | -moz-user-select: none;
277 | -ms-user-select: none;
278 | user-select: none;
279 |
280 | &:hover {
281 | .background-color-with-alpha( @main-font-color, 1 );
282 | }
283 | }
284 | .vjs-playlist-slide-pane {
285 | height: 100%;
286 | width: 100%;
287 | position: relative;
288 | overflow: scroll;
289 | .mobile-scroll();
290 |
291 | ul {
292 | margin: 0;
293 | padding: 0;
294 |
295 | .vjs-playlist-item {
296 | position: relative;
297 | overflow: hidden;
298 |
299 | margin: 10px;
300 | padding: 0;
301 |
302 | outline: 0;
303 | cursor: pointer;
304 |
305 | &:before {
306 | position: absolute;
307 | top: 5px;
308 | right: 3px;
309 |
310 | font-family: 'FontAwesome';
311 | font-size: 16px;
312 | line-height: 14px;
313 |
314 | opacity: .75;
315 | }
316 | &.video:before {
317 | content: '\f008';
318 | }
319 | &.image:before {
320 | content: '\f030';
321 | }
322 | &.vtour:before {
323 | content: '\f0e2';
324 | }
325 |
326 | &.vjs-item-placeholder {
327 | min-width: 120px;
328 | min-height: 80px;
329 | .background-color-with-alpha( @main-font-color, .1 );
330 | opacity: .75;
331 |
332 | }
333 |
334 | &.vjs-playlist-selected {
335 | margin: 7px;
336 | border: 3px solid @main-font-color;
337 | opacity: 1;
338 | }
339 | img {
340 | width: 100%;
341 | height: 100%;
342 | max-height: 80px;
343 | max-width: 120px;
344 | z-index: 10;
345 | }
346 |
347 | .vjs-playlist-item-caption {
348 | position: absolute;
349 | bottom: -20px;
350 | left: 0;
351 | z-index: 20;
352 | opacity: 0;
353 |
354 | width: 100%;
355 | height: 12px;
356 | margin: 0;
357 | padding: 4px 0;
358 |
359 | white-space: nowrap;
360 | overflow: hidden;
361 | text-overflow: ellipsis;
362 | text-indent: 5px;
363 | .background-color-with-alpha(@control-bg-color, .9);
364 |
365 | font-size: 11px;
366 | font-weight: bold;
367 |
368 | .transition(all .2s ease-out);
369 | }
370 | &:hover .vjs-playlist-item-caption,
371 | &.vjs-playlist-selected .vjs-playlist-item-caption {
372 | opacity: 1;
373 | bottom: 0;
374 | }
375 | }
376 | }
377 | }
378 | }
379 | /****** Filtering ******/
380 | &.vjs-playlist-filter-video .video{
381 | display: none !important;
382 | }
383 | &.vjs-playlist-filter-image .image{
384 | display: none !important;
385 | }
386 | &.vjs-playlist-filter-vtour .vtour{
387 | display: none !important;
388 | }
389 | }
390 |
391 |
392 |
393 |
394 |
395 | .inline-block() {
396 | display: inline-block;
397 | *display: inline;
398 | zoom: 1;
399 | }
400 | .mobile-scroll() {
401 | overflow-scrolling: touch;
402 | -webkit-overflow-scrolling: touch;
403 | }
404 |
405 |
406 | @import (inline) 'responsive.css';
407 |
408 |
409 |
--------------------------------------------------------------------------------
/playlist/responsive.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .video-js-responsive-container.vjs-horizontal-playlist {
4 | margin-bottom: 130px;
5 | }
6 | .video-js-responsive-container.vjs-vertical-playlist .video-js {
7 | width: calc( 100% - 150px ) !important; /* calc( 100% - 150px) is used to include space for vertical playlist */
8 | }
9 |
10 | /*
11 | * 16:9 = 56.25%
12 | * 4:3 = 75%
13 | *
14 | * Using a vertical playlist we need to dynamically calculate the padding.
15 | * 16:9 = calc( 56.25% - 84px )
16 | * 4:3 = calc( 75% - 112px )
17 | *
18 | **/
19 | .video-js-responsive-container.vjs-sd.vjs-vertical-playlist { padding-top: calc( 75% - 112px ); }
20 | .video-js-responsive-container.vjs-hd.vjs-vertical-playlist { padding-top: calc( 56.25% - 84px ); }
--------------------------------------------------------------------------------
/playlist/scroll-indicator.js:
--------------------------------------------------------------------------------
1 | videojs.ScrollIndicator = videojs.Button.extend({
2 | init: function( player, options) {
3 | videojs.Button.call(this, player, options);
4 | this.on( 'mousedown', this.onMouseDown );
5 | this.on( 'touchstart', this.onMouseDown );
6 |
7 | this.on( 'selectstart', function() { return false; } );
8 | this.el_.setAttribute('unselectable', 'on');
9 |
10 |
11 | this.linkEl_ = options.linkEl;
12 |
13 | this.dragging_ = true;
14 | this.dragDiff_ = null;
15 | this.handle_ = null;
16 |
17 | videojs.on( this.linkEl_, 'resize', videojs.bind( this, this.onResize ) );
18 | videojs.on( this.linkEl_, 'scroll', videojs.bind( this, this.onScroll ) );
19 |
20 | }
21 | });
22 |
23 | videojs.ScrollIndicator.prototype.createEl = function( type, props ) {
24 | return vjs.Component.prototype.createEl.call(this, 'div', vjs.obj.merge({
25 | className: 'vjs-playlist-scroll-indicator',
26 | innerHTML: ''
27 | }, props));
28 | };
29 |
30 |
31 |
32 | videojs.ScrollIndicator.prototype.onResize = function( e ) {
33 | //console.log( "scrollIndicator.onResize()" );
34 | this.setIndicatorSize();
35 | this.setTrackSize();
36 | this.options_.vertical ? this.moveIndicator_( this.el_.offsetTop ) : this.moveIndicator_( this.el_.offsetLeft );
37 | };
38 |
39 |
40 |
41 |
42 | videojs.ScrollIndicator.prototype.setTrackSize = function() {
43 | this.min_ = 0;
44 | this.max_ = this.options_.vertical ? this.linkEl_.offsetHeight - this.el_.offsetHeight : this.linkEl_.offsetWidth - this.el_.offsetWidth;
45 | };
46 |
47 | videojs.ScrollIndicator.prototype.setIndicatorSize = function() {
48 | var total = this.options_.vertical ? this.linkEl_.offsetHeight : this.linkEl_.offsetWidth;
49 | var maxScroll = this.options_.vertical ? this.linkEl_.scrollHeight : this.linkEl_.scrollWidth;
50 |
51 | var percent = (80 * ( total / maxScroll ) ) + 20; // No smaller than 20%
52 |
53 | if ( this.options_.vertical ) {
54 | this.el_.style.height = percent + "%";
55 | } else {
56 | this.el_.style.width = percent + "%";
57 | }
58 |
59 | };
60 |
61 | videojs.ScrollIndicator.prototype.getSize = function() {
62 | return {from: this.min_, to: this.max_};
63 | };
64 |
65 |
66 | videojs.ScrollIndicator.prototype.onMouseDown = function( e ) {
67 |
68 | this.draggin_ = true;
69 |
70 | var current = videojs.findPosition( this.el_ );
71 | this.parent_ = videojs.findPosition( this.el_.parentNode );
72 |
73 | if ( this.options_.vertical ) {
74 | var mouseY = e.pageY;
75 | this.dragDiff_ = mouseY - current.top;
76 | } else {
77 | var mouseX = e.pageX;
78 | this.dragDiff_ = mouseX - current.left;
79 | }
80 |
81 | this.handle_ = videojs.bind( this, this.onDrag );
82 |
83 | videojs.on( document, 'mousemove', this.handle_ );
84 | videojs.one( document, 'mouseup', videojs.bind( this, this.onMouseUp ) );
85 |
86 | return false;
87 |
88 | };
89 |
90 | videojs.ScrollIndicator.prototype.onDrag = function(e) {
91 | var newPos;
92 | newPos = this.options_.vertical ? ( e.pageY - this.parent_.top - this.dragDiff_ ) : newPos = ( e.pageX - this.parent_.left - this.dragDiff_ );
93 |
94 | //this.moveIndicator_( newPos );
95 |
96 | this.trigger( { type:'dragscroll', position: newPos } );
97 | };
98 |
99 | videojs.ScrollIndicator.prototype.onMouseUp = function() {
100 | videojs.off( document, 'mousemove', this.handle_ );
101 | this.trigger( 'mouseup' );
102 | };
103 |
104 |
105 | videojs.ScrollIndicator.prototype.moveIndicator_ = function( newPos ) {
106 | if ( newPos <= this.min_ ) {
107 | newPos = this.min_;
108 | } else if ( newPos >= this.max_ ) {
109 | newPos = this.max_;
110 | }
111 |
112 | if ( this.options_.vertical ) {
113 | this.el_.style.top = newPos + "px";
114 | } else {
115 | this.el_.style.left = newPos + "px";
116 | }
117 | };
118 |
119 | videojs.ScrollIndicator.prototype.onScroll = function( e ) {
120 | var percent = this.options_.vertical ? this.linkEl_.scrollTop / ( this.linkEl_.scrollHeight - this.linkEl_.offsetHeight ) : this.linkEl_.scrollLeft / ( this.linkEl_.scrollWidth - this.linkEl_.offsetWidth );
121 | this.moveIndicator_( this.max_ * percent );
122 | };
123 |
--------------------------------------------------------------------------------
/replayState/replayState.css:
--------------------------------------------------------------------------------
1 | .video-js .vjs-play-control.icon-undo::before,
2 | .video-js .vjs-big-play-button.icon-undo::before {
3 | content: "\f0e2" !important;
4 | font-family: FontAwesome !important;
5 | }
--------------------------------------------------------------------------------
/replayState/replayState.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 |
5 | vjs.PlayToggle.prototype.removeRestart = function() {
6 | setTimeout( videojs.bind( this, function() {
7 | vjs.removeClass(this.el_, 'icon-undo');
8 | }), 1);
9 | };
10 |
11 |
12 |
13 | // OnPlay - Add the vjs-playing class to the element so it can change appearance
14 | vjs.PlayToggle.prototype.onPlay = function(){
15 |
16 | this.removeRestart();
17 |
18 | vjs.removeClass(this.el_, 'vjs-paused');
19 | vjs.addClass(this.el_, 'vjs-playing');
20 | this.el_.children[0].children[0].innerHTML = 'Pause'; // change the button text to "Pause"
21 | };
22 |
23 | // OnPause - Add the vjs-paused class to the element so it can change appearance
24 | vjs.PlayToggle.prototype.onPause = function(){
25 | var bigPlayButton = this.player().bigPlayButton;
26 |
27 | vjs.removeClass(this.el_, 'icon-undo');
28 | vjs.removeClass(this.el_, 'vjs-playing');
29 |
30 | vjs.removeClass(bigPlayButton.el(), 'icon-undo' );
31 |
32 | if ( this.player_.duration() == this.player_.currentTime() ) {
33 | vjs.addClass(this.el_, 'icon-undo');
34 | vjs.addClass(bigPlayButton.el() , 'icon-undo');
35 | this.el_.children[0].children[0].innerHTML = 'Replay'; // change the button text to "Play"
36 |
37 | this.removeRestart_ = videojs.bind( this, function() {
38 | vjs.removeClass(this.el_, 'icon-undo');
39 | });
40 | this.player_.one('playlistautoload', this.removeRestart_ );
41 | } else {
42 | vjs.addClass(this.el_, 'vjs-paused');
43 | this.el_.children[0].children[0].innerHTML = 'Play'; // change the button text to "Play"
44 | }
45 | };
46 |
47 |
48 |
49 | })();
50 |
--------------------------------------------------------------------------------
/resize/videojs.resize.css:
--------------------------------------------------------------------------------
1 | .video-js .vjs-menu-button.vjs-resize-button .vjs-menu-content {
2 | width: 4em !important;
3 | height: 7em;
4 | left: -2em !important;
5 | }
6 |
7 | .video-js .vjs-menu-button.vjs-resize-button .vjs-menu-content .vjs-menu-item {
8 | width: 100%;
9 | float: left;
10 | font-size: 1.8em;
11 | padding: 5px 0;
12 | }
13 |
14 | .video-js .vjs-fullscreen-control {
15 | display: none !important;
16 | }
17 |
18 | .video-js {
19 | -webkit-transition: all .7s ease;
20 | -moz-transition: all .7s ease;
21 | transition: all .7s ease;
22 | }
--------------------------------------------------------------------------------
/resize/videojs.resize.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 |
4 |
5 | // Main button
6 | videojs.ResizeControl = videojs.MenuButton.extend({
7 | init: function( player, options ) {
8 | videojs.MenuButton.call(this, player, options);
9 | }
10 | });
11 |
12 | // Enable Fullscreen on main icon click
13 | videojs.ResizeControl.prototype.onClick = videojs.FullscreenToggle.prototype.onClick;
14 |
15 | videojs.ResizeControl.prototype.createItems = function(){
16 | var items = [], track;
17 | var options = this.options();
18 |
19 | items.push(new videojs.LargerToggle(this.player_,this.options_.bigSize));
20 | items.push(new videojs.SmallerToggle(this.player_,this.options_.smallSize));
21 |
22 | console.log( items[0].el().style.width );
23 |
24 | return items;
25 | };
26 |
27 |
28 | // Go Larger button
29 | videojs.LargerToggle = videojs.MenuItem.extend({
30 | init: function( player, options ) {
31 | videojs.Button.call(this, player, options);
32 | }
33 |
34 | });
35 |
36 | videojs.LargerToggle.prototype.createEl = function(type, props) {
37 | return vjs.Button.prototype.createEl.call(this, 'li', vjs.obj.merge({
38 | className: 'vjs-menu-item',
39 | innerHTML: ' '
40 | }, props));
41 | }
42 |
43 | videojs.LargerToggle.prototype.buildCSSClass = function(){
44 | return 'vjs-larger-control ' + vjs.Button.prototype.buildCSSClass.call(this);
45 | };
46 |
47 | videojs.LargerToggle.prototype.onClick = function() {
48 | this.player().el().style.height = this.options_.h + "px";
49 | this.player().el().style.width = this.options_.w + "px";
50 | }
51 |
52 |
53 |
54 | // Go Smaller button
55 | videojs.SmallerToggle = videojs.MenuItem.extend({
56 | init: function( player, options ) {
57 | videojs.Button.call(this, player, options);
58 | }
59 | });
60 |
61 | videojs.SmallerToggle.prototype.createEl = function(type, props) {
62 | return vjs.Button.prototype.createEl.call(this, 'li', vjs.obj.merge({
63 | className: 'vjs-menu-item',
64 | innerHTML: ' '
65 | }, props));
66 | }
67 |
68 | videojs.SmallerToggle.prototype.buildCSSClass = function(){
69 | return 'vjs-smaller-control icon-resize-small ' + vjs.Button.prototype.buildCSSClass.call(this);
70 | };
71 |
72 | videojs.SmallerToggle.prototype.onClick = function() {
73 | this.player().el().style.height = this.options_.h + "px";
74 | this.player().el().style.width = this.options_.w + "px";
75 | }
76 |
77 |
78 | videojs.plugin('resize', function(options) {
79 | var player = this.el();
80 | var newOpts = {};
81 | options = options || {};
82 |
83 | if ( options.h > player.offsetHeight ) {
84 | newOpts.smallSize = {
85 | h: player.offsetHeight,
86 | w: player.offsetWidth
87 | };
88 | newOpts.bigSize = options;
89 | } else {
90 | newOpts.bigSize = {
91 | h: player.offsetHeight,
92 | w: player.offsetWidth
93 | };
94 | newOpts.smallSize = options;
95 | }
96 | var resize = this.controlBar.addChild( 'resizeControl', newOpts );
97 |
98 | this.controlBar.el().className += " vjs-does-resize";
99 | });
100 | })();
--------------------------------------------------------------------------------
/showPosterAtEnd/videojs.showPosterAtEnd.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | videojs.plugin('showPosterAtEnd', function(){
3 | this.on('ended',function() {
4 | console.log( this );
5 | this.posterImage.show();
6 | this.bigPlayButton.show();
7 | this.currentTime(0.0);
8 | this.pause();
9 | });
10 | });
11 | })();
--------------------------------------------------------------------------------
/socialOverlay/README.md:
--------------------------------------------------------------------------------
1 | Creating this plugin: http://tastybytes.net/creating-a-video-js-plugin/
2 |
3 | Demo: http://brianpkelley.github.io/video-js-4-plugins/demos/socialOverlay.html
4 |
5 | Usage: https://github.com/brianpkelley/video-js-4-plugins/blob/gh-pages/demos/socialOverlay.html
6 |
--------------------------------------------------------------------------------
/socialOverlay/socialOverlay.css:
--------------------------------------------------------------------------------
1 | /* We are using the font awesome set. */
2 | @import url('//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css');
3 |
4 | /* This applies the blur filter to the video/preview etc */
5 | .video-js .vjs-tech.vjs-blur {
6 | -webkit-transition: .75s all;
7 | transition: .75s all;
8 |
9 | -webkit-filter: blur(5px);
10 | filter: blur(5px);
11 | }
12 |
13 | /* Basic overlay styles, we are using the table-cell layout hack to center the content */
14 | .video-js .vjs-sharing-overlay {
15 | background: rgba( 0, 0, 0, 0.6 );
16 | position: absolute;
17 | top: 0;
18 | left: 0;
19 | opacity: 0;
20 | -webkit-transition: .75s all;
21 | transition: .75s all;
22 |
23 | /* Root "Table" element for hack */
24 | display: table;
25 | height: 100%;
26 | width: 100%;
27 | }
28 |
29 |
30 | /* Icon for our initial button */
31 | .vjs-control.vjs-share-button {
32 | cursor: pointer;
33 | }
34 | .vjs-control.vjs-share-button:before {
35 | font-family: FontAwesome;
36 | }
37 |
38 | /* The styles for an on-screen button */
39 | .video-js > .vjs-control.vjs-share-button {
40 | position: absolute;
41 | top: 1em;
42 | right: 1em;
43 | }
44 | .video-js > .vjs-control.vjs-share-button:hover:before {
45 | text-shadow: 0 0 .3em rgba( 255,255,255,0.8);
46 | }
47 |
48 | /* The styles for the button on a control bar */
49 | .vjs-control-bar .vjs-control.vjs-share-button:before {
50 | content: '\f064';
51 | }
52 |
53 | .video-js > .vjs-control.vjs-share-button:before {
54 | content: '\f14d';
55 | font-size: 2em;
56 | color: rgba(255,255,255,0.75);
57 | text-shadow: 0 0 .5em rgba(0,0,0,0.8);
58 | }
59 |
60 |
61 |
62 |
63 |
64 | /* Styling for the icons */
65 | .vjs-sharing-container {
66 | /* The table-cell of the hack */
67 | display: table-cell;
68 | height: 100%;
69 | width: 100%;
70 |
71 | vertical-align: middle;
72 | text-align: center;
73 | }
74 |
75 | /* Icon body */
76 | .vjs-sharing-container .vjs-share-icon {
77 | font-size: 7em;
78 | margin: .2em;
79 | cursor: pointer;
80 | position: relative;
81 | }
82 | /* The actual Icon */
83 | .vjs-sharing-container .vjs-share-icon:hover:before {
84 | color: #fff;
85 | text-shadow: 0 0 .5em rgba(255,255,255,0.5);
86 | }
87 |
88 | /* Show the text that is usually hidden in a videojs.Button */
89 | .vjs-sharing-container .vjs-share-icon .vjs-control-text {
90 | position: absolute;
91 | width: 100%;
92 | font-size: .15em;
93 | font-weight: 700;
94 | text-align: center;
95 | left: 0;
96 | bottom: -1em;
97 |
98 | clip: initial;
99 | height: initial;
100 | margin: 0;
101 | }
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | /* To show/hide the onscreen button. Duplicate the showing / hiding of the control bar */
112 |
113 | .vjs-has-started.vjs-user-inactive.vjs-playing > .vjs-control.vjs-share-button,
114 | .video-js > .vjs-control.vjs-share-button {
115 | display: block;
116 | visibility: hidden;
117 | opacity: 0;
118 | -webkit-transition: visibility 1s, opacity 1s;
119 | -moz-transition: visibility 1s, opacity 1s;
120 | -o-transition: visibility 1s, opacity 1s;
121 | transition: visibility 1s, opacity 1s;
122 | }
123 |
124 | .vjs-has-started > .vjs-control.vjs-share-button {
125 | display: block;
126 | visibility: visible;
127 | opacity: 1;
128 | -webkit-transition: visibility 0.1s, opacity 0.1s;
129 | -moz-transition: visibility 0.1s, opacity 0.1s;
130 | -o-transition: visibility 0.1s, opacity 0.1s;
131 | transition: visibility 0.1s, opacity 0.1s;
132 | }
133 |
134 |
135 |
--------------------------------------------------------------------------------
/socialOverlay/socialOverlay.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | // Create the button
5 | videojs.ShareButton = videojs.Button.extend({
6 | init: function( player, options ) {
7 | // Initialize the button using the default constructor
8 | videojs.Button.call( this, player, options );
9 |
10 | }
11 | });
12 |
13 | // Set the text for the button
14 | videojs.ShareButton.prototype.buttonText = 'Share Video';
15 |
16 | // These are the defaults for this class.
17 | videojs.ShareButton.prototype.options_ = {};
18 |
19 | // videojs.Button uses this function to build the class name.
20 | videojs.ShareButton.prototype.buildCSSClass = function() {
21 | // Add our className to the returned className
22 | return 'vjs-share-button ' + videojs.Button.prototype.buildCSSClass.call(this);
23 | };
24 |
25 | // videojs.Button already sets up the onclick event handler, we just need to overwrite the callback
26 | videojs.ShareButton.prototype.onClick = function( e ) {
27 | // We need to stop this event before it bubbles up to "window" for our event listener below.
28 | e.stopImmediatePropagation();
29 |
30 |
31 | // There are a few ways to accomplish opening the overlay
32 | // I chose to create and destroy the overlay to demonstrate
33 | // the dispose method. Creating the component as a child is
34 | // the direction I would choose.
35 | this.overlay_ = new videojs.ShareContainer( this.player_, this.options_ );
36 |
37 | // We need to add an event listener to close the overlay when the user clicks outside the overlay / player.
38 | // Because we are destroying the overlay, we only need to listen to this once.
39 | videojs.one( window, 'click', videojs.bind( this, this.windowClick ) );
40 |
41 | // Add the overlay to the player
42 | this.player_.addChild( this.overlay_ );
43 |
44 | // Call the show method to apply effects and display the overlay
45 | this.overlay_.show();
46 |
47 | // Pause the video
48 | this.player_.pause();
49 |
50 |
51 | };
52 |
53 | videojs.ShareButton.prototype.windowClick = function( e ) {
54 | // Remove it from the parent (player)
55 | this.player_.removeChild( this.overlay_ );
56 |
57 | // Now remove it from memory.
58 | // The dispose method removes the element and component.
59 | this.overlay_.dispose();
60 |
61 | // We no longer use this variable so release it.
62 | delete this.overlay_;
63 | };
64 |
65 |
66 |
67 |
68 |
69 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
70 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
71 |
72 |
73 |
74 |
75 | // Create the overlay and container for the links
76 | videojs.ShareContainer = videojs.Component.extend({
77 | init: function( player, options ) {
78 | // call the parent constructor
79 | videojs.Component.call( this, player, options );
80 |
81 | }
82 | });
83 |
84 | videojs.ShareContainer.prototype.options_ = {
85 | children: {
86 | 'facebookShare': {},
87 | 'twitterShare': {},
88 | 'pinterestShare': {},
89 | 'googlePlusShare': {},
90 | 'linkedInShare': {}
91 | }
92 | };
93 |
94 | // This function will be called by the videojs.Component constructor.
95 | videojs.ShareContainer.prototype.createEl = function( tagName, props ) {
96 | // Create the elements
97 |
98 | // The black and blury overlay
99 | var overlay = videojs.createEl( 'div', {
100 | className: 'vjs-sharing-overlay'
101 | });
102 |
103 | // The container for the links/logos of the social sites we wish to offer
104 | var container = videojs.createEl( 'div', {
105 | className: 'vjs-sharing-container'
106 | });
107 |
108 | // this.contentEl is the element that children (links/logos) are added to.
109 | this.contentEl_ = container;
110 |
111 | overlay.appendChild( this.contentEl_);
112 |
113 | // This will become "this.el_"
114 | return overlay;
115 | };
116 |
117 | videojs.ShareContainer.prototype.show = function() {
118 | var techEl;
119 | var playerEl;
120 |
121 | // Do the default show method
122 | this.el_.style.display = 'table';
123 |
124 | // To get the blur effect, we need to add it to the tech element.
125 | // But we do not want to waste our time with trying to blur a flash element.
126 | if ( this.player_.techName != "Flash" ) {
127 | techEl = this.player_.tech.el();
128 | playerEl = this.player_.el();
129 |
130 | // We have to set the clip property here because it is dependent on the size of the player
131 | techEl.style.clip = 'rect(0 0 ' + playerEl.offsetWidth + 'px ' + playerEl.offsetHeight + 'px)';
132 |
133 | // Add our class to blur the video.
134 | videojs.addClass( techEl, 'vjs-blur' );
135 | }
136 |
137 | // Hide the controls, using opacity = 0 will use the default transition timing.
138 | this.player_.controlBar.el().style.opacity = '0';
139 |
140 | this.el_.style.opacity = '1';
141 |
142 | };
143 |
144 | videojs.ShareContainer.prototype.hide = function() {
145 | var techEl = this.player_.tech.el();
146 |
147 | // Do the default hide method
148 | videojs.Component.prototype.hide.call( this );
149 |
150 | // This time we don't care if it is flash, html, youtube etc
151 | techEl.style.clip = '';
152 | videojs.removeClass( techEl, 'vjs-blur' );
153 |
154 | // Show the controls, using opacity = '' will use the default opacity.
155 | this.player_.controlBar.el().style.opacity = '';
156 | };
157 |
158 | videojs.ShareContainer.prototype.dispose = function() {
159 | // Hide and remove classes from the tech element
160 | this.hide();
161 |
162 | // Do the default dispose method
163 | videojs.Component.prototype.dispose.call( this );
164 |
165 | };
166 |
167 |
168 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
169 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
170 |
171 | // This is the base class for the share items. Each Icon can be passed a "Name" and an icon class.
172 | videojs.OverlaySocialButton = videojs.Button.extend({
173 | init: function( player, options ) {
174 | videojs.Button.call(this, player, options );
175 |
176 | }
177 | });
178 |
179 |
180 | videojs.OverlaySocialButton.prototype.createEl = function(type, props){
181 | var el;
182 |
183 | // Add standard Aria and Tabindex info
184 | props = vjs.obj.merge({
185 | className: this.buildCSSClass(),
186 | 'role': 'button',
187 | 'aria-live': 'polite', // let the screen reader user know that the text of the button may change
188 | tabIndex: 0
189 | }, props);
190 |
191 | // 'i' is needed for the Font-Awesome icons
192 | el = vjs.Component.prototype.createEl.call(this, 'i', props);
193 |
194 | // if innerHTML hasn't been overridden (bigPlayButton), add content elements
195 | if (!props.innerHTML) {
196 | this.contentEl_ = vjs.createEl('div', {
197 | className: 'vjs-control-content'
198 | });
199 |
200 | this.controlText_ = vjs.createEl('span', {
201 | className: 'vjs-control-text',
202 | innerHTML: this.options_.text || 'Need Text'
203 | });
204 |
205 | this.contentEl_.appendChild(this.controlText_);
206 | el.appendChild(this.contentEl_);
207 | }
208 |
209 | return el;
210 | };
211 |
212 | videojs.OverlaySocialButton.prototype.buildCSSClass = function() {
213 | return 'vjs-share-icon fa fa-' + this.options_.icon + '-square fa-5x';//+ vjs.Button.prototype.buildCSSClass.call(this);
214 | };
215 |
216 |
217 | // These are the indvidual buttons for each type of share.
218 | // Twitter
219 | videojs.TwitterShare = videojs.OverlaySocialButton.extend({
220 | init: function( player, options ) {
221 | videojs.OverlaySocialButton.call( this, player, options );
222 | }
223 | });
224 | videojs.TwitterShare.prototype.options_ = { icon: 'twitter', text: 'Twitter' };
225 | videojs.TwitterShare.prototype.onClick = function() {
226 | // Do Share action here
227 | };
228 |
229 | // Facebook
230 | videojs.FacebookShare = videojs.OverlaySocialButton.extend({
231 | init: function( player, options ) {
232 | videojs.OverlaySocialButton.call( this, player, options );
233 | }
234 | });
235 | videojs.FacebookShare.prototype.options_ = { icon: 'facebook', text: 'Facebook' };
236 | videojs.FacebookShare.prototype.onClick = function() {
237 | // Do Share action here
238 | };
239 |
240 | // Pinterest
241 | videojs.PinterestShare = videojs.OverlaySocialButton.extend({
242 | init: function( player, options ) {
243 | videojs.OverlaySocialButton.call( this, player, options );
244 | }
245 | });
246 | videojs.PinterestShare.prototype.options_ = { icon: 'pinterest', text: 'Pinterest' };
247 | videojs.PinterestShare.prototype.onClick = function() {
248 | // Do Share action here
249 | };
250 |
251 | // Google Plus
252 | videojs.GooglePlusShare = videojs.OverlaySocialButton.extend({
253 | init: function( player, options ) {
254 | videojs.OverlaySocialButton.call( this, player, options );
255 | }
256 | });
257 | videojs.GooglePlusShare.prototype.options_ = { icon: 'google-plus', text: 'Google+' };
258 | videojs.GooglePlusShare.prototype.onClick = function() {
259 | // Do Share action here
260 | };
261 |
262 | // LinkedIn
263 | videojs.LinkedInShare = videojs.OverlaySocialButton.extend({
264 | init: function( player, options ) {
265 | videojs.OverlaySocialButton.call( this, player, options );
266 | }
267 | });
268 | videojs.LinkedInShare.prototype.options_ = { icon: 'linkedin', text: 'LinkedIn' };
269 | videojs.LinkedInShare.prototype.onClick = function() {
270 | // Do Share action here
271 | };
272 |
273 |
274 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
275 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
276 |
277 |
278 | // This function will be called by video.js when it loops through all of the registered plugins.
279 | var pluginFn = function( options ) {
280 | // We need to pass off the options to the control bar button.
281 | var shareComponent = new videojs.ShareButton( this, options );
282 |
283 | // Set the default position for the sharing button. Default: control-bar
284 | var onScreen = options.onScreen || false;
285 | // Now we remove the onScreen option as it does not pertain to anything inside the button.
286 | delete options.onScreen;
287 |
288 | var shareButton;
289 |
290 | // Should the button be added to the control bar or screen?
291 | if ( onScreen ) {
292 | shareButton = this.addChild( shareComponent );
293 | } else {
294 | shareButton = this.controlBar.addChild( shareComponent );
295 | }
296 |
297 |
298 | };
299 |
300 | videojs.plugin( 'socialOverlay', pluginFn );
301 |
302 |
303 |
304 |
305 | //videojs.obj.merge(videojs, videojs);
306 | })();
--------------------------------------------------------------------------------
/themeLoader/videojs.themeLoader.js:
--------------------------------------------------------------------------------
1 | //
2 | // Author: Brian Kelley
3 | // Description: Very simple plugin that automatically includes the video.js css file that
4 | // relates to the classname vjs-SKINNAME-skin. On line 17 insert your theme
5 | // directory relative to the page or absolute. Strongly recommended to us
6 | // temp.href = "//yoursite.com/XXXXXXX" (note the absence of http: or https:) to avoid issues with protocols.
7 | //
8 | // Example: would automatically include "yourThemeDirectory/blue.css"
9 | //
10 |
11 | (function(){
12 | videojs.plugin('bvThemeLoader', function(){
13 | var skinTest = /vjs\-(.*?)\-skin/.exec(this.el().className);
14 | var skinName = skinTest[1];
15 |
16 | var head = document.getElementsByTagName('head')[0];
17 | var temp = document.createElement('link');
18 |
19 | // replace with path to your themes directory
20 | temp.href = "themes/"+skinName+".css";
21 | temp.rel = "stylesheet";
22 |
23 | head.appendChild( temp );
24 |
25 | });
26 | })();
--------------------------------------------------------------------------------