Skip to content

Commit

Permalink
Eliminate keepTooltipsInside option and fix videojs#3645
Browse files Browse the repository at this point in the history
This eliminates the keepTooltipsInside option and fixes issue videojs#3645 by
forcing a limitation on the calculated position of the tooltip.
  • Loading branch information
misteroneill committed Jan 19, 2017
1 parent 7bafcc2 commit 9a574b4
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 96 deletions.
18 changes: 0 additions & 18 deletions docs/guides/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,24 +316,6 @@ Player

## Specific Component Details

### Progress Control

The progress control has a grandchild component, the mouse time display, which shows a time tooltip that follows the mouse cursor.

By default, the progress control is sandwiched inside the control bar between the volume menu button and the remaining time display. Some skins attempt to move the it above the control bar and have it span the full width of the player. In these cases, it is less than ideal to have the tooltips leave the bounds of the player. This can be prevented by setting the `keepTooltipsInside` option on the progress control.

```js
let player = videojs('myplayer', {
controlBar: {
progressControl: {
keepTooltipsInside: true
}
}
});
```

> **Note:** This makes the tooltips use a real element instead of pseudo-elements so targeting them with CSS is different.
### Text Track Settings

The text track settings component is only available when using emulated text tracks.
9 changes: 2 additions & 7 deletions src/css/components/_progress.scss
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
display: none;
}
}

