mirror of
https://github.com/videojs/video.js.git
synced 2025-01-25 11:13:52 +02:00
@misteroneill exposed DOM helpers. closes #2754
This commit is contained in:
parent
cd800b02ea
commit
f2fa8f8687
@ -41,6 +41,7 @@
|
|||||||
"stop",
|
"stop",
|
||||||
"strictEqual",
|
"strictEqual",
|
||||||
"test",
|
"test",
|
||||||
|
"throws",
|
||||||
"sinon"
|
"sinon"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ CHANGELOG
|
|||||||
* @paladox updated grunt-cli dependency ([view](https://github.com/videojs/video.js/pull/2555))
|
* @paladox updated grunt-cli dependency ([view](https://github.com/videojs/video.js/pull/2555))
|
||||||
* @paladox updated grunt-contrib-jshint ([view](https://github.com/videojs/video.js/pull/2554))
|
* @paladox updated grunt-contrib-jshint ([view](https://github.com/videojs/video.js/pull/2554))
|
||||||
* @siebrand updated dutch translations ([view](https://github.com/videojs/video.js/pull/2556))
|
* @siebrand updated dutch translations ([view](https://github.com/videojs/video.js/pull/2556))
|
||||||
|
* @misteroneill exposed DOM helpers ([view](https://github.com/videojs/video.js/pull/2754))
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -830,6 +830,46 @@ class Component {
|
|||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a single DOM element matching `selector` within the component's
|
||||||
|
* `contentEl` or another custom context.
|
||||||
|
*
|
||||||
|
* @method $
|
||||||
|
* @param {String} selector
|
||||||
|
* A valid CSS selector, which will be passed to `querySelector`.
|
||||||
|
*
|
||||||
|
* @param {Element|String} [context=document]
|
||||||
|
* A DOM element within which to query. Can also be a selector
|
||||||
|
* string in which case the first matching element will be used
|
||||||
|
* as context. If missing (or no element matches selector), falls
|
||||||
|
* back to `document`.
|
||||||
|
*
|
||||||
|
* @return {Element|null}
|
||||||
|
*/
|
||||||
|
$(selector, context) {
|
||||||
|
return Dom.$(selector, context || this.contentEl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a all DOM elements matching `selector` within the component's
|
||||||
|
* `contentEl` or another custom context.
|
||||||
|
*
|
||||||
|
* @method $$
|
||||||
|
* @param {String} selector
|
||||||
|
* A valid CSS selector, which will be passed to `querySelectorAll`.
|
||||||
|
*
|
||||||
|
* @param {Element|String} [context=document]
|
||||||
|
* A DOM element within which to query. Can also be a selector
|
||||||
|
* string in which case the first matching element will be used
|
||||||
|
* as context. If missing (or no element matches selector), falls
|
||||||
|
* back to `document`.
|
||||||
|
*
|
||||||
|
* @return {NodeList}
|
||||||
|
*/
|
||||||
|
$$(selector, context) {
|
||||||
|
return Dom.$$(selector, context || this.contentEl());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a component's element has a CSS class name
|
* Check if a component's element has a CSS class name
|
||||||
*
|
*
|
||||||
@ -854,7 +894,7 @@ class Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove and return a CSS class name from the component's element
|
* Remove a CSS class name from the component's element
|
||||||
*
|
*
|
||||||
* @param {String} classToRemove Classname to remove
|
* @param {String} classToRemove Classname to remove
|
||||||
* @return {Component}
|
* @return {Component}
|
||||||
@ -865,6 +905,23 @@ class Component {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add or remove a CSS class name from the component's element
|
||||||
|
*
|
||||||
|
* @param {String} classToToggle
|
||||||
|
* @param {Boolean|Function} [predicate]
|
||||||
|
* Can be a function that returns a Boolean. If `true`, the class
|
||||||
|
* will be added; if `false`, the class will be removed. If not
|
||||||
|
* given, the class will be added if not present and vice versa.
|
||||||
|
*
|
||||||
|
* @return {Component}
|
||||||
|
* @method toggleClass
|
||||||
|
*/
|
||||||
|
toggleClass(classToToggle, predicate) {
|
||||||
|
Dom.toggleElClass(this.el_, classToToggle, predicate);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the component element if hidden
|
* Show the component element if hidden
|
||||||
*
|
*
|
||||||
|
@ -281,8 +281,8 @@ class Player extends Component {
|
|||||||
// of the player in a way that's still overrideable by CSS, just like the
|
// of the player in a way that's still overrideable by CSS, just like the
|
||||||
// video element
|
// video element
|
||||||
this.styleEl_ = stylesheet.createStyleElement('vjs-styles-dimensions');
|
this.styleEl_ = stylesheet.createStyleElement('vjs-styles-dimensions');
|
||||||
let defaultsStyleEl = document.querySelector('.vjs-styles-defaults');
|
let defaultsStyleEl = Dom.$('.vjs-styles-defaults');
|
||||||
let head = document.querySelector('head');
|
let head = Dom.$('head');
|
||||||
head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild);
|
head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild);
|
||||||
|
|
||||||
// Pass in the width/height/aspectRatio options which will update the style el
|
// Pass in the width/height/aspectRatio options which will update the style el
|
||||||
|
@ -771,7 +771,7 @@ class Html5 extends Tech {
|
|||||||
|
|
||||||
this.remoteTextTracks().removeTrack_(track);
|
this.remoteTextTracks().removeTrack_(track);
|
||||||
|
|
||||||
tracks = this.el().querySelectorAll('track');
|
tracks = this.$$('track');
|
||||||
|
|
||||||
i = tracks.length;
|
i = tracks.length;
|
||||||
while (i--) {
|
while (i--) {
|
||||||
|
@ -44,6 +44,8 @@ let trackToJson_ = function(track) {
|
|||||||
* @function textTracksToJson
|
* @function textTracksToJson
|
||||||
*/
|
*/
|
||||||
let textTracksToJson = function(tech) {
|
let textTracksToJson = function(tech) {
|
||||||
|
|
||||||
|
// Cannot use $$ here because it is not an instance of Tech
|
||||||
let trackEls = tech.el().querySelectorAll('track');
|
let trackEls = tech.el().querySelectorAll('track');
|
||||||
|
|
||||||
let trackObjs = Array.prototype.map.call(trackEls, (t) => t.track);
|
let trackObjs = Array.prototype.map.call(trackEls, (t) => t.track);
|
||||||
|
@ -27,33 +27,33 @@ class TextTrackSettings extends Component {
|
|||||||
this.options_.persistTextTrackSettings = this.options_.playerOptions.persistTextTrackSettings;
|
this.options_.persistTextTrackSettings = this.options_.playerOptions.persistTextTrackSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
Events.on(this.el().querySelector('.vjs-done-button'), 'click', Fn.bind(this, function() {
|
Events.on(this.$('.vjs-done-button'), 'click', Fn.bind(this, function() {
|
||||||
this.saveSettings();
|
this.saveSettings();
|
||||||
this.hide();
|
this.hide();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Events.on(this.el().querySelector('.vjs-default-button'), 'click', Fn.bind(this, function() {
|
Events.on(this.$('.vjs-default-button'), 'click', Fn.bind(this, function() {
|
||||||
this.el().querySelector('.vjs-fg-color > select').selectedIndex = 0;
|
this.$('.vjs-fg-color > select').selectedIndex = 0;
|
||||||
this.el().querySelector('.vjs-bg-color > select').selectedIndex = 0;
|
this.$('.vjs-bg-color > select').selectedIndex = 0;
|
||||||
this.el().querySelector('.window-color > select').selectedIndex = 0;
|
this.$('.window-color > select').selectedIndex = 0;
|
||||||
this.el().querySelector('.vjs-text-opacity > select').selectedIndex = 0;
|
this.$('.vjs-text-opacity > select').selectedIndex = 0;
|
||||||
this.el().querySelector('.vjs-bg-opacity > select').selectedIndex = 0;
|
this.$('.vjs-bg-opacity > select').selectedIndex = 0;
|
||||||
this.el().querySelector('.vjs-window-opacity > select').selectedIndex = 0;
|
this.$('.vjs-window-opacity > select').selectedIndex = 0;
|
||||||
this.el().querySelector('.vjs-edge-style select').selectedIndex = 0;
|
this.$('.vjs-edge-style select').selectedIndex = 0;
|
||||||
this.el().querySelector('.vjs-font-family select').selectedIndex = 0;
|
this.$('.vjs-font-family select').selectedIndex = 0;
|
||||||
this.el().querySelector('.vjs-font-percent select').selectedIndex = 2;
|
this.$('.vjs-font-percent select').selectedIndex = 2;
|
||||||
this.updateDisplay();
|
this.updateDisplay();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Events.on(this.el().querySelector('.vjs-fg-color > select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.vjs-fg-color > select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
Events.on(this.el().querySelector('.vjs-bg-color > select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.vjs-bg-color > select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
Events.on(this.el().querySelector('.window-color > select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.window-color > select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
Events.on(this.el().querySelector('.vjs-text-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.vjs-text-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
Events.on(this.el().querySelector('.vjs-bg-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.vjs-bg-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
Events.on(this.el().querySelector('.vjs-window-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.vjs-window-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
Events.on(this.el().querySelector('.vjs-font-percent select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.vjs-font-percent select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
Events.on(this.el().querySelector('.vjs-edge-style select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.vjs-edge-style select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
Events.on(this.el().querySelector('.vjs-font-family select'), 'change', Fn.bind(this, this.updateDisplay));
|
Events.on(this.$('.vjs-font-family select'), 'change', Fn.bind(this, this.updateDisplay));
|
||||||
|
|
||||||
if (this.options_.persistTextTrackSettings) {
|
if (this.options_.persistTextTrackSettings) {
|
||||||
this.restoreSettings();
|
this.restoreSettings();
|
||||||
@ -89,17 +89,15 @@ class TextTrackSettings extends Component {
|
|||||||
* @method getValues
|
* @method getValues
|
||||||
*/
|
*/
|
||||||
getValues() {
|
getValues() {
|
||||||
const el = this.el();
|
const textEdge = getSelectedOptionValue(this.$('.vjs-edge-style select'));
|
||||||
|
const fontFamily = getSelectedOptionValue(this.$('.vjs-font-family select'));
|
||||||
const textEdge = getSelectedOptionValue(el.querySelector('.vjs-edge-style select'));
|
const fgColor = getSelectedOptionValue(this.$('.vjs-fg-color > select'));
|
||||||
const fontFamily = getSelectedOptionValue(el.querySelector('.vjs-font-family select'));
|
const textOpacity = getSelectedOptionValue(this.$('.vjs-text-opacity > select'));
|
||||||
const fgColor = getSelectedOptionValue(el.querySelector('.vjs-fg-color > select'));
|
const bgColor = getSelectedOptionValue(this.$('.vjs-bg-color > select'));
|
||||||
const textOpacity = getSelectedOptionValue(el.querySelector('.vjs-text-opacity > select'));
|
const bgOpacity = getSelectedOptionValue(this.$('.vjs-bg-opacity > select'));
|
||||||
const bgColor = getSelectedOptionValue(el.querySelector('.vjs-bg-color > select'));
|
const windowColor = getSelectedOptionValue(this.$('.window-color > select'));
|
||||||
const bgOpacity = getSelectedOptionValue(el.querySelector('.vjs-bg-opacity > select'));
|
const windowOpacity = getSelectedOptionValue(this.$('.vjs-window-opacity > select'));
|
||||||
const windowColor = getSelectedOptionValue(el.querySelector('.window-color > select'));
|
const fontPercent = window['parseFloat'](getSelectedOptionValue(this.$('.vjs-font-percent > select')));
|
||||||
const windowOpacity = getSelectedOptionValue(el.querySelector('.vjs-window-opacity > select'));
|
|
||||||
const fontPercent = window['parseFloat'](getSelectedOptionValue(el.querySelector('.vjs-font-percent > select')));
|
|
||||||
|
|
||||||
let result = {
|
let result = {
|
||||||
'backgroundOpacity': bgOpacity,
|
'backgroundOpacity': bgOpacity,
|
||||||
@ -136,16 +134,14 @@ class TextTrackSettings extends Component {
|
|||||||
* @method setValues
|
* @method setValues
|
||||||
*/
|
*/
|
||||||
setValues(values) {
|
setValues(values) {
|
||||||
const el = this.el();
|
setSelectedOption(this.$('.vjs-edge-style select'), values.edgeStyle);
|
||||||
|
setSelectedOption(this.$('.vjs-font-family select'), values.fontFamily);
|
||||||
setSelectedOption(el.querySelector('.vjs-edge-style select'), values.edgeStyle);
|
setSelectedOption(this.$('.vjs-fg-color > select'), values.color);
|
||||||
setSelectedOption(el.querySelector('.vjs-font-family select'), values.fontFamily);
|
setSelectedOption(this.$('.vjs-text-opacity > select'), values.textOpacity);
|
||||||
setSelectedOption(el.querySelector('.vjs-fg-color > select'), values.color);
|
setSelectedOption(this.$('.vjs-bg-color > select'), values.backgroundColor);
|
||||||
setSelectedOption(el.querySelector('.vjs-text-opacity > select'), values.textOpacity);
|
setSelectedOption(this.$('.vjs-bg-opacity > select'), values.backgroundOpacity);
|
||||||
setSelectedOption(el.querySelector('.vjs-bg-color > select'), values.backgroundColor);
|
setSelectedOption(this.$('.window-color > select'), values.windowColor);
|
||||||
setSelectedOption(el.querySelector('.vjs-bg-opacity > select'), values.backgroundOpacity);
|
setSelectedOption(this.$('.vjs-window-opacity > select'), values.windowOpacity);
|
||||||
setSelectedOption(el.querySelector('.window-color > select'), values.windowColor);
|
|
||||||
setSelectedOption(el.querySelector('.vjs-window-opacity > select'), values.windowOpacity);
|
|
||||||
|
|
||||||
let fontPercent = values.fontPercent;
|
let fontPercent = values.fontPercent;
|
||||||
|
|
||||||
@ -153,7 +149,7 @@ class TextTrackSettings extends Component {
|
|||||||
fontPercent = fontPercent.toFixed(2);
|
fontPercent = fontPercent.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedOption(el.querySelector('.vjs-font-percent > select'), fontPercent);
|
setSelectedOption(this.$('.vjs-font-percent > select'), fontPercent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,6 +7,59 @@ import * as Guid from './guid.js';
|
|||||||
import log from './log.js';
|
import log from './log.js';
|
||||||
import tsml from 'tsml';
|
import tsml from 'tsml';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if a value is a string with any non-whitespace characters.
|
||||||
|
*
|
||||||
|
* @param {String} str
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
function isNonBlankString(str) {
|
||||||
|
return typeof str === 'string' && /\S/.test(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an error if the passed string has whitespace. This is used by
|
||||||
|
* class methods to be relatively consistent with the classList API.
|
||||||
|
*
|
||||||
|
* @param {String} str
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
function throwIfWhitespace(str) {
|
||||||
|
if (/\s/.test(str)) {
|
||||||
|
throw new Error('class has illegal whitespace characters');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce a regular expression for matching a class name.
|
||||||
|
*
|
||||||
|
* @param {String} className
|
||||||
|
* @return {RegExp}
|
||||||
|
*/
|
||||||
|
function classRegExp(className) {
|
||||||
|
return new RegExp('(^|\\s)' + className + '($|\\s)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates functions to query the DOM using a given method.
|
||||||
|
*
|
||||||
|
* @function createQuerier
|
||||||
|
* @private
|
||||||
|
* @param {String} method
|
||||||
|
* @return {Function}
|
||||||
|
*/
|
||||||
|
function createQuerier(method) {
|
||||||
|
return function (selector, context) {
|
||||||
|
if (!isNonBlankString(selector)) {
|
||||||
|
return document[method](null);
|
||||||
|
}
|
||||||
|
if (isNonBlankString(context)) {
|
||||||
|
context = document.querySelector(context);
|
||||||
|
}
|
||||||
|
return (isEl(context) ? context : document)[method](selector);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shorthand for document.getElementById()
|
* Shorthand for document.getElementById()
|
||||||
* Also allows for CSS (jQuery) ID syntax. But nothing other than IDs.
|
* Also allows for CSS (jQuery) ID syntax. But nothing other than IDs.
|
||||||
@ -181,47 +234,99 @@ export function removeElData(el) {
|
|||||||
/**
|
/**
|
||||||
* Check if an element has a CSS class
|
* Check if an element has a CSS class
|
||||||
*
|
*
|
||||||
|
* @function hasElClass
|
||||||
* @param {Element} element Element to check
|
* @param {Element} element Element to check
|
||||||
* @param {String} classToCheck Classname to check
|
* @param {String} classToCheck Classname to check
|
||||||
* @function hasElClass
|
|
||||||
*/
|
*/
|
||||||
export function hasElClass(element, classToCheck) {
|
export function hasElClass(element, classToCheck) {
|
||||||
return ((' ' + element.className + ' ').indexOf(' ' + classToCheck + ' ') !== -1);
|
if (element.classList) {
|
||||||
|
return element.classList.contains(classToCheck);
|
||||||
|
} else {
|
||||||
|
throwIfWhitespace(classToCheck);
|
||||||
|
return classRegExp(classToCheck).test(element.className);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a CSS class name to an element
|
* Add a CSS class name to an element
|
||||||
*
|
*
|
||||||
|
* @function addElClass
|
||||||
* @param {Element} element Element to add class name to
|
* @param {Element} element Element to add class name to
|
||||||
* @param {String} classToAdd Classname to add
|
* @param {String} classToAdd Classname to add
|
||||||
* @function addElClass
|
|
||||||
*/
|
*/
|
||||||
export function addElClass(element, classToAdd) {
|
export function addElClass(element, classToAdd) {
|
||||||
if (!hasElClass(element, classToAdd)) {
|
if (element.classList) {
|
||||||
element.className = element.className === '' ? classToAdd : element.className + ' ' + classToAdd;
|
element.classList.add(classToAdd);
|
||||||
|
|
||||||
|
// Don't need to `throwIfWhitespace` here because `hasElClass` will do it
|
||||||
|
// in the case of classList not being supported.
|
||||||
|
} else if (!hasElClass(element, classToAdd)) {
|
||||||
|
element.className = (element.className + ' ' + classToAdd).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a CSS class name from an element
|
* Remove a CSS class name from an element
|
||||||
*
|
*
|
||||||
|
* @function removeElClass
|
||||||
* @param {Element} element Element to remove from class name
|
* @param {Element} element Element to remove from class name
|
||||||
* @param {String} classToRemove Classname to remove
|
* @param {String} classToRemove Classname to remove
|
||||||
* @function removeElClass
|
|
||||||
*/
|
*/
|
||||||
export function removeElClass(element, classToRemove) {
|
export function removeElClass(element, classToRemove) {
|
||||||
if (!hasElClass(element, classToRemove)) {return;}
|
if (element.classList) {
|
||||||
|
element.classList.remove(classToRemove);
|
||||||
let classNames = element.className.split(' ');
|
} else {
|
||||||
|
throwIfWhitespace(classToRemove);
|
||||||
// no arr.indexOf in ie8, and we don't want to add a big shim
|
element.className = element.className.split(/\s+/).filter(function(c) {
|
||||||
for (let i = classNames.length - 1; i >= 0; i--) {
|
return c !== classToRemove;
|
||||||
if (classNames[i] === classToRemove) {
|
}).join(' ');
|
||||||
classNames.splice(i,1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
element.className = classNames.join(' ');
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds or removes a CSS class name on an element depending on an optional
|
||||||
|
* condition or the presence/absence of the class name.
|
||||||
|
*
|
||||||
|
* @function toggleElClass
|
||||||
|
* @param {Element} element
|
||||||
|
* @param {String} classToToggle
|
||||||
|
* @param {Boolean|Function} [predicate]
|
||||||
|
* Can be a function that returns a Boolean. If `true`, the class
|
||||||
|
* will be added; if `false`, the class will be removed. If not
|
||||||
|
* given, the class will be added if not present and vice versa.
|
||||||
|
*/
|
||||||
|
export function toggleElClass(element, classToToggle, predicate) {
|
||||||
|
|
||||||
|
// This CANNOT use `classList` internally because IE does not support the
|
||||||
|
// second parameter to the `classList.toggle()` method! Which is fine because
|
||||||
|
// `classList` will be used by the add/remove functions.
|
||||||
|
let has = hasElClass(element, classToToggle);
|
||||||
|
|
||||||
|
if (typeof predicate === 'function') {
|
||||||
|
predicate = predicate(element, classToToggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof predicate !== 'boolean') {
|
||||||
|
predicate = !has;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the necessary class operation matches the current state of the
|
||||||
|
// element, no action is required.
|
||||||
|
if (predicate === has) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicate) {
|
||||||
|
addElClass(element, classToToggle);
|
||||||
|
} else {
|
||||||
|
removeElClass(element, classToToggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -292,7 +397,7 @@ export function getElAttributes(tag) {
|
|||||||
* Attempt to block the ability to select text while dragging controls
|
* Attempt to block the ability to select text while dragging controls
|
||||||
*
|
*
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @method blockTextSelection
|
* @function blockTextSelection
|
||||||
*/
|
*/
|
||||||
export function blockTextSelection() {
|
export function blockTextSelection() {
|
||||||
document.body.focus();
|
document.body.focus();
|
||||||
@ -305,7 +410,7 @@ export function blockTextSelection() {
|
|||||||
* Turn off text selection blocking
|
* Turn off text selection blocking
|
||||||
*
|
*
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @method unblockTextSelection
|
* @function unblockTextSelection
|
||||||
*/
|
*/
|
||||||
export function unblockTextSelection() {
|
export function unblockTextSelection() {
|
||||||
document.onselectstart = function() {
|
document.onselectstart = function() {
|
||||||
@ -318,9 +423,9 @@ export function unblockTextSelection() {
|
|||||||
* getBoundingClientRect technique from
|
* getBoundingClientRect technique from
|
||||||
* John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/
|
* John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/
|
||||||
*
|
*
|
||||||
|
* @function findElPosition
|
||||||
* @param {Element} el Element from which to get offset
|
* @param {Element} el Element from which to get offset
|
||||||
* @return {Object=}
|
* @return {Object}
|
||||||
* @method findElPosition
|
|
||||||
*/
|
*/
|
||||||
export function findElPosition(el) {
|
export function findElPosition(el) {
|
||||||
let box;
|
let box;
|
||||||
@ -359,10 +464,10 @@ export function findElPosition(el) {
|
|||||||
* Returns an object with x and y coordinates.
|
* Returns an object with x and y coordinates.
|
||||||
* The base on the coordinates are the bottom left of the element.
|
* The base on the coordinates are the bottom left of the element.
|
||||||
*
|
*
|
||||||
|
* @function getPointerPosition
|
||||||
* @param {Element} el Element on which to get the pointer position on
|
* @param {Element} el Element on which to get the pointer position on
|
||||||
* @param {Event} event Event object
|
* @param {Event} event Event object
|
||||||
* @return {Object=} position This object will have x and y coordinates corresponding to the mouse position
|
* @return {Object} This object will have x and y coordinates corresponding to the mouse position
|
||||||
* @metho getPointerPosition
|
|
||||||
*/
|
*/
|
||||||
export function getPointerPosition(el, event) {
|
export function getPointerPosition(el, event) {
|
||||||
let position = {};
|
let position = {};
|
||||||
@ -389,8 +494,9 @@ export function getPointerPosition(el, event) {
|
|||||||
/**
|
/**
|
||||||
* Determines, via duck typing, whether or not a value is a DOM element.
|
* Determines, via duck typing, whether or not a value is a DOM element.
|
||||||
*
|
*
|
||||||
* @param {Mixed} value
|
* @function isEl
|
||||||
* @return {Boolean}
|
* @param {Mixed} value
|
||||||
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
export function isEl(value) {
|
export function isEl(value) {
|
||||||
return !!value && typeof value === 'object' && value.nodeType === 1;
|
return !!value && typeof value === 'object' && value.nodeType === 1;
|
||||||
@ -427,18 +533,25 @@ export function emptyEl(el) {
|
|||||||
* from falling into the trap of simply writing to `innerHTML`, which is
|
* from falling into the trap of simply writing to `innerHTML`, which is
|
||||||
* an XSS concern.
|
* an XSS concern.
|
||||||
*
|
*
|
||||||
* The content for an element can be passed in multiple types, whose
|
* The content for an element can be passed in multiple types and
|
||||||
* behavior is as follows:
|
* combinations, whose behavior is as follows:
|
||||||
*
|
*
|
||||||
* - String: Normalized into a text node.
|
* - String
|
||||||
* - Node: An Element or TextNode is passed through.
|
* Normalized into a text node.
|
||||||
* - Array: A one-dimensional array of strings, nodes, or functions (which
|
*
|
||||||
* return single strings or nodes).
|
* - Element, TextNode
|
||||||
* - Function: If the sole argument, is expected to produce a string, node,
|
* Passed through.
|
||||||
* or array.
|
*
|
||||||
|
* - Array
|
||||||
|
* A one-dimensional array of strings, elements, nodes, or functions (which
|
||||||
|
* return single strings, elements, or nodes).
|
||||||
|
*
|
||||||
|
* - Function
|
||||||
|
* If the sole argument, is expected to produce a string, element,
|
||||||
|
* node, or array.
|
||||||
*
|
*
|
||||||
* @function normalizeContent
|
* @function normalizeContent
|
||||||
* @param {String|Element|Array|Function} content
|
* @param {String|Element|TextNode|Array|Function} content
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
export function normalizeContent(content) {
|
export function normalizeContent(content) {
|
||||||
@ -474,7 +587,8 @@ export function normalizeContent(content) {
|
|||||||
*
|
*
|
||||||
* @function appendContent
|
* @function appendContent
|
||||||
* @param {Element} el
|
* @param {Element} el
|
||||||
* @param {String|Element|Array|Function} content
|
* @param {String|Element|TextNode|Array|Function} content
|
||||||
|
* See: `normalizeContent`
|
||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
export function appendContent(el, content) {
|
export function appendContent(el, content) {
|
||||||
@ -488,9 +602,46 @@ export function appendContent(el, content) {
|
|||||||
*
|
*
|
||||||
* @function insertContent
|
* @function insertContent
|
||||||
* @param {Element} el
|
* @param {Element} el
|
||||||
* @param {String|Element|Array|Function} content
|
* @param {String|Element|TextNode|Array|Function} content
|
||||||
|
* See: `normalizeContent`
|
||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
export function insertContent(el, content) {
|
export function insertContent(el, content) {
|
||||||
return appendContent(emptyEl(el), content);
|
return appendContent(emptyEl(el), content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a single DOM element matching `selector` within the optional
|
||||||
|
* `context` of another DOM element (defaulting to `document`).
|
||||||
|
*
|
||||||
|
* @function $
|
||||||
|
* @param {String} selector
|
||||||
|
* A valid CSS selector, which will be passed to `querySelector`.
|
||||||
|
*
|
||||||
|
* @param {Element|String} [context=document]
|
||||||
|
* A DOM element within which to query. Can also be a selector
|
||||||
|
* string in which case the first matching element will be used
|
||||||
|
* as context. If missing (or no element matches selector), falls
|
||||||
|
* back to `document`.
|
||||||
|
*
|
||||||
|
* @return {Element|null}
|
||||||
|
*/
|
||||||
|
export const $ = createQuerier('querySelector');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a all DOM elements matching `selector` within the optional
|
||||||
|
* `context` of another DOM element (defaulting to `document`).
|
||||||
|
*
|
||||||
|
* @function $$
|
||||||
|
* @param {String} selector
|
||||||
|
* A valid CSS selector, which will be passed to `querySelectorAll`.
|
||||||
|
*
|
||||||
|
* @param {Element|String} [context=document]
|
||||||
|
* A DOM element within which to query. Can also be a selector
|
||||||
|
* string in which case the first matching element will be used
|
||||||
|
* as context. If missing (or no element matches selector), falls
|
||||||
|
* back to `document`.
|
||||||
|
*
|
||||||
|
* @return {NodeList}
|
||||||
|
*/
|
||||||
|
export const $$ = createQuerier('querySelectorAll');
|
||||||
|
163
src/js/video.js
163
src/js/video.js
@ -99,10 +99,10 @@ var videojs = function(id, options, ready){
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Add default styles
|
// Add default styles
|
||||||
let style = document.querySelector('.vjs-styles-defaults');
|
let style = Dom.$('.vjs-styles-defaults');
|
||||||
if (!style) {
|
if (!style) {
|
||||||
style = stylesheet.createStyleElement('vjs-styles-defaults');
|
style = stylesheet.createStyleElement('vjs-styles-defaults');
|
||||||
let head = document.querySelector('head');
|
let head = Dom.$('head');
|
||||||
head.insertBefore(style, head.firstChild);
|
head.insertBefore(style, head.firstChild);
|
||||||
stylesheet.setTextContent(style, `
|
stylesheet.setTextContent(style, `
|
||||||
.video-js {
|
.video-js {
|
||||||
@ -545,22 +545,149 @@ videojs.xhr = xhr;
|
|||||||
*/
|
*/
|
||||||
videojs.TextTrack = TextTrack;
|
videojs.TextTrack = TextTrack;
|
||||||
|
|
||||||
// REMOVING: We probably should add this to the migration plugin
|
/**
|
||||||
// // Expose but deprecate the window[componentName] method for accessing components
|
* Determines, via duck typing, whether or not a value is a DOM element.
|
||||||
// Object.getOwnPropertyNames(Component.components).forEach(function(name){
|
*
|
||||||
// let component = Component.components[name];
|
* @method isEl
|
||||||
//
|
* @param {Mixed} value
|
||||||
// // A deprecation warning as the constuctor
|
* @return {Boolean}
|
||||||
// module.exports[name] = function(player, options, ready){
|
*/
|
||||||
// log.warn('Using videojs.'+name+' to access the '+name+' component has been deprecated. Please use videojs.getComponent("componentName")');
|
videojs.isEl = Dom.isEl;
|
||||||
//
|
|
||||||
// return new Component(player, options, ready);
|
/**
|
||||||
// };
|
* Determines, via duck typing, whether or not a value is a text node.
|
||||||
//
|
*
|
||||||
// // Allow the prototype and class methods to be accessible still this way
|
* @method isTextNode
|
||||||
// // Though anything that attempts to override class methods will no longer work
|
* @param {Mixed} value
|
||||||
// assign(module.exports[name], component);
|
* @return {Boolean}
|
||||||
// });
|
*/
|
||||||
|
videojs.isTextNode = Dom.isTextNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an element has a CSS class
|
||||||
|
*
|
||||||
|
* @method hasClass
|
||||||
|
* @param {Element} element Element to check
|
||||||
|
* @param {String} classToCheck Classname to check
|
||||||
|
*/
|
||||||
|
videojs.hasClass = Dom.hasElClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a CSS class name to an element
|
||||||
|
*
|
||||||
|
* @method addClass
|
||||||
|
* @param {Element} element Element to add class name to
|
||||||
|
* @param {String} classToAdd Classname to add
|
||||||
|
*/
|
||||||
|
videojs.addClass = Dom.addElClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a CSS class name from an element
|
||||||
|
*
|
||||||
|
* @method removeClass
|
||||||
|
* @param {Element} element Element to remove from class name
|
||||||
|
* @param {String} classToRemove Classname to remove
|
||||||
|
*/
|
||||||
|
videojs.removeClass = Dom.removeElClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds or removes a CSS class name on an element depending on an optional
|
||||||
|
* condition or the presence/absence of the class name.
|
||||||
|
*
|
||||||
|
* @method toggleElClass
|
||||||
|
* @param {Element} element
|
||||||
|
* @param {String} classToToggle
|
||||||
|
* @param {Boolean|Function} [predicate]
|
||||||
|
* Can be a function that returns a Boolean. If `true`, the class
|
||||||
|
* will be added; if `false`, the class will be removed. If not
|
||||||
|
* given, the class will be added if not present and vice versa.
|
||||||
|
*/
|
||||||
|
videojs.toggleClass = Dom.toggleElClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply attributes to an HTML element.
|
||||||
|
*
|
||||||
|
* @method setAttributes
|
||||||
|
* @param {Element} el Target element.
|
||||||
|
* @param {Object=} attributes Element attributes to be applied.
|
||||||
|
*/
|
||||||
|
videojs.setAttributes = Dom.setElAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an element's attribute values, as defined on the HTML tag
|
||||||
|
* Attributes are not the same as properties. They're defined on the tag
|
||||||
|
* or with setAttribute (which shouldn't be used with HTML)
|
||||||
|
* This will return true or false for boolean attributes.
|
||||||
|
*
|
||||||
|
* @method getAttributes
|
||||||
|
* @param {Element} tag Element from which to get tag attributes
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
videojs.getAttributes = Dom.getElAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empties the contents of an element.
|
||||||
|
*
|
||||||
|
* @method emptyEl
|
||||||
|
* @param {Element} el
|
||||||
|
* @return {Element}
|
||||||
|
*/
|
||||||
|
videojs.emptyEl = Dom.emptyEl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes and appends content to an element.
|
||||||
|
*
|
||||||
|
* The content for an element can be passed in multiple types and
|
||||||
|
* combinations, whose behavior is as follows:
|
||||||
|
*
|
||||||
|
* - String
|
||||||
|
* Normalized into a text node.
|
||||||
|
*
|
||||||
|
* - Element, TextNode
|
||||||
|
* Passed through.
|
||||||
|
*
|
||||||
|
* - Array
|
||||||
|
* A one-dimensional array of strings, elements, nodes, or functions (which
|
||||||
|
* return single strings, elements, or nodes).
|
||||||
|
*
|
||||||
|
* - Function
|
||||||
|
* If the sole argument, is expected to produce a string, element,
|
||||||
|
* node, or array.
|
||||||
|
*
|
||||||
|
* @method appendContent
|
||||||
|
* @param {Element} el
|
||||||
|
* @param {String|Element|TextNode|Array|Function} content
|
||||||
|
* @return {Element}
|
||||||
|
*/
|
||||||
|
videojs.appendContent = Dom.appendContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes and inserts content into an element; this is identical to
|
||||||
|
* `appendContent()`, except it empties the element first.
|
||||||
|
*
|
||||||
|
* The content for an element can be passed in multiple types and
|
||||||
|
* combinations, whose behavior is as follows:
|
||||||
|
*
|
||||||
|
* - String
|
||||||
|
* Normalized into a text node.
|
||||||
|
*
|
||||||
|
* - Element, TextNode
|
||||||
|
* Passed through.
|
||||||
|
*
|
||||||
|
* - Array
|
||||||
|
* A one-dimensional array of strings, elements, nodes, or functions (which
|
||||||
|
* return single strings, elements, or nodes).
|
||||||
|
*
|
||||||
|
* - Function
|
||||||
|
* If the sole argument, is expected to produce a string, element,
|
||||||
|
* node, or array.
|
||||||
|
*
|
||||||
|
* @method insertContent
|
||||||
|
* @param {Element} el
|
||||||
|
* @param {String|Element|TextNode|Array|Function} content
|
||||||
|
* @return {Element}
|
||||||
|
*/
|
||||||
|
videojs.insertContent = Dom.insertContent;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Custom Universal Module Definition (UMD)
|
* Custom Universal Module Definition (UMD)
|
||||||
|
@ -471,6 +471,10 @@ test('should add and remove a CSS class', function(){
|
|||||||
ok(comp.el().className.indexOf('test-class') !== -1);
|
ok(comp.el().className.indexOf('test-class') !== -1);
|
||||||
comp.removeClass('test-class');
|
comp.removeClass('test-class');
|
||||||
ok(comp.el().className.indexOf('test-class') === -1);
|
ok(comp.el().className.indexOf('test-class') === -1);
|
||||||
|
comp.toggleClass('test-class');
|
||||||
|
ok(comp.el().className.indexOf('test-class') !== -1);
|
||||||
|
comp.toggleClass('test-class');
|
||||||
|
ok(comp.el().className.indexOf('test-class') === -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show and hide an element', function(){
|
test('should show and hide an element', function(){
|
||||||
@ -695,3 +699,18 @@ test('should provide interval methods that automatically get cleared on componen
|
|||||||
|
|
||||||
ok(intervalsFired === 5, 'Interval was cleared when component was disposed');
|
ok(intervalsFired === 5, 'Interval was cleared when component was disposed');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('$ and $$ functions', function() {
|
||||||
|
var comp = new Component(getFakePlayer());
|
||||||
|
var contentEl = document.createElement('div');
|
||||||
|
var children = [
|
||||||
|
document.createElement('div'),
|
||||||
|
document.createElement('div')
|
||||||
|
];
|
||||||
|
|
||||||
|
comp.contentEl_ = contentEl;
|
||||||
|
children.forEach(child => contentEl.appendChild(child));
|
||||||
|
|
||||||
|
strictEqual(comp.$('div'), children[0], '$ defaults to contentEl as scope');
|
||||||
|
strictEqual(comp.$$('div').length, children.length, '$$ defaults to contentEl as scope');
|
||||||
|
});
|
||||||
|
@ -35,17 +35,17 @@ test('should update settings', function() {
|
|||||||
player.textTrackSettings.setValues(newSettings);
|
player.textTrackSettings.setValues(newSettings);
|
||||||
deepEqual(player.textTrackSettings.getValues(), newSettings, 'values are updated');
|
deepEqual(player.textTrackSettings.getValues(), newSettings, 'values are updated');
|
||||||
|
|
||||||
equal(player.el().querySelector('.vjs-fg-color > select').selectedIndex, 1, 'fg-color is set to new value');
|
equal(player.$('.vjs-fg-color > select').selectedIndex, 1, 'fg-color is set to new value');
|
||||||
equal(player.el().querySelector('.vjs-bg-color > select').selectedIndex, 1, 'bg-color is set to new value');
|
equal(player.$('.vjs-bg-color > select').selectedIndex, 1, 'bg-color is set to new value');
|
||||||
equal(player.el().querySelector('.window-color > select').selectedIndex, 1, 'window-color is set to new value');
|
equal(player.$('.window-color > select').selectedIndex, 1, 'window-color is set to new value');
|
||||||
equal(player.el().querySelector('.vjs-text-opacity > select').selectedIndex, 1, 'text-opacity is set to new value');
|
equal(player.$('.vjs-text-opacity > select').selectedIndex, 1, 'text-opacity is set to new value');
|
||||||
equal(player.el().querySelector('.vjs-bg-opacity > select').selectedIndex, 1, 'bg-opacity is set to new value');
|
equal(player.$('.vjs-bg-opacity > select').selectedIndex, 1, 'bg-opacity is set to new value');
|
||||||
equal(player.el().querySelector('.vjs-window-opacity > select').selectedIndex, 1, 'window-opacity is set to new value');
|
equal(player.$('.vjs-window-opacity > select').selectedIndex, 1, 'window-opacity is set to new value');
|
||||||
equal(player.el().querySelector('.vjs-edge-style select').selectedIndex, 1, 'edge-style is set to new value');
|
equal(player.$('.vjs-edge-style select').selectedIndex, 1, 'edge-style is set to new value');
|
||||||
equal(player.el().querySelector('.vjs-font-family select').selectedIndex, 1, 'font-family is set to new value');
|
equal(player.$('.vjs-font-family select').selectedIndex, 1, 'font-family is set to new value');
|
||||||
equal(player.el().querySelector('.vjs-font-percent select').selectedIndex, 3, 'font-percent is set to new value');
|
equal(player.$('.vjs-font-percent select').selectedIndex, 3, 'font-percent is set to new value');
|
||||||
|
|
||||||
Events.trigger(player.el().querySelector('.vjs-done-button'), 'click');
|
Events.trigger(player.$('.vjs-done-button'), 'click');
|
||||||
deepEqual(safeParseTuple(window.localStorage.getItem('vjs-text-track-settings'))[1], newSettings, 'values are saved');
|
deepEqual(safeParseTuple(window.localStorage.getItem('vjs-text-track-settings'))[1], newSettings, 'values are saved');
|
||||||
|
|
||||||
player.dispose();
|
player.dispose();
|
||||||
@ -57,32 +57,32 @@ test('should restore default settings', function() {
|
|||||||
persistTextTrackSettings: true
|
persistTextTrackSettings: true
|
||||||
});
|
});
|
||||||
|
|
||||||
player.el().querySelector('.vjs-fg-color > select').selectedIndex = 1;
|
player.$('.vjs-fg-color > select').selectedIndex = 1;
|
||||||
player.el().querySelector('.vjs-bg-color > select').selectedIndex = 1;
|
player.$('.vjs-bg-color > select').selectedIndex = 1;
|
||||||
player.el().querySelector('.window-color > select').selectedIndex = 1;
|
player.$('.window-color > select').selectedIndex = 1;
|
||||||
player.el().querySelector('.vjs-text-opacity > select').selectedIndex = 1;
|
player.$('.vjs-text-opacity > select').selectedIndex = 1;
|
||||||
player.el().querySelector('.vjs-bg-opacity > select').selectedIndex = 1;
|
player.$('.vjs-bg-opacity > select').selectedIndex = 1;
|
||||||
player.el().querySelector('.vjs-window-opacity > select').selectedIndex = 1;
|
player.$('.vjs-window-opacity > select').selectedIndex = 1;
|
||||||
player.el().querySelector('.vjs-edge-style select').selectedIndex = 1;
|
player.$('.vjs-edge-style select').selectedIndex = 1;
|
||||||
player.el().querySelector('.vjs-font-family select').selectedIndex = 1;
|
player.$('.vjs-font-family select').selectedIndex = 1;
|
||||||
player.el().querySelector('.vjs-font-percent select').selectedIndex = 3;
|
player.$('.vjs-font-percent select').selectedIndex = 3;
|
||||||
|
|
||||||
Events.trigger(player.el().querySelector('.vjs-done-button'), 'click');
|
Events.trigger(player.$('.vjs-done-button'), 'click');
|
||||||
Events.trigger(player.el().querySelector('.vjs-default-button'), 'click');
|
Events.trigger(player.$('.vjs-default-button'), 'click');
|
||||||
Events.trigger(player.el().querySelector('.vjs-done-button'), 'click');
|
Events.trigger(player.$('.vjs-done-button'), 'click');
|
||||||
|
|
||||||
deepEqual(player.textTrackSettings.getValues(), {}, 'values are defaulted');
|
deepEqual(player.textTrackSettings.getValues(), {}, 'values are defaulted');
|
||||||
deepEqual(window.localStorage.getItem('vjs-text-track-settings'), null, 'values are saved');
|
deepEqual(window.localStorage.getItem('vjs-text-track-settings'), null, 'values are saved');
|
||||||
|
|
||||||
equal(player.el().querySelector('.vjs-fg-color > select').selectedIndex, 0, 'fg-color is set to default value');
|
equal(player.$('.vjs-fg-color > select').selectedIndex, 0, 'fg-color is set to default value');
|
||||||
equal(player.el().querySelector('.vjs-bg-color > select').selectedIndex, 0, 'bg-color is set to default value');
|
equal(player.$('.vjs-bg-color > select').selectedIndex, 0, 'bg-color is set to default value');
|
||||||
equal(player.el().querySelector('.window-color > select').selectedIndex, 0, 'window-color is set to default value');
|
equal(player.$('.window-color > select').selectedIndex, 0, 'window-color is set to default value');
|
||||||
equal(player.el().querySelector('.vjs-text-opacity > select').selectedIndex, 0, 'text-opacity is set to default value');
|
equal(player.$('.vjs-text-opacity > select').selectedIndex, 0, 'text-opacity is set to default value');
|
||||||
equal(player.el().querySelector('.vjs-bg-opacity > select').selectedIndex, 0, 'bg-opacity is set to default value');
|
equal(player.$('.vjs-bg-opacity > select').selectedIndex, 0, 'bg-opacity is set to default value');
|
||||||
equal(player.el().querySelector('.vjs-window-opacity > select').selectedIndex, 0, 'window-opacity is set to default value');
|
equal(player.$('.vjs-window-opacity > select').selectedIndex, 0, 'window-opacity is set to default value');
|
||||||
equal(player.el().querySelector('.vjs-edge-style select').selectedIndex, 0, 'edge-style is set to default value');
|
equal(player.$('.vjs-edge-style select').selectedIndex, 0, 'edge-style is set to default value');
|
||||||
equal(player.el().querySelector('.vjs-font-family select').selectedIndex, 0, 'font-family is set to default value');
|
equal(player.$('.vjs-font-family select').selectedIndex, 0, 'font-family is set to default value');
|
||||||
equal(player.el().querySelector('.vjs-font-percent select').selectedIndex, 2, 'font-percent is set to default value');
|
equal(player.$('.vjs-font-percent select').selectedIndex, 2, 'font-percent is set to default value');
|
||||||
|
|
||||||
player.dispose();
|
player.dispose();
|
||||||
});
|
});
|
||||||
@ -91,7 +91,7 @@ test('should open on click', function() {
|
|||||||
var player = TestHelpers.makePlayer({
|
var player = TestHelpers.makePlayer({
|
||||||
tracks: tracks
|
tracks: tracks
|
||||||
});
|
});
|
||||||
Events.trigger(player.el().querySelector('.vjs-texttrack-settings'), 'click');
|
Events.trigger(player.$('.vjs-texttrack-settings'), 'click');
|
||||||
ok(!player.textTrackSettings.hasClass('vjs-hidden'), 'settings open');
|
ok(!player.textTrackSettings.hasClass('vjs-hidden'), 'settings open');
|
||||||
|
|
||||||
player.dispose();
|
player.dispose();
|
||||||
@ -101,8 +101,8 @@ test('should close on done click', function() {
|
|||||||
var player = TestHelpers.makePlayer({
|
var player = TestHelpers.makePlayer({
|
||||||
tracks: tracks
|
tracks: tracks
|
||||||
});
|
});
|
||||||
Events.trigger(player.el().querySelector('.vjs-texttrack-settings'), 'click');
|
Events.trigger(player.$('.vjs-texttrack-settings'), 'click');
|
||||||
Events.trigger(player.el().querySelector('.vjs-done-button'), 'click');
|
Events.trigger(player.$('.vjs-done-button'), 'click');
|
||||||
ok(player.textTrackSettings.hasClass('vjs-hidden'), 'settings closed');
|
ok(player.textTrackSettings.hasClass('vjs-hidden'), 'settings closed');
|
||||||
|
|
||||||
player.dispose();
|
player.dispose();
|
||||||
@ -141,7 +141,7 @@ test('if persist option is set, save settings when "done"', function() {
|
|||||||
save++;
|
save++;
|
||||||
};
|
};
|
||||||
|
|
||||||
Events.trigger(player.el().querySelector('.vjs-done-button'), 'click');
|
Events.trigger(player.$('.vjs-done-button'), 'click');
|
||||||
|
|
||||||
equal(save, 1, 'save was called');
|
equal(save, 1, 'save was called');
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ test('do not try to restore or save settings if persist option is not set', func
|
|||||||
|
|
||||||
equal(restore, 0, 'restore was not called');
|
equal(restore, 0, 'restore was not called');
|
||||||
|
|
||||||
Events.trigger(player.el().querySelector('.vjs-done-button'), 'click');
|
Events.trigger(player.$('.vjs-done-button'), 'click');
|
||||||
|
|
||||||
// saveSettings is called but does nothing
|
// saveSettings is called but does nothing
|
||||||
equal(save, 1, 'save was not called');
|
equal(save, 1, 'save was not called');
|
||||||
|
@ -62,23 +62,164 @@ test('should get and remove data from an element', function(){
|
|||||||
ok(!Dom.hasElData(el), 'cached item emptied');
|
ok(!Dom.hasElData(el), 'cached item emptied');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should add and remove a class name on an element', function(){
|
test('addElClass()', function(){
|
||||||
var el = document.createElement('div');
|
var el = document.createElement('div');
|
||||||
|
|
||||||
|
expect(5);
|
||||||
|
|
||||||
Dom.addElClass(el, 'test-class');
|
Dom.addElClass(el, 'test-class');
|
||||||
ok(el.className === 'test-class', 'class added');
|
strictEqual(el.className, 'test-class', 'adds a single class');
|
||||||
|
|
||||||
Dom.addElClass(el, 'test-class');
|
Dom.addElClass(el, 'test-class');
|
||||||
ok(el.className === 'test-class', 'same class not duplicated');
|
strictEqual(el.className, 'test-class', 'does not duplicate classes');
|
||||||
Dom.addElClass(el, 'test-class2');
|
|
||||||
ok(el.className === 'test-class test-class2', 'added second class');
|
throws(function(){
|
||||||
Dom.removeElClass(el, 'test-class');
|
Dom.addElClass(el, 'foo foo-bar');
|
||||||
ok(el.className === 'test-class2', 'removed first class');
|
}, 'throws when attempting to add a class with whitespace');
|
||||||
|
|
||||||
|
Dom.addElClass(el, 'test2_className');
|
||||||
|
strictEqual(el.className, 'test-class test2_className', 'adds second class');
|
||||||
|
|
||||||
|
Dom.addElClass(el, 'FOO');
|
||||||
|
strictEqual(el.className, 'test-class test2_className FOO', 'adds third class');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should read class names on an element', function(){
|
test('removeElClass()', function() {
|
||||||
var el = document.createElement('div');
|
var el = document.createElement('div');
|
||||||
Dom.addElClass(el, 'test-class1');
|
|
||||||
ok(Dom.hasElClass(el, 'test-class1') === true, 'class detected');
|
el.className = 'test-class foo foo test2_className FOO bar';
|
||||||
ok(Dom.hasElClass(el, 'test-class') === false, 'substring correctly not detected');
|
|
||||||
|
expect(5);
|
||||||
|
|
||||||
|
Dom.removeElClass(el, 'test-class');
|
||||||
|
strictEqual(el.className, 'foo foo test2_className FOO bar', 'removes one class');
|
||||||
|
|
||||||
|
Dom.removeElClass(el, 'foo');
|
||||||
|
strictEqual(el.className, 'test2_className FOO bar', 'removes all instances of a class');
|
||||||
|
|
||||||
|
throws(function(){
|
||||||
|
Dom.removeElClass(el, 'test2_className bar');
|
||||||
|
}, 'throws when attempting to remove a class with whitespace');
|
||||||
|
|
||||||
|
Dom.removeElClass(el, 'test2_className');
|
||||||
|
strictEqual(el.className, 'FOO bar', 'removes another class');
|
||||||
|
|
||||||
|
Dom.removeElClass(el, 'FOO');
|
||||||
|
strictEqual(el.className, 'bar', 'removes another class');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hasElClass()', function(){
|
||||||
|
var el = document.createElement('div');
|
||||||
|
|
||||||
|
el.className = 'test-class foo foo test2_className FOO bar';
|
||||||
|
|
||||||
|
strictEqual(Dom.hasElClass(el, 'test-class'), true, 'class detected');
|
||||||
|
strictEqual(Dom.hasElClass(el, 'foo'), true, 'class detected');
|
||||||
|
strictEqual(Dom.hasElClass(el, 'test2_className'), true, 'class detected');
|
||||||
|
strictEqual(Dom.hasElClass(el, 'FOO'), true, 'class detected');
|
||||||
|
strictEqual(Dom.hasElClass(el, 'bar'), true, 'class detected');
|
||||||
|
strictEqual(Dom.hasElClass(el, 'test2'), false, 'valid substring - but not a class - correctly not detected');
|
||||||
|
strictEqual(Dom.hasElClass(el, 'className'), false, 'valid substring - but not a class - correctly not detected');
|
||||||
|
|
||||||
|
throws(function(){
|
||||||
|
Dom.hasElClass(el, 'FOO bar');
|
||||||
|
}, 'throws when attempting to detect a class with whitespace');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('toggleElClass()', function() {
|
||||||
|
let el = Dom.createEl('div', {className: 'foo bar'});
|
||||||
|
|
||||||
|
let predicateToggles = [
|
||||||
|
{
|
||||||
|
toggle: 'foo',
|
||||||
|
predicate: true,
|
||||||
|
className: 'foo bar',
|
||||||
|
message: 'if predicate `true` matches state of the element, do nothing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'baz',
|
||||||
|
predicate: false,
|
||||||
|
className: 'foo bar',
|
||||||
|
message: 'if predicate `false` matches state of the element, do nothing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'baz',
|
||||||
|
predicate: true,
|
||||||
|
className: 'foo bar baz',
|
||||||
|
message: 'if predicate `true` differs from state of the element, add the class'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'foo',
|
||||||
|
predicate: false,
|
||||||
|
className: 'bar baz',
|
||||||
|
message: 'if predicate `false` differs from state of the element, remove the class'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'bar',
|
||||||
|
predicate: () => true,
|
||||||
|
className: 'bar baz',
|
||||||
|
message: 'if a predicate function returns `true`, matching the state of the element, do nothing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'foo',
|
||||||
|
predicate: () => false,
|
||||||
|
className: 'bar baz',
|
||||||
|
message: 'if a predicate function returns `false`, matching the state of the element, do nothing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'foo',
|
||||||
|
predicate: () => true,
|
||||||
|
className: 'bar baz foo',
|
||||||
|
message: 'if a predicate function returns `true`, differing from state of the element, add the class'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'foo',
|
||||||
|
predicate: () => false,
|
||||||
|
className: 'bar baz',
|
||||||
|
message: 'if a predicate function returns `false`, differing from state of the element, remove the class'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'foo',
|
||||||
|
predicate: Function.prototype,
|
||||||
|
className: 'bar baz foo',
|
||||||
|
message: 'if a predicate function returns `undefined` and the element does not have the class, add the class'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'bar',
|
||||||
|
predicate: Function.prototype,
|
||||||
|
className: 'baz foo',
|
||||||
|
message: 'if a predicate function returns `undefined` and the element has the class, remove the class'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'bar',
|
||||||
|
predicate: () => [],
|
||||||
|
className: 'baz foo bar',
|
||||||
|
message: 'if a predicate function returns a defined non-boolean value and the element does not have the class, add the class'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toggle: 'baz',
|
||||||
|
predicate: () => 'this is incorrect',
|
||||||
|
className: 'foo bar',
|
||||||
|
message: 'if a predicate function returns a defined non-boolean value and the element has the class, remove the class'
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(3 + predicateToggles.length);
|
||||||
|
|
||||||
|
Dom.toggleElClass(el, 'bar');
|
||||||
|
strictEqual(el.className, 'foo', 'toggles a class off, if present');
|
||||||
|
|
||||||
|
Dom.toggleElClass(el, 'bar');
|
||||||
|
strictEqual(el.className, 'foo bar', 'toggles a class on, if absent');
|
||||||
|
|
||||||
|
throws(function(){
|
||||||
|
Dom.toggleElClass(el, 'foo bar');
|
||||||
|
}, 'throws when attempting to toggle a class with whitespace');
|
||||||
|
|
||||||
|
predicateToggles.forEach(x => {
|
||||||
|
Dom.toggleElClass(el, x.toggle, x.predicate);
|
||||||
|
strictEqual(el.className, x.className, x.message);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should set element attributes from object', function(){
|
test('should set element attributes from object', function(){
|
||||||
@ -293,4 +434,37 @@ test('Dom.appendContent', function(assert) {
|
|||||||
assert.strictEqual(el.firstChild.nextSibling, p2, 'the second paragraph was appended');
|
assert.strictEqual(el.firstChild.nextSibling, p2, 'the second paragraph was appended');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('$() and $$()', function() {
|
||||||
|
let fixture = document.getElementById('qunit-fixture');
|
||||||
|
let container = document.createElement('div');
|
||||||
|
let children = [
|
||||||
|
document.createElement('div'),
|
||||||
|
document.createElement('div'),
|
||||||
|
document.createElement('div'),
|
||||||
|
];
|
||||||
|
|
||||||
|
children.forEach(child => container.appendChild(child));
|
||||||
|
fixture.appendChild(container);
|
||||||
|
|
||||||
|
let totalDivCount = document.getElementsByTagName('div').length;
|
||||||
|
|
||||||
|
expect(12);
|
||||||
|
|
||||||
|
strictEqual(Dom.$('#qunit-fixture'), fixture, 'can find an element in the document context');
|
||||||
|
strictEqual(Dom.$$('div').length, totalDivCount, 'finds elements in the document context');
|
||||||
|
|
||||||
|
strictEqual(Dom.$('div', container), children[0], 'can find an element in a DOM element context');
|
||||||
|
strictEqual(Dom.$$('div', container).length, children.length, 'finds elements in a DOM element context');
|
||||||
|
|
||||||
|
strictEqual(Dom.$('#qunit-fixture', document.querySelector('unknown')), fixture, 'falls back to document given a bad context element');
|
||||||
|
strictEqual(Dom.$$('div', document.querySelector('unknown')).length, totalDivCount, 'falls back to document given a bad context element');
|
||||||
|
|
||||||
|
strictEqual(Dom.$('#qunit-fixture', 'body'), fixture, 'can find an element in a selector context');
|
||||||
|
strictEqual(Dom.$$('div', '#qunit-fixture').length, 1 + children.length, 'finds elements in a selector context');
|
||||||
|
|
||||||
|
strictEqual(Dom.$('#qunit-fixture', 'unknown'), fixture, 'falls back to document given a bad context selector');
|
||||||
|
strictEqual(Dom.$$('div', 'unknown').length, totalDivCount, 'falls back to document given a bad context selector');
|
||||||
|
|
||||||
|
strictEqual(Dom.$('div', children[0]), null, 'returns null for missing elements');
|
||||||
|
strictEqual(Dom.$$('div', children[0]).length, 0, 'returns 0 for missing elements');
|
||||||
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import videojs from '../../src/js/video.js';
|
import videojs from '../../src/js/video.js';
|
||||||
import TestHelpers from './test-helpers.js';
|
import TestHelpers from './test-helpers.js';
|
||||||
import Player from '../../src/js/player.js';
|
import Player from '../../src/js/player.js';
|
||||||
|
import * as Dom from '../../src/js/utils/dom.js';
|
||||||
import log from '../../src/js/utils/log.js';
|
import log from '../../src/js/utils/log.js';
|
||||||
import document from 'global/document';
|
import document from 'global/document';
|
||||||
|
|
||||||
@ -78,3 +79,29 @@ test('should expose options and players properties for backward-compatibility',
|
|||||||
ok(typeof videojs.options, 'object', 'options should be an object');
|
ok(typeof videojs.options, 'object', 'options should be an object');
|
||||||
ok(typeof videojs.players, 'object', 'players should be an object');
|
ok(typeof videojs.players, 'object', 'players should be an object');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should expose DOM functions', function() {
|
||||||
|
|
||||||
|
// Keys are videojs methods, values are Dom methods.
|
||||||
|
let methods = {
|
||||||
|
isEl: 'isEl',
|
||||||
|
isTextNode: 'isTextNode',
|
||||||
|
hasClass: 'hasElClass',
|
||||||
|
addClass: 'addElClass',
|
||||||
|
removeClass: 'removeElClass',
|
||||||
|
toggleClass: 'toggleElClass',
|
||||||
|
setAttributes: 'setElAttributes',
|
||||||
|
getAttributes: 'getElAttributes',
|
||||||
|
emptyEl: 'emptyEl',
|
||||||
|
insertContent: 'insertContent',
|
||||||
|
appendContent: 'appendContent'
|
||||||
|
};
|
||||||
|
|
||||||
|
let keys = Object.keys(methods);
|
||||||
|
|
||||||
|
expect(keys.length);
|
||||||
|
keys.forEach(function(vjsName) {
|
||||||
|
let domName = methods[vjsName];
|
||||||
|
strictEqual(videojs[vjsName], Dom[domName], `videojs.${vjsName} is a reference to Dom.${domName}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user