Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add getPlayer method to Video.js. #4836

Merged
merged 3 commits into from
Jan 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/guides/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,28 @@ However, using an `id` attribute isn't always practical; so, the `videojs` funct
videojs(document.querySelector('.video-js'));
```

### Getting References to Players

Once players are created, Video.js keeps track of them internally. There are a few ways to get references to pre-existing players.

#### Using `videojs`

Calling `videojs()` with the ID of element of an already-existing player will return that player and will not create another one.

If there is no player matching the argument, it will attempt to create one.

#### Using `videojs.getPlayer()`

Sometimes, you want to get a reference to a player without the potential side effects of calling `videojs()`. This can be acheived by calling `videojs.getPlayer()` with either a string matching the element's ID or the element itself.

#### Using `videojs.getPlayers()` or `videojs.players`

The `videojs.players` property exposes all known players. The method, `videojs.getPlayers()` simply returns the same object.

Players are stored on this object with keys matching their IDs.

> **Note:** A player created from an element without an ID will be assigned an automatically-generated ID.

## Options

> **Note:** This guide only covers how to pass options during player setup. For a complete reference on _all_ available options, see the [options guide](/docs/guides/options.md).
Expand Down
105 changes: 60 additions & 45 deletions src/js/video.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ if (typeof HTMLVideoElement === 'undefined' && Dom.isReal()) {
document.createElement('video-js');
}

/**
* Normalize an `id` value by trimming off a leading `#`
*
* @param {string} id
* A string, maybe with a leading `#`.
*
* @returns {string}
* The string, without any leading `#`.
*/
const normalizeId = (id) => id.indexOf('#') === 0 ? id.slice(1) : id;

/**
* Doubles as the main function for users to create a player instance and also
* the main library object.
Expand All @@ -59,62 +70,32 @@ if (typeof HTMLVideoElement === 'undefined' && Dom.isReal()) {
* A player instance
*/
function videojs(id, options, ready) {
let tag;
let player = videojs.getPlayer(id);

// Allow for element or ID to be passed in
// String ID
if (typeof id === 'string') {
const players = videojs.getPlayers();

// Adjust for jQuery ID syntax
if (id.indexOf('#') === 0) {
id = id.slice(1);
if (player) {
if (options) {
log.warn(`Player "${id}" is already initialised. Options will not be applied.`);
}

// If a player instance has already been created for this ID return it.
if (players[id]) {

// If options or ready function are passed, warn
if (options) {
log.warn(`Player "${id}" is already initialised. Options will not be applied.`);
}

if (ready) {
players[id].ready(ready);
}

return players[id];
if (ready) {
player.ready(ready);
}

// Otherwise get element for ID
tag = Dom.$('#' + id);

// ID is a media element
} else {
tag = id;
return player;
}

// Check for a useable element
// re: nodeName, could be a box div also
if (!tag || !tag.nodeName) {
throw new TypeError('The element or ID supplied is not valid. (videojs)');
}
const el = (typeof id === 'string') ? Dom.$('#' + normalizeId(id)) : id;

// Element may have a player attr referring to an already created player instance.
// If so return that otherwise set up a new player below
if (tag.player || Player.players[tag.playerId]) {
return tag.player || Player.players[tag.playerId];
if (!Dom.isEl(el)) {
throw new TypeError('The element or ID supplied is not valid. (videojs)');
}

// Check if element is included in the DOM
if (Dom.isEl(tag) && !document.body.contains(tag)) {
if (!document.body.contains(el)) {
log.warn('The element supplied is not included in the DOM');
}

options = options || {};

videojs.hooks('beforesetup').forEach(function(hookFunction) {
const opts = hookFunction(tag, mergeOptions(options));
videojs.hooks('beforesetup').forEach((hookFunction) => {
const opts = hookFunction(el, mergeOptions(options));

if (!isObject(opts) || Array.isArray(opts)) {
log.error('please return an object in beforesetup hooks');
Expand All @@ -124,9 +105,11 @@ function videojs(id, options, ready) {
options = mergeOptions(options, opts);
});

// We get the current "Player" component here in case an integration has
// replaced it with a custom player.
const PlayerComponent = Component.getComponent('Player');
// If not, set up a new player
const player = new PlayerComponent(tag, options, ready);

player = new PlayerComponent(el, options, ready);

videojs.hooks('setup').forEach((hookFunction) => hookFunction(player));

Expand Down Expand Up @@ -270,6 +253,38 @@ videojs.options = Player.prototype.options_;
*/
videojs.getPlayers = () => Player.players;

/**
* Get a single player based on an ID or DOM element.
*
* This is useful if you want to check if an element or ID has an associated
* Video.js player, but not create one if it doesn't.
*
* @param {string|Element} id
* An HTML element - `<video>`, `<audio>`, or `<video-js>` -
* or a string matching the `id` of such an element.
*
* @returns {Player|undefined}
* A player instance or `undefined` if there is no player instance
* matching the argument.
*/
videojs.getPlayer = (id) => {
const players = Player.players;

if (typeof id === 'string') {
return players[normalizeId(id)];
}

if (Dom.isEl(id)) {
const {player, playerId} = id;

// Element may have a `player` property referring to an already created
// player instance. If so, return that.
if (player || players[playerId]) {
return player || players[playerId];
}
}
};

/**
* Expose players object.
*
Expand Down
17 changes: 17 additions & 0 deletions test/unit/video.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,23 @@ QUnit.test('should create a new tag for movingMediaElementInDOM', function(asser
Html5.nativeSourceHandler.canPlayType = oldCPT;
});

QUnit.test('getPlayer', function(assert) {
const fixture = document.getElementById('qunit-fixture');

fixture.innerHTML += '<video-js id="test_vid_id"></video-js>';

assert.notOk(videojs.getPlayer('test_vid_id'), 'no player was created yet');

const tag = document.querySelector('#test_vid_id');
const player = videojs(tag);

assert.strictEqual(videojs.getPlayer('#test_vid_id'), player, 'the player was returned when using a jQuery-style ID selector');
assert.strictEqual(videojs.getPlayer('test_vid_id'), player, 'the player was returned when using a raw ID value');
assert.strictEqual(videojs.getPlayer(tag), player, 'the player was returned when using the original tag/element');

player.dispose();
});

/* **************************************************** *
* div embed tests copied from video emebed tests above *
* **************************************************** */
Expand Down