Add <google-cast-launcher> custom element + misc changes

This commit is contained in:
hensm
2019-03-20 19:35:01 +00:00
parent 77162c794f
commit 04bf7a209d
7 changed files with 115 additions and 64 deletions

View File

@@ -33,7 +33,7 @@ import { onMessage, sendMessageResponse } from "../messageBridge";
type ReceiverActionListener = (
receiver: Receiver
, receiverAction: typeof ReceiverAction) => void;
, receiverAction: string) => void;
type RequestSessionSuccessCallback = (
session: Session

View 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");
});
}
}

View File

@@ -1,20 +1,14 @@
"use strict";
import * as cast from "../../cast";
import CastOptions from "./CastOptions";
import CastSession from "./CastSession";
import CastStateEventData from "./CastStateEventData";
import SessionStateEventData from "./SessionStateEventData";
type EventHandler = (eventData:
CastStateEventData
| SessionStateEventData) => void;
export default class CastContext {
public addEventListener (type: string, handler: EventHandler): void {
console.info("STUB :: CastContext#addEventListener");
}
export default class CastContext extends EventTarget {
public endCurrentSession (stopCasting: boolean): void {
console.info("STUB :: CastContext#endCurrentSession");
}
@@ -34,10 +28,6 @@ export default class CastContext {
console.info("STUB :: CastContext#getSessionState");
}
public removeEventListener (type: string, handler: EventHandler): void {
console.info("STUB :: CastContext#removeEventListener");
}
// @ts-ignore
public requestSession (): Promise<string> {
console.info("STUB :: CastContext#requestSession");
@@ -47,3 +37,5 @@ export default class CastContext {
console.info("STUB :: CastContext#setOptions");
}
}
export const instance = new CastContext();

View File

@@ -10,28 +10,15 @@ import MediaSessionEventData from "./MediaSessionEventData";
import VolumeEventData from "./VolumeEventData";
type EventHandler = (eventData:
ApplicationStatusEventData
| ApplicationMetadataEventData
| ActiveInputStateEventData
| MediaSessionEventData
| VolumeEventData) => void;
type MessageListener = (namespace: string, message: string) => void;
export default class CastSession {
export default class CastSession extends EventTarget {
constructor (sessionObj: cast.Session, state: string) {
super();
console.info("STUB :: CastSession#constructor");
}
public addEventListener (
type: string
, handler: EventHandler): void {
console.info("STUB :: CastSession#addEventListener");
}
public addMessageListener (
namespace: string
, listener: MessageListener): void {
@@ -98,13 +85,6 @@ export default class CastSession {
console.info("STUB :: CastSession#loadMedia");
}
public removeEventListener (
type: string
, handler: EventHandler): void {
console.info("STUB :: CastSession#removeEventListener");
}
public removeMessageListener (
namespace: string
, listener: MessageListener): void {

View File

@@ -4,17 +4,12 @@ import RemotePlayer from "./RemotePlayer";
import RemotePlayerChangedEvent from "./RemotePlayerChangedEvent";
type EventHandler = (event: RemotePlayerChangedEvent) => void;
export default class RemotePlayerController {
export default class RemotePlayerController extends EventTarget {
constructor (player: RemotePlayer) {
super();
console.info("STUB :: RemotePlayerController#constructor");
}
public addEventListener (type: string, handler: EventHandler): void {
console.info("STUB :: RemotePlayerContoller#addEventListener");
}
public getFormattedTime (timeInSec: number): string {
const hours = Math.floor(timeInSec / 3600) % 24;
const minutes = Math.floor(timeInSec / 60) % 60;
@@ -41,10 +36,6 @@ export default class RemotePlayerController {
console.info("STUB :: RemotePlayerController#playOrPause");
}
public removeEventListener (type: string, handler: EventHandler): void {
console.info("STUB :: RemotePlayerController#removeEventListener");
}
public seek (): void {
console.info("STUB :: RemotePlayerController#seek");
}

View File

@@ -6,7 +6,7 @@ import ActiveInputStateEventData from "./classes/ActiveInputStateEventData";
import ApplicationMetadata from "./classes/ApplicationMetadata";
import ApplicationMetadataEventData from "./classes/ApplicationMetadataEventData";
import ApplicationStatusEventData from "./classes/ApplicationStatusEventData";
import CastContext from "./classes/CastContext";
import CastContext, { instance } from "./classes/CastContext";
import CastOptions from "./classes/CastOptions";
import CastSession from "./classes/CastSession";
import CastStateEventData from "./classes/CastStateEventData";
@@ -26,12 +26,11 @@ import { ActiveInputState
, SessionEventType
, SessionState } from "./enums";
import GoogleCastLauncher from "./GoogleCastLauncher";
import { onMessage } from "../messageBridge";
let castContext: CastContext = null;
export default {
// Enums
ActiveInputState, CastContextEventType, CastState, LoggerLevel
@@ -52,12 +51,7 @@ export default {
...CastContext
, getInstance () {
if (castContext) {
return castContext;
}
castContext = new CastContext();
return castContext;
return instance;
}
}
@@ -67,3 +61,19 @@ export default {
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);

View File

@@ -5,13 +5,13 @@ import * as cast from "./cast";
import { onMessage } from "./messageBridge";
const global = (window as any);
const _window = (window as any);
if (!global.chrome) {
global.chrome = {};
if (!_window.chrome) {
_window.chrome = {};
}
global.chrome.cast = cast;
_window.chrome.cast = cast;
/**
* If loaded within a page via a <script> element,
@@ -25,12 +25,12 @@ if (document.currentScript) {
// Load Framework API if requested
if (currentScriptParams.get("loadCastFramework") === "1") {
if (!global.cast) {
global.cast = {};
if (!_window.cast) {
_window.cast = {};
}
import("./framework").then(framework => {
global.cast.framework = framework.default;
_window.cast.framework = framework.default;
});
}
}
@@ -42,7 +42,7 @@ onMessage(message => {
const bridgeInfo = message.data;
// Call page's API loaded function if defined
const readyFunction = global.__onGCastApiAvailable;
const readyFunction = _window.__onGCastApiAvailable;
if (readyFunction && typeof readyFunction === "function") {
readyFunction(bridgeInfo && bridgeInfo.isVersionCompatible);
}