Skip to content

Commit b8b0607

Browse files
bc-paulmisteroneill
authored andcommitted
feat: Allow choosing the placement of overlay elements in the control bar.
1 parent b0b3a5d commit b8b0607

File tree

3 files changed

+178
-9
lines changed

3 files changed

+178
-9
lines changed

README.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,16 @@ Whether or not to include background styling & padding around the overlay.
4646

4747
#### `attachToControlBar`
4848

49-
__Type:__ `Boolean`
49+
__Type:__ `Boolean`, `String`
5050
__Default:__ `false`
5151

5252
_This setting can be overridden by being set on individual overlay objects._
5353

54-
If set to true, bottom aligned overlays will adjust positioning when the control bar minimizes. This has no effect on overlays that are not aligned to bottom, bottom-left, or bottom-right. For use with the default control bar, it may not work for custom control bars.
54+
If set to `true` or a `string` value, bottom aligned overlays will adjust positioning when the control bar minimizes. This has no effect on overlays that are not aligned to bottom, bottom-left, or bottom-right. For use with the default control bar, it may not work for custom control bars.
55+
56+
The value of `string` must be the name of a ControlBar component.
57+
58+
Bottom aligned overlays will be inserted before the specified component. Otherwise, bottom aligned overlays are inserted before the first child component of the ControlBar. All other overlays are inserted before the ControlBar component.
5559

5660
#### `class`
5761

src/plugin.js

