This commit is contained in:
redphx 2024-12-07 16:48:58 +07:00
parent 557a38214d
commit 4011eb402a
55 changed files with 181 additions and 139 deletions

View File

@ -38,7 +38,7 @@ try {
if (!BX_FLAGS.DeviceInfo.userAgent) BX_FLAGS.DeviceInfo.userAgent = window.navigator.userAgent; if (!BX_FLAGS.DeviceInfo.userAgent) BX_FLAGS.DeviceInfo.userAgent = window.navigator.userAgent;
BxLogger.info("BxFlags", BX_FLAGS); BxLogger.info("BxFlags", BX_FLAGS);
var NATIVE_FETCH = window.fetch; var NATIVE_FETCH = window.fetch;
var SMART_TV_UNIQUE_ID = "FC4A1DA2-711C-4E9C-BC7F-047AF8A672EA", CHROMIUM_VERSION = "123.0.0.0"; var SMART_TV_UNIQUE_ID = "FC4A1DA2-711C-4E9C-BC7F-047AF8A672EA", CHROMIUM_VERSION = "125.0.0.0";
if (!!window.chrome || window.navigator.userAgent.includes("Chrome")) { if (!!window.chrome || window.navigator.userAgent.includes("Chrome")) {
let match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/); let match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/);
if (match) CHROMIUM_VERSION = match[1]; if (match) CHROMIUM_VERSION = match[1];
@ -2515,6 +2515,7 @@ class ControllerSettingsTable extends BaseLocalTable {
async getControllersData() { async getControllersData() {
let all = await this.getAll(), results = {}; let all = await this.getAll(), results = {};
for (let key in all) { for (let key in all) {
if (!all[key]) continue;
let settings = all[key].data; let settings = all[key].data;
settings.vibrationIntensity /= 100, results[key] = settings; settings.vibrationIntensity /= 100, results[key] = settings;
} }
@ -3085,8 +3086,14 @@ class EmulatedMkbHandler extends MkbHandler {
else this.mouseDataProvider = new PointerLockMouseDataProvider(this); else this.mouseDataProvider = new PointerLockMouseDataProvider(this);
if (this.mouseDataProvider.init(), window.addEventListener("keydown", this.onKeyboardEvent), window.addEventListener("keyup", this.onKeyboardEvent), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown), AppInterface) window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this); if (this.mouseDataProvider.init(), window.addEventListener("keydown", this.onKeyboardEvent), window.addEventListener("keyup", this.onKeyboardEvent), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown), AppInterface) window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this);
else document.addEventListener("pointerlockchange", this.onPointerLockChange), document.addEventListener("pointerlockerror", this.onPointerLockError); else document.addEventListener("pointerlockchange", this.onPointerLockChange), document.addEventListener("pointerlockerror", this.onPointerLockError);
if (MkbPopup.getInstance().reset(), AppInterface) Toast.show(t("press-key-to-toggle-mkb", { key: "<b>F8</b>" }), t("virtual-controller"), { html: !0 }), this.waitForMouseData(!1); if (MkbPopup.getInstance().reset(), AppInterface) {
else this.waitForMouseData(!0); let shortcutKey = StreamSettings.findKeyboardShortcut("mkb.toggle");
if (shortcutKey) {
let msg = t("press-key-to-toggle-mkb", { key: `<b>${KeyHelper.codeToKeyName(shortcutKey)}</b>` });
Toast.show(msg, t("native-mkb"), { html: !0 });
}
this.waitForMouseData(!1);
} else this.waitForMouseData(!0);
} }
destroy() { destroy() {
if (!this.initialized) return; if (!this.initialized) return;
@ -3295,7 +3302,7 @@ class NavigationDialogManager {
if (this.gamepadLastStates[gamepad.index] = null, lastKeyPressed) return; if (this.gamepadLastStates[gamepad.index] = null, lastKeyPressed) return;
if (this.updateActiveInput("gamepad"), this.handleGamepad(gamepad, releasedButton)) return; if (this.updateActiveInput("gamepad"), this.handleGamepad(gamepad, releasedButton)) return;
if (releasedButton === 0) { if (releasedButton === 0) {
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent("click", { bubbles: !0 })); document.activeElement?.dispatchEvent(new MouseEvent("click", { bubbles: !0 }));
return; return;
} else if (releasedButton === 1) { } else if (releasedButton === 1) {
this.hide(); this.hide();
@ -3560,6 +3567,7 @@ class BxSelectElement extends HTMLSelectElement {
$btnPrev.classList.toggle("bx-inactive", disableButtons), $btnNext.classList.toggle("bx-inactive", disableButtons); $btnPrev.classList.toggle("bx-inactive", disableButtons), $btnNext.classList.toggle("bx-inactive", disableButtons);
for (let i = 0;i < optionsList.length; i++) { for (let i = 0;i < optionsList.length; i++) {
let $option2 = optionsList[i], $indicator = indicatorsList[i]; let $option2 = optionsList[i], $indicator = indicatorsList[i];
if (!$option2 || !$indicator) continue;
if (clearDataSet($indicator), $option2.selected) $indicator.dataset.selected = "true"; if (clearDataSet($indicator), $option2.selected) $indicator.dataset.selected = "true";
if ($option2.index === visibleIndex) $indicator.dataset.highlighted = "true"; if ($option2.index === visibleIndex) $indicator.dataset.highlighted = "true";
} }
@ -5489,7 +5497,7 @@ class XcloudInterceptor {
let PREF_STREAM_TARGET_RESOLUTION = getPref("stream.video.resolution"), PREF_STREAM_PREFERRED_LOCALE = getPref("stream.locale"), url = typeof request === "string" ? request : request.url, parsedUrl = new URL(url), badgeRegion = parsedUrl.host.split(".", 1)[0]; let PREF_STREAM_TARGET_RESOLUTION = getPref("stream.video.resolution"), PREF_STREAM_PREFERRED_LOCALE = getPref("stream.locale"), url = typeof request === "string" ? request : request.url, parsedUrl = new URL(url), badgeRegion = parsedUrl.host.split(".", 1)[0];
for (let regionName in STATES.serverRegions) { for (let regionName in STATES.serverRegions) {
let region = STATES.serverRegions[regionName]; let region = STATES.serverRegions[regionName];
if (parsedUrl.origin == region.baseUri) { if (region && parsedUrl.origin === region.baseUri) {
badgeRegion = regionName; badgeRegion = regionName;
break; break;
} }
@ -6307,7 +6315,7 @@ class XboxApi {
let url = `https://displaycatalog.mp.microsoft.com/v7.0/products/lookup?market=US&languages=en&value=${xboxTitleId}&alternateId=XboxTitleId&fieldsTemplate=browse`, productTitle = (await (await NATIVE_FETCH(url)).json()).Products[0].LocalizedProperties[0].ProductTitle; let url = `https://displaycatalog.mp.microsoft.com/v7.0/products/lookup?market=US&languages=en&value=${xboxTitleId}&alternateId=XboxTitleId&fieldsTemplate=browse`, productTitle = (await (await NATIVE_FETCH(url)).json()).Products[0].LocalizedProperties[0].ProductTitle;
return XboxApi.CACHED_TITLES[xboxTitleId] = productTitle, productTitle; return XboxApi.CACHED_TITLES[xboxTitleId] = productTitle, productTitle;
} catch (e) {} } catch (e) {}
return null; return;
} }
} }
class RootDialogObserver { class RootDialogObserver {

View File

@ -40,7 +40,7 @@ try {
if (!BX_FLAGS.DeviceInfo.userAgent) BX_FLAGS.DeviceInfo.userAgent = window.navigator.userAgent; if (!BX_FLAGS.DeviceInfo.userAgent) BX_FLAGS.DeviceInfo.userAgent = window.navigator.userAgent;
BxLogger.info("BxFlags", BX_FLAGS); BxLogger.info("BxFlags", BX_FLAGS);
var NATIVE_FETCH = window.fetch; var NATIVE_FETCH = window.fetch;
var SMART_TV_UNIQUE_ID = "FC4A1DA2-711C-4E9C-BC7F-047AF8A672EA", CHROMIUM_VERSION = "123.0.0.0"; var SMART_TV_UNIQUE_ID = "FC4A1DA2-711C-4E9C-BC7F-047AF8A672EA", CHROMIUM_VERSION = "125.0.0.0";
if (!!window.chrome || window.navigator.userAgent.includes("Chrome")) { if (!!window.chrome || window.navigator.userAgent.includes("Chrome")) {
let match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/); let match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/);
if (match) CHROMIUM_VERSION = match[1]; if (match) CHROMIUM_VERSION = match[1];
@ -2624,6 +2624,7 @@ class ControllerSettingsTable extends BaseLocalTable {
async getControllersData() { async getControllersData() {
let all = await this.getAll(), results = {}; let all = await this.getAll(), results = {};
for (let key in all) { for (let key in all) {
if (!all[key]) continue;
let settings = all[key].data; let settings = all[key].data;
settings.vibrationIntensity /= 100, results[key] = settings; settings.vibrationIntensity /= 100, results[key] = settings;
} }
@ -3200,8 +3201,14 @@ class EmulatedMkbHandler extends MkbHandler {
else this.mouseDataProvider = new PointerLockMouseDataProvider(this); else this.mouseDataProvider = new PointerLockMouseDataProvider(this);
if (this.mouseDataProvider.init(), window.addEventListener("keydown", this.onKeyboardEvent), window.addEventListener("keyup", this.onKeyboardEvent), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown), AppInterface) window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this); if (this.mouseDataProvider.init(), window.addEventListener("keydown", this.onKeyboardEvent), window.addEventListener("keyup", this.onKeyboardEvent), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown), AppInterface) window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this);
else document.addEventListener("pointerlockchange", this.onPointerLockChange), document.addEventListener("pointerlockerror", this.onPointerLockError); else document.addEventListener("pointerlockchange", this.onPointerLockChange), document.addEventListener("pointerlockerror", this.onPointerLockError);
if (MkbPopup.getInstance().reset(), AppInterface) Toast.show(t("press-key-to-toggle-mkb", { key: "<b>F8</b>" }), t("virtual-controller"), { html: !0 }), this.waitForMouseData(!1); if (MkbPopup.getInstance().reset(), AppInterface) {
else this.waitForMouseData(!0); let shortcutKey = StreamSettings.findKeyboardShortcut("mkb.toggle");
if (shortcutKey) {
let msg = t("press-key-to-toggle-mkb", { key: `<b>${KeyHelper.codeToKeyName(shortcutKey)}</b>` });
Toast.show(msg, t("native-mkb"), { html: !0 });
}
this.waitForMouseData(!1);
} else this.waitForMouseData(!0);
} }
destroy() { destroy() {
if (!this.initialized) return; if (!this.initialized) return;
@ -3418,7 +3425,7 @@ class NavigationDialogManager {
if (this.gamepadLastStates[gamepad.index] = null, lastKeyPressed) return; if (this.gamepadLastStates[gamepad.index] = null, lastKeyPressed) return;
if (this.updateActiveInput("gamepad"), this.handleGamepad(gamepad, releasedButton)) return; if (this.updateActiveInput("gamepad"), this.handleGamepad(gamepad, releasedButton)) return;
if (releasedButton === 0) { if (releasedButton === 0) {
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent("click", { bubbles: !0 })); document.activeElement?.dispatchEvent(new MouseEvent("click", { bubbles: !0 }));
return; return;
} else if (releasedButton === 1) { } else if (releasedButton === 1) {
this.hide(); this.hide();
@ -3869,6 +3876,7 @@ class BxSelectElement extends HTMLSelectElement {
$btnPrev.classList.toggle("bx-inactive", disableButtons), $btnNext.classList.toggle("bx-inactive", disableButtons); $btnPrev.classList.toggle("bx-inactive", disableButtons), $btnNext.classList.toggle("bx-inactive", disableButtons);
for (let i = 0;i < optionsList.length; i++) { for (let i = 0;i < optionsList.length; i++) {
let $option2 = optionsList[i], $indicator = indicatorsList[i]; let $option2 = optionsList[i], $indicator = indicatorsList[i];
if (!$option2 || !$indicator) continue;
if (clearDataSet($indicator), $option2.selected) $indicator.dataset.selected = "true"; if (clearDataSet($indicator), $option2.selected) $indicator.dataset.selected = "true";
if ($option2.index === visibleIndex) $indicator.dataset.highlighted = "true"; if ($option2.index === visibleIndex) $indicator.dataset.highlighted = "true";
} }
@ -4031,7 +4039,7 @@ window.dispatchEvent(new GamepadEvent('gamepadconnected', { gamepad }));
} }
}; };
window.BX_EXPOSED.toggleLocalCoOp = this.toggleLocalCoOp.bind(this);`; window.BX_EXPOSED.toggleLocalCoOp = this.toggleLocalCoOp.bind(this);`;
var set_currently_focused_interactable_default = `e && BxEvent.dispatch(window, BxEvent.NAVIGATION_FOCUS_CHANGED, {element: e});`; var set_currently_focused_interactable_default = `e && BxEvent.dispatch(window, BxEvent.NAVIGATION_FOCUS_CHANGED, { element: e });`;
var remote_play_enable_default = `connectMode: window.BX_REMOTE_PLAY_CONFIG ? "xhome-connect" : "cloud-connect", var remote_play_enable_default = `connectMode: window.BX_REMOTE_PLAY_CONFIG ? "xhome-connect" : "cloud-connect",
remotePlayServerId: (window.BX_REMOTE_PLAY_CONFIG && window.BX_REMOTE_PLAY_CONFIG.serverId) || '',`; remotePlayServerId: (window.BX_REMOTE_PLAY_CONFIG && window.BX_REMOTE_PLAY_CONFIG.serverId) || '',`;
var remote_play_keep_alive_default = `const msg = JSON.parse(e); var remote_play_keep_alive_default = `const msg = JSON.parse(e);
@ -4329,7 +4337,9 @@ BxEvent.dispatch(window, BxEvent.XCLOUD_POLLING_MODE_CHANGED);
patchXcloudTitleInfo(str) { patchXcloudTitleInfo(str) {
let text = "async cloudConnect", index = str.indexOf(text); let text = "async cloudConnect", index = str.indexOf(text);
if (index < 0) return !1; if (index < 0) return !1;
let backetIndex = str.indexOf("{", index), titleInfoVar = str.substring(index, backetIndex).match(/\(([^)]+)\)/)[1].split(",")[0], newCode = ` let backetIndex = str.indexOf("{", index), params = str.substring(index, backetIndex).match(/\(([^)]+)\)/)[1];
if (!params) return !1;
let titleInfoVar = params.split(",")[0], newCode = `
${titleInfoVar} = window.BX_EXPOSED.modifyTitleInfo(${titleInfoVar}); ${titleInfoVar} = window.BX_EXPOSED.modifyTitleInfo(${titleInfoVar});
BxLogger.info('patchXcloudTitleInfo', ${titleInfoVar}); BxLogger.info('patchXcloudTitleInfo', ${titleInfoVar});
`; `;
@ -4338,7 +4348,9 @@ BxLogger.info('patchXcloudTitleInfo', ${titleInfoVar});
patchRemotePlayMkb(str) { patchRemotePlayMkb(str) {
let text = "async homeConsoleConnect", index = str.indexOf(text); let text = "async homeConsoleConnect", index = str.indexOf(text);
if (index < 0) return !1; if (index < 0) return !1;
let backetIndex = str.indexOf("{", index), configsVar = str.substring(index, backetIndex).match(/\(([^)]+)\)/)[1].split(",")[1], newCode = ` let backetIndex = str.indexOf("{", index), params = str.substring(index, backetIndex).match(/\(([^)]+)\)/)[1];
if (!params) return !1;
let configsVar = params.split(",")[1], newCode = `
Object.assign(${configsVar}.inputConfiguration, { Object.assign(${configsVar}.inputConfiguration, {
enableMouseInput: false, enableMouseInput: false,
enableKeyboardInput: false, enableKeyboardInput: false,
@ -7317,7 +7329,7 @@ class XhomeInterceptor {
XhomeInterceptor.consoleAddrs = {}; XhomeInterceptor.consoleAddrs = {};
for (let pair of pairs) { for (let pair of pairs) {
let [keyAddr, keyPort] = pair; let [keyAddr, keyPort] = pair;
if (serverDetails[keyAddr]) { if (keyAddr && keyPort && serverDetails[keyAddr]) {
let port = serverDetails[keyPort], ports = new Set; let port = serverDetails[keyPort], ports = new Set;
port && ports.add(port), ports.add(9002), XhomeInterceptor.consoleAddrs[serverDetails[keyAddr]] = Array.from(ports); port && ports.add(port), ports.add(9002), XhomeInterceptor.consoleAddrs[serverDetails[keyAddr]] = Array.from(ports);
} }
@ -7836,7 +7848,7 @@ class XcloudInterceptor {
let PREF_STREAM_TARGET_RESOLUTION = getPref("stream.video.resolution"), PREF_STREAM_PREFERRED_LOCALE = getPref("stream.locale"), url = typeof request === "string" ? request : request.url, parsedUrl = new URL(url), badgeRegion = parsedUrl.host.split(".", 1)[0]; let PREF_STREAM_TARGET_RESOLUTION = getPref("stream.video.resolution"), PREF_STREAM_PREFERRED_LOCALE = getPref("stream.locale"), url = typeof request === "string" ? request : request.url, parsedUrl = new URL(url), badgeRegion = parsedUrl.host.split(".", 1)[0];
for (let regionName in STATES.serverRegions) { for (let regionName in STATES.serverRegions) {
let region = STATES.serverRegions[regionName]; let region = STATES.serverRegions[regionName];
if (parsedUrl.origin == region.baseUri) { if (region && parsedUrl.origin === region.baseUri) {
badgeRegion = regionName; badgeRegion = regionName;
break; break;
} }
@ -8814,7 +8826,7 @@ class XcloudApi {
async getTitleInfo(id) { async getTitleInfo(id) {
if (id in this.CACHE_TITLES) return this.CACHE_TITLES[id]; if (id in this.CACHE_TITLES) return this.CACHE_TITLES[id];
let baseUri = STATES.selectedRegion.baseUri; let baseUri = STATES.selectedRegion.baseUri;
if (!baseUri || !STATES.gsToken) return null; if (!baseUri || !STATES.gsToken) return;
let json; let json;
try { try {
json = (await (await NATIVE_FETCH(`${baseUri}/v2/titles`, { json = (await (await NATIVE_FETCH(`${baseUri}/v2/titles`, {
@ -9048,7 +9060,7 @@ class XboxApi {
let url = `https://displaycatalog.mp.microsoft.com/v7.0/products/lookup?market=US&languages=en&value=${xboxTitleId}&alternateId=XboxTitleId&fieldsTemplate=browse`, productTitle = (await (await NATIVE_FETCH(url)).json()).Products[0].LocalizedProperties[0].ProductTitle; let url = `https://displaycatalog.mp.microsoft.com/v7.0/products/lookup?market=US&languages=en&value=${xboxTitleId}&alternateId=XboxTitleId&fieldsTemplate=browse`, productTitle = (await (await NATIVE_FETCH(url)).json()).Products[0].LocalizedProperties[0].ProductTitle;
return XboxApi.CACHED_TITLES[xboxTitleId] = productTitle, productTitle; return XboxApi.CACHED_TITLES[xboxTitleId] = productTitle, productTitle;
} catch (e) {} } catch (e) {}
return null; return;
} }
} }
class RootDialogObserver { class RootDialogObserver {

View File

@ -1,4 +1,4 @@
import { compressCss, isFullVersion } from "@macros/build" with {type: "macro"}; import { compressCss, isFullVersion } from "@macros/build" with { type: "macro" };
import "@utils/global"; import "@utils/global";
import { BxEvent } from "@utils/bx-event"; import { BxEvent } from "@utils/bx-event";
@ -199,7 +199,7 @@ window.addEventListener(BxEvent.XCLOUD_SERVERS_UNAVAILABLE, e => {
if ($unsupportedPage) { if ($unsupportedPage) {
SettingsDialog.getInstance().show(); SettingsDialog.getInstance().show();
} }
}, {once: true}); }, { once: true });
window.addEventListener(BxEvent.XCLOUD_SERVERS_READY, e => { window.addEventListener(BxEvent.XCLOUD_SERVERS_READY, e => {
STATES.isSignedIn = true; STATES.isSignedIn = true;

View File

@ -3,8 +3,8 @@ import { ShortcutHandler } from "@/utils/shortcut-handler";
export class ControllerShortcut { export class ControllerShortcut {
private static buttonsCache: {[key: string]: boolean[]} = {}; private static buttonsCache: { [key: string]: boolean[] } = {};
private static buttonsStatus: {[key: string]: boolean[]} = {}; private static buttonsStatus: { [key: string]: boolean[] } = {};
static reset(index: number) { static reset(index: number) {
ControllerShortcut.buttonsCache[index] = []; ControllerShortcut.buttonsCache[index] = [];

View File

@ -47,8 +47,8 @@ export class GameBar {
const position = getPref<GameBarPosition>(PrefKey.GAME_BAR_POSITION); const position = getPref<GameBarPosition>(PrefKey.GAME_BAR_POSITION);
const $gameBar = CE('div', {id: 'bx-game-bar', class: 'bx-gone', 'data-position': position}, const $gameBar = CE('div', { id: 'bx-game-bar', class: 'bx-gone', 'data-position': position },
$container = CE('div', {class: 'bx-game-bar-container bx-offscreen'}), $container = CE('div', { class: 'bx-game-bar-container bx-offscreen' }),
createSvgIcon(position === 'bottom-left' ? BxIcon.CARET_RIGHT : BxIcon.CARET_LEFT), createSvgIcon(position === 'bottom-left' ? BxIcon.CARET_RIGHT : BxIcon.CARET_LEFT),
); );

View File

@ -4,7 +4,7 @@ import { t } from "@utils/translation";
import { STATES } from "@utils/global"; import { STATES } from "@utils/global";
import { PrefKey } from "@/enums/pref-keys"; import { PrefKey } from "@/enums/pref-keys";
import { getPref } from "@/utils/settings-storages/global-settings-storage"; import { getPref } from "@/utils/settings-storages/global-settings-storage";
import { compressCss } from "@macros/build" with {type: "macro"}; import { compressCss } from "@macros/build" with { type: "macro" };
import { LoadingScreenRocket } from "@/enums/pref-values"; import { LoadingScreenRocket } from "@/enums/pref-values";
export class LoadingScreen { export class LoadingScreen {

View File

@ -95,7 +95,7 @@ export class KeyHelper {
const tmp = str.split(':'); const tmp = str.split(':');
const code = tmp[0] as KeyEventInfo['code']; const code = tmp[0] as KeyEventInfo['code'];
const modifiers = parseInt(tmp[1]); const modifiers = parseInt(tmp[1] as string);
return { return {
code, code,

View File

@ -1,4 +1,4 @@
import { isFullVersion } from "@macros/build" with {type: "macro"}; import { isFullVersion } from "@macros/build" with { type: "macro" };
import { MkbPresetKey, MouseConstant, MouseMapTo, WheelCode } from "@/enums/mkb"; import { MkbPresetKey, MouseConstant, MouseMapTo, WheelCode } from "@/enums/mkb";
import { BxEvent } from "@utils/bx-event"; import { BxEvent } from "@utils/bx-event";
@ -16,6 +16,8 @@ import { getPref } from "@/utils/settings-storages/global-settings-storage";
import { GamepadKey, GamepadStick } from "@/enums/gamepad"; import { GamepadKey, GamepadStick } from "@/enums/gamepad";
import { MkbPopup } from "./mkb-popup"; import { MkbPopup } from "./mkb-popup";
import type { MkbConvertedPresetData } from "@/types/presets"; import type { MkbConvertedPresetData } from "@/types/presets";
import { StreamSettings } from "@/utils/stream-settings";
import { ShortcutAction } from "@/enums/shortcut-actions";
const PointerToMouseButton = { const PointerToMouseButton = {
1: 0, 1: 0,
@ -168,7 +170,7 @@ export class EmulatedMkbHandler extends MkbHandler {
private popup: MkbPopup; private popup: MkbPopup;
private STICK_MAP: {[key in GamepadKey]?: [GamepadKey[], number, number]} = { private STICK_MAP: { [key in GamepadKey]?: [GamepadKey[], number, number] } = {
[GamepadKey.LS_LEFT]: [this.LEFT_STICK_X, 0, -1], [GamepadKey.LS_LEFT]: [this.LEFT_STICK_X, 0, -1],
[GamepadKey.LS_RIGHT]: [this.LEFT_STICK_X, 0, 1], [GamepadKey.LS_RIGHT]: [this.LEFT_STICK_X, 0, 1],
[GamepadKey.LS_UP]: [this.LEFT_STICK_Y, 1, -1], [GamepadKey.LS_UP]: [this.LEFT_STICK_Y, 1, -1],
@ -529,7 +531,12 @@ export class EmulatedMkbHandler extends MkbHandler {
MkbPopup.getInstance().reset(); MkbPopup.getInstance().reset();
if (AppInterface) { if (AppInterface) {
Toast.show(t('press-key-to-toggle-mkb', {key: `<b>F8</b>`}), t('virtual-controller'), {html: true}); const shortcutKey = StreamSettings.findKeyboardShortcut(ShortcutAction.MKB_TOGGLE);
if (shortcutKey) {
const msg = t('press-key-to-toggle-mkb', { key: `<b>${KeyHelper.codeToKeyName(shortcutKey)}</b>` });
Toast.show(msg, t('native-mkb'), { html: true });
}
this.waitForMouseData(false); this.waitForMouseData(false);
} else { } else {
this.waitForMouseData(true); this.waitForMouseData(true);
@ -627,7 +634,7 @@ export class EmulatedMkbHandler extends MkbHandler {
this.waitForMouseData(true); this.waitForMouseData(true);
this.mouseDataProvider?.stop(); this.mouseDataProvider?.stop();
// Toast.show(t('virtual-controller'), t('disabled'), {instant: true}); // Toast.show(t('virtual-controller'), t('disabled'), { instant: true });
} }
static setupEvents() { static setupEvents() {

View File

@ -182,7 +182,7 @@ export class NativeMkbHandler extends MkbHandler {
window.BX_EXPOSED.stopTakRendering = true; window.BX_EXPOSED.stopTakRendering = true;
this.waitForMouseData(false); this.waitForMouseData(false);
Toast.show(t('native-mkb'), t('enabled'), {instant: true}); Toast.show(t('native-mkb'), t('enabled'), { instant: true });
} }
stop() { stop() {

View File

@ -480,6 +480,10 @@ BxEvent.dispatch(window, BxEvent.XCLOUD_POLLING_MODE_CHANGED);
// Get param name // Get param name
const params = str.substring(index, backetIndex).match(/\(([^)]+)\)/)![1]; const params = str.substring(index, backetIndex).match(/\(([^)]+)\)/)![1];
if (!params) {
return false;
}
const titleInfoVar = params.split(',')[0]; const titleInfoVar = params.split(',')[0];
const newCode = ` const newCode = `
@ -502,6 +506,10 @@ BxLogger.info('patchXcloudTitleInfo', ${titleInfoVar});
// Get param name // Get param name
const params = str.substring(index, backetIndex).match(/\(([^)]+)\)/)![1]; const params = str.substring(index, backetIndex).match(/\(([^)]+)\)/)![1];
if (!params) {
return false;
}
const configsVar = params.split(',')[1]; const configsVar = params.split(',')[1];
const newCode = ` const newCode = `

View File

@ -1 +1 @@
e && BxEvent.dispatch(window, BxEvent.NAVIGATION_FOCUS_CHANGED, {element: e}); e && BxEvent.dispatch(window, BxEvent.NAVIGATION_FOCUS_CHANGED, { element: e });

View File

@ -204,7 +204,7 @@ export class RemotePlayManager {
} }
if (this.consoles.length === 0) { if (this.consoles.length === 0) {
Toast.show(t('no-consoles-found'), '', {instant: true}); Toast.show(t('no-consoles-found'), '', { instant: true });
return; return;
} }

View File

@ -21,7 +21,7 @@ export class MicrophoneShortcut {
try { try {
window.BX_EXPOSED.streamSession.tryEnableChatAsync(enableMic); window.BX_EXPOSED.streamSession.tryEnableChatAsync(enableMic);
showToast && Toast.show(t('microphone'), t(enableMic ? 'unmuted': 'muted'), {instant: true}); showToast && Toast.show(t('microphone'), t(enableMic ? 'unmuted': 'muted'), { instant: true });
return enableMic; return enableMic;
} catch (e) { } catch (e) {

View File

@ -37,7 +37,7 @@ export class SoundShortcut {
SoundShortcut.setGainNodeVolume(newValue); SoundShortcut.setGainNodeVolume(newValue);
// Show toast // Show toast
Toast.show(`${t('stream')} ${t('volume')}`, newValue + '%', {instant: true}); Toast.show(`${t('stream')} ${t('volume')}`, newValue + '%', { instant: true });
return newValue; return newValue;
} }
@ -69,7 +69,7 @@ export class SoundShortcut {
} }
SoundShortcut.setGainNodeVolume(targetValue); SoundShortcut.setGainNodeVolume(targetValue);
Toast.show(`${t('stream')} ${t('volume')}`, status, {instant: true}); Toast.show(`${t('stream')} ${t('volume')}`, status, { instant: true });
BxEvent.dispatch(window, BxEvent.SPEAKER_STATE_CHANGED, { BxEvent.dispatch(window, BxEvent.SPEAKER_STATE_CHANGED, {
speakerState: targetValue === 0 ? SpeakerState.MUTED : SpeakerState.ENABLED, speakerState: targetValue === 0 ? SpeakerState.MUTED : SpeakerState.ENABLED,
@ -82,7 +82,7 @@ export class SoundShortcut {
$media.muted = !$media.muted; $media.muted = !$media.muted;
const status = $media.muted ? t('muted') : t('unmuted'); const status = $media.muted ? t('muted') : t('unmuted');
Toast.show(`${t('stream')} ${t('volume')}`, status, {instant: true}); Toast.show(`${t('stream')} ${t('volume')}`, status, { instant: true });
BxEvent.dispatch(window, BxEvent.SPEAKER_STATE_CHANGED, { BxEvent.dispatch(window, BxEvent.SPEAKER_STATE_CHANGED, {
speakerState: $media.muted ? SpeakerState.MUTED : SpeakerState.ENABLED, speakerState: $media.muted ? SpeakerState.MUTED : SpeakerState.ENABLED,

View File

@ -1,4 +1,4 @@
import { isFullVersion } from "@macros/build" with {type: "macro"}; import { isFullVersion } from "@macros/build" with { type: "macro" };
import { CE } from "@/utils/html"; import { CE } from "@/utils/html";
import { WebGL2Player } from "./player/webgl2-player"; import { WebGL2Player } from "./player/webgl2-player";
@ -52,7 +52,7 @@ export class StreamPlayer {
id: 'bx-video-filters', id: 'bx-video-filters',
xmlns: 'http://www.w3.org/2000/svg', xmlns: 'http://www.w3.org/2000/svg',
class: 'bx-gone', class: 'bx-gone',
}, CE('defs', {xmlns: 'http://www.w3.org/2000/svg'}, }, CE('defs', { xmlns: 'http://www.w3.org/2000/svg' },
CE('filter', { CE('filter', {
id: 'bx-filter-usm', id: 'bx-filter-usm',
xmlns: 'http://www.w3.org/2000/svg', xmlns: 'http://www.w3.org/2000/svg',

View File

@ -1,4 +1,4 @@
import { isLiteVersion } from "@macros/build" with {type: "macro"}; import { isLiteVersion } from "@macros/build" with { type: "macro" };
import { t } from "@utils/translation"; import { t } from "@utils/translation";
import { BxEvent } from "@utils/bx-event"; import { BxEvent } from "@utils/bx-event";
@ -118,9 +118,9 @@ export class StreamBadges {
return $badge; return $badge;
} }
$badge = CE('div', {class: 'bx-badge', title: badgeInfo.name}, $badge = CE('div', { class: 'bx-badge', title: badgeInfo.name },
CE('span', {class: 'bx-badge-name'}, createSvgIcon(badgeInfo.icon)), CE('span', { class: 'bx-badge-name' }, createSvgIcon(badgeInfo.icon)),
CE('span', {class: 'bx-badge-value', style: `background-color: ${badgeInfo.color}`}, value), CE('span', { class: 'bx-badge-value', style: `background-color: ${badgeInfo.color}` }, value),
); );
if (name === StreamBadge.BATTERY) { if (name === StreamBadge.BATTERY) {
@ -219,7 +219,7 @@ export class StreamBadges {
this.serverInfo.audio ? this.badges.audio.$element : [StreamBadge.AUDIO, '?'], this.serverInfo.audio ? this.badges.audio.$element : [StreamBadge.AUDIO, '?'],
]; ];
const $container = CE('div', {class: 'bx-badges'}); const $container = CE('div', { class: 'bx-badges' });
for (const item of BADGES) { for (const item of BADGES) {
if (!item) { if (!item) {

View File

@ -209,7 +209,7 @@ export class StreamStats {
} }
private async render() { private async render() {
this.$container = CE('div', {class: 'bx-stats-bar bx-gone'}); this.$container = CE('div', { class: 'bx-stats-bar bx-gone' });
let statKey: keyof typeof this.stats; let statKey: keyof typeof this.stats;
for (statKey in this.stats) { for (statKey in this.stats) {

View File

@ -267,7 +267,7 @@ export class StreamUiHandler {
}; };
}); });
observer.observe($screen, {subtree: true, childList: true}); observer.observe($screen, { subtree: true, childList: true });
StreamUiHandler.observer = observer; StreamUiHandler.observer = observer;
} }
} }

View File

@ -233,13 +233,13 @@ export class TouchController {
let html = false; let html = false;
if (layout.author) { if (layout.author) {
const author = `<b>${escapeHtml(layout.author)}</b>`; const author = `<b>${escapeHtml(layout.author)}</b>`;
msg = t('touch-control-layout-by', {name: author}); msg = t('touch-control-layout-by', { name: author });
html = true; html = true;
} else { } else {
msg = t('touch-control-layout'); msg = t('touch-control-layout');
} }
layoutChanged && Toast.show(msg, layout.name, {html: html}); layoutChanged && Toast.show(msg, layout.name, { html });
window.setTimeout(() => { window.setTimeout(() => {
// Show gyroscope control in the "More options" dialog if this layout has gyroscope // Show gyroscope control in the "More options" dialog if this layout has gyroscope

View File

@ -154,7 +154,7 @@ export class NavigationDialogManager {
private constructor() { private constructor() {
BxLogger.info(this.LOG_TAG, 'constructor()'); BxLogger.info(this.LOG_TAG, 'constructor()');
this.$overlay = CE('div', {class: 'bx-navigation-dialog-overlay bx-gone'}); this.$overlay = CE('div', { class: 'bx-navigation-dialog-overlay bx-gone' });
this.$overlay.addEventListener('click', e => { this.$overlay.addEventListener('click', e => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -164,7 +164,7 @@ export class NavigationDialogManager {
document.documentElement.appendChild(this.$overlay); document.documentElement.appendChild(this.$overlay);
this.$container = CE('div', {class: 'bx-navigation-dialog bx-gone'}); this.$container = CE('div', { class: 'bx-navigation-dialog bx-gone' });
document.documentElement.appendChild(this.$container); document.documentElement.appendChild(this.$container);
// Hide dialog when the Guide menu is shown // Hide dialog when the Guide menu is shown
@ -186,7 +186,7 @@ export class NavigationDialogManager {
// Find un-calculated <select> elements // Find un-calculated <select> elements
this.calculateSelectBoxes($dialog); this.calculateSelectBoxes($dialog);
}); });
observer.observe(this.$container, {childList: true}); observer.observe(this.$container, { childList: true });
} }
} }
@ -260,7 +260,7 @@ export class NavigationDialogManager {
} else if (keyCode === 'Enter' || keyCode === 'NumpadEnter' || keyCode === 'Space') { } else if (keyCode === 'Enter' || keyCode === 'NumpadEnter' || keyCode === 'Space') {
if (!($target instanceof HTMLInputElement && $target.type === 'text')) { if (!($target instanceof HTMLInputElement && $target.type === 'text')) {
handled = true; handled = true;
$target.dispatchEvent(new MouseEvent('click', {bubbles: true})); $target.dispatchEvent(new MouseEvent('click', { bubbles: true }));
} }
} else if (keyCode === 'Escape') { } else if (keyCode === 'Escape') {
handled = true; handled = true;
@ -393,7 +393,7 @@ export class NavigationDialogManager {
} }
if (releasedButton === GamepadKey.A) { if (releasedButton === GamepadKey.A) {
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent('click', {bubbles: true})); document.activeElement?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
return; return;
} else if (releasedButton === GamepadKey.B) { } else if (releasedButton === GamepadKey.B) {
this.hide(); this.hide();

View File

@ -95,8 +95,8 @@ export class ControllerShortcutsManagerDialog extends BaseProfileManagerDialog<C
}; };
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
fragment.appendChild(CE('p', {class: 'bx-shortcut-note'}, fragment.appendChild(CE('p', { class: 'bx-shortcut-note' },
CE('span', {class: 'bx-prompt'}, PrompFont.HOME), CE('span', { class: 'bx-prompt' }, PrompFont.HOME),
': ' + t('controller-shortcuts-xbox-note'), ': ' + t('controller-shortcuts-xbox-note'),
)); ));
@ -109,8 +109,8 @@ export class ControllerShortcutsManagerDialog extends BaseProfileManagerDialog<C
orientation: 'horizontal', orientation: 'horizontal',
}, },
}); });
const $label = CE('label', {class: 'bx-prompt'}, `${PrompFont.HOME}${prompt}`); const $label = CE('label', { class: 'bx-prompt' }, `${PrompFont.HOME}${prompt}`);
const $div = CE('div', {class: 'bx-shortcut-actions'}); const $div = CE('div', { class: 'bx-shortcut-actions' });
let $fakeSelect: HTMLSelectElement | null = null; let $fakeSelect: HTMLSelectElement | null = null;
if (!PREF_CONTROLLER_FRIENDLY_UI) { if (!PREF_CONTROLLER_FRIENDLY_UI) {

View File

@ -32,7 +32,7 @@ export class RemotePlayDialog extends NavigationDialog {
} }
private setupDialog() { private setupDialog() {
const $fragment = CE('div', {'class': 'bx-remote-play-container'}); const $fragment = CE('div', { class: 'bx-remote-play-container' });
const $settingNote = CE('p', {}); const $settingNote = CE('p', {});
@ -69,13 +69,13 @@ export class RemotePlayDialog extends NavigationDialog {
const consoles = manager.getConsoles(); const consoles = manager.getConsoles();
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', {},
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', ''))
), ),
CE('div', {class: 'bx-remote-play-power-state'}, this.STATE_LABELS[con.powerState]), CE('div', { class: 'bx-remote-play-power-state' }, this.STATE_LABELS[con.powerState]),
), ),
// Connect button // Connect button

View File

@ -1,4 +1,4 @@
import { isFullVersion } from "@macros/build" with {type: "macro"}; import { isFullVersion } from "@macros/build" with { type: "macro" };
import { limitVideoPlayerFps, onChangeVideoPlayerType, updateVideoPlayer } from "@/modules/stream/stream-settings-utils"; import { limitVideoPlayerFps, onChangeVideoPlayerType, updateVideoPlayer } from "@/modules/stream/stream-settings-utils";
import { ButtonStyle, CE, createButton, createSettingRow, createSvgIcon, escapeCssSelector, type BxButtonOptions } from "@/utils/html"; import { ButtonStyle, CE, createButton, createSettingRow, createSvgIcon, escapeCssSelector, type BxButtonOptions } from "@/utils/html";
@ -39,7 +39,7 @@ type SettingTabSectionItem = Partial<{
note: string | (() => HTMLElement); note: string | (() => HTMLElement);
experimental: string; experimental: string;
content: HTMLElement | (() => HTMLElement); content: HTMLElement | (() => HTMLElement);
options: {[key: string]: string}; options: { [key: string]: string };
unsupported: boolean; unsupported: boolean;
unsupportedNote: string; unsupportedNote: string;
onChange: (e: any, value: number) => void; onChange: (e: any, value: number) => void;
@ -112,7 +112,7 @@ export class SettingsDialog extends NavigationDialog {
if (!SCRIPT_VERSION.includes('beta') && PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) { if (!SCRIPT_VERSION.includes('beta') && PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {
// Show new version button // Show new version button
const opts = { const opts = {
label: '🌟 ' + t('new-version-available', {version: PREF_LATEST_VERSION}), label: '🌟 ' + t('new-version-available', { version: PREF_LATEST_VERSION }),
style: ButtonStyle.PRIMARY | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_WIDTH, style: ButtonStyle.PRIMARY | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_WIDTH,
} as BxButtonOptions; } as BxButtonOptions;
@ -549,7 +549,7 @@ export class SettingsDialog extends NavigationDialog {
// If there is no custom layouts -> show only Default option // If there is no custom layouts -> show only Default option
if (!customLayouts) { if (!customLayouts) {
$elm.appendChild(CE('option', {value: ''}, t('default'))); $elm.appendChild(CE('option', { value: '' }, t('default')));
$elm.value = ''; $elm.value = '';
$elm.dispatchEvent(new Event('input')); $elm.dispatchEvent(new Event('input'));
return; return;
@ -567,7 +567,7 @@ export class SettingsDialog extends NavigationDialog {
name = layout.name; name = layout.name;
} }
const $option = CE('option', {value: key}, name); const $option = CE('option', { value: key }, name);
$fragment.appendChild($option); $fragment.appendChild($option);
} }
@ -859,7 +859,7 @@ export class SettingsDialog extends NavigationDialog {
setting.options[value] = label; setting.options[value] = label;
const $option = CE<HTMLOptionElement>('option', {value: value}, label); const $option = CE<HTMLOptionElement>('option', { value }, label);
const continent = continents[region.contintent]; const continent = continents[region.contintent];
if (!continent.children) { if (!continent.children) {
continent.children = []; continent.children = [];
@ -1002,9 +1002,9 @@ export class SettingsDialog extends NavigationDialog {
let $note; let $note;
if (unsupportedNote) { if (unsupportedNote) {
$note = CE('div', {class: 'bx-settings-dialog-note'}, unsupportedNote); $note = CE('div', { class: 'bx-settings-dialog-note' }, unsupportedNote);
} else if (note) { } else if (note) {
$note = CE('div', {class: 'bx-settings-dialog-note'}, note); $note = CE('div', { class: 'bx-settings-dialog-note' }, note);
} }
const $row = createSettingRow(label, !prefDefinition?.unsupported && $control, { const $row = createSettingRow(label, !prefDefinition?.unsupported && $control, {
@ -1083,7 +1083,7 @@ export class SettingsDialog extends NavigationDialog {
// Add note // Add note
if (section.unsupportedNote) { if (section.unsupportedNote) {
const $note = CE('b', {class: 'bx-note-unsupported'}, section.unsupportedNote); const $note = CE('b', { class: 'bx-note-unsupported' }, section.unsupportedNote);
$tabContent.appendChild($note); $tabContent.appendChild($note);
} }

View File

@ -65,7 +65,7 @@ export class ControllerExtraSettings extends HTMLElement {
CE('div', { class: 'bx-controller-extra-wrapper' }, CE('div', { class: 'bx-controller-extra-wrapper' },
$selectControllers, $selectControllers,
CE('div', {class: 'bx-sub-content-box'}, CE('div', { class: 'bx-sub-content-box' },
createSettingRow( createSettingRow(
t('controller-shortcuts-in-game'), t('controller-shortcuts-in-game'),
CE('div', { CE('div', {

View File

@ -91,12 +91,12 @@ export class SuggestionsSetting {
SuggestionsSetting.generateDefaultSuggestedSettings.call(this); SuggestionsSetting.generateDefaultSuggestedSettings.call(this);
// Start rendering // Start rendering
const $suggestedSettings = CE('div', {class: 'bx-suggest-wrapper'}); const $suggestedSettings = CE('div', { class: 'bx-suggest-wrapper' });
const $select = CE<HTMLSelectElement>('select', {}, const $select = CE<HTMLSelectElement>('select', {},
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')),
CE('option', {value: 'lowest'}, t('lowest-quality')), CE('option', { value: 'lowest' }, t('lowest-quality')),
); );
$select.addEventListener('input', e => { $select.addEventListener('input', e => {
const profile = $select.value as SuggestedSettingProfile; const profile = $select.value as SuggestedSettingProfile;
@ -107,13 +107,13 @@ export class SuggestionsSetting {
let note: HTMLElement | string | undefined; let note: HTMLElement | string | undefined;
if (profile === 'recommended') { if (profile === 'recommended') {
note = t('recommended-settings-for-device', {device: recommendedDevice}); note = t('recommended-settings-for-device', { device: recommendedDevice });
} else if (profile === 'highest') { } else if (profile === 'highest') {
// Add note for "Highest quality" profile // Add note for "Highest quality" profile
note = '⚠️ ' + t('highest-quality-note'); note = '⚠️ ' + t('highest-quality-note');
} }
note && fragment.appendChild(CE('div', {class: 'bx-suggest-note'}, note)); note && fragment.appendChild(CE('div', { class: 'bx-suggest-note' }, note));
const settings = this.suggestedSettings[profile]; const settings = this.suggestedSettings[profile];
let prefKey: PrefKey; let prefKey: PrefKey;
@ -265,7 +265,7 @@ export class SuggestionsSetting {
// Get recommended settings from GitHub // Get recommended settings from GitHub
try { try {
let {brand, board, model} = androidInfo!; let { brand, board, model } = androidInfo!;
brand = normalize(brand); brand = normalize(brand);
board = normalize(board); board = normalize(board);
model = normalize(model); model = normalize(model);

View File

@ -28,7 +28,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', {}, secondsToHms(totalWaitTime)), CE('span', {}, secondsToHms(totalWaitTime)),
); );

View File

@ -1,4 +1,4 @@
import { isFullVersion } from "@macros/build" with {type: "macro"}; import { isFullVersion } from "@macros/build" with { type: "macro" };
import { BxEvent } from "@/utils/bx-event"; import { BxEvent } from "@/utils/bx-event";
import { AppInterface, STATES } from "@/utils/global"; import { AppInterface, STATES } from "@/utils/global";
@ -42,7 +42,7 @@ export class GuideMenu {
// Wait until the Guide dialog is closed // Wait until the Guide dialog is closed
window.addEventListener(BxEvent.XCLOUD_DIALOG_DISMISSED, e => { window.addEventListener(BxEvent.XCLOUD_DIALOG_DISMISSED, e => {
setTimeout(() => SettingsDialog.getInstance().show(), 50); setTimeout(() => SettingsDialog.getInstance().show(), 50);
}, {once: true}); }, { once: true });
// Close all xCloud's dialogs // Close all xCloud's dialogs
this.closeGuideMenu(); this.closeGuideMenu();
@ -218,7 +218,7 @@ export class GuideMenu {
for (index = 0; ($elm = $elm?.previousElementSibling); index++); for (index = 0; ($elm = $elm?.previousElementSibling); index++);
if (index === 0) { if (index === 0) {
BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, {where: GuideMenuTab.HOME}); BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, { where: GuideMenuTab.HOME });
} }
} }
} }

View File

@ -92,7 +92,7 @@ export class HeaderSection {
this.timeoutId && clearTimeout(this.timeoutId); this.timeoutId && clearTimeout(this.timeoutId);
this.timeoutId = window.setTimeout(this.checkHeader, 2000); this.timeoutId = window.setTimeout(this.checkHeader, 2000);
}); });
this.observer.observe($root, {subtree: true, childList: true}); this.observer.observe($root, { subtree: true, childList: true });
this.checkHeader(); this.checkHeader();
} }

View File

@ -9,7 +9,7 @@ declare global {
interface Window { interface Window {
AppInterface: any; AppInterface: any;
BX_FLAGS?: BxFlags; BX_FLAGS?: BxFlags;
BX_CE: (elmName: string, props: {[index: string]: any}={}) => HTMLElement; BX_CE: (elmName: string, props: { [index: string]: any }={}) => HTMLElement;
BX_EXPOSED: typeof BxExposed & Partial<{ BX_EXPOSED: typeof BxExposed & Partial<{
shouldShowSensorControls: boolean; shouldShowSensorControls: boolean;
stopTakRendering: boolean; stopTakRendering: boolean;

View File

@ -1,8 +1,8 @@
export type PreferenceSetting = { export type PreferenceSetting = {
default: any; default: any;
optionsGroup?: string; optionsGroup?: string;
options?: {[index: string]: string}; options?: { [index: string]: string };
multipleOptions?: {[index: string]: string}; multipleOptions?: { [index: string]: string };
unsupported?: boolean; unsupported?: boolean;
unsupportedNote?: string | (() => HTMLElement); unsupportedNote?: string | (() => HTMLElement);
note?: string | (() => HTMLElement); note?: string | (() => HTMLElement);
@ -17,4 +17,4 @@ export type PreferenceSetting = {
label?: string; label?: string;
}; };
export type PreferenceSettings = {[index in PrefKey]: PreferenceSetting}; export type PreferenceSettings = { [index in PrefKey]: PreferenceSetting };

View File

@ -65,7 +65,7 @@ type KeyboardShortcutConvertedPresetData = KeyboardShortcutPresetData & {
interface AllPresets<T extends PresetRecord> { interface AllPresets<T extends PresetRecord> {
default: Array<number>, default: Array<number>,
custom: Array<number>, custom: Array<number>,
data: {[key: string]: T}, data: { [key: string]: T },
}; };
interface AllPresetsData<T extends PresetRecord> { interface AllPresetsData<T extends PresetRecord> {

View File

@ -1,4 +1,4 @@
import { isFullVersion } from "@macros/build" with {type: "macro"}; import { isFullVersion } from "@macros/build" with { type: "macro" };
import { ControllerShortcut } from "@/modules/controller-shortcut"; import { ControllerShortcut } from "@/modules/controller-shortcut";
import { BxEvent } from "@utils/bx-event"; import { BxEvent } from "@utils/bx-event";

View File

@ -8,7 +8,7 @@ export type BxFlags = {
SafariWorkaround: boolean; SafariWorkaround: boolean;
ForceNativeMkbTitles: string[]; ForceNativeMkbTitles: string[];
FeatureGates: {[key: string]: boolean} | null, FeatureGates: { [key: string]: boolean } | null,
DeviceInfo: { DeviceInfo: {
deviceType: 'android' | 'android-tv' | 'android-handheld' | 'webos' | 'unknown', deviceType: 'android' | 'android-tv' | 'android-handheld' | 'webos' | 'unknown',

View File

@ -1,5 +1,5 @@
import { CE } from "@utils/html"; import { CE } from "@utils/html";
import { compressCss, renderStylus } from "@macros/build" with {type: "macro"}; import { compressCss, renderStylus } from "@macros/build" with { type: "macro" };
import { UiSection } from "@/enums/pref-values"; import { UiSection } from "@/enums/pref-values";
import { PrefKey } from "@/enums/pref-keys"; import { PrefKey } from "@/enums/pref-keys";
import { getPref } from "./settings-storages/global-settings-storage"; import { getPref } from "./settings-storages/global-settings-storage";

View File

@ -3,7 +3,7 @@ import { BX_FLAGS } from "./bx-flags";
import { getPref } from "./settings-storages/global-settings-storage"; import { getPref } from "./settings-storages/global-settings-storage";
import { NativeMkbMode } from "@/enums/pref-values"; import { NativeMkbMode } from "@/enums/pref-values";
export let FeatureGates: {[key: string]: boolean} = { export let FeatureGates: { [key: string]: boolean } = {
PwaPrompt: false, PwaPrompt: false,
EnableWifiWarnings: false, EnableWifiWarnings: false,
EnableUpdateRequiredPage: false, EnableUpdateRequiredPage: false,

View File

@ -31,7 +31,7 @@ export function showGamepadToast(gamepad: Gamepad) {
status = t('disconnected'); status = t('disconnected');
} }
Toast.show(text, status, {instant: false}); Toast.show(text, status, { instant: false });
} }
export function getUniqueGamepadNames() { export function getUniqueGamepadNames() {

View File

@ -47,7 +47,7 @@ export const STATES: BxStates = {
pointerServerPort: 9269, pointerServerPort: 9269,
}; };
export const STORAGE: {[key: string]: BaseSettingsStore} = {}; export const STORAGE: { [key: string]: BaseSettingsStore } = {};
export function deepClone(obj: any): typeof obj | {} { export function deepClone(obj: any): typeof obj | {} {
if (!obj) { if (!obj) {

View File

@ -47,7 +47,7 @@ export type BxButtonOptions = Partial<{
disabled: boolean; disabled: boolean;
onClick: EventListener; onClick: EventListener;
tabIndex: number; tabIndex: number;
attributes: {[key: string]: any}, attributes: { [key: string]: any },
}>; }>;
export type SettingsRowOptions = Partial<{ export type SettingsRowOptions = Partial<{
@ -186,7 +186,7 @@ export function createSettingRow(label: string, $control: HTMLElement | false |
let $label: HTMLElement; let $label: HTMLElement;
const $row = CE<HTMLLabelElement>('label', { class: 'bx-settings-row' }, const $row = CE<HTMLLabelElement>('label', { class: 'bx-settings-row' },
$label = CE('span', {class: 'bx-settings-label'}, $label = CE('span', { class: 'bx-settings-label' },
label, label,
options.$note, options.$note,
), ),

View File

@ -55,11 +55,11 @@ export class BaseLocalTable<T extends BaseRecord> {
return this.call(table.get.bind(table), ...arguments); return this.call(table.get.bind(table), ...arguments);
} }
async getAll(): Promise<{[key: string]: T}> { async getAll(): Promise<{ [key: string]: T }> {
const table = await this.prepareTable(); const table = await this.prepareTable();
// @ts-ignore // @ts-ignore
const all = await (this.call(table.getAll.bind(table), ...arguments) as Promise<T[]>); const all = await (this.call(table.getAll.bind(table), ...arguments) as Promise<T[]>);
const results: {[key: string]: T} = {}; const results: { [key: string]: T } = {};
all.forEach(item => { all.forEach(item => {
results[item.id as T['id']] = item; results[item.id as T['id']] = item;

View File

@ -23,9 +23,13 @@ export class ControllerSettingsTable extends BaseLocalTable<ControllerSettingsRe
async getControllersData() { async getControllersData() {
const all = await this.getAll(); const all = await this.getAll();
const results: {[key: string]: ControllerSettingsRecord['data']} = {}; const results: { [key: string]: ControllerSettingsRecord['data'] } = {};
for (const key in all) { for (const key in all) {
if (!all[key]) {
continue;
}
const settings = all[key].data; const settings = all[key].data;
// Pre-calculate virabtionIntensity // Pre-calculate virabtionIntensity
settings.vibrationIntensity /= 100; settings.vibrationIntensity /= 100;

View File

@ -50,7 +50,7 @@ export function patchVideoApi() {
const $parent = this.parentElement!!; const $parent = this.parentElement!!;
// Video tag is stream player // Video tag is stream player
if (!this.src && $parent.dataset.testid === 'media-container') { if (!this.src && $parent.dataset.testid === 'media-container') {
this.addEventListener('loadedmetadata', showFunc, {once: true}); this.addEventListener('loadedmetadata', showFunc, { once: true });
} }
return nativePlay.apply(this); return nativePlay.apply(this);

View File

@ -1,4 +1,4 @@
import { isFullVersion } from "@macros/build" with {type: "macro"}; import { isFullVersion } from "@macros/build" with { type: "macro" };
import { BX_FLAGS, NATIVE_FETCH } from "@utils/bx-flags"; import { BX_FLAGS, NATIVE_FETCH } from "@utils/bx-flags";
import { TouchController } from "@modules/touch-controller"; import { TouchController } from "@modules/touch-controller";
@ -39,7 +39,7 @@ function clearAllLogs() {
clearDbLogs('XCloudAppLogs', 'logs'); clearDbLogs('XCloudAppLogs', 'logs');
} }
function updateIceCandidates(candidates: any, options: {preferIpv6Server: boolean, consoleAddrs?: RemotePlayConsoleAddresses}) { function updateIceCandidates(candidates: any, options: { preferIpv6Server: boolean, consoleAddrs?: RemotePlayConsoleAddresses }) {
const pattern = new RegExp(/a=candidate:(?<foundation>\d+) (?<component>\d+) UDP (?<priority>\d+) (?<ip>[^\s]+) (?<port>\d+) (?<the_rest>.*)/); const pattern = new RegExp(/a=candidate:(?<foundation>\d+) (?<component>\d+) UDP (?<priority>\d+) (?<ip>[^\s]+) (?<port>\d+) (?<the_rest>.*)/);
const lst = []; const lst = [];
@ -48,7 +48,7 @@ function updateIceCandidates(candidates: any, options: {preferIpv6Server: boolea
continue; continue;
} }
const groups: {[index: string]: string | number} = pattern.exec(item.candidate)!.groups!; const groups: { [index: string]: string | number } = pattern.exec(item.candidate)!.groups!;
lst.push(groups); lst.push(groups);
} }

View File

@ -89,7 +89,7 @@ export class RootDialogObserver {
} }
} }
}); });
observer.observe($root, {subtree: true, childList: true}); observer.observe($root, { subtree: true, childList: true });
} }
public static waitForRootDialog() { public static waitForRootDialog() {
@ -107,6 +107,6 @@ export class RootDialogObserver {
} }
}; };
}); });
observer.observe(document.documentElement, {subtree: true, childList: true}); observer.observe(document.documentElement, { subtree: true, childList: true });
} }
} }

View File

@ -20,7 +20,7 @@ export class ScreenshotManager {
this.$download = CE<HTMLAnchorElement>('a'); this.$download = CE<HTMLAnchorElement>('a');
this.$canvas = CE<HTMLCanvasElement>('canvas', {'class': 'bx-gone'}); this.$canvas = CE<HTMLCanvasElement>('canvas', { class: 'bx-gone' });
this.canvasContext = this.$canvas.getContext('2d', { this.canvasContext = this.$canvas.getContext('2d', {
alpha: false, alpha: false,
willReadFrequently: false, willReadFrequently: false,

View File

@ -41,7 +41,7 @@ export class SettingElement {
for (let value in setting.options) { for (let value in setting.options) {
const label = setting.options[value]; const label = setting.options[value];
const $option = CE<HTMLOptionElement>('option', {value: value}, label); const $option = CE<HTMLOptionElement>('option', { value }, label);
$parent.appendChild($option); $parent.appendChild($option);
} }
@ -75,7 +75,7 @@ export class SettingElement {
for (const value in setting.multipleOptions) { for (const value in setting.multipleOptions) {
const label = setting.multipleOptions[value]; const label = setting.multipleOptions[value];
const $option = CE<HTMLOptionElement>('option', {value: value}, label) as HTMLOptionElement; const $option = CE<HTMLOptionElement>('option', { value }, label) as HTMLOptionElement;
$option.selected = currentValue.indexOf(value) > -1; $option.selected = currentValue.indexOf(value) > -1;
$option.addEventListener('mousedown', function(e) { $option.addEventListener('mousedown', function(e) {
@ -111,7 +111,7 @@ export class SettingElement {
} }
private static renderCheckbox(key: string, setting: PreferenceSetting, currentValue: any, onChange: any) { private static renderCheckbox(key: string, setting: PreferenceSetting, currentValue: any, onChange: any) {
const $control = CE('input', {type: 'checkbox', tabindex: 0}) as HTMLInputElement; const $control = CE('input', { type: 'checkbox', tabindex: 0 }) as HTMLInputElement;
$control.checked = currentValue; $control.checked = currentValue;
onChange && $control.addEventListener('input', e => { onChange && $control.addEventListener('input', e => {

View File

@ -89,7 +89,7 @@ export class GlobalSettingsStorage extends BaseSettingsStorage {
}, },
[PrefKey.SERVER_REGION]: { [PrefKey.SERVER_REGION]: {
label: t('region'), label: t('region'),
note: CE('a', {target: '_blank', href: 'https://umap.openstreetmap.fr/en/map/xbox-cloud-gaming-servers_1135022'}, t('server-locations')), note: CE('a', { target: '_blank', href: 'https://umap.openstreetmap.fr/en/map/xbox-cloud-gaming-servers_1135022' }, t('server-locations')),
default: 'default', default: 'default',
}, },
[PrefKey.SERVER_BYPASS_RESTRICTION]: { [PrefKey.SERVER_BYPASS_RESTRICTION]: {

View File

@ -24,9 +24,9 @@ export class Toast {
private constructor() { private constructor() {
BxLogger.info(this.LOG_TAG, 'constructor()'); BxLogger.info(this.LOG_TAG, 'constructor()');
this.$wrapper = CE('div', {class: 'bx-toast bx-offscreen'}, this.$wrapper = CE('div', { class: 'bx-toast bx-offscreen' },
this.$msg = CE('span', {class: 'bx-toast-msg'}), this.$msg = CE('span', { class: 'bx-toast-msg' }),
this.$status = CE('span', {class: 'bx-toast-status'}), this.$status = CE('span', { class: 'bx-toast-status' }),
); );
this.$wrapper.addEventListener('transitionend', e => { this.$wrapper.addEventListener('transitionend', e => {

View File

@ -9,12 +9,12 @@ type UserAgentConfig = {
const SMART_TV_UNIQUE_ID = 'FC4A1DA2-711C-4E9C-BC7F-047AF8A672EA'; const SMART_TV_UNIQUE_ID = 'FC4A1DA2-711C-4E9C-BC7F-047AF8A672EA';
let CHROMIUM_VERSION = '123.0.0.0'; let CHROMIUM_VERSION = '125.0.0.0';
if (!!(window as any).chrome || window.navigator.userAgent.includes('Chrome')) { if (!!(window as any).chrome || window.navigator.userAgent.includes('Chrome')) {
// Get Chromium version in the original User-Agent value // Get Chromium version in the original User-Agent value
const match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/); const match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/);
if (match) { if (match) {
CHROMIUM_VERSION = match[1]; CHROMIUM_VERSION = match[1] as string;
} }
} }

View File

@ -102,11 +102,11 @@ export function roundToNearest(value: number, interval: number): number {
export async function copyToClipboard(text: string, showToast=true): Promise<boolean> { export async function copyToClipboard(text: string, showToast=true): Promise<boolean> {
try { try {
await navigator.clipboard.writeText(text); await navigator.clipboard.writeText(text);
showToast && Toast.show('Copied to clipboard', '', {instant: true}); showToast && Toast.show('Copied to clipboard', '', { instant: true });
return true; return true;
} catch (err) { } catch (err) {
console.error('Failed to copy: ', err); console.error('Failed to copy: ', err);
showToast && Toast.show('Failed to copy', '', {instant: true}); showToast && Toast.show('Failed to copy', '', { instant: true });
} }
return false; return false;
@ -128,10 +128,10 @@ export function parseDetailsPath(path: string) {
return; return;
} }
const titleSlug = matches.groups.titleSlug.replaceAll('\%' + '7C', '-'); const titleSlug = matches.groups.titleSlug!.replaceAll('\%' + '7C', '-');
const productId = matches.groups.productId; const productId = matches.groups.productId;
return {titleSlug, productId}; return { titleSlug, productId };
} }
export function clearAllData() { export function clearAllData() {

View File

@ -3,7 +3,7 @@ import { NATIVE_FETCH } from "./bx-flags"
export class XboxApi { export class XboxApi {
private static CACHED_TITLES: Record<string, string> = {}; private static CACHED_TITLES: Record<string, string> = {};
static async getProductTitle(xboxTitleId: number | string): Promise<string | null> { static async getProductTitle(xboxTitleId: number | string): Promise<string | undefined> {
xboxTitleId = xboxTitleId.toString(); xboxTitleId = xboxTitleId.toString();
if (XboxApi.CACHED_TITLES[xboxTitleId]) { if (XboxApi.CACHED_TITLES[xboxTitleId]) {
return XboxApi.CACHED_TITLES[xboxTitleId]; return XboxApi.CACHED_TITLES[xboxTitleId];
@ -20,6 +20,6 @@ export class XboxApi {
return productTitle; return productTitle;
} catch (e) {} } catch (e) {}
return null; return;
} }
} }

View File

@ -7,21 +7,21 @@ export class XcloudApi {
public static getInstance = () => XcloudApi.instance ?? (XcloudApi.instance = new XcloudApi()); public static getInstance = () => XcloudApi.instance ?? (XcloudApi.instance = new XcloudApi());
private readonly LOG_TAG = 'XcloudApi'; private readonly LOG_TAG = 'XcloudApi';
private CACHE_TITLES: {[key: string]: XcloudTitleInfo} = {}; private CACHE_TITLES: { [key: string]: XcloudTitleInfo } = {};
private CACHE_WAIT_TIME: {[key: string]: XcloudWaitTimeInfo} = {}; private CACHE_WAIT_TIME: { [key: string]: XcloudWaitTimeInfo } = {};
private constructor() { private constructor() {
BxLogger.info(this.LOG_TAG, 'constructor()'); BxLogger.info(this.LOG_TAG, 'constructor()');
} }
async getTitleInfo(id: string): Promise<XcloudTitleInfo | null> { async getTitleInfo(id: string): Promise<XcloudTitleInfo | undefined> {
if (id in this.CACHE_TITLES) { if (id in this.CACHE_TITLES) {
return this.CACHE_TITLES[id]; return this.CACHE_TITLES[id];
} }
const baseUri = STATES.selectedRegion.baseUri; const baseUri = STATES.selectedRegion.baseUri;
if (!baseUri || !STATES.gsToken) { if (!baseUri || !STATES.gsToken) {
return null; return;
} }
let json; let json;

View File

@ -1,4 +1,4 @@
import { isFullVersion } from "@macros/build" with {type: "macro"}; import { isFullVersion } from "@macros/build" with { type: "macro" };
import { LoadingScreen } from "@modules/loading-screen"; import { LoadingScreen } from "@modules/loading-screen";
import { RemotePlayManager } from "@/modules/remote-play-manager"; import { RemotePlayManager } from "@/modules/remote-play-manager";
@ -116,7 +116,7 @@ export class XcloudInterceptor {
let match = serverRegex.exec(region.baseUri); let match = serverRegex.exec(region.baseUri);
if (match) { if (match) {
shortName = match[1]; shortName = match[1] as string;
if (serverExtra[regionName]) { if (serverExtra[regionName]) {
shortName = serverExtra[regionName][0] + ' ' + shortName; shortName = serverExtra[regionName][0] + ' ' + shortName;
region.contintent = serverExtra[regionName][1]; region.contintent = serverExtra[regionName][1];
@ -155,10 +155,10 @@ export class XcloudInterceptor {
const url = (typeof request === 'string') ? request : (request as Request).url; const url = (typeof request === 'string') ? request : (request as Request).url;
const parsedUrl = new URL(url); const parsedUrl = new URL(url);
let badgeRegion: string = parsedUrl.host.split('.', 1)[0]; let badgeRegion: string = parsedUrl.host.split('.', 1)[0] as string;
for (let regionName in STATES.serverRegions) { for (let regionName in STATES.serverRegions) {
const region = STATES.serverRegions[regionName]; const region = STATES.serverRegions[regionName];
if (parsedUrl.origin == region.baseUri) { if (region && parsedUrl.origin === region.baseUri) {
badgeRegion = regionName; badgeRegion = regionName;
break; break;
} }
@ -168,7 +168,7 @@ export class XcloudInterceptor {
const clone = (request as Request).clone(); const clone = (request as Request).clone();
const body = await clone.json(); const body = await clone.json();
const headers: {[index: string]: string} = {}; const headers: { [index: string]: string } = {};
for (const pair of (clone.headers as any).entries()) { for (const pair of (clone.headers as any).entries()) {
headers[pair[0]] = pair[1]; headers[pair[0]] = pair[1];
} }

View File

@ -90,7 +90,7 @@ export class XhomeInterceptor {
XhomeInterceptor.consoleAddrs = {}; XhomeInterceptor.consoleAddrs = {};
for (const pair of pairs) { for (const pair of pairs) {
const [keyAddr, keyPort] = pair; const [keyAddr, keyPort] = pair;
if (serverDetails[keyAddr]) { if (keyAddr && keyPort && serverDetails[keyAddr]) {
const port = serverDetails[keyPort]; const port = serverDetails[keyPort];
// Add port 9002 to the list of ports // Add port 9002 to the list of ports
const ports = new Set<number>(); const ports = new Set<number>();
@ -107,7 +107,7 @@ export class XhomeInterceptor {
return response; return response;
} }
private static async handleInputConfigs(request: Request | URL, opts: {[index: string]: any}) { private static async handleInputConfigs(request: Request | URL, opts: { [index: string]: any }) {
const response = await NATIVE_FETCH(request); const response = await NATIVE_FETCH(request);
if (getPref<TouchControllerMode>(PrefKey.TOUCH_CONTROLLER_MODE) !== TouchControllerMode.ALL) { if (getPref<TouchControllerMode>(PrefKey.TOUCH_CONTROLLER_MODE) !== TouchControllerMode.ALL) {
@ -147,7 +147,7 @@ export class XhomeInterceptor {
private static async handleTitles(request: Request) { private static async handleTitles(request: Request) {
const clone = request.clone(); const clone = request.clone();
const headers: {[index: string]: any} = {}; const headers: { [index: string]: any } = {};
for (const pair of (clone.headers as any).entries()) { for (const pair of (clone.headers as any).entries()) {
headers[pair[0]] = pair[1]; headers[pair[0]] = pair[1];
} }
@ -183,7 +183,7 @@ export class XhomeInterceptor {
const clone = request.clone(); const clone = request.clone();
const headers: {[index: string]: string} = {}; const headers: { [index: string]: string } = {};
for (const pair of (clone.headers as any).entries()) { for (const pair of (clone.headers as any).entries()) {
headers[pair[0]] = pair[1]; headers[pair[0]] = pair[1];
} }

View File

@ -123,7 +123,7 @@ export class BxNumberStepper extends HTMLInputElement implements BxHtmlSettingEl
if (options.ticks || options.exactTicks) { if (options.ticks || options.exactTicks) {
const markersId = `markers-${key}`; const markersId = `markers-${key}`;
const $markers = CE('datalist', {id: markersId}); const $markers = CE('datalist', { id: markersId });
$range.setAttribute('list', markersId); $range.setAttribute('list', markersId);
if (options.exactTicks) { if (options.exactTicks) {
@ -140,7 +140,7 @@ export class BxNumberStepper extends HTMLInputElement implements BxHtmlSettingEl
} }
} else { } else {
for (let i = self.uiMin + options.ticks!; i < self.uiMax; i += options.ticks!) { for (let i = self.uiMin + options.ticks!; i < self.uiMax; i += options.ticks!) {
$markers.appendChild(CE<HTMLOptionElement>('option', {value: i})); $markers.appendChild(CE<HTMLOptionElement>('option', { value: i }));
} }
} }
self.appendChild($markers); self.appendChild($markers);

View File

@ -260,6 +260,9 @@ export class BxSelectElement extends HTMLSelectElement {
for (let i = 0; i < optionsList.length; i++) { for (let i = 0; i < optionsList.length; i++) {
const $option = optionsList[i]; const $option = optionsList[i];
const $indicator = indicatorsList[i]; const $indicator = indicatorsList[i];
if (!$option || !$indicator) {
continue;
}
clearDataSet($indicator); clearDataSet($indicator);
if ($option.selected) { if ($option.selected) {
@ -288,7 +291,7 @@ export class BxSelectElement extends HTMLSelectElement {
visibleIndex: currentIndex, visibleIndex: currentIndex,
} = this; } = this;
const goNext = (e.target as any).closest('button') === $btnNext; const goNext = (e.target as HTMLElement).closest('button') === $btnNext;
let newIndex = goNext ? currentIndex + 1 : currentIndex - 1; let newIndex = goNext ? currentIndex + 1 : currentIndex - 1;
if (newIndex > this.optionsList.length - 1) { if (newIndex > this.optionsList.length - 1) {