1
0
mirror of https://github.com/videojs/video.js.git synced 2025-07-07 01:07:13 +02:00

Changed to vjs.obj.function naming for object related functions.

Updated mergeOptions to just options.
This commit is contained in:
Steve Heffernan
2013-01-25 17:36:40 -08:00
parent c7d3b9ebf9
commit dc18f475f8
13 changed files with 146 additions and 92 deletions

View File

@ -39,7 +39,7 @@ module.exports = function(grunt) {
minified: ['test/minified.html'] minified: ['test/minified.html']
}, },
watch: { watch: {
files: [ "src/**/*.js" ], files: [ "src/**/*.js", "test/unit/*.js" ],
tasks: "dev" tasks: "dev"
} }
// Copy is broken. Waiting for an update to use. // Copy is broken. Waiting for an update to use.
@ -133,6 +133,7 @@ module.exports = function(grunt) {
// + ' --formatting=pretty_print' // + ' --formatting=pretty_print'
+ ' --js_output_file=' + dest + ' --js_output_file=' + dest
+ ' --create_source_map ' + dest + '.map --source_map_format=V3' + ' --create_source_map ' + dest + '.map --source_map_format=V3'
+ ' --jscomp_warning=checkTypes --warning_level=VERBOSE';
+ ' --output_wrapper "(function() {%output%})();//@ sourceMappingURL=video.js.map"'; + ' --output_wrapper "(function() {%output%})();//@ sourceMappingURL=video.js.map"';
files.forEach(function(file){ files.forEach(function(file){

View File

@ -17,8 +17,11 @@ goog.require('vjs.dom');
vjs.Component = function(player, options, ready){ vjs.Component = function(player, options, ready){
this.player_ = player; this.player_ = player;
// // Allow for overridding default component options // Make a copy of prototype.options_ to protect against overriding global defaults
options = this.options_ = this.mergeOptions(this.options_, options); this.options_ = vjs.obj.copy(this.options_);
// Updated options with supplied options
options = this.options(options);
// Get ID from options, element, or create using player ID and unique ID // Get ID from options, element, or create using player ID and unique ID
this.id_ = options['id'] || ((options['el'] && options['el']['id']) ? options['el']['id'] : player.id() + '_component_' + vjs.guid++ ); this.id_ = options['id'] || ((options['el'] && options['el']['id']) ? options['el']['id'] : player.id() + '_component_' + vjs.guid++ );
@ -95,20 +98,20 @@ vjs.Component.prototype.options_;
/** /**
* Deep merge of options objects * Deep merge of options objects
* Whenever a property is an object on both options objects * Whenever a property is an object on both options objects
* the two properties will be merged using mergeOptions * the two properties will be merged using vjs.obj.deepMerge.
* *
* This is used for merging options for child components. We * This is used for merging options for child components. We
* want it to be easy to override individual options on a child * want it to be easy to override individual options on a child
* component without having to rewrite all the other default options. * component without having to rewrite all the other default options.
* *
* parentDefaultOptions = { * Parent.prototype.options_ = {
* children: { * children: {
* 'childOne': { 'foo': 'bar', 'asdf': 'fdsa' }, * 'childOne': { 'foo': 'bar', 'asdf': 'fdsa' },
* 'childTwo': {}, * 'childTwo': {},
* 'childThree': {} * 'childThree': {}
* } * }
* } * }
* parentOptionsFromInit = { * newOptions = {
* children: { * children: {
* 'childOne': { 'foo': 'baz', 'abc': '123' } * 'childOne': { 'foo': 'baz', 'abc': '123' }
* 'childTwo': null, * 'childTwo': null,
@ -116,7 +119,7 @@ vjs.Component.prototype.options_;
* } * }
* } * }
* *
* this.mergeOptions(parentDefaultOptions, parentOptionsFromInit); * this.options(newOptions);
* *
* RESULT * RESULT
* *
@ -129,41 +132,13 @@ vjs.Component.prototype.options_;
* } * }
* } * }
* *
* * @param {Object} obj Object whose values will be overwritten
* @param {Object} obj1 Object whose values will be overwritten
* @param {Object} obj2 Object whose values will overwrite
* @return {Object} NEW merged object. Does not return obj1. * @return {Object} NEW merged object. Does not return obj1.
*/ */
vjs.Component.prototype.mergeOptions = function(obj1, obj2){ vjs.Component.prototype.options = function(obj){
var retObj, toString, hasOwnProp, propName, objDef, val1, val2; if (obj === undefined) return this.options_;
hasOwnProp = Object.prototype.hasOwnProperty; return this.options_ = vjs.obj.deepMerge(this.options_, obj);
toString = Object.prototype.toString;
objDef = '[object Object]';
obj1 = obj1 || {};
retObj = {};
// Make a copy of obj1 so we don't affect the original options
vjs.eachProp(obj1, function(name, val){
retObj[name] = val;
});
if (!obj2) { return retObj; }
for (propName in obj2){
if (hasOwnProp.call(obj2, propName)) {
val1 = retObj[propName];
val2 = obj2[propName];
if (toString.call(val1) === objDef && toString.call(val2) === objDef) {
retObj[propName] = this.mergeOptions(val1, val2);
} else {
retObj[propName] = obj2[propName];
}
}
}
return retObj;
}; };
/** /**
@ -363,7 +338,7 @@ vjs.Component.prototype.initChildren = function(){
var self = this; var self = this;
// Loop through components and add them to the player // Loop through components and add them to the player
vjs.eachProp(options['children'], function(name, opts){ vjs.obj.each(options['children'], function(name, opts){
// Allow for disabling default components // Allow for disabling default components
// e.g. vjs.options['children']['posterImage'] = false // e.g. vjs.options['children']['posterImage'] = false

6
src/js/controls.js vendored
View File

@ -96,7 +96,7 @@ goog.inherits(vjs.Button, vjs.Control);
vjs.Button.prototype.createEl = function(type, props){ vjs.Button.prototype.createEl = function(type, props){
// Add standard Aria and Tabindex info // Add standard Aria and Tabindex info
props = vjs.merge({ props = vjs.obj.merge({
className: this.buildCSSClass(), className: this.buildCSSClass(),
innerHTML: '<div><span class="vjs-control-text">' + (this.buttonText || 'Need Text') + '</span></div>', innerHTML: '<div><span class="vjs-control-text">' + (this.buttonText || 'Need Text') + '</span></div>',
role: 'button', role: 'button',
@ -486,7 +486,7 @@ vjs.Slider = function(player, options){
goog.inherits(vjs.Slider, vjs.Component); goog.inherits(vjs.Slider, vjs.Component);
vjs.Slider.prototype.createEl = function(type, props) { vjs.Slider.prototype.createEl = function(type, props) {
props = vjs.merge({ props = vjs.obj.merge({
role: 'slider', role: 'slider',
'aria-valuenow': 0, 'aria-valuenow': 0,
'aria-valuemin': 0, 'aria-valuemin': 0,
@ -983,7 +983,7 @@ vjs.MenuItem = function(player, options){
goog.inherits(vjs.MenuItem, vjs.Button); goog.inherits(vjs.MenuItem, vjs.Button);
vjs.MenuItem.prototype.createEl = function(type, props){ vjs.MenuItem.prototype.createEl = function(type, props){
return goog.base(this, 'createEl', 'li', vjs.merge({ return goog.base(this, 'createEl', 'li', vjs.obj.merge({
className: 'vjs-menu-item', className: 'vjs-menu-item',
innerHTML: this.options_['label'] innerHTML: this.options_['label']
}, props)); }, props));

View File

@ -1,3 +1,9 @@
/**
* @fileoverview Add JSON support
* @suppress {undefinedVars}
* (Compiler doesn't like JSON not being declared)
*/
goog.provide('vjs.JSON'); goog.provide('vjs.JSON');
/** /**

View File

@ -1,4 +1,5 @@
goog.provide('vjs.dom'); goog.provide('vjs.dom');
goog.provide('vjs.obj');
goog.require('vjs'); goog.require('vjs');
@ -35,6 +36,14 @@ vjs.capitalize = function(string){
return string.charAt(0).toUpperCase() + string.slice(1); return string.charAt(0).toUpperCase() + string.slice(1);
}; };
/**
* Object functions container
* @type {Object}
*/
vjs.obj = {};
vjs.obj.toString = Object.prototype.toString;
vjs.obj.hasOwnProperty = Object.prototype.hasOwnProperty;
/** /**
* Loop through each property in an object and call a function * Loop through each property in an object and call a function
* whose arguments are (key,value) * whose arguments are (key,value)
@ -42,33 +51,71 @@ vjs.capitalize = function(string){
* @param {Function} fn Function to be called on each property. * @param {Function} fn Function to be called on each property.
* @this {*} * @this {*}
*/ */
vjs.eachProp = function(obj, fn){ vjs.obj.each = function(obj, fn){
if (!obj) { return; } for (var key in obj) {
if (vjs.obj.hasOwnProperty.call(obj, key)) {
for (var name in obj) { fn.call(this, key, obj[key]);
if (obj.hasOwnProperty(name)) {
fn.call(this, name, obj[name]);
} }
} }
}; };
/** /**
* Merge two objects together and return the original. * Merge two objects together and return the original.
* @param {[type]} obj1 [description] * @param {Object} obj1
* @param {[type]} obj2 [description] * @param {Object} obj2
* @param {[type]} safe [description] * @return {Object}
* @return {[type]}
*/ */
vjs.merge = function(obj1, obj2){ vjs.obj.merge = function(obj1, obj2){
// Make sure second object exists
if (!obj2) { return obj1; } if (!obj2) { return obj1; }
for (var key in obj2){
for (var propName in obj2){ if (vjs.obj.hasOwnProperty.call(obj2, key)) {
if (obj2.hasOwnProperty(propName)) { obj1[propName] = obj2[propName]; } obj1[key] = obj2[key];
}
} }
return obj1; return obj1;
}; };
/**
* Merge two objects, and merge any properties that are objects
* instead of just overwriting one. Uses to merge options hashes
* where deeper default settings are important.
* @param {Object} obj1 Object to override
* @param {Object} obj2 Overriding object
* @return {Object} New object. Obj1 and Obj2 will be untouched.
*/
vjs.obj.deepMerge = function(obj1, obj2){
var key, val1, val2, objDef;
objDef = '[object Object]';
// Make a copy of obj1 so we're not ovewriting original values.
// like prototype.options_ and all sub options objects
obj1 = vjs.obj.copy(obj1);
for (key in obj2){
if (vjs.obj.hasOwnProperty.call(obj2, key)) {
val1 = obj1[key];
val2 = obj2[key];
// Check if both properties are pure objects and do a deep merge if so
if (vjs.obj.toString.call(val1) === objDef && vjs.obj.toString.call(val2) === objDef) {
obj1[key] = vjs.obj.deepMerge(val1, val2);
} else {
obj1[key] = obj2[key];
}
}
}
return obj1;
};
/**
* Make a copy of the supplied object
* @param {Object} obj Object to copy
* @return {Object} Copy of object
*/
vjs.obj.copy = function(obj){
return vjs.obj.merge({}, obj);
};
/** /**
* Bind (a.k.a proxy or Context). A simple method for changing the context of a function * Bind (a.k.a proxy or Context). A simple method for changing the context of a function
It also stores a unique id on the function so it can be easily removed from events It also stores a unique id on the function so it can be easily removed from events

View File

@ -35,7 +35,7 @@ vjs.Flash = function(player, options, ready){
playerOptions = player.options_, playerOptions = player.options_,
// Merge default flashvars with ones passed in to init // Merge default flashvars with ones passed in to init
flashVars = vjs.merge({ flashVars = vjs.obj.merge({
// SWF Callback Functions // SWF Callback Functions
'readyFunction': 'videojs.Flash.onReady', 'readyFunction': 'videojs.Flash.onReady',
@ -51,13 +51,13 @@ vjs.Flash = function(player, options, ready){
}, options['flashVars']), }, options['flashVars']),
// Merge default parames with ones passed in // Merge default parames with ones passed in
params = vjs.merge({ params = vjs.obj.merge({
'wmode': 'opaque', // Opaque is needed to overlay controls, but can affect playback performance 'wmode': 'opaque', // Opaque is needed to overlay controls, but can affect playback performance
'bgcolor': '#000000' // Using bgcolor prevents a white flash when the object is loading 'bgcolor': '#000000' // Using bgcolor prevents a white flash when the object is loading
}, options['params']), }, options['params']),
// Merge default attributes with ones passed in // Merge default attributes with ones passed in
attributes = vjs.merge({ attributes = vjs.obj.merge({
'id': objId, 'id': objId,
'name': objId, // Both ID and Name needed or swf to identifty itself 'name': objId, // Both ID and Name needed or swf to identifty itself
'class': 'vjs-tech' 'class': 'vjs-tech'
@ -285,16 +285,19 @@ var createGetter = function(attr){
api[attr] = function(){ return this.el_.vjs_getProperty(attr); }; api[attr] = function(){ return this.el_.vjs_getProperty(attr); };
}; };
// Create getter and setters for all read/write attributes (function(){
for (var i = 0; i < readWrite.length; i++) { var i;
createGetter(readWrite[i]); // Create getter and setters for all read/write attributes
createSetter(readWrite[i]); for (i = 0; i < readWrite.length; i++) {
} createGetter(readWrite[i]);
createSetter(readWrite[i]);
}
// Create getters for read-only attributes // Create getters for read-only attributes
for (var i = 0; i < readOnly.length; i++) { for (i = 0; i < readOnly.length; i++) {
createGetter(readOnly[i]); createGetter(readOnly[i]);
} }
})();
/* Flash Support Testing -------------------------------------------------------- */ /* Flash Support Testing -------------------------------------------------------- */
@ -434,13 +437,13 @@ vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
// Convert flash vars to string // Convert flash vars to string
if (flashVars) { if (flashVars) {
vjs.eachProp(flashVars, function(key, val){ vjs.obj.each(flashVars, function(key, val){
flashVarsString += (key + '=' + val + '&amp;'); flashVarsString += (key + '=' + val + '&amp;');
}); });
} }
// Add swf, flashVars, and other default params // Add swf, flashVars, and other default params
params = vjs.merge({ params = vjs.obj.merge({
'movie': swf, 'movie': swf,
'flashvars': flashVarsString, 'flashvars': flashVarsString,
'allowScriptAccess': 'always', // Required to talk to swf 'allowScriptAccess': 'always', // Required to talk to swf
@ -448,11 +451,11 @@ vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
}, params); }, params);
// Create param tags string // Create param tags string
vjs.eachProp(params, function(key, val){ vjs.obj.each(params, function(key, val){
paramsString += '<param name="'+key+'" value="'+val+'" />'; paramsString += '<param name="'+key+'" value="'+val+'" />';
}); });
attributes = vjs.merge({ attributes = vjs.obj.merge({
// Add swf to attributes (need both for IE and Others to work) // Add swf to attributes (need both for IE and Others to work)
'data': swf, 'data': swf,
@ -463,7 +466,7 @@ vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
}, attributes); }, attributes);
// Create Attributes string // Create Attributes string
vjs.eachProp(attributes, function(key, val){ vjs.obj.each(attributes, function(key, val){
attrsString += (key + '="' + val + '" '); attrsString += (key + '="' + val + '" ');
}); });

View File

@ -17,7 +17,7 @@ vjs.Player = function(tag, options, ready){
// which overrides globally set options. // which overrides globally set options.
// This latter part coincides with the load order // This latter part coincides with the load order
// (tag must exist before Player) // (tag must exist before Player)
options = this.mergeOptions(this.getTagSettings(tag), options); options = vjs.obj.merge(this.getTagSettings(tag), options);
// Cache for video property values. // Cache for video property values.
this.cache_ = {}; this.cache_ = {};
@ -93,7 +93,7 @@ vjs.Player.prototype.getTagSettings = function(tag){
'tracks': [] 'tracks': []
}; };
vjs.merge(options, vjs.getAttributeValues(tag)); vjs.obj.merge(options, vjs.getAttributeValues(tag));
// Get tag children settings // Get tag children settings
if (tag.hasChildNodes()) { if (tag.hasChildNodes()) {
@ -216,7 +216,7 @@ vjs.Player.prototype.loadTech = function(techName, source){
}; };
// Grab tech-specific options from player options and add source and parent element to use. // Grab tech-specific options from player options and add source and parent element to use.
var techOptions = vjs.merge({ source: source, parentEl: this.el_ }, this.options_[techName.toLowerCase()]); var techOptions = vjs.obj.merge({ source: source, parentEl: this.el_ }, this.options_[techName.toLowerCase()]);
if (source) { if (source) {
if (source.src == this.cache_.src && this.cache_.currentTime > 0) { if (source.src == this.cache_.src && this.cache_.currentTime > 0) {
@ -832,7 +832,7 @@ vjs.Player.prototype.poster_;
/** /**
* Get or set the poster image source url. * Get or set the poster image source url.
* @param {String} src Poster image source URL * @param {String} src Poster image source URL
* @return {String=} Poster image source URL or null * @return {String} Poster image source URL or null
*/ */
vjs.Player.prototype.poster = function(src){ vjs.Player.prototype.poster = function(src){
if (src !== undefined) { if (src !== undefined) {

View File

@ -1012,7 +1012,7 @@ vjs.ChaptersTrackMenuItem.prototype.update = function(){
}; };
// Add Buttons to controlBar // Add Buttons to controlBar
vjs.merge(vjs.ControlBar.prototype.options_['children'], { vjs.obj.merge(vjs.ControlBar.prototype.options_['children'], {
'subtitlesButton': {}, 'subtitlesButton': {},
'captionsButton': {}, 'captionsButton': {},
'chaptersButton': {} 'chaptersButton': {}

View File

@ -37,24 +37,25 @@ test('should init child coponents from options', function(){
}); });
test('should do a deep merge of child options', function(){ test('should do a deep merge of child options', function(){
var compDefaultOptions = { // Create a default option for component
'children': { vjs.Component.prototype.options_ = {
'example': {
'childOne': { 'foo': 'bar', 'asdf': 'fdsa' }, 'childOne': { 'foo': 'bar', 'asdf': 'fdsa' },
'childTwo': {}, 'childTwo': {},
'childThree': {} 'childThree': {}
} }
} }
var compInitOptions = { var comp = new vjs.Component(getFakePlayer(), {
'children': { 'example': {
'childOne': { 'foo': 'baz', 'abc': '123' }, 'childOne': { 'foo': 'baz', 'abc': '123' },
'childThree': null, 'childThree': null,
'childFour': {} 'childFour': {}
} }
} });
var mergedOptions = vjs.Component.prototype.mergeOptions(compDefaultOptions, compInitOptions); var mergedOptions = comp.options();
var children = mergedOptions['children']; var children = mergedOptions['example'];
ok(children['childOne']['foo'] === 'baz', 'value three levels deep overridden'); ok(children['childOne']['foo'] === 'baz', 'value three levels deep overridden');
ok(children['childOne']['asdf'] === 'fdsa', 'value three levels deep maintained'); ok(children['childOne']['asdf'] === 'fdsa', 'value three levels deep maintained');
@ -62,6 +63,11 @@ test('should do a deep merge of child options', function(){
ok(children['childTwo'], 'object two levels deep maintained'); ok(children['childTwo'], 'object two levels deep maintained');
ok(children['childThree'] === null, 'object two levels deep removed'); ok(children['childThree'] === null, 'object two levels deep removed');
ok(children['childFour'], 'object two levels deep added'); ok(children['childFour'], 'object two levels deep added');
ok(vjs.Component.prototype.options_['example']['childOne']['foo'] === 'bar', 'prototype options were not overridden');
// Reset default component options to none
vjs.Component.prototype.options_ = null;
}); });
test('should dispose of component and children', function(){ test('should dispose of component and children', function(){

View File

@ -5,7 +5,7 @@ test('should create a video tag and have access children in old IE', function(){
fixture.innerHTML += "<video id='test_vid_id'><source type='video/mp4'></video>"; fixture.innerHTML += "<video id='test_vid_id'><source type='video/mp4'></video>";
vid = document.getElementById('test_vid_id'); var vid = document.getElementById('test_vid_id');
ok(vid.childNodes.length === 1); ok(vid.childNodes.length === 1);
ok(vid.childNodes[0].getAttribute('type') === 'video/mp4'); ok(vid.childNodes[0].getAttribute('type') === 'video/mp4');

View File

@ -22,13 +22,25 @@ test('should loop through each property on an object', function(){
} }
// Add 3 to each value // Add 3 to each value
vjs.eachProp(asdf, function(key, value){ vjs.obj.each(asdf, function(key, value){
asdf[key] = value + 3; asdf[key] = value + 3;
}); });
deepEqual(asdf,{a:4,b:5,'c':6}) deepEqual(asdf,{a:4,b:5,'c':6})
}); });
test('should copy an object', function(){
var asdf = {
a: 1,
b: 2,
'c': 3
}
var fdsa = vjs.obj.copy(asdf);
deepEqual(asdf,fdsa)
});
test('should add context to a function', function(){ test('should add context to a function', function(){
var newContext = { test: 'obj'}; var newContext = { test: 'obj'};
var asdf = function(){ var asdf = function(){

View File

@ -1,6 +1,9 @@
// Fake a media playback tech controller so that player tests // Fake a media playback tech controller so that player tests
// can run without HTML5 or Flash, of which PhantomJS supports neither. // can run without HTML5 or Flash, of which PhantomJS supports neither.
/**
* @constructor
*/
vjs.MediaFaker = function(player, options, onReady){ vjs.MediaFaker = function(player, options, onReady){
goog.base(this, player, options, onReady); goog.base(this, player, options, onReady);
@ -30,4 +33,4 @@ vjs.MediaFaker.prototype.volume = function(){ return 0; };
goog.exportSymbol('videojs.MediaFaker', vjs.MediaFaker); goog.exportSymbol('videojs.MediaFaker', vjs.MediaFaker);
goog.exportProperty(vjs.MediaFaker, 'isSupported', vjs.MediaFaker.isSupported); goog.exportProperty(vjs.MediaFaker, 'isSupported', vjs.MediaFaker.isSupported);
goog.exportProperty(vjs.MediaFaker, 'canPlaySource', vjs.MediaFaker.canPlaySource); goog.exportProperty(vjs.MediaFaker, 'canPlaySource', vjs.MediaFaker.canPlaySource);

View File

@ -8,12 +8,13 @@ var PlayerTest = {
return videoTag; return videoTag;
}, },
makePlayer: function(playerOptions){ makePlayer: function(playerOptions){
var player;
var videoTag = PlayerTest.makeTag(); var videoTag = PlayerTest.makeTag();
var fixture = document.getElementById('qunit-fixture'); var fixture = document.getElementById('qunit-fixture');
fixture.appendChild(videoTag); fixture.appendChild(videoTag);
var opts = vjs.merge({ var opts = vjs.obj.merge({
'techOrder': ['mediaFaker'] 'techOrder': ['mediaFaker']
}, playerOptions); }, playerOptions);