mirror of
https://github.com/videojs/video.js.git
synced 2025-04-11 11:42:08 +02:00
Merge pull request #1 from heff/Akkuma-master
Updates for videojs/video.js#1093
This commit is contained in:
commit
e7617bfdd4
22
CHANGELOG.md
22
CHANGELOG.md
@ -2,13 +2,31 @@ CHANGELOG
|
||||
=========
|
||||
|
||||
## HEAD (Unreleased)
|
||||
* Updated the UI to support live video ([view](https://github.com/videojs/video.js/pull/1121))
|
||||
* The UI now resets after a source change ([view](https://github.com/videojs/video.js/pull/1124))
|
||||
* Now assuming smart CSS defaults for sliders to prevent reflow on player init ([view](https://github.com/videojs/video.js/pull/1122))
|
||||
* Fixed the title element placement in menus [[view](https://github.com/videojs/video.js/pull/1114)]
|
||||
* Fixed title support for menu buttons ([view](https://github.com/videojs/video.js/pull/1128))
|
||||
* Fixed extra mousemove events on Windows caused by certain apps, not users [[view](https://github.com/videojs/video.js/pull/1068)]
|
||||
* Fixed error due to undefined tech when no source is supported [[view](https://github.com/videojs/video.js/pull/1172)]
|
||||
* Fixed the progress bar not finishing when manual timeupdate events are used [[view](https://github.com/videojs/video.js/pull/1173)]
|
||||
* Added a more informative and styled fallback message for non-html5 browsers [[view](https://github.com/videojs/video.js/pull/1181)]
|
||||
|
||||
--------------------
|
||||
|
||||
## 4.5.2 (2014-04-12)
|
||||
* Updated release versioning to include bower.json and component.json
|
||||
|
||||
## 4.5.1 (2014-03-27)
|
||||
* Fixed a bug from the last release where canPlaySource was no longer exported
|
||||
|
||||
## 4.5.0 (2014-03-27)
|
||||
* Added component(1) support ([view](https://github.com/videojs/video.js/pull/1032))
|
||||
* Captions now move down when controls are hidden ([view](https://github.com/videojs/video.js/pull/1053))
|
||||
* Added the .less source file to the distribution files ([view](https://github.com/videojs/video.js/pull/1056))
|
||||
* Changed src() to return the current selected source ([view](https://github.com/videojs/video.js/pull/968))
|
||||
* Added a grunt task for opening the next issue that needs addressing ([view](https://github.com/videojs/video.js/pull/1059))
|
||||
|
||||
--------------------
|
||||
* Fixed Android 4.0+ devices' check for HLS support ([view](https://github.com/videojs/video.js/pull/1084))
|
||||
|
||||
## 4.4.3 (2014-03-06)
|
||||
* Fixed bugs in IE9 Windows 7N with no Media Player ([view](https://github.com/videojs/video.js/pull/1060))
|
||||
|
@ -183,15 +183,24 @@ cp sandbox/index.html.example sandbox/index.html
|
||||
open sandbox/index.html
|
||||
```
|
||||
|
||||
> #### NOTE: Testing Flash Locally in Chrome
|
||||
> Chrome 21+ (as of 2013/01/01) doens't run Flash files that are local and loaded into a locally accessed page (file:///).
|
||||
|
||||
### Testing Locally
|
||||
A simple Connect server is available via the Grunt plugin. The commands below will allow you to setup a test sandbox and begin development.
|
||||
|
||||
```bash
|
||||
cp sandbox/index.html.example sandbox/index.html
|
||||
grunt connect
|
||||
open http://localhost:9999/sandbox/index.html
|
||||
```
|
||||
|
||||
> NOTES regarding local testing in Chrome 21+ (as of 2013/01/01)
|
||||
> Flash files that are local and loaded into a locally accessed page (file:///) will NOT run.
|
||||
> To get around this you can do either of the following:
|
||||
>
|
||||
> 1. Do your development and testing using a local HTTP server.
|
||||
> 1. Do your development and testing using a local HTTP server. See Grunt commands above.
|
||||
>
|
||||
> 2. [Disable the version of Flash included with Chrome](http://helpx.adobe.com/flash-player/kb/flash-player-google-chrome.html#How_can_I_run_debugger_or_alternate_versions_of_Flash_Player_in_Google_Chrome) and enable a system-wide version of Flash instead.
|
||||
|
||||
|
||||
Commit and push changes as you go (using git directly). Write thorough descriptions of your changes in your commit messages.
|
||||
|
||||
```bash
|
||||
|
36
Gruntfile.js
36
Gruntfile.js
@ -71,6 +71,14 @@ module.exports = function(grunt) {
|
||||
files: [ 'src/**/*', 'test/unit/*.js', 'Gruntfile.js' ],
|
||||
tasks: 'dev'
|
||||
},
|
||||
connect: {
|
||||
dev: {
|
||||
options: {
|
||||
port: 9999,
|
||||
keepalive: true
|
||||
}
|
||||
}
|
||||
},
|
||||
copy: {
|
||||
minor: {
|
||||
files: [
|
||||
@ -171,9 +179,28 @@ module.exports = function(grunt) {
|
||||
}
|
||||
}
|
||||
},
|
||||
bump: {
|
||||
files: ['package.json'],
|
||||
updateConfigs: ['pkg']
|
||||
version: {
|
||||
options: {
|
||||
pkg: 'package.json'
|
||||
},
|
||||
major: {
|
||||
options: {
|
||||
release: 'major'
|
||||
},
|
||||
src: ['package.json', 'bower.json', 'component.json']
|
||||
},
|
||||
minor: {
|
||||
options: {
|
||||
release: 'minor'
|
||||
},
|
||||
src: ['package.json', 'bower.json', 'component.json']
|
||||
},
|
||||
patch: {
|
||||
options: {
|
||||
release: 'patch'
|
||||
},
|
||||
src: ['package.json', 'bower.json', 'component.json']
|
||||
}
|
||||
},
|
||||
tagrelease: {
|
||||
file: 'package.json',
|
||||
@ -183,6 +210,7 @@ module.exports = function(grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-qunit');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
@ -196,7 +224,7 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('videojs-doc-generator');
|
||||
grunt.loadNpmTasks('grunt-zip');
|
||||
grunt.loadNpmTasks('grunt-banner');
|
||||
grunt.loadNpmTasks('grunt-bump');
|
||||
grunt.loadNpmTasks('grunt-version');
|
||||
grunt.loadNpmTasks('grunt-tagrelease');
|
||||
grunt.loadNpmTasks('chg');
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "video.js",
|
||||
"description": "An HTML5 and Flash video player with a common API and skin for both.",
|
||||
"version": "4.4.3",
|
||||
"version": "4.5.2",
|
||||
"main": [
|
||||
"dist/video-js/video.js",
|
||||
"dist/video-js/video.js",
|
||||
"dist/video-js/video-js.css"
|
||||
],
|
||||
"keywords": [
|
||||
@ -13,4 +13,4 @@
|
||||
"video",
|
||||
"player"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
<source src="http://video-js.zencoder.com/oceans-clip.ogv" type='video/ogg' />
|
||||
<track kind="captions" src="demo.captions.vtt" srclang="en" label="English"></track><!-- Tracks need an ending tag thanks to IE9 -->
|
||||
<track kind="subtitles" src="demo.captions.vtt" srclang="en" label="English"></track><!-- Tracks need an ending tag thanks to IE9 -->
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
|
||||
</body>
|
||||
|
@ -26,6 +26,7 @@ var sourceFiles = [
|
||||
"src/js/menu.js",
|
||||
"src/js/player.js",
|
||||
"src/js/control-bar/control-bar.js",
|
||||
"src/js/control-bar/live-display.js",
|
||||
"src/js/control-bar/play-toggle.js",
|
||||
"src/js/control-bar/time-display.js",
|
||||
"src/js/control-bar/fullscreen-toggle.js",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "video.js",
|
||||
"description": "An HTML5 and Flash video player with a common API and skin for both.",
|
||||
"version": "4.4.2",
|
||||
"version": "4.5.2",
|
||||
"keywords": [
|
||||
"videojs",
|
||||
"html5",
|
||||
|
@ -257,9 +257,9 @@
|
||||
"prompt": "confirm"
|
||||
},
|
||||
{
|
||||
"id": "type",
|
||||
"desc": "Provide the release type",
|
||||
"prompt": {
|
||||
"id": "type",
|
||||
"message": "release type",
|
||||
"default": "patch",
|
||||
"type": "text"
|
||||
@ -278,8 +278,8 @@
|
||||
"exec": "grunt chg-release:<%= type %>"
|
||||
},
|
||||
{
|
||||
"desc": "Bump the package version",
|
||||
"exec": "grunt bump-only:<%= type %>"
|
||||
"desc": "Bump package versions",
|
||||
"exec": "grunt version:<%= type %>"
|
||||
},
|
||||
{
|
||||
"desc": "Build the release",
|
||||
|
@ -234,7 +234,7 @@ _inherited from_: [src/js/component.js#L224](https://github.com/videojs/video.js
|
||||
##### RETURNS:
|
||||
* `Boolean` Controls are showing
|
||||
|
||||
_defined in_: [src/js/player.js#L1167](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1167)
|
||||
_defined in_: [src/js/player.js#L1174](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1174)
|
||||
|
||||
---
|
||||
|
||||
@ -673,7 +673,7 @@ _inherited from_: [src/js/component.js#L120](https://github.com/videojs/video.js
|
||||
* `String` poster URL when getting
|
||||
* `vjs.Player` self when setting
|
||||
|
||||
_defined in_: [src/js/player.js#L1140](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1140)
|
||||
_defined in_: [src/js/player.js#L1147](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1147)
|
||||
|
||||
---
|
||||
|
||||
@ -778,9 +778,10 @@ _inherited from_: [src/js/component.js#L653](https://github.com/videojs/video.js
|
||||
* __source__ `String|Object|Array` _(OPTIONAL)_ The source URL, object, or array of sources
|
||||
|
||||
##### RETURNS:
|
||||
* `vjs.Player` self
|
||||
* `String` The current video source when getting
|
||||
* `String` The player when setting
|
||||
|
||||
_defined in_: [src/js/player.js#L1024](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1024)
|
||||
_defined in_: [src/js/player.js#L1025](https://github.com/videojs/video.js/blob/master/src/js/player.js#L1025)
|
||||
|
||||
---
|
||||
|
||||
|
@ -20,8 +20,8 @@ You can download the Video.js source and host it on your own servers, or use the
|
||||
|
||||
### CDN Version ###
|
||||
```html
|
||||
<link href="//vjs.zencdn.net/4.4/video-js.css" rel="stylesheet">
|
||||
<script src="//vjs.zencdn.net/4.4/video.js"></script>
|
||||
<link href="//vjs.zencdn.net/4.5/video-js.css" rel="stylesheet">
|
||||
<script src="//vjs.zencdn.net/4.5/video.js"></script>
|
||||
```
|
||||
|
||||
### Self Hosted. ###
|
||||
@ -57,6 +57,7 @@ Otherwise include/exclude attributes, settings, sources, and tracks exactly as y
|
||||
<source src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4' />
|
||||
<source src="http://video-js.zencoder.com/oceans-clip.webm" type='video/webm' />
|
||||
<source src="http://video-js.zencoder.com/oceans-clip.ogv" type='video/ogg' />
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
```
|
||||
|
||||
@ -89,13 +90,13 @@ The third argument is a 'ready' callback. Once Video.js has initialized it will
|
||||
Instead of using an element ID, you can also pass a reference to the element itself.
|
||||
|
||||
```js
|
||||
videojs(document.getElementsById('example_video_1')), {}, function()) {
|
||||
videojs(document.getElementById('example_video_1'), {}, function() {
|
||||
// This is functionally the same as the previous example.
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
videojs(document.getElementsByClassName('awesome_video_class')[0], {}, function()) {
|
||||
videojs(document.getElementsByClassName('awesome_video_class')[0], {}, function() {
|
||||
// You can grab an element by class if you'd like, just make sure
|
||||
// if it's an array that you pick one (here we chose the first).
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "video.js",
|
||||
"description": "An HTML5 and Flash video player with a common API and skin for both.",
|
||||
"version": "4.4.3",
|
||||
"version": "4.5.2",
|
||||
"copyright": "Copyright 2014 Brightcove, Inc. https://github.com/videojs/video.js/blob/master/LICENSE",
|
||||
"keywords": [
|
||||
"videojs",
|
||||
@ -26,6 +26,7 @@
|
||||
"devDependencies": {
|
||||
"grunt-cli": "~0.1.0",
|
||||
"grunt": "~0.4",
|
||||
"grunt-contrib-connect": "~0.7.1",
|
||||
"grunt-contrib-jshint": "~0.4.3",
|
||||
"grunt-contrib-watch": "~0.1.4",
|
||||
"grunt-contrib-qunit": "~0.2.1",
|
||||
@ -53,9 +54,9 @@
|
||||
"grunt-zip": "0.10.2",
|
||||
"grunt-banner": "~0.2.0",
|
||||
"chg": "~0.1.8",
|
||||
"grunt-bump": "0.0.13",
|
||||
"grunt-tagrelease": "~0.3.3",
|
||||
"github": "~0.1.14",
|
||||
"open": "0.0.4"
|
||||
"open": "0.0.4",
|
||||
"grunt-version": "~0.3.0"
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
<source src="http://video-js.zencoder.com/oceans-clip.webm" type='video/webm'>
|
||||
<source src="http://video-js.zencoder.com/oceans-clip.ogv" type='video/ogg'>
|
||||
<track kind="captions" src="../build/demo-files/demo.captions.vtt" srclang="en" label="English"></track><!-- Tracks need an ending tag thanks to IE9 -->
|
||||
<p>Video Playback Not Supported</p>
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a>
|
||||
</video>
|
||||
|
||||
<script>
|
||||
|
@ -303,6 +303,8 @@ fonts to show/hide properly.
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 0.5em;
|
||||
/* assuming volume starts at 1.0 */
|
||||
width: 100%;
|
||||
|
||||
background: @slider-bar-color
|
||||
url(@slider-bar-pattern)
|
||||
@ -311,6 +313,10 @@ fonts to show/hide properly.
|
||||
.vjs-default-skin .vjs-volume-bar .vjs-volume-handle {
|
||||
width: 0.5em;
|
||||
height: 0.5em;
|
||||
/* Assumes volume starts at 1.0. If you change the size of the
|
||||
handle relative to the volume bar, you'll need to update this value
|
||||
too. */
|
||||
left: 4.5em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-volume-handle:before {
|
||||
@ -368,6 +374,8 @@ fonts to show/hide properly.
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
/* updated by javascript during playback */
|
||||
width: 0;
|
||||
/* Needed for IE6 *///
|
||||
left: 0;
|
||||
top: 0;
|
||||
@ -400,6 +408,27 @@ fonts to show/hide properly.
|
||||
padding-top: 0.1em /* Minor adjustment */;
|
||||
}
|
||||
|
||||
/* Live Mode
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
.vjs-default-skin.vjs-live .vjs-time-controls,
|
||||
.vjs-default-skin.vjs-live .vjs-time-divider,
|
||||
.vjs-default-skin.vjs-live .vjs-progress-control {
|
||||
display: none;
|
||||
}
|
||||
.vjs-default-skin.vjs-live .vjs-live-display {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Live Display
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
.vjs-default-skin .vjs-live-display {
|
||||
display: none;
|
||||
font-size: 1em;
|
||||
line-height: 3em;
|
||||
}
|
||||
|
||||
/* Time Display
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
@ -798,6 +827,26 @@ body.vjs-full-window {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* In IE8 w/ no JavaScript (no HTML5 shim), the video tag doesn't register.
|
||||
The .video-js classname on the video tag also isn't considered.
|
||||
This optional paragraph inside the video tag can provide a message to users
|
||||
about what's required to play video. */
|
||||
.vjs-no-js {
|
||||
padding: 20px;
|
||||
color: #ccc;
|
||||
background-color: #333;
|
||||
font-size: 18px;
|
||||
font-family: Arial, sans-serif;
|
||||
text-align: center;
|
||||
width: 300px;
|
||||
height: 150px;
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
.vjs-no-js a, .vjs-no-js a:visited {
|
||||
color: #F4A460;
|
||||
}
|
||||
|
||||
// MIXINS
|
||||
// =============================================================================
|
||||
// Mixins are a LESS feature and are used to add vendor prefixes to CSS rules
|
||||
|
@ -439,37 +439,62 @@ vjs.Component.prototype.removeChild = function(component){
|
||||
* myChildOption: true
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Or when creating the component
|
||||
* var myComp = new MyComponent(player, {
|
||||
* children: {
|
||||
* myChildComponent: {
|
||||
* myChildOption: true
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* The children option can also be an Array of child names or
|
||||
* child options objects (that also include a 'name' key).
|
||||
*
|
||||
* var myComp = new MyComponent(player, {
|
||||
* children: [
|
||||
* 'button',
|
||||
* {
|
||||
* name: 'button',
|
||||
* someOtherOption: true
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
*/
|
||||
vjs.Component.prototype.initChildren = function(){
|
||||
var options = this.options_;
|
||||
var parent, children, child, name, opts;
|
||||
|
||||
if (options && options['children']) {
|
||||
var self = this;
|
||||
parent = this;
|
||||
children = this.options()['children'];
|
||||
|
||||
// Loop through components and add them to the player
|
||||
vjs.each(options['children'], function(name, opts){
|
||||
//Support for a simpler setup, children with no options
|
||||
if (typeof name == 'number') {
|
||||
name = opts;
|
||||
opts = {};
|
||||
if (children) {
|
||||
// Allow for an array of children details to passed in the options
|
||||
if (children instanceof Array) {
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
child = children[i];
|
||||
|
||||
if (typeof child == 'string') {
|
||||
name = child;
|
||||
opts = {};
|
||||
} else {
|
||||
name = child.name;
|
||||
opts = child;
|
||||
}
|
||||
|
||||
parent[name] = parent.addChild(name, opts);
|
||||
}
|
||||
} else {
|
||||
vjs.obj.each(children, function(name, opts){
|
||||
// Allow for disabling default components
|
||||
// e.g. vjs.options['children']['posterImage'] = false
|
||||
if (opts === false) return;
|
||||
|
||||
// Allow for disabling default components
|
||||
// e.g. vjs.options['children']['posterImage'] = false
|
||||
if (opts === false) return;
|
||||
|
||||
// Allow waiting to add components until a specific event is called
|
||||
var tempAdd = function(){
|
||||
// Set property name on player. Could cause conflicts with other prop names, but it's worth making refs easy.
|
||||
self[name] = self.addChild(name, opts);
|
||||
};
|
||||
|
||||
if (opts['loadEvent']) {
|
||||
// this.one(opts.loadEvent, tempAdd)
|
||||
} else {
|
||||
tempAdd();
|
||||
}
|
||||
});
|
||||
parent[name] = parent.addChild(name, opts);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -16,6 +16,7 @@ vjs.ControlBar.prototype.options_ = {
|
||||
'timeDivider': {},
|
||||
'durationDisplay': {},
|
||||
'remainingTimeDisplay': {},
|
||||
'liveDisplay': {},
|
||||
'progressControl': {},
|
||||
'fullscreenToggle': {},
|
||||
'volumeControl': {},
|
||||
|
28
src/js/control-bar/live-display.js
Normal file
28
src/js/control-bar/live-display.js
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Displays the live indicator
|
||||
* TODO - Future make it click to snap to live
|
||||
* @param {vjs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
vjs.LiveDisplay = vjs.Component.extend({
|
||||
init: function(player, options){
|
||||
vjs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
vjs.LiveDisplay.prototype.createEl = function(){
|
||||
var el = vjs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-live-controls vjs-control'
|
||||
});
|
||||
|
||||
this.contentEl_ = vjs.createEl('div', {
|
||||
className: 'vjs-live-display',
|
||||
innerHTML: '<span class="vjs-control-text">Stream Type </span>LIVE',
|
||||
'aria-live': 'off'
|
||||
});
|
||||
|
||||
el.appendChild(this.contentEl_);
|
||||
|
||||
return el;
|
||||
};
|
@ -49,7 +49,6 @@ vjs.VolumeBar = vjs.Slider.extend({
|
||||
vjs.Slider.call(this, player, options);
|
||||
player.on('volumechange', vjs.bind(this, this.updateARIAAttributes));
|
||||
player.ready(vjs.bind(this, this.updateARIAAttributes));
|
||||
setTimeout(vjs.bind(this, this.update), 0); // update when elements is in DOM
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -206,9 +206,11 @@ vjs.fixEvent = function(event) {
|
||||
}
|
||||
event.returnValue = false;
|
||||
event.isDefaultPrevented = returnTrue;
|
||||
event.defaultPrevented = true;
|
||||
};
|
||||
|
||||
event.isDefaultPrevented = returnFalse;
|
||||
event.defaultPrevented = false;
|
||||
|
||||
// Stop the event from bubbling
|
||||
event.stopPropagation = function () {
|
||||
@ -293,7 +295,7 @@ vjs.trigger = function(elem, event) {
|
||||
vjs.trigger(parent, event);
|
||||
|
||||
// If at the top of the DOM, triggers the default action unless disabled.
|
||||
} else if (!parent && !event.isDefaultPrevented()) {
|
||||
} else if (!parent && !event.defaultPrevented) {
|
||||
var targetData = vjs.getData(event.target);
|
||||
|
||||
// Checks if the target has a default action for this event.
|
||||
@ -310,7 +312,7 @@ vjs.trigger = function(elem, event) {
|
||||
}
|
||||
|
||||
// Inform the triggerer if the default was prevented by returning false
|
||||
return !event.isDefaultPrevented();
|
||||
return !event.defaultPrevented;
|
||||
/* Original version of js ninja events wasn't complete.
|
||||
* We've since updated to the latest version, but keeping this around
|
||||
* for now just in case.
|
||||
|
@ -84,6 +84,7 @@ goog.exportSymbol('videojs.CurrentTimeDisplay', vjs.CurrentTimeDisplay);
|
||||
goog.exportSymbol('videojs.DurationDisplay', vjs.DurationDisplay);
|
||||
goog.exportSymbol('videojs.TimeDivider', vjs.TimeDivider);
|
||||
goog.exportSymbol('videojs.RemainingTimeDisplay', vjs.RemainingTimeDisplay);
|
||||
goog.exportSymbol('videojs.LiveDisplay', vjs.LiveDisplay);
|
||||
goog.exportSymbol('videojs.Slider', vjs.Slider);
|
||||
goog.exportSymbol('videojs.ProgressControl', vjs.ProgressControl);
|
||||
goog.exportSymbol('videojs.SeekBar', vjs.SeekBar);
|
||||
@ -121,6 +122,8 @@ goog.exportSymbol('videojs.Html5', vjs.Html5);
|
||||
goog.exportProperty(vjs.Html5, 'Events', vjs.Html5.Events);
|
||||
goog.exportProperty(vjs.Html5, 'isSupported', vjs.Html5.isSupported);
|
||||
goog.exportProperty(vjs.Html5, 'canPlaySource', vjs.Html5.canPlaySource);
|
||||
goog.exportProperty(vjs.Html5, 'patchCanPlayType', vjs.Html5.patchCanPlayType);
|
||||
goog.exportProperty(vjs.Html5, 'unpatchCanPlayType', vjs.Html5.unpatchCanPlayType);
|
||||
|
||||
// Export non-standard HTML5 video API methods.
|
||||
// Standard method names already protected by default externs.
|
||||
|
@ -44,26 +44,6 @@ vjs.capitalize = function(string){
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Loop through an array, an array of objects, or each property
|
||||
* in an object and call a function whose arguments are (key,value)
|
||||
* @param {Object} arrLike Object of properties
|
||||
* @param {Function} fn Function to be called on each property.
|
||||
* @this {*}
|
||||
* @private
|
||||
*/
|
||||
vjs.each = function (arrLike, fn, context) {
|
||||
if (vjs.obj.isPlain(arrLike)) vjs.obj.each(arrLike, fn, context);
|
||||
else {
|
||||
for (var i = 0, len = arrLike.length; i < len; ++i) {
|
||||
var val = arrLike[i];
|
||||
|
||||
if (vjs.obj.isPlain(val)) vjs.obj.each(val, fn, context);
|
||||
else fn.call(context || this, i, val);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Object functions container
|
||||
* @type {Object}
|
||||
@ -713,8 +693,9 @@ vjs.findPosition = function(el) {
|
||||
scrollTop = window.pageYOffset || body.scrollTop;
|
||||
top = box.top + scrollTop - clientTop;
|
||||
|
||||
// Android sometimes returns slightly off decimal values, so need to round
|
||||
return {
|
||||
left: left,
|
||||
top: top
|
||||
left: vjs.round(left),
|
||||
top: vjs.round(top)
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -284,8 +284,8 @@ vjs.Flash.prototype.currentSrc = function(){
|
||||
var src = this.el_.vjs_getProperty('currentSrc');
|
||||
// no src, check and see if RTMP
|
||||
if (src == null) {
|
||||
var connection = this.rtmpConnection(),
|
||||
stream = this.rtmpStream();
|
||||
var connection = this['rtmpConnection'](),
|
||||
stream = this['rtmpStream']();
|
||||
|
||||
if (connection && stream) {
|
||||
src = vjs.Flash.streamFromParts(connection, stream);
|
||||
|
@ -266,6 +266,53 @@ vjs.Html5.canControlVolume = function(){
|
||||
return volume !== vjs.TEST_VID.volume;
|
||||
};
|
||||
|
||||
// HTML5 Feature detection and Device Fixes --------------------------------- //
|
||||
(function() {
|
||||
var canPlayType,
|
||||
mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i,
|
||||
mp4RE = /^video\/mp4/i;
|
||||
|
||||
vjs.Html5.patchCanPlayType = function() {
|
||||
// Android 4.0 and above can play HLS to some extent but it reports being unable to do so
|
||||
if (vjs.ANDROID_VERSION >= 4.0) {
|
||||
if (!canPlayType) {
|
||||
canPlayType = vjs.TEST_VID.constructor.prototype.canPlayType;
|
||||
}
|
||||
|
||||
vjs.TEST_VID.constructor.prototype.canPlayType = function(type) {
|
||||
if (type && mpegurlRE.test(type)) {
|
||||
return 'maybe';
|
||||
}
|
||||
return canPlayType.call(this, type);
|
||||
};
|
||||
}
|
||||
|
||||
// Override Android 2.2 and less canPlayType method which is broken
|
||||
if (vjs.IS_OLD_ANDROID) {
|
||||
if (!canPlayType) {
|
||||
canPlayType = vjs.TEST_VID.constructor.prototype.canPlayType;
|
||||
}
|
||||
|
||||
vjs.TEST_VID.constructor.prototype.canPlayType = function(type){
|
||||
if (type && mp4RE.test(type)) {
|
||||
return 'maybe';
|
||||
}
|
||||
return canPlayType.call(this, type);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
vjs.Html5.unpatchCanPlayType = function() {
|
||||
var r = vjs.TEST_VID.constructor.prototype.canPlayType;
|
||||
vjs.TEST_VID.constructor.prototype.canPlayType = canPlayType;
|
||||
canPlayType = null;
|
||||
return r;
|
||||
};
|
||||
|
||||
// by default, patch the video element
|
||||
vjs.Html5.patchCanPlayType();
|
||||
})();
|
||||
|
||||
// List of all HTML5 events (various uses).
|
||||
vjs.Html5.Events = 'loadstart,suspend,abort,error,emptied,stalled,loadedmetadata,loadeddata,canplay,canplaythrough,playing,waiting,seeking,seeked,ended,durationchange,timeupdate,progress,play,pause,ratechange,volumechange'.split(',');
|
||||
|
||||
@ -300,12 +347,3 @@ vjs.Html5.disposeMediaElement = function(el){
|
||||
})();
|
||||
}
|
||||
};
|
||||
|
||||
// HTML5 Feature detection and Device Fixes --------------------------------- //
|
||||
|
||||
// Override Android 2.2 and less canPlayType method which is broken
|
||||
if (vjs.IS_OLD_ANDROID) {
|
||||
document.createElement('video').constructor.prototype.canPlayType = function(type){
|
||||
return (type && type.toLowerCase().indexOf('video/mp4') != -1) ? 'maybe' : '';
|
||||
};
|
||||
}
|
||||
|
@ -129,9 +129,9 @@ vjs.MenuButton.prototype.createMenu = function(){
|
||||
|
||||
// Add a title list item to the top
|
||||
if (this.options().title) {
|
||||
menu.el().appendChild(vjs.createEl('li', {
|
||||
menu.contentEl().appendChild(vjs.createEl('li', {
|
||||
className: 'vjs-menu-title',
|
||||
innerHTML: vjs.capitalize(this.kind_),
|
||||
innerHTML: vjs.capitalize(this.options().title),
|
||||
tabindex: -1
|
||||
}));
|
||||
}
|
||||
|
109
src/js/player.js
109
src/js/player.js
@ -77,20 +77,7 @@ vjs.Player = vjs.Component.extend({
|
||||
// this.addClass('vjs-touch-enabled');
|
||||
// }
|
||||
|
||||
// Firstplay event implimentation. Not sold on the event yet.
|
||||
// Could probably just check currentTime==0?
|
||||
this.one('play', function(e){
|
||||
var fpEvent = { type: 'firstplay', target: this.el_ };
|
||||
// Using vjs.trigger so we can check if default was prevented
|
||||
var keepGoing = vjs.trigger(this.el_, fpEvent);
|
||||
|
||||
if (!keepGoing) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
|
||||
this.on('loadstart', this.onLoadStart);
|
||||
this.on('ended', this.onEnded);
|
||||
this.on('play', this.onPlay);
|
||||
this.on('firstplay', this.onFirstPlay);
|
||||
@ -335,14 +322,16 @@ vjs.Player.prototype.manualProgressOn = function(){
|
||||
// In HTML5, some older versions don't support the progress event
|
||||
// So we're assuming they don't, and turning off manual progress if they do.
|
||||
// As opposed to doing user agent detection
|
||||
this.tech.one('progress', function(){
|
||||
if (this.tech) {
|
||||
this.tech.one('progress', function(){
|
||||
|
||||
// Update known progress support for this playback technology
|
||||
this.features['progressEvents'] = true;
|
||||
// Update known progress support for this playback technology
|
||||
this.features['progressEvents'] = true;
|
||||
|
||||
// Turn off manual progress tracking
|
||||
this.player_.manualProgressOff();
|
||||
});
|
||||
// Turn off manual progress tracking
|
||||
this.player_.manualProgressOff();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
vjs.Player.prototype.manualProgressOff = function(){
|
||||
@ -375,12 +364,14 @@ vjs.Player.prototype.manualTimeUpdatesOn = function(){
|
||||
// timeupdate is also called by .currentTime whenever current time is set
|
||||
|
||||
// Watch for native timeupdate event
|
||||
this.tech.one('timeupdate', function(){
|
||||
// Update known progress support for this playback technology
|
||||
this.features['timeupdateEvents'] = true;
|
||||
// Turn off manual progress tracking
|
||||
this.player_.manualTimeUpdatesOff();
|
||||
});
|
||||
if (this.tech) {
|
||||
this.tech.one('timeupdate', function(){
|
||||
// Update known progress support for this playback technology
|
||||
this.features['timeupdateEvents'] = true;
|
||||
// Turn off manual progress tracking
|
||||
this.player_.manualTimeUpdatesOff();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
vjs.Player.prototype.manualTimeUpdatesOff = function(){
|
||||
@ -398,8 +389,13 @@ vjs.Player.prototype.trackCurrentTime = function(){
|
||||
};
|
||||
|
||||
// Turn off play progress tracking (when paused or dragging)
|
||||
vjs.Player.prototype.stopTrackingCurrentTime = function(){ clearInterval(this.currentTimeInterval); };
|
||||
vjs.Player.prototype.stopTrackingCurrentTime = function(){
|
||||
clearInterval(this.currentTimeInterval);
|
||||
|
||||
// #1002 - if the video ends right before the next timeupdate would happen,
|
||||
// the progress bar won't make it all the way to the end
|
||||
this.trigger('timeupdate');
|
||||
};
|
||||
// /* Player event handlers (how the player reacts to certain events)
|
||||
// ================================================================================ */
|
||||
|
||||
@ -407,7 +403,27 @@ vjs.Player.prototype.stopTrackingCurrentTime = function(){ clearInterval(this.cu
|
||||
* Fired when the user agent begins looking for media data
|
||||
* @event loadstart
|
||||
*/
|
||||
vjs.Player.prototype.onLoadStart;
|
||||
vjs.Player.prototype.onLoadStart = function() {
|
||||
// remove any first play listeners that weren't triggered from a previous video.
|
||||
this.off('play', initFirstPlay);
|
||||
this.one('play', initFirstPlay);
|
||||
|
||||
vjs.removeClass(this.el_, 'vjs-has-started');
|
||||
};
|
||||
|
||||
// Need to create this outside the scope of onLoadStart so it
|
||||
// can be added and removed (to avoid piling first play listeners).
|
||||
function initFirstPlay(e) {
|
||||
var fpEvent = { type: 'firstplay', target: this.el_ };
|
||||
// Using vjs.trigger so we can check if default was prevented
|
||||
var keepGoing = vjs.trigger(this.el_, fpEvent);
|
||||
|
||||
if (!keepGoing) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the player has initial duration and dimension information
|
||||
@ -505,7 +521,16 @@ vjs.Player.prototype.onDurationChange = function(){
|
||||
// accidentally cause the stack to blow up.
|
||||
var duration = this.techGet('duration');
|
||||
if (duration) {
|
||||
if (duration < 0) {
|
||||
duration = Infinity;
|
||||
}
|
||||
this.duration(duration);
|
||||
// Determine if the stream is live and propagate styles down to UI.
|
||||
if (duration === Infinity) {
|
||||
this.addClass('vjs-live');
|
||||
} else {
|
||||
this.removeClass('vjs-live');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1298,13 +1323,23 @@ vjs.Player.prototype.userActive = function(bool){
|
||||
};
|
||||
|
||||
vjs.Player.prototype.listenForUserActivity = function(){
|
||||
var onMouseActivity, onMouseDown, mouseInProgress, onMouseUp,
|
||||
activityCheck, inactivityTimeout;
|
||||
var onActivity, onMouseMove, onMouseDown, mouseInProgress, onMouseUp,
|
||||
activityCheck, inactivityTimeout, lastMoveX, lastMoveY;
|
||||
|
||||
onMouseActivity = vjs.bind(this, this.reportUserActivity);
|
||||
onActivity = vjs.bind(this, this.reportUserActivity);
|
||||
|
||||
onMouseMove = function(e) {
|
||||
// #1068 - Prevent mousemove spamming
|
||||
// Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=366970
|
||||
if(e.screenX != lastMoveX || e.screenY != lastMoveY) {
|
||||
lastMoveX = e.screenX;
|
||||
lastMoveY = e.screenY;
|
||||
onActivity();
|
||||
}
|
||||
};
|
||||
|
||||
onMouseDown = function() {
|
||||
onMouseActivity();
|
||||
onActivity();
|
||||
// For as long as the they are touching the device or have their mouse down,
|
||||
// we consider them active even if they're not moving their finger or mouse.
|
||||
// So we want to continue to update that they are active
|
||||
@ -1312,24 +1347,24 @@ vjs.Player.prototype.listenForUserActivity = function(){
|
||||
// Setting userActivity=true now and setting the interval to the same time
|
||||
// as the activityCheck interval (250) should ensure we never miss the
|
||||
// next activityCheck
|
||||
mouseInProgress = setInterval(onMouseActivity, 250);
|
||||
mouseInProgress = setInterval(onActivity, 250);
|
||||
};
|
||||
|
||||
onMouseUp = function(event) {
|
||||
onMouseActivity();
|
||||
onActivity();
|
||||
// Stop the interval that maintains activity if the mouse/touch is down
|
||||
clearInterval(mouseInProgress);
|
||||
};
|
||||
|
||||
// Any mouse movement will be considered user activity
|
||||
this.on('mousedown', onMouseDown);
|
||||
this.on('mousemove', onMouseActivity);
|
||||
this.on('mousemove', onMouseMove);
|
||||
this.on('mouseup', onMouseUp);
|
||||
|
||||
// Listen for keyboard navigation
|
||||
// Shouldn't need to use inProgress interval because of key repeat
|
||||
this.on('keydown', onMouseActivity);
|
||||
this.on('keyup', onMouseActivity);
|
||||
this.on('keydown', onActivity);
|
||||
this.on('keyup', onActivity);
|
||||
|
||||
// Run an interval every 250 milliseconds instead of stuffing everything into
|
||||
// the mousemove/touchmove function itself, to prevent performance degradation.
|
||||
|
@ -16,8 +16,6 @@ vjs.Slider = vjs.Component.extend({
|
||||
this.bar = this.getChild(this.options_['barName']);
|
||||
this.handle = this.getChild(this.options_['handleName']);
|
||||
|
||||
player.on(this.playerEvent, vjs.bind(this, this.update));
|
||||
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
this.on('touchstart', this.onMouseDown);
|
||||
this.on('focus', this.onFocus);
|
||||
@ -26,10 +24,7 @@ vjs.Slider = vjs.Component.extend({
|
||||
|
||||
this.player_.on('controlsvisible', vjs.bind(this, this.update));
|
||||
|
||||
// This is actually to fix the volume handle position. http://twitter.com/#!/gerritvanaaken/status/159046254519787520
|
||||
// this.player_.one('timeupdate', vjs.bind(this, this.update));
|
||||
|
||||
player.ready(vjs.bind(this, this.update));
|
||||
player.on(this.playerEvent, vjs.bind(this, this.update));
|
||||
|
||||
this.boundEvents = {};
|
||||
}
|
||||
|
@ -948,7 +948,7 @@ vjs.ChaptersButton.prototype.createMenu = function(){
|
||||
|
||||
var menu = this.menu = new vjs.Menu(this.player_);
|
||||
|
||||
menu.el_.appendChild(vjs.createEl('li', {
|
||||
menu.contentEl().appendChild(vjs.createEl('li', {
|
||||
className: 'vjs-menu-title',
|
||||
innerHTML: vjs.capitalize(this.kind_),
|
||||
tabindex: -1
|
||||
|
@ -33,7 +33,9 @@
|
||||
'test/unit/poster.js',
|
||||
'test/unit/plugins.js',
|
||||
'test/unit/flash.js',
|
||||
'test/unit/api.js'
|
||||
'test/unit/api.js',
|
||||
'test/unit/menu.js',
|
||||
'test/unit/tracks.js'
|
||||
];
|
||||
|
||||
var projectRoot = '../';
|
||||
|
@ -91,6 +91,12 @@ test('should be able to access expected MediaTech API methods', function() {
|
||||
ok(techProto.setPoster, 'setPoster should exist on the Media tech');
|
||||
ok(html5Proto.setPoster, 'setPoster should exist on the HTML5 tech');
|
||||
ok(flashProto.setPoster, 'setPoster should exist on the Flash tech');
|
||||
|
||||
ok(videojs.Html5.patchCanPlayType, 'patchCanPlayType should exist for HTML5');
|
||||
ok(videojs.Html5.unpatchCanPlayType, 'unpatchCanPlayType should exist for HTML5');
|
||||
|
||||
ok(videojs.Html5.canPlaySource, 'canPlaySource should exist for HTML5');
|
||||
ok(videojs.Flash.canPlaySource, 'canPlaySource should exist for Flash');
|
||||
});
|
||||
|
||||
test('should export ready api call to public', function() {
|
||||
|
@ -53,9 +53,9 @@ test('should init child components from simple children array', function(){
|
||||
test('should init child components from children array of objects', function(){
|
||||
var comp = new vjs.Component(getFakePlayer(), {
|
||||
children: [
|
||||
{'component':{}},
|
||||
{'component':{}},
|
||||
{'component':{}}
|
||||
{ 'name': 'component' },
|
||||
{ 'name': 'component' },
|
||||
{ 'name': 'component' }
|
||||
]
|
||||
});
|
||||
|
||||
|
@ -114,3 +114,20 @@ test('should bubble up DOM unless bubbles == false', function(){
|
||||
});
|
||||
vjs.trigger(inner, { type:'nobub', target:inner, bubbles:false });
|
||||
});
|
||||
|
||||
test('should have a defaultPrevented property on an event that was prevent from doing default action', function() {
|
||||
expect(2);
|
||||
|
||||
var el = document.createElement('div');
|
||||
|
||||
vjs.on(el, 'test', function(e){
|
||||
ok(true, 'First listener fired');
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
vjs.on(el, 'test', function(e){
|
||||
ok(e.defaultPrevented, 'Should have `defaultPrevented` to signify preventDefault being called');
|
||||
});
|
||||
|
||||
vjs.trigger(el, 'test');
|
||||
});
|
||||
|
@ -22,47 +22,13 @@ test('should loop through each property on an object', function(){
|
||||
};
|
||||
|
||||
// Add 3 to each value
|
||||
vjs.each(asdf, function(key, value){
|
||||
vjs.obj.each(asdf, function(key, value){
|
||||
asdf[key] = value + 3;
|
||||
});
|
||||
|
||||
deepEqual(asdf,{a:4,b:5,'c':6});
|
||||
});
|
||||
|
||||
test('should loop through simple array', function(){
|
||||
var asdf = [
|
||||
'a',
|
||||
'b',
|
||||
'c'
|
||||
];
|
||||
|
||||
var newArr = [];
|
||||
vjs.each(asdf, function(key, value){
|
||||
newArr[key] = value;
|
||||
ok(typeof key == 'number', 'Key is not a number, the array index');
|
||||
ok(typeof value == 'string', 'Value is not a string');
|
||||
});
|
||||
|
||||
deepEqual(asdf,newArr);
|
||||
});
|
||||
|
||||
test('should loop through an array of objects', function(){
|
||||
var asdf = [
|
||||
{ a: {} },
|
||||
{ b: {} },
|
||||
{ 'c': {} }
|
||||
];
|
||||
|
||||
var newObj = {};
|
||||
vjs.each(asdf, function(key, value){
|
||||
newObj[key] = value;
|
||||
ok(typeof key == 'string', 'Key is not a string');
|
||||
ok(vjs.obj.isPlain(value), 'Value is not an object');
|
||||
});
|
||||
|
||||
deepEqual(newObj, { a: {}, b: {}, 'c': {}});
|
||||
});
|
||||
|
||||
test('should copy an object', function(){
|
||||
var asdf = {
|
||||
a: 1,
|
||||
|
@ -38,3 +38,57 @@ test('should re-link the player if the tech is moved', function(){
|
||||
|
||||
strictEqual(player, tech.el()['player']);
|
||||
});
|
||||
|
||||
test('patchCanPlayType patches canplaytype with our function, conditionally', function() {
|
||||
// the patch runs automatically so we need to first unpatch
|
||||
vjs.Html5.unpatchCanPlayType();
|
||||
|
||||
var oldAV = vjs.ANDROID_VERSION,
|
||||
video = document.createElement('video'),
|
||||
canPlayType = vjs.TEST_VID.constructor.prototype.canPlayType,
|
||||
patchedCanPlayType,
|
||||
unpatchedCanPlayType;
|
||||
|
||||
vjs.ANDROID_VERSION = 4.0;
|
||||
vjs.Html5.patchCanPlayType();
|
||||
|
||||
notStrictEqual(video.canPlayType, canPlayType, 'original canPlayType and patched canPlayType should not be equal');
|
||||
|
||||
patchedCanPlayType = video.canPlayType;
|
||||
unpatchedCanPlayType = vjs.Html5.unpatchCanPlayType();
|
||||
|
||||
strictEqual(canPlayType, vjs.TEST_VID.constructor.prototype.canPlayType, 'original canPlayType and unpatched canPlayType should be equal');
|
||||
strictEqual(patchedCanPlayType, unpatchedCanPlayType, 'patched canPlayType and function returned from unpatch are equal');
|
||||
|
||||
vjs.ANDROID_VERSION = oldAV;
|
||||
vjs.Html5.unpatchCanPlayType();
|
||||
});
|
||||
|
||||
test('should return maybe for HLS urls on Android 4.0 or above', function() {
|
||||
var oldAV = vjs.ANDROID_VERSION,
|
||||
video = document.createElement('video');
|
||||
|
||||
vjs.ANDROID_VERSION = 4.0;
|
||||
vjs.Html5.patchCanPlayType();
|
||||
|
||||
strictEqual(video.canPlayType('application/x-mpegurl'), 'maybe', 'android version 4.0 or above should be a maybe for x-mpegurl');
|
||||
strictEqual(video.canPlayType('application/x-mpegURL'), 'maybe', 'android version 4.0 or above should be a maybe for x-mpegURL');
|
||||
strictEqual(video.canPlayType('application/vnd.apple.mpegurl'), 'maybe', 'android version 4.0 or above should be a maybe for vnd.apple.mpegurl');
|
||||
strictEqual(video.canPlayType('application/vnd.apple.mpegURL'), 'maybe', 'android version 4.0 or above should be a maybe for vnd.apple.mpegurl');
|
||||
|
||||
vjs.ANDROID_VERSION = oldAV;
|
||||
vjs.Html5.unpatchCanPlayType();
|
||||
});
|
||||
|
||||
test('should return a maybe for mp4 on OLD ANDROID', function() {
|
||||
var isOldAndroid = vjs.IS_OLD_ANDROID,
|
||||
video = document.createElement('video');
|
||||
|
||||
vjs.IS_OLD_ANDROID = true;
|
||||
vjs.Html5.patchCanPlayType();
|
||||
|
||||
strictEqual(video.canPlayType('video/mp4'), 'maybe', 'old android should return a maybe for video/mp4');
|
||||
|
||||
vjs.IS_OLD_ANDROID = isOldAndroid;
|
||||
vjs.Html5.unpatchCanPlayType();
|
||||
});
|
||||
|
18
test/unit/menu.js
Normal file
18
test/unit/menu.js
Normal file
@ -0,0 +1,18 @@
|
||||
module('MenuButton');
|
||||
|
||||
test('should place title list item into ul', function() {
|
||||
var player, menuButton;
|
||||
|
||||
player = PlayerTest.makePlayer();
|
||||
|
||||
menuButton = new vjs.MenuButton(player, {
|
||||
'title': 'testTitle'
|
||||
});
|
||||
|
||||
var menuContentElement = menuButton.el().getElementsByTagName('UL')[0];
|
||||
var titleElement = menuContentElement.children[0];
|
||||
|
||||
ok(titleElement.innerHTML === 'TestTitle', 'title element placed in ul');
|
||||
|
||||
player.dispose();
|
||||
});
|
@ -357,15 +357,6 @@ test('should use custom message when encountering an unsupported video type',
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
test('should return the player when setting src', function() {
|
||||
var player, ret;
|
||||
|
||||
player = PlayerTest.makePlayer({}),
|
||||
ret = player.src('foo');
|
||||
|
||||
equal(player, ret, 'the player is returned');
|
||||
});
|
||||
|
||||
test('should register players with generated ids', function(){
|
||||
var fixture, video, player, id;
|
||||
fixture = document.getElementById('qunit-fixture');
|
||||
@ -380,3 +371,34 @@ test('should register players with generated ids', function(){
|
||||
equal(player.el().id, player.id(), 'the player and element ids are equal');
|
||||
ok(vjs.players[id], 'the generated id is registered');
|
||||
});
|
||||
|
||||
test('should not add multiple first play events despite subsequent loads', function() {
|
||||
expect(1);
|
||||
|
||||
var player = PlayerTest.makePlayer({});
|
||||
|
||||
player.on('firstplay', function(){
|
||||
ok('First play should fire once.');
|
||||
});
|
||||
|
||||
// Checking to make sure onLoadStart removes first play listener before adding a new one.
|
||||
player.trigger('loadstart');
|
||||
player.trigger('loadstart');
|
||||
player.trigger('play');
|
||||
});
|
||||
|
||||
test('should remove vjs-has-started class', function(){
|
||||
expect(3);
|
||||
|
||||
var player = PlayerTest.makePlayer({});
|
||||
|
||||
player.trigger('loadstart');
|
||||
player.trigger('play');
|
||||
ok(player.el().className.indexOf('vjs-has-started') !== -1, 'vjs-has-started class added');
|
||||
|
||||
player.trigger('loadstart');
|
||||
ok(player.el().className.indexOf('vjs-has-started') === -1, 'vjs-has-started class removed');
|
||||
|
||||
player.trigger('play');
|
||||
ok(player.el().className.indexOf('vjs-has-started') !== -1, 'vjs-has-started class added again');
|
||||
});
|
||||
|
16
test/unit/tracks.js
Normal file
16
test/unit/tracks.js
Normal file
@ -0,0 +1,16 @@
|
||||
module('Tracks');
|
||||
|
||||
test('should place title list item into ul', function() {
|
||||
var player, chaptersButton;
|
||||
|
||||
player = PlayerTest.makePlayer();
|
||||
|
||||
chaptersButton = new vjs.ChaptersButton(player);
|
||||
|
||||
var menuContentElement = chaptersButton.el().getElementsByTagName('UL')[0];
|
||||
var titleElement = menuContentElement.children[0];
|
||||
|
||||
ok(titleElement.innerHTML === 'Chapters', 'title element placed in ul');
|
||||
|
||||
player.dispose();
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user