1
0
mirror of https://github.com/videojs/video.js.git synced 2024-12-25 02:42:10 +02:00

@dmlap switched global options back to an object at videojs.options. closes #2461

This commit is contained in:
David LaPalomento 2015-08-12 13:51:43 -07:00 committed by heff
parent 4fd59c89db
commit fecf3a0f8a
7 changed files with 121 additions and 157 deletions

View File

@ -93,6 +93,7 @@ CHANGELOG
* @misteroneill pass vtt.js option to tech ([view](https://github.com/videojs/video.js/pull/2448))
* @forbesjo updated the sauce labs config and browser versions ([view](https://github.com/videojs/video.js/pull/2450))
* @mmcc made sure controls respect muted attribute ([view](https://github.com/videojs/video.js/pull/2408))
* @dmlap switched global options back to an object at videojs.options ([view](https://github.com/videojs/video.js/pull/2461))
--------------------

View File

@ -1,54 +0,0 @@
/**
* @file global-options.js
*/
import document from 'global/document';
import window from 'global/window';
let navigator = window.navigator;
/*
* Global Player instance options, surfaced from Player.prototype.options_
* options = Player.prototype.options_
* All options should use string keys so they avoid
* renaming by closure compiler
*
* @type {Object}
*/
export default {
// Default order of fallback technology
'techOrder': ['html5','flash'],
// techOrder: ['flash','html5'],
'html5': {},
'flash': {},
// defaultVolume: 0.85,
'defaultVolume': 0.00, // The freakin seaguls are driving me crazy!
// default inactivity timeout
'inactivityTimeout': 2000,
// default playback rates
'playbackRates': [],
// Add playback rate selection by adding rates
// 'playbackRates': [0.5, 1, 1.5, 2],
// Included control sets
'children': {
'mediaLoader': {},
'posterImage': {},
'textTrackDisplay': {},
'loadingSpinner': {},
'bigPlayButton': {},
'controlBar': {},
'errorDisplay': {},
'textTrackSettings': {}
},
'language': document.getElementsByTagName('html')[0].getAttribute('lang') || navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language || 'en',
// locales and their language translations
'languages': {},
// Default message to show when a video cannot be played.
'notSupportedMessage': 'No compatible source was found for this video.'
};

View File

@ -17,7 +17,6 @@ import { createTimeRange } from './utils/time-ranges.js';
import { bufferedPercent } from './utils/buffer.js';
import FullscreenApi from './fullscreen-api.js';
import MediaError from './media-error.js';
import globalOptions from './global-options.js';
import safeParseTuple from 'safe-json-parse/tuple';
import assign from 'object.assign';
import mergeOptions from './utils/merge-options.js';
@ -91,7 +90,6 @@ class Player extends Component {
// Run base component initializing with new options
super(null, options, ready);
// if the global option object was accidentally blown away by
// someone, bail early with an informative error
if (!this.options_ ||
@ -108,7 +106,7 @@ class Player extends Component {
this.tagAttributes = tag && Dom.getElAttributes(tag);
// Update current language
this.language(options.language || globalOptions.language);
this.language(this.options_.language);
// Update Supported Languages
if (options.languages) {
@ -120,7 +118,7 @@ class Player extends Component {
});
this.languages_ = languagesToLower;
} else {
this.languages_ = globalOptions.languages;
this.languages_ = Player.prototype.options_.languages;
}
// Cache for video property values.
@ -151,7 +149,7 @@ class Player extends Component {
// as well so they don't need to reach back into the player for options later.
// We also need to do another copy of this.options_ so we don't end up with
// an infinite loop.
let playerOptionsCopy = mergeOptions({}, this.options_);
let playerOptionsCopy = mergeOptions(this.options_);
// Load plugins
if (options.plugins) {
@ -2403,7 +2401,7 @@ class Player extends Component {
* @method languages
*/
languages() {
return mergeOptions(globalOptions.languages, this.languages_);
return mergeOptions(Player.prototype.options_.languages, this.languages_);
}
/**
@ -2488,17 +2486,54 @@ class Player extends Component {
*/
Player.players = {};
let navigator = window.navigator;
/*
* Player instance options, surfaced using options
* options = Player.prototype.options_
* Make changes in options, not here.
* All options should use string keys so they avoid
* renaming by closure compiler
*
* @type {Object}
* @private
*/
Player.prototype.options_ = globalOptions;
Player.prototype.options_ = {
// Default order of fallback technology
techOrder: ['html5','flash'],
// techOrder: ['flash','html5'],
html5: {},
flash: {},
// defaultVolume: 0.85,
defaultVolume: 0.00, // The freakin seaguls are driving me crazy!
// default inactivity timeout
inactivityTimeout: 2000,
// default playback rates
playbackRates: [],
// Add playback rate selection by adding rates
// 'playbackRates': [0.5, 1, 1.5, 2],
// Included control sets
children: {
mediaLoader: {},
posterImage: {},
textTrackDisplay: {},
loadingSpinner: {},
bigPlayButton: {},
controlBar: {},
errorDisplay: {},
textTrackSettings: {}
},
language: document.getElementsByTagName('html')[0].getAttribute('lang') || navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language || 'en',
// locales and their language translations
languages: {},
// Default message to show when a video cannot be played.
notSupportedMessage: 'No compatible source was found for this video.'
};
/**
* Fired when the player has initial duration and dimension information

View File

@ -11,38 +11,50 @@ function isPlain(obj) {
}
/**
* Merge two options objects, recursively merging **only* * plain object
* properties. Previously `deepMerge`.
* Merge customizer. video.js simply overwrites non-simple objects
* (like arrays) instead of attempting to overlay them.
* @see https://lodash.com/docs#merge
*/
const customizer = function(destination, source) {
// If we're not working with a plain object, copy the value as is
// If source is an array, for instance, it will replace destination
if (!isPlain(source)) {
return source;
}
// If the new value is a plain object but the first object value is not
// we need to create a new object for the first object to merge with.
// This makes it consistent with how merge() works by default
// and also protects from later changes the to first object affecting
// the second object's values.
if (!isPlain(destination)) {
return mergeOptions(source);
}
};
/**
* Merge one or more options objects, recursively merging **only**
* plain object properties. Previously `deepMerge`.
*
* @param {Object} object The destination object
* @param {...Object} source One or more objects to merge into the first
* @returns {Object} The updated first object
* @param {...Object} source One or more objects to merge
* @returns {Object} a new object that is the union of all
* provided objects
* @function mergeOptions
*/
export default function mergeOptions(object={}) {
export default function mergeOptions() {
// contruct the call dynamically to handle the variable number of
// objects to merge
let args = Array.prototype.slice.call(arguments);
// Allow for infinite additional object args to merge
Array.prototype.slice.call(arguments, 1).forEach(function(source){
// unshift an empty object into the front of the call as the target
// of the merge
args.unshift({});
// Recursively merge only plain objects
// All other values will be directly copied
merge(object, source, function(a, b) {
// customize conflict resolution to match our historical merge behavior
args.push(customizer);
// If we're not working with a plain object, copy the value as is
if (!isPlain(b)) {
return b;
}
merge.apply(null, args);
// If the new value is a plain object but the first object value is not
// we need to create a new object for the first object to merge with.
// This makes it consistent with how merge() works by default
// and also protects from later changes the to first object affecting
// the second object's values.
if (!isPlain(a)) {
return mergeOptions({}, b);
}
});
});
return object;
// return the mutated result object
return args[0];
}

View File

@ -5,7 +5,6 @@ import document from 'global/document';
import * as setup from './setup';
import Component from './component';
import EventTarget from './event-target';
import globalOptions from './global-options.js';
import Player from './player';
import plugin from './plugins.js';
import mergeOptions from '../../src/js/utils/merge-options.js';
@ -62,7 +61,7 @@ var videojs = function(id, options, ready){
}
// If a player instance has already been created for this ID return it.
if (Player.players[id]) {
if (videojs.getPlayers()[id]) {
// If options or ready funtion are passed, warn
if (options) {
@ -70,10 +69,10 @@ var videojs = function(id, options, ready){
}
if (ready) {
Player.players[id].ready(ready);
videojs.getPlayers()[id].ready(ready);
}
return Player.players[id];
return videojs.getPlayers()[id];
// Otherwise get element for ID
} else {
@ -107,44 +106,17 @@ setup.autoSetupTimeout(1, videojs);
videojs.VERSION = '__VERSION__';
/**
* Get the global options object
* The global options object. These are the settings that take effect
* if no overrides are specified when the player is created.
*
* @return {Object} The global options object
* @mixes videojs
* @method getGlobalOptions
*/
videojs.getGlobalOptions = () => globalOptions;
/**
* For backward compatibility, expose global options.
*
* @deprecated
* @memberOf videojs
* @property {Object|Proxy} options
*/
videojs.options = createDeprecationProxy(globalOptions, {
get: 'Access to videojs.options is deprecated; use videojs.getGlobalOptions instead',
set: 'Modification of videojs.options is deprecated; use videojs.setGlobalOptions instead'
});
/**
* Set options that will apply to every player
* ```js
* videojs.setGlobalOptions({
* autoplay: true
* });
* videojs.options.autoplay = true
* // -> all players will autoplay by default
* ```
* NOTE: This will do a deep merge with the new options,
* not overwrite the entire global options object.
*
* @return {Object} The updated global options object
* @mixes videojs
* @method setGlobalOptions
* @type {Object}
*/
videojs.setGlobalOptions = function(newOptions) {
return mergeOptions(globalOptions, newOptions);
};
videojs.options = Player.prototype.options_;
/**
* Get an object with the currently created players, keyed by player ID
@ -377,7 +349,7 @@ videojs.plugin = plugin;
*/
videojs.addLanguage = function(code, data){
code = ('' + code).toLowerCase();
return merge(globalOptions.languages, { [code]: data })[code];
return merge(videojs.options.languages, { [code]: data })[code];
};
/**

View File

@ -1,6 +1,5 @@
import Player from '../../src/js/player.js';
import videojs from '../../src/js/video.js';
import globalOptions from '../../src/js/global-options.js';
import * as Dom from '../../src/js/utils/dom.js';
import * as browser from '../../src/js/utils/browser.js';
import log from '../../src/js/utils/log.js';
@ -58,36 +57,36 @@ test('should create player instance that inherits from component and dispose it'
ok(player.el() === null, 'element disposed');
});
// technically, all uses of videojs.options should be replaced with
// Player.prototype.options_ in this file and a equivalent test using
// videojs.options should be made in video.test.js. Keeping this here
// until we make that move.
test('should accept options from multiple sources and override in correct order', function(){
// For closure compiler to work, all reference to the prop have to be the same type
// As in options['attr'] or options.attr. Compiler will minimize each separately.
// Since we're using setAttribute which requires a string, we have to use the string
// version of the key for all version.
// Set a global option
globalOptions['attr'] = 1;
videojs.options.attr = 1;
var tag0 = TestHelpers.makeTag();
var player0 = new Player(tag0);
let tag0 = TestHelpers.makeTag();
let player0 = new Player(tag0);
ok(player0.options_['attr'] === 1, 'global option was set');
equal(player0.options_.attr, 1, 'global option was set');
player0.dispose();
// Set a tag level option
var tag1 = TestHelpers.makeTag();
tag1.setAttribute('attr', 'asdf'); // Attributes must be set as strings
let tag2 = TestHelpers.makeTag();
tag2.setAttribute('attr', 'asdf'); // Attributes must be set as strings
var player1 = new Player(tag1);
ok(player1.options_['attr'] === 'asdf', 'Tag options overrode global options');
player1.dispose();
let player2 = new Player(tag2);
equal(player2.options_.attr, 'asdf', 'Tag options overrode global options');
player2.dispose();
// Set a tag level option
var tag2 = TestHelpers.makeTag();
tag2.setAttribute('attr', 'asdf');
let tag3 = TestHelpers.makeTag();
tag3.setAttribute('attr', 'asdf');
var player2 = new Player(tag2, { 'attr': 'fdsa' });
ok(player2.options_['attr'] === 'fdsa', 'Init options overrode tag and global options');
player2.dispose();
let player3 = new Player(tag3, { 'attr': 'fdsa' });
equal(player3.options_.attr, 'fdsa', 'Init options overrode tag and global options');
player3.dispose();
});
test('should get tag, source, and track settings', function(){
@ -739,14 +738,14 @@ test('should be scrubbing while seeking', function(){
});
test('should throw on startup no techs are specified', function() {
const techOrder = globalOptions.techOrder;
const techOrder = videojs.options.techOrder;
globalOptions.techOrder = null;
videojs.options.techOrder = null;
q.throws(function() {
videojs(TestHelpers.makeTag());
}, 'a falsey techOrder should throw');
globalOptions.techOrder = techOrder;
videojs.options.techOrder = techOrder;
});
test('should have a sensible toJSON that is equivalent to player.options', function() {

View File

@ -1,7 +1,6 @@
import videojs from '../../src/js/video.js';
import TestHelpers from './test-helpers.js';
import Player from '../../src/js/player.js';
import globalOptions from '../../src/js/global-options.js';
import log from '../../src/js/utils/log.js';
import document from 'global/document';
@ -25,7 +24,7 @@ test('should return a video player instance', function(){
var player = videojs('test_vid_id');
ok(player, 'created player from tag');
ok(player.id() === 'test_vid_id');
ok(Player.players['test_vid_id'] === player, 'added player to global reference');
ok(videojs.getPlayers()['test_vid_id'] === player, 'added player to global reference');
var playerAgain = videojs('test_vid_id');
ok(player === playerAgain, 'did not create a second player from same tag');
@ -42,9 +41,9 @@ test('should add the value to the languages object', function() {
data = {'Hello': 'Hola'};
result = videojs.addLanguage(code, data);
ok(globalOptions.languages[code], 'should exist');
equal(globalOptions.languages['es']['Hello'], 'Hola', 'should match');
deepEqual(result['Hello'], globalOptions.languages['es']['Hello'], 'should also match');
ok(videojs.options.languages[code], 'should exist');
equal(videojs.options.languages['es']['Hello'], 'Hola', 'should match');
deepEqual(result['Hello'], videojs.options.languages['es']['Hello'], 'should also match');
});
test('should add the value to the languages object with lower case lang code', function() {
@ -54,9 +53,9 @@ test('should add the value to the languages object with lower case lang code', f
data = {'Hello': 'Guten Tag'};
result = videojs.addLanguage(code, data);
ok(globalOptions['languages'][code.toLowerCase()], 'should exist');
equal(globalOptions['languages'][code.toLowerCase()]['Hello'], 'Guten Tag', 'should match');
deepEqual(result, globalOptions['languages'][code.toLowerCase()], 'should also match');
ok(videojs.options['languages'][code.toLowerCase()], 'should exist');
equal(videojs.options['languages'][code.toLowerCase()]['Hello'], 'Guten Tag', 'should match');
deepEqual(result, videojs.options['languages'][code.toLowerCase()], 'should also match');
});
test('should expose plugin registry function', function() {