- 1 :
/**
- 2 :
* @file resize-manager.js
- 3 :
*/
- 4 :
import window from 'global/window';
- 5 :
import { debounce } from './utils/fn.js';
- 6 :
import * as Events from './utils/events.js';
- 7 :
import mergeOptions from './utils/merge-options.js';
- 8 :
import Component from './component.js';
- 9 :
- 10 :
/**
- 11 :
* A Resize Manager. It is in charge of triggering `playerresize` on the player in the right conditions.
- 12 :
*
- 13 :
* It'll either create an iframe and use a debounced resize handler on it or use the new {@link https://wicg.github.io/ResizeObserver/|ResizeObserver}.
- 14 :
*
- 15 :
* If the ResizeObserver is available natively, it will be used. A polyfill can be passed in as an option.
- 16 :
* If a `playerresize` event is not needed, the ResizeManager component can be removed from the player, see the example below.
- 17 :
* @example <caption>How to disable the resize manager</caption>
- 18 :
* const player = videojs('#vid', {
- 19 :
* resizeManager: false
- 20 :
* });
- 21 :
*
- 22 :
* @see {@link https://wicg.github.io/ResizeObserver/|ResizeObserver specification}
- 23 :
*
- 24 :
* @extends Component
- 25 :
*/
- 26 :
class ResizeManager extends Component {
- 27 :
- 28 :
/**
- 29 :
* Create the ResizeManager.
- 30 :
*
- 31 :
* @param {Object} player
- 32 :
* The `Player` that this class should be attached to.
- 33 :
*
- 34 :
* @param {Object} [options]
- 35 :
* The key/value store of ResizeManager options.
- 36 :
*
- 37 :
* @param {Object} [options.ResizeObserver]
- 38 :
* A polyfill for ResizeObserver can be passed in here.
- 39 :
* If this is set to null it will ignore the native ResizeObserver and fall back to the iframe fallback.
- 40 :
*/
- 41 :
constructor(player, options) {
- 42 :
let RESIZE_OBSERVER_AVAILABLE = options.ResizeObserver || window.ResizeObserver;
- 43 :
- 44 :
// if `null` was passed, we want to disable the ResizeObserver
- 45 :
if (options.ResizeObserver === null) {
- 46 :
RESIZE_OBSERVER_AVAILABLE = false;
- 47 :
}
- 48 :
- 49 :
// Only create an element when ResizeObserver isn't available
- 50 :
const options_ = mergeOptions({
- 51 :
createEl: !RESIZE_OBSERVER_AVAILABLE,
- 52 :
reportTouchActivity: false
- 53 :
}, options);
- 54 :
- 55 :
super(player, options_);
- 56 :
- 57 :
this.ResizeObserver = options.ResizeObserver || window.ResizeObserver;
- 58 :
this.loadListener_ = null;
- 59 :
this.resizeObserver_ = null;
- 60 :
this.debouncedHandler_ = debounce(() => {
- 61 :
this.resizeHandler();
- 62 :
}, 100, false, this);
- 63 :
- 64 :
if (RESIZE_OBSERVER_AVAILABLE) {
- 65 :
this.resizeObserver_ = new this.ResizeObserver(this.debouncedHandler_);
- 66 :
this.resizeObserver_.observe(player.el());
- 67 :
- 68 :
} else {
- 69 :
this.loadListener_ = () => {
- 70 :
if (!this.el_ || !this.el_.contentWindow) {
- 71 :
return;
- 72 :
}
- 73 :
- 74 :
const debouncedHandler_ = this.debouncedHandler_;
- 75 :
let unloadListener_ = this.unloadListener_ = function() {
- 76 :
Events.off(this, 'resize', debouncedHandler_);
- 77 :
Events.off(this, 'unload', unloadListener_);
- 78 :
- 79 :
unloadListener_ = null;
- 80 :
};
- 81 :
- 82 :
// safari and edge can unload the iframe before resizemanager dispose
- 83 :
// we have to dispose of event handlers correctly before that happens
- 84 :
Events.on(this.el_.contentWindow, 'unload', unloadListener_);
- 85 :
Events.on(this.el_.contentWindow, 'resize', debouncedHandler_);
- 86 :
};
- 87 :
- 88 :
this.one('load', this.loadListener_);
- 89 :
}
- 90 :
}
- 91 :
- 92 :
createEl() {
- 93 :
return super.createEl('iframe', {
- 94 :
className: 'vjs-resize-manager',
- 95 :
tabIndex: -1
- 96 :
}, {
- 97 :
'aria-hidden': 'true'
- 98 :
});
- 99 :
}
- 100 :
- 101 :
/**
- 102 :
* Called when a resize is triggered on the iframe or a resize is observed via the ResizeObserver
- 103 :
*
- 104 :
* @fires Player#playerresize
- 105 :
*/
- 106 :
resizeHandler() {
- 107 :
/**
- 108 :
* Called when the player size has changed
- 109 :
*
- 110 :
* @event Player#playerresize
- 111 :
* @type {EventTarget~Event}
- 112 :
*/
- 113 :
// make sure player is still around to trigger
- 114 :
// prevents this from causing an error after dispose
- 115 :
if (!this.player_ || !this.player_.trigger) {
- 116 :
return;
- 117 :
}
- 118 :
- 119 :
this.player_.trigger('playerresize');
- 120 :
}
- 121 :
- 122 :
dispose() {
- 123 :
if (this.debouncedHandler_) {
- 124 :
this.debouncedHandler_.cancel();
- 125 :
}
- 126 :
- 127 :
if (this.resizeObserver_) {
- 128 :
if (this.player_.el()) {
- 129 :
this.resizeObserver_.unobserve(this.player_.el());
- 130 :
}
- 131 :
this.resizeObserver_.disconnect();
- 132 :
}
- 133 :
- 134 :
if (this.loadListener_) {
- 135 :
this.off('load', this.loadListener_);
- 136 :
}
- 137 :
- 138 :
if (this.el_ && this.el_.contentWindow && this.unloadListener_) {
- 139 :
this.unloadListener_.call(this.el_.contentWindow);
- 140 :
}
- 141 :
- 142 :
this.ResizeObserver = null;
- 143 :
this.resizeObserver = null;
- 144 :
this.debouncedHandler_ = null;
- 145 :
this.loadListener_ = null;
- 146 :
super.dispose();
- 147 :
}
- 148 :
- 149 :
}
- 150 :
- 151 :
Component.registerComponent('ResizeManager', ResizeManager);
- 152 :
export default ResizeManager;