Skip to content

Commit

Permalink
feat: Add getPlayer method to Video.js. (#4836)
Browse files Browse the repository at this point in the history
  • Loading branch information
misteroneill authored and gkatsev committed Jan 30, 2018
1 parent dcab42e commit a15e616
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 45 deletions.
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

0 comments on commit a15e616

Please sign in to comment.