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

Change codes of recently-added errors and allow type and code to be shared. #96

Merged
merged 5 commits into from
May 15, 2017
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
48 changes: 41 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,18 @@ Once you've initialized Video.js, you can activate the errors plugin. The plugin

Additionally, some custom errors have been added as reference for future extension.

- MEDIA_ERR_UNKNOWN (value `'unknown'`)
- PLAYER_ERR_NO_SRC (numeric value `-1`)
- PLAYER_ERR_TIMEOUT (numeric value `-2`)
- PLAYER_ERR_DOMAIN_RESTRICTED (numeric value `-3`)
- PLAYER_ERR_IP_RESTRICTED (numeric value `-4`)
- PLAYER_ERR_GEO_RESTRICTED (numeric value `-5`)
- PLAYER_ERR_DOMAIN_RESTRICTED
- PLAYER_ERR_IP_RESTRICTED
- PLAYER_ERR_GEO_RESTRICTED

**Note:**

- Custom errors should reference a code value of a negative integer.
- Custom errors should reference a type beginning with `PLAYER_ERR` versus the standardized `MEDIA_ERR` to avoid confusion.
- Custom errors should reference a code value of a string.
- Two of the provided errors use negative numbers for historical reasons, but alpha-numeric/descriptive strings are less likely to cause collision issues.
- Custom errors should have a `type` beginning with `PLAYER_ERR_` versus the standardized `MEDIA_ERR` to avoid confusion.
- Custom errors can be chosen to be dismissible (boolean value `true`)

If the video element emits any of those errors, the corresponding error message will be displayed. You can override and add custom error codes by supplying options to the plugin:
Expand Down Expand Up @@ -95,19 +97,51 @@ player.errors.extend({
},
foo: {
headline: 'My custom "foo" error',
message: 'A custom "foo" error message.'
message: 'A custom "foo" error message.',
type: 'PLAYER_ERR_FOO'
}
});
```

If you define custom error messages, you'll need to let Video.js know when to emit them yourself:

```js
player.error({code: 'custom', dismiss: true});
player.error({code: 'foo', dismiss: true});
```

If an error is emitted that doesn't have an associated key, a generic, catch-all message is displayed. You can override that text by supplying a message for the key `unknown`.

### Custom Errors without a Type

As of v2.0.0, custom errors can be defined without a code. In these cases, the key provided will be used as the code. For example, the custom `foo` error above could be:

```js
player.errors.extend({
PLAYER_ERR_FOO: {
headline: 'My custom "foo" error',
message: 'A custom "foo" error message.'
}
});
```

The difference here being that one would then trigger it via:

```js
player.error({code: 'PLAYER_ERR_FOO'});
```

### `getAll()`

After the errors plugin has been initialized on a player, a `getAll()` method is available on the `errors()` plugin method. This function returns an object with all the errors the plugin currently understands:

```js
player.errors();

var errors = player.errors.getAll();