+28-7
Original file line numberDiff line numberDiff line change
@@ -321,16 +321,37 @@ const plugin = function(options) {
321321

322322
this.overlays_ = overlays.map(o => {
323323
const mergeOptions = videojs.mergeOptions(settings, o);
324+
const attachToControlBar = typeof mergeOptions.attachToControlBar === 'string' || mergeOptions.attachToControlBar === true;
324325

325-
// Attach bottom aligned overlays to the control bar so
326-
// they will adjust positioning when the control bar minimizes
327-
if (mergeOptions.attachToControlBar &&
328-
this.controlBar &&
329-
mergeOptions.align.indexOf('bottom') !== -1) {
330-
return this.controlBar.addChild('overlay', mergeOptions);
326+
if (!this.controls() || !this.controlBar) {
327+
return this.addChild('overlay', mergeOptions);
331328
}
332329

333-
return this.addChild('overlay', mergeOptions);
330+
if (attachToControlBar && mergeOptions.align.indexOf('bottom') !== -1) {
331+
let referenceChild = this.controlBar.children()[0];
332+
333+
if (this.controlBar.getChild(mergeOptions.attachToControlBar) !== undefined) {
334+
referenceChild = this.controlBar.getChild(mergeOptions.attachToControlBar);
335+
}
336+
337+
if (referenceChild) {
338+
const controlBarChild = this.controlBar.addChild('overlay', mergeOptions);
339+
340+
this.controlBar.el().insertBefore(
341+
controlBarChild.el(),
342+
referenceChild.el()
343+
);
344+
return controlBarChild;
345+
}
346+
}
347+
348+
const playerChild = this.addChild('overlay', mergeOptions);
349+
350+
this.el().insertBefore(
351+
playerChild.el(),
352+
this.controlBar.el()
353+
);
354+
return playerChild;
334355
});
335356
};
336357

test/plugin.test.js

+144
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ QUnit.module('videojs-overlay', {
2828

2929
this.fixture = document.getElementById('qunit-fixture');
3030
this.video = document.createElement('video');
31+
this.video.controls = true;
3132
this.fixture.appendChild(this.video);
3233
this.player = videojs(this.video);
3334

@@ -663,3 +664,146 @@ QUnit.test('can deinitialize the plugin on reinitialization', function(assert) {
663664
'new top-left overlay added'
664665
);
665666
});
667+
668+
QUnit.test('attach bottom overlay as first child when attachToControlBar is invalid component', function(assert) {
669+
assert.expect(1);
670+
671+
this.player.overlay({
672+
attachToControlBar: 'InvalidComponent',
673+
overlays: [{
674+
start: 'start',
675+
align: 'bottom'
676+
}]
677+
});
678+
679+
this.player.trigger('start');
680+
681+
assert.equal(
682+
this.player.$('.vjs-overlay.vjs-overlay-bottom'),
683+
this.player.controlBar.el().firstChild,
684+
'bottom attaches as first child of controlBar'
685+
);
686+
});
687+
688+
QUnit.test('attach top overlay as previous sibling when attachToControlBar is invalid component', function(assert) {
689+
assert.expect(1);
690+
691+
this.player.overlay({
692+
attachToControlBar: 'InvalidComponent',
693+
overlays: [{
694+
start: 'start',
695+
align: 'top'
696+
}]
697+
});
698+
699+
this.player.trigger('start');
700+
701+
assert.equal(
702+
this.player.$('.vjs-overlay.vjs-overlay-top'),
703+
this.player.controlBar.el().previousSibling,
704+
'top attaches as previous sibiling of controlBar'
705+
);
706+
});
707+
708+
QUnit.test('attach overlays when attachToControlBar is true', function(assert) {
709+
assert.expect(4);
710+
711+
this.player.overlay({
712+
attachToControlBar: true,
713+
overlays: [{
714+
start: 'start',
715+
align: 'bottom'
716+
}]
717+
});
718+
719+
this.player.trigger('start');
720+
721+
assert.equal(
722+
this.player.controlBar.$('.vjs-overlay.vjs-overlay-bottom'),
723+
this.player.controlBar.el().firstChild,
724+
'bottom attaches as first child of control bar'
725+
);
726+
727+
this.player.overlay({
728+
attachToControlBar: true,
729+
overlays: [{
730+
start: 'start',
731+
align: 'top'
732+
}]
733+
});
734+
735+
this.player.trigger('start');
736+
737+
assert.equal(
738+
this.player.$('.vjs-overlay.vjs-overlay-top'),
739+
this.player.controlBar.el().previousSibling,
740+
'top attaches as previous sibiling of controlBar'
741+
);
742+
743+
this.player.overlay({
744+
attachToControlBar: 'RemainingTimeDisplay',
745+
overlays: [{
746+
start: 'start',
747+
align: 'bottom'
748+
}]
749+
});
750+
751+
this.player.trigger('start');
752+
753+
assert.equal(
754+
this.player.controlBar.$('.vjs-overlay.vjs-overlay-bottom'),
755+
this.player.controlBar.remainingTimeDisplay.el().previousSibling,
756+
'bottom attaches as previous sibiling of attachToControlBar component'
757+
);
758+
759+
this.player.overlay({
760+
attachToControlBar: 'RemainingTimeDisplay',
761+
overlays: [{
762+
start: 'start',
763+
align: 'top'
764+
}]
765+
});
766+
767+
this.player.trigger('start');
768+
769+
assert.equal(
770+
this.player.$('.vjs-overlay.vjs-overlay-top'),
771+
this.player.controlBar.el().previousSibling,
772+
'top attaches as previous sibiling of controlBar when using attachToControlBar component'
773+
);
774+
});
775+
776+
QUnit.test('attach overlays as last child when no controls are present', function(assert) {
777+
assert.expect(2);
778+
this.player.controls(false);
779+
780+
this.player.overlay({
781+
overlays: [{
782+
start: 'start',
783+
align: 'bottom'
784+
}]
785+
});
786+
787+
this.player.trigger('start');
788+
789+
assert.equal(
790+
this.player.$('.vjs-overlay.vjs-overlay-bottom'),
791+
this.player.el().lastChild,
792+
'bottom attaches as last child of player'
793+
);
794+
795+
this.player.overlay({
796+
overlays: [{
797+
start: 'start',
798+
align: 'top'
799+
}]
800+
});
801+
802+
this.player.trigger('start');
803+
804+
assert.equal(
805+
this.player.$('.vjs-overlay.vjs-overlay-top'),
806+
this.player.el().lastChild,
807+
'top attaches as last child of player'
808+
);
809+
});

0 commit comments

Comments
 (0)