mirror of
https://github.com/videojs/video.js.git
synced 2025-01-10 23:30:03 +02:00
Clean up and documentation of src/js/video.js and DOM functions
Preparing to export utility functions on the videojs object closes #2182 Change el() to getEl() for consistency Cleaned up DOM functions library Clean up and document videojs object API Fixed mergeOptions to modify the first object instead of a copy More cleanup of the main video.js file and documentation Fixed issues with mergeOptions Cleaned up the addLanguage function Removed unnecessary underscores in private module vars
This commit is contained in:
parent
5d550ffada
commit
1bfe0b4fed
@ -32,6 +32,7 @@ CHANGELOG
|
||||
* @heff added support for fluid widths, aspect ratios, and metadata defaults ([view](https://github.com/videojs/video.js/pull/1952))
|
||||
* @heff reorganized all utility functions in the codebase ([view](https://github.com/videojs/video.js/pull/2139))
|
||||
* @eXon made additional tech 2.0 improvements listed in #2126 ([view](https://github.com/videojs/video.js/pull/2166))
|
||||
* @heff Cleaned up and documented src/js/video.js and DOM functions ([view](https://github.com/videojs/video.js/pull/2182))
|
||||
|
||||
--------------------
|
||||
|
||||
|
@ -24,7 +24,6 @@
|
||||
"style": "./dist/video-js.css",
|
||||
"dependencies": {
|
||||
"global": "^4.3.0",
|
||||
"lodash.clonedeep": "^3.0.0",
|
||||
"lodash.isplainobject": "^3.0.2",
|
||||
"lodash.merge": "^3.2.1",
|
||||
"object.assign": "^2.0.1",
|
||||
|
@ -13,6 +13,7 @@ import toTitleCase from './utils/to-title-case.js';
|
||||
import assign from 'object.assign';
|
||||
import mergeOptions from './utils/merge-options.js';
|
||||
|
||||
|
||||
/**
|
||||
* Base UI Component class
|
||||
*
|
||||
@ -52,8 +53,8 @@ class Component {
|
||||
this.player_ = player;
|
||||
}
|
||||
|
||||
// Make a copy of prototype.options_ to protect against overriding global defaults
|
||||
this.options_ = assign({}, this.options_);
|
||||
// Make a copy of prototype.options_ to protect against overriding defaults
|
||||
this.options_ = mergeOptions({}, this.options_);
|
||||
|
||||
// Updated options with supplied options
|
||||
options = this.options(options);
|
||||
@ -130,7 +131,7 @@ class Component {
|
||||
this.el_.parentNode.removeChild(this.el_);
|
||||
}
|
||||
|
||||
Dom.removeData(this.el_);
|
||||
Dom.removeElData(this.el_);
|
||||
this.el_ = null;
|
||||
}
|
||||
|
||||
@ -741,7 +742,7 @@ class Component {
|
||||
* @return {Component}
|
||||
*/
|
||||
hasClass(classToCheck) {
|
||||
return Dom.hasClass(this.el_, classToCheck);
|
||||
return Dom.hasElClass(this.el_, classToCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -751,7 +752,7 @@ class Component {
|
||||
* @return {Component}
|
||||
*/
|
||||
addClass(classToAdd) {
|
||||
Dom.addClass(this.el_, classToAdd);
|
||||
Dom.addElClass(this.el_, classToAdd);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -762,7 +763,7 @@ class Component {
|
||||
* @return {Component}
|
||||
*/
|
||||
removeClass(classToRemove) {
|
||||
Dom.removeClass(this.el_, classToRemove);
|
||||
Dom.removeElClass(this.el_, classToRemove);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -918,19 +919,6 @@ class Component {
|
||||
// If component has display:none, offset will return 0
|
||||
// TODO: handle display:none and no dimension style using px
|
||||
return parseInt(this.el_['offset' + toTitleCase(widthOrHeight)], 10);
|
||||
|
||||
// ComputedStyle version.
|
||||
// Only difference is if the element is hidden it will return
|
||||
// the percent value (e.g. '100%'')
|
||||
// instead of zero like offsetWidth returns.
|
||||
// var val = Dom.getComputedStyleValue(this.el_, widthOrHeight);
|
||||
// var pxIndex = val.indexOf('px');
|
||||
|
||||
// if (pxIndex !== -1) {
|
||||
// return val.slice(0, pxIndex);
|
||||
// } else {
|
||||
// return val;
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,9 +68,9 @@ class MuteToggle extends Button {
|
||||
|
||||
/* TODO improve muted icon classes */
|
||||
for (var i = 0; i < 4; i++) {
|
||||
Dom.removeClass(this.el_, `vjs-vol-${i}`);
|
||||
Dom.removeElClass(this.el_, `vjs-vol-${i}`);
|
||||
}
|
||||
Dom.addClass(this.el_, `vjs-vol-${level}`);
|
||||
Dom.addElClass(this.el_, `vjs-vol-${level}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
// Subclasses Component
|
||||
import Component from './component.js';
|
||||
|
||||
import document from 'global/document';
|
||||
import window from 'global/window';
|
||||
import * as Events from './utils/events.js';
|
||||
import * as Dom from './utils/dom.js';
|
||||
import * as Fn from './utils/fn.js';
|
||||
@ -10,23 +14,22 @@ 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 Options from './options.js';
|
||||
import globalOptions from './global-options.js';
|
||||
import safeParseTuple from 'safe-json-parse/tuple';
|
||||
import window from 'global/window';
|
||||
import document from 'global/document';
|
||||
import assign from 'object.assign';
|
||||
import mergeOptions from './utils/merge-options.js';
|
||||
|
||||
// Include required child components
|
||||
// Include required child components (importing also registers them)
|
||||
import MediaLoader from './tech/loader.js';
|
||||
import Poster from './poster-image.js';
|
||||
import PosterImage from './poster-image.js';
|
||||
import TextTrackDisplay from './tracks/text-track-display.js';
|
||||
import LoadingSpinner from './loading-spinner.js';
|
||||
import BigPlayButton from './big-play-button.js';
|
||||
import controlBar from './control-bar/control-bar.js';
|
||||
import ControlBar from './control-bar/control-bar.js';
|
||||
import ErrorDisplay from './error-display.js';
|
||||
import TextTrackSettings from './tracks/text-track-settings.js';
|
||||
// Require html5 for disposing the original video tag
|
||||
|
||||
// Require html5 tech, at least for disposing the original video tag
|
||||
import Html5 from './tech/html5.js';
|
||||
|
||||
/**
|
||||
@ -99,13 +102,13 @@ class Player extends Component {
|
||||
this.tag = tag; // Store the original tag used to set options
|
||||
|
||||
// Store the tag attributes used to restore html5 element
|
||||
this.tagAttributes = tag && Dom.getElementAttributes(tag);
|
||||
this.tagAttributes = tag && Dom.getElAttributes(tag);
|
||||
|
||||
// Update Current Language
|
||||
this.language_ = options['language'] || Options['language'];
|
||||
this.language_ = options['language'] || globalOptions['language'];
|
||||
|
||||
// Update Supported Languages
|
||||
this.languages_ = options['languages'] || Options['languages'];
|
||||
this.languages_ = options['languages'] || globalOptions['languages'];
|
||||
|
||||
// Cache for video property values.
|
||||
this.cache_ = {};
|
||||
@ -211,7 +214,7 @@ class Player extends Component {
|
||||
|
||||
// Copy over all the attributes from the tag, including ID and class
|
||||
// ID will now reference player box, not the video tag
|
||||
const attrs = Dom.getElementAttributes(tag);
|
||||
const attrs = Dom.getElAttributes(tag);
|
||||
|
||||
Object.getOwnPropertyNames(attrs).forEach(function(attr){
|
||||
// workaround so we don't totally break IE7
|
||||
@ -246,7 +249,7 @@ class Player extends Component {
|
||||
this.fluid(this.options_['fluid']);
|
||||
this.aspectRatio(this.options_['aspectRatio']);
|
||||
|
||||
// insertFirst seems to cause the networkState to flicker from 3 to 2, so
|
||||
// insertElFirst seems to cause the networkState to flicker from 3 to 2, so
|
||||
// keep track of the original for later so we can know if the source originally failed
|
||||
tag.initNetworkState_ = tag.networkState;
|
||||
|
||||
@ -254,7 +257,7 @@ class Player extends Component {
|
||||
if (tag.parentNode) {
|
||||
tag.parentNode.insertBefore(el, tag);
|
||||
}
|
||||
Dom.insertFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup.
|
||||
Dom.insertElFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup.
|
||||
|
||||
this.el_ = el;
|
||||
|
||||
@ -479,7 +482,7 @@ class Player extends Component {
|
||||
// Add the tech element in the DOM if it was not already there
|
||||
// Make sure to not insert the original video element if using Html5
|
||||
if (this.tech.el().parentNode !== this.el() && (techName !== 'Html5' || !this.tag)) {
|
||||
Dom.insertFirst(this.tech.el(), this.el());
|
||||
Dom.insertElFirst(this.tech.el(), this.el());
|
||||
}
|
||||
|
||||
// Get rid of the original video tag reference after the first tech is loaded
|
||||
@ -1376,7 +1379,7 @@ class Player extends Component {
|
||||
document.documentElement.style.overflow = 'hidden';
|
||||
|
||||
// Apply fullscreen styles
|
||||
Dom.addClass(document.body, 'vjs-full-window');
|
||||
Dom.addElClass(document.body, 'vjs-full-window');
|
||||
|
||||
this.trigger('enterFullWindow');
|
||||
}
|
||||
@ -1399,7 +1402,7 @@ class Player extends Component {
|
||||
document.documentElement.style.overflow = this.docOrigOverflow;
|
||||
|
||||
// Remove fullscreen styles
|
||||
Dom.removeClass(document.body, 'vjs-full-window');
|
||||
Dom.removeElClass(document.body, 'vjs-full-window');
|
||||
|
||||
// Resize the box, controller, and poster to original sizes
|
||||
// this.positionAll();
|
||||
@ -2116,7 +2119,7 @@ class Player extends Component {
|
||||
'tracks': []
|
||||
};
|
||||
|
||||
const tagOptions = Dom.getElementAttributes(tag);
|
||||
const tagOptions = Dom.getElAttributes(tag);
|
||||
const dataSetup = tagOptions['data-setup'];
|
||||
|
||||
// Check if data-setup attr exists.
|
||||
@ -2141,9 +2144,9 @@ class Player extends Component {
|
||||
// Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/
|
||||
const childName = child.nodeName.toLowerCase();
|
||||
if (childName === 'source') {
|
||||
baseOptions['sources'].push(Dom.getElementAttributes(child));
|
||||
baseOptions['sources'].push(Dom.getElAttributes(child));
|
||||
} else if (childName === 'track') {
|
||||
baseOptions['tracks'].push(Dom.getElementAttributes(child));
|
||||
baseOptions['tracks'].push(Dom.getElAttributes(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2168,7 +2171,7 @@ Player.players = {};
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
Player.prototype.options_ = Options;
|
||||
Player.prototype.options_ = globalOptions;
|
||||
|
||||
/**
|
||||
* Fired when the player has initial duration and dimension information
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Player from './player';
|
||||
import Player from './player.js';
|
||||
|
||||
/**
|
||||
* the method for registering a video.js plugin
|
||||
* The method for registering a video.js plugin
|
||||
*
|
||||
* @param {String} name The name of the plugin
|
||||
* @param {Function} init The function that is run when the player inits
|
||||
|
@ -160,7 +160,7 @@ class Slider extends Component {
|
||||
|
||||
calculateDistance(event){
|
||||
let el = this.el_;
|
||||
let box = Dom.findPosition(el);
|
||||
let box = Dom.findElPosition(el);
|
||||
let boxW = el.offsetWidth;
|
||||
let boxH = el.offsetHeight;
|
||||
let handle = this.handle;
|
||||
|
@ -267,7 +267,7 @@ Flash.formats = {
|
||||
};
|
||||
|
||||
Flash.onReady = function(currSwf){
|
||||
let el = Dom.el(currSwf);
|
||||
let el = Dom.getEl(currSwf);
|
||||
let tech = el && el.tech;
|
||||
|
||||
// if there is no el then the tech has been disposed
|
||||
@ -300,13 +300,13 @@ Flash.checkReady = function(tech){
|
||||
|
||||
// Trigger events from the swf on the player
|
||||
Flash.onEvent = function(swfID, eventName){
|
||||
let tech = Dom.el(swfID).tech;
|
||||
let tech = Dom.getEl(swfID).tech;
|
||||
tech.trigger(eventName);
|
||||
};
|
||||
|
||||
// Log errors from the swf
|
||||
Flash.onError = function(swfID, err){
|
||||
const tech = Dom.el(swfID).tech;
|
||||
const tech = Dom.getEl(swfID).tech;
|
||||
const msg = 'FLASH: '+err;
|
||||
|
||||
if (err === 'srcnotfound') {
|
||||
|
@ -101,13 +101,13 @@ class Html5 extends Tech {
|
||||
el = document.createElement('video');
|
||||
|
||||
// determine if native controls should be used
|
||||
let tagAttributes = this.options_.tag && Dom.getElementAttributes(this.options_.tag);
|
||||
let tagAttributes = this.options_.tag && Dom.getElAttributes(this.options_.tag);
|
||||
let attributes = mergeOptions({}, tagAttributes);
|
||||
if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) {
|
||||
delete attributes.controls;
|
||||
}
|
||||
|
||||
Dom.setElementAttributes(el,
|
||||
Dom.setElAttributes(el,
|
||||
assign(attributes, {
|
||||
id: this.options_.techId,
|
||||
class: 'vjs-tech'
|
||||
@ -139,7 +139,7 @@ class Html5 extends Tech {
|
||||
if (typeof this.options_[attr] !== 'undefined') {
|
||||
overwriteAttrs[attr] = this.options_[attr];
|
||||
}
|
||||
Dom.setElementAttributes(el, overwriteAttrs);
|
||||
Dom.setElAttributes(el, overwriteAttrs);
|
||||
}
|
||||
|
||||
return el;
|
||||
|
@ -8,24 +8,22 @@ import roundFloat from './round-float.js';
|
||||
* Also allows for CSS (jQuery) ID syntax. But nothing other than IDs.
|
||||
* @param {String} id Element ID
|
||||
* @return {Element} Element with supplied ID
|
||||
* @private
|
||||
*/
|
||||
export const el = function(id){
|
||||
export function getEl(id){
|
||||
if (id.indexOf('#') === 0) {
|
||||
id = id.slice(1);
|
||||
}
|
||||
|
||||
return document.getElementById(id);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an element and applies properties.
|
||||
* @param {String=} tagName Name of tag to be created.
|
||||
* @param {Object=} properties Element properties to be applied.
|
||||
* @return {Element}
|
||||
* @private
|
||||
*/
|
||||
export const createEl = function(tagName='div', properties={}){
|
||||
export function createEl(tagName='div', properties={}){
|
||||
let el = document.createElement(tagName);
|
||||
|
||||
Object.getOwnPropertyNames(properties).forEach(function(propName){
|
||||
@ -47,7 +45,7 @@ export const createEl = function(tagName='div', properties={}){
|
||||
});
|
||||
|
||||
return el;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an element as the first child node of another
|
||||
@ -55,13 +53,13 @@ export const createEl = function(tagName='div', properties={}){
|
||||
* @param {[type]} parent Element to insert child into
|
||||
* @private
|
||||
*/
|
||||
export const insertFirst = function(child, parent){
|
||||
export function insertElFirst(child, parent){
|
||||
if (parent.firstChild) {
|
||||
parent.insertBefore(child, parent.firstChild);
|
||||
} else {
|
||||
parent.appendChild(child);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Element Data Store. Allows for binding data to an element without putting it directly on the element.
|
||||
@ -70,7 +68,7 @@ export const insertFirst = function(child, parent){
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
export const cache = {};
|
||||
const elData = {};
|
||||
|
||||
/**
|
||||
* Unique attribute name to store an element's guid in
|
||||
@ -78,24 +76,26 @@ export const cache = {};
|
||||
* @constant
|
||||
* @private
|
||||
*/
|
||||
export const expando = 'vdata' + (new Date()).getTime();
|
||||
const elIdAttr = 'vdata' + (new Date()).getTime();
|
||||
|
||||
/**
|
||||
* Returns the cache object where data for an element is stored
|
||||
* @param {Element} el Element to store data for.
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
export const getData = function(el){
|
||||
var id = el[expando];
|
||||
export function getElData(el) {
|
||||
let id = el[elIdAttr];
|
||||
|
||||
if (!id) {
|
||||
id = el[expando] = Guid.newGUID();
|
||||
id = el[elIdAttr] = Guid.newGUID();
|
||||
}
|
||||
if (!cache[id]) {
|
||||
cache[id] = {};
|
||||
|
||||
if (!elData[id]) {
|
||||
elData[id] = {};
|
||||
}
|
||||
return cache[id];
|
||||
};
|
||||
|
||||
return elData[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not an element has cached data
|
||||
@ -103,73 +103,71 @@ export const getData = function(el){
|
||||
* @return {Boolean}
|
||||
* @private
|
||||
*/
|
||||
export const hasData = function(el){
|
||||
const id = el[expando];
|
||||
export function hasElData(el) {
|
||||
const id = el[elIdAttr];
|
||||
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!Object.getOwnPropertyNames(cache[id]).length;
|
||||
};
|
||||
return !!Object.getOwnPropertyNames(elData[id]).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete data for the element from the cache and the guid attr from getElementById
|
||||
* @param {Element} el Remove data for an element
|
||||
* @private
|
||||
*/
|
||||
export const removeData = function(el){
|
||||
var id = el[expando];
|
||||
if (!id) { return; }
|
||||
// Remove all stored data
|
||||
// Changed to = null
|
||||
// http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
|
||||
// cache[id] = null;
|
||||
delete cache[id];
|
||||
export function removeElData(el) {
|
||||
let id = el[elIdAttr];
|
||||
|
||||
// Remove the expando property from the DOM node
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove all stored data
|
||||
delete elData[id];
|
||||
|
||||
// Remove the elIdAttr property from the DOM node
|
||||
try {
|
||||
delete el[expando];
|
||||
delete el[elIdAttr];
|
||||
} catch(e) {
|
||||
if (el.removeAttribute) {
|
||||
el.removeAttribute(expando);
|
||||
el.removeAttribute(elIdAttr);
|
||||
} else {
|
||||
// IE doesn't appear to support removeAttribute on the document element
|
||||
el[expando] = null;
|
||||
el[elIdAttr] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an element has a CSS class
|
||||
* @param {Element} element Element to check
|
||||
* @param {String} classToCheck Classname to check
|
||||
* @private
|
||||
*/
|
||||
export const hasClass = function(element, classToCheck){
|
||||
export function hasElClass(element, classToCheck) {
|
||||
return ((' ' + element.className + ' ').indexOf(' ' + classToCheck + ' ') !== -1);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a CSS class name to an element
|
||||
* @param {Element} element Element to add class name to
|
||||
* @param {String} classToAdd Classname to add
|
||||
* @private
|
||||
*/
|
||||
export const addClass = function(element, classToAdd){
|
||||
if (!hasClass(element, classToAdd)) {
|
||||
export function addElClass(element, classToAdd) {
|
||||
if (!hasElClass(element, classToAdd)) {
|
||||
element.className = element.className === '' ? classToAdd : element.className + ' ' + classToAdd;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a CSS class name from an element
|
||||
* @param {Element} element Element to remove from class name
|
||||
* @param {String} classToAdd Classname to remove
|
||||
* @private
|
||||
*/
|
||||
export const removeClass = function(element, classToRemove){
|
||||
if (!hasClass(element, classToRemove)) {return;}
|
||||
export function removeElClass(element, classToRemove) {
|
||||
if (!hasElClass(element, classToRemove)) {return;}
|
||||
|
||||
let classNames = element.className.split(' ');
|
||||
|
||||
@ -181,7 +179,7 @@ export const removeClass = function(element, classToRemove){
|
||||
}
|
||||
|
||||
element.className = classNames.join(' ');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply attributes to an HTML element.
|
||||
@ -189,7 +187,7 @@ export const removeClass = function(element, classToRemove){
|
||||
* @param {Object=} attributes Element attributes to be applied.
|
||||
* @private
|
||||
*/
|
||||
export const setElementAttributes = function(el, attributes){
|
||||
export function setElAttributes(el, attributes) {
|
||||
Object.getOwnPropertyNames(attributes).forEach(function(attrName){
|
||||
let attrValue = attributes[attrName];
|
||||
|
||||
@ -199,7 +197,7 @@ export const setElementAttributes = function(el, attributes){
|
||||
el.setAttribute(attrName, (attrValue === true ? '' : attrValue));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element's attribute values, as defined on the HTML tag
|
||||
@ -210,7 +208,7 @@ export const setElementAttributes = function(el, attributes){
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
export const getElementAttributes = function(tag){
|
||||
export function getElAttributes(tag) {
|
||||
var obj, knownBooleans, attrs, attrName, attrVal;
|
||||
|
||||
obj = {};
|
||||
@ -241,40 +239,26 @@ export const getElementAttributes = function(tag){
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the computed style value for an element
|
||||
* From http://robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
|
||||
* @param {Element} el Element to get style value for
|
||||
* @param {String} strCssRule Style name
|
||||
* @return {String} Style value
|
||||
* @private
|
||||
*/
|
||||
export const getComputedDimension = function(el, strCssRule){
|
||||
var strValue = '';
|
||||
if(document.defaultView && document.defaultView.getComputedStyle){
|
||||
strValue = document.defaultView.getComputedStyle(el, '').getPropertyValue(strCssRule);
|
||||
|
||||
} else if(el.currentStyle){
|
||||
// IE8 Width/Height support
|
||||
let upperCasedRule = strCssRule.substr(0,1).toUpperCase() + strCssRule.substr(1);
|
||||
strValue = el[`client${upperCasedRule}`] + 'px';
|
||||
}
|
||||
return strValue;
|
||||
};
|
||||
}
|
||||
|
||||
// Attempt to block the ability to select text while dragging controls
|
||||
export const blockTextSelection = function(){
|
||||
export function blockTextSelection() {
|
||||
document.body.focus();
|
||||
document.onselectstart = function () { return false; };
|
||||
};
|
||||
document.onselectstart = function() {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
// Turn off text selection blocking
|
||||
export const unblockTextSelection = function(){ document.onselectstart = function () { return true; }; };
|
||||
export function unblockTextSelection() {
|
||||
document.onselectstart = function() {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
// Offset Left
|
||||
// getBoundingClientRect technique from John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/
|
||||
export const findPosition = function(el) {
|
||||
export function findElPosition(el) {
|
||||
let box;
|
||||
|
||||
if (el.getBoundingClientRect && el.parentNode) {
|
||||
@ -304,4 +288,4 @@ export const findPosition = function(el) {
|
||||
left: roundFloat(left),
|
||||
top: roundFloat(top)
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ export function on(elem, type, fn){
|
||||
return _handleMultipleEvents(on, elem, type, fn);
|
||||
}
|
||||
|
||||
let data = Dom.getData(elem);
|
||||
let data = Dom.getElData(elem);
|
||||
|
||||
// We need a place to store all our handler data
|
||||
if (!data.handlers) data.handlers = {};
|
||||
@ -76,10 +76,10 @@ export function on(elem, type, fn){
|
||||
* @param {Function} fn Specific listener to remove. Don't include to remove listeners for an event type.
|
||||
*/
|
||||
export function off(elem, type, fn) {
|
||||
// Don't want to add a cache object through getData if not needed
|
||||
if (!Dom.hasData(elem)) return;
|
||||
// Don't want to add a cache object through getElData if not needed
|
||||
if (!Dom.hasElData(elem)) return;
|
||||
|
||||
let data = Dom.getData(elem);
|
||||
let data = Dom.getElData(elem);
|
||||
|
||||
// If no events exist, nothing to unbind
|
||||
if (!data.handlers) { return; }
|
||||
@ -131,8 +131,8 @@ export function off(elem, type, fn) {
|
||||
export function trigger(elem, event) {
|
||||
// Fetches element data and a reference to the parent (for bubbling).
|
||||
// Don't want to add a data object to cache for every parent,
|
||||
// so checking hasData first.
|
||||
var elemData = (Dom.hasData(elem)) ? Dom.getData(elem) : {};
|
||||
// so checking hasElData first.
|
||||
var elemData = (Dom.hasElData(elem)) ? Dom.getElData(elem) : {};
|
||||
var parent = elem.parentNode || elem.ownerDocument;
|
||||
// type = event.type || event,
|
||||
// handler;
|
||||
@ -156,7 +156,7 @@ export function trigger(elem, event) {
|
||||
|
||||
// If at the top of the DOM, triggers the default action unless disabled.
|
||||
} else if (!parent && !event.defaultPrevented) {
|
||||
var targetData = Dom.getData(event.target);
|
||||
var targetData = Dom.getElData(event.target);
|
||||
|
||||
// Checks if the target has a default action for this event.
|
||||
if (event.target[event.type]) {
|
||||
@ -309,7 +309,7 @@ export function fixEvent(event) {
|
||||
* @private
|
||||
*/
|
||||
function _cleanUpEvents(elem, type) {
|
||||
var data = Dom.getData(elem);
|
||||
var data = Dom.getElData(elem);
|
||||
|
||||
// Remove the events of a particular type if there are none left
|
||||
if (data.handlers[type].length === 0) {
|
||||
@ -330,15 +330,11 @@ function _cleanUpEvents(elem, type) {
|
||||
delete data.handlers;
|
||||
delete data.dispatcher;
|
||||
delete data.disabled;
|
||||
|
||||
// data.handlers = null;
|
||||
// data.dispatcher = null;
|
||||
// data.disabled = null;
|
||||
}
|
||||
|
||||
// Finally remove the expando if there is no data left
|
||||
if (Object.getOwnPropertyNames(data).length <= 0) {
|
||||
Dom.removeData(elem);
|
||||
// Finally remove the element data if there is no data left
|
||||
if (Object.getOwnPropertyNames(data).length === 0) {
|
||||
Dom.removeElData(elem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,33 +1,39 @@
|
||||
import merge from 'lodash.merge';
|
||||
import isPlainObject from 'lodash.isplainobject';
|
||||
import cloneDeep from 'lodash.clonedeep';
|
||||
|
||||
/**
|
||||
* Merge two options objects, recursively merging any plain object properties as
|
||||
* well. Previously `deepMerge`
|
||||
* Merge two options objects, recursively merging **only** plain object
|
||||
* properties. Previously `deepMerge`.
|
||||
*
|
||||
* @param {Object} obj1 Object to override values in
|
||||
* @param {Object} obj2 Overriding object
|
||||
* @return {Object} New object -- obj1 and obj2 will be untouched
|
||||
* @param {Object} object The destination object
|
||||
* @param {...Object} source One or more objects to merge into the first
|
||||
*
|
||||
* @returns {Object} The updated first object
|
||||
*/
|
||||
export default function mergeOptions(obj1){
|
||||
// Copy to ensure we're not modifying the defaults somewhere
|
||||
obj1 = cloneDeep(obj1, function(value) {
|
||||
if (!isPlainObject(value)) {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
export default function mergeOptions(object={}) {
|
||||
|
||||
// Allow for infinite additional object args to merge
|
||||
Array.prototype.slice.call(arguments, 1).forEach(function(argObj){
|
||||
Array.prototype.slice.call(arguments, 1).forEach(function(source){
|
||||
|
||||
// Recursively merge only plain objects
|
||||
// All other values will be directly copied
|
||||
merge(obj1, argObj, function(a, b) {
|
||||
if (!isPlainObject(a) || !isPlainObject(b)) {
|
||||
merge(object, source, function(a, b) {
|
||||
|
||||
// If we're not working with a plain object, copy the value as is
|
||||
if (!isPlainObject(b)) {
|
||||
return b;
|
||||
}
|
||||
|
||||
// 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 (!isPlainObject(a)) {
|
||||
return mergeOptions({}, b);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return obj1;
|
||||
return object;
|
||||
}
|
||||
|
287
src/js/video.js
287
src/js/video.js
@ -1,26 +1,22 @@
|
||||
import document from 'global/document';
|
||||
import assign from 'object.assign';
|
||||
import MediaLoader from './tech/loader.js';
|
||||
import Html5 from './tech/html5.js';
|
||||
import Flash from './tech/flash.js';
|
||||
import PosterImage from './poster-image.js';
|
||||
import TextTrackDisplay from './tracks/text-track-display.js';
|
||||
import LoadingSpinner from './loading-spinner.js';
|
||||
import BigPlayButton from './big-play-button.js';
|
||||
import ControlBar from './control-bar/control-bar.js';
|
||||
import ErrorDisplay from './error-display.js';
|
||||
import * as setup from './setup';
|
||||
import Component from './component';
|
||||
import Options from './options';
|
||||
import * as Dom from './utils/dom.js';
|
||||
import log from './utils/log.js';
|
||||
import * as browser from './utils/browser.js';
|
||||
import globalOptions from './global-options.js';
|
||||
import Player from './player';
|
||||
import extendsFn from './extends.js';
|
||||
import plugin from './plugins.js';
|
||||
import options from './options.js';
|
||||
import mergeOptions from '../../src/js/utils/merge-options.js';
|
||||
|
||||
import assign from 'object.assign';
|
||||
import log from './utils/log.js';
|
||||
import * as Dom from './utils/dom.js';
|
||||
import * as browser from './utils/browser.js';
|
||||
import extendsFn from './extends.js';
|
||||
import merge from 'lodash.merge';
|
||||
|
||||
// Include the built-in techs
|
||||
import Html5 from './tech/html5.js';
|
||||
import Flash from './tech/flash.js';
|
||||
|
||||
// HTML5 Element Shim for IE8
|
||||
if (typeof HTMLVideoElement === 'undefined') {
|
||||
document.createElement('video');
|
||||
@ -32,11 +28,9 @@ if (typeof HTMLVideoElement === 'undefined') {
|
||||
* Doubles as the main function for users to create a player instance and also
|
||||
* the main library object.
|
||||
*
|
||||
* **ALIASES** videojs, _V_ (deprecated)
|
||||
* The `videojs` function can be used to initialize or retrieve a player.
|
||||
*
|
||||
* The `vjs` function can be used to initialize or retrieve a player.
|
||||
*
|
||||
* var myPlayer = vjs('my_video_id');
|
||||
* var myPlayer = videojs('my_video_id');
|
||||
*
|
||||
* @param {String|Element} id Video element or video element ID
|
||||
* @param {Object=} options Optional options object for config/settings
|
||||
@ -72,7 +66,7 @@ var videojs = function(id, options, ready){
|
||||
|
||||
// Otherwise get element for ID
|
||||
} else {
|
||||
tag = Dom.el(id);
|
||||
tag = Dom.getEl(id);
|
||||
}
|
||||
|
||||
// ID is a media element
|
||||
@ -90,64 +84,235 @@ var videojs = function(id, options, ready){
|
||||
return tag['player'] || new Player(tag, options, ready);
|
||||
};
|
||||
|
||||
// CDN Version. Used to target right flash swf.
|
||||
videojs.CDN_VERSION = '__VERSION_NO_PATCH__';
|
||||
videojs.ACCESS_PROTOCOL = ('https:' === document.location.protocol ? 'https://' : 'http://');
|
||||
|
||||
/**
|
||||
* Full player version
|
||||
* @type {string}
|
||||
*/
|
||||
videojs['VERSION'] = '__VERSION__';
|
||||
|
||||
// Set CDN Version of swf
|
||||
// The added (+) blocks the replace from changing this _VERSION_NO_PATCH_ string
|
||||
if (videojs.CDN_VERSION !== '__VERSION_'+'NO_PATCH__') {
|
||||
Options['flash']['swf'] = `${videojs.ACCESS_PROTOCOL}vjs.zencdn.net/${videojs.CDN_VERSION}/video-js.swf`;
|
||||
}
|
||||
|
||||
// Run Auto-load players
|
||||
// You have to wait at least once in case this script is loaded after your video in the DOM (weird behavior only with minified version)
|
||||
setup.autoSetupTimeout(1, videojs);
|
||||
|
||||
videojs.getComponent = Component.getComponent;
|
||||
videojs.registerComponent = Component.registerComponent;
|
||||
/**
|
||||
* Current software version (semver)
|
||||
* @type {String}
|
||||
*/
|
||||
videojs['VERSION'] = '__VERSION__';
|
||||
|
||||
// APIs that will be removed with 5.0, but need them to get tests passing
|
||||
// in ES6 transition
|
||||
videojs.TOUCH_ENABLED = browser.TOUCH_ENABLED;
|
||||
/**
|
||||
* Get the global options object
|
||||
*
|
||||
* @returns {Object} The global options object
|
||||
*/
|
||||
videojs.getGlobalOptions = () => globalOptions;
|
||||
|
||||
// Probably want to keep this one for 5.0?
|
||||
videojs.players = Player.players;
|
||||
|
||||
videojs.extends = extendsFn;
|
||||
|
||||
videojs.mergeOptions = mergeOptions;
|
||||
|
||||
videojs.getGlobalOptions = () => options;
|
||||
/**
|
||||
* Set options that will apply to every player
|
||||
*
|
||||
* videojs.setGlobalOptions({
|
||||
* 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.
|
||||
*
|
||||
* @returns {Object} The updated global options object
|
||||
*/
|
||||
videojs.setGlobalOptions = function(newOptions) {
|
||||
mergeOptions(options, newOptions);
|
||||
return mergeOptions(globalOptions, newOptions);
|
||||
};
|
||||
|
||||
// Set CDN Version of swf
|
||||
const MINOR_VERSION = '__VERSION_NO_PATCH__';
|
||||
const ACCESS_PROTOCOL = ('https:' === document.location.protocol ? 'https://' : 'http://');
|
||||
|
||||
// The added (+) blocks the replace from changing this _VERSION_NO_PATCH_ string
|
||||
if (MINOR_VERSION !== '__VERSION_'+'NO_PATCH__') {
|
||||
globalOptions['flash']['swf'] = `${ACCESS_PROTOCOL}vjs.zencdn.net/${MINOR_VERSION}/video-js.swf`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object with the currently created players, keyed by player ID
|
||||
*
|
||||
* @returns {Object} The created players
|
||||
*/
|
||||
videojs.getPlayers = function() {
|
||||
return Player.players;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a component class object by name
|
||||
*
|
||||
* var VjsButton = videojs.getComponent('Button');
|
||||
*
|
||||
* // Create a new instance of the component
|
||||
* var myButton = new VjsButton(myPlayer);
|
||||
*
|
||||
*/
|
||||
videojs.getComponent = Component.getComponent;
|
||||
|
||||
/**
|
||||
* Register a component so it can referred to by name
|
||||
*
|
||||
* Used when adding to other
|
||||
* components, either through addChild
|
||||
* `component.addChild('myComponent')`
|
||||
* or through default children options
|
||||
* `{ children: ['myComponent'] }`.
|
||||
*
|
||||
* // Get a component to subclass
|
||||
* var VjsButton = videojs.getComponent('Button');
|
||||
*
|
||||
* // Subclass the component (see 'extends' doc for more info)
|
||||
* var MySpecialButton = videojs.extends(VjsButton, {});
|
||||
*
|
||||
* // Register the new component
|
||||
* VjsButton.registerComponent('MySepcialButton', MySepcialButton);
|
||||
*
|
||||
* // (optionally) add the new component as a default player child
|
||||
* myPlayer.addChild('MySepcialButton');
|
||||
*
|
||||
* NOTE: You could also just initialize the component before adding.
|
||||
* `component.addChild(new MyComponent());`
|
||||
*
|
||||
* @param {String} The class name of the component
|
||||
* @param {Component} The component class
|
||||
* @returns {Component} The newly registered component
|
||||
*/
|
||||
videojs.registerComponent = Component.registerComponent;
|
||||
|
||||
/**
|
||||
* A suite of browser and device tests
|
||||
* @type {Object}
|
||||
*/
|
||||
videojs.browser = browser;
|
||||
|
||||
/**
|
||||
* Subclass an existing class
|
||||
* Mimics ES6 subclassing with the `extends` keyword
|
||||
*
|
||||
* // Create a basic javascript 'class'
|
||||
* function MyClass(name){
|
||||
* // Set a property at initialization
|
||||
* this.myName = name;
|
||||
* }
|
||||
*
|
||||
* // Create an instance method
|
||||
* MyClass.prototype.sayMyName = function(){
|
||||
* alert(this.myName);
|
||||
* };
|
||||
*
|
||||
* // Subclass the exisitng class and change the name
|
||||
* // when initializing
|
||||
* var MySubClass = videojs.extends(MyClass, {
|
||||
* constructor: function(name) {
|
||||
* // Call the super class constructor for the subclass
|
||||
* MyClass.call(this, name)
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* // Create an instance of the new sub class
|
||||
* var myInstance = new MySubClass('John');
|
||||
* myInstance.sayMyName(); // -> should alert "John"
|
||||
*
|
||||
* @param {Function} The Class to subclass
|
||||
* @param {Object} An object including instace methods for the new class
|
||||
* Optionally including a `constructor` function
|
||||
*
|
||||
* @returns {Function} The newly created subclass
|
||||
*/
|
||||
videojs.extends = extendsFn;
|
||||
|
||||
/**
|
||||
* Merge two options objects recursively
|
||||
* Performs a deep merge like lodash.merge but **only merges plain objects**
|
||||
* (not arrays, elements, anything else)
|
||||
* Other values will be copied directly from the second object.
|
||||
*
|
||||
* var defaultOptions = {
|
||||
* foo: true,
|
||||
* bar: {
|
||||
* a: true,
|
||||
* b: [1,2,3]
|
||||
* }
|
||||
* };
|
||||
* var newOptions = {
|
||||
* foo: false,
|
||||
* bar: {
|
||||
* b: [4,5,6]
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* var result = videojs.mergeOptions(defaultOptions, newOptions);
|
||||
* // result.foo = false;
|
||||
* // result.bar.a = true;
|
||||
* // result.bar.b = [4,5,6];
|
||||
*
|
||||
* @param {Object} The options object whose values will be overriden
|
||||
* @param {Object} The options object with values to override the first
|
||||
* @param {Object} Any number of additional options objects
|
||||
*
|
||||
* @returns {Object} a new object with the merged values
|
||||
*/
|
||||
videojs.mergeOptions = mergeOptions;
|
||||
|
||||
/**
|
||||
* Create a Video.js player plugin
|
||||
*
|
||||
* Plugins are only initialized when options for the plugin are included
|
||||
* in the player options, or the plugin function on the player instance is
|
||||
* called.
|
||||
*
|
||||
* **See the plugin guide in the docs for a more detailed example**
|
||||
*
|
||||
* // Make a plugin that alerts when the player plays
|
||||
* videojs.plugin('myPlugin', function(myPluginOptions) {
|
||||
* myPluginOptions = myPluginOptions || {};
|
||||
*
|
||||
* var player = this;
|
||||
* var alertText = myPluginOptions.text || 'Player is playing!'
|
||||
*
|
||||
* player.on('play', function(){
|
||||
* alert(alertText);
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* // USAGE EXAMPLES
|
||||
*
|
||||
* // EXAMPLE 1: New player with plugin options, call plugin immediately
|
||||
* var player1 = videojs('idOne', {
|
||||
* myPlugin: {
|
||||
* text: 'Custom text!'
|
||||
* }
|
||||
* });
|
||||
* // Click play
|
||||
* // --> Should alert 'Custom text!'
|
||||
*
|
||||
* // EXAMPLE 3: New player, initialize plugin later
|
||||
* var player3 = videojs('idThree');
|
||||
* // Click play
|
||||
* // --> NO ALERT
|
||||
* // Click pause
|
||||
* // Initialize plugin using the plugin function on the player instance
|
||||
* player3.myPlugin({
|
||||
* text: 'Plugin added later!'
|
||||
* });
|
||||
* // Click play
|
||||
* // --> Should alert 'Plugin added later!'
|
||||
*
|
||||
* @param {String} The plugin name
|
||||
* @param {Function} The plugin function that will be called with options
|
||||
*/
|
||||
videojs.plugin = plugin;
|
||||
|
||||
/**
|
||||
* Utility function for adding languages to the default options. Useful for
|
||||
* amending multiple language support at runtime.
|
||||
* Adding languages so that they're available to all players.
|
||||
*
|
||||
* Example: videojs.addLanguage('es', {'Hello':'Hola'});
|
||||
* videojs.addLanguage('es', { 'Hello': 'Hola' });
|
||||
*
|
||||
* @param {String} code The language code or dictionary property
|
||||
* @param {Object} data The data values to be translated
|
||||
* @return {Object} The resulting global languages dictionary object
|
||||
*
|
||||
* @return {Object} The resulting language dictionary object
|
||||
*/
|
||||
videojs.addLanguage = function(code, data){
|
||||
if(Options['languages'][code] !== undefined) {
|
||||
Options['languages'][code] = mergeOptions(Options['languages'][code], data);
|
||||
} else {
|
||||
Options['languages'][code] = data;
|
||||
}
|
||||
return Options['languages'];
|
||||
return merge(globalOptions.languages, { [code]: data })[code];
|
||||
};
|
||||
|
||||
// REMOVING: We probably should add this to the migration plugin
|
||||
|
@ -153,7 +153,7 @@ test('should export ready api call to public', function() {
|
||||
});
|
||||
|
||||
test('should export useful components to the public', function () {
|
||||
ok(videojs.TOUCH_ENABLED !== undefined, 'Touch detection should be public');
|
||||
ok(videojs.browser.TOUCH_ENABLED !== undefined, 'Touch detection should be public');
|
||||
ok(videojs.getComponent('ControlBar'), 'ControlBar should be public');
|
||||
ok(videojs.getComponent('Button'), 'Button should be public');
|
||||
ok(videojs.getComponent('PlayToggle'), 'PlayToggle should be public');
|
||||
@ -213,7 +213,7 @@ test('should be able to initialize player twice on the same tag using string ref
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
test('videojs.players should be available after minification', function() {
|
||||
test('videojs.getPlayers() should be available after minification', function() {
|
||||
var videoTag = testHelperMakeTag();
|
||||
var id = videoTag.id;
|
||||
|
||||
@ -221,7 +221,7 @@ test('videojs.players should be available after minification', function() {
|
||||
fixture.appendChild(videoTag);
|
||||
|
||||
var player = videojs(id);
|
||||
ok(videojs.players[id] === player, 'videojs.players is available');
|
||||
ok(videojs.getPlayers()[id] === player, 'videojs.getPlayers() is available');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
@ -3,6 +3,7 @@ import * as Dom from '../../src/js/utils/dom.js';
|
||||
import * as Events from '../../src/js/utils/events.js';
|
||||
import * as browser from '../../src/js/utils/browser.js';
|
||||
import document from 'global/document';
|
||||
import TestHelpers from './test-helpers.js';
|
||||
|
||||
q.module('Component', {
|
||||
'setup': function() {
|
||||
@ -97,14 +98,14 @@ test('should do a deep merge of child options', function(){
|
||||
var mergedOptions = comp.options();
|
||||
var children = mergedOptions['example'];
|
||||
|
||||
ok(children['childOne']['foo'] === 'baz', 'value three levels deep overridden');
|
||||
ok(children['childOne']['asdf'] === 'fdsa', 'value three levels deep maintained');
|
||||
ok(children['childOne']['abc'] === '123', 'value three levels deep added');
|
||||
strictEqual(children['childOne']['foo'], 'baz', 'value three levels deep overridden');
|
||||
strictEqual(children['childOne']['asdf'], 'fdsa', 'value three levels deep maintained');
|
||||
strictEqual(children['childOne']['abc'], '123', 'value three levels deep added');
|
||||
ok(children['childTwo'], 'object two levels deep maintained');
|
||||
ok(children['childThree'] === false, 'object two levels deep removed');
|
||||
strictEqual(children['childThree'], false, 'object two levels deep removed');
|
||||
ok(children['childFour'], 'object two levels deep added');
|
||||
|
||||
ok(Component.prototype.options_['example']['childOne']['foo'] === 'bar', 'prototype options were not overridden');
|
||||
strictEqual(Component.prototype.options_['example']['childOne']['foo'], 'bar', 'prototype options were not overridden');
|
||||
|
||||
// Reset default component options to none
|
||||
Component.prototype.options_ = null;
|
||||
@ -165,8 +166,8 @@ test('should dispose of component and children', function(){
|
||||
|
||||
// Add a listener
|
||||
comp.on('click', function(){ return true; });
|
||||
var data = Dom.getData(comp.el());
|
||||
var id = comp.el()[Dom.expando];
|
||||
var el = comp.el();
|
||||
var data = Dom.getElData(el);
|
||||
|
||||
var hasDisposed = false;
|
||||
var bubbles = null;
|
||||
@ -183,8 +184,8 @@ test('should dispose of component and children', function(){
|
||||
ok(!comp.el(), 'component element was deleted');
|
||||
ok(!child.children(), 'child children were deleted');
|
||||
ok(!child.el(), 'child element was deleted');
|
||||
ok(!Dom.cache[id], 'listener cache nulled');
|
||||
ok(!Object.getOwnPropertyNames(data).length, 'original listener cache object was emptied');
|
||||
ok(!Dom.hasElData(el), 'listener data nulled');
|
||||
ok(!Object.getOwnPropertyNames(data).length, 'original listener data object was emptied');
|
||||
});
|
||||
|
||||
test('should add and remove event listeners to element', function(){
|
||||
@ -428,7 +429,7 @@ test('should change the width and height of a component', function(){
|
||||
comp.height('123px');
|
||||
|
||||
ok(comp.width() === 500, 'percent values working');
|
||||
var compStyle = Dom.getComputedDimension(el, 'width');
|
||||
var compStyle = TestHelpers.getComputedStyle(el, 'width');
|
||||
ok(compStyle === comp.width() + 'px', 'matches computed style');
|
||||
ok(comp.height() === 123, 'px values working');
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Player from '../../src/js/player.js';
|
||||
import videojs from '../../src/js/video.js';
|
||||
import Options from '../../src/js/options.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';
|
||||
@ -66,7 +66,7 @@ test('should accept options from multiple sources and override in correct order'
|
||||
// version of the key for all version.
|
||||
|
||||
// Set a global option
|
||||
Options['attr'] = 1;
|
||||
globalOptions['attr'] = 1;
|
||||
|
||||
var tag0 = TestHelpers.makeTag();
|
||||
var player0 = new Player(tag0);
|
||||
@ -92,7 +92,7 @@ test('should accept options from multiple sources and override in correct order'
|
||||
});
|
||||
|
||||
test('should get tag, source, and track settings', function(){
|
||||
// Partially tested in lib->getElementAttributes
|
||||
// Partially tested in lib->getElAttributes
|
||||
|
||||
var fixture = document.getElementById('qunit-fixture');
|
||||
|
||||
@ -752,14 +752,14 @@ test('should be scrubbing while seeking', function(){
|
||||
});
|
||||
|
||||
test('should throw on startup no techs are specified', function() {
|
||||
const techOrder = Options.techOrder;
|
||||
const techOrder = globalOptions.techOrder;
|
||||
|
||||
Options.techOrder = null;
|
||||
globalOptions.techOrder = null;
|
||||
q.throws(function() {
|
||||
videojs(TestHelpers.makeTag());
|
||||
}, 'a falsey techOrder should throw');
|
||||
|
||||
Options.techOrder = techOrder;
|
||||
globalOptions.techOrder = techOrder;
|
||||
});
|
||||
|
||||
test('should have a sensible toJSON that is equivalent to player.options', function() {
|
||||
|
@ -26,16 +26,20 @@ var TestHelpers = {
|
||||
},
|
||||
|
||||
getComputedStyle: function(el, rule){
|
||||
var val;
|
||||
|
||||
if(window.getComputedStyle){
|
||||
val = window.getComputedStyle(el, null).getPropertyValue(rule);
|
||||
// IE8
|
||||
} else if(el.currentStyle){
|
||||
val = el.currentStyle[rule];
|
||||
if (document.defaultView && document.defaultView.getComputedStyle) {
|
||||
return document.defaultView.getComputedStyle(el, null).getPropertyValue(rule);
|
||||
}
|
||||
|
||||
return val;
|
||||
// IE8
|
||||
if (el.currentStyle) {
|
||||
if (rule === 'width' || rule === 'height') {
|
||||
// return clientWidth or clientHeight instead for better accuracy
|
||||
rule = 'client' + rule.substr(0, 1).toUpperCase() + rule.substr(1);
|
||||
return el[rule] + 'px';
|
||||
} else {
|
||||
return el.currentStyle[rule];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import document from 'global/document';
|
||||
import * as Dom from '../../../src/js/utils/dom.js';
|
||||
import TestHelpers from '../test-helpers.js';
|
||||
|
||||
test('should return the element with the ID', function(){
|
||||
var el1 = document.createElement('div');
|
||||
@ -12,8 +13,8 @@ test('should return the element with the ID', function(){
|
||||
el1.id = 'test_id1';
|
||||
el2.id = 'test_id2';
|
||||
|
||||
ok(Dom.el('test_id1') === el1, 'found element for ID');
|
||||
ok(Dom.el('#test_id2') === el2, 'found element for CSS ID');
|
||||
ok(Dom.getEl('test_id1') === el1, 'found element for ID');
|
||||
ok(Dom.getEl('#test_id2') === el2, 'found element for CSS ID');
|
||||
});
|
||||
|
||||
test('should create an element', function(){
|
||||
@ -30,49 +31,47 @@ test('should insert an element first in another', function(){
|
||||
var el2 = document.createElement('div');
|
||||
var parent = document.createElement('div');
|
||||
|
||||
Dom.insertFirst(el1, parent);
|
||||
Dom.insertElFirst(el1, parent);
|
||||
ok(parent.firstChild === el1, 'inserts first into empty parent');
|
||||
|
||||
Dom.insertFirst(el2, parent);
|
||||
Dom.insertElFirst(el2, parent);
|
||||
ok(parent.firstChild === el2, 'inserts first into parent with child');
|
||||
});
|
||||
|
||||
test('should get and remove data from an element', function(){
|
||||
var el = document.createElement('div');
|
||||
var data = Dom.getData(el);
|
||||
var id = el[Dom.expando];
|
||||
var data = Dom.getElData(el);
|
||||
|
||||
ok(typeof data === 'object', 'data object created');
|
||||
|
||||
// Add data
|
||||
var testData = { asdf: 'fdsa' };
|
||||
data.test = testData;
|
||||
ok(Dom.getData(el).test === testData, 'data added');
|
||||
ok(Dom.getElData(el).test === testData, 'data added');
|
||||
|
||||
// Remove all data
|
||||
Dom.removeData(el);
|
||||
Dom.removeElData(el);
|
||||
|
||||
ok(!Dom.cache[id], 'cached item nulled');
|
||||
ok(el[Dom.expando] === null || el[Dom.expando] === undefined, 'element data id removed');
|
||||
ok(!Dom.hasElData(el), 'cached item emptied');
|
||||
});
|
||||
|
||||
test('should add and remove a class name on an element', function(){
|
||||
var el = document.createElement('div');
|
||||
Dom.addClass(el, 'test-class');
|
||||
Dom.addElClass(el, 'test-class');
|
||||
ok(el.className === 'test-class', 'class added');
|
||||
Dom.addClass(el, 'test-class');
|
||||
Dom.addElClass(el, 'test-class');
|
||||
ok(el.className === 'test-class', 'same class not duplicated');
|
||||
Dom.addClass(el, 'test-class2');
|
||||
Dom.addElClass(el, 'test-class2');
|
||||
ok(el.className === 'test-class test-class2', 'added second class');
|
||||
Dom.removeClass(el, 'test-class');
|
||||
Dom.removeElClass(el, 'test-class');
|
||||
ok(el.className === 'test-class2', 'removed first class');
|
||||
});
|
||||
|
||||
test('should read class names on an element', function(){
|
||||
var el = document.createElement('div');
|
||||
Dom.addClass(el, 'test-class1');
|
||||
ok(Dom.hasClass(el, 'test-class1') === true, 'class detected');
|
||||
ok(Dom.hasClass(el, 'test-class') === false, 'substring correctly not detected');
|
||||
Dom.addElClass(el, 'test-class1');
|
||||
ok(Dom.hasElClass(el, 'test-class1') === true, 'class detected');
|
||||
ok(Dom.hasElClass(el, 'test-class') === false, 'substring correctly not detected');
|
||||
});
|
||||
|
||||
test('should set element attributes from object', function(){
|
||||
@ -81,7 +80,7 @@ test('should set element attributes from object', function(){
|
||||
el = document.createElement('div');
|
||||
el.id = 'el1';
|
||||
|
||||
Dom.setElementAttributes(el, { controls: true, 'data-test': 'asdf' });
|
||||
Dom.setElAttributes(el, { controls: true, 'data-test': 'asdf' });
|
||||
|
||||
equal(el.getAttribute('id'), 'el1');
|
||||
equal(el.getAttribute('controls'), '');
|
||||
@ -100,10 +99,10 @@ test('should read tag attributes from elements, including HTML5 in all browsers'
|
||||
|
||||
document.getElementById('qunit-fixture').innerHTML += tags;
|
||||
|
||||
var vid1Vals = Dom.getElementAttributes(document.getElementById('vid1'));
|
||||
var vid2Vals = Dom.getElementAttributes(document.getElementById('vid2'));
|
||||
var sourceVals = Dom.getElementAttributes(document.getElementById('source'));
|
||||
var trackVals = Dom.getElementAttributes(document.getElementById('track'));
|
||||
var vid1Vals = Dom.getElAttributes(document.getElementById('vid1'));
|
||||
var vid2Vals = Dom.getElAttributes(document.getElementById('vid2'));
|
||||
var sourceVals = Dom.getElAttributes(document.getElementById('source'));
|
||||
var trackVals = Dom.getElAttributes(document.getElementById('track'));
|
||||
|
||||
// was using deepEqual, but ie8 would send all properties as attributes
|
||||
|
||||
@ -139,29 +138,9 @@ test('should read tag attributes from elements, including HTML5 in all browsers'
|
||||
equal(trackVals['title'], 'test');
|
||||
});
|
||||
|
||||
test('should get the right style values for an element', function(){
|
||||
var el = document.createElement('div');
|
||||
var container = document.createElement('div');
|
||||
var fixture = document.getElementById('qunit-fixture');
|
||||
|
||||
container.appendChild(el);
|
||||
fixture.appendChild(container);
|
||||
|
||||
container.style.width = '1000px';
|
||||
container.style.height = '1000px';
|
||||
|
||||
el.style.height = '100%';
|
||||
el.style.width = '123px';
|
||||
|
||||
// integer px values may get translated int very-close floats in Chrome/OS X
|
||||
// so round the dimensions to ignore this
|
||||
equal(Math.round(parseFloat(Dom.getComputedDimension(el, 'height'))), 1000, 'the computed height is equal');
|
||||
equal(Math.round(parseFloat(Dom.getComputedDimension(el, 'width'))), 123, 'the computed width is equal');
|
||||
});
|
||||
|
||||
test('Dom.findPosition should find top and left position', function() {
|
||||
test('Dom.findElPosition should find top and left position', function() {
|
||||
const d = document.createElement('div');
|
||||
let position = Dom.findPosition(d);
|
||||
let position = Dom.findElPosition(d);
|
||||
d.style.top = '10px';
|
||||
d.style.left = '20px';
|
||||
d.style.position = 'absolute';
|
||||
@ -169,10 +148,10 @@ test('Dom.findPosition should find top and left position', function() {
|
||||
deepEqual(position, {left: 0, top: 0}, 'If element isn\'t in the DOM, we should get zeros');
|
||||
|
||||
document.body.appendChild(d);
|
||||
position = Dom.findPosition(d);
|
||||
position = Dom.findElPosition(d);
|
||||
deepEqual(position, {left: 20, top: 10}, 'The position was not correct');
|
||||
|
||||
d.getBoundingClientRect = null;
|
||||
position = Dom.findPosition(d);
|
||||
position = Dom.findElPosition(d);
|
||||
deepEqual(position, {left: 0, top: 0}, 'If there is no gBCR, we should get zeros');
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import videojs from '../../src/js/video.js';
|
||||
import TestHelpers from './test-helpers.js';
|
||||
import Player from '../../src/js/player.js';
|
||||
import Options from '../../src/js/options.js';
|
||||
import globalOptions from '../../src/js/global-options.js';
|
||||
import document from 'global/document';
|
||||
|
||||
q.module('video.js');
|
||||
@ -41,9 +41,9 @@ test('should add the value to the languages object', function() {
|
||||
data = {'Hello': 'Hola'};
|
||||
result = videojs.addLanguage(code, data);
|
||||
|
||||
ok(Options['languages'][code], 'should exist');
|
||||
equal(Options['languages'][code], data, 'should match');
|
||||
deepEqual(result[code], Options['languages'][code], 'should also match');
|
||||
ok(globalOptions.languages[code], 'should exist');
|
||||
equal(globalOptions.languages['es']['Hello'], 'Hola', 'should match');
|
||||
deepEqual(result['Hello'], globalOptions.languages['es']['Hello'], 'should also match');
|
||||
});
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user