mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-07-07 23:01:44 +02:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
297c0848d5 | |||
51ef9f9e8f | |||
9717315b79 | |||
e176ef6fc0 | |||
52694d8f8e | |||
b7928ebe68 | |||
05eddce11e | |||
057da5b3ea | |||
11ef014c74 | |||
fa82f0ba95 | |||
36db8db1e7 | |||
d906de7803 | |||
cf546123db | |||
d6a4d1741b |
47
README.md
47
README.md
@ -5,7 +5,9 @@ Improve Xbox Cloud Gaming (xCloud) experience on [xbox.com/play](https://www.xbo
|
|||||||
> The Android app is in development at [redphx/better-xcloud-android](https://github.com/redphx/better-xcloud-android)
|
> The Android app is in development at [redphx/better-xcloud-android](https://github.com/redphx/better-xcloud-android)
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> I don't accept pull requests at the moment (except PR for custom touch controls)
|
> I only accept pull requests for:
|
||||||
|
> - Custom touch controls
|
||||||
|
> - Bug fixes
|
||||||
|
|
||||||
**Supported platforms:**
|
**Supported platforms:**
|
||||||
- Windows
|
- Windows
|
||||||
@ -21,50 +23,15 @@ If you like this project please give it a 🌟. Thank you 🙏.
|
|||||||
[](https://github.com/redphx/better-xcloud/releases)
|
[](https://github.com/redphx/better-xcloud/releases)
|
||||||
[](https://github.com/redphx/better-xcloud/stargazers)
|
[](https://github.com/redphx/better-xcloud/stargazers)
|
||||||
|
|
||||||
|
## How to install
|
||||||
|
Visit the [home page](https://better-xcloud.github.io) to know how to install Better xCloud on your device.
|
||||||
|
|
||||||
## Full documentations
|
## Full documentations
|
||||||
- For the full details please visit: https://better-xcloud.github.io
|
- For the full details please visit: [**better-xcloud.github.io**](https://better-xcloud.github.io)
|
||||||
- [Demo video](https://youtu.be/hyp69Jrb2sQ)
|
- [Demo video](https://youtu.be/hyp69Jrb2sQ)
|
||||||
|
|
||||||
⚠️ Please DO NOT report **Better xCloud**'s bugs on [/r/xcloud subreddit](https://reddit.com/r/xcloud/). Report bugs in [Issues](https://github.com/redphx/better-xcloud/issues) or [Telegram channel](https://t.me/betterxcloud) instead.
|
⚠️ Please DO NOT report **Better xCloud**'s bugs on [/r/xcloud subreddit](https://reddit.com/r/xcloud/). Report bugs in [Issues](https://github.com/redphx/better-xcloud/issues) or [Telegram channel](https://t.me/betterxcloud) instead.
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
- [**How to install**](#how-to-install)
|
|
||||||
- [**Features**](#features)
|
|
||||||
- [**Donation**](#donation)
|
|
||||||
- [**Acknowledgements**](#acknowledgements)
|
|
||||||
- [**Disclaimers**](#disclaimers)
|
|
||||||
|
|
||||||
## How to install
|
|
||||||
Visit [this page](https://better-xcloud.github.io/browsers) to know how to install Better xCloud on your device.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
<img width="400" alt="Settings UI" src="https://github.com/redphx/better-xcloud/assets/96280/4bec2d62-31df-499c-9aad-2485626b6925">
|
|
||||||
<br>
|
|
||||||
<img width="400" alt="Remote Play dialog" src="https://github.com/redphx/better-xcloud/assets/96280/daf7f698-a228-4f9c-8f23-9669e061a64c">
|
|
||||||
<br>
|
|
||||||
<img width="600" alt="Stream HUD" src="https://github.com/redphx/better-xcloud/assets/96280/51bdb96c-79ab-402f-902a-a9e6229973b2">
|
|
||||||
<br>
|
|
||||||
<img width="600" alt="Stream settings" src="https://github.com/redphx/better-xcloud/assets/96280/ed513cb3-6e6c-4e8e-9e06-c62e71e41c90">
|
|
||||||
<br>
|
|
||||||
<img width="600" alt="Remapper" src="https://github.com/redphx/better-xcloud/assets/96280/f2e2bc51-f673-4b24-b127-c7169b86462b">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Demo video:** [https://youtu.be/oDr5Eddp55E ](https://youtu.be/AYb-EUcz72U)
|
|
||||||
- **🔥 Totally free and open-source**
|
|
||||||
- **🔥 Allow playing with [Mouse & Keyboard](https://better-xcloud.github.io/mouse-and-keyboard)**
|
|
||||||
- **🔥 Enable [Remote Play](https://better-xcloud.github.io/remote-play) support**
|
|
||||||
> 1080p resolution and can stream Xbox 360 games.
|
|
||||||
- **🔥 [Improve visual quality](https://better-xcloud.github.io/ingame-features/#improve-streams-clarity) of the stream**
|
|
||||||
> Similar to (but not as good as) the "Clarity Boost" of xCloud on Edge browser. [Demo video](https://youtu.be/ZhW2choAHUs).
|
|
||||||
- **🔥 Show [Stream stats](https://better-xcloud.github.io/stream-stats)**
|
|
||||||
- **🔥 [Screenshot capture](https://better-xcloud.github.io/screenshot-capture)**
|
|
||||||
- **🔥 [Touch controller](https://better-xcloud.github.io/features/#touch-controller)**
|
|
||||||
> Enable touch controller support for all games.
|
|
||||||
- [And more...](https://better-xcloud.github.io/features/)
|
|
||||||
|
|
||||||
## Donation
|
## Donation
|
||||||
If you think this project is useful and want to support future developments, please consider making a donate via [my Ko-fi page](https://ko-fi.com/redphx).
|
If you think this project is useful and want to support future developments, please consider making a donate via [my Ko-fi page](https://ko-fi.com/redphx).
|
||||||
Or you can give this project a star, that's also helpful.
|
Or you can give this project a star, that's also helpful.
|
||||||
|
111
build.ts
111
build.ts
@ -6,10 +6,10 @@ import txtScriptHeader from "./src/assets/header_script.txt" with { type: "text"
|
|||||||
import txtMetaHeader from "./src/assets/header_meta.txt" with { type: "text" };
|
import txtMetaHeader from "./src/assets/header_meta.txt" with { type: "text" };
|
||||||
|
|
||||||
enum BuildTarget {
|
enum BuildTarget {
|
||||||
ALL = 'all',
|
ALL = 'all',
|
||||||
ANDROID_APP = 'android-app',
|
ANDROID_APP = 'android-app',
|
||||||
MOBILE = 'mobile',
|
MOBILE = 'mobile',
|
||||||
WEBOS = 'webos',
|
WEBOS = 'webos',
|
||||||
}
|
}
|
||||||
|
|
||||||
const postProcess = (str: string): string => {
|
const postProcess = (str: string): string => {
|
||||||
@ -21,83 +21,86 @@ const postProcess = (str: string): string => {
|
|||||||
// Replace "globalThis." with "var";
|
// Replace "globalThis." with "var";
|
||||||
str = str.replaceAll('globalThis.', 'var ');
|
str = str.replaceAll('globalThis.', 'var ');
|
||||||
|
|
||||||
// Add ADDITIONAL CODE block
|
// Add ADDITIONAL CODE block
|
||||||
str = str.replace('var DEFAULT_FLAGS', '\n/* ADDITIONAL CODE */\n\nvar DEFAULT_FLAGS');
|
str = str.replace('var DEFAULT_FLAGS', '\n/* ADDITIONAL CODE */\n\nvar DEFAULT_FLAGS');
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const build = async (target: BuildTarget, version: string, config: any={}) => {
|
const build = async (target: BuildTarget, version: string, config: any={}) => {
|
||||||
console.log('-- Target:', target);
|
console.log('-- Target:', target);
|
||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
|
|
||||||
let outputScriptName = 'better-xcloud';
|
let outputScriptName = 'better-xcloud';
|
||||||
if (target !== BuildTarget.ALL) {
|
if (target !== BuildTarget.ALL) {
|
||||||
outputScriptName += `.${target}`;
|
outputScriptName += `.${target}`;
|
||||||
}
|
}
|
||||||
let outputMetaName = outputScriptName;
|
let outputMetaName = outputScriptName;
|
||||||
outputScriptName += '.user.js';
|
outputScriptName += '.user.js';
|
||||||
outputMetaName += '.meta.js';
|
outputMetaName += '.meta.js';
|
||||||
|
|
||||||
const outDir = './dist';
|
const outDir = './dist';
|
||||||
|
|
||||||
let output = await Bun.build({
|
let output = await Bun.build({
|
||||||
entrypoints: ['src/index.ts'],
|
entrypoints: ['src/index.ts'],
|
||||||
outdir: outDir,
|
outdir: outDir,
|
||||||
naming: outputScriptName,
|
naming: outputScriptName,
|
||||||
define: {
|
minify: {
|
||||||
'Bun.env.BUILD_TARGET': JSON.stringify(target),
|
syntax: true,
|
||||||
'Bun.env.SCRIPT_VERSION': JSON.stringify(version),
|
},
|
||||||
},
|
define: {
|
||||||
});
|
'Bun.env.BUILD_TARGET': JSON.stringify(target),
|
||||||
|
'Bun.env.SCRIPT_VERSION': JSON.stringify(version),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!output.success) {
|
if (!output.success) {
|
||||||
console.log(output);
|
console.log(output);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {path} = output.outputs[0];
|
const {path} = output.outputs[0];
|
||||||
// Get generated file
|
// Get generated file
|
||||||
let result = postProcess(await readFile(path, 'utf-8'));
|
let result = postProcess(await readFile(path, 'utf-8'));
|
||||||
|
|
||||||
// Replace [[VERSION]] with real value
|
// Replace [[VERSION]] with real value
|
||||||
const scriptHeader = txtScriptHeader.replace('[[VERSION]]', version);
|
const scriptHeader = txtScriptHeader.replace('[[VERSION]]', version);
|
||||||
|
|
||||||
// Save to script
|
// Save to script
|
||||||
await Bun.write(path, scriptHeader + result);
|
await Bun.write(path, scriptHeader + result);
|
||||||
console.log(`---- [${target}] done in ${performance.now() - startTime} ms`);
|
console.log(`---- [${target}] done in ${performance.now() - startTime} ms`);
|
||||||
|
|
||||||
// Create meta file
|
// Create meta file
|
||||||
await Bun.write(outDir + '/' + outputMetaName, txtMetaHeader.replace('[[VERSION]]', version));
|
await Bun.write(outDir + '/' + outputMetaName, txtMetaHeader.replace('[[VERSION]]', version));
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildTargets = [
|
const buildTargets = [
|
||||||
BuildTarget.ALL,
|
BuildTarget.ALL,
|
||||||
// BuildTarget.ANDROID_APP,
|
// BuildTarget.ANDROID_APP,
|
||||||
// BuildTarget.MOBILE,
|
// BuildTarget.MOBILE,
|
||||||
// BuildTarget.WEBOS,
|
// BuildTarget.WEBOS,
|
||||||
];
|
];
|
||||||
|
|
||||||
const { values, positionals } = parseArgs({
|
const { values, positionals } = parseArgs({
|
||||||
args: Bun.argv,
|
args: Bun.argv,
|
||||||
options: {
|
options: {
|
||||||
version: {
|
version: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
strict: true,
|
strict: true,
|
||||||
allowPositionals: true,
|
allowPositionals: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!values['version']) {
|
if (!values['version']) {
|
||||||
console.log('Missing --version param');
|
console.log('Missing --version param');
|
||||||
sys.exit(-1);
|
sys.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Building: ', values['version']);
|
console.log('Building: ', values['version']);
|
||||||
|
|
||||||
const config = {};
|
const config = {};
|
||||||
for (const target of buildTargets) {
|
for (const target of buildTargets) {
|
||||||
await build(target, values['version'], config);
|
await build(target, values['version']!!, config);
|
||||||
}
|
}
|
||||||
|
2
dist/better-xcloud.meta.js
vendored
2
dist/better-xcloud.meta.js
vendored
@ -1,5 +1,5 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 5.0.0
|
// @version 5.0.1
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
4855
dist/better-xcloud.user.js
vendored
4855
dist/better-xcloud.user.js
vendored
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.1.5",
|
"@types/bun": "^1.1.5",
|
||||||
"@types/node": "^20.14.7",
|
"@types/node": "^20.14.9",
|
||||||
"@types/stylus": "^0.48.42",
|
"@types/stylus": "^0.48.42",
|
||||||
"stylus": "^0.63.0"
|
"stylus": "^0.63.0"
|
||||||
},
|
},
|
||||||
|
@ -158,19 +158,26 @@ export class StreamBadges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#secondsToHm(seconds: number) {
|
#secondsToHm(seconds: number) {
|
||||||
const h = Math.floor(seconds / 3600);
|
let h = Math.floor(seconds / 3600);
|
||||||
const m = Math.floor(seconds % 3600 / 60) + 1;
|
let m = Math.floor(seconds % 3600 / 60) + 1;
|
||||||
|
|
||||||
const hDisplay = h > 0 ? `${h}h`: '';
|
if (m === 60) {
|
||||||
const mDisplay = m > 0 ? `${m}m`: '';
|
h += 1;
|
||||||
return hDisplay + mDisplay;
|
m = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = [];
|
||||||
|
h > 0 && output.push(`${h}h`);
|
||||||
|
m > 0 && output.push(`${m}m`);
|
||||||
|
|
||||||
|
return output.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/a/20732091
|
// https://stackoverflow.com/a/20732091
|
||||||
#humanFileSize(size: number) {
|
#humanFileSize(size: number) {
|
||||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
|
||||||
let i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
|
const i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
|
||||||
return (size / Math.pow(1024, i)).toFixed(2) + ' ' + units[i];
|
return (size / Math.pow(1024, i)).toFixed(2) + ' ' + units[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,19 +128,19 @@ function setupStreamSettingsDialog() {
|
|||||||
{
|
{
|
||||||
pref: PrefKey.CONTROLLER_ENABLE_VIBRATION,
|
pref: PrefKey.CONTROLLER_ENABLE_VIBRATION,
|
||||||
unsupported: !VibrationManager.supportControllerVibration(),
|
unsupported: !VibrationManager.supportControllerVibration(),
|
||||||
onChange: VibrationManager.updateGlobalVars,
|
onChange: () => VibrationManager.updateGlobalVars(),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
pref: PrefKey.CONTROLLER_DEVICE_VIBRATION,
|
pref: PrefKey.CONTROLLER_DEVICE_VIBRATION,
|
||||||
unsupported: !VibrationManager.supportDeviceVibration(),
|
unsupported: !VibrationManager.supportDeviceVibration(),
|
||||||
onChange: VibrationManager.updateGlobalVars,
|
onChange: () => VibrationManager.updateGlobalVars(),
|
||||||
},
|
},
|
||||||
|
|
||||||
(VibrationManager.supportControllerVibration() || VibrationManager.supportDeviceVibration()) && {
|
(VibrationManager.supportControllerVibration() || VibrationManager.supportDeviceVibration()) && {
|
||||||
pref: PrefKey.CONTROLLER_VIBRATION_INTENSITY,
|
pref: PrefKey.CONTROLLER_VIBRATION_INTENSITY,
|
||||||
unsupported: !VibrationManager.supportDeviceVibration(),
|
unsupported: !VibrationManager.supportDeviceVibration(),
|
||||||
onChange: VibrationManager.updateGlobalVars,
|
onChange: () => VibrationManager.updateGlobalVars(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -53,7 +53,7 @@ export class VibrationManager {
|
|||||||
return !!window.navigator.vibrate;
|
return !!window.navigator.vibrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static updateGlobalVars() {
|
static updateGlobalVars(stopVibration: boolean = true) {
|
||||||
window.BX_ENABLE_CONTROLLER_VIBRATION = VibrationManager.supportControllerVibration() ? getPref(PrefKey.CONTROLLER_ENABLE_VIBRATION) : false;
|
window.BX_ENABLE_CONTROLLER_VIBRATION = VibrationManager.supportControllerVibration() ? getPref(PrefKey.CONTROLLER_ENABLE_VIBRATION) : false;
|
||||||
window.BX_VIBRATION_INTENSITY = getPref(PrefKey.CONTROLLER_VIBRATION_INTENSITY) / 100;
|
window.BX_VIBRATION_INTENSITY = getPref(PrefKey.CONTROLLER_VIBRATION_INTENSITY) / 100;
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ export class VibrationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop vibration
|
// Stop vibration
|
||||||
window.navigator.vibrate(0);
|
stopVibration && window.navigator.vibrate(0);
|
||||||
|
|
||||||
const value = getPref(PrefKey.CONTROLLER_DEVICE_VIBRATION);
|
const value = getPref(PrefKey.CONTROLLER_DEVICE_VIBRATION);
|
||||||
let enabled;
|
let enabled;
|
||||||
@ -134,10 +134,10 @@ export class VibrationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static initialSetup() {
|
static initialSetup() {
|
||||||
window.addEventListener('gamepadconnected', VibrationManager.updateGlobalVars);
|
window.addEventListener('gamepadconnected', e => VibrationManager.updateGlobalVars());
|
||||||
window.addEventListener('gamepaddisconnected', VibrationManager.updateGlobalVars);
|
window.addEventListener('gamepaddisconnected', e => VibrationManager.updateGlobalVars());
|
||||||
|
|
||||||
VibrationManager.updateGlobalVars();
|
VibrationManager.updateGlobalVars(false);
|
||||||
|
|
||||||
window.addEventListener(BxEvent.DATA_CHANNEL_CREATED, e => {
|
window.addEventListener(BxEvent.DATA_CHANNEL_CREATED, e => {
|
||||||
const dataChannel = (e as any).dataChannel;
|
const dataChannel = (e as any).dataChannel;
|
||||||
|
@ -4,7 +4,8 @@ import { renderStylus } from "@macros/build" with {type: "macro"};
|
|||||||
|
|
||||||
|
|
||||||
export function addCss() {
|
export function addCss() {
|
||||||
let css = renderStylus();
|
const STYLUS_CSS = renderStylus();
|
||||||
|
let css = STYLUS_CSS;
|
||||||
|
|
||||||
if (getPref(PrefKey.BLOCK_SOCIAL_FEATURES)) {
|
if (getPref(PrefKey.BLOCK_SOCIAL_FEATURES)) {
|
||||||
css += `
|
css += `
|
||||||
|
@ -598,6 +598,10 @@ export class Preferences {
|
|||||||
max: 10,
|
max: 10,
|
||||||
params: {
|
params: {
|
||||||
hideSlider: true,
|
hideSlider: true,
|
||||||
|
customTextValue: (value: any) => {
|
||||||
|
value = parseInt(value);
|
||||||
|
return value === 0 ? t('off') : value.toString();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[PrefKey.VIDEO_RATIO]: {
|
[PrefKey.VIDEO_RATIO]: {
|
||||||
|
@ -132,10 +132,12 @@ export class SettingElement {
|
|||||||
options.hideSlider = !!options.hideSlider;
|
options.hideSlider = !!options.hideSlider;
|
||||||
|
|
||||||
let $text: HTMLSpanElement;
|
let $text: HTMLSpanElement;
|
||||||
let $decBtn: HTMLButtonElement;
|
let $btnDec: HTMLButtonElement;
|
||||||
let $incBtn: HTMLButtonElement;
|
let $btnInc: HTMLButtonElement;
|
||||||
let $range: HTMLInputElement;
|
let $range: HTMLInputElement;
|
||||||
|
|
||||||
|
let controlValue = value;
|
||||||
|
|
||||||
const MIN = setting.min!;
|
const MIN = setting.min!;
|
||||||
const MAX = setting.max!;
|
const MAX = setting.max!;
|
||||||
const STEPS = Math.max(setting.steps || 1, 1);
|
const STEPS = Math.max(setting.steps || 1, 1);
|
||||||
@ -155,14 +157,19 @@ export class SettingElement {
|
|||||||
return textContent;
|
return textContent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateButtonsVisibility = () => {
|
||||||
|
$btnDec.classList.toggle('bx-hidden', controlValue === MIN);
|
||||||
|
$btnInc.classList.toggle('bx-hidden', controlValue === MAX);
|
||||||
|
}
|
||||||
|
|
||||||
const $wrapper = CE('div', {'class': 'bx-number-stepper', id: `bx_setting_${key}`},
|
const $wrapper = CE('div', {'class': 'bx-number-stepper', id: `bx_setting_${key}`},
|
||||||
$decBtn = CE('button', {
|
$btnDec = CE('button', {
|
||||||
'data-type': 'dec',
|
'data-type': 'dec',
|
||||||
type: 'button',
|
type: 'button',
|
||||||
tabindex: -1,
|
tabindex: -1,
|
||||||
}, '-') as HTMLButtonElement,
|
}, '-') as HTMLButtonElement,
|
||||||
$text = CE('span', {}, renderTextValue(value)) as HTMLSpanElement,
|
$text = CE('span', {}, renderTextValue(value)) as HTMLSpanElement,
|
||||||
$incBtn = CE('button', {
|
$btnInc = CE('button', {
|
||||||
'data-type': 'inc',
|
'data-type': 'inc',
|
||||||
type: 'button',
|
type: 'button',
|
||||||
tabindex: -1,
|
tabindex: -1,
|
||||||
@ -182,6 +189,9 @@ export class SettingElement {
|
|||||||
|
|
||||||
$range.addEventListener('input', e => {
|
$range.addEventListener('input', e => {
|
||||||
value = parseInt((e.target as HTMLInputElement).value);
|
value = parseInt((e.target as HTMLInputElement).value);
|
||||||
|
controlValue = value;
|
||||||
|
updateButtonsVisibility();
|
||||||
|
|
||||||
$text.textContent = renderTextValue(value);
|
$text.textContent = renderTextValue(value);
|
||||||
!(e as any).ignoreOnChange && onChange && onChange(e, value);
|
!(e as any).ignoreOnChange && onChange && onChange(e, value);
|
||||||
});
|
});
|
||||||
@ -212,14 +222,16 @@ export class SettingElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.disabled) {
|
if (options.disabled) {
|
||||||
$incBtn.disabled = true;
|
$btnInc.disabled = true;
|
||||||
$incBtn.classList.add('bx-hidden');
|
$btnInc.classList.add('bx-hidden');
|
||||||
|
|
||||||
$decBtn.disabled = true;
|
$btnDec.disabled = true;
|
||||||
$decBtn.classList.add('bx-hidden');
|
$btnDec.classList.add('bx-hidden');
|
||||||
return $wrapper;
|
return $wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateButtonsVisibility();
|
||||||
|
|
||||||
let interval: number;
|
let interval: number;
|
||||||
let isHolding = false;
|
let isHolding = false;
|
||||||
|
|
||||||
@ -231,19 +243,19 @@ export class SettingElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let value: number;
|
const $btn = e.target as HTMLElement;
|
||||||
if ($range) {
|
let value = parseInt(controlValue);
|
||||||
value = parseInt($range.value);
|
|
||||||
} else {
|
const btnType = $btn.dataset.type;
|
||||||
value = parseInt($text.textContent!);
|
|
||||||
}
|
|
||||||
const btnType = (e.target as HTMLElement).getAttribute('data-type');
|
|
||||||
if (btnType === 'dec') {
|
if (btnType === 'dec') {
|
||||||
value = Math.max(MIN, value - STEPS);
|
value = Math.max(MIN, value - STEPS);
|
||||||
} else {
|
} else {
|
||||||
value = Math.min(MAX, value + STEPS);
|
value = Math.min(MAX, value + STEPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controlValue = value;
|
||||||
|
updateButtonsVisibility();
|
||||||
|
|
||||||
$text.textContent = renderTextValue(value);
|
$text.textContent = renderTextValue(value);
|
||||||
$range && ($range.value = value.toString());
|
$range && ($range.value = value.toString());
|
||||||
|
|
||||||
@ -277,19 +289,21 @@ export class SettingElement {
|
|||||||
|
|
||||||
// Custom method
|
// Custom method
|
||||||
($wrapper as any).setValue = (value: any) => {
|
($wrapper as any).setValue = (value: any) => {
|
||||||
|
controlValue = parseInt(value);
|
||||||
|
|
||||||
$text.textContent = renderTextValue(value);
|
$text.textContent = renderTextValue(value);
|
||||||
$range && ($range.value = value);
|
$range && ($range.value = value);
|
||||||
};
|
};
|
||||||
|
|
||||||
$decBtn.addEventListener('click', onClick);
|
$btnDec.addEventListener('click', onClick);
|
||||||
$decBtn.addEventListener('pointerdown', onMouseDown);
|
$btnDec.addEventListener('pointerdown', onMouseDown);
|
||||||
$decBtn.addEventListener('pointerup', onMouseUp);
|
$btnDec.addEventListener('pointerup', onMouseUp);
|
||||||
$decBtn.addEventListener('contextmenu', onContextMenu);
|
$btnDec.addEventListener('contextmenu', onContextMenu);
|
||||||
|
|
||||||
$incBtn.addEventListener('click', onClick);
|
$btnInc.addEventListener('click', onClick);
|
||||||
$incBtn.addEventListener('pointerdown', onMouseDown);
|
$btnInc.addEventListener('pointerdown', onMouseDown);
|
||||||
$incBtn.addEventListener('pointerup', onMouseUp);
|
$btnInc.addEventListener('pointerup', onMouseUp);
|
||||||
$incBtn.addEventListener('contextmenu', onContextMenu);
|
$btnInc.addEventListener('contextmenu', onContextMenu);
|
||||||
|
|
||||||
return $wrapper;
|
return $wrapper;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user