The option for the player techCanOverridePoster is introduced in this commit. It allows techs to update the post whenever they like. isPosterFromTech_ is introduced as a private player field in order to track when a poster was set by a tech. This allows us to clear the poster whenever the tech is disposed of by the player.
Additionally, attempting to set the same poster more than once will have no effect / no changes will be made, since the poster is the same. This was done in order to stop triggering multiple posterchange events when calling player.poster(aPoster) with techCanOverridePoster set to true.
When a tech is disposed and a poster was set by it, unset the poster.
Pass a `canOverridePoster` option to techs to know whether techCanOverridePoster was set.
Fixes#4910.
Trigger a sourceset event whenever the source is set in the Html5 tech, including initial source. We override the video element's src and setAttribute methods so that we can trigger the sourceset event when people change the src with both the video element and our API methods.
The event object for sourceset will contain the src string that was provided at the time the sourceset was triggered. This is mostly important if a source is being set while a tech is changing.
A Tech has a featuresSourceset option that it can set to for sourceset handling. It can then call the helper triggerSourceset(src) to trigger the sourceset.
If a user disabled the text track setting component, trying to play emulated captions would crash. Add a null check before applying the text track settings.
Fixes#4964.
This is a first in a few changes related to #4902. This just adds a text alternative to the loading spinner. In future PRs, we would make it alert to screen readers and potentially have a generic alerting mechanism.
Scrubbing inside the seekbar paused the player properly but scrubbing inside the progress control outside the seekbar, the player never paused. This meant that when you scrubbed, if you kept the mouse down but lingered for a moment, the player would continue playing until the mouse moved again.
This fixes it so that the seekbar mousedown and mouseup handlers are called when the progress control mousedown and mouseup handlers are triggered.
Middleware factories currently get run each time a source is set. Because middleware are assocated with a player, the factories should only run once per player.
This PR fixes it so that we associate a middleware instance with a middleware factory per player.
Each time a player is disposed, we will clear the cache of the middleware instances for that player.
Fixes#4677.
These changes address an issue where screen readers may repeatedly and redundantly read TextTrackMenuItem's control text on every texttrackchange event in some browsers.
The source of the problem is in the handleTracksChange() method of TextTrackMenuItem and its subclass OffTextTrackMenuItem, in which this.selected(true/false) gets called even if the selected state has not changed since its previous invocation.
Use ResizeObserver when available for better and more performant resizing information, otherwise, fall back to a throttled resize event on an iframe that's the size of the player.
Allows a video.js user to disable this by setting resizeManager: false as an option since the component will not be initialized.
Add a debounce util.
This reverts #4800 (e0ed0b5) because we end up getting two playerresize events with the dimension methods now.
This will allow middleware to interact with calls to play() from the tech. This will require a method of indicating to middleware previously run that a middleware down the chain has terminated or stopped execution.
* Adds middleware mediator method that runs middleware from the player to the tech and a second time back up to the player. This category was created because play is both a setter(changes the playback state) and a getter(gets a native play promise if available). This also has the ability to tell whether a middleware has terminated before reaching the tech.
* Adds a middleware.TERMINATOR sentinel value that is available on the videojs object
* Adds play to the allowedMediators
* Adds paused to the allowedGetters
* Adds a sandbox example of a play mediator middleware
Chrome has started pausing autoplaying video elements when they are
moved in the DOM. Here we need to make sure that if the video started
autoplaying, after we move the element in the DOM we call play again.
Fixes#4720.
If the HTML element doesn't have a lang attribute, Edge throws an exception when calling closest.getAttribute because tag.closest('[lang]') returns an empty object (which will be coerced to true) instead of null.
Uses the new Dom.isSingleLeftClick method to do the check we were doing previously.
Also, refactor the player.handleTechClick_() method to follow the new style of code.
Fixes#4689
If the player is paused, when we seek, the time displays don't update. So, we trigger a timeupdate manually to let components know that the time has updated.
The core goal here is to make sure the following works in light of some middleware process that makes setting the source more async than next tick:
```js
player.src('...');
player.ready(() => player.play());
```
In fact, given this change, we should even be able to do:
```js
player.src('...');
player.play();
```
Unlike #4665, which would have clarified/changed the meaning of "ready", it remains a reflection of the tech's state and we make better use of the ability to queue things on that state and on the middleware `setSource` process.
Previously, any mouse button interaction with the bars would cause a reaction but that's unexpected for right and middle mouse clicks. This PR makes it so right and middle mouse clicks are ignored for dragging and clicking.
A we retained a lot of references to DOM elements in various components. Here we clear it up. Also, make sure that we remove unused listeners as they can retain objects as well.
Update evented mixin to null out the eventBusEl_ after the component is disposed.
Add a feature for components, to tell it not to auto-initialize the evented mixin.
Re-enable the tests that were removed in #4640.
Add the ability to initialize Video.js with an element named video-js. This is because sometimes, seeing the native element is undesirable, plus, it's cool to have our own element.
Can be used just like the video embed.
IE9 is supported but only with dynamic sources as the source element can only be used inside of the video element.
Right now the durationchange event is throttled with the other two events, timeupdate and loadedmetadata. This means that only one of those events will trigger an update if they all occur within 25ms of each other.
This functionality makes sense for timeupdate or loadedmetadata as those should not indicate a time update (even though they often do).
For durationchange however it will always indicate a change in the duration, and we want to always update the display when it happens. Here is a scenario of how we could show duration incorrectly right now:
User is playing a video that has a postroll ad at the end. After the postroll ad their will be a timeupdate, and then a durationchange to signify that we are back in content. Then ended will fire, and no more events will happen.
The player will still show the duration of the ad, as the durationchange was eaten by the timeupdate that happened at nearly the same time.
Also, fix a potential issue where if the page was translated using google translate, the time displays stopped updating.
The aria-labelledby attribute on the fontPercent, edgeStyle, and
fontFamily select options inlcudes an extra space since there is
no ledgendId variable being set on the createElFont_() method. This
fix adds a check to see if the legendId value is set or not inside
the createElSelect_() method. This should keep the extra space
from appearing on the select tags created by the createElFont_()
method.
Fixes#4688
Add `enable` and `disable` methods to the progress control. This disabled things like the mouse time display and the progress control continues updating for current time and loading but the user will not be able to interact with the control anymore.
If Object.prototype was modified to have extra properties, the `off` method crashed because `data.handlers` would've been removed before getting to the extra property.
Also, this fixes an issue where if a falsey value was passed to off, the events system would remove all the events, i.e. `player.off('')`. Instead, we make sure that only if it is called as `player.off()` will they be removed.
When setting the source, we were calling `play` if `autoplay` was set. We shouldn't do that and instead we should rely on the browser or tech (like Flash) to handle it properly.
Make boolean attributes like muted set the property video.muted = {{boolean}} and the attribute video.setAttribute('muted', 'muted') when changing the value.
Also, in html5's createEl, we were setting/updating attributes for various properties but we were only setting the attributes and not also the properties but also autoplay was happening first rather than last which caused autoplay to fail because muted and playsinline weren't necessary set by that time.
Fix#4351.
In 6.0, we changed the way that Menu Buttons were being created by
wrapping an actual button with a menu sibling in a container. The
playback rate menu also had a rate value display. In 6.x, this rate
value display ended up coming on top of the button itself and capturing
it's clicks. So, we want to remove pointer-events from the rate-value
display and resize the actual button to be the size of the control.
We added a feature so that remote text tracks can auto-removed when a source changes. However, in 6.x we changed the source behavior to be asynchronous meaning that some text tracks were accidentally being removed when they weren't supposed to be.
For example:
```js
var player = videojs('my-player');
player.src({src: 'video.mp4', type: 'video/mp4'});
// set second arg to false so that they get auto-removed on source change
player.addRemoteTextTrack({kind: 'captions', src: 'text.vtt', srclang: 'en'}, false);
```
Now when the player loads, this captions track is actually missing because it was removed.
Instead of adding auto-removal tracks immediately to the list, wait until we've selected a source before adding them in.
Fixes#4403 and #4315.
player.duration() currently returns 0 if the duration is not known, when it should return NaN. The problem is that if NaN is passed to player.duration() as an argument, we set the duration to 0. If player.cache_.duration was set to NaN by other means, player.duration() would still return 0.
Modify the player duration() method so that it will 1.) set the cached duration to NaN if it is passed in as an argument, and 2.) return the proper value when called without an argument.
When picture-in-picture mode is entered on Safari, `webkitbeginfullscreen` is triggered which results in a proxied `fullscreenchange` event and adding the fullscreen class to the player. That causes the tech element to collapse to zero height so that the "this video is playing in picture in picture" placeholder is not visible.
On `webkitbeginfullscreen` check whether the presentation mode is `picture-in-picture` before proxying `fullscreenchange` event.
These are a few performance improvements.
* Use textContent instead of innerHTML for text content.
* Construct TextTrackSettings content with HTML strings where possible because it's a bit faster than manual DOM construction.
* Do minimal DOM updates to time controls. This reduces our timeupdate footprint from ~2-2.5ms to ~1ms!
Video.js players can accept a number of standard <video> element options (autoplay, muted, loop, etc), but not currently playsinline, which is now part of the [HTML spec](https://html.spec.whatwg.org/multipage/embedded-content.html#attr-video-playsinline). We should add it to the list of <video> attributes that can be provided to the player as options.
On Safari and iOS, we use native text tracks, so, during text track
button creation, textTracks() is populated. However, `this.kinds_` isn't
necessarily set and ends up throwing.
Instead, we want to move the fallback for `this.kinds_` from the
constructor and right above the usage of `this.kinds_`.
Prevent ClickableComponents re-adding event listeners each time enabled() is called.
* Keeps track of enabled state (this.enabled_)
* enable() doesn't do anything if the component is enabled, so the event handlers are not re-added
Fixes#4312
This adds a beforepluginsetup event as well as beforepluginsetup:$name and pluginsetup:$name events.
The drive behind this is improving the ability for people to make cross-plugin dependencies in a more robust manner.
Android Chrome now supports playbackRate properly, so removes the blacklist added in #3246 for newer Chrome versions.
Adds `browser.CHROME_VERSION` as a necessary evil.
No longer blacklists for Chrome 58+ -- this could possibly be fixed since 52, but 58 is all I've been able to test on and most users should keep Chrome up to date.
In the new middleware work, the way that new sources were loaded was refactored. We also recently made techs and components work either TitleCased or camelcased. There was one comparison that didn't do the proper check and cause the tech to be reloaded, even if the two techs were the same.
This allows default tracks or tracks with a `mode`of `showing` to be seen
when they are added (as we would expect). Rather than only being seen
after the first `modechange` event (aka a selection from the menu). This is done by watching for `loadstart` on Player.
Currently, the behavior of time tooltips is inconsistent across iOS and Android devices so we want to hide the tooltips on mobile devices for the time being.
The issue is that in Flash, Flash.embed wraps the object element in a div but that object element is what is referenced by this.el(), so, parentNode isn't null but we aren't actually in the DOM. Instead, just check to see whether the tech element is in the DOM or not via node.contains().
This fixes a logging in the console regarding timetooltips which don't exist. Also, makes sure not to focus the menu button when the captions settings menu item is clicked since the caption settings is getting focused instead. In addition, it makes sure the legend text in the track settings is the foreground color.
In addition, the track buttons need to update on the ready event because when the tech loads, it could run with support native captions, so, it needs to know whether to include the captions settings menu.
And all tracks should always be included in player.textTracks() and not just player.remoteTextTracks().
Implement a `hideThreshold` property that defaults to 1 so
descendants can override it if necessary. Right now the only
descendant that will override will be `CaptionsButton` because
video.js adds a "captions settings" for emulated text tracks.
Move the CC icon in the SubsCapsMenuItem into an icon-placeholder span. Also, include that information for the screen reader.
In addition, only apply default sizing to icon-placeholder if they're direct descendants of a vjs-control.
In #4034, we changed the way that menu buttons work slightly by introduction a wrapper element with a separate wrapper css builder. However, this broke, at least the playback-rate menu.
This PR adds a buildWrapperCSSClass to each of our menu buttons.
Previously timeupdate would fire before the video was playing, and the tech was not ready. This caused issues when preload was set to auto, because cuechange would fire before the video was even started for cues with a startTime of 0.
Wait for tech to be ready before watching for timeupdate
update unit tests to use TechFaker
Add a unit test to verify that we wait for Tech to be ready.
Update videojs-vtt.js and don't auto-export its versions of VTTCue globally.
When our TextTrack object is given a cue, if it's a native cue, wrap it in our emulated vttjs.VTTCue.
Fixes#4093.
It allows you to use string as an key for the language files but have a default value that's different. In this case, we have a key of progress bar timing: currentTime={1} duration={2} which is used so that we have a descriptive key to what is happening. The default value matches that default value in en.json: {1} of {2}. The reason for the default value is so that the translation uses {1} of {2} for the actual localization without requiring en.json to be included in videojs by default.
Fix#4024.
This fixes a lot of the issues from #2746 by making the dialog inherit from our actual ModalDialog which now has tab focus trapping.
The Captions Settings dialog has some accessibility issues:
- Field labels and fields are not explicitly associated
- Keyboard focus does not move into the dialog when it is opened
- Keyboard focus is not trapped inside the dialog while it is open
- Keyboard focus does not return to the control which opened the dialog when it is closed
- The extent (top and bottom) of the dialog is not indicated to screen readers
- The dialog cannot be closed with the Esc key
- The meaning of '---' in the select fields is not clear
- The control to close the dialog is labeled "Done" rather than "Close"
- The purpose of the "Defaults" button may not be obvious, and its effect may not be apparent to screen reader users
- Focus highlighting (outline) on the Default and Done buttons is *very* hard to see
- Pressing the Done button doesn’t seem to have the same effect as pressing the Close (x) button; does it trigger the same focus movement
- This requirement to move it back to the triggering element is tricky, since clicking on that item in the CC menu dismisses the CC menu. I need to think about this a little more - either the menu should open again, or the focus should go to the main CC Menu Button
- The focus outline on the whole dialog goes too far to the left (all the way to the edge of the video window, not just to the edge of the dialog)
Fixes#2746.
Currently, the ARIA value of VolumeBar tracks the value of volume. It should instead track the position of the slider on VolumeBar, which tracks volume except when the player is muted, in which case it's 0.
Fixes#4064.
If the modal dialog was opened and the focus was preset inside the
player, move the focus to the modal dialog.
When the modal dialog is closed, move the focus back to the previously
active element.
When focus is inside the dialog, trap tab focus. This was inspired by https://github.com/gdkraus/accessible-modal-dialog and ally.js.
Fix the structure of elements in menus so that actionable elements are not children of actionable elements, as required by ARIA.
Remove unnecessary aria-labels on menus.
If the control bar and playtoggle exist, focus the playtoggle after
triggering play via the keyboard from the Big Play Button.
If the control bar isn't available, then focus the player element.
If play() returns a promise, wait until it resolves to focus,
otherwise, use a setTimeout.
Fixes#2729
Prevents a title attribute from being applied to MenuItems.
MenuItem indicates to ClickableComponent that the control is not just an icon, so it shouldn't have a title attribute.
Fixes#3699
* Fixes#3986
* update `techOptions` to look for `TitleCase`/`camelCase` user tech options
* remove deprecated usage of Tech as Component
* add a unit test to verify that registerTech works
* change defaultTech_ to defaultTechOrder_
If a user changed the volume to zero either via the mouse or keyboard, clicking unmute will now restore the volume back to this last position. Previously, the mute and volume values were completely not linked.
Fixes#3909.
If the time tooltips try to update when the player isn't in the DOM,
they error out because the bounding rects for the player will not be available.
This does a null check and exists early.
If you try to delegate an to an EventTarget from an evented component, you'll end up failing because it didn't think that an EventTarget object worked. But it should and does. This adds a check for it in the isEvented function.
Middleware registration now only accept a factory method which takes a player reference and returns some object that represents the middleware with the various methods on it.
Also, add a use to register a middleware for all types.
Advanced plugins introduced the concept of mixins and added two: evented and stateful.
This provides Components with the benefits of the stateful mixin
Advanced plugins introduced the concept of mixins and added two: evented and stateful.
This refactors Component to use the evented mixin, granting it event broadcast/handling capabilities.
Add middleware support. Middleware can function as go-between between the player and the tech. For example, it can modify the duration that the tech returns to the player. In addition, middleware allow for supporting custom video sources and types.
Currently, middleware can only intercept timeline methods like duration, currentTime, and setCurrentTime.
For example,
```js
videojs.use('video/foo', {
setSource(src, next) {
next(null, {
src: 'http://example.com/video.mp4',
type: 'video/mp4'
});
}
});
```
Will allow you to set a source with type `video/foo` which will play back `video.mp4`.
This makes setting the source asynchronous, which aligns it with the spec a bit more. Methods like play can still be called synchronously on the player after setting the source and the player will play once the source has loaded.
`sourceOrder` option was removed as well and it will now always use source ordering.
BREAKING CHANGE: setting the source is now asynchronous. `sourceOrder` option removed and made the default.
Internally uses the VolumeControl and MuteToggle components to create the VolumePanel component. Acts like the old VolumeMenuButton but does not have the screen reader issues of the older version.
BREAKING CHANGE: remove VolumeMenuButton, introduce a new default volume control: VolumePanel.
Switch to `keepTooltipsInside` by default and simplify DOM structure around the time tooltips and progress control.
BREAKING CHANGE: removal of `keepTooltipsInside` option.
* Switch to es3 preset for babel so that it runs last. Plugins run before presets and presets run in reverse order. Also, we ran into a weird bug in babel that causes `default` not to be quoted in some cases (https://github.com/babel/babel/issues/4799) which we've worked around here.
* Restore the es-shims for tests and the ie8 fallback script.
* Do a null-check around `Player.players`.
* use more round fractions (like 0.5 and 1) to avoid rounding issues.
Remove method chaining from videojs. This helps keep the methods consistent especially since play() now returns a Promise in some cases. Also, it can add some performance benefits.
BREAKING CHANGE: player methods no longer return a player instance when called. Fixes#3704.
Return the native Promise from `play()` if it exists. `undefined` is returned otherwise.
This comes in as part of the greater effort to remove method chaining.
BREAKING CHANGE: `play()` no longer returns the player object but instead the native Promise or nothing.
Restore all outlines on components that are focusable to increase accessibility of these components.
BREAKING CHANGE: restoring the outlines changes the skin slightly and potentially break users. Fixes#3200.
Prevent techs (and others) from being registered via registerComponent.
* `registerComponent` now throws if given an object that is not a subclass of Component (or Component itself).
* `registerComponent` now throws if given a non-empty string as its name argument.
BREAKING CHANGE: registerComponent now throws if no name or not a component is passed in.