Backed out 2 changesets (bug 1654054) for causing bc failures on browser_nimbusShowIconOnly.js

CLOSED TREE

Backed out changeset 2b6a67ada4d3 (bug 1654054)
Backed out changeset 2f9ad49eb131 (bug 1654054)
This commit is contained in:
Norisz Fay 2022-04-21 22:53:22 +03:00
Родитель fabc9f884f
Коммит 88be59b607
9 изменённых файлов: 264 добавлений и 417 удалений

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

@ -466,15 +466,6 @@ async function compareFiles(src1, src2, options = {}) {
iframeElement.addEventListener("load", resolve, { capture: true, once: true });
iframeElement.setAttribute("src", new URL(src1, BASE).href);
});
let mediaElements = iframeElement.contentDocument.querySelectorAll(
"audio, video"
);
for (let mediaElement of mediaElements) {
let { widget } = SpecialPowers.wrap(iframeElement.contentWindow)
.windowGlobalChild.getActor("UAWidgets")
.widgets.get(mediaElement);
await widget.impl.Utils.l10n.translateRoots();
}
if (messagePromise) {
info("awaiting for message to arrive");
@ -489,15 +480,6 @@ async function compareFiles(src1, src2, options = {}) {
iframeElement.addEventListener("load", resolve, { capture: true, once: true });
iframeElement.setAttribute("src", new URL(src2, BASE).href);
});
mediaElements = iframeElement.contentDocument.querySelectorAll(
"audio, video"
);
for (let mediaElement of mediaElements) {
let { widget } = SpecialPowers.wrap(iframeElement.contentWindow)
.windowGlobalChild.getActor("UAWidgets")
.widgets.get(mediaElement);
await widget.impl.Utils.l10n.translateRoots();
}
await printpreview(options.ref || options);
drawPrintPreviewWindow(ctx2);

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

@ -1,111 +0,0 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
from __future__ import absolute_import
import fluent.syntax.ast as FTL
from fluent.migrate.helpers import transforms_from, TERM_REFERENCE, VARIABLE_REFERENCE
from fluent.migrate import REPLACE, COPY
def migrate(ctx):
"""Bug 1654054 - Port videocontrols to Fluent, part {index}."""
source = "toolkit/chrome/global/videocontrols.dtd"
target = "toolkit/toolkit/global/videocontrols.ftl"
ctx.add_transforms(
target,
target,
transforms_from(
"""
videocontrols-play-button =
.aria-label = { COPY(from_path, "playButton.playLabel") }
videocontrols-pause-button =
.aria-label = { COPY(from_path, "playButton.pauseLabel") }
videocontrols-mute-button =
.aria-label = { COPY(from_path, "muteButton.muteLabel") }
videocontrols-unmute-button =
.aria-label = { COPY(from_path, "muteButton.unmuteLabel") }
videocontrols-enterfullscreen-button =
.aria-label = { COPY(from_path, "fullscreenButton.enterfullscreenlabel") }
videocontrols-exitfullscreen-button =
.aria-label = { COPY(from_path, "fullscreenButton.exitfullscreenlabel") }
videocontrols-casting-button-label =
.aria-label = { COPY(from_path, "castingButton.castingLabel") }
videocontrols-closed-caption-off =
.offlabel = { COPY(from_path, "closedCaption.off") }
videocontrols-picture-in-picture-label = { COPY(from_path, "pictureInPicture.label") }
videocontrols-picture-in-picture-toggle-label = { COPY(from_path, "pictureInPictureToggle.label") }
""",
from_path=source,
),
)
ctx.add_transforms(
target,
target,
[
FTL.Message(
id=FTL.Identifier("videocontrols-picture-in-picture-explainer"),
value=REPLACE(
source,
"pictureInPictureExplainer",
{
"&brandShortName;": TERM_REFERENCE("brand-short-name"),
},
),
),
],
)
ctx.add_transforms(
target,
target,
transforms_from(
"""
videocontrols-error-aborted = { COPY(from_path, "error.aborted") }
videocontrols-error-network = { COPY(from_path, "error.network") }
videocontrols-error-decode = { COPY(from_path, "error.decode") }
videocontrols-error-src-not-supported = { COPY(from_path, "error.srcNotSupported") }
videocontrols-error-no-source = { COPY(from_path, "error.noSource2") }
videocontrols-error-generic = { COPY(from_path, "error.generic") }
videocontrols-status-picture-in-picture = { COPY(from_path, "status.pictureInPicture") }
""",
from_path=source,
),
)
ctx.add_transforms(
target,
target,
[
FTL.Message(
id=FTL.Identifier("videocontrols-position-and-duration-labels"),
value=REPLACE(
source,
"positionAndDuration.nameFormat",
{
"<span>": FTL.TextElement(
'<span data-l10n-name="position-duration-format">'
),
"#1": VARIABLE_REFERENCE("position"),
"#2": VARIABLE_REFERENCE("duration"),
},
),
),
],
)

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