.video-js .vjs-play-progress {
background-color: $primary-foreground-color;
@extend .vjs-icon-circle;
Expand All @@ -86,9 +87,7 @@

// Current Time "tooltip"
// By default this is hidden and only shown when hovering over the progress control
.video-js .vjs-time-tooltip,
.video-js .vjs-mouse-display:after,
.video-js .vjs-play-progress:after {
.video-js .vjs-time-tooltip {
visibility: hidden;
pointer-events: none;
position: absolute;
Expand All @@ -108,10 +107,6 @@
z-index: 1;
}

.video-js .vjs-progress-control .vjs-keep-tooltips-inside:after {
display: none;
}

.video-js .vjs-load-progress {
// For IE8 we'll lighten the color
background: lighten($secondary-background-color, 25%);
Expand Down
76 changes: 42 additions & 34 deletions src/js/control-bar/progress-control/mouse-time-display.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,20 @@ class MouseTimeDisplay extends Component {
constructor(player, options) {
super(player, options);

if (options.playerOptions &&
options.playerOptions.controlBar &&
options.playerOptions.controlBar.progressControl &&
options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
}

if (this.keepTooltipsInside) {
this.tooltip = Dom.createEl('div', {className: 'vjs-time-tooltip'});
this.el().appendChild(this.tooltip);
this.addClass('vjs-keep-tooltips-inside');
}
this.tooltip = Dom.createEl('div', {className: 'vjs-time-tooltip'});
this.el().appendChild(this.tooltip);

this.update(0, 0);

player.on('ready', () => {
this.on(player.controlBar.progressControl.el(), 'mousemove', Fn.throttle(Fn.bind(this, this.handleMouseMove), 25));
const progressControlEl = player.
getChild('controlBar').
getChild('progressControl').
el();

const listener = Fn.throttle(Fn.bind(this, this.handleProgressMouseMove), 25);

this.on(progressControlEl, 'mousemove', listener);
});
}

Expand All @@ -60,28 +57,43 @@ class MouseTimeDisplay extends Component {
}

/**
* Handle the mouse move event on the `MouseTimeDisplay`.
* Handle the mouse move event on the grandparent progress control.
*
* @param {EventTarget~Event} event
* The `mousemove` event that caused this to event to run.
*
* @listen mousemove
*/
handleMouseMove(event) {
handleProgressMouseMove(event) {
const referenceEl = this.el().parentNode;
const duration = this.player_.duration();
const newTime = this.calculateDistance(event) * duration;
const position = event.pageX - Dom.findElPosition(this.el().parentNode).left;

let position = event.pageX - Dom.findElPosition(referenceEl).left;

// Because the event is targeting the grandparent of this component, we
// need to ensure that the position remains within the actual reference
// element (the parent, i.e. the seek-bar). On the left, this means
// ensuring that position is always 0 or above.
if (position < 0) {
position = 0;

// On the right, this means ensuring the position is always less than or
// equal to the seek bar's client width.
} else if (position > referenceEl.clientWidth) {
position = referenceEl.clientWidth;
}

this.update(newTime, position);
}

/**
* Update the time and posistion of the `MouseTimeDisplay`.
* Update the time and position of the `MouseTimeDisplay`.
*
* @param {number} newTime
* Time to change the `MouseTimeDisplay` to.
*
* @param {nubmer} position
* @param {number} position
* Postion from the left of the in pixels.
*/
update(newTime, position) {
Expand All @@ -90,15 +102,13 @@ class MouseTimeDisplay extends Component {
this.el().style.left = position + 'px';
this.el().setAttribute('data-current-time', time);

if (this.keepTooltipsInside) {
const clampedPosition = this.clampPosition_(position);
const difference = position - clampedPosition + 1;
const tooltipWidth = parseFloat(computedStyle(this.tooltip, 'width'));
const tooltipWidthHalf = tooltipWidth / 2;
const clampedPosition = this.clampPosition_(position);
const difference = position - clampedPosition + 1;
const tooltipWidth = parseFloat(computedStyle(this.tooltip, 'width'));
const tooltipWidthHalf = tooltipWidth / 2;

this.tooltip.innerHTML = time;
this.tooltip.style.right = `-${tooltipWidthHalf - difference}px`;
}
this.tooltip.innerHTML = time;
this.tooltip.style.right = `-${tooltipWidthHalf - difference}px`;
}

/**
Expand All @@ -116,10 +126,10 @@ class MouseTimeDisplay extends Component {
}

/**
* This takes in a horizontal position for the bar and returns a clamped position.
* Clamped position means that it will keep the position greater than half the width
* of the tooltip and smaller than the player width minus half the width o the tooltip.
* It will only clamp the position if `keepTooltipsInside` option is set.
* This takes in a horizontal position for the bar and returns a clamped
* position. Clamped position means that it will keep the position greater
* than half the width of the tooltip and smaller than the player width minus
* half the width of the tooltip.
*
* @param {number} position
* The position the bar wants to be
Expand All @@ -130,15 +140,13 @@ class MouseTimeDisplay extends Component {
* @private
*/
clampPosition_(position) {
if (!this.keepTooltipsInside) {
return position;
}

const playerWidth = parseFloat(computedStyle(this.player().el(), 'width'));
const tooltipWidth = parseFloat(computedStyle(this.tooltip, 'width'));
const tooltipWidthHalf = tooltipWidth / 2;
let actualPosition = position;

// need to account for the width of the progress-holder element

if (position < tooltipWidthHalf) {
actualPosition = Math.ceil(tooltipWidthHalf);
} else if (position > (playerWidth - tooltipWidthHalf)) {
Expand Down
11 changes: 0 additions & 11 deletions src/js/control-bar/progress-control/play-progress-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,6 @@ class PlayProgressBar extends Component {
this.updateDataAttr();
this.on(player, 'timeupdate', this.updateDataAttr);
player.ready(Fn.bind(this, this.updateDataAttr));

if (options.playerOptions &&
options.playerOptions.controlBar &&
options.playerOptions.controlBar.progressControl &&
options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
}

if (this.keepTooltipsInside) {
this.addClass('vjs-keep-tooltips-inside');
}
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/js/control-bar/progress-control/progress-control.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import Component from '../../component.js';

import './seek-bar.js';
import './mouse-time-display.js';

/**
* The Progress Control component contains the seek bar, load progress,
Expand Down
39 changes: 14 additions & 25 deletions src/js/control-bar/progress-control/seek-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import computedStyle from '../../utils/computed-style.js';
import './load-progress-bar.js';
import './play-progress-bar.js';
import './tooltip-progress-bar.js';
import './mouse-time-display.js';

/**
* Seek Bar and holder for the progress bars
Expand All @@ -29,20 +30,10 @@ class SeekBar extends Slider {
*/
constructor(player, options) {
super(player, options);
this.on(player, 'timeupdate', this.updateProgress);
this.on(player, 'ended', this.updateProgress);
player.ready(Fn.bind(this, this.updateProgress));

if (options.playerOptions &&
options.playerOptions.controlBar &&
options.playerOptions.controlBar.progressControl &&
options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
}

if (this.keepTooltipsInside) {
this.tooltipProgressBar = this.addChild('TooltipProgressBar');
}
this.updateProgress = Fn.bind(this, this.updateProgress);
this.on(player, ['timeupdate', 'ended'], this.updateProgress);
player.ready(this.updateProgress);
this.tooltipProgressBar = this.addChild('TooltipProgressBar');
}

/**
Expand Down Expand Up @@ -70,19 +61,16 @@ class SeekBar extends Slider {
*/
updateProgress(event) {
this.updateAriaAttributes(this.el_);
this.updateAriaAttributes(this.tooltipProgressBar.el_);
this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width;

if (this.keepTooltipsInside) {
this.updateAriaAttributes(this.tooltipProgressBar.el_);
this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width;
const playerWidth = parseFloat(computedStyle(this.player_.el(), 'width'));
const tooltipWidth = parseFloat(computedStyle(this.tooltipProgressBar.tooltip, 'width'));
const tooltipStyle = this.tooltipProgressBar.el().style;

const playerWidth = parseFloat(computedStyle(this.player().el(), 'width'));
const tooltipWidth = parseFloat(computedStyle(this.tooltipProgressBar.tooltip, 'width'));
const tooltipStyle = this.tooltipProgressBar.el().style;

tooltipStyle.maxWidth = Math.floor(playerWidth - (tooltipWidth / 2)) + 'px';
tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px';
tooltipStyle.right = `-${tooltipWidth / 2}px`;
}
tooltipStyle.maxWidth = Math.floor(playerWidth - (tooltipWidth / 2)) + 'px';
tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px';
tooltipStyle.right = `-${tooltipWidth / 2}px`;
}

/**
Expand All @@ -97,6 +85,7 @@ class SeekBar extends Slider {

// machine readable value of progress bar (percentage complete)
el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2));

// human readable value of progress bar (time complete)
el.setAttribute('aria-valuetext', formatTime(time, this.player_.duration()));
}
Expand Down

0 comments on commit 9a574b4

Please sign in to comment.