2020-11-12 22:32:53 +00:00
|
|
|
import {
|
2020-05-12 22:24:41 +00:00
|
|
|
FLASH_MIMETYPE,
|
|
|
|
FUTURESPLASH_MIMETYPE,
|
|
|
|
FLASH7_AND_8_MIMETYPE,
|
|
|
|
FLASH_MOVIE_MIMETYPE,
|
|
|
|
FLASH_ACTIVEX_CLASSID,
|
2020-11-16 21:54:35 +00:00
|
|
|
isSwfFilename,
|
2020-05-12 22:24:41 +00:00
|
|
|
RufflePlayer,
|
2020-11-12 22:32:53 +00:00
|
|
|
} from "./ruffle-player";
|
|
|
|
import { register_element } from "./register-element";
|
2019-08-22 01:02:43 +00:00
|
|
|
|
2020-11-16 22:55:58 +00:00
|
|
|
/**
|
|
|
|
* Find and return the first value in obj with the given key.
|
|
|
|
* Many Flash params were case insensitive, so we use this when checking for them.
|
|
|
|
*
|
|
|
|
* @param obj Object to check
|
|
|
|
* @param key Key to find
|
|
|
|
* @param defaultValue Value if not found
|
|
|
|
* @return Value if found, else [[defaultValue]]
|
|
|
|
*/
|
|
|
|
function findCaseInsensitive(
|
|
|
|
obj: { [key: string]: string | null },
|
|
|
|
key: string,
|
|
|
|
defaultValue: string | null
|
|
|
|
): string | null {
|
|
|
|
key = key.toLowerCase();
|
|
|
|
for (const k in obj) {
|
|
|
|
if (Object.hasOwnProperty.call(obj, k) && key === k.toLowerCase()) {
|
|
|
|
return obj[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return defaultValue;
|
|
|
|
}
|
|
|
|
|
2020-11-16 22:57:29 +00:00
|
|
|
/**
|
|
|
|
* Returns all flash params ([[HTMLParamElement]]) that are for the given object.
|
|
|
|
*
|
|
|
|
* @param elem Element to check.
|
|
|
|
* @return A record of every parameter.
|
|
|
|
*/
|
|
|
|
function paramsOf(elem: HTMLElement): Record<string, string> {
|
|
|
|
const params: Record<string, string> = {};
|
|
|
|
|
|
|
|
for (const param of elem.children) {
|
|
|
|
if (param instanceof HTMLParamElement) {
|
|
|
|
const key = param.attributes.getNamedItem("name")?.value;
|
|
|
|
const value = param.attributes.getNamedItem("value")?.value;
|
|
|
|
if (key && value) {
|
|
|
|
params[key] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return params;
|
|
|
|
}
|
|
|
|
|
2020-11-16 22:52:39 +00:00
|
|
|
/**
|
|
|
|
* A polyfill html element.
|
|
|
|
*
|
|
|
|
* This specific class tries to polyfill existing `<object>` tags,
|
|
|
|
* and should not be used. Prefer [[RufflePlayer]] instead.
|
|
|
|
*
|
|
|
|
* @internal
|
|
|
|
*/
|
2020-11-12 22:32:53 +00:00
|
|
|
export class RuffleObject extends RufflePlayer {
|
|
|
|
private params: Record<string, string> = {};
|
|
|
|
|
2020-11-16 22:52:39 +00:00
|
|
|
/**
|
|
|
|
* Constructs a new Ruffle flash player for insertion onto the page.
|
|
|
|
*
|
|
|
|
* This specific class tries to polyfill existing `<object>` tags,
|
|
|
|
* and should not be used. Prefer [[RufflePlayer]] instead.
|
|
|
|
*/
|
2020-11-12 22:32:53 +00:00
|
|
|
constructor() {
|
|
|
|
super();
|
2019-08-22 01:02:43 +00:00
|
|
|
}
|
|
|
|
|
2020-11-16 22:52:39 +00:00
|
|
|
/**
|
|
|
|
* @ignore
|
|
|
|
*/
|
|
|
|
connectedCallback(): void {
|
2019-08-25 19:46:38 +00:00
|
|
|
super.connectedCallback();
|
2020-05-12 22:24:41 +00:00
|
|
|
|
2020-11-16 22:57:29 +00:00
|
|
|
this.params = paramsOf(this);
|
2020-03-21 01:27:59 +00:00
|
|
|
|
2020-11-16 22:55:58 +00:00
|
|
|
const allowScriptAccess = findCaseInsensitive(
|
2020-09-02 21:34:04 +00:00
|
|
|
this.params,
|
|
|
|
"allowScriptAccess",
|
|
|
|
"sameDomain"
|
|
|
|
);
|
|
|
|
let url = null;
|
|
|
|
|
2020-11-12 22:32:53 +00:00
|
|
|
if (this.attributes.getNamedItem("data")) {
|
|
|
|
url = this.attributes.getNamedItem("data")?.value;
|
2019-09-14 19:40:19 +00:00
|
|
|
} else if (this.params.movie) {
|
2020-09-02 21:34:04 +00:00
|
|
|
url = this.params.movie;
|
|
|
|
}
|
|
|
|
|
2020-11-16 22:55:58 +00:00
|
|
|
const parameters = findCaseInsensitive(
|
2020-10-11 18:35:28 +00:00
|
|
|
this.params,
|
|
|
|
"flashvars",
|
2020-11-16 22:52:39 +00:00
|
|
|
this.getAttribute("flashvars")
|
2020-10-11 18:35:28 +00:00
|
|
|
);
|
|
|
|
|
2020-09-02 21:34:04 +00:00
|
|
|
if (url) {
|
2020-11-16 22:52:39 +00:00
|
|
|
this.allowScriptAccess = !!(
|
2020-09-02 21:34:04 +00:00
|
|
|
allowScriptAccess &&
|
|
|
|
(allowScriptAccess.toLowerCase() === "always" ||
|
|
|
|
(allowScriptAccess.toLowerCase() === "samedomain" &&
|
|
|
|
new URL(window.location.href).origin ===
|
2020-11-16 22:52:39 +00:00
|
|
|
new URL(url, window.location.href).origin))
|
|
|
|
);
|
2020-09-02 21:34:04 +00:00
|
|
|
|
|
|
|
//Kick off the SWF download.
|
2020-11-15 00:44:47 +00:00
|
|
|
this.streamSwfUrl(url, parameters);
|
2019-08-22 01:02:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-16 22:52:39 +00:00
|
|
|
protected debugPlayerInfo(): string {
|
2020-11-16 21:53:41 +00:00
|
|
|
let error_text = super.debugPlayerInfo();
|
2020-09-12 22:03:19 +00:00
|
|
|
error_text += "Player type: Object\n";
|
|
|
|
|
|
|
|
let url = null;
|
|
|
|
|
2020-11-12 22:32:53 +00:00
|
|
|
if (this.attributes.getNamedItem("data")) {
|
|
|
|
url = this.attributes.getNamedItem("data")?.value;
|
2020-09-12 22:03:19 +00:00
|
|
|
} else if (this.params.movie) {
|
|
|
|
url = this.params.movie;
|
|
|
|
}
|
|
|
|
error_text += `SWF URL: ${url}\n`;
|
|
|
|
|
|
|
|
Object.keys(this.params).forEach((key) => {
|
|
|
|
error_text += `Param ${key}: ${this.params[key]}\n`;
|
|
|
|
});
|
|
|
|
|
|
|
|
Object.keys(this.attributes).forEach((key) => {
|
2020-11-12 22:32:53 +00:00
|
|
|
error_text += `Attribute ${key}: ${
|
|
|
|
this.attributes.getNamedItem(key)?.value
|
|
|
|
}\n`;
|
2020-09-12 22:03:19 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return error_text;
|
|
|
|
}
|
|
|
|
|
2020-11-16 22:52:39 +00:00
|
|
|
/**
|
|
|
|
* Polyfill of HTMLObjectElement.
|
|
|
|
*
|
|
|
|
* @ignore
|
|
|
|
*/
|
|
|
|
get data(): string | null {
|
|
|
|
return this.getAttribute("data");
|
2019-09-14 19:40:19 +00:00
|
|
|
}
|
|
|
|
|
2020-11-16 22:52:39 +00:00
|
|
|
/**
|
|
|
|
* Polyfill of HTMLObjectElement.
|
|
|
|
*
|
|
|
|
* @ignore
|
|
|
|
*/
|
|
|
|
set data(href: string | null) {
|
2020-11-12 22:32:53 +00:00
|
|
|
if (href != undefined) {
|
|
|
|
const attr = document.createAttribute("data");
|
|
|
|
attr.value = href;
|
|
|
|
this.attributes.setNamedItem(attr);
|
|
|
|
} else {
|
|
|
|
this.attributes.removeNamedItem("data");
|
|
|
|
}
|
2019-09-14 19:40:19 +00:00
|
|
|
}
|
|
|
|
|
2020-11-16 22:52:39 +00:00
|
|
|
/**
|
|
|
|
* Checks if the given element may be polyfilled with this one.
|
|
|
|
*
|
|
|
|
* @param elem Element to check.
|
|
|
|
* @return True if the element looks like a flash object.
|
|
|
|
*/
|
|
|
|
static is_interdictable(elem: HTMLElement): boolean {
|
2020-11-12 22:32:53 +00:00
|
|
|
const data = elem.attributes.getNamedItem("data")?.value.toLowerCase();
|
|
|
|
if (!data) {
|
2020-05-12 06:33:46 +00:00
|
|
|
let has_movie = false;
|
2020-11-12 22:32:53 +00:00
|
|
|
const params = elem.getElementsByTagName("param");
|
2020-05-12 22:24:41 +00:00
|
|
|
for (let i = 0; i < params.length; i++) {
|
2020-05-12 06:33:46 +00:00
|
|
|
if (params[i].name == "movie" && params[i].value) {
|
|
|
|
has_movie = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!has_movie) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-11-12 22:32:53 +00:00
|
|
|
|
|
|
|
const type = elem.attributes.getNamedItem("type")?.value.toLowerCase();
|
|
|
|
const classid = elem.attributes
|
|
|
|
.getNamedItem("classid")
|
|
|
|
?.value.toLowerCase();
|
2020-05-12 22:24:41 +00:00
|
|
|
if (
|
2020-11-12 22:32:53 +00:00
|
|
|
type === FLASH_MIMETYPE.toLowerCase() ||
|
|
|
|
type === FUTURESPLASH_MIMETYPE.toLowerCase() ||
|
|
|
|
type === FLASH7_AND_8_MIMETYPE.toLowerCase() ||
|
|
|
|
type === FLASH_MOVIE_MIMETYPE.toLowerCase()
|
2020-05-12 22:24:41 +00:00
|
|
|
) {
|
2020-03-21 01:27:59 +00:00
|
|
|
return true;
|
2020-11-12 22:32:53 +00:00
|
|
|
} else if (classid === FLASH_ACTIVEX_CLASSID.toLowerCase()) {
|
2020-03-21 01:27:59 +00:00
|
|
|
return true;
|
2020-05-12 22:24:41 +00:00
|
|
|
} else if (
|
2020-11-12 22:32:53 +00:00
|
|
|
(type == null || type === "") &&
|
|
|
|
(classid == null || classid === "")
|
2020-05-12 22:24:41 +00:00
|
|
|
) {
|
2020-11-16 22:57:29 +00:00
|
|
|
const params = paramsOf(elem);
|
2020-11-16 21:54:35 +00:00
|
|
|
if (data && isSwfFilename(data)) {
|
2020-07-14 13:53:08 +00:00
|
|
|
return true;
|
2020-11-16 21:54:35 +00:00
|
|
|
} else if (params && params.movie && isSwfFilename(params.movie)) {
|
2020-07-14 13:53:08 +00:00
|
|
|
return true;
|
2020-03-21 01:27:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2019-08-22 01:02:43 +00:00
|
|
|
}
|
|
|
|
|
2020-11-16 22:52:39 +00:00
|
|
|
/**
|
|
|
|
* Creates a RuffleObject that will polyfill and replace the given element.
|
|
|
|
*
|
|
|
|
* @param elem Element to replace.
|
|
|
|
* @return Created RuffleObject.
|
|
|
|
*/
|
|
|
|
static from_native_object_element(elem: HTMLElement): RuffleObject {
|
2020-11-12 22:32:53 +00:00
|
|
|
const external_name = register_element("ruffle-object", RuffleObject);
|
|
|
|
const ruffle_obj: RuffleObject = <RuffleObject>(
|
|
|
|
document.createElement(external_name)
|
|
|
|
);
|
2020-11-16 21:46:32 +00:00
|
|
|
ruffle_obj.copyElement(elem);
|
2019-08-22 01:02:43 +00:00
|
|
|
|
|
|
|
return ruffle_obj;
|
|
|
|
}
|
2020-11-12 22:32:53 +00:00
|
|
|
}
|