mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-12 10:39:57 +00:00
Add <google-cast-launcher> custom element + misc changes
This commit is contained in:
@@ -33,7 +33,7 @@ import { onMessage, sendMessageResponse } from "../messageBridge";
|
|||||||
|
|
||||||
type ReceiverActionListener = (
|
type ReceiverActionListener = (
|
||||||
receiver: Receiver
|
receiver: Receiver
|
||||||
, receiverAction: typeof ReceiverAction) => void;
|
, receiverAction: string) => void;
|
||||||
|
|
||||||
type RequestSessionSuccessCallback = (
|
type RequestSessionSuccessCallback = (
|
||||||
session: Session
|
session: Session
|
||||||
|
|||||||
78
ext/src/shim/framework/GoogleCastLauncher.ts
Normal file
78
ext/src/shim/framework/GoogleCastLauncher.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom element for a cast button used by sites that injects
|
||||||
|
* a cast icon and manages visibility state and event handling.
|
||||||
|
*/
|
||||||
|
export default class GoogleCastLauncher extends HTMLElement {
|
||||||
|
constructor () {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.style.display = "none";
|
||||||
|
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.textContent = `
|
||||||
|
.cast_caf_state_c {
|
||||||
|
fill: var(--connected-color, #4285f4);
|
||||||
|
}
|
||||||
|
.cast_caf_state_d {
|
||||||
|
fill: var(--disconnected-color, #7d7d7d);
|
||||||
|
}
|
||||||
|
.cast_caf_state_h {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// tslint:disable:max-line-length
|
||||||
|
|
||||||
|
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
||||||
|
|
||||||
|
const icon = document.createElementNS(SVG_NAMESPACE, "svg");
|
||||||
|
const iconArch0 = document.createElementNS(SVG_NAMESPACE, "path");
|
||||||
|
const iconArch1 = document.createElementNS(SVG_NAMESPACE, "path");
|
||||||
|
const iconArch2 = document.createElementNS(SVG_NAMESPACE, "path");
|
||||||
|
const iconBox = document.createElementNS(SVG_NAMESPACE, "path");
|
||||||
|
const iconBoxFill = document.createElementNS(SVG_NAMESPACE, "path");
|
||||||
|
|
||||||
|
// Set SVG attributes
|
||||||
|
icon.setAttribute("x", "0");
|
||||||
|
icon.setAttribute("y", "0");
|
||||||
|
icon.setAttribute("width", "100%");
|
||||||
|
icon.setAttribute("height", "100%");
|
||||||
|
icon.setAttribute("viewBox", "0 0 24 24");
|
||||||
|
|
||||||
|
iconArch0.classList.add("cast_caf_state_d");
|
||||||
|
iconArch0.setAttribute("id", "cast_caf_icon_arch0");
|
||||||
|
iconArch0.setAttribute("d", "M1 18v3h3c0-1.7-1.34-3-3-3z");
|
||||||
|
|
||||||
|
iconArch1.classList.add("cast_caf_state_d");
|
||||||
|
iconArch1.setAttribute("id", "cast_caf_icon_arch1");
|
||||||
|
iconArch1.setAttribute("d", "M1 14v2c2.76 0 5 2.2 5 5h2c0-3.87-3.13-7-7-7z");
|
||||||
|
|
||||||
|
iconArch2.classList.add("cast_caf_state_d");
|
||||||
|
iconArch2.setAttribute("id", "cast_caf_icon_arch2");
|
||||||
|
iconArch2.setAttribute("d", "M1 10v2c4.97 0 9 4 9 9h2c0-6.08-4.93-11-11-11z");
|
||||||
|
|
||||||
|
iconBox.classList.add("cast_caf_state_d");
|
||||||
|
iconBox.setAttribute("id", "cast_caf_icon_box");
|
||||||
|
iconBox.setAttribute("d", "M21 3H3c-1.1 0-2 .9-2 2v3h2V5h18v14h-7v2h7c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z");
|
||||||
|
|
||||||
|
iconBoxFill.classList.add("cast_caf_state_h");
|
||||||
|
iconBoxFill.setAttribute("id", "cast_caf_icon_boxfill");
|
||||||
|
iconBoxFill.setAttribute("d", "M5 7v1.63C8 8.6 13.37 14 13.37 17H19V7z");
|
||||||
|
|
||||||
|
// Add icon paths to SVG
|
||||||
|
icon.append(iconArch0, iconArch1, iconArch2, iconBox, iconBoxFill);
|
||||||
|
|
||||||
|
// tslint:enable:max-line-length
|
||||||
|
|
||||||
|
|
||||||
|
const shadow = this.attachShadow({ mode: "open" });
|
||||||
|
shadow.append(icon, style);
|
||||||
|
|
||||||
|
|
||||||
|
this.addEventListener("click", ev => {
|
||||||
|
console.info("<google-cast-launcher> onClick");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,14 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
import * as cast from "../../cast";
|
||||||
|
|
||||||
import CastOptions from "./CastOptions";
|
import CastOptions from "./CastOptions";
|
||||||
import CastSession from "./CastSession";
|
import CastSession from "./CastSession";
|
||||||
import CastStateEventData from "./CastStateEventData";
|
import CastStateEventData from "./CastStateEventData";
|
||||||
import SessionStateEventData from "./SessionStateEventData";
|
import SessionStateEventData from "./SessionStateEventData";
|
||||||
|
|
||||||
|
|
||||||
type EventHandler = (eventData:
|
export default class CastContext extends EventTarget {
|
||||||
CastStateEventData
|
|
||||||
| SessionStateEventData) => void;
|
|
||||||
|
|
||||||
export default class CastContext {
|
|
||||||
public addEventListener (type: string, handler: EventHandler): void {
|
|
||||||
console.info("STUB :: CastContext#addEventListener");
|
|
||||||
}
|
|
||||||
|
|
||||||
public endCurrentSession (stopCasting: boolean): void {
|
public endCurrentSession (stopCasting: boolean): void {
|
||||||
console.info("STUB :: CastContext#endCurrentSession");
|
console.info("STUB :: CastContext#endCurrentSession");
|
||||||
}
|
}
|
||||||
@@ -34,10 +28,6 @@ export default class CastContext {
|
|||||||
console.info("STUB :: CastContext#getSessionState");
|
console.info("STUB :: CastContext#getSessionState");
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeEventListener (type: string, handler: EventHandler): void {
|
|
||||||
console.info("STUB :: CastContext#removeEventListener");
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
public requestSession (): Promise<string> {
|
public requestSession (): Promise<string> {
|
||||||
console.info("STUB :: CastContext#requestSession");
|
console.info("STUB :: CastContext#requestSession");
|
||||||
@@ -47,3 +37,5 @@ export default class CastContext {
|
|||||||
console.info("STUB :: CastContext#setOptions");
|
console.info("STUB :: CastContext#setOptions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const instance = new CastContext();
|
||||||
|
|||||||
@@ -10,28 +10,15 @@ import MediaSessionEventData from "./MediaSessionEventData";
|
|||||||
import VolumeEventData from "./VolumeEventData";
|
import VolumeEventData from "./VolumeEventData";
|
||||||
|
|
||||||
|
|
||||||
type EventHandler = (eventData:
|
|
||||||
ApplicationStatusEventData
|
|
||||||
| ApplicationMetadataEventData
|
|
||||||
| ActiveInputStateEventData
|
|
||||||
| MediaSessionEventData
|
|
||||||
| VolumeEventData) => void;
|
|
||||||
|
|
||||||
type MessageListener = (namespace: string, message: string) => void;
|
type MessageListener = (namespace: string, message: string) => void;
|
||||||
|
|
||||||
|
|
||||||
export default class CastSession {
|
export default class CastSession extends EventTarget {
|
||||||
constructor (sessionObj: cast.Session, state: string) {
|
constructor (sessionObj: cast.Session, state: string) {
|
||||||
|
super();
|
||||||
console.info("STUB :: CastSession#constructor");
|
console.info("STUB :: CastSession#constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
public addEventListener (
|
|
||||||
type: string
|
|
||||||
, handler: EventHandler): void {
|
|
||||||
|
|
||||||
console.info("STUB :: CastSession#addEventListener");
|
|
||||||
}
|
|
||||||
|
|
||||||
public addMessageListener (
|
public addMessageListener (
|
||||||
namespace: string
|
namespace: string
|
||||||
, listener: MessageListener): void {
|
, listener: MessageListener): void {
|
||||||
@@ -98,13 +85,6 @@ export default class CastSession {
|
|||||||
console.info("STUB :: CastSession#loadMedia");
|
console.info("STUB :: CastSession#loadMedia");
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeEventListener (
|
|
||||||
type: string
|
|
||||||
, handler: EventHandler): void {
|
|
||||||
|
|
||||||
console.info("STUB :: CastSession#removeEventListener");
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeMessageListener (
|
public removeMessageListener (
|
||||||
namespace: string
|
namespace: string
|
||||||
, listener: MessageListener): void {
|
, listener: MessageListener): void {
|
||||||
|
|||||||
@@ -4,17 +4,12 @@ import RemotePlayer from "./RemotePlayer";
|
|||||||
import RemotePlayerChangedEvent from "./RemotePlayerChangedEvent";
|
import RemotePlayerChangedEvent from "./RemotePlayerChangedEvent";
|
||||||
|
|
||||||
|
|
||||||
type EventHandler = (event: RemotePlayerChangedEvent) => void;
|
export default class RemotePlayerController extends EventTarget {
|
||||||
|
|
||||||
export default class RemotePlayerController {
|
|
||||||
constructor (player: RemotePlayer) {
|
constructor (player: RemotePlayer) {
|
||||||
|
super();
|
||||||
console.info("STUB :: RemotePlayerController#constructor");
|
console.info("STUB :: RemotePlayerController#constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
public addEventListener (type: string, handler: EventHandler): void {
|
|
||||||
console.info("STUB :: RemotePlayerContoller#addEventListener");
|
|
||||||
}
|
|
||||||
|
|
||||||
public getFormattedTime (timeInSec: number): string {
|
public getFormattedTime (timeInSec: number): string {
|
||||||
const hours = Math.floor(timeInSec / 3600) % 24;
|
const hours = Math.floor(timeInSec / 3600) % 24;
|
||||||
const minutes = Math.floor(timeInSec / 60) % 60;
|
const minutes = Math.floor(timeInSec / 60) % 60;
|
||||||
@@ -41,10 +36,6 @@ export default class RemotePlayerController {
|
|||||||
console.info("STUB :: RemotePlayerController#playOrPause");
|
console.info("STUB :: RemotePlayerController#playOrPause");
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeEventListener (type: string, handler: EventHandler): void {
|
|
||||||
console.info("STUB :: RemotePlayerController#removeEventListener");
|
|
||||||
}
|
|
||||||
|
|
||||||
public seek (): void {
|
public seek (): void {
|
||||||
console.info("STUB :: RemotePlayerController#seek");
|
console.info("STUB :: RemotePlayerController#seek");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import ActiveInputStateEventData from "./classes/ActiveInputStateEventData";
|
|||||||
import ApplicationMetadata from "./classes/ApplicationMetadata";
|
import ApplicationMetadata from "./classes/ApplicationMetadata";
|
||||||
import ApplicationMetadataEventData from "./classes/ApplicationMetadataEventData";
|
import ApplicationMetadataEventData from "./classes/ApplicationMetadataEventData";
|
||||||
import ApplicationStatusEventData from "./classes/ApplicationStatusEventData";
|
import ApplicationStatusEventData from "./classes/ApplicationStatusEventData";
|
||||||
import CastContext from "./classes/CastContext";
|
import CastContext, { instance } from "./classes/CastContext";
|
||||||
import CastOptions from "./classes/CastOptions";
|
import CastOptions from "./classes/CastOptions";
|
||||||
import CastSession from "./classes/CastSession";
|
import CastSession from "./classes/CastSession";
|
||||||
import CastStateEventData from "./classes/CastStateEventData";
|
import CastStateEventData from "./classes/CastStateEventData";
|
||||||
@@ -26,12 +26,11 @@ import { ActiveInputState
|
|||||||
, SessionEventType
|
, SessionEventType
|
||||||
, SessionState } from "./enums";
|
, SessionState } from "./enums";
|
||||||
|
|
||||||
|
import GoogleCastLauncher from "./GoogleCastLauncher";
|
||||||
|
|
||||||
import { onMessage } from "../messageBridge";
|
import { onMessage } from "../messageBridge";
|
||||||
|
|
||||||
|
|
||||||
let castContext: CastContext = null;
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// Enums
|
// Enums
|
||||||
ActiveInputState, CastContextEventType, CastState, LoggerLevel
|
ActiveInputState, CastContextEventType, CastState, LoggerLevel
|
||||||
@@ -52,12 +51,7 @@ export default {
|
|||||||
...CastContext
|
...CastContext
|
||||||
|
|
||||||
, getInstance () {
|
, getInstance () {
|
||||||
if (castContext) {
|
return instance;
|
||||||
return castContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
castContext = new CastContext();
|
|
||||||
return castContext;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,3 +61,19 @@ export default {
|
|||||||
console.info("STUB :: cast.framework.setLoggerLevel");
|
console.info("STUB :: cast.framework.setLoggerLevel");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Framework API defines a <google-cast-launcher> element
|
||||||
|
* and a <button is="google-cast-button"> element extension,
|
||||||
|
* both of which produce the same result.
|
||||||
|
*
|
||||||
|
* Chrome allowed custom elements to extend <button> elements
|
||||||
|
* via Element#createShadowRoot, but the standard
|
||||||
|
* Element#attachShadow method supported in Firefox specifies a
|
||||||
|
* limited whitelist of elements that are extendable.
|
||||||
|
*
|
||||||
|
* It's not officially advertised in the cast docs, so it
|
||||||
|
* shouldn't be much of a compatibility issue to ignore it.
|
||||||
|
*/
|
||||||
|
customElements.define("google-cast-launcher", GoogleCastLauncher);
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import * as cast from "./cast";
|
|||||||
import { onMessage } from "./messageBridge";
|
import { onMessage } from "./messageBridge";
|
||||||
|
|
||||||
|
|
||||||
const global = (window as any);
|
const _window = (window as any);
|
||||||
|
|
||||||
if (!global.chrome) {
|
if (!_window.chrome) {
|
||||||
global.chrome = {};
|
_window.chrome = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
global.chrome.cast = cast;
|
_window.chrome.cast = cast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If loaded within a page via a <script> element,
|
* If loaded within a page via a <script> element,
|
||||||
@@ -25,12 +25,12 @@ if (document.currentScript) {
|
|||||||
|
|
||||||
// Load Framework API if requested
|
// Load Framework API if requested
|
||||||
if (currentScriptParams.get("loadCastFramework") === "1") {
|
if (currentScriptParams.get("loadCastFramework") === "1") {
|
||||||
if (!global.cast) {
|
if (!_window.cast) {
|
||||||
global.cast = {};
|
_window.cast = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
import("./framework").then(framework => {
|
import("./framework").then(framework => {
|
||||||
global.cast.framework = framework.default;
|
_window.cast.framework = framework.default;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ onMessage(message => {
|
|||||||
const bridgeInfo = message.data;
|
const bridgeInfo = message.data;
|
||||||
|
|
||||||
// Call page's API loaded function if defined
|
// Call page's API loaded function if defined
|
||||||
const readyFunction = global.__onGCastApiAvailable;
|
const readyFunction = _window.__onGCastApiAvailable;
|
||||||
if (readyFunction && typeof readyFunction === "function") {
|
if (readyFunction && typeof readyFunction === "function") {
|
||||||
readyFunction(bridgeInfo && bridgeInfo.isVersionCompatible);
|
readyFunction(bridgeInfo && bridgeInfo.isVersionCompatible);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user