web: Allow overriding of methods via ExternalInterface - fixes #13974

This commit is contained in:
Nathan Adams 2024-08-06 15:46:00 +02:00
parent 2f9f275eff
commit ccbad52a1e
4 changed files with 45 additions and 3 deletions

View File

@ -35,9 +35,21 @@ export class RufflePlayerElement extends HTMLElement implements Player {
this,
() => this.debugPlayerInfo(),
(name) => {
(this as any)[name] = (...args: unknown[]) => {
return this.#inner.callExternalInterface(name, args);
};
try {
Object.defineProperty(this, name, {
value: (...args: unknown[]) => {
return this.#inner.callExternalInterface(
name,
args,
);
},
});
} catch (error) {
console.warn(
`Error setting ExternalInterface legacy callback for ${name}`,
error,
);
}
},
);
}

View File

@ -49,6 +49,13 @@
log("setMarshallExceptions called with " + repr(value));
ExternalInterface.marshallExceptions = value;
});
ExternalInterface.addCallback("addAnotherCallback", function(name: String, returnValue: *) {
log("addAnotherCallback called for " + repr(name) + " to return " + repr(returnValue));
ExternalInterface.addCallback(name, function() {
log(name + " called");
return returnValue;
});
});
} catch (e) {
log("Error adding callbacks: " + e);
}

View File

@ -44,6 +44,9 @@ declare global {
// Calls `ExternalInterface.marshallExceptions = value`
setMarshallExceptions: (value: boolean) => void;
// Calls `ExternalInterface.addCallback(name, function() { return returnValue; })`
addAnotherCallback: (name: string, returnValue: unknown) => void;
}
}
@ -297,4 +300,24 @@ log called with 1 argument
`,
);
});
it("allows overriding a Ruffle method", async () => {
const player = await browser.$("<ruffle-object>");
await browser.execute((player) => {
player.addAnotherCallback("isPlaying", "isPlaying from EI");
}, player);
let actualOutput = await getTraceOutput(browser, player);
expect(actualOutput).to.eql(
`addAnotherCallback called for "isPlaying" to return "isPlaying from EI"\n`,
);
const isPlayingResult = await browser.execute((player) => {
return (player as unknown as any).isPlaying();
}, player);
expect(isPlayingResult).to.eql("isPlaying from EI");
actualOutput = await getTraceOutput(browser, player);
expect(actualOutput).to.eql(`isPlaying called\n`);
});
});