web: Add an onFSCommand callback into JavaScript

This commit is contained in:
Brian Gontowski 2021-01-28 02:55:26 -08:00 committed by Mike Welsh
parent d1fb36fbe2
commit 31dd2729e2
7 changed files with 51 additions and 8 deletions

View File

@ -1267,7 +1267,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} }
if let Some(fscommand) = fscommand::parse(&url) { if let Some(fscommand) = fscommand::parse(&url) {
fscommand::handle(fscommand, self)?; let fsargs = target;
fscommand::handle(fscommand, fsargs, self)?;
} else { } else {
self.context self.context
.navigator .navigator
@ -1290,7 +1291,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
let url = url_val.coerce_to_string(self)?; let url = url_val.coerce_to_string(self)?;
if let Some(fscommand) = fscommand::parse(&url) { if let Some(fscommand) = fscommand::parse(&url) {
fscommand::handle(fscommand, self)?; let fsargs = target.coerce_to_string(self)?.to_string();
fscommand::handle(fscommand, &fsargs, self)?;
return Ok(FrameControl::Continue); return Ok(FrameControl::Continue);
} }

View File

@ -13,13 +13,17 @@ pub fn parse(url: &str) -> Option<&str> {
} }
} }
/// TODO: FSCommand URL handling
pub fn handle<'gc>( pub fn handle<'gc>(
fscommand: &str, command: &str,
args: &str,
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error<'gc>> { ) -> Result<(), Error<'gc>> {
avm_warn!(activation, "Unhandled FSCommand: {}", fscommand); if !activation
.context
//This should be an error. .external_interface
.invoke_fs_command(command, args)
{
avm_warn!(activation, "Unhandled FSCommand: {}", command);
}
Ok(()) Ok(())
} }

View File

@ -1129,7 +1129,9 @@ pub fn get_url<'gc>(
if let Some(url_val) = args.get(0) { if let Some(url_val) = args.get(0) {
let url = url_val.coerce_to_string(activation)?; let url = url_val.coerce_to_string(activation)?;
if let Some(fscommand) = fscommand::parse(&url) { if let Some(fscommand) = fscommand::parse(&url) {
fscommand::handle(fscommand, activation); let fsargs_val = args.get(1).cloned().unwrap_or(Value::Undefined);
let fsargs = fsargs_val.coerce_to_string(activation)?;
fscommand::handle(fscommand, &fsargs, activation);
return Ok(Value::Undefined); return Ok(Value::Undefined);
} }

View File

@ -235,6 +235,8 @@ pub trait ExternalInterfaceProvider {
fn get_method(&self, name: &str) -> Option<Box<dyn ExternalInterfaceMethod>>; fn get_method(&self, name: &str) -> Option<Box<dyn ExternalInterfaceMethod>>;
fn on_callback_available(&self, name: &str); fn on_callback_available(&self, name: &str);
fn on_fs_command(&self, command: &str, args: &str) -> bool;
} }
pub trait ExternalInterfaceMethod { pub trait ExternalInterfaceMethod {
@ -295,4 +297,13 @@ impl<'gc> ExternalInterface<'gc> {
pub fn available(&self) -> bool { pub fn available(&self) -> bool {
!self.providers.is_empty() !self.providers.is_empty()
} }
pub fn invoke_fs_command(&self, command: &str, args: &str) -> bool {
for provider in &self.providers {
if provider.on_fs_command(command, args) {
return true;
}
}
false
}
} }

View File

@ -811,4 +811,8 @@ impl ExternalInterfaceProvider for ExternalInterfaceTestProvider {
} }
fn on_callback_available(&self, _name: &str) {} fn on_callback_available(&self, _name: &str) {}
fn on_fs_command(&self, _command: &str, _args: &str) -> bool {
false
}
} }

View File

@ -116,6 +116,16 @@ export class RufflePlayer extends HTMLElement {
private ruffleConstructor: Promise<{ new (...args: any[]): Ruffle }>; private ruffleConstructor: Promise<{ new (...args: any[]): Ruffle }>;
private panicked = false; private panicked = false;
/**
* A movie can communicate with the hosting page using fscommand
* as long as script access is allowed.
*
* @param command A string passed to the host application for any use.
* @param args A string passed to the host application for any use.
* @returns True if the command was handled.
*/
onFSCommand: ((command: string, args: string) => boolean) | null;
/** /**
* Any configuration that should apply to this specific player. * Any configuration that should apply to this specific player.
* This will be defaulted with any global configuration. * This will be defaulted with any global configuration.
@ -155,6 +165,7 @@ export class RufflePlayer extends HTMLElement {
this.instance = null; this.instance = null;
this.options = null; this.options = null;
this.onFSCommand = null;
this._trace_observer = null; this._trace_observer = null;
this.ruffleConstructor = loadRuffle(); this.ruffleConstructor = loadRuffle();

View File

@ -96,6 +96,9 @@ extern "C" {
#[wasm_bindgen(method, js_name = "onCallbackAvailable")] #[wasm_bindgen(method, js_name = "onCallbackAvailable")]
fn on_callback_available(this: &JavascriptPlayer, name: &str); fn on_callback_available(this: &JavascriptPlayer, name: &str);
#[wasm_bindgen(method, catch, js_name = "onFSCommand")]
fn on_fs_command(this: &JavascriptPlayer, command: &str, args: &str) -> Result<bool, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method)]
fn panic(this: &JavascriptPlayer, error: &JsError); fn panic(this: &JavascriptPlayer, error: &JsError);
@ -979,6 +982,12 @@ impl ExternalInterfaceProvider for JavascriptInterface {
fn on_callback_available(&self, name: &str) { fn on_callback_available(&self, name: &str) {
self.js_player.on_callback_available(name); self.js_player.on_callback_available(name);
} }
fn on_fs_command(&self, command: &str, args: &str) -> bool {
self.js_player
.on_fs_command(command, args)
.unwrap_or_default()
}
} }
fn js_to_external_value(js: &JsValue) -> ExternalValue { fn js_to_external_value(js: &JsValue) -> ExternalValue {