import { InitiativeTrackerPlayerMessageHandlerV0, InitiativeTrackerPlayerMessageHandlerV1, InitiativeTrackerPlayerUiV0, InitiativeTrackerPlayerUiV1, } from "./initiativetracker/initiativetracker-player.js"; window.addEventListener("load", async () => { await Promise.all([ PrereleaseUtil.pInit(), BrewUtil2.pInit(), ]); ExcludeUtil.pInitialise().then(null); // don't await, as this is only used for search const hash = window.location.hash.slice(1); const views = new InitTrackerPlayerViews(); views.init({hash}); Hist.replaceHistoryHash(""); window.dispatchEvent(new Event("toolsLoaded")); }); /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class InitTrackerPlayerViews extends BaseComponent { constructor () { super(); TabUiUtil.decorate(this, {isInitMeta: true}); } init ({hash}) { const {v0: tokenV0, v1: tokenV1} = this.constructor._getTokens({hash}); const $wrpContent = $(`#page-content`).empty(); const iptTabMetas = [ new TabUiUtil.TabMeta({name: "Standard", hasBorder: true, hasBackground: true}), new TabUiUtil.TabMeta({name: "Manual (Legacy)", hasBorder: true, hasBackground: true}), ]; const tabMetas = this._renderTabs(iptTabMetas, {$parent: $wrpContent, additionalClassesWrpHeads: "initp__fullscreen-hidden"}); const [tabMetaV1, tabMetaV0] = tabMetas; const viewV1 = new InitTrackerPlayerViewV1({parent: this}); const viewV0 = new InitTrackerPlayerViewV0({parent: this}); viewV1.render({tabMeta: tabMetaV1, token: tokenV1}); viewV0.render({tabMeta: tabMetaV0, token: tokenV0}); } static _getTokens ({hash}) { hash = (hash || "").trim(); if (!hash) return {v0: null, v1: null}; if (hash.startsWith("v1:")) return {v0: null, v1: hash.slice(3)}; if (hash.startsWith("v0:")) return {v0: hash.slice(3), v1: null}; return {v0: null, v1: hash}; } } /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class InitiativeTrackerPlayerMessageHandlerPageV1 extends InitiativeTrackerPlayerMessageHandlerV1 { constructor ($wrpTab) { super(false); this._$wrpTab = $wrpTab; } initUi () { if (this._isUiInit) return; this._isUiInit = true; this._$wrpTab.find(`.initp__initial`).remove(); this._$wrpTab.find(`.initp__wrp_active`).show(); this._$meta = this._$wrpTab.find(`.initp__meta`); this._$head = this._$wrpTab.find(`.initp__header`); this._$rows = this._$wrpTab.find(`.initp__rows`); } static initUnloadMessage () { $(window).on("beforeunload", evt => { const message = `The connection will be closed`; (evt || window.event).message = message; return message; }); } } /** * PeerJS implementation. */ class InitTrackerPlayerViewV1 { constructor ({parent}) { this._parent = parent; } render ({tabMeta, token}) { const view = new InitiativeTrackerPlayerMessageHandlerPageV1(tabMeta.$wrpTab); const $iptPlayerName = $(``) .change(() => $iptServerToken.removeClass("form-control--error")) .disableSpellcheck(); const $iptServerToken = $(``) .change(() => $iptPlayerName.removeClass("form-control--error")) .disableSpellcheck(); if (token) $iptServerToken.val(token); const $btnConnect = $(``) .click(async () => { if (!$iptPlayerName.val().trim()) return $iptPlayerName.addClass("form-control--error"); if (!$iptServerToken.val().trim()) return $iptServerToken.addClass("form-control--error"); try { $btnConnect.attr("disabled", true); const ui = new InitiativeTrackerPlayerUiV1(view, $iptPlayerName.val(), $iptServerToken.val()); await ui.pInit(); InitiativeTrackerPlayerMessageHandlerPageV1.initUnloadMessage(); view.initUi(); } catch (e) { $btnConnect.attr("disabled", false); throw e; } }); $$(tabMeta.$wrpTab)`

The Player View is part of a peer-to-peer (i.e., serverless) system to allow players to connect to a DM's DM Screen initiative tracker. As a player, the usage is as follows:

  1. Enter a name into the "Player Name" field.
  2. Paste a "server token," provided by a DM, into the "Server Token" field.
  3. Click "Connect."

After a short delay, you should be connected to the DM and this page will change to display the encounter in the DM's tracker. Please note that this system is highly experimental. Your experience may vary.


Player Name
Server Token
${$iptPlayerName}
${$iptServerToken}
${$btnConnect}
`; const $body = $(`body`); $body.on("keypress", (evt) => { if (this._parent._getActiveTab() !== tabMeta) return; if (EventUtil.getKeyIgnoreCapsLock(evt) === "f" && EventUtil.noModifierKeys(evt) && !EventUtil.isInInput(evt)) { evt.preventDefault(); if (view.isActive) $body.toggleClass("is-fullscreen"); } }); } } /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class InitiativeTrackerPlayerMessageHandlerPageV0 extends InitiativeTrackerPlayerMessageHandlerV0 { constructor ($wrpTab) { super(false); this._$wrpTab = $wrpTab; } initUi () { if (this._isUiInit) return; this._isUiInit = true; this._$wrpTab.find(`.initp__initial`).remove(); this._$wrpTab.find(`.initp__wrp_active`).show(); this._$meta = this._$wrpTab.find(`.initp__meta`); this._$head = this._$wrpTab.find(`.initp__header`); this._$rows = this._$wrpTab.find(`.initp__rows`); $(window).on("beforeunload", evt => { if (this._clientData.client.isActive) { const message = `The connection will be closed`; (evt || window.event).message = message; return message; } }); } } /** * Legacy implementation. */ class InitTrackerPlayerViewV0 { constructor ({parent}) { this._parent = parent; } render ({tabMeta, token}) { const view = new InitiativeTrackerPlayerMessageHandlerPageV0(tabMeta.$wrpTab); const $iptServerToken = $(``).disableSpellcheck(); if (token) $iptServerToken.val(token); const $btnGenClientToken = $(``) .click(() => $dispWarning.remove()); const $iptClientToken = $(``).disableSpellcheck(); const ui = new InitiativeTrackerPlayerUiV0(view, $iptServerToken, $btnGenClientToken, $iptClientToken); ui.init(); const $dispWarning = $(`

Use of "Standard" mode is strongly recommended, as it provides a simplified workflow. If Standard mode is unavailable, "Manual" mode may be used instead.

`); $$(tabMeta.$wrpTab)`
${$dispWarning}

The Player View is part of a peer-to-peer (i.e., serverless) system to allow players to connect to a DM's DM Screen initiative tracker. As a player, the usage is as follows:

  1. Paste a "server token," provided by a DM, into the "Server Token" field, and click "Generate Client Token."
  2. Wait for a token to appear in the "Client Token" field, copy it, and send it to the DM.

Once the DM accepts your token, this page will change to display the encounter in the DM's tracker.


Server Token
Client Token
${$iptServerToken}
${$btnGenClientToken}
${$iptClientToken}
`; const $body = $(`body`); $body.on("keypress", (evt) => { if (this._parent._getActiveTab() !== tabMeta) return; if (EventUtil.getKeyIgnoreCapsLock(evt) === "f" && EventUtil.noModifierKeys(evt) && !EventUtil.isInInput(evt)) { evt.preventDefault(); if (view.isActive) $body.toggleClass("is-fullscreen"); } }); } }