From 3ec1e3a0114b0b98068e83e08c135759504d9f62 Mon Sep 17 00:00:00 2001 From: Idle <651462+reonZ@users.noreply.github.com> Date: Mon, 13 May 2024 15:17:38 +0200 Subject: [PATCH] adapt to null return for api element helpers --- src/settings.ts | 3 ++- src/tools/actionable.ts | 19 ++++++++++++------ src/tools/betterMerchant.ts | 39 +++++++++++++++++++++++------------- src/tools/effectsPanel.ts | 3 +++ src/tools/heroActions.ts | 40 ++++++++++++++++++++++++++----------- src/tools/mergeDamage.ts | 2 +- src/tools/spellsSummary.ts | 3 ++- src/tools/stances.ts | 4 +++- src/tools/targetHelper.ts | 14 ++++++++----- src/tools/templateHelper.ts | 6 +++--- src/tools/useButton.ts | 2 +- 11 files changed, 90 insertions(+), 45 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index 230b6d9..29f8112 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -14,6 +14,7 @@ const firstSettings: { tool: string; key: string }[] = []; function onRenderSettingsConfig(app: SettingsConfig, $html: JQuery) { const html = htmlElement($html); const tab = querySelector(html, `.tab[data-tab="${MODULE.id}"]`); + if (!tab) return; for (const { tool, key } of firstSettings) { const group = tab.querySelector(`[data-setting-id="${MODULE.id}.${key}"]`); @@ -31,7 +32,7 @@ function onRenderSettingsConfig(app: SettingsConfig, $html: JQuery) { const setting = game.settings.settings.get(settingId)!; if (setting.requiresReload) { - const label = querySelector(group, "label"); + const label = querySelector(group, "label")!; label.textContent = `${label.textContent} ${localize("settings.requiresReload")}`; } } diff --git a/src/tools/actionable.ts b/src/tools/actionable.ts index 47087a0..035699a 100644 --- a/src/tools/actionable.ts +++ b/src/tools/actionable.ts @@ -158,18 +158,24 @@ async function actionSheetPF2eRenderInner( const html = htmlElement($html); const label = localize("itemSheet.label"); const group = querySelector(html, "[data-drop-zone='self-applied-effect']"); - const dropZone = group.querySelector(".drop-zone.empty"); - const macro = await getActionMacro(item); + if (!group) return $html; + + const labelEl = querySelector(group, ":scope > label"); + const hintEl = querySelector(group, ".hint"); - querySelector(group, ":scope > label").innerText += ` / ${label}`; - querySelector(group, ".hint").innerText += localize("itemSheet.hint"); + if (labelEl) labelEl.innerText += ` / ${label}`; + if (hintEl) hintEl.innerText += localize("itemSheet.hint"); + const dropZone = group?.querySelector(".drop-zone.empty"); if (!dropZone) return $html; + const macro = await getActionMacro(item); + if (macro) { dropZone.outerHTML = await render("dropzone", { macro }); } else { - querySelector(dropZone, ".name").innerText += ` / ${label}`; + const nameEl = querySelector(dropZone, ".name"); + if (nameEl) nameEl.innerText += ` / ${label}`; } return $html; @@ -187,11 +193,12 @@ function actionSheetPF2eActivateListeners( item.system.actionType.value === "passive" || item.permission <= CONST.DOCUMENT_PERMISSION_LEVELS.LIMITED ) { - return $html; + return; } const html = htmlElement($html); const group = querySelector(html, "[data-drop-zone='self-applied-effect']"); + if (!group) return; addListener(group, "[data-action='open-macro-sheet']", async () => { const macro = await getActionMacro(item); diff --git a/src/tools/betterMerchant.ts b/src/tools/betterMerchant.ts index c0e1f04..d81b645 100644 --- a/src/tools/betterMerchant.ts +++ b/src/tools/betterMerchant.ts @@ -1,5 +1,4 @@ import { - ErrorPF2e, R, addListener, addListenerAll, @@ -496,6 +495,7 @@ async function browserRenderInner( html, "section.content .tab[data-tab='equipment'] .list-buttons" ); + if (!listButtons) return $html; html.classList.add("toolbelt-merchant"); @@ -611,6 +611,8 @@ function updateBrowser(selection: string[], skipAll = false) { if (!browserTab) return; const listButtons = querySelector(browserTab, ".list-buttons"); + if (!listButtons) return; + const tab = game.pf2e.compendiumBrowser.tabs.equipment; const selected = selection.length; const total = tab.currentIndex.length; @@ -640,7 +642,7 @@ function updateBrowser(selection: string[], skipAll = false) { } } - querySelector(listButtons, "button").disabled = selected === 0; + querySelector(listButtons, "button")!.disabled = selected === 0; for (const checkbox of checkboxes) { const checked = checkbox.checked; @@ -661,12 +663,14 @@ function browserActivateListeners( const data = getInMemory(this); if (!data?.actor?.isMerchant) return; - const actor = data.actor; const html = htmlElement($html); - const browser = this; - const tab = browser.tabs.equipment; const tabEl = querySelector(html, "section.content .tab[data-tab='equipment']"); const listButtons = querySelector(tabEl, ".list-buttons"); + if (!listButtons) return; + + const actor = data.actor; + const browser = this; + const tab = browser.tabs.equipment; if (data.type === "pull") { addListener(listButtons, "[data-action='add-to-merchant']", async () => { @@ -707,7 +711,7 @@ function browserActivateListeners( selection.length = 0; } - const checkboxes = tabEl.querySelectorAll(".item input"); + const checkboxes = tabEl!.querySelectorAll(".item input"); for (const checkbox of checkboxes) { const { uuid } = elementData(checkbox); checkbox.checked = selection.includes(uuid); @@ -827,14 +831,16 @@ async function lootSheetPF2eRenderInner( if (filter) { const priceElement = querySelector(itemElement, ".price"); - priceElement.classList.add(filter.ratio < 1 ? "cheap" : "expensive"); - priceElement.dataset.tooltip = `${filter.name} (${filter.ratio})`; + if (priceElement) { + priceElement.classList.add(filter.ratio < 1 ? "cheap" : "expensive"); + priceElement.dataset.tooltip = `${filter.name} (${filter.ratio})`; + } } } if (infiniteAll) { const quantityElement = querySelector(itemElement, ".quantity"); - quantityElement.innerHTML = INFINITE; + if (quantityElement) quantityElement.innerHTML = INFINITE; } } @@ -842,10 +848,14 @@ async function lootSheetPF2eRenderInner( const bulkElement = querySelector(html, ".total-bulk span"); const wealthElement = querySelector(html, ".coinage .wealth .item-name:last-child span"); - wealthElement.innerHTML = INFINITE; - bulkElement.innerHTML = game.i18n.format("PF2E.Actor.Inventory.TotalBulk", { - bulk: INFINITE, - }); + if (bulkElement) { + bulkElement.innerHTML = game.i18n.format("PF2E.Actor.Inventory.TotalBulk", { + bulk: INFINITE, + }); + } + if (wealthElement) { + wealthElement.innerHTML = INFINITE; + } } return $html; @@ -863,6 +873,7 @@ function lootSheetPF2eActivateListeners( const html = htmlElement($html); const betterMenu = querySelector(html, ".better-merchant"); + if (!betterMenu) return; addListener(betterMenu, "[data-action='open-equipment-tab']", () => { openEquipmentTab({ actor, type: "pull", owned: [] }); @@ -955,7 +966,7 @@ class FiltersMenu extends Application { const getItemData = (el: HTMLElement) => { const data = elementData<{ id: string; type: ItemFilterType }>( - closest(el, "[data-id]") + closest(el, "[data-id]")! ); const { type, id } = data; diff --git a/src/tools/effectsPanel.ts b/src/tools/effectsPanel.ts index cf9c5d2..f16e444 100644 --- a/src/tools/effectsPanel.ts +++ b/src/tools/effectsPanel.ts @@ -84,6 +84,7 @@ function onRenderEffectsPanel(panel: EffectsPanel, $html: JQuery) { effect.slug !== "persistent-damage" ) { const h1 = querySelector(effectsPanel, ".effect-info > h1"); + if (!h1) continue; appendHTMLFromString(h1, editIcon); addListener(h1, "[data-action='edit']", (event, el) => @@ -117,6 +118,8 @@ function onEditCondition(event: MouseEvent, el: HTMLElement, actor: ActorPF2e) { function getEffect(target: HTMLElement, actor: ActorPF2e) { const effectEl = closest(target, ".effect-item[data-item-id]"); + if (!effectEl) return; + const { itemId } = elementData(effectEl); return actor.items.get(itemId); } diff --git a/src/tools/heroActions.ts b/src/tools/heroActions.ts index 4b8ec67..55cf884 100644 --- a/src/tools/heroActions.ts +++ b/src/tools/heroActions.ts @@ -173,6 +173,7 @@ function characterSheetPF2eActivateListeners(this: CharacterSheetPF2e, html: HTM const actor = this.actor; const tab = querySelector(html, ".tab[data-tab=actions] .tab-content .tab[data-tab=encounter]"); const list = querySelector(tab, ".heroActions-list"); + if (!list || !tab) return; addListener(tab, "[data-action='hero-actions-draw']", () => drawHeroActions(actor)); addListener(tab, "[data-action='hero-actions-trade']", () => tradeHeroAction(actor, this)); @@ -187,6 +188,8 @@ function characterSheetPF2eActivateListeners(this: CharacterSheetPF2e, html: HTM ) => { addListenerAll(list, `[data-action="${action}"]`, (event: Event, el: HTMLElement) => { const actionEl = closest(el, "[data-uuid]"); + if (!actionEl) return; + const { uuid } = elementData(actionEl); callback(actor, uuid, actionEl); }); @@ -305,7 +308,10 @@ async function onTradeRequest(packet: SocketPacket, senderId: string) { content: await TextEditor.enrichHTML(content, { async: true }), onRender: (html) => { addListenerAll(html, "[data-action='description']", async (event, el) => { - const { uuid } = elementData(closest(el, ".action")); + const action = closest(el, ".action"); + if (!action) return; + + const { uuid } = elementData(action); const entry = await fromUuid(uuid); entry?.sheet.render(true); }); @@ -324,7 +330,7 @@ async function onTradeRequest(packet: SocketPacket, senderId: string) { packet.receiver.uuid = querySelector( html, "[name='action']:checked" - ).value; + )!.value; } if (game.user.isGM) { @@ -394,7 +400,10 @@ async function tradeHeroAction(actor: CharacterPF2e, app?: Application) { }); addListenerAll(html, "[data-action='description']", async (event, el) => { - const { uuid } = elementData(closest(el, ".action")); + const action = closest(el, ".action"); + if (!action) return; + + const { uuid } = elementData(action); const entry = await fromUuid(uuid); entry?.sheet.render(true); }); @@ -415,15 +424,20 @@ async function tradeHeroAction(actor: CharacterPF2e, app?: Application) { if (html === null) return; - const targetId = querySelector(html, ".header [name='target']").value; + const targetId = querySelector(html, ".header [name='target']")?.value; const target = game.actors.get(targetId); if (!target) return; - const actionUuid = querySelector(html, ".left [name='action']:checked").value; + const actionUuid = querySelector( + html, + ".left [name='action']:checked" + )?.value; const targetActionUUid = html.querySelector( `.right [name="action-${targetId}"]:checked` )?.value; + if (!actionUuid || !targetActionUUid) return; + if (target.isOwner && targetActionUUid) { const targetActions = others.find((x) => x.id === targetId)!.actions; @@ -452,7 +466,7 @@ async function tradeHeroAction(actor: CharacterPF2e, app?: Application) { }, receiver: { id: getOwner(target)?.id ?? game.users.activeGM!.id, - cid: targetId, + cid: targetId!, uuid: targetActionUUid, }, }); @@ -476,7 +490,7 @@ function exchangeHeroActions(trader1: ExchangeObj, trader2: ExchangeObj, senderI async function onExpandAction(actor: CharacterPF2e, uuid: string, actionEl: HTMLElement) { const duration = 0.4; - const summaryEl = querySelector(actionEl, ".item-summary"); + const summaryEl = querySelector(actionEl, ".item-summary")!; if (!summaryEl.classList.contains("loaded")) { const details = await getHeroActionDetails(uuid); @@ -579,7 +593,7 @@ async function getHeroActionDetails(uuid: string) { } function onDiscardAction(actor: CharacterPF2e, uuid: string, el: HTMLElement) { - const parent = closest(el, ".actions-list"); + const parent = closest(el, ".actions-list")!; const toDiscard = Number(elementData(parent).discard); const discarded = querySelectorArray(parent, ".item.discarded").map((x) => elementData(x).uuid); @@ -813,6 +827,8 @@ async function giveHeroActions(actor: CharacterPF2e) { onRender: (html) => { addListenerAll(html, "[data-action='expand']", (event, el) => { const actionEl = closest(el, "[data-uuid]"); + if (!actionEl) return; + const { uuid } = elementData(actionEl); onExpandAction(actor, uuid, actionEl); }); @@ -822,11 +838,11 @@ async function giveHeroActions(actor: CharacterPF2e) { if (!html) return; const selected = querySelectorArray(html, "[name='action']:checked").map((el) => { - const parent = closest(el, ".action"); + const parent = closest(el, ".action")!; return elementData<{ uuid: string; name: string; key: string }>(parent); }); - const asDrawn = html.querySelector("[name='drawn']")?.checked; - const withMessage = querySelector(html, "[name='message']").checked; + const asDrawn = querySelector(html, "[name='drawn']")?.checked; + const withMessage = querySelector(html, "[name='message']")!.checked; const tableUpdates = []; for (const { uuid, name, key } of selected) { @@ -860,7 +876,7 @@ async function removeHeroActions() { const translate = localize.sub("removeActions"); const onRender = (html: HTMLElement) => { - const allInput = querySelector(html, "[name='all']"); + const allInput = querySelector(html, "[name='all']")!; const actorInputs = querySelectorArray(html, "[name='actor']"); allInput.addEventListener("change", () => { diff --git a/src/tools/mergeDamage.ts b/src/tools/mergeDamage.ts index e93e2a3..1356dbc 100644 --- a/src/tools/mergeDamage.ts +++ b/src/tools/mergeDamage.ts @@ -53,7 +53,7 @@ async function onRenderChatMessage(message: ChatMessagePF2e, $html: JQuery) { html.classList.add("merged"); } - querySelector(html, ".dice-result .dice-total").append(buttons); + querySelector(html, ".dice-result .dice-total")?.append(buttons); addListener(buttons, "[data-action='merge-damage']", (event) => { event.stopPropagation(); diff --git a/src/tools/spellsSummary.ts b/src/tools/spellsSummary.ts index 73c7a95..bc73897 100644 --- a/src/tools/spellsSummary.ts +++ b/src/tools/spellsSummary.ts @@ -87,6 +87,7 @@ function characterSheetPF2eActivateListeners(this: CharacterSheetPF2e, html: HTM const spellcastingTab = getSpellcastingTab(html); const spellsSummaryTab = querySelector(spellcastingTab, ".tab.spells-summary"); + if (!spellsSummaryTab) return; addListenerAll( spellsSummaryTab, @@ -111,7 +112,7 @@ function toggleSpellcastingTab(this: CharacterSheetPF2e, html: HTMLElement, navI const isActive = querySelector( spellcastingNav, "[data-tab='spells-summary']" - ).classList.contains("active"); + )?.classList.contains("active"); const tabName = isActive ? "known-spells" : "spells-summary"; this.activateTab(tabName, { group: "spell-collections" }); diff --git a/src/tools/stances.ts b/src/tools/stances.ts index bdca826..12d4abc 100644 --- a/src/tools/stances.ts +++ b/src/tools/stances.ts @@ -135,6 +135,7 @@ function characterSheetPF2eActivateListeners(this: CharacterSheetPF2e, html: HTM if (!actor.isOwner) return; const encounterTab = getEncounterTab(html); + if (!encounterTab) return; addListenerAll(encounterTab, ".pf2e-stances .stance", (event, el) => { const uuid = elementData(el).effectUuid; @@ -195,9 +196,10 @@ async function onCreateCombatant(combatant: CombatantPF2e) { }); const effectUUID = html - ? querySelector(html, "[name='stance']:checked").value + ? querySelector(html, "[name='stance']:checked")?.value : stances[0].effectUUID; + if (!effectUUID) return; addStance(actor, effectUUID); } diff --git a/src/tools/targetHelper.ts b/src/tools/targetHelper.ts index 7dbeb5b..70f5c2b 100644 --- a/src/tools/targetHelper.ts +++ b/src/tools/targetHelper.ts @@ -352,8 +352,10 @@ async function chatMessageGetHTML(this: ChatMessagePF2e, html: HTMLElement) { async function damageChatMessageGetHTML(message: ChatMessagePF2e, html: HTMLElement) { const msgContent = querySelector(html, ".message-content"); + if (!msgContent) return; + const damageRows = querySelectorArray(msgContent, ".damage-application"); - const diceTotalElement = msgContent.querySelector(".dice-result .dice-total"); + const diceTotalElement = querySelector(msgContent, ".dice-result .dice-total"); if (!damageRows.length || !diceTotalElement) return; const data = await getMessageData(message); @@ -552,7 +554,7 @@ function onChatMessageDrop(event: DragEvent) { } async function onTargetButton(event: MouseEvent, btn: HTMLButtonElement, message: ChatMessagePF2e) { - const { rollIndex, targetUuid } = elementData(closest(btn, "[data-target-uuid]")); + const { rollIndex, targetUuid } = elementData(closest(btn, "[data-target-uuid]")!); const target = await fromUuid(targetUuid); if (!target) return; @@ -566,7 +568,7 @@ async function onTargetButton(event: MouseEvent, btn: HTMLButtonElement, message } requestAnimationFrame(() => { - onClickShieldBlock(btn, closest(btn, ".chat-message"), target); + onClickShieldBlock(btn, closest(btn, ".chat-message")!, target); }); return; @@ -635,7 +637,9 @@ async function spellChatMessageGetHTML(message: ChatMessagePF2e, html: HTMLEleme if (!data?.save) return; const msgContent = querySelector(html, ".message-content"); - const cardBtns = msgContent.querySelector(".card-buttons"); + if (!msgContent) return; + + const cardBtns = msgContent?.querySelector(".card-buttons"); const saveBtn = cardBtns?.querySelector("[data-action='spell-save']"); if (saveBtn && (game.user.isGM || message.isAuthor)) { @@ -817,7 +821,7 @@ async function rerollSave( if (!html) return; const rerollElement = querySelector(html, "[name='reroll']:checked"); - const reroll = rerollElement.value as keyof typeof REROLL; + const reroll = rerollElement!.value as keyof typeof REROLL; const isHeroReroll = reroll === "hero"; const keep = isHeroReroll ? "new" : reroll; diff --git a/src/tools/templateHelper.ts b/src/tools/templateHelper.ts index 99e9b7a..309f781 100644 --- a/src/tools/templateHelper.ts +++ b/src/tools/templateHelper.ts @@ -58,9 +58,9 @@ async function onCreateMeasuredTemplate( ); if (html) { - const target = querySelector(html, "[name='targets']:checked").value; - const targetNeutral = querySelector(html, "[name='neutral']").checked; - const targetSelf = querySelector(html, "[name='self']").checked; + const target = querySelector(html, "[name='targets']:checked")?.value; + const targetNeutral = querySelector(html, "[name='neutral']")?.checked; + const targetSelf = querySelector(html, "[name='self']")?.checked; const alliance = actor ? actor.alliance : user.isGM ? "opposition" : "party"; const opposition = alliance === "party" ? "opposition" : alliance === "opposition" ? "party" : null; diff --git a/src/tools/useButton.ts b/src/tools/useButton.ts index e711fe8..98da529 100644 --- a/src/tools/useButton.ts +++ b/src/tools/useButton.ts @@ -149,7 +149,7 @@ function createActionUseButton(item: AbilityItemPF2e | FeatPF2e) { } function getItemFromActionButton(actor: CharacterPF2e, btn: HTMLButtonElement) { - const { itemId } = elementData(closest(btn, "[data-item-id]")); + const { itemId } = elementData(closest(btn, "[data-item-id]")!); return actor.items.get>(itemId); }