Bug 1546954 - Refactor player.js to break up large anonymous functions into smaller pieces. r=JSON_voorhees

Differential Revision: https://phabricator.services.mozilla.com/D37885

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Mike Conley 2019-07-17 16:18:28 +00:00
Родитель 3ff0a02c54
Коммит 47499265e5
2 изменённых файлов: 205 добавлений и 74 удалений

Просмотреть файл

@ -51,16 +51,16 @@ var PictureInPicture = {
break;
}
case "PictureInPicture:Playing": {
let controls = this.weakPipControls && this.weakPipControls.get();
if (controls) {
controls.classList.add("playing");
let player = this.weakPipPlayer && this.weakPipPlayer.get();
if (player) {
player.setIsPlayingState(true);
}
break;
}
case "PictureInPicture:Paused": {
let controls = this.weakPipControls && this.weakPipControls.get();
if (controls) {
controls.classList.remove("playing");
let player = this.weakPipPlayer && this.weakPipPlayer.get();
if (player) {
player.setIsPlayingState(false);
}
break;
}
@ -131,16 +131,14 @@ var PictureInPicture = {
let parentWin = browser.ownerGlobal;
this.browser = browser;
let win = await this.openPipWindow(parentWin, videoData);
let controls = win.document.getElementById("controls");
this.weakPipControls = Cu.getWeakReference(controls);
if (videoData.playing) {
controls.classList.add("playing");
}
this.weakPipPlayer = Cu.getWeakReference(win);
win.setIsPlayingState(videoData.playing);
// set attribute which shows pip icon in tab
let tab = parentWin.gBrowser.getTabForBrowser(browser);
tab.setAttribute("pictureinpicture", true);
win.setupPlayer(gNextWindowID.toString(), browser, videoData);
win.setupPlayer(gNextWindowID.toString(), browser);
gNextWindowID++;
},
@ -162,7 +160,7 @@ var PictureInPicture = {
);
this.clearPipTabIcon();
delete this.weakPipControls;
delete this.weakPipPlayer;
delete this.browser;
},

Просмотреть файл

@ -14,88 +14,221 @@ const { DeferredTask } = ChromeUtils.import(
const CONTROLS_FADE_TIMEOUT_MS = 3000;
const RESIZE_DEBOUNCE_RATE_MS = 500;
async function setupPlayer(id, originatingBrowser, videoData) {
let holder = document.querySelector(".player-holder");
let browser = document.getElementById("browser");
browser.remove();
/**
* Public function to be called from PictureInPicture.jsm. This is the main
* entrypoint for initializing the player window.
*
* @param id (Number)
* A unique numeric ID for the window, used for Telemetry Events.
* @param originatingBrowser (xul:browser)
* The <xul:browser> that the Picture-in-Picture video is coming from.
*/
function setupPlayer(id, originatingBrowser) {
Player.init(id, originatingBrowser);
}
browser.setAttribute("nodefaultsrc", "true");
browser.sameProcessAsFrameLoader = originatingBrowser.frameLoader;
holder.appendChild(browser);
/**
* Public function to be called from PictureInPicture.jsm. This update the
* controls based on whether or not the video is playing.
*
* @param isPlaying (Boolean)
* True if the Picture-in-Picture video is playing.
*/
function setIsPlayingState(isPlaying) {
Player.isPlaying = isPlaying;
}
browser.loadURI("about:blank", {
triggeringPrincipal: originatingBrowser.contentPrincipal,
});
/**
* The Player object handles initializing the player, holds state, and handles
* events for updating state.
*/
let Player = {
WINDOW_EVENTS: ["click", "mouseout", "resize", "unload"],
mm: null,
/**
* Used for resizing Telemetry to avoid recording an event for every resize
* event. Instead, we wait until RESIZE_DEBOUNCE_RATE_MS has passed since the
* last resize event before recording.
*/
resizeDebouncer: null,
/**
* Used for window movement Telemetry to determine if the player window has
* moved since the last time we checked.
*/
lastScreenX: -1,
lastScreenY: -1,
id: -1,
let mm = browser.frameLoader.messageManager;
mm.sendAsyncMessage("PictureInPicture:SetupPlayer");
/**
* Initializes the player browser, and sets up the initial state.
*
* @param id (Number)
* A unique numeric ID for the window, used for Telemetry Events.
* @param originatingBrowser (xul:browser)
* The <xul:browser> that the Picture-in-Picture video is coming from.
*/
init(id, originatingBrowser) {
this.id = id;
document.getElementById("play").addEventListener("click", () => {
mm.sendAsyncMessage("PictureInPicture:Play");
});
let holder = document.querySelector(".player-holder");
let browser = document.getElementById("browser");
browser.remove();
document.getElementById("pause").addEventListener("click", () => {
mm.sendAsyncMessage("PictureInPicture:Pause");
});
browser.setAttribute("nodefaultsrc", "true");
browser.sameProcessAsFrameLoader = originatingBrowser.frameLoader;
holder.appendChild(browser);
document.getElementById("unpip").addEventListener("click", () => {
PictureInPicture.focusTabAndClosePip();
});
browser.loadURI("about:blank", {
triggeringPrincipal: originatingBrowser.contentPrincipal,
});
// If the content process hosting the video crashes, let's
// just close the window for now.
browser.addEventListener("oop-browser-crashed", () => {
PictureInPicture.closePipWindow({ reason: "browser-crash" });
});
this.mm = browser.frameLoader.messageManager;
this.mm.sendAsyncMessage("PictureInPicture:SetupPlayer");
let close = document.getElementById("close");
close.addEventListener("click", () => {
PictureInPicture.closePipWindow({ reason: "close-button" });
});
for (let eventType of this.WINDOW_EVENTS) {
addEventListener(eventType, this);
}
document.getElementById("controls").setAttribute("showing", true);
setTimeout(() => {
document.getElementById("controls").removeAttribute("showing");
}, CONTROLS_FADE_TIMEOUT_MS);
// If the content process hosting the video crashes, let's
// just close the window for now.
browser.addEventListener("oop-browser-crashed", this);
Services.telemetry.setEventRecordingEnabled("pictureinpicture", true);
// Show the controls immediately, but set them up to fade out after
// CONTROLS_FADE_TIMEOUT_MS if the mouse isn't hovering them.
this.controls.setAttribute("showing", true);
setTimeout(() => {
this.controls.removeAttribute("showing");
}, CONTROLS_FADE_TIMEOUT_MS);
let resizeDebouncer = new DeferredTask(() => {
Services.telemetry.recordEvent("pictureinpicture", "resize", "player", id, {
Services.telemetry.setEventRecordingEnabled("pictureinpicture", true);
this.resizeDebouncer = new DeferredTask(() => {
this.recordEvent("resize", {
width: window.outerWidth.toString(),
height: window.outerHeight.toString(),
});
}, RESIZE_DEBOUNCE_RATE_MS);
this.lastScreenX = window.screenX;
this.lastScreenY = window.screenY;
this.recordEvent("create", {
width: window.outerWidth.toString(),
height: window.outerHeight.toString(),
screenX: window.screenX.toString(),
screenY: window.screenY.toString(),
});
}, RESIZE_DEBOUNCE_RATE_MS);
},
addEventListener("resize", e => {
resizeDebouncer.disarm();
resizeDebouncer.arm();
});
uninit() {
this.resizeDebouncer.disarm();
PictureInPicture.unload(window);
},
let lastScreenX = window.screenX;
let lastScreenY = window.screenY;
handleEvent(event) {
switch (event.type) {
case "click": {
this.onClick(event);
break;
}
addEventListener("mouseout", e => {
if (window.screenX != lastScreenX || window.screenY != lastScreenY) {
Services.telemetry.recordEvent("pictureinpicture", "move", "player", id, {
case "mouseout": {
this.onMouseOut(event);
break;
}
case "oop-browser-crashed": {
PictureInPicture.closePipWindow({ reason: "browser-crash" });
break;
}
case "resize": {
this.onResize(event);
break;
}
case "unload": {
this.uninit();
break;
}
}
},
onClick(event) {
switch (event.target.id) {
case "close": {
PictureInPicture.closePipWindow({ reason: "close-button" });
break;
}
case "play": {
this.mm.sendAsyncMessage("PictureInPicture:Play");
break;
}
case "pause": {
this.mm.sendAsyncMessage("PictureInPicture:Pause");
break;
}
case "unpip": {
PictureInPicture.focusTabAndClosePip();
break;
}
}
},
onMouseOut(event) {
if (
window.screenX != this.lastScreenX ||
window.screenY != this.lastScreenY
) {
this.recordEvent("move", {
screenX: window.screenX.toString(),
screenY: window.screenY.toString(),
});
}
lastScreenX = window.screenX;
lastScreenY = window.screenY;
});
this.lastScreenX = window.screenX;
this.lastScreenY = window.screenY;
},
Services.telemetry.recordEvent("pictureinpicture", "create", "player", id, {
width: window.outerWidth.toString(),
height: window.outerHeight.toString(),
screenX: window.screenX.toString(),
screenY: window.screenY.toString(),
});
onResize(event) {
this.resizeDebouncer.disarm();
this.resizeDebouncer.arm();
},
window.addEventListener("unload", () => {
resizeDebouncer.disarm();
PictureInPicture.unload(window);
});
}
get controls() {
delete this.controls;
return (this.controls = document.getElementById("controls"));
},
_isPlaying: false,
/**
* isPlaying returns true if the video is currently playing.
*
* @return Boolean
*/
get isPlaying() {
return this._isPlaying;
},
/**
* Set isPlaying to true if the video is playing, false otherwise. This will
* update the internal state and displayed controls.
*/
set isPlaying(isPlaying) {
this._isPlaying = isPlaying;
this.controls.classList.toggle("playing", isPlaying);
},
recordEvent(type, args) {
Services.telemetry.recordEvent(
"pictureinpicture",
type,
"player",
this.id,
args
);
},
};