1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 12:55:55 +00:00
* Fixed: Add support for a new React router Twitch is testing in an A/B experiment.
This commit is contained in:
SirStendec 2025-03-12 13:34:39 -04:00
parent 850c4d53fd
commit 43c80713e9
8 changed files with 114 additions and 22 deletions

View file

@ -1,7 +1,7 @@
{
"name": "frankerfacez",
"author": "Dan Salvato LLC",
"version": "4.77.0",
"version": "4.77.1",
"description": "FrankerFaceZ is a Twitch enhancement suite.",
"private": true,
"license": "Apache-2.0",

View file

@ -140,10 +140,10 @@ export default class ClipsSite extends BaseSite {
updateContext() {
try {
const state = this.store.getState(),
history = this.router && this.router.history;
location = this.router?.reactLocation;
this.settings.updateContext({
location: history?.location,
location,
ui: state?.ui,
session: state?.session
});
@ -223,4 +223,8 @@ ClipsSite.CLIP_ROUTES = {
'clip-page': '/:slug'
};
ClipsSite.CHAT_ROUTES = [
'clip-page'
];
ClipsSite.DIALOG_SELECTOR = '#root > div';

View file

@ -211,3 +211,6 @@ export default class PlayerSite extends BaseSite {
ver.textContent = this.resolve('core').constructor.version_info.toString();
}
}
PlayerSite.CHAT_ROUTES = [];

View file

@ -165,14 +165,15 @@ export default class Twilight extends BaseSite {
updateContext() {
try {
const state = this.store.getState(),
history = this.router && this.router.history;
location = this.router?.reactLocation;
this.settings.updateContext({
location: history && history.location,
location,
ui: state && state.ui,
session: state && state.session,
chat: state && state.chat
});
} catch(err) {
this.log.error('Error updating context.', err);
}

View file

@ -247,7 +247,7 @@ export default class Channel extends Module {
if ( this.router.old_location === this.router.location )
return;
this.router.history.replace(this.router.location, {channelView: 'Watch'});
this.router.replace(this.router.location, {channelView: 'Watch'});
}
updateLinks() {

View file

@ -621,7 +621,7 @@ export default class Directory extends Module {
link.props.onClick();
// And follow the generated link.
this.router.history.push(link.props.linkTo);
this.router.push(link.props.linkTo);
}
updateGameCard(el) {
@ -1029,7 +1029,7 @@ export default class Directory extends Module {
}
if ( url )
this.router.history.push(url);
this.router.push(url);
}

View file

@ -9,6 +9,7 @@ import Module, { GenericModule } from 'utilities/module';
import {has, deep_equals, sleep} from 'utilities/object';
import type Fine from './fine';
import type { OptionalPromise } from 'utilities/types';
import { ReactNode, ReactStateNode } from './react-types';
declare module 'utilities/types' {
interface ModuleEventMap {
@ -34,6 +35,36 @@ export type RouteInfo = {
};
type ReactLocation = Location & {
state: unknown;
}
type HistoryObject = {
listen(fn: (location: ReactLocation) => void): void;
push(url: string, state: unknown): void;
replace(url: string, state: unknown): void;
location: ReactLocation;
};
type RouterState = {
historyAction: string;
location: ReactLocation;
};
type RouterObject = {
subscribe(fn: (state: RouterState) => void): void;
router: {
state: RouterState
}
};
type NavigationObject = {
push(url: string, state: unknown): void;
replace(url: string, state: unknown): void;
}
export default class FineRouter extends Module<'site.router', FineRouterEvents> {
// Dependencies
@ -51,6 +82,10 @@ export default class FineRouter extends Module<'site.router', FineRouterEvents>
match: unknown | null;
location: unknown | null;
// Things
history?: HistoryObject | null;
router?: RouterObject | null;
navigator?: NavigationObject | null;
constructor(name?: string, parent?: GenericModule) {
@ -69,26 +104,75 @@ export default class FineRouter extends Module<'site.router', FineRouterEvents>
}
/** @internal */
onEnable(): OptionalPromise<void> {
const thing = this.fine.searchTree(null, n => n.props && n.props.history),
history = this.history = thing && thing.props && thing.props.history;
onEnable(tries = 0): OptionalPromise<void> {
const thing = this.fine.searchTree<ReactStateNode<{history: HistoryObject}>>(null, n => n?.props?.history);
this.history = thing?.props?.history;
if ( ! history )
return sleep(50).then(() => this.onEnable());
if ( this.history ) {
this.history.listen(location => {
if ( this.enabled )
this._navigateTo(location);
});
history.listen(location => {
if ( this.enabled )
this._navigateTo(location);
this._navigateTo(this.history.location);
return;
}
const other = this.fine.searchNode(null, n => n?.pendingProps?.router?.subscribe);
this.router = other?.pendingProps?.router;
const nav = this.fine.searchNode(null, n => n?.pendingProps?.navigator?.push);
this.navigator = nav?.pendingProps?.navigator;
if ( ! this.router || ! this.navigator ) {
if (tries > 100) {
this.log.warn('Finding React\'s router is taking a long time.');
tries = -500;
}
return sleep(50).then(() => this.onEnable(tries + 1));
}
this.router.subscribe(evt => {
if ( this.enabled && evt?.location )
this._navigateTo(evt.location);
});
this._navigateTo(history.location);
this._navigateTo(this.router.router.state.location);
}
navigate(route, data, opts, state) {
this.history.push(this.getURL(route, data, opts), state);
const url = this.getURL(route, data, opts);
this.push(url, state);
}
private _navigateTo(location) {
get reactLocation() {
if (this.history)
return this.history.location;
else if (this.router)
return this.router.router.state.location;
}
push(url: string, state: unknown) {
if (this.history)
this.history.push(url, state);
else if (this.navigator)
this.navigator.push(url, state);
else
throw new Error('unable to push new route');
}
replace(url: string, state: unknown) {
if (this.history)
this.history.replace(url, state);
else if (this.navigator)
this.navigator.replace(url, state);
else
throw new Error('unable to replace route');
}
private _navigateTo(location: ReactLocation) {
this.log.debug('New Location', location);
const host = window.location.host,
path = location.pathname,

View file

@ -218,16 +218,16 @@ export class VueModule extends Module<'vue'> {
methods: {
reactNavigate(url, event, state) {
const router = t.resolve('site.router');
if ( router && router.history ) {
if ( router ) {
if ( event ) {
event.preventDefault();
event.stopPropagation();
}
router.history.push(url, state ?? undefined);
router.push(url, state ?? undefined);
}
},
getReactURL(route, data, opts, ...args) {
const router = t.resolve('site.router');
const router = t.resolve('site.router')!;
return router.getURL(route, data, opts, ...args);
},
getI18n() {