Skip to content

Commit

Permalink
feat(debug): check for presence of default controls component tree
Browse files Browse the repository at this point in the history
- also bail out immediately when default tree structure has changed at
  runtime
- clean up and refactor debug logging.

Implements #58
  • Loading branch information
phloxic committed Oct 1, 2024
1 parent 078dc5b commit 206da48
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 20 deletions.
65 changes: 50 additions & 15 deletions src/sprite-thumbnails.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,39 @@ const spriteThumbs = (player, plugin, options) => {
const dom = videojs.dom;
const obj = videojs.obj;
const log = plugin.log;
const debug = log.debug;

const controls = player.controlBar;
const defaultState = { ...plugin.state };
const setDefaultState = () => {
plugin.setState(defaultState);
};

// default control bar component tree is expected
// https://docs.videojs.com/tutorial-components.html#default-component-tree
const progress = controls && controls.progressControl;
const seekBar = progress && progress.seekBar;
const mouseTimeTooltip = seekBar && seekBar.mouseTimeDisplay && seekBar.mouseTimeDisplay.timeTooltip;
const tooltipEl = mouseTimeTooltip && mouseTimeTooltip.el();
const tooltipStyleOrig = tooltipEl && tooltipEl.style;
const _controlBar = 'ControlBar';
const _progressControl = 'ProgressControl';
const _seekBar = 'SeekBar';
const _timeTooltip = 'TimeTooltip';
const playerDescendant = (componentName) => {
const descendants = [
_controlBar,
_progressControl,
_seekBar,
'MouseTimeDisplay',
_timeTooltip
];
const idx = descendants.indexOf(componentName);
const component = player.getDescendant(descendants.slice(0, idx + 1));

if (!component) {
setDefaultState();
debug(`component tree ${descendants.join(' > ')} required`);
}
return component;
};

let tooltipEl;
let tooltipStyleOrig;

const getUrl = idx => {
const urlArray = options.urlArray;
Expand All @@ -37,7 +60,12 @@ const spriteThumbs = (player, plugin, options) => {
};

const hijackMouseTooltip = evt => {
const seekBarEl = seekBar.el();
if (!playerDescendant(_timeTooltip)) {
return;
}
const seekBarEl = playerDescendant(_seekBar).el();
const controlsTop = dom
.findPosition(playerDescendant(_controlBar).el()).top;
const playerWidth = player.currentWidth();
const duration = player.duration();
const interval = options.interval;
Expand All @@ -62,7 +90,6 @@ const spriteThumbs = (player, plugin, options) => {
const scaledHeight = options.height * scaleFactor;
const cleft = Math.floor(position % columns) * -scaledWidth;
const ctop = Math.floor(position / columns) * -scaledHeight;
const controlsTop = dom.findPosition(controls.el()).top;
const seekBarTop = dom.findPosition(seekBarEl).top;
// top of seekBar is 0 position
const topOffset = -scaledHeight - Math.max(0, seekBarTop - controlsTop);
Expand Down Expand Up @@ -112,18 +139,19 @@ const spriteThumbs = (player, plugin, options) => {
plugin.on('statechanged', () => {
const pstate = plugin.state;
const spriteEvents = ['mousemove', 'touchmove'];
const debug = log.debug;
const progress = playerDescendant(_progressControl);

if (pstate.ready) {
debug('ready to show thumbnails');
progress.on(spriteEvents, hijackMouseTooltip);
} else {
if (!options.url && !options.urlArray.length) {
log('no urls given');
debug('no urls given, resetting');
}
if (progress) {
progress.off(spriteEvents, hijackMouseTooltip);
tooltipEl.style = tooltipStyleOrig;
}
debug('resetting');
progress.off(spriteEvents, hijackMouseTooltip);
tooltipEl.style = tooltipStyleOrig;
}
player.toggleClass('vjs-thumbnails-ready', pstate.ready);
});
Expand All @@ -137,6 +165,10 @@ const spriteThumbs = (player, plugin, options) => {
// `spriteThumbnails` options cannot be merged
// Thereafter the `loadstart` callback is redundant.
player.off('loadstart', init);

// clean slate
setDefaultState();

// if present, merge source config with current config
const plugName = plugin.name;
const thumbSource = player.currentSources().find(source => {
Expand All @@ -151,7 +183,6 @@ const spriteThumbs = (player, plugin, options) => {

if (!Object.keys(srcOpts).length) {
srcOpts = {url: '', urlArray: []};
log('disabling plugin');
} else if (urlArray && urlArray.length) {
srcOpts.url = '';
} else if (srcOpts.url) {
Expand All @@ -160,12 +191,16 @@ const spriteThumbs = (player, plugin, options) => {
plugin.options = options = obj.merge(options, srcOpts);
}

const mouseTimeTooltip = playerDescendant(_timeTooltip);

if (!mouseTimeTooltip || evt.type === 'loadstart') {
return;
}
tooltipEl = mouseTimeTooltip.el();
tooltipStyleOrig = tooltipEl.style;

plugin.setState({
ready: !!(mouseTimeTooltip && (options.urlArray.length || options.url) &&
ready: !!((options.urlArray.length || options.url) &&
intCheck('width') && intCheck('height') && intCheck('columns') &&
intCheck('rows') && downlinkCheck())
});
Expand Down
44 changes: 39 additions & 5 deletions test/sprite-thumbnails.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,17 @@ QUnit.module('videojs-sprite-thumbnails', {
}
});

QUnit.test('changes ready state', function(assert) {
assert.expect(7);
QUnit.test('checking controls default tree', function(assert) {
assert.expect(2);

const mouseTimeDisplay = this.player.controlBar.progressControl.seekBar.mouseTimeDisplay;

mouseTimeDisplay.removeChild('TimeTooltip');
assert.strictEqual(
mouseTimeDisplay.getChild('TimeTooltip'),
null,
'removed mouse display time tooltip: no default controls tree'
);

this.player.spriteThumbnails({
url: '../img/oceans-thumbs.jpg',
Expand All @@ -47,19 +56,45 @@ QUnit.test('changes ready state', function(assert) {
columns: 10
}).log.level('all');

this.clock.tick(1);
this.player.trigger('loadedmetadata');

assert.strictEqual(
this.player.spriteThumbnails().state.ready,
false,
'the plugin is not ready to show thumbnails'
'no default controls tree: plugin not ready'
);
});

QUnit.test('changes ready state', function(assert) {
assert.expect(7);

this.player.spriteThumbnails({
url: '../img/oceans-thumbs.jpg',
width: 240,
height: 100
}).log.level('all');

this.player.trigger('loadedmetadata');

assert.strictEqual(
this.player.spriteThumbnails().state.ready,
false,
'no columns given, plugin not ready to show thumbnails'
);

this.player.src({src: 'dummy.mp4', spriteThumbnails: {
url: '../img/oceans-thumbs.jpg',
columns: 10
}});

this.clock.tick(1);
this.player.trigger('loadedmetadata');

assert.strictEqual(
this.player.spriteThumbnails().state.ready,
true,
'the plugin is now able to show thumbnails on ready'
'the plugin is now able to show thumbnails'
);
assert.strictEqual(
this.player.hasClass('vjs-thumbnails-ready'),
Expand Down Expand Up @@ -93,7 +128,6 @@ QUnit.test('changes ready state', function(assert) {
'options empty: disabled plugin inherits options, except for url'
);

this.clock.tick(1);
this.player.src({src: 'dummy.mp4', spriteThumbnails: {url: '../img/oceans-thumbs.jpg'}});
this.player.trigger('loadedmetadata');

Expand Down

0 comments on commit 206da48

Please sign in to comment.