Optimize CE()

This commit is contained in:
redphx 2024-12-23 05:55:11 +07:00
parent 560a4c309c
commit 03b7c7358e
27 changed files with 179 additions and 173 deletions

View File

@ -269,7 +269,6 @@ var SUPPORTED_LANGUAGES = {
"zh-CN": "中文(简体)", "zh-CN": "中文(简体)",
"zh-TW": "中文(繁體)" "zh-TW": "中文(繁體)"
}, Texts = { }, Texts = {
"slightly-increase-input-latency": "Slightly increase input latency",
achievements: "Achievements", achievements: "Achievements",
activate: "Activate", activate: "Activate",
activated: "Activated", activated: "Activated",
@ -567,6 +566,7 @@ var SUPPORTED_LANGUAGES = {
"show-wait-time-in-game-card": "Show wait time in game card", "show-wait-time-in-game-card": "Show wait time in game card",
"simplify-stream-menu": "Simplify Stream's menu", "simplify-stream-menu": "Simplify Stream's menu",
"skip-splash-video": "Skip Xbox splash video", "skip-splash-video": "Skip Xbox splash video",
"slightly-increases-input-latency": "Slightly increases input latency",
slow: "Slow", slow: "Slow",
small: "Small", small: "Small",
"smart-tv": "Smart TV", "smart-tv": "Smart TV",
@ -756,26 +756,28 @@ var ButtonStyleClass = {
4096: "bx-normal-case", 4096: "bx-normal-case",
8192: "bx-normal-link" 8192: "bx-normal-link"
}; };
function createElement(elmName, props = {}, ..._) { function createElement(elmName, props, ..._) {
let $elm, hasNs = "xmlns" in props; let $elm, hasNs = props && "xmlns" in props;
if (hasNs) $elm = document.createElementNS(props.xmlns, elmName), delete props.xmlns; if (hasNs) $elm = document.createElementNS(props.xmlns, elmName), delete props.xmlns;
else $elm = document.createElement(elmName); else $elm = document.createElement(elmName);
if (props._nearby) setNearby($elm, props._nearby), delete props._nearby; if (props) {
if (props._on) { if (props._nearby) setNearby($elm, props._nearby), delete props._nearby;
for (let name in props._on) if (props._on) {
$elm.addEventListener(name, props._on[name]); for (let name in props._on)
delete props._on; $elm.addEventListener(name, props._on[name]);
} delete props._on;
if (props._dataset) { }
for (let name in props._dataset) if (props._dataset) {
$elm.dataset[name] = props._dataset[name]; for (let name in props._dataset)
delete props._dataset; $elm.dataset[name] = props._dataset[name];
} delete props._dataset;
for (let key in props) { }
if ($elm.hasOwnProperty(key)) continue; for (let key in props) {
let value = props[key]; if ($elm.hasOwnProperty(key)) continue;
if (hasNs) $elm.setAttributeNS(null, key, value); let value = props[key];
else $elm.setAttribute(key, value); if (hasNs) $elm.setAttributeNS(null, key, value);
else $elm.setAttribute(key, value);
}
} }
for (let i = 2, size = arguments.length;i < size; i++) { for (let i = 2, size = arguments.length;i < size; i++) {
let arg = arguments[i]; let arg = arguments[i];
@ -805,7 +807,7 @@ function createButton(options) {
for (index of ButtonStyleIndices) for (index of ButtonStyleIndices)
style & index && $btn.classList.add(ButtonStyleClass[index]); style & index && $btn.classList.add(ButtonStyleClass[index]);
} }
if (options.classes && $btn.classList.add(...options.classes), options.icon && $btn.appendChild(createSvgIcon(options.icon)), options.label && $btn.appendChild(CE("span", {}, options.label)), options.title && $btn.setAttribute("title", options.title), options.onClick && $btn.addEventListener("click", options.onClick), $btn.tabIndex = typeof options.tabIndex === "number" ? options.tabIndex : 0, options.secondaryText) $btn.classList.add("bx-button-multi-lines"), $btn.appendChild(CE("span", {}, options.secondaryText)); if (options.classes && $btn.classList.add(...options.classes), options.icon && $btn.appendChild(createSvgIcon(options.icon)), options.label && $btn.appendChild(CE("span", !1, options.label)), options.title && $btn.setAttribute("title", options.title), options.onClick && $btn.addEventListener("click", options.onClick), $btn.tabIndex = typeof options.tabIndex === "number" ? options.tabIndex : 0, options.secondaryText) $btn.classList.add("bx-button-multi-lines"), $btn.appendChild(CE("span", !1, options.secondaryText));
for (let key in options.attributes) for (let key in options.attributes)
if (!$btn.hasOwnProperty(key)) $btn.setAttribute(key, options.attributes[key]); if (!$btn.hasOwnProperty(key)) $btn.setAttribute(key, options.attributes[key]);
return $btn; return $btn;
@ -1524,7 +1526,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
requiredVariants: "full", requiredVariants: "full",
label: t("enable-local-co-op-support"), label: t("enable-local-co-op-support"),
default: !1, default: !1,
note: () => CE("div", {}, CE("a", { note: () => CE("div", !1, CE("a", {
href: "https://github.com/redphx/better-xcloud/discussions/275", href: "https://github.com/redphx/better-xcloud/discussions/275",
target: "_blank" target: "_blank"
}, t("enable-local-co-op-support-note")), CE("br"), "⚠️ " + t("unexpected-behavior")) }, t("enable-local-co-op-support-note")), CE("br"), "⚠️ " + t("unexpected-behavior"))
@ -2393,7 +2395,7 @@ class StreamStats {
let stat = this.stats[statKey], $div = CE("div", { let stat = this.stats[statKey], $div = CE("div", {
class: `bx-stat-${statKey}`, class: `bx-stat-${statKey}`,
title: stat.name title: stat.name
}, CE("label", {}, statKey.toUpperCase()), stat.$element); }, CE("label", !1, statKey.toUpperCase()), stat.$element);
this.$container.appendChild($div); this.$container.appendChild($div);
} }
this.refreshStyles(), document.documentElement.appendChild(this.$container); this.refreshStyles(), document.documentElement.appendChild(this.$container);
@ -2879,7 +2881,7 @@ class MkbPopup {
e.preventDefault(), this.mkbHandler.toggle(!0); e.preventDefault(), this.mkbHandler.toggle(!0);
}; };
render() { render() {
this.$popup = CE("div", { class: "bx-mkb-pointer-lock-msg bx-gone" }, this.$title = CE("p"), this.$btnActivate = this.createActivateButton(), CE("div", {}, createButton({ this.$popup = CE("div", { class: "bx-mkb-pointer-lock-msg bx-gone" }, this.$title = CE("p"), this.$btnActivate = this.createActivateButton(), CE("div", !1, createButton({
label: t("ignore"), label: t("ignore"),
style: 8, style: 8,
onClick: (e) => { onClick: (e) => {
@ -3682,13 +3684,13 @@ class BxSelectElement extends HTMLSelectElement {
if (self.isMultiple) $content = CE("button", { if (self.isMultiple) $content = CE("button", {
class: "bx-select-value bx-focusable", class: "bx-select-value bx-focusable",
tabindex: 0 tabindex: 0
}, CE("div", {}, self.$checkBox = CE("input", { type: "checkbox" }), self.$label = CE("span", {}, "")), self.$indicators), $content.addEventListener("click", (e) => { }, CE("div", !1, self.$checkBox = CE("input", { type: "checkbox" }), self.$label = CE("span", !1, "")), self.$indicators), $content.addEventListener("click", (e) => {
self.$checkBox.click(); self.$checkBox.click();
}), self.$checkBox.addEventListener("input", (e) => { }), self.$checkBox.addEventListener("input", (e) => {
let $option = BxSelectElement.getOptionAtIndex.call(self, self.visibleIndex); let $option = BxSelectElement.getOptionAtIndex.call(self, self.visibleIndex);
$option && ($option.selected = e.target.checked), BxEvent.dispatch($select, "input"); $option && ($option.selected = e.target.checked), BxEvent.dispatch($select, "input");
}); });
else $content = CE("div", {}, self.$label = CE("label", { for: $select.id + "_checkbox" }, ""), self.$indicators); else $content = CE("div", !1, self.$label = CE("label", { for: $select.id + "_checkbox" }, ""), self.$indicators);
return $select.addEventListener("input", BxSelectElement.render.bind(self)), new MutationObserver((mutationList, observer2) => { return $select.addEventListener("input", BxSelectElement.render.bind(self)), new MutationObserver((mutationList, observer2) => {
mutationList.forEach((mutation) => { mutationList.forEach((mutation) => {
if (mutation.type === "childList" || mutation.type === "attributes") self.visibleIndex = $select.selectedIndex, self.optionsList = Array.from($select.querySelectorAll("option")), BxSelectElement.resetIndicators.call(self), BxSelectElement.render.call(self); if (mutation.type === "childList" || mutation.type === "attributes") self.visibleIndex = $select.selectedIndex, self.optionsList = Array.from($select.querySelectorAll("option")), BxSelectElement.resetIndicators.call(self), BxSelectElement.render.call(self);
@ -3758,7 +3760,7 @@ class BxSelectElement extends HTMLSelectElement {
let groupLabel = $parent instanceof HTMLOptGroupElement ? $parent.label : " "; let groupLabel = $parent instanceof HTMLOptGroupElement ? $parent.label : " ";
$label.innerHTML = ""; $label.innerHTML = "";
let fragment = document.createDocumentFragment(); let fragment = document.createDocumentFragment();
fragment.appendChild(CE("span", {}, groupLabel)), fragment.appendChild(document.createTextNode(content)), $label.appendChild(fragment); fragment.appendChild(CE("span", !1, groupLabel)), fragment.appendChild(document.createTextNode(content)), $label.appendChild(fragment);
} else $label.textContent = content; } else $label.textContent = content;
} else $label.textContent = content; } else $label.textContent = content;
if ($label.classList.toggle("bx-line-through", $option && $option.disabled), this.isMultiple) $checkBox.checked = $option?.selected || !1, $checkBox.classList.toggle("bx-gone", !content); if ($label.classList.toggle("bx-line-through", $option && $option.disabled), this.isMultiple) $checkBox.checked = $option?.selected || !1, $checkBox.classList.toggle("bx-gone", !content);
@ -3815,7 +3817,7 @@ class BxNumberStepper extends HTMLInputElement {
let $text, $btnInc, $btnDec, $range, self = CE("div", { let $text, $btnInc, $btnDec, $range, self = CE("div", {
class: "bx-number-stepper", class: "bx-number-stepper",
id: `bx_setting_${escapeCssSelector(key)}` id: `bx_setting_${escapeCssSelector(key)}`
}, CE("div", {}, $btnDec = CE("button", { }, CE("div", !1, $btnDec = CE("button", {
_dataset: { _dataset: {
type: "dec" type: "dec"
}, },
@ -4043,7 +4045,7 @@ class SuggestionsSetting {
else if (deviceType === "android") SuggestionsSetting.addDefaultSuggestedSetting.call(this, "deviceVibration.mode", "auto"); else if (deviceType === "android") SuggestionsSetting.addDefaultSuggestedSetting.call(this, "deviceVibration.mode", "auto");
else if (deviceType === "android-tv") SuggestionsSetting.addDefaultSuggestedSetting.call(this, "touchController.mode", "off"); else if (deviceType === "android-tv") SuggestionsSetting.addDefaultSuggestedSetting.call(this, "touchController.mode", "off");
SuggestionsSetting.generateDefaultSuggestedSettings.call(this); SuggestionsSetting.generateDefaultSuggestedSettings.call(this);
let $suggestedSettings = CE("div", { class: "bx-suggest-wrapper" }), $select = CE("select", {}, hasRecommendedSettings && CE("option", { value: "recommended" }, t("recommended")), !hasRecommendedSettings && CE("option", { value: "highest" }, t("highest-quality")), CE("option", { value: "default" }, t("default")), CE("option", { value: "lowest" }, t("lowest-quality"))); let $suggestedSettings = CE("div", { class: "bx-suggest-wrapper" }), $select = CE("select", !1, hasRecommendedSettings && CE("option", { value: "recommended" }, t("recommended")), !hasRecommendedSettings && CE("option", { value: "highest" }, t("highest-quality")), CE("option", { value: "default" }, t("default")), CE("option", { value: "lowest" }, t("lowest-quality")));
$select.addEventListener("input", (e2) => { $select.addEventListener("input", (e2) => {
let profile = $select.value; let profile = $select.value;
removeChildElements($suggestedSettings); removeChildElements($suggestedSettings);
@ -4222,7 +4224,7 @@ class SettingsDialog extends NavigationDialog {
}, t("settings-reload-note")), topButtons.push(this.$noteGlobalReload), this.$btnSuggestion = CE("div", { }, t("settings-reload-note")), topButtons.push(this.$noteGlobalReload), this.$btnSuggestion = CE("div", {
class: "bx-suggest-toggler bx-focusable", class: "bx-suggest-toggler bx-focusable",
tabindex: 0 tabindex: 0
}, CE("label", {}, t("suggest-settings")), CE("span", {}, "")), this.$btnSuggestion.addEventListener("click", SuggestionsSetting.renderSuggestions.bind(this)), topButtons.push(this.$btnSuggestion); }, CE("label", !1, t("suggest-settings")), CE("span", !1, "")), this.$btnSuggestion.addEventListener("click", SuggestionsSetting.renderSuggestions.bind(this)), topButtons.push(this.$btnSuggestion);
let $div = CE("div", { let $div = CE("div", {
class: "bx-top-buttons", class: "bx-top-buttons",
_nearby: { _nearby: {
@ -4751,7 +4753,7 @@ class SettingsDialog extends NavigationDialog {
_nearby: { _nearby: {
orientation: "horizontal" orientation: "horizontal"
} }
}, CE("span", {}, label), section.helpUrl && createButton({ }, CE("span", !1, label), section.helpUrl && createButton({
icon: BxIcon.QUESTION, icon: BxIcon.QUESTION,
style: 8 | 64, style: 8 | 64,
url: section.helpUrl, url: section.helpUrl,
@ -4803,7 +4805,7 @@ class SettingsDialog extends NavigationDialog {
_nearby: { _nearby: {
focus: () => this.focusActiveTab() focus: () => this.focusActiveTab()
} }
}), CE("div", {}, this.$btnReload = createButton({ }), CE("div", !1, this.$btnReload = createButton({
icon: BxIcon.REFRESH, icon: BxIcon.REFRESH,
style: 64 | 32, style: 64 | 32,
onClick: (e) => { onClick: (e) => {
@ -5052,7 +5054,7 @@ class HeaderSection {
label: "???", label: "???",
style: 16 | 32 | 64 | 256, style: 16 | 32 | 64 | 256,
onClick: (e) => SettingsDialog.getInstance().show() onClick: (e) => SettingsDialog.getInstance().show()
}), this.$buttonsWrapper = CE("div", {}, getPref("xhome.enabled") ? this.$btnRemotePlay : null, this.$btnSettings); }), this.$buttonsWrapper = CE("div", !1, getPref("xhome.enabled") ? this.$btnRemotePlay : null, this.$btnSettings);
} }
injectSettingsButton($parent) { injectSettingsButton($parent) {
if (!$parent) return; if (!$parent) return;
@ -5096,7 +5098,7 @@ class RemotePlayDialog extends NavigationDialog {
BxLogger.info(this.LOG_TAG, "constructor()"), this.setupDialog(); BxLogger.info(this.LOG_TAG, "constructor()"), this.setupDialog();
} }
setupDialog() { setupDialog() {
let $fragment = CE("div", { class: "bx-remote-play-container" }), $settingNote = CE("p", {}), currentResolution = getPref("xhome.video.resolution"), $resolutions = CE("select", {}, CE("option", { value: "720p" }, "720p"), CE("option", { value: "1080p" }, "1080p")); let $fragment = CE("div", { class: "bx-remote-play-container" }), $settingNote = CE("p", {}), currentResolution = getPref("xhome.video.resolution"), $resolutions = CE("select", !1, CE("option", { value: "720p" }, "720p"), CE("option", { value: "1080p" }, "1080p"));
$resolutions = BxSelectElement.create($resolutions), $resolutions.addEventListener("input", (e) => { $resolutions = BxSelectElement.create($resolutions), $resolutions.addEventListener("input", (e) => {
let value = e.target.value; let value = e.target.value;
$settingNote.textContent = value === "1080p" ? "✅ " + t("can-stream-xbox-360-games") : "❌ " + t("cant-stream-xbox-360-games"), setPref("xhome.video.resolution", value); $settingNote.textContent = value === "1080p" ? "✅ " + t("can-stream-xbox-360-games") : "❌ " + t("cant-stream-xbox-360-games"), setPref("xhome.video.resolution", value);
@ -5105,11 +5107,11 @@ class RemotePlayDialog extends NavigationDialog {
}); });
let $qualitySettings = CE("div", { let $qualitySettings = CE("div", {
class: "bx-remote-play-settings" class: "bx-remote-play-settings"
}, CE("div", {}, CE("label", {}, t("target-resolution"), $settingNote), $resolutions)); }, CE("div", !1, CE("label", !1, t("target-resolution"), $settingNote), $resolutions));
$fragment.appendChild($qualitySettings); $fragment.appendChild($qualitySettings);
let manager = RemotePlayManager.getInstance(), consoles = manager.getConsoles(); let manager = RemotePlayManager.getInstance(), consoles = manager.getConsoles();
for (let con of consoles) { for (let con of consoles) {
let $child = CE("div", { class: "bx-remote-play-device-wrapper" }, CE("div", { class: "bx-remote-play-device-info" }, CE("div", {}, CE("span", { class: "bx-remote-play-device-name" }, con.deviceName), CE("span", { class: "bx-remote-play-console-type" }, con.consoleType.replace("Xbox", ""))), CE("div", { class: "bx-remote-play-power-state" }, this.STATE_LABELS[con.powerState])), createButton({ let $child = CE("div", { class: "bx-remote-play-device-wrapper" }, CE("div", { class: "bx-remote-play-device-info" }, CE("div", !1, CE("span", { class: "bx-remote-play-device-name" }, con.deviceName), CE("span", { class: "bx-remote-play-console-type" }, con.consoleType.replace("Xbox", ""))), CE("div", { class: "bx-remote-play-power-state" }, this.STATE_LABELS[con.powerState])), createButton({
classes: ["bx-remote-play-connect-button"], classes: ["bx-remote-play-connect-button"],
label: t("console-connect"), label: t("console-connect"),
style: 1 | 64, style: 1 | 64,
@ -5301,7 +5303,7 @@ class LoadingScreen {
let endDateStr = endDate.toISOString().slice(0, 19); let endDateStr = endDate.toISOString().slice(0, 19);
endDateStr = endDateStr.substring(0, 10) + " " + endDateStr.substring(11, 19), endDateStr += ` (${LoadingScreen.secondsToString(waitTime)})`; endDateStr = endDateStr.substring(0, 10) + " " + endDateStr.substring(11, 19), endDateStr += ` (${LoadingScreen.secondsToString(waitTime)})`;
let $waitTimeBox = LoadingScreen.$waitTimeBox; let $waitTimeBox = LoadingScreen.$waitTimeBox;
if (!$waitTimeBox) $waitTimeBox = CE("div", { class: "bx-wait-time-box" }, CE("label", {}, t("server")), CE("span", {}, getPreferredServerRegion()), CE("label", {}, t("wait-time-estimated")), $estimated = CE("span", {}), CE("label", {}, t("wait-time-countdown")), $countDown = CE("span", {})), document.documentElement.appendChild($waitTimeBox), LoadingScreen.$waitTimeBox = $waitTimeBox; if (!$waitTimeBox) $waitTimeBox = CE("div", { class: "bx-wait-time-box" }, CE("label", !1, t("server")), CE("span", !1, getPreferredServerRegion()), CE("label", !1, t("wait-time-estimated")), $estimated = CE("span", {}), CE("label", !1, t("wait-time-countdown")), $countDown = CE("span", {})), document.documentElement.appendChild($waitTimeBox), LoadingScreen.$waitTimeBox = $waitTimeBox;
else $waitTimeBox.classList.remove("bx-gone"), $estimated = $waitTimeBox.querySelector(".bx-wait-time-estimated"), $countDown = $waitTimeBox.querySelector(".bx-wait-time-countdown"); else $waitTimeBox.classList.remove("bx-gone"), $estimated = $waitTimeBox.querySelector(".bx-wait-time-estimated"), $countDown = $waitTimeBox.querySelector(".bx-wait-time-countdown");
$estimated.textContent = endDateStr, $countDown.textContent = LoadingScreen.secondsToString(secondsLeft), document.title = `[${$countDown.textContent}] ${LoadingScreen.orgWebTitle}`, LoadingScreen.waitTimeInterval = window.setInterval(() => { $estimated.textContent = endDateStr, $countDown.textContent = LoadingScreen.secondsToString(secondsLeft), document.title = `[${$countDown.textContent}] ${LoadingScreen.orgWebTitle}`, LoadingScreen.waitTimeInterval = window.setInterval(() => {
if (secondsLeft--, $countDown.textContent = LoadingScreen.secondsToString(secondsLeft), document.title = `[${$countDown.textContent}] ${LoadingScreen.orgWebTitle}`, secondsLeft <= 0) LoadingScreen.waitTimeInterval && clearInterval(LoadingScreen.waitTimeInterval), LoadingScreen.waitTimeInterval = null; if (secondsLeft--, $countDown.textContent = LoadingScreen.secondsToString(secondsLeft), document.title = `[${$countDown.textContent}] ${LoadingScreen.orgWebTitle}`, secondsLeft <= 0) LoadingScreen.waitTimeInterval && clearInterval(LoadingScreen.waitTimeInterval), LoadingScreen.waitTimeInterval = null;
@ -5888,7 +5890,7 @@ function addCss() {
if (css += "div[class*=StreamMenu-module__menu]{min-width:100vw !important}", getPref("ui.streamMenu.simplify")) css += "div[class*=Menu-module__scrollable]{--bxStreamMenuItemSize:80px;--streamMenuItemSize:calc(var(--bxStreamMenuItemSize) + 40px) !important}.bx-badges{top:calc(var(--streamMenuItemSize) - 20px)}body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) - 10px) !important}button[class*=MenuItem-module__container]{min-width:auto !important;min-height:auto !important;width:var(--bxStreamMenuItemSize) !important;height:var(--bxStreamMenuItemSize) !important}div[class*=MenuItem-module__label]{display:none !important}svg[class*=MenuItem-module__icon]{width:36px;height:100% !important;padding:0 !important;margin:0 !important}"; if (css += "div[class*=StreamMenu-module__menu]{min-width:100vw !important}", getPref("ui.streamMenu.simplify")) css += "div[class*=Menu-module__scrollable]{--bxStreamMenuItemSize:80px;--streamMenuItemSize:calc(var(--bxStreamMenuItemSize) + 40px) !important}.bx-badges{top:calc(var(--streamMenuItemSize) - 20px)}body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) - 10px) !important}button[class*=MenuItem-module__container]{min-width:auto !important;min-height:auto !important;width:var(--bxStreamMenuItemSize) !important;height:var(--bxStreamMenuItemSize) !important}div[class*=MenuItem-module__label]{display:none !important}svg[class*=MenuItem-module__icon]{width:36px;height:100% !important;padding:0 !important;margin:0 !important}";
else css += "body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) + 30px)}body:not([data-media-type=tv]) .bx-badges{top:calc(var(--streamMenuItemSize) + 20px)}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]{min-width:auto !important;width:100px !important}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]:nth-child(n+2){margin-left:10px !important}body:not([data-media-type=tv]) div[class*=MenuItem-module__label]{margin-left:8px !important;margin-right:8px !important}"; else css += "body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) + 30px)}body:not([data-media-type=tv]) .bx-badges{top:calc(var(--streamMenuItemSize) + 20px)}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]{min-width:auto !important;width:100px !important}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]:nth-child(n+2){margin-left:10px !important}body:not([data-media-type=tv]) div[class*=MenuItem-module__label]{margin-left:8px !important;margin-right:8px !important}";
if (getPref("ui.hideScrollbar")) css += "html{scrollbar-width:none}body::-webkit-scrollbar{display:none}"; if (getPref("ui.hideScrollbar")) css += "html{scrollbar-width:none}body::-webkit-scrollbar{display:none}";
let $style = CE("style", {}, css); let $style = CE("style", !1, css);
document.documentElement.appendChild($style); document.documentElement.appendChild($style);
} }
function preloadFonts() { function preloadFonts() {

View File

@ -301,7 +301,6 @@ var SUPPORTED_LANGUAGES = {
"zh-CN": "中文(简体)", "zh-CN": "中文(简体)",
"zh-TW": "中文(繁體)" "zh-TW": "中文(繁體)"
}, Texts = { }, Texts = {
"slightly-increase-input-latency": "Slightly increase input latency",
achievements: "Achievements", achievements: "Achievements",
activate: "Activate", activate: "Activate",
activated: "Activated", activated: "Activated",
@ -599,6 +598,7 @@ var SUPPORTED_LANGUAGES = {
"show-wait-time-in-game-card": "Show wait time in game card", "show-wait-time-in-game-card": "Show wait time in game card",
"simplify-stream-menu": "Simplify Stream's menu", "simplify-stream-menu": "Simplify Stream's menu",
"skip-splash-video": "Skip Xbox splash video", "skip-splash-video": "Skip Xbox splash video",
"slightly-increases-input-latency": "Slightly increases input latency",
slow: "Slow", slow: "Slow",
small: "Small", small: "Small",
"smart-tv": "Smart TV", "smart-tv": "Smart TV",
@ -788,26 +788,28 @@ var ButtonStyleClass = {
4096: "bx-normal-case", 4096: "bx-normal-case",
8192: "bx-normal-link" 8192: "bx-normal-link"
}; };
function createElement(elmName, props = {}, ..._) { function createElement(elmName, props, ..._) {
let $elm, hasNs = "xmlns" in props; let $elm, hasNs = props && "xmlns" in props;
if (hasNs) $elm = document.createElementNS(props.xmlns, elmName), delete props.xmlns; if (hasNs) $elm = document.createElementNS(props.xmlns, elmName), delete props.xmlns;
else $elm = document.createElement(elmName); else $elm = document.createElement(elmName);
if (props._nearby) setNearby($elm, props._nearby), delete props._nearby; if (props) {
if (props._on) { if (props._nearby) setNearby($elm, props._nearby), delete props._nearby;
for (let name in props._on) if (props._on) {
$elm.addEventListener(name, props._on[name]); for (let name in props._on)
delete props._on; $elm.addEventListener(name, props._on[name]);
} delete props._on;
if (props._dataset) { }
for (let name in props._dataset) if (props._dataset) {
$elm.dataset[name] = props._dataset[name]; for (let name in props._dataset)
delete props._dataset; $elm.dataset[name] = props._dataset[name];
} delete props._dataset;
for (let key in props) { }
if ($elm.hasOwnProperty(key)) continue; for (let key in props) {
let value = props[key]; if ($elm.hasOwnProperty(key)) continue;
if (hasNs) $elm.setAttributeNS(null, key, value); let value = props[key];
else $elm.setAttribute(key, value); if (hasNs) $elm.setAttributeNS(null, key, value);
else $elm.setAttribute(key, value);
}
} }
for (let i = 2, size = arguments.length;i < size; i++) { for (let i = 2, size = arguments.length;i < size; i++) {
let arg = arguments[i]; let arg = arguments[i];
@ -837,7 +839,7 @@ function createButton(options) {
for (index of ButtonStyleIndices) for (index of ButtonStyleIndices)
style & index && $btn.classList.add(ButtonStyleClass[index]); style & index && $btn.classList.add(ButtonStyleClass[index]);
} }
if (options.classes && $btn.classList.add(...options.classes), options.icon && $btn.appendChild(createSvgIcon(options.icon)), options.label && $btn.appendChild(CE("span", {}, options.label)), options.title && $btn.setAttribute("title", options.title), options.onClick && $btn.addEventListener("click", options.onClick), $btn.tabIndex = typeof options.tabIndex === "number" ? options.tabIndex : 0, options.secondaryText) $btn.classList.add("bx-button-multi-lines"), $btn.appendChild(CE("span", {}, options.secondaryText)); if (options.classes && $btn.classList.add(...options.classes), options.icon && $btn.appendChild(createSvgIcon(options.icon)), options.label && $btn.appendChild(CE("span", !1, options.label)), options.title && $btn.setAttribute("title", options.title), options.onClick && $btn.addEventListener("click", options.onClick), $btn.tabIndex = typeof options.tabIndex === "number" ? options.tabIndex : 0, options.secondaryText) $btn.classList.add("bx-button-multi-lines"), $btn.appendChild(CE("span", !1, options.secondaryText));
for (let key in options.attributes) for (let key in options.attributes)
if (!$btn.hasOwnProperty(key)) $btn.setAttribute(key, options.attributes[key]); if (!$btn.hasOwnProperty(key)) $btn.setAttribute(key, options.attributes[key]);
return $btn; return $btn;
@ -1596,7 +1598,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
requiredVariants: "full", requiredVariants: "full",
label: t("enable-local-co-op-support"), label: t("enable-local-co-op-support"),
default: !1, default: !1,
note: () => CE("div", {}, CE("a", { note: () => CE("div", !1, CE("a", {
href: "https://github.com/redphx/better-xcloud/discussions/275", href: "https://github.com/redphx/better-xcloud/discussions/275",
target: "_blank" target: "_blank"
}, t("enable-local-co-op-support-note")), CE("br"), "⚠️ " + t("unexpected-behavior")) }, t("enable-local-co-op-support-note")), CE("br"), "⚠️ " + t("unexpected-behavior"))
@ -2503,7 +2505,7 @@ class StreamStats {
let stat = this.stats[statKey], $div = CE("div", { let stat = this.stats[statKey], $div = CE("div", {
class: `bx-stat-${statKey}`, class: `bx-stat-${statKey}`,
title: stat.name title: stat.name
}, CE("label", {}, statKey.toUpperCase()), stat.$element); }, CE("label", !1, statKey.toUpperCase()), stat.$element);
this.$container.appendChild($div); this.$container.appendChild($div);
} }
this.refreshStyles(), document.documentElement.appendChild(this.$container); this.refreshStyles(), document.documentElement.appendChild(this.$container);
@ -3025,7 +3027,7 @@ class MkbPopup {
e.preventDefault(), this.mkbHandler.toggle(!0); e.preventDefault(), this.mkbHandler.toggle(!0);
}; };
render() { render() {
this.$popup = CE("div", { class: "bx-mkb-pointer-lock-msg bx-gone" }, this.$title = CE("p"), this.$btnActivate = this.createActivateButton(), CE("div", {}, createButton({ this.$popup = CE("div", { class: "bx-mkb-pointer-lock-msg bx-gone" }, this.$title = CE("p"), this.$btnActivate = this.createActivateButton(), CE("div", !1, createButton({
label: t("ignore"), label: t("ignore"),
style: 8, style: 8,
onClick: (e) => { onClick: (e) => {
@ -4022,13 +4024,13 @@ class BxSelectElement extends HTMLSelectElement {
if (self.isMultiple) $content = CE("button", { if (self.isMultiple) $content = CE("button", {
class: "bx-select-value bx-focusable", class: "bx-select-value bx-focusable",
tabindex: 0 tabindex: 0
}, CE("div", {}, self.$checkBox = CE("input", { type: "checkbox" }), self.$label = CE("span", {}, "")), self.$indicators), $content.addEventListener("click", (e) => { }, CE("div", !1, self.$checkBox = CE("input", { type: "checkbox" }), self.$label = CE("span", !1, "")), self.$indicators), $content.addEventListener("click", (e) => {
self.$checkBox.click(); self.$checkBox.click();
}), self.$checkBox.addEventListener("input", (e) => { }), self.$checkBox.addEventListener("input", (e) => {
let $option = BxSelectElement.getOptionAtIndex.call(self, self.visibleIndex); let $option = BxSelectElement.getOptionAtIndex.call(self, self.visibleIndex);
$option && ($option.selected = e.target.checked), BxEvent.dispatch($select, "input"); $option && ($option.selected = e.target.checked), BxEvent.dispatch($select, "input");
}); });
else $content = CE("div", {}, self.$label = CE("label", { for: $select.id + "_checkbox" }, ""), self.$indicators); else $content = CE("div", !1, self.$label = CE("label", { for: $select.id + "_checkbox" }, ""), self.$indicators);
return $select.addEventListener("input", BxSelectElement.render.bind(self)), new MutationObserver((mutationList, observer2) => { return $select.addEventListener("input", BxSelectElement.render.bind(self)), new MutationObserver((mutationList, observer2) => {
mutationList.forEach((mutation) => { mutationList.forEach((mutation) => {
if (mutation.type === "childList" || mutation.type === "attributes") self.visibleIndex = $select.selectedIndex, self.optionsList = Array.from($select.querySelectorAll("option")), BxSelectElement.resetIndicators.call(self), BxSelectElement.render.call(self); if (mutation.type === "childList" || mutation.type === "attributes") self.visibleIndex = $select.selectedIndex, self.optionsList = Array.from($select.querySelectorAll("option")), BxSelectElement.resetIndicators.call(self), BxSelectElement.render.call(self);
@ -4098,7 +4100,7 @@ class BxSelectElement extends HTMLSelectElement {
let groupLabel = $parent instanceof HTMLOptGroupElement ? $parent.label : " "; let groupLabel = $parent instanceof HTMLOptGroupElement ? $parent.label : " ";
$label.innerHTML = ""; $label.innerHTML = "";
let fragment = document.createDocumentFragment(); let fragment = document.createDocumentFragment();
fragment.appendChild(CE("span", {}, groupLabel)), fragment.appendChild(document.createTextNode(content)), $label.appendChild(fragment); fragment.appendChild(CE("span", !1, groupLabel)), fragment.appendChild(document.createTextNode(content)), $label.appendChild(fragment);
} else $label.textContent = content; } else $label.textContent = content;
} else $label.textContent = content; } else $label.textContent = content;
if ($label.classList.toggle("bx-line-through", $option && $option.disabled), this.isMultiple) $checkBox.checked = $option?.selected || !1, $checkBox.classList.toggle("bx-gone", !content); if ($label.classList.toggle("bx-line-through", $option && $option.disabled), this.isMultiple) $checkBox.checked = $option?.selected || !1, $checkBox.classList.toggle("bx-gone", !content);
@ -4850,7 +4852,7 @@ class BxNumberStepper extends HTMLInputElement {
let $text, $btnInc, $btnDec, $range, self = CE("div", { let $text, $btnInc, $btnDec, $range, self = CE("div", {
class: "bx-number-stepper", class: "bx-number-stepper",
id: `bx_setting_${escapeCssSelector(key)}` id: `bx_setting_${escapeCssSelector(key)}`
}, CE("div", {}, $btnDec = CE("button", { }, CE("div", !1, $btnDec = CE("button", {
_dataset: { _dataset: {
type: "dec" type: "dec"
}, },
@ -5132,11 +5134,11 @@ class BaseProfileManagerDialog extends NavigationDialog {
this.currentPresetId = newId, await this.refresh(); this.currentPresetId = newId, await this.refresh();
} }
})); }));
this.$header = $header, this.$container = CE("div", { class: "bx-centered-dialog" }, CE("div", { class: "bx-dialog-title" }, CE("p", {}, this.title), createButton({ this.$header = $header, this.$container = CE("div", { class: "bx-centered-dialog" }, CE("div", { class: "bx-dialog-title" }, CE("p", !1, this.title), createButton({
icon: BxIcon.CLOSE, icon: BxIcon.CLOSE,
style: 64 | 2048 | 8, style: 64 | 2048 | 8,
onClick: (e) => this.hide() onClick: (e) => this.hide()
})), CE("div", {}, $header, this.$defaultNote = CE("div", { class: "bx-default-preset-note bx-gone" }, t("default-preset-note"))), CE("div", { class: "bx-dialog-content" }, this.$content)); })), CE("div", !1, $header, this.$defaultNote = CE("div", { class: "bx-default-preset-note bx-gone" }, t("default-preset-note"))), CE("div", { class: "bx-dialog-content" }, this.$content));
} }
async refresh() { async refresh() {
await this.renderPresetsList(), this.$presets.value = this.currentPresetId.toString(), BxEvent.dispatch(this.$presets, "input", { manualTrigger: !0 }); await this.renderPresetsList(), this.$presets.value = this.currentPresetId.toString(), BxEvent.dispatch(this.$presets, "input", { manualTrigger: !0 });
@ -5321,7 +5323,7 @@ class BxDualNumberStepper extends HTMLInputElement {
max: self.controlMax, max: self.controlMax,
step: self.steps, step: self.steps,
tabindex: 0 tabindex: 0
}), $rangeTo = $rangeFrom.cloneNode(), self.$rangeFrom = $rangeFrom, self.$rangeTo = $rangeTo, self.$activeRange = $rangeFrom, self.getValue = BxDualNumberStepper.getValues.bind(self), self.setValue = BxDualNumberStepper.setValues.bind(self), $rangeFrom.addEventListener("input", self.onRangeInput), $rangeTo.addEventListener("input", self.onRangeInput), self.addEventListener("input", self.onRangeInput), self.append(CE("div", {}, $rangeFrom, $rangeTo)), BxDualNumberStepper.setValues.call(self, values), self.addEventListener("contextmenu", BxDualNumberStepper.onContextMenu), setNearby(self, { }), $rangeTo = $rangeFrom.cloneNode(), self.$rangeFrom = $rangeFrom, self.$rangeTo = $rangeTo, self.$activeRange = $rangeFrom, self.getValue = BxDualNumberStepper.getValues.bind(self), self.setValue = BxDualNumberStepper.setValues.bind(self), $rangeFrom.addEventListener("input", self.onRangeInput), $rangeTo.addEventListener("input", self.onRangeInput), self.addEventListener("input", self.onRangeInput), self.append(CE("div", !1, $rangeFrom, $rangeTo)), BxDualNumberStepper.setValues.call(self, values), self.addEventListener("contextmenu", BxDualNumberStepper.onContextMenu), setNearby(self, {
focus: $rangeFrom, focus: $rangeFrom,
orientation: "vertical" orientation: "vertical"
}), Object.defineProperty(self, "value", { }), Object.defineProperty(self, "value", {
@ -5601,7 +5603,7 @@ class ControllerExtraSettings extends HTMLElement {
autocomplete: "off", autocomplete: "off",
_on: { input: $container.saveSettings } _on: { input: $container.saveSettings }
})); }));
return $container.append(CE("span", {}, t("no-controllers-connected")), CE("div", { class: "bx-controller-extra-wrapper" }, $selectControllers, CE("div", { class: "bx-sub-content-box" }, createSettingRow(t("in-game-controller-shortcuts"), CE("div", { return $container.append(CE("span", !1, t("no-controllers-connected")), CE("div", { class: "bx-controller-extra-wrapper" }, $selectControllers, CE("div", { class: "bx-sub-content-box" }, createSettingRow(t("in-game-controller-shortcuts"), CE("div", {
class: "bx-preset-row", class: "bx-preset-row",
_nearby: { orientation: "horizontal" } _nearby: { orientation: "horizontal" }
}, $selectShortcuts, createButton({ }, $selectShortcuts, createButton({
@ -5623,7 +5625,7 @@ class ControllerExtraSettings extends HTMLElement {
}) })
})), { })), {
multiLines: !0, multiLines: !0,
$note: CE("div", { class: "bx-settings-dialog-note" }, "ⓘ " + t("slightly-increase-input-latency")) $note: CE("div", { class: "bx-settings-dialog-note" }, "ⓘ " + t("slightly-increases-input-latency"))
})))), $container.$selectControllers = $selectControllers, $container.$selectShortcuts = $selectShortcuts, $container.$selectCustomization = $selectCustomization, $container.updateLayout(), window.addEventListener("gamepadconnected", $container.updateLayout), window.addEventListener("gamepaddisconnected", $container.updateLayout), this.onMountedCallbacks.push(() => { })))), $container.$selectControllers = $selectControllers, $container.$selectShortcuts = $selectShortcuts, $container.$selectCustomization = $selectCustomization, $container.updateLayout(), window.addEventListener("gamepadconnected", $container.updateLayout), window.addEventListener("gamepaddisconnected", $container.updateLayout), this.onMountedCallbacks.push(() => {
$container.updateLayout(); $container.updateLayout();
}), $container; }), $container;
@ -5705,7 +5707,7 @@ class SuggestionsSetting {
else if (deviceType === "android") SuggestionsSetting.addDefaultSuggestedSetting.call(this, "deviceVibration.mode", "auto"); else if (deviceType === "android") SuggestionsSetting.addDefaultSuggestedSetting.call(this, "deviceVibration.mode", "auto");
else if (deviceType === "android-tv") SuggestionsSetting.addDefaultSuggestedSetting.call(this, "touchController.mode", "off"); else if (deviceType === "android-tv") SuggestionsSetting.addDefaultSuggestedSetting.call(this, "touchController.mode", "off");
SuggestionsSetting.generateDefaultSuggestedSettings.call(this); SuggestionsSetting.generateDefaultSuggestedSettings.call(this);
let $suggestedSettings = CE("div", { class: "bx-suggest-wrapper" }), $select = CE("select", {}, hasRecommendedSettings && CE("option", { value: "recommended" }, t("recommended")), !hasRecommendedSettings && CE("option", { value: "highest" }, t("highest-quality")), CE("option", { value: "default" }, t("default")), CE("option", { value: "lowest" }, t("lowest-quality"))); let $suggestedSettings = CE("div", { class: "bx-suggest-wrapper" }), $select = CE("select", !1, hasRecommendedSettings && CE("option", { value: "recommended" }, t("recommended")), !hasRecommendedSettings && CE("option", { value: "highest" }, t("highest-quality")), CE("option", { value: "default" }, t("default")), CE("option", { value: "lowest" }, t("lowest-quality")));
$select.addEventListener("input", (e2) => { $select.addEventListener("input", (e2) => {
let profile = $select.value; let profile = $select.value;
removeChildElements($suggestedSettings); removeChildElements($suggestedSettings);
@ -5871,7 +5873,7 @@ class KeyBindingDialog {
$currentElm; $currentElm;
countdownIntervalId; countdownIntervalId;
constructor() { constructor() {
this.$overlay = CE("div", { class: "bx-key-binding-dialog-overlay bx-gone" }), this.$overlay.addEventListener("contextmenu", (e) => e.preventDefault()), document.documentElement.appendChild(this.$overlay), this.$dialog = CE("div", { class: "bx-key-binding-dialog bx-gone" }, this.$title = CE("h2", {}), CE("div", { class: "bx-key-binding-dialog-content" }, CE("div", {}, this.$wait = CE("p", { class: "bx-blink-me" }), this.$inputList = CE("ul", {}, CE("li", { _dataset: { flag: 1 } }, t("keyboard-key")), CE("li", { _dataset: { flag: 2 } }, t("modifiers-note")), CE("li", { _dataset: { flag: 4 } }, t("mouse-click")), CE("li", { _dataset: { flag: 8 } }, t("mouse-wheel"))), CE("i", {}, t("press-esc-to-cancel"))))), this.$dialog.addEventListener("contextmenu", (e) => e.preventDefault()), document.documentElement.appendChild(this.$dialog); this.$overlay = CE("div", { class: "bx-key-binding-dialog-overlay bx-gone" }), this.$overlay.addEventListener("contextmenu", (e) => e.preventDefault()), document.documentElement.appendChild(this.$overlay), this.$dialog = CE("div", { class: "bx-key-binding-dialog bx-gone" }, this.$title = CE("h2", {}), CE("div", { class: "bx-key-binding-dialog-content" }, CE("div", !1, this.$wait = CE("p", { class: "bx-blink-me" }), this.$inputList = CE("ul", !1, CE("li", { _dataset: { flag: 1 } }, t("keyboard-key")), CE("li", { _dataset: { flag: 2 } }, t("modifiers-note")), CE("li", { _dataset: { flag: 4 } }, t("mouse-click")), CE("li", { _dataset: { flag: 8 } }, t("mouse-wheel"))), CE("i", !1, t("press-esc-to-cancel"))))), this.$dialog.addEventListener("contextmenu", (e) => e.preventDefault()), document.documentElement.appendChild(this.$dialog);
} }
show(options) { show(options) {
this.$currentElm = options.$elm, this.addEventListeners(); this.$currentElm = options.$elm, this.addEventListeners();
@ -6000,7 +6002,7 @@ class MkbMappingManagerDialog extends BaseProfileManagerDialog {
this.savePreset(); this.savePreset();
}; };
render() { render() {
let $rows = CE("div", {}, this.$unbindNote = CE("i", { class: "bx-mkb-note" }, t("right-click-to-unbind"))); let $rows = CE("div", !1, this.$unbindNote = CE("i", { class: "bx-mkb-note" }, t("right-click-to-unbind")));
for (let buttonIndex of this.BUTTONS_ORDER) { for (let buttonIndex of this.BUTTONS_ORDER) {
let [buttonName, buttonPrompt] = GamepadKeyName[buttonIndex], $elm, $fragment = document.createDocumentFragment(); let [buttonName, buttonPrompt] = GamepadKeyName[buttonIndex], $elm, $fragment = document.createDocumentFragment();
for (let i = 0;i < this.KEYS_PER_BUTTON; i++) for (let i = 0;i < this.KEYS_PER_BUTTON; i++)
@ -6016,7 +6018,7 @@ class MkbMappingManagerDialog extends BaseProfileManagerDialog {
}, CE("label", { title: buttonName }, buttonPrompt), $fragment); }, CE("label", { title: buttonName }, buttonPrompt), $fragment);
$rows.appendChild($keyRow); $rows.appendChild($keyRow);
} }
let savePreset = () => this.savePreset(), $extraSettings = CE("div", {}, createSettingRow(t("map-mouse-to"), this.$mouseMapTo = BxSelectElement.create(CE("select", { _on: { input: savePreset } }, CE("option", { value: 2 }, t("right-stick")), CE("option", { value: 1 }, t("left-stick")), CE("option", { value: 0 }, t("off"))))), createSettingRow(t("horizontal-sensitivity"), this.$mouseSensitivityX = BxNumberStepper.create("hor_sensitivity", 0, 1, 300, { let savePreset = () => this.savePreset(), $extraSettings = CE("div", !1, createSettingRow(t("map-mouse-to"), this.$mouseMapTo = BxSelectElement.create(CE("select", { _on: { input: savePreset } }, CE("option", { value: 2 }, t("right-stick")), CE("option", { value: 1 }, t("left-stick")), CE("option", { value: 0 }, t("off"))))), createSettingRow(t("horizontal-sensitivity"), this.$mouseSensitivityX = BxNumberStepper.create("hor_sensitivity", 0, 1, 300, {
suffix: "%", suffix: "%",
exactTicks: 50 exactTicks: 50
}, savePreset)), createSettingRow(t("vertical-sensitivity"), this.$mouseSensitivityY = BxNumberStepper.create("ver_sensitivity", 0, 1, 300, { }, savePreset)), createSettingRow(t("vertical-sensitivity"), this.$mouseSensitivityY = BxNumberStepper.create("ver_sensitivity", 0, 1, 300, {
@ -6026,7 +6028,7 @@ class MkbMappingManagerDialog extends BaseProfileManagerDialog {
suffix: "%", suffix: "%",
exactTicks: 10 exactTicks: 10
}, savePreset))); }, savePreset)));
this.$content = CE("div", {}, $rows, $extraSettings); this.$content = CE("div", !1, $rows, $extraSettings);
} }
switchPreset(id) { switchPreset(id) {
let preset = this.allPresets.data[id]; let preset = this.allPresets.data[id];
@ -6085,7 +6087,7 @@ class KeyboardShortcutsManagerDialog extends BaseProfileManagerDialog {
for (let groupLabel in SHORTCUT_ACTIONS) { for (let groupLabel in SHORTCUT_ACTIONS) {
let items = SHORTCUT_ACTIONS[groupLabel]; let items = SHORTCUT_ACTIONS[groupLabel];
if (!items) continue; if (!items) continue;
let $fieldSet = CE("fieldset", {}, CE("legend", {}, groupLabel)); let $fieldSet = CE("fieldset", !1, CE("legend", !1, groupLabel));
for (let action in items) { for (let action in items) {
let crumbs = items[action]; let crumbs = items[action];
if (!crumbs) continue; if (!crumbs) continue;
@ -6101,7 +6103,7 @@ class KeyboardShortcutsManagerDialog extends BaseProfileManagerDialog {
} }
if ($fieldSet.childElementCount > 1) $rows.appendChild($fieldSet); if ($fieldSet.childElementCount > 1) $rows.appendChild($fieldSet);
} }
this.$content = CE("div", {}, this.$unbindNote = CE("i", { class: "bx-mkb-note" }, t("right-click-to-unbind")), $rows); this.$content = CE("div", !1, this.$unbindNote = CE("i", { class: "bx-mkb-note" }, t("right-click-to-unbind")), $rows);
} }
onKeyChanged = (e) => { onKeyChanged = (e) => {
let $current = e.target, keyInfo = $current.keyInfo; let $current = e.target, keyInfo = $current.keyInfo;
@ -6279,7 +6281,7 @@ class SettingsDialog extends NavigationDialog {
}, t("settings-reload-note")), topButtons.push(this.$noteGlobalReload), this.$btnSuggestion = CE("div", { }, t("settings-reload-note")), topButtons.push(this.$noteGlobalReload), this.$btnSuggestion = CE("div", {
class: "bx-suggest-toggler bx-focusable", class: "bx-suggest-toggler bx-focusable",
tabindex: 0 tabindex: 0
}, CE("label", {}, t("suggest-settings")), CE("span", {}, "")), this.$btnSuggestion.addEventListener("click", SuggestionsSetting.renderSuggestions.bind(this)), topButtons.push(this.$btnSuggestion); }, CE("label", !1, t("suggest-settings")), CE("span", !1, "")), this.$btnSuggestion.addEventListener("click", SuggestionsSetting.renderSuggestions.bind(this)), topButtons.push(this.$btnSuggestion);
let $div = CE("div", { let $div = CE("div", {
class: "bx-top-buttons", class: "bx-top-buttons",
_nearby: { _nearby: {
@ -6574,7 +6576,7 @@ class SettingsDialog extends NavigationDialog {
label: t("layout"), label: t("layout"),
content: CE("select", { content: CE("select", {
disabled: !0 disabled: !0
}, CE("option", {}, t("default"))), }, CE("option", !1, t("default"))),
onCreated: (setting, $elm) => { onCreated: (setting, $elm) => {
$elm.addEventListener("input", (e) => { $elm.addEventListener("input", (e) => {
TouchController.applyCustomLayout($elm.value, 1000); TouchController.applyCustomLayout($elm.value, 1000);
@ -6893,7 +6895,7 @@ class SettingsDialog extends NavigationDialog {
_nearby: { _nearby: {
orientation: "horizontal" orientation: "horizontal"
} }
}, CE("span", {}, label), section.helpUrl && createButton({ }, CE("span", !1, label), section.helpUrl && createButton({
icon: BxIcon.QUESTION, icon: BxIcon.QUESTION,
style: 8 | 64, style: 8 | 64,
url: section.helpUrl, url: section.helpUrl,
@ -6945,7 +6947,7 @@ class SettingsDialog extends NavigationDialog {
_nearby: { _nearby: {
focus: () => this.focusActiveTab() focus: () => this.focusActiveTab()
} }
}), CE("div", {}, this.$btnReload = createButton({ }), CE("div", !1, this.$btnReload = createButton({
icon: BxIcon.REFRESH, icon: BxIcon.REFRESH,
style: 64 | 32, style: 64 | 32,
onClick: (e) => { onClick: (e) => {
@ -7477,7 +7479,7 @@ class HeaderSection {
label: "???", label: "???",
style: 16 | 32 | 64 | 256, style: 16 | 32 | 64 | 256,
onClick: (e) => SettingsDialog.getInstance().show() onClick: (e) => SettingsDialog.getInstance().show()
}), this.$buttonsWrapper = CE("div", {}, getPref("xhome.enabled") ? this.$btnRemotePlay : null, this.$btnSettings); }), this.$buttonsWrapper = CE("div", !1, getPref("xhome.enabled") ? this.$btnRemotePlay : null, this.$btnSettings);
} }
injectSettingsButton($parent) { injectSettingsButton($parent) {
if (!$parent) return; if (!$parent) return;
@ -7521,7 +7523,7 @@ class RemotePlayDialog extends NavigationDialog {
BxLogger.info(this.LOG_TAG, "constructor()"), this.setupDialog(); BxLogger.info(this.LOG_TAG, "constructor()"), this.setupDialog();
} }
setupDialog() { setupDialog() {
let $fragment = CE("div", { class: "bx-remote-play-container" }), $settingNote = CE("p", {}), currentResolution = getPref("xhome.video.resolution"), $resolutions = CE("select", {}, CE("option", { value: "720p" }, "720p"), CE("option", { value: "1080p" }, "1080p")); let $fragment = CE("div", { class: "bx-remote-play-container" }), $settingNote = CE("p", {}), currentResolution = getPref("xhome.video.resolution"), $resolutions = CE("select", !1, CE("option", { value: "720p" }, "720p"), CE("option", { value: "1080p" }, "1080p"));
$resolutions = BxSelectElement.create($resolutions), $resolutions.addEventListener("input", (e) => { $resolutions = BxSelectElement.create($resolutions), $resolutions.addEventListener("input", (e) => {
let value = e.target.value; let value = e.target.value;
$settingNote.textContent = value === "1080p" ? "✅ " + t("can-stream-xbox-360-games") : "❌ " + t("cant-stream-xbox-360-games"), setPref("xhome.video.resolution", value); $settingNote.textContent = value === "1080p" ? "✅ " + t("can-stream-xbox-360-games") : "❌ " + t("cant-stream-xbox-360-games"), setPref("xhome.video.resolution", value);
@ -7530,11 +7532,11 @@ class RemotePlayDialog extends NavigationDialog {
}); });
let $qualitySettings = CE("div", { let $qualitySettings = CE("div", {
class: "bx-remote-play-settings" class: "bx-remote-play-settings"
}, CE("div", {}, CE("label", {}, t("target-resolution"), $settingNote), $resolutions)); }, CE("div", !1, CE("label", !1, t("target-resolution"), $settingNote), $resolutions));
$fragment.appendChild($qualitySettings); $fragment.appendChild($qualitySettings);
let manager = RemotePlayManager.getInstance(), consoles = manager.getConsoles(); let manager = RemotePlayManager.getInstance(), consoles = manager.getConsoles();
for (let con of consoles) { for (let con of consoles) {
let $child = CE("div", { class: "bx-remote-play-device-wrapper" }, CE("div", { class: "bx-remote-play-device-info" }, CE("div", {}, CE("span", { class: "bx-remote-play-device-name" }, con.deviceName), CE("span", { class: "bx-remote-play-console-type" }, con.consoleType.replace("Xbox", ""))), CE("div", { class: "bx-remote-play-power-state" }, this.STATE_LABELS[con.powerState])), createButton({ let $child = CE("div", { class: "bx-remote-play-device-wrapper" }, CE("div", { class: "bx-remote-play-device-info" }, CE("div", !1, CE("span", { class: "bx-remote-play-device-name" }, con.deviceName), CE("span", { class: "bx-remote-play-console-type" }, con.consoleType.replace("Xbox", ""))), CE("div", { class: "bx-remote-play-power-state" }, this.STATE_LABELS[con.powerState])), createButton({
classes: ["bx-remote-play-connect-button"], classes: ["bx-remote-play-connect-button"],
label: t("console-connect"), label: t("console-connect"),
style: 1 | 64, style: 1 | 64,
@ -7822,7 +7824,7 @@ class LoadingScreen {
let endDateStr = endDate.toISOString().slice(0, 19); let endDateStr = endDate.toISOString().slice(0, 19);
endDateStr = endDateStr.substring(0, 10) + " " + endDateStr.substring(11, 19), endDateStr += ` (${LoadingScreen.secondsToString(waitTime)})`; endDateStr = endDateStr.substring(0, 10) + " " + endDateStr.substring(11, 19), endDateStr += ` (${LoadingScreen.secondsToString(waitTime)})`;
let $waitTimeBox = LoadingScreen.$waitTimeBox; let $waitTimeBox = LoadingScreen.$waitTimeBox;
if (!$waitTimeBox) $waitTimeBox = CE("div", { class: "bx-wait-time-box" }, CE("label", {}, t("server")), CE("span", {}, getPreferredServerRegion()), CE("label", {}, t("wait-time-estimated")), $estimated = CE("span", {}), CE("label", {}, t("wait-time-countdown")), $countDown = CE("span", {})), document.documentElement.appendChild($waitTimeBox), LoadingScreen.$waitTimeBox = $waitTimeBox; if (!$waitTimeBox) $waitTimeBox = CE("div", { class: "bx-wait-time-box" }, CE("label", !1, t("server")), CE("span", !1, getPreferredServerRegion()), CE("label", !1, t("wait-time-estimated")), $estimated = CE("span", {}), CE("label", !1, t("wait-time-countdown")), $countDown = CE("span", {})), document.documentElement.appendChild($waitTimeBox), LoadingScreen.$waitTimeBox = $waitTimeBox;
else $waitTimeBox.classList.remove("bx-gone"), $estimated = $waitTimeBox.querySelector(".bx-wait-time-estimated"), $countDown = $waitTimeBox.querySelector(".bx-wait-time-countdown"); else $waitTimeBox.classList.remove("bx-gone"), $estimated = $waitTimeBox.querySelector(".bx-wait-time-estimated"), $countDown = $waitTimeBox.querySelector(".bx-wait-time-countdown");
$estimated.textContent = endDateStr, $countDown.textContent = LoadingScreen.secondsToString(secondsLeft), document.title = `[${$countDown.textContent}] ${LoadingScreen.orgWebTitle}`, LoadingScreen.waitTimeInterval = window.setInterval(() => { $estimated.textContent = endDateStr, $countDown.textContent = LoadingScreen.secondsToString(secondsLeft), document.title = `[${$countDown.textContent}] ${LoadingScreen.orgWebTitle}`, LoadingScreen.waitTimeInterval = window.setInterval(() => {
if (secondsLeft--, $countDown.textContent = LoadingScreen.secondsToString(secondsLeft), document.title = `[${$countDown.textContent}] ${LoadingScreen.orgWebTitle}`, secondsLeft <= 0) LoadingScreen.waitTimeInterval && clearInterval(LoadingScreen.waitTimeInterval), LoadingScreen.waitTimeInterval = null; if (secondsLeft--, $countDown.textContent = LoadingScreen.secondsToString(secondsLeft), document.title = `[${$countDown.textContent}] ${LoadingScreen.orgWebTitle}`, secondsLeft <= 0) LoadingScreen.waitTimeInterval && clearInterval(LoadingScreen.waitTimeInterval), LoadingScreen.waitTimeInterval = null;
@ -8429,7 +8431,7 @@ function addCss() {
if (css += "div[class*=StreamMenu-module__menu]{min-width:100vw !important}", getPref("ui.streamMenu.simplify")) css += "div[class*=Menu-module__scrollable]{--bxStreamMenuItemSize:80px;--streamMenuItemSize:calc(var(--bxStreamMenuItemSize) + 40px) !important}.bx-badges{top:calc(var(--streamMenuItemSize) - 20px)}body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) - 10px) !important}button[class*=MenuItem-module__container]{min-width:auto !important;min-height:auto !important;width:var(--bxStreamMenuItemSize) !important;height:var(--bxStreamMenuItemSize) !important}div[class*=MenuItem-module__label]{display:none !important}svg[class*=MenuItem-module__icon]{width:36px;height:100% !important;padding:0 !important;margin:0 !important}"; if (css += "div[class*=StreamMenu-module__menu]{min-width:100vw !important}", getPref("ui.streamMenu.simplify")) css += "div[class*=Menu-module__scrollable]{--bxStreamMenuItemSize:80px;--streamMenuItemSize:calc(var(--bxStreamMenuItemSize) + 40px) !important}.bx-badges{top:calc(var(--streamMenuItemSize) - 20px)}body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) - 10px) !important}button[class*=MenuItem-module__container]{min-width:auto !important;min-height:auto !important;width:var(--bxStreamMenuItemSize) !important;height:var(--bxStreamMenuItemSize) !important}div[class*=MenuItem-module__label]{display:none !important}svg[class*=MenuItem-module__icon]{width:36px;height:100% !important;padding:0 !important;margin:0 !important}";
else css += "body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) + 30px)}body:not([data-media-type=tv]) .bx-badges{top:calc(var(--streamMenuItemSize) + 20px)}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]{min-width:auto !important;width:100px !important}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]:nth-child(n+2){margin-left:10px !important}body:not([data-media-type=tv]) div[class*=MenuItem-module__label]{margin-left:8px !important;margin-right:8px !important}"; else css += "body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) + 30px)}body:not([data-media-type=tv]) .bx-badges{top:calc(var(--streamMenuItemSize) + 20px)}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]{min-width:auto !important;width:100px !important}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]:nth-child(n+2){margin-left:10px !important}body:not([data-media-type=tv]) div[class*=MenuItem-module__label]{margin-left:8px !important;margin-right:8px !important}";
if (getPref("ui.hideScrollbar")) css += "html{scrollbar-width:none}body::-webkit-scrollbar{display:none}"; if (getPref("ui.hideScrollbar")) css += "html{scrollbar-width:none}body::-webkit-scrollbar{display:none}";
let $style = CE("style", {}, css); let $style = CE("style", !1, css);
document.documentElement.appendChild($style); document.documentElement.appendChild($style);
} }
function preloadFonts() { function preloadFonts() {
@ -9004,7 +9006,7 @@ class TouchControlAction extends BaseGameBarAction {
onClick: this.onClick, onClick: this.onClick,
classes: ["bx-activated"] classes: ["bx-activated"]
}); });
this.$content = CE("div", {}, $btnEnable, $btnDisable); this.$content = CE("div", !1, $btnEnable, $btnDisable);
} }
onClick = (e) => { onClick = (e) => {
super.onClick(e); super.onClick(e);
@ -9029,7 +9031,7 @@ class MicrophoneAction extends BaseGameBarAction {
icon: BxIcon.MICROPHONE_MUTED, icon: BxIcon.MICROPHONE_MUTED,
onClick: this.onClick onClick: this.onClick
}); });
this.$content = CE("div", {}, $btnMuted, $btnDefault), BxEventBus.Stream.on("microphone.state.changed", (payload) => { this.$content = CE("div", !1, $btnMuted, $btnDefault), BxEventBus.Stream.on("microphone.state.changed", (payload) => {
let enabled = payload.state === "Enabled"; let enabled = payload.state === "Enabled";
this.$content.dataset.activated = enabled.toString(), this.$content.classList.remove("bx-gone"); this.$content.dataset.activated = enabled.toString(), this.$content.classList.remove("bx-gone");
}); });
@ -9071,7 +9073,7 @@ class SpeakerAction extends BaseGameBarAction {
onClick: this.onClick, onClick: this.onClick,
classes: ["bx-activated"] classes: ["bx-activated"]
}); });
this.$content = CE("div", {}, $btnEnable, $btnMuted), BxEventBus.Stream.on("speaker.state.changed", (payload) => { this.$content = CE("div", !1, $btnEnable, $btnMuted), BxEventBus.Stream.on("speaker.state.changed", (payload) => {
let enabled = payload.state === 0; let enabled = payload.state === 0;
this.$content.dataset.activated = (!enabled).toString(); this.$content.dataset.activated = (!enabled).toString();
}); });
@ -9097,7 +9099,7 @@ class RendererAction extends BaseGameBarAction {
onClick: this.onClick, onClick: this.onClick,
classes: ["bx-activated"] classes: ["bx-activated"]
}); });
this.$content = CE("div", {}, $btnDefault, $btnActivated), BxEventBus.Stream.on("video.visibility.changed", (payload) => { this.$content = CE("div", !1, $btnDefault, $btnActivated), BxEventBus.Stream.on("video.visibility.changed", (payload) => {
this.$content.dataset.activated = (!payload.isVisible).toString(); this.$content.dataset.activated = (!payload.isVisible).toString();
}); });
} }
@ -9229,7 +9231,7 @@ class GameTile {
if (waitTime) totalWaitTime = waitTime.estimatedAllocationTimeInSeconds; if (waitTime) totalWaitTime = waitTime.estimatedAllocationTimeInSeconds;
} }
if (typeof totalWaitTime === "number" && isElementVisible($elm)) { if (typeof totalWaitTime === "number" && isElementVisible($elm)) {
let $div = CE("div", { class: "bx-game-tile-wait-time" }, createSvgIcon(BxIcon.PLAYTIME), CE("span", {}, totalWaitTime < 60 ? totalWaitTime + "s" : secondsToHm(totalWaitTime))), duration = totalWaitTime >= 900 ? "long" : totalWaitTime >= 600 ? "medium" : totalWaitTime >= 300 ? "short" : ""; let $div = CE("div", { class: "bx-game-tile-wait-time" }, createSvgIcon(BxIcon.PLAYTIME), CE("span", !1, totalWaitTime < 60 ? totalWaitTime + "s" : secondsToHm(totalWaitTime))), duration = totalWaitTime >= 900 ? "long" : totalWaitTime >= 600 ? "medium" : totalWaitTime >= 300 ? "short" : "";
if (duration) $div.dataset.duration = duration; if (duration) $div.dataset.duration = duration;
$elm.insertAdjacentElement("afterbegin", $div); $elm.insertAdjacentElement("afterbegin", $div);
} }
@ -9580,15 +9582,15 @@ if (BX_FLAGS.SafariWorkaround && document.readyState !== "loading") {
let css = ""; let css = "";
css += '.bx-reload-overlay{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;align-items:center;background:rgba(0,0,0,0.8);z-index:9999;color:#fff;text-align:center;font-weight:400;font-family:"Segoe UI",Arial,Helvetica,sans-serif;font-size:1.3rem}.bx-reload-overlay *:focus{outline:none !important}.bx-reload-overlay > div{margin:0 auto}.bx-reload-overlay a{text-decoration:none;display:inline-block;background:#107c10;color:#fff;border-radius:4px;padding:6px}'; css += '.bx-reload-overlay{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;align-items:center;background:rgba(0,0,0,0.8);z-index:9999;color:#fff;text-align:center;font-weight:400;font-family:"Segoe UI",Arial,Helvetica,sans-serif;font-size:1.3rem}.bx-reload-overlay *:focus{outline:none !important}.bx-reload-overlay > div{margin:0 auto}.bx-reload-overlay a{text-decoration:none;display:inline-block;background:#107c10;color:#fff;border-radius:4px;padding:6px}';
let isSafari = UserAgent.isSafari(), $secondaryAction; let isSafari = UserAgent.isSafari(), $secondaryAction;
if (isSafari) $secondaryAction = CE("p", {}, t("settings-reloading")); if (isSafari) $secondaryAction = CE("p", !1, t("settings-reloading"));
else $secondaryAction = CE("a", { else $secondaryAction = CE("a", {
href: "https://better-xcloud.github.io/troubleshooting", href: "https://better-xcloud.github.io/troubleshooting",
target: "_blank" target: "_blank"
}, "🤓 " + t("how-to-fix")); }, "🤓 " + t("how-to-fix"));
let $fragment = document.createDocumentFragment(); let $fragment = document.createDocumentFragment();
throw $fragment.appendChild(CE("style", {}, css)), $fragment.appendChild(CE("div", { throw $fragment.appendChild(CE("style", !1, css)), $fragment.appendChild(CE("div", {
class: "bx-reload-overlay" class: "bx-reload-overlay"
}, CE("div", {}, CE("p", {}, t("load-failed-message")), $secondaryAction))), document.documentElement.appendChild($fragment), isSafari && window.location.reload(!0), new Error("[Better xCloud] Executing workaround for Safari"); }, CE("div", !1, CE("p", !1, t("load-failed-message")), $secondaryAction))), document.documentElement.appendChild($fragment), isSafari && window.location.reload(!0), new Error("[Better xCloud] Executing workaround for Safari");
} }
window.addEventListener("load", (e) => { window.addEventListener("load", (e) => {
window.setTimeout(() => { window.setTimeout(() => {

View File

@ -113,7 +113,7 @@ if (isFullVersion() && BX_FLAGS.SafariWorkaround && document.readyState !== 'loa
const isSafari = UserAgent.isSafari(); const isSafari = UserAgent.isSafari();
let $secondaryAction: HTMLElement; let $secondaryAction: HTMLElement;
if (isSafari) { if (isSafari) {
$secondaryAction = CE('p', {}, t('settings-reloading')); $secondaryAction = CE('p', false, t('settings-reloading'));
} else { } else {
$secondaryAction = CE('a', { $secondaryAction = CE('a', {
href: 'https://better-xcloud.github.io/troubleshooting', href: 'https://better-xcloud.github.io/troubleshooting',
@ -123,12 +123,12 @@ if (isFullVersion() && BX_FLAGS.SafariWorkaround && document.readyState !== 'loa
// Show the reloading overlay // Show the reloading overlay
const $fragment = document.createDocumentFragment(); const $fragment = document.createDocumentFragment();
$fragment.appendChild(CE('style', {}, css)); $fragment.appendChild(CE('style', false, css));
$fragment.appendChild(CE('div',{ $fragment.appendChild(CE('div',{
class: 'bx-reload-overlay', class: 'bx-reload-overlay',
}, },
CE('div', {}, CE('div', false,
CE('p', {}, t('load-failed-message')), CE('p', false, t('load-failed-message')),
$secondaryAction, $secondaryAction,
), ),
)); ));

View File

@ -24,7 +24,7 @@ export class MicrophoneAction extends BaseGameBarAction {
onClick: this.onClick, onClick: this.onClick,
}); });
this.$content = CE('div', {}, $btnMuted, $btnDefault); this.$content = CE('div', false, $btnMuted, $btnDefault);
BxEventBus.Stream.on('microphone.state.changed', payload => { BxEventBus.Stream.on('microphone.state.changed', payload => {
const enabled = payload.state === MicrophoneState.ENABLED; const enabled = payload.state === MicrophoneState.ENABLED;

View File

@ -24,7 +24,7 @@ export class RendererAction extends BaseGameBarAction {
classes: ['bx-activated'], classes: ['bx-activated'],
}); });
this.$content = CE('div', {}, $btnDefault, $btnActivated); this.$content = CE('div', false, $btnDefault, $btnActivated);
BxEventBus.Stream.on('video.visibility.changed', payload => { BxEventBus.Stream.on('video.visibility.changed', payload => {
this.$content.dataset.activated = (!payload.isVisible).toString(); this.$content.dataset.activated = (!payload.isVisible).toString();

View File

@ -24,7 +24,7 @@ export class SpeakerAction extends BaseGameBarAction {
classes: ['bx-activated'], classes: ['bx-activated'],
}); });
this.$content = CE('div', {}, $btnEnable, $btnMuted); this.$content = CE('div', false, $btnEnable, $btnMuted);
BxEventBus.Stream.on('speaker.state.changed', payload => { BxEventBus.Stream.on('speaker.state.changed', payload => {
const enabled = payload.state === SpeakerState.ENABLED; const enabled = payload.state === SpeakerState.ENABLED;

View File

@ -25,7 +25,7 @@ export class TouchControlAction extends BaseGameBarAction {
classes: ['bx-activated'], classes: ['bx-activated'],
}); });
this.$content = CE('div', {}, $btnEnable, $btnDisable); this.$content = CE('div', false, $btnEnable, $btnDisable);
} }
onClick = (e: Event) => { onClick = (e: Event) => {

View File

@ -110,11 +110,11 @@ export class LoadingScreen {
let $waitTimeBox = LoadingScreen.$waitTimeBox; let $waitTimeBox = LoadingScreen.$waitTimeBox;
if (!$waitTimeBox) { if (!$waitTimeBox) {
$waitTimeBox = CE('div', { class: 'bx-wait-time-box' }, $waitTimeBox = CE('div', { class: 'bx-wait-time-box' },
CE('label', {}, t('server')), CE('label', false, t('server')),
CE('span', {}, getPreferredServerRegion()), CE('span', false, getPreferredServerRegion()),
CE('label', {}, t('wait-time-estimated')), CE('label', false, t('wait-time-estimated')),
$estimated = CE('span', {}), $estimated = CE('span', {}),
CE('label', {}, t('wait-time-countdown')), CE('label', false, t('wait-time-countdown')),
$countDown = CE('span', {}), $countDown = CE('span', {}),
); );

View File

@ -78,7 +78,7 @@ export class MkbPopup {
this.$title = CE('p'), this.$title = CE('p'),
this.$btnActivate = this.createActivateButton(), this.$btnActivate = this.createActivateButton(),
CE('div', {}, CE('div', false,
createButton({ createButton({
label: t('ignore'), label: t('ignore'),
style: ButtonStyle.GHOST, style: ButtonStyle.GHOST,

View File

@ -227,7 +227,7 @@ export class StreamStats {
class: `bx-stat-${statKey}`, class: `bx-stat-${statKey}`,
title: stat.name, title: stat.name,
}, },
CE('label', {}, statKey.toUpperCase()), CE('label', false, statKey.toUpperCase()),
stat.$element, stat.$element,
); );

View File

@ -167,14 +167,14 @@ export abstract class BaseProfileManagerDialog<T extends PresetRecord> extends N
this.$container = CE('div', { class: 'bx-centered-dialog' }, this.$container = CE('div', { class: 'bx-centered-dialog' },
CE('div', { class: 'bx-dialog-title' }, CE('div', { class: 'bx-dialog-title' },
CE('p', {}, this.title), CE('p', false, this.title),
createButton({ createButton({
icon: BxIcon.CLOSE, icon: BxIcon.CLOSE,
style: ButtonStyle.FOCUSABLE | ButtonStyle.CIRCULAR | ButtonStyle.GHOST, style: ButtonStyle.FOCUSABLE | ButtonStyle.CIRCULAR | ButtonStyle.GHOST,
onClick: e => this.hide(), onClick: e => this.hide(),
}), }),
), ),
CE('div', {}, CE('div', false,
$header, $header,
this.$defaultNote = CE('div', { class: 'bx-default-preset-note bx-gone' }, t('default-preset-note')), this.$defaultNote = CE('div', { class: 'bx-default-preset-note bx-gone' }, t('default-preset-note')),
), ),

View File

@ -37,7 +37,7 @@ export class KeyboardShortcutsManagerDialog extends BaseProfileManagerDialog<Key
continue; continue;
} }
const $fieldSet = CE('fieldset', {}, CE('legend', {}, groupLabel)); const $fieldSet = CE('fieldset', false, CE('legend', false, groupLabel));
for (const action in items) { for (const action in items) {
const crumbs = items[action as keyof typeof items]; const crumbs = items[action as keyof typeof items];
if (!crumbs) { if (!crumbs) {
@ -66,7 +66,7 @@ export class KeyboardShortcutsManagerDialog extends BaseProfileManagerDialog<Key
} }
} }
this.$content = CE('div', {}, this.$content = CE('div', false,
this.$unbindNote = CE('i', { class: 'bx-mkb-note' }, t('right-click-to-unbind')), this.$unbindNote = CE('i', { class: 'bx-mkb-note' }, t('right-click-to-unbind')),
$rows, $rows,
); );

View File

@ -93,7 +93,7 @@ export class MkbMappingManagerDialog extends BaseProfileManagerDialog<MkbPresetR
} }
private render() { private render() {
const $rows = CE('div', {}, const $rows = CE('div', false,
this.$unbindNote = CE('i', { class: 'bx-mkb-note' }, t('right-click-to-unbind')), this.$unbindNote = CE('i', { class: 'bx-mkb-note' }, t('right-click-to-unbind')),
); );
@ -131,7 +131,7 @@ export class MkbMappingManagerDialog extends BaseProfileManagerDialog<MkbPresetR
} }
const savePreset = () => this.savePreset(); const savePreset = () => this.savePreset();
const $extraSettings = CE('div', {}, const $extraSettings = CE('div', false,
createSettingRow( createSettingRow(
t('map-mouse-to'), t('map-mouse-to'),
this.$mouseMapTo = BxSelectElement.create(CE('select', { _on: { input: savePreset } }, this.$mouseMapTo = BxSelectElement.create(CE('select', { _on: { input: savePreset } },
@ -166,7 +166,7 @@ export class MkbMappingManagerDialog extends BaseProfileManagerDialog<MkbPresetR
), ),
); );
this.$content = CE('div', {}, this.$content = CE('div', false,
$rows, $rows,
$extraSettings, $extraSettings,
); );

View File

@ -37,7 +37,7 @@ export class RemotePlayDialog extends NavigationDialog {
const $settingNote = CE('p', {}); const $settingNote = CE('p', {});
const currentResolution = getPref(PrefKey.REMOTE_PLAY_STREAM_RESOLUTION); const currentResolution = getPref(PrefKey.REMOTE_PLAY_STREAM_RESOLUTION);
let $resolutions : HTMLSelectElement | NavigationElement = CE('select', {}, let $resolutions : HTMLSelectElement | NavigationElement = CE('select', false,
CE('option', { value: StreamResolution.DIM_720P }, '720p'), CE('option', { value: StreamResolution.DIM_720P }, '720p'),
CE('option', { value: StreamResolution.DIM_1080P }, '1080p'), CE('option', { value: StreamResolution.DIM_1080P }, '1080p'),
// CE('option', { value: StreamResolution.DIM_1080P_HQ }, `1080p (HQ)`), // CE('option', { value: StreamResolution.DIM_1080P_HQ }, `1080p (HQ)`),
@ -58,8 +58,8 @@ export class RemotePlayDialog extends NavigationDialog {
const $qualitySettings = CE('div', { const $qualitySettings = CE('div', {
class: 'bx-remote-play-settings', class: 'bx-remote-play-settings',
}, CE('div', {}, }, CE('div', false,
CE('label', {}, t('target-resolution'), $settingNote), CE('label', false, t('target-resolution'), $settingNote),
$resolutions, $resolutions,
)); ));
@ -72,7 +72,7 @@ export class RemotePlayDialog extends NavigationDialog {
for (let con of consoles) { for (let con of consoles) {
const $child = CE('div', { class: 'bx-remote-play-device-wrapper' }, const $child = CE('div', { class: 'bx-remote-play-device-wrapper' },
CE('div', { class: 'bx-remote-play-device-info' }, CE('div', { class: 'bx-remote-play-device-info' },
CE('div', {}, CE('div', false,
CE('span', { class: 'bx-remote-play-device-name' }, con.deviceName), CE('span', { class: 'bx-remote-play-device-name' }, con.deviceName),
CE('span', { class: 'bx-remote-play-console-type' }, con.consoleType.replace('Xbox', '')) CE('span', { class: 'bx-remote-play-console-type' }, con.consoleType.replace('Xbox', ''))
), ),

View File

@ -170,8 +170,8 @@ export class SettingsDialog extends NavigationDialog {
this.$btnSuggestion = CE('div', { this.$btnSuggestion = CE('div', {
class: 'bx-suggest-toggler bx-focusable', class: 'bx-suggest-toggler bx-focusable',
tabindex: 0, tabindex: 0,
}, CE('label', {}, t('suggest-settings')), }, CE('label', false, t('suggest-settings')),
CE('span', {}, ''), CE('span', false, ''),
); );
this.$btnSuggestion.addEventListener('click', SuggestionsSetting.renderSuggestions.bind(this)); this.$btnSuggestion.addEventListener('click', SuggestionsSetting.renderSuggestions.bind(this));
@ -518,7 +518,7 @@ export class SettingsDialog extends NavigationDialog {
label: t('layout'), label: t('layout'),
content: CE('select', { content: CE('select', {
disabled: true, disabled: true,
}, CE('option', {}, t('default'))), }, CE('option', false, t('default'))),
onCreated: (setting: SettingTabSectionItem, $elm: HTMLSelectElement) => { onCreated: (setting: SettingTabSectionItem, $elm: HTMLSelectElement) => {
$elm.addEventListener('input', e => { $elm.addEventListener('input', e => {
TouchController.applyCustomLayout($elm.value, 1000); TouchController.applyCustomLayout($elm.value, 1000);
@ -1066,7 +1066,7 @@ export class SettingsDialog extends NavigationDialog {
orientation: 'horizontal', orientation: 'horizontal',
} }
}, },
CE('span', {}, label), CE('span', false, label),
section.helpUrl && createButton({ section.helpUrl && createButton({
icon: BxIcon.QUESTION, icon: BxIcon.QUESTION,
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE, style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
@ -1146,7 +1146,7 @@ export class SettingsDialog extends NavigationDialog {
focus: () => this.focusActiveTab(), focus: () => this.focusActiveTab(),
}, },
}), }),
CE('div', {}, CE('div', false,
this.$btnReload = createButton({ this.$btnReload = createButton({
icon: BxIcon.REFRESH, icon: BxIcon.REFRESH,
style: ButtonStyle.FOCUSABLE | ButtonStyle.DROP_SHADOW, style: ButtonStyle.FOCUSABLE | ButtonStyle.DROP_SHADOW,

View File

@ -56,7 +56,7 @@ export class ControllerExtraSettings extends HTMLElement {
})); }));
$container.append( $container.append(
CE('span', {}, t('no-controllers-connected')), CE('span', false, t('no-controllers-connected')),
CE('div', { class: 'bx-controller-extra-wrapper' }, CE('div', { class: 'bx-controller-extra-wrapper' },
$selectControllers, $selectControllers,
@ -98,7 +98,7 @@ export class ControllerExtraSettings extends HTMLElement {
), ),
{ {
multiLines: true, multiLines: true,
$note: CE('div', { class: 'bx-settings-dialog-note' }, 'ⓘ ' + t('slightly-increase-input-latency')), $note: CE('div', { class: 'bx-settings-dialog-note' }, 'ⓘ ' + t('slightly-increases-input-latency')),
}, },
), ),
), ),

View File

@ -92,7 +92,7 @@ export class SuggestionsSetting {
// Start rendering // Start rendering
const $suggestedSettings = CE('div', { class: 'bx-suggest-wrapper' }); const $suggestedSettings = CE('div', { class: 'bx-suggest-wrapper' });
const $select = CE('select', {}, const $select = CE('select', false,
hasRecommendedSettings && CE('option', { value: 'recommended' }, t('recommended')), hasRecommendedSettings && CE('option', { value: 'recommended' }, t('recommended')),
!hasRecommendedSettings && CE('option', { value: 'highest' }, t('highest-quality')), !hasRecommendedSettings && CE('option', { value: 'highest' }, t('highest-quality')),
CE('option', { value: 'default' }, t('default')), CE('option', { value: 'default' }, t('default')),

View File

@ -30,7 +30,7 @@ export class GameTile {
if (typeof totalWaitTime === 'number' && isElementVisible($elm)) { if (typeof totalWaitTime === 'number' && isElementVisible($elm)) {
const $div = CE('div', { class: 'bx-game-tile-wait-time' }, const $div = CE('div', { class: 'bx-game-tile-wait-time' },
createSvgIcon(BxIcon.PLAYTIME), createSvgIcon(BxIcon.PLAYTIME),
CE('span', {}, totalWaitTime < 60 ? totalWaitTime + 's' : secondsToHm(totalWaitTime)), CE('span', false, totalWaitTime < 60 ? totalWaitTime + 's' : secondsToHm(totalWaitTime)),
); );
const duration = (totalWaitTime >= 15 * 60) ? 'long' : (totalWaitTime >= 10 * 60) ? 'medium' : (totalWaitTime >= 5 * 60 ) ? 'short' : ''; const duration = (totalWaitTime >= 15 * 60) ? 'long' : (totalWaitTime >= 10 * 60) ? 'medium' : (totalWaitTime >= 5 * 60 ) ? 'short' : '';

View File

@ -39,7 +39,7 @@ export class HeaderSection {
onClick: e => SettingsDialog.getInstance().show(), onClick: e => SettingsDialog.getInstance().show(),
}); });
this.$buttonsWrapper = CE('div', {}, this.$buttonsWrapper = CE('div', false,
getPref(PrefKey.REMOTE_PLAY_ENABLED) ? this.$btnRemotePlay : null, getPref(PrefKey.REMOTE_PLAY_ENABLED) ? this.$btnRemotePlay : null,
this.$btnSettings, this.$btnSettings,
); );

View File

@ -164,7 +164,7 @@ body::-webkit-scrollbar {
`); `);
} }
const $style = CE('style', {}, css); const $style = CE('style', false, css);
document.documentElement.appendChild($style); document.documentElement.appendChild($style);
} }

View File

@ -89,11 +89,9 @@ type HTMLElementTagNameMap = {
[key: string] : HTMLElement; [key: string] : HTMLElement;
}; };
function createElement<T extends keyof HTMLElementTagNameMap>(elmName: T, props: CreateElementOptions={}, ..._: any): HTMLElementTagNameMap[T] { function createElement<T extends keyof HTMLElementTagNameMap>(elmName: T, props?: CreateElementOptions | false, ..._: any): HTMLElementTagNameMap[T] {
let $elm; let $elm;
const hasNs = 'xmlns' in props; const hasNs = props && 'xmlns' in props;
// console.trace('createElement', elmName, props);
if (hasNs) { if (hasNs) {
$elm = document.createElementNS(props.xmlns, elmName as string); $elm = document.createElementNS(props.xmlns, elmName as string);
@ -102,35 +100,39 @@ function createElement<T extends keyof HTMLElementTagNameMap>(elmName: T, props:
$elm = document.createElement(elmName as string); $elm = document.createElement(elmName as string);
} }
if (props._nearby) { if (props) {
setNearby($elm, props._nearby); // console.trace('createElement', elmName, props);
delete props._nearby;
}
if (props._on) { if (props._nearby) {
for (const name in props._on) { setNearby($elm, props._nearby);
$elm.addEventListener(name, props._on[name]); delete props._nearby;
}
delete props._on;
}
if (props._dataset) {
for (const name in props._dataset) {
$elm.dataset[name] = props._dataset[name] as string;
}
delete props._dataset;
}
for (const key in props) {
if ($elm.hasOwnProperty(key)) {
continue;
} }
const value = props[key]; if (props._on) {
if (hasNs) { for (const name in props._on) {
$elm.setAttributeNS(null, key, value); $elm.addEventListener(name, props._on[name]);
} else { }
$elm.setAttribute(key, value); delete props._on;
}
if (props._dataset) {
for (const name in props._dataset) {
$elm.dataset[name] = props._dataset[name] as string;
}
delete props._dataset;
}
for (const key in props) {
if ($elm.hasOwnProperty(key)) {
continue;
}
const value = props[key];
if (hasNs) {
$elm.setAttributeNS(null, key, value);
} else {
$elm.setAttribute(key, value);
}
} }
} }
@ -184,14 +186,14 @@ export function createButton<T=HTMLButtonElement>(options: BxButtonOptions): T {
options.classes && $btn.classList.add(...options.classes); options.classes && $btn.classList.add(...options.classes);
options.icon && $btn.appendChild(createSvgIcon(options.icon)); options.icon && $btn.appendChild(createSvgIcon(options.icon));
options.label && $btn.appendChild(CE('span', {}, options.label)); options.label && $btn.appendChild(CE('span', false, options.label));
options.title && $btn.setAttribute('title', options.title); options.title && $btn.setAttribute('title', options.title);
options.onClick && $btn.addEventListener('click', options.onClick); options.onClick && $btn.addEventListener('click', options.onClick);
$btn.tabIndex = typeof options.tabIndex === 'number' ? options.tabIndex : 0; $btn.tabIndex = typeof options.tabIndex === 'number' ? options.tabIndex : 0;
if (options.secondaryText) { if (options.secondaryText) {
$btn.classList.add('bx-button-multi-lines'); $btn.classList.add('bx-button-multi-lines');
$btn.appendChild(CE('span', {}, options.secondaryText)); $btn.appendChild(CE('span', false, options.secondaryText));
} }
for (const key in options.attributes) { for (const key in options.attributes) {

View File

@ -321,7 +321,7 @@ export class GlobalSettingsStorage extends BaseSettingsStorage {
requiredVariants: 'full', requiredVariants: 'full',
label: t('enable-local-co-op-support'), label: t('enable-local-co-op-support'),
default: false, default: false,
note: () => CE('div', {}, note: () => CE('div', false,
CE('a', { CE('a', {
href: 'https://github.com/redphx/better-xcloud/discussions/275', href: 'https://github.com/redphx/better-xcloud/discussions/275',
target: '_blank', target: '_blank',

View File

@ -27,7 +27,6 @@ export const SUPPORTED_LANGUAGES = {
}; };
const Texts = { const Texts = {
"slightly-increase-input-latency": "Slightly increase input latency",
"achievements": "Achievements", "achievements": "Achievements",
"activate": "Activate", "activate": "Activate",
"activated": "Activated", "activated": "Activated",
@ -325,6 +324,7 @@ const Texts = {
"show-wait-time-in-game-card": "Show wait time in game card", "show-wait-time-in-game-card": "Show wait time in game card",
"simplify-stream-menu": "Simplify Stream's menu", "simplify-stream-menu": "Simplify Stream's menu",
"skip-splash-video": "Skip Xbox splash video", "skip-splash-video": "Skip Xbox splash video",
"slightly-increases-input-latency": "Slightly increases input latency",
"slow": "Slow", "slow": "Slow",
"small": "Small", "small": "Small",
"smart-tv": "Smart TV", "smart-tv": "Smart TV",

View File

@ -79,7 +79,7 @@ export class BxDualNumberStepper extends HTMLInputElement implements BxHtmlSetti
$rangeTo.addEventListener('input', self.onRangeInput); $rangeTo.addEventListener('input', self.onRangeInput);
self.addEventListener('input', self.onRangeInput); self.addEventListener('input', self.onRangeInput);
self.append(CE('div', {}, $rangeFrom, $rangeTo)); self.append(CE('div', false, $rangeFrom, $rangeTo));
// Set values // Set values
BxDualNumberStepper.setValues.call(self, values); BxDualNumberStepper.setValues.call(self, values);

View File

@ -121,15 +121,15 @@ class KeyBindingDialog {
this.$dialog = CE('div', { class: `bx-key-binding-dialog bx-gone` }, this.$dialog = CE('div', { class: `bx-key-binding-dialog bx-gone` },
this.$title = CE('h2', {}), this.$title = CE('h2', {}),
CE('div', { class: 'bx-key-binding-dialog-content' }, CE('div', { class: 'bx-key-binding-dialog-content' },
CE('div', {}, CE('div', false,
this.$wait = CE('p', { class: 'bx-blink-me' }), this.$wait = CE('p', { class: 'bx-blink-me' }),
this.$inputList = CE('ul', {}, this.$inputList = CE('ul', false,
CE('li', { _dataset: { flag: BxKeyBindingButtonFlag.KEYBOARD_PRESS } }, t('keyboard-key')), CE('li', { _dataset: { flag: BxKeyBindingButtonFlag.KEYBOARD_PRESS } }, t('keyboard-key')),
CE('li', { _dataset: { flag: BxKeyBindingButtonFlag.KEYBOARD_MODIFIER } }, t('modifiers-note')), CE('li', { _dataset: { flag: BxKeyBindingButtonFlag.KEYBOARD_MODIFIER } }, t('modifiers-note')),
CE('li', { _dataset: { flag: BxKeyBindingButtonFlag.MOUSE_CLICK } }, t('mouse-click')), CE('li', { _dataset: { flag: BxKeyBindingButtonFlag.MOUSE_CLICK } }, t('mouse-click')),
CE('li', { _dataset: { flag: BxKeyBindingButtonFlag.MOUSE_WHEEL } }, t('mouse-wheel')), CE('li', { _dataset: { flag: BxKeyBindingButtonFlag.MOUSE_WHEEL } }, t('mouse-wheel')),
), ),
CE('i', {}, t('press-esc-to-cancel')), CE('i', false, t('press-esc-to-cancel')),
), ),
), ),
); );

View File

@ -48,7 +48,7 @@ export class BxNumberStepper extends HTMLInputElement implements BxHtmlSettingEl
class: 'bx-number-stepper', class: 'bx-number-stepper',
id: `bx_setting_${escapeCssSelector(key)}`, id: `bx_setting_${escapeCssSelector(key)}`,
}, },
CE('div', {}, CE('div', false,
$btnDec = CE('button', { $btnDec = CE('button', {
_dataset: { _dataset: {
type: 'dec' as ButtonType, type: 'dec' as ButtonType,

View File

@ -96,9 +96,9 @@ export class BxSelectElement extends HTMLSelectElement {
class: 'bx-select-value bx-focusable', class: 'bx-select-value bx-focusable',
tabindex: 0, tabindex: 0,
}, },
CE('div', {}, CE('div', false,
self.$checkBox = CE('input', { type: 'checkbox' }), self.$checkBox = CE('input', { type: 'checkbox' }),
self.$label = CE('span', {}, ''), self.$label = CE('span', false, ''),
), ),
self.$indicators, self.$indicators,
@ -115,7 +115,7 @@ export class BxSelectElement extends HTMLSelectElement {
BxEvent.dispatch($select, 'input'); BxEvent.dispatch($select, 'input');
}); });
} else { } else {
$content = CE('div', {}, $content = CE('div', false,
self.$label = CE('label', { for: $select.id + '_checkbox' }, ''), self.$label = CE('label', { for: $select.id + '_checkbox' }, ''),
self.$indicators, self.$indicators,
); );
@ -259,7 +259,7 @@ export class BxSelectElement extends HTMLSelectElement {
$label.innerHTML = ''; $label.innerHTML = '';
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
fragment.appendChild(CE('span', {}, groupLabel)); fragment.appendChild(CE('span', false, groupLabel));
fragment.appendChild(document.createTextNode(content)); fragment.appendChild(document.createTextNode(content));
$label.appendChild(fragment); $label.appendChild(fragment);