@ -72,14 +72,21 @@ add_task(async function test_experiment_control() {
url: TEST_PAGE,
},
async browser => {
const l10n = new Localization(
["branding/brand.ftl", "toolkit/global/videocontrols.ftl"],
true
);
const s = `<!DOCTYPE bindings [
<!ENTITY % videocontrolsDTD SYSTEM "chrome://global/locale/videocontrols.dtd">
%videocontrolsDTD;
]>
<html xmlns=\"http://www.w3.org/1999/xhtml\">
<head>
<meta charset=\"utf-8\"/>
<div class="pip-message">&pictureInPictureExplainer;</div>
</head>
</html>`;
const parser = new DOMParser();
let pipExplainerMessage = l10n.formatValueSync(
"videocontrols-picture-in-picture-explainer"
);
parser.forceEnableDTD();
let doc = parser.parseFromString(s, "application/xhtml+xml");
const pipDTDMessage = doc.querySelector(".pip-message").innerHTML.trim();
await SimpleTest.promiseFocus(browser);
await ensureVideosReady(browser);
@ -93,8 +100,8 @@ add_task(async function test_experiment_control() {
let videoID = "with-controls";
await hoverToggle(browser, videoID);
await SpecialPowers.spawn(browser, [pipExplainerMessage], async function(
pipExplainerMessage
await SpecialPowers.spawn(browser, [pipDTDMessage], async function(
pipDTDMessage
) {
let video = content.document.getElementById("with-controls");
let shadowRoot = video.openOrClosedShadowRoot;
@ -102,7 +109,7 @@ add_task(async function test_experiment_control() {
Assert.equal(
pipButton.textContent.trim(),
pipExplainerMessage,
pipDTDMessage,
"The PiP explainer is default"
);
});

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

@ -20,17 +20,13 @@
const testCases = [];
function testUI(video) {
const clickToPlay = getElementWithinVideo(video, "clickToPlay");
ok(!!clickToPlay.getAttribute("aria-label"), "clickToPlay has aria-label attribute");
const clickToPlay = getElementWithinVideo(video, "clickToPlay");
ok(!!clickToPlay.getAttribute("aria-label"), "clickToPlay has aria-label attribute");
};
videoElems.forEach(video => {
testCases.push(() => new Promise(resolve => {
SimpleTest.executeSoon(async () => {
const { widget } = SpecialPowers.wrap(window)
.windowGlobalChild.getActor("UAWidgets")
.widgets.get(video);
await widget.impl.Utils.l10n.translateRoots();
SimpleTest.executeSoon(() => {
testUI(video);
resolve();
});

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

@ -28,15 +28,7 @@ RemoteCanvas.prototype.load = function(callback) {
"suspend",
function(aEvent) {
setTimeout(function() {
let mediaElement = iframe.contentDocument.querySelector(
"audio, video"
);
const { widget } = SpecialPowers.wrap(iframe.contentWindow)
.windowGlobalChild.getActor("UAWidgets")
.widgets.get(mediaElement);
widget.impl.Utils.l10n.translateRoots().then(() => {
me.remotePageLoaded(callback);
});
me.remotePageLoaded(callback);
}, 0);
},
{ once: true }

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

@ -264,7 +264,6 @@ this.VideoControlsImplWidget = class {
fullscreenButton: null,
layoutControls: null,
isShowingPictureInPictureMessage: false,
l10n: this.l10n,
textTracksCount: 0,
videoEvents: [
@ -474,12 +473,101 @@ this.VideoControlsImplWidget = class {
this.clickToPlay,
];
let throwOnGet = {
get() {
throw new Error("Please don't trigger reflow. See bug 1493525.");
},
};
for (let control of adjustableControls) {
if (!control) {
break;
}
this.defineControlProperties(control);
Object.defineProperties(control, {
// We should directly access CSSOM to get pre-defined style instead of
// retrieving computed dimensions from layout.
minWidth: {
get: () => {
let controlId = control.id;
let propertyName = `--${controlId}-width`;
if (control.modifier) {
propertyName += "-" + control.modifier;
}
let preDefinedSize = this.controlBarComputedStyles.getPropertyValue(
propertyName
);
// The stylesheet from <link> might not be loaded if the
// element was inserted into a hidden iframe.
// We can safely return 0 here for now, given that the controls
// will be resized again, by the resizevideocontrols event,
// from nsVideoFrame, when the element is visible.
if (!preDefinedSize) {
return 0;
}
return parseInt(preDefinedSize, 10);
},
},
offsetLeft: throwOnGet,
offsetTop: throwOnGet,
offsetWidth: throwOnGet,
offsetHeight: throwOnGet,
offsetParent: throwOnGet,
clientLeft: throwOnGet,
clientTop: throwOnGet,
clientWidth: throwOnGet,
clientHeight: throwOnGet,
getClientRects: throwOnGet,
getBoundingClientRect: throwOnGet,
isAdjustableControl: {
value: true,
},
modifier: {
value: "",
writable: true,
},
isWanted: {
value: true,
writable: true,
},
hidden: {
set: v => {
control._isHiddenExplicitly = v;
control._updateHiddenAttribute();
},
get: () => {
return (
control.hasAttribute("hidden") ||
control.classList.contains("fadeout")
);
},
},
hiddenByAdjustment: {
set: v => {
control._isHiddenByAdjustment = v;
control._updateHiddenAttribute();
},
get: () => control._isHiddenByAdjustment,
},
_isHiddenByAdjustment: {
value: false,
writable: true,
},
_isHiddenExplicitly: {
value: false,
writable: true,
},
_updateHiddenAttribute: {
value: () => {
control.toggleAttribute(
"hidden",
control._isHiddenExplicitly || control._isHiddenByAdjustment
);
},
},
});
}
this.adjustControlSize();
@ -489,98 +577,6 @@ this.VideoControlsImplWidget = class {
this.updateVolumeControls();
},
defineControlProperties(control) {
let throwOnGet = {
get() {
throw new Error("Please don't trigger reflow. See bug 1493525.");
},
};
Object.defineProperties(control, {
// We should directly access CSSOM to get pre-defined style instead of
// retrieving computed dimensions from layout.
minWidth: {
get: () => {
let controlId = control.id;
let propertyName = `--${controlId}-width`;
if (control.modifier) {
propertyName += "-" + control.modifier;
}
let preDefinedSize = this.controlBarComputedStyles.getPropertyValue(
propertyName
);
// The stylesheet from <link> might not be loaded if the
// element was inserted into a hidden iframe.
// We can safely return 0 here for now, given that the controls
// will be resized again, by the resizevideocontrols event,
// from nsVideoFrame, when the element is visible.
if (!preDefinedSize) {
return 0;
}
return parseInt(preDefinedSize, 10);
},
},
offsetLeft: throwOnGet,
offsetTop: throwOnGet,
offsetWidth: throwOnGet,
offsetHeight: throwOnGet,
offsetParent: throwOnGet,
clientLeft: throwOnGet,
clientTop: throwOnGet,
clientWidth: throwOnGet,
clientHeight: throwOnGet,
getClientRects: throwOnGet,
getBoundingClientRect: throwOnGet,
isAdjustableControl: {
value: true,
},
modifier: {
value: "",
writable: true,
},
isWanted: {
value: true,
writable: true,
},
hidden: {
set: v => {
control._isHiddenExplicitly = v;
control._updateHiddenAttribute();
},
get: () => {
return (
control.hasAttribute("hidden") ||
control.classList.contains("fadeout")
);
},
},
hiddenByAdjustment: {
set: v => {
control._isHiddenByAdjustment = v;
control._updateHiddenAttribute();
},
get: () => control._isHiddenByAdjustment,
},
_isHiddenByAdjustment: {
value: false,
writable: true,
},
_isHiddenExplicitly: {
value: false,
writable: true,
},
_updateHiddenAttribute: {
value: () => {
control.toggleAttribute(
"hidden",
control._isHiddenExplicitly || control._isHiddenByAdjustment
);
},
},
});
},
updatePictureInPictureToggleDisplay() {
if (this.isAudioOnly) {
this.pictureInPictureToggle.hidden = true;
@ -1161,16 +1157,35 @@ this.VideoControlsImplWidget = class {
},
initPositionDurationBox() {
const positionTextNode = Array.prototype.find.call(
this.positionDurationBox.childNodes,
n => !!~n.textContent.search("#1")
);
const durationSpan = this.durationSpan;
const durationFormat = durationSpan.textContent;
const positionFormat = positionTextNode.textContent;
durationSpan.classList.add("duration");
durationSpan.setAttribute("role", "none");
durationSpan.id = "durationSpan";
this.l10n.setAttributes(
this.positionDurationBox,
"videocontrols-position-and-duration-labels",
{ position: "", duration: "" }
);
Object.defineProperties(this.positionDurationBox, {
durationSpan: {
value: durationSpan,
},
position: {
set: v => {
positionTextNode.textContent = positionFormat.replace("#1", v);
},
},
duration: {
set: v => {
durationSpan.textContent = v
? durationFormat.replace("#2", v)
: "";
},
},
});
},
showDuration(duration) {
@ -1187,14 +1202,6 @@ this.VideoControlsImplWidget = class {
// Format the duration as "h:mm:ss" or "m:ss"
let timeString = isInfinite ? "" : this.formatTime(duration);
this.positionDurationBox.duration = timeString;
this.l10n.setAttributes(
this.positionDurationBox,
"videocontrols-position-and-duration-labels",
{
position: this.positionDurationBox.position,
duration: timeString,
}
);
if (this.showHours) {
this.positionDurationBox.modifier = "long";
@ -1272,38 +1279,10 @@ this.VideoControlsImplWidget = class {
this.scrubber.value = currentTime;
this.positionDurationBox.position = positionTime;
this.l10n.setAttributes(
this.positionDurationBox,
"videocontrols-position-and-duration-labels",
{
position: positionTime,
duration: this.positionDurationBox.duration,
}
this.scrubber.setAttribute(
"aria-valuetext",
this.positionDurationBox.textContent.trim()
);
// We use .formatValueSync here because .setAttribute doesn't update
// the DOM fast enough to use this.positionDurationBox.textContent and
// if we set the innterHTML on the positionDurationBox then we lose
// reference to the durationSpan element so it is easier to use
// .formatValueSync to just update the string for the aria-valuetext
let positionDurationMarkup = this.l10n.formatValueSync(
"videocontrols-position-and-duration-labels",
{
position: positionTime,
duration: this.positionDurationBox.duration,
}
);
// It's possible that the string we get has markup to overlay into the
// DOM. We only want the raw text so we use DOMParser to strip any tags
let parser = new this.window.DOMParser();
let positionDurationString = parser.parseFromString(
positionDurationMarkup,
"text/html"
).body.textContent;
this.scrubber.setAttribute("aria-valuetext", positionDurationString);
this.updateScrubberProgress();
},
@ -1719,10 +1698,11 @@ this.VideoControlsImplWidget = class {
this.controlBar.removeAttribute("fullscreen-unavailable");
this.adjustControlSize();
var id = this.isVideoInFullScreen
? "videocontrols-exitfullscreen-button"
: "videocontrols-enterfullscreen-button";
this.l10n.setAttributes(this.fullscreenButton, id);
var attrName = this.isVideoInFullScreen
? "exitfullscreenlabel"
: "enterfullscreenlabel";
var value = this.fullscreenButton.getAttribute(attrName);
this.fullscreenButton.setAttribute("aria-label", value);
if (this.isVideoInFullScreen) {
this.fullscreenButton.setAttribute("fullscreened", "true");
@ -1823,11 +1803,10 @@ this.VideoControlsImplWidget = class {
this.playButton.removeAttribute("paused");
}
var id = aPaused
? "videocontrols-play-button"
: "videocontrols-pause-button";
this.l10n.setAttributes(this.playButton, id);
this.l10n.setAttributes(this.clickToPlay, id);
var attrName = aPaused ? "playlabel" : "pauselabel";
var value = this.playButton.getAttribute(attrName);
this.playButton.setAttribute("aria-label", value);
this.clickToPlay.setAttribute("aria-label", value);
},
get isEffectivelyMuted() {
@ -1843,10 +1822,9 @@ this.VideoControlsImplWidget = class {
this.muteButton.removeAttribute("muted");
}
var id = muted
? "videocontrols-unmute-button"
: "videocontrols-mute-button";
this.l10n.setAttributes(this.muteButton, id);
var attrName = muted ? "unmutelabel" : "mutelabel";
var value = this.muteButton.getAttribute(attrName);
this.muteButton.setAttribute("aria-label", value);
},
keyboardVolumeDecrease() {
@ -2398,18 +2376,7 @@ this.VideoControlsImplWidget = class {
let widthUsed = minControlBarPaddingWidth;
let preventAppendControl = false;
for (let [index, control] of this.prioritizedControls.entries()) {
// The "durationSpan" element is disconnected from the document during l10n so
// we check if our reference to "durationSpan" is the connected one and if not we
// replace it with the correct one
if (control.id === "durationSpan" && !control.isConnected) {
const durationSpan = this.durationSpan;
if (durationSpan) {
this.defineControlProperties(durationSpan);
this.prioritizedControls[index] = durationSpan;
control = durationSpan;
}
}
for (let control of this.prioritizedControls) {
if (!control.isWanted) {
control.hiddenByAdjustment = true;
continue;
@ -2500,14 +2467,6 @@ this.VideoControlsImplWidget = class {
);
},
get positionDurationBox() {
return this.shadowRoot.getElementById("positionDurationBox");
},
get durationSpan() {
return this.positionDurationBox?.getElementsByTagName("span")[0];
},
init(shadowRoot, prefs) {
this.shadowRoot = shadowRoot;
this.video = this.installReflowCallValidator(shadowRoot.host);
@ -2538,6 +2497,9 @@ this.VideoControlsImplWidget = class {
this.scrubber = this.shadowRoot.getElementById("scrubber");
this.durationLabel = this.shadowRoot.getElementById("durationLabel");
this.positionLabel = this.shadowRoot.getElementById("positionLabel");
this.positionDurationBox = this.shadowRoot.getElementById(
"positionDurationBox"
);
this.statusOverlay = this.shadowRoot.getElementById("statusOverlay");
this.controlsOverlay = this.shadowRoot.getElementById(
"controlsOverlay"
@ -2562,6 +2524,12 @@ this.VideoControlsImplWidget = class {
"pictureInPictureToggle"
);
if (this.positionDurationBox) {
this.durationSpan = this.positionDurationBox.getElementsByTagName(
"span"
)[0];
}
let isMobile = this.window.navigator.appVersion.includes("Android");
if (isMobile) {
this.controlsContainer.classList.add("mobile");
@ -2832,30 +2800,35 @@ this.VideoControlsImplWidget = class {
* Remove it when migrate to Fluent.
*/
const parser = new this.window.DOMParser();
parser.forceEnableDTD();
let parserDoc = parser.parseFromString(
`<div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
`<!DOCTYPE bindings [
<!ENTITY % videocontrolsDTD SYSTEM "chrome://global/locale/videocontrols.dtd">
%videocontrolsDTD;
]>
<div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
<link rel="stylesheet" href="chrome://global/skin/media/videocontrols.css" />
<div id="controlsContainer" class="controlsContainer" role="none">
<div id="statusOverlay" class="statusOverlay stackItem" hidden="true">
<div id="statusIcon" class="statusIcon"></div>
<bdi class="statusLabel" id="errorAborted" data-l10n-id="videocontrols-error-aborted"></bdi>
<bdi class="statusLabel" id="errorNetwork" data-l10n-id="videocontrols-error-network"></bdi>
<bdi class="statusLabel" id="errorDecode" data-l10n-id="videocontrols-error-decode"></bdi>
<bdi class="statusLabel" id="errorSrcNotSupported" data-l10n-id="videocontrols-error-src-not-supported"></bdi>
<bdi class="statusLabel" id="errorNoSource" data-l10n-id="videocontrols-error-no-source"></bdi>
<bdi class="statusLabel" id="errorGeneric"> data-l10n-id="videocontrols-error-generic"></bdi>
<bdi class="statusLabel" id="errorAborted">&error.aborted;</bdi>
<bdi class="statusLabel" id="errorNetwork">&error.network;</bdi>
<bdi class="statusLabel" id="errorDecode">&error.decode;</bdi>
<bdi class="statusLabel" id="errorSrcNotSupported">&error.srcNotSupported;</bdi>
<bdi class="statusLabel" id="errorNoSource">&error.noSource2;</bdi>
<bdi class="statusLabel" id="errorGeneric">&error.generic;</bdi>
</div>
<div id="pictureInPictureOverlay" class="pictureInPictureOverlay stackItem" status="pictureInPicture" hidden="true">
<div class="statusIcon" type="pictureInPicture"></div>
<bdi class="statusLabel" id="pictureInPicture" data-l10n-id="videocontrols-status-picture-in-picture"></bdi>
<bdi class="statusLabel" id="pictureInPicture">&status.pictureInPicture;</bdi>
</div>
<div id="controlsOverlay" class="controlsOverlay stackItem" role="none">
<div class="controlsSpacerStack">
<div id="controlsSpacer" class="controlsSpacer stackItem" role="none"></div>
<button id="clickToPlay" class="clickToPlay" hidden="true"></button>
<button id="clickToPlay" class="clickToPlay" aria-label="&playButton.playLabel;" hidden="true"></button>
</div>
<button id="pictureInPictureToggle" class="pip-wrapper" position="left" hidden="true">
@ -2863,9 +2836,11 @@ this.VideoControlsImplWidget = class {
<div class="pip-expanded clickable">
<span class="pip-icon-label clickable">
<span class="pip-icon"></span>
<span class="pip-label" data-l10n-id="videocontrols-picture-in-picture-toggle-label"></span>
<span class="pip-label">&pictureInPictureToggle.label;</span>
</span>
<div class="pip-explainer clickable" data-l10n-id="videocontrols-picture-in-picture-explainer"></div>
<div class="pip-explainer clickable">
&pictureInPictureExplainer;
</div>
</div>
<div class="pip-icon clickable"></div>
</button>
@ -2873,6 +2848,8 @@ this.VideoControlsImplWidget = class {
<div id="controlBar" class="controlBar" role="none" hidden="true">
<button id="playButton"
class="button playButton"
playlabel="&playButton.playLabel;"
pauselabel="&playButton.pauseLabel;"
tabindex="-1"/>
<div id="scrubberStack" class="scrubberStack progressContainer" role="none">
<div class="progressBackgroundBar stackItem" role="none">
@ -2890,36 +2867,39 @@ this.VideoControlsImplWidget = class {
<bdi id="positionLabel" class="positionLabel" role="presentation"></bdi>
<bdi id="durationLabel" class="durationLabel" role="presentation"></bdi>
<bdi id="positionDurationBox" class="positionDurationBox" aria-hidden="true">
<span data-l10n-name="position-duration-format"></span>
&positionAndDuration.nameFormat;
</bdi>
<div id="controlBarSpacer" class="controlBarSpacer" hidden="true" role="none"></div>
<button id="muteButton"
class="button muteButton"
mutelabel="&muteButton.muteLabel;"
unmutelabel="&muteButton.unmuteLabel;"
tabindex="-1"/>
<div id="volumeStack" class="volumeStack progressContainer" role="none">
<input type="range" id="volumeControl" class="volumeControl" min="0" max="100" step="1" tabindex="-1"
data-l10n-id="videocontrols-volume-control"/>
</div>
<button id="castingButton" class="button castingButton"
data-l10n-id="videocontrols-casting-button-label"/>
aria-label="&castingButton.castingLabel;"/>
<button id="closedCaptionButton" class="button closedCaptionButton" aria-controls="textTrackList"
aria-haspopup="menu" aria-expanded="false" data-l10n-id="videocontrols-closed-caption-button"/>
<div id="textTrackListContainer" class="textTrackListContainer" hidden="true" role="presentation">
<div id="textTrackList" role="menu" class="textTrackList"
data-l10n-id="videocontrols-closed-caption-off" data-l10n-attrs="offlabel"/>
<div id="textTrackList" role="menu" class="textTrackList" offlabel="&closedCaption.off;"
data-l10n-id="videocontrols-closed-caption-button"/>
</div>
<button id="fullscreenButton"
class="button fullscreenButton"/>
class="button fullscreenButton"
enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
</div>
</div>
</div>
</div>`,
"application/xml"
);
this.l10n = new this.window.DOMLocalization(
["branding/brand.ftl", "toolkit/global/videocontrols.ftl"],
true
);
this.l10n = new this.window.DOMLocalization([
"toolkit/global/videocontrols.ftl",
]);
this.l10n.connectRoot(this.shadowRoot);
if (this.prefs["media.videocontrols.keyboard-tab-to-all-controls"]) {
// Make all of the individual controls tabbable.
@ -2934,7 +2914,6 @@ this.VideoControlsImplWidget = class {
parserDoc.documentElement,
true
);
this.l10n.translateRoots();
}
elementStateMatches(element) {
@ -3123,8 +3102,13 @@ this.NoControlsMobileImplWidget = class {
* Remove it when migrate to Fluent.
*/
const parser = new this.window.DOMParser();
parser.forceEnableDTD();
let parserDoc = parser.parseFromString(
`<div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
`<!DOCTYPE bindings [
<!ENTITY % videocontrolsDTD SYSTEM "chrome://global/locale/videocontrols.dtd">
%videocontrolsDTD;
]>
<div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
<link rel="stylesheet" href="chrome://global/skin/media/videocontrols.css" />
<div id="controlsContainer" class="controlsContainer" role="none" hidden="true">
<div class="controlsOverlay stackItem">
@ -3175,13 +3159,18 @@ this.NoControlsPictureInPictureImplWidget = class {
* Remove it when migrate to Fluent.
*/
const parser = new this.window.DOMParser();
parser.forceEnableDTD();
let parserDoc = parser.parseFromString(
`<div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
`<!DOCTYPE bindings [
<!ENTITY % videocontrolsDTD SYSTEM "chrome://global/locale/videocontrols.dtd">
%videocontrolsDTD;
]>
<div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
<link rel="stylesheet" href="chrome://global/skin/media/videocontrols.css" />
<div id="controlsContainer" class="controlsContainer" role="none">
<div class="pictureInPictureOverlay stackItem" status="pictureInPicture">
<div id="statusIcon" class="statusIcon" type="pictureInPicture"></div>
<bdi class="statusLabel" id="pictureInPicture" data-l10n-id="videocontrols-status-picture-in-picture"></bdi>
<bdi class="statusLabel" id="pictureInPicture">&status.pictureInPicture;</bdi>
</div>
<div class="controlsOverlay stackItem"></div>
</div>
@ -3193,12 +3182,6 @@ this.NoControlsPictureInPictureImplWidget = class {
parserDoc.documentElement,
true
);
this.l10n = new this.window.DOMLocalization([
"branding/brand.ftl",
"toolkit/global/videocontrols.ftl",
]);
this.l10n.connectRoot(this.shadowRoot);
this.l10n.translateRoots();
}
};
@ -3358,8 +3341,13 @@ this.NoControlsDesktopImplWidget = class {
* Remove it when migrate to Fluent.
*/
const parser = new this.window.DOMParser();
parser.forceEnableDTD();
let parserDoc = parser.parseFromString(
`<div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
`<!DOCTYPE bindings [
<!ENTITY % videocontrolsDTD SYSTEM "chrome://global/locale/videocontrols.dtd">
%videocontrolsDTD;
]>
<div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
<link rel="stylesheet" href="chrome://global/skin/media/videocontrols.css" />
<div id="controlsContainer" class="controlsContainer" role="none">
@ -3369,9 +3357,11 @@ this.NoControlsDesktopImplWidget = class {
<div class="pip-expanded clickable">
<span class="pip-icon-label clickable">
<span class="pip-icon"></span>
<span class="pip-label" data-l10n-id="videocontrols-picture-in-picture-toggle-label"></span>
<span class="pip-label">&pictureInPictureToggle.label;</span>
</span>
<div class="pip-explainer clickable" data-l10n-id="videocontrols-picture-in-picture-explainer"></div>
<div class="pip-explainer clickable">
&pictureInPictureExplainer;
</div>
</div>
<div class="pip-icon"></div>
</button>
@ -3385,11 +3375,5 @@ this.NoControlsDesktopImplWidget = class {
parserDoc.documentElement,
true
);
this.l10n = new this.window.DOMLocalization([
"branding/brand.ftl",
"toolkit/global/videocontrols.ftl",
]);
this.l10n.connectRoot(this.shadowRoot);
this.l10n.translateRoots();
}
};

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

@ -0,0 +1,48 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY % brandDTD
SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY playButton.playLabel "Play">
<!ENTITY playButton.pauseLabel "Pause">
<!ENTITY muteButton.muteLabel "Mute">
<!ENTITY muteButton.unmuteLabel "Unmute">
<!ENTITY fullscreenButton.enterfullscreenlabel "Full Screen">
<!ENTITY fullscreenButton.exitfullscreenlabel "Exit Full Screen">
<!ENTITY castingButton.castingLabel "Cast to Screen">
<!ENTITY closedCaption.off "Off">
<!-- LOCALIZATION NOTE (pictureInPicture.label): This string is used as part of
the Picture-in-Picture video toggle button when the mouse is hovering it. -->
<!ENTITY pictureInPicture.label "Picture-in-Picture">
<!-- LOCALIZATION NOTE (pictureInPictureToggle.label): This string is used as the
label for a variation of the Picture-in-Picture video toggle button when the mouse is
hovering over the video. -->
<!ENTITY pictureInPictureToggle.label "Watch in Picture-in-Picture">
<!-- LOCALIZATION NOTE (pictureInPictureExplainer): This string is used as part of
a variation of the Picture-in-Picture video toggle button. When using this variation,
this string appears below the toggle when the mouse hovers the toggle. -->
<!ENTITY pictureInPictureExplainer "Play videos in the foreground while you do other things in &brandShortName;">
<!ENTITY error.aborted "Video loading stopped.">
<!ENTITY error.network "Video playback aborted due to a network error.">
<!ENTITY error.decode "Video cant be played because the file is corrupt.">
<!ENTITY error.srcNotSupported "Video format or MIME type is not supported.">
<!ENTITY error.noSource2 "No video with supported format and MIME type found.">
<!ENTITY error.generic "Video playback aborted due to an unknown error.">
<!ENTITY status.pictureInPicture "This video is playing in Picture-in-Picture mode.">
<!-- LOCALIZATION NOTE (positionAndDuration.nameFormat): the #1 string is the current
media position, and the #2 string is the total duration. For example, when at
the 5 minute mark in a 6 hour long video, #1 would be "5:00" and #2 would be
"6:00:00", result string would be "5:00 / 6:00:00".
Note that #2 is not always available. For example, when at the 5 minute mark in an
unknown duration video, #1 would be "5:00" and the string which is surrounded by
<span> would be deleted, result string would be "5:00".
-->
<!ENTITY positionAndDuration.nameFormat "#1<span> / #2</span>">

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

@ -12,55 +12,3 @@ videocontrols-volume-control =
.aria-label = Volume
videocontrols-closed-caption-button =
.aria-label = Closed Captions
videocontrols-play-button =
.aria-label = Play
videocontrols-pause-button =
.aria-label = Pause
videocontrols-mute-button =
.aria-label = Mute
videocontrols-unmute-button =
.aria-label = Unmute
videocontrols-enterfullscreen-button =
.aria-label = Full Screen
videocontrols-exitfullscreen-button =
.aria-label = Exit Full Screen
videocontrols-casting-button-label =
.aria-label = Cast to Screen
videocontrols-closed-caption-off =
.offlabel = Off
# This string is used as part of the Picture-in-Picture video toggle button when
# the mouse is hovering it.
videocontrols-picture-in-picture-label = Picture-in-Picture
# This string is used as the label for a variation of the Picture-in-Picture video
# toggle button when the mouse is hovering over the video.
videocontrols-picture-in-picture-toggle-label = Watch in Picture-in-Picture
# This string is used as part of a variation of the Picture-in-Picture video toggle
# button. When using this variation, this string appears below the toggle when the
# mouse hovers the toggle.
videocontrols-picture-in-picture-explainer = Play videos in the foreground while you do other things in { -brand-short-name }
videocontrols-error-aborted = Video loading stopped.
videocontrols-error-network = Video playback aborted due to a network error.
videocontrols-error-decode = Video cant be played because the file is corrupt.
videocontrols-error-src-not-supported = Video format or MIME type is not supported.
videocontrols-error-no-source = No video with supported format and MIME type found.
videocontrols-error-generic = Video playback aborted due to an unknown error.
videocontrols-status-picture-in-picture = This video is playing in Picture-in-Picture mode.
# This message shows the current position and total video duration
#
# Variables:
# $position (String): The current media position
# $duration (String): The total video duration
#
# For example, when at the 5 minute mark in a 6 hour long video,
# $position would be "5:00" and $duration would be "6:00:00", result
# string would be "5:00 / 6:00:00". Note that $duration is not always
# available. For example, when at the 5 minute mark in an unknown
# duration video, $position would be "5:00" and the string which is
# surrounded by <span> would be deleted, result string would be "5:00".
videocontrols-position-and-duration-labels = { $position }<span data-l10n-name="position-duration-format"> / { $duration }</span>

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

@ -43,6 +43,7 @@
locale/@AB_CD@/global/resetProfile.properties (%chrome/global/resetProfile.properties)
locale/@AB_CD@/global/dialog.properties (%chrome/global/dialog.properties)
locale/@AB_CD@/global/tree.dtd (%chrome/global/tree.dtd)
locale/@AB_CD@/global/videocontrols.dtd (%chrome/global/videocontrols.dtd)
locale/@AB_CD@/global/viewSource.properties (%chrome/global/viewSource.properties)
locale/@AB_CD@/global/wizard.properties (%chrome/global/wizard.properties)
% locale global-platform @AB_CD@ %locale/@AB_CD@/global-platform/unix/ os=LikeUnix os=Android