diff --git a/src/Applet/Init.ts b/src/Applet/Init.ts index ba50b55..1c9bfe1 100644 --- a/src/Applet/Init.ts +++ b/src/Applet/Init.ts @@ -1,40 +1,48 @@ import { KeyControl } from "./Keyboard"; -/** - * A class decorator for automatically constructing - * class instances around elements on page load. - */ -export function Bind(selector: string) { - return (appletType: AppletConstructor) => { - const elements = document.querySelectorAll(selector); - for(let i = 0; i < elements.length; i++) { - const element = elements[i] as HTMLElement; - new appletType(element); - } - } -}; -export interface AppletConstructor { - new(element: HTMLElement): any -}; - -/** - * A class decorator for automatically constructing - * a KeyControl around a canvas on page load & fetching the render context. - */ -export function Game(selector: string, tabIndex = -1) { - return (gameType: GameConstructor) => { - const elements = document.querySelectorAll(selector); - for(let i = 0; i < elements.length; i++) { - const element = elements[i] as HTMLCanvasElement; - if(!(element instanceof HTMLCanvasElement)) continue; - - const cx = element.getContext("2d") as CanvasRenderingContext2D; - const keys = new KeyControl(element, tabIndex); - - new gameType(element, cx, keys); - } - } -}; export interface GameConstructor { new(canvas: HTMLCanvasElement, cx: CanvasRenderingContext2D, keys: KeyControl): any }; + +class Selection { + constructor(private elements: HTMLElement[]) {} + + /** + * Run a callback for every selected item. + */ + public forEach(callback: (e: HTMLElement) => {}) { + this.elements.forEach(callback); + } + + /** + * Run a callback for selected canvases, with a 2d context & KeyControl established for use. + */ + public forEachCanvas(callback: (canvas: HTMLCanvasElement, cx: CanvasRenderingContext2D, keys: KeyControl) => {}, tabIndex = -1) { + this.elements.forEach(e => { + if(e instanceof HTMLCanvasElement) { + const cx = e.getContext("2d") as CanvasRenderingContext2D; + const keys = new KeyControl(e, tabIndex); + + callback(e, cx, keys); + } + }); + } +} + +/** + * Wrap an HTML element or list of elements to bind them to behavior. + * + * @param selector A CSS selector or a literal Element + */ +export function Select(selector: string): Selection; +export function Select(selector: HTMLElement): Selection; +export function Select(selector: string | HTMLElement): Selection { + if(typeof selector === "string") { + const elementList = document.querySelectorAll(selector); + const elements: HTMLElement[] = Array.prototype.slice.call(elementList); + return new Selection(elements); + } else { + const elements = [selector]; + return new Selection(elements); + } +} diff --git a/src/Applet/demo.ts b/src/Applet/demo.ts index 9d16810..448648b 100644 --- a/src/Applet/demo.ts +++ b/src/Applet/demo.ts @@ -1,9 +1,8 @@ -import { Bind } from "./Init"; +import { Select } from "./Init"; import { KeyControl, KeyHandler, KeyName } from "./Keyboard"; import { Loop } from "./Loop"; -@Bind("#KeyTest") -export class Test implements KeyHandler { +class Test implements KeyHandler { private keys: KeyControl; constructor(public div: HTMLElement) { @@ -29,8 +28,7 @@ export class Test implements KeyHandler { } } -@Bind("#LoopTest") -export class LoopTest { +class LoopTest { frames: number = 0; constructor(public div: HTMLElement) { @@ -45,3 +43,8 @@ export class LoopTest { loop.start(); } } + +export function BindDemos(): void { + Select("#KeyTest").forEach(e => new Test(e)); + Select("#LoopTest").forEach(e => new LoopTest(e)); +} diff --git a/src/Ecs/test.ts b/src/Ecs/test.ts index ac1be13..3cae37b 100644 --- a/src/Ecs/test.ts +++ b/src/Ecs/test.ts @@ -1,4 +1,4 @@ -import { Bind, Game } from "../Applet/Init"; +import { Select } from "../Applet/Init"; import { KeyControl } from "../Applet/Keyboard"; import { Loop } from "../Applet/Loop"; import { DrawSet, Layer } from "../Applet/Render"; @@ -45,8 +45,7 @@ class TestData extends Data { }; } -@Bind("#EcsJoinTest") -export class EcsJoinTest { +class EcsJoinTest { constructor(pre: HTMLElement) { const data = new TestData(); pre.innerText = JSON.stringify({ @@ -58,8 +57,7 @@ export class EcsJoinTest { } } -@Bind("#EcsLookupTest") -export class EcsLookupTest { +class EcsLookupTest { constructor(pre: HTMLElement) { const data = new TestData(); const applesMaybeCarrots = Join(data, "apple", "id").map(([apple, id]) => ({ @@ -70,8 +68,7 @@ export class EcsLookupTest { } } -@Bind("#EcsRemoveTest") -export class EcsRemoveTest { +class EcsRemoveTest { constructor(pre: HTMLElement) { const data = new TestData(); const beforeDelete = Join(data, "apple", "carrot", "id",); @@ -84,8 +81,7 @@ export class EcsRemoveTest { } } -@Bind("#EcsCreateTest") -export class EcsCreateTest { +class EcsCreateTest { constructor(pre: HTMLElement) { const data = new TestData(); const beforeCreate = Join(data, "apple", "banana", "carrot", "id"); @@ -103,8 +99,7 @@ export class EcsCreateTest { } } -@Game("#RenderTest") -export class LoopTest { +class LoopTest { data = new Data(); constructor(public canvas: HTMLCanvasElement, cx: CanvasRenderingContext2D, keys: KeyControl) { @@ -174,3 +169,11 @@ export class LoopTest { }); } } + +export function BindTests(): void { + Select("#EcsJoinTest").forEach(e => new EcsJoinTest(e)); + Select("#EcsLookupTest").forEach(e => new EcsLookupTest(e)); + Select("#EcsRemoveTest").forEach(e => new EcsRemoveTest(e)); + Select("#EcsCreateTest").forEach(e => new EcsCreateTest(e)); + Select("#RenderTest").forEachCanvas((c, cx, keys) => new LoopTest(c, cx, keys)); +} diff --git a/src/Game/Main.ts b/src/Game/Main.ts index 521cb09..86c5367 100644 --- a/src/Game/Main.ts +++ b/src/Game/Main.ts @@ -1,18 +1,15 @@ import subscribe from "callbag-subscribe"; -import { Game } from "../Applet/Init"; import { KeyControl, KeyName } from "../Applet/Keyboard"; import { DrawSet } from "../Applet/Render"; import { Location, Polygon, RenderBounds } from "../Ecs/Components"; import { Create } from "../Ecs/Data"; -import {} from "../Ecs/Lockstep"; import { RunRenderBounds } from "../Ecs/Renderers"; import { LockstepClient } from "../Net/LockstepClient"; import { Loopback } from "../Net/LoopbackServer"; import { Data, Engine } from "./GameComponents"; import { Buttons } from "./Input"; -@Game("#GameCanvas") export class Main extends LockstepClient { buttons = new Buttons(); diff --git a/src/index.ts b/src/index.ts index c840bf5..0971c53 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,7 @@ -import "./Game/Main"; -import "./Ecs/test"; +import { Select } from "./Applet/Init"; +import { BindTests } from "./Ecs/test"; +import { Main } from "./Game/Main"; + +Select("#GameCanvas").forEachCanvas((c, cx, keys) => new Main(c, cx, keys)); + +BindTests();