console.log(errors['1'].type); // "MEDIA_ERR_ABORTED"
```

## Known Issues

On iPhones, default errors are not dismissible. The video element intercepts all user interaction so error message dialogs miss the tap events. If your video is busted anyways, you may not be that upset about this.
8 changes: 4 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
<head>
<meta charset="utf-8">
<title>videojs-errors Demo</title>
<link href="/node_modules/video.js/dist/video-js.css" rel="stylesheet">
<link href="/dist/browser/videojs-errors.css" rel="stylesheet">
<script src="/node_modules/video.js/dist/video.js"></script>
<script src="/dist/browser/videojs-errors.js"></script>
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet">
<link href="dist/videojs-errors.css" rel="stylesheet">
<script src="node_modules/video.js/dist/video.js"></script>
<script src="dist/videojs-errors.js"></script>
<style>
body {
font-family: Arial, sans-serif;
Expand Down
48 changes: 30 additions & 18 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,30 +51,38 @@ const defaults = {
type: 'PLAYER_ERR_TIMEOUT',
headline: 'Could not download the video'
},
'-3': {
type: 'PLAYER_ERR_DOMAIN_RESTRICTED',
'PLAYER_ERR_DOMAIN_RESTRICTED': {
headline: 'This video is restricted from playing on your current domain'
},
'-4': {
type: 'PLAYER_ERR_IP_RESTRICTED',
'PLAYER_ERR_IP_RESTRICTED': {
headline: 'This video is restricted at your current IP address'
},
'-5': {
type: 'PLAYER_ERR_GEO_RESTRICTED',
'PLAYER_ERR_GEO_RESTRICTED': {
headline: 'This video is restricted from playing in your current geographic region'
}
}
};

/**
* Monitors a player for signs of life during playback and
* triggers PLAYER_ERR_TIMEOUT if none occur within a reasonable
* timeframe.
*/
const initPlugin = function(player, options) {
let monitor;
const listeners = [];

const updateErrors = function(updates) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do the default errors get passed in here during init?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but they should. Good catch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want to add a test to make sure that happens.

options.errors = videojs.mergeOptions(options.errors, updates);

// Create `code`s from errors which don't have them (based on their keys).
Object.keys(options.errors).forEach(k => {
const err = options.errors[k];

if (!err.type) {
err.type = k;
}
});
};

// Make sure we flesh out initially-provided errors.
updateErrors();

// clears the previous monitor timeout and sets up a new one
const resetMonitor = function() {
window.clearTimeout(monitor);
Expand Down Expand Up @@ -197,7 +205,9 @@ const initPlugin = function(player, options) {
}

if (error.code === 4 && FlashObj && !FlashObj.isSupported()) {
const flashMessage = player.localize('If you are using an older browser please try upgrading or installing Flash.');
const flashMessage = player.localize(
'If you are using an older browser please try upgrading or installing Flash.'
);

details += `<span class="vjs-errors-flashmessage">${flashMessage}</span>`;
}
Expand Down Expand Up @@ -258,9 +268,8 @@ const initPlugin = function(player, options) {
initPlugin(player, videojs.mergeOptions(defaults, newOptions));
};

reInitPlugin.extend = function(errors) {
options.errors = videojs.mergeOptions(options.errors, errors);
};
reInitPlugin.extend = (errors) => updateErrors(errors);
reInitPlugin.getAll = () => videojs.mergeOptions(options.errors);

reInitPlugin.disableProgress = function(disabled) {
options.progressDisabled = disabled;
Expand All @@ -279,13 +288,16 @@ const initPlugin = function(player, options) {
player.errors = reInitPlugin;
};

/**
* Initialize the plugin. Waits until the player is ready to do anything.
*/
const errors = function(options) {
initPlugin(this, videojs.mergeOptions(defaults, options));
};

['extend', 'getAll', 'disableProgress'].forEach(k => {
errors[k] = function() {
videojs.log.warn(`The errors.${k}() method is not available until the plugin has been initialized!`);
};
});

// Register the plugin with video.js.
registerPlugin('errors', errors);

Expand Down
79 changes: 79 additions & 0 deletions test/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,3 +508,82 @@ QUnit.test('custom errors can be added at runtime', function(assert) {
'message should match custom override value'
);
});

QUnit.test('custom errors can be defined without a type at init time', function(assert) {
const error = {
TEST: {
headline: 'test',
message: 'test test'
}
};

this.player.errors({errors: error});

// tick forward enough to ready the player
this.clock.tick(1);

this.player.error({code: 'TEST'});

assert.strictEqual(
this.player.errorDisplay.$('.vjs-errors-headline').textContent,
error.TEST.headline,
'headline should match custom override value'
);

assert.strictEqual(
this.player.errorDisplay.$('.vjs-errors-message').textContent,
error.TEST.message,
'message should match custom override value'
);
});

QUnit.test('custom errors can be defined without a type at init time', function(assert) {
const error = {
TEST: {
headline: 'test',
message: 'test test'
}
};

this.player.errors();

// tick forward enough to ready the player
this.clock.tick(1);

this.player.errors.extend(error);
this.player.error({code: 'TEST'});

assert.strictEqual(
this.player.errorDisplay.$('.vjs-errors-headline').textContent,
error.TEST.headline,
'headline should match custom override value'
);

assert.strictEqual(
this.player.errorDisplay.$('.vjs-errors-message').textContent,
error.TEST.message,
'message should match custom override value'
);
});

QUnit.test('getAll()', function(assert) {
this.player.errors();

let errors = this.player.errors.getAll();

assert.strictEqual(errors['1'].type, 'MEDIA_ERR_ABORTED');
assert.strictEqual(errors['2'].type, 'MEDIA_ERR_NETWORK');

this.player.errors.extend({
TEST: {
headline: 'test',
message: 'test test'
}
});

errors = this.player.errors.getAll();

assert.strictEqual(errors['1'].type, 'MEDIA_ERR_ABORTED');
assert.strictEqual(errors['2'].type, 'MEDIA_ERR_NETWORK');
assert.strictEqual(errors.TEST.type, 'TEST');
});