This commit is contained in:
TheGiddyLimit
2024-04-02 22:46:42 +01:00
parent d075252329
commit 5e0cc455b9
112 changed files with 2980 additions and 397 deletions

View File

@@ -302,6 +302,7 @@ class BestiaryPage extends ListPageMultiSource {
colTransforms: {
name: UtilsTableview.COL_TRANSFORM_NAME,
source: UtilsTableview.COL_TRANSFORM_SOURCE,
page: UtilsTableview.COL_TRANSFORM_PAGE,
size: {name: "Size", transform: size => Renderer.utils.getRenderedSize(size)},
type: {name: "Type", transform: type => Parser.monTypeToFullObj(type).asText},
alignment: {name: "Alignment", transform: align => Parser.alignmentListToFull(align)},

View File

@@ -226,7 +226,7 @@ class BlocklistUi {
<button class="ve-col-1 sort btn btn-default btn-xs" disabled>&nbsp;</button>
</div>`;
const $wrpList = $(`<div class="list-display-only smooth-scroll overflow-y-auto h-100 min-h-0"></div>`);
const $wrpList = $(`<div class="list-display-only smooth-scroll ve-overflow-y-auto h-100 min-h-0"></div>`);
$$(this._$wrpContent.empty())`
${this._$wrpControls}

View File

@@ -2375,7 +2375,7 @@ ClassesPage.ClassBookView = class extends BookModeViewBase {
// Main panel
const $tblBook = $(`<table class="w-100 stats stats--book stats--book-large stats--bkmv"></div>`);
$$`<div class="ve-flex-col overflow-y-auto container">${$tblBook}</div>`.appendTo($wrpContent);
$$`<div class="ve-flex-col ve-overflow-y-auto container">${$tblBook}</div>`.appendTo($wrpContent);
const renderStack = [];
Renderer.get().setFirstSection(true);

View File

@@ -1432,7 +1432,17 @@ class CreatureParser extends BaseParser {
const spellcasting = [];
stats[prop] = stats[prop].map(ent => {
if (!ent.name || !ent.name.toLowerCase().includes("spellcasting")) return ent;
const parsed = SpellcastingTraitConvert.tryParseSpellcasting(ent, {isMarkdown, cbErr: options.cbErr, displayAs: prop, actions: stats.action, reactions: stats.reaction});
const parsed = SpellcastingTraitConvert.tryParseSpellcasting(
ent,
{
isMarkdown,
cbMan: (wrn) => options.cbWarning(`${stats.name ? `(${stats.name}) ` : ""}${wrn}`),
cbErr: (err) => options.cbWarning(`${stats.name ? `(${stats.name}) ` : ""}${err}`),
displayAs: prop,
actions: stats.action,
reactions: stats.reaction,
},
);
if (!parsed) return ent;
spellcasting.push(parsed);
return null;

View File

@@ -645,7 +645,130 @@ class AlignmentConvert {
globalThis.AlignmentConvert = AlignmentConvert;
class TraitActionTag {
static _doTag ({m, cbMan, prop, outProp}) {
static _TAGS = { // true = map directly; string = map to this string
trait: {
"turn immunity": "Turn Immunity",
"brute": "Brute",
"antimagic susceptibility": "Antimagic Susceptibility",
"sneak attack": "Sneak Attack",
"reckless": "Reckless",
"web sense": "Web Sense",
"flyby": "Flyby",
"pounce": "Pounce",
"water breathing": "Water Breathing",
"turn resistance": "Turn Resistance",
"turn defiance": "Turn Resistance",
"turning defiance": "Turn Resistance",
"turn resistance aura": "Turn Resistance",
"undead fortitude": "Undead Fortitude",
"aggressive": "Aggressive",
"illumination": "Illumination",
"rampage": "Rampage",
"rejuvenation": "Rejuvenation",
"web walker": "Web Walker",
"incorporeal movement": "Incorporeal Movement",
"incorporeal passage": "Incorporeal Movement",
"keen hearing and smell": "Keen Senses",
"keen sight and smell": "Keen Senses",
"keen hearing and sight": "Keen Senses",
"keen hearing": "Keen Senses",
"keen smell": "Keen Senses",
"keen senses": "Keen Senses",
"hold breath": "Hold Breath",
"charge": "Charge",
"fey ancestry": "Fey Ancestry",
"siege monster": "Siege Monster",
"pack tactics": "Pack Tactics",
"regeneration": "Regeneration",
"shapechanger": "Shapechanger",
"false appearance": "False Appearance",
"spider climb": "Spider Climb",
"sunlight sensitivity": "Sunlight Sensitivity",
"sunlight hypersensitivity": "Sunlight Sensitivity",
"light sensitivity": "Light Sensitivity",
"vampire weaknesses": "Sunlight Sensitivity",
"amphibious": "Amphibious",
"legendary resistance": "Legendary Resistances",
"magic weapon": "Magic Weapons",
"magic weapons": "Magic Weapons",
"magic resistance": "Magic Resistance",
"spell immunity": "Spell Immunity",
"ambush": "Ambusher",
"ambusher": "Ambusher",
"amorphous": "Amorphous",
"amorphous form": "Amorphous",
"death burst": "Death Burst",
"death throes": "Death Burst",
"devil's sight": "Devil's Sight",
"devil sight": "Devil's Sight",
"immutable form": "Immutable Form",
"tree stride": "Tree Stride",
"unusual nature": "Unusual Nature",
"tunneler": "Tunneler",
"beast of burden": "Beast of Burden",
},
action: {
"multiattack": "Multiattack",
"frightful presence": "Frightful Presence",
"teleport": "Teleport",
"swallow": "Swallow",
"tentacle": "Tentacles",
"tentacles": "Tentacles",
"change shape": "Shapechanger",
},
reaction: {
"parry": "Parry",
},
bonus: {
"change shape": "Shapechanger",
},
legendary: {
// unused
},
mythic: {
// unused
},
};
static _TAGS_DEEP = {
action: {
"Swallow": strEntries => /\bswallowed\b/i.test(strEntries),
},
};
static _doAdd ({tags, tag, allowlist}) {
if (allowlist && !allowlist.has(tag)) return;
tags.add(tag);
}
static _doTag ({m, cbMan, prop, tags, allowlist}) {
if (!m[prop]) return;
m[prop]
@@ -658,36 +781,36 @@ class TraitActionTag {
.replace(/\([^)]+\)/g, "") // Remove parentheses
.trim();
const mapped = TraitActionTag.tags[prop][cleanName];
const mapped = TraitActionTag._TAGS[prop][cleanName];
if (mapped) {
if (mapped === true) return m[outProp].add(t.name);
return m[outProp].add(mapped);
if (mapped === true) return this._doAdd({tags, tag: t.name, allowlist});
return this._doAdd({tags, tag: mapped, allowlist});
}
if (this._isTraits(prop)) {
if (cleanName.startsWith("keen ")) return m[outProp].add("Keen Senses");
if (cleanName.endsWith(" absorption")) return m[outProp].add("Damage Absorption");
if (cleanName.startsWith("keen ")) return this._doAdd({tags, tag: "Keen Senses", allowlist});
if (cleanName.endsWith(" absorption")) return this._doAdd({tags, tag: "Damage Absorption", allowlist});
}
if (this._isActions(prop)) {
if (/\bbreath\b/.test(cleanName)) return m[outProp].add("Breath Weapon");
if (/\bbreath\b/.test(cleanName)) return this._doAdd({tags, tag: "Breath Weapon", allowlist});
}
if (cbMan) cbMan(prop, outProp, cleanName);
if (cbMan) cbMan(prop, tags, cleanName);
});
}
static _doTagDeep ({m, prop, outProp}) {
if (!TraitActionTag.tagsDeep[prop]) return;
static _doTagDeep ({m, prop, tags, allowlist}) {
if (!TraitActionTag._TAGS_DEEP[prop]) return;
if (!m[prop]) return;
m[prop].forEach(t => {
if (!t.entries) return;
const strEntries = JSON.stringify(t.entries);
Object.entries(TraitActionTag.tagsDeep[prop])
Object.entries(TraitActionTag._TAGS_DEEP[prop])
.forEach(([tagName, fnShouldTag]) => {
if (fnShouldTag(strEntries)) m[outProp].add(tagName);
if (fnShouldTag(strEntries)) this._doAdd({tags, tag: tagName, allowlist});
});
});
}
@@ -695,138 +818,21 @@ class TraitActionTag {
static _isTraits (prop) { return prop === "trait"; }
static _isActions (prop) { return prop === "action"; }
static tryRun (m, cbMan) {
m.traitTags = new Set(m.traitTags || []);
m.actionTags = new Set(m.actionTags || []);
static tryRun (m, {cbMan, allowlistTraitTags, allowlistActionTags} = {}) {
const traitTags = new Set(m.traitTags || []);
const actionTags = new Set(m.actionTags || []);
this._doTag({m, cbMan, prop: "trait", outProp: "traitTags"});
this._doTag({m, cbMan, prop: "action", outProp: "actionTags"});
this._doTag({m, cbMan, prop: "reaction", outProp: "actionTags"});
this._doTag({m, cbMan, prop: "bonus", outProp: "actionTags"});
this._doTag({m, cbMan, prop: "trait", tags: traitTags, allowlist: allowlistTraitTags});
this._doTag({m, cbMan, prop: "action", tags: actionTags, allowlist: allowlistActionTags});
this._doTag({m, cbMan, prop: "reaction", tags: actionTags, allowlist: allowlistActionTags});
this._doTag({m, cbMan, prop: "bonus", tags: actionTags, allowlist: allowlistActionTags});
this._doTagDeep({m, prop: "action", outProp: "actionTags"});
this._doTagDeep({m, prop: "action", tags: actionTags, allowlist: allowlistActionTags});
if (!m.traitTags.size) delete m.traitTags;
else m.traitTags = [...m.traitTags].sort(SortUtil.ascSortLower);
if (!m.actionTags.size) delete m.actionTags;
else m.actionTags = [...m.actionTags].sort(SortUtil.ascSortLower);
if (traitTags.size) m.traitTags = [...traitTags].sort(SortUtil.ascSortLower);
if (actionTags.size) m.actionTags = [...actionTags].sort(SortUtil.ascSortLower);
}
}
TraitActionTag.tags = { // true = map directly; string = map to this string
trait: {
"turn immunity": "Turn Immunity",
"brute": "Brute",
"antimagic susceptibility": "Antimagic Susceptibility",
"sneak attack": "Sneak Attack",
"reckless": "Reckless",
"web sense": "Web Sense",
"flyby": "Flyby",
"pounce": "Pounce",
"water breathing": "Water Breathing",
"turn resistance": "Turn Resistance",
"turn defiance": "Turn Resistance",
"turning defiance": "Turn Resistance",
"turn resistance aura": "Turn Resistance",
"undead fortitude": "Undead Fortitude",
"aggressive": "Aggressive",
"illumination": "Illumination",
"rampage": "Rampage",
"rejuvenation": "Rejuvenation",
"web walker": "Web Walker",
"incorporeal movement": "Incorporeal Movement",
"incorporeal passage": "Incorporeal Movement",
"keen hearing and smell": "Keen Senses",
"keen sight and smell": "Keen Senses",
"keen hearing and sight": "Keen Senses",
"keen hearing": "Keen Senses",
"keen smell": "Keen Senses",
"keen senses": "Keen Senses",
"hold breath": "Hold Breath",
"charge": "Charge",
"fey ancestry": "Fey Ancestry",
"siege monster": "Siege Monster",
"pack tactics": "Pack Tactics",
"regeneration": "Regeneration",
"shapechanger": "Shapechanger",
"false appearance": "False Appearance",
"spider climb": "Spider Climb",
"sunlight sensitivity": "Sunlight Sensitivity",
"sunlight hypersensitivity": "Sunlight Sensitivity",
"light sensitivity": "Light Sensitivity",
"vampire weaknesses": "Sunlight Sensitivity",
"amphibious": "Amphibious",
"legendary resistance": "Legendary Resistances",
"magic weapon": "Magic Weapons",
"magic weapons": "Magic Weapons",
"magic resistance": "Magic Resistance",
"spell immunity": "Spell Immunity",
"ambush": "Ambusher",
"ambusher": "Ambusher",
"amorphous": "Amorphous",
"amorphous form": "Amorphous",
"death burst": "Death Burst",
"death throes": "Death Burst",
"devil's sight": "Devil's Sight",
"devil sight": "Devil's Sight",
"immutable form": "Immutable Form",
"tree stride": "Tree Stride",
"unusual nature": "Unusual Nature",
"tunneler": "Tunneler",
},
action: {
"multiattack": "Multiattack",
"frightful presence": "Frightful Presence",
"teleport": "Teleport",
"swallow": "Swallow",
"tentacle": "Tentacles",
"tentacles": "Tentacles",
"change shape": "Shapechanger",
},
reaction: {
"parry": "Parry",
},
bonus: {
"change shape": "Shapechanger",
},
legendary: {
// unused
},
mythic: {
// unused
},
};
TraitActionTag.tagsDeep = {
action: {
"Swallow": strEntries => /\bswallowed\b/i.test(strEntries),
},
};
globalThis.TraitActionTag = TraitActionTag;
@@ -1373,85 +1379,93 @@ class SpellcastingTraitConvert {
});
}
static tryParseSpellcasting (ent, {isMarkdown, cbErr, displayAs, actions, reactions}) {
static tryParseSpellcasting (ent, {isMarkdown, cbMan, cbErr, displayAs, actions, reactions}) {
try {
return this._parseSpellcasting({ent, isMarkdown, displayAs, actions, reactions});
return this._parseSpellcasting({ent, isMarkdown, cbMan, displayAs, actions, reactions});
} catch (e) {
cbErr && cbErr(`Failed to parse spellcasting: ${e.message}`);
return null;
}
}
static _parseSpellcasting ({ent, isMarkdown, displayAs, actions, reactions}) {
let hasAnyHeader = false;
static _parseSpellcasting ({ent, isMarkdown, cbMan, displayAs, actions, reactions}) {
const spellcastingEntry = {
"name": ent.name,
"type": "spellcasting",
"headerEntries": [this._parseToHit(ent.entries[0])],
"headerEntries": [],
};
ent.entries.forEach((thisLine, i) => {
thisLine = thisLine.replace(/,\s*\*/g, ",*"); // put asterisks on the correct side of commas
if (i === 0) return;
const perDurations = [
{re: /\/rest/i, prop: "rest"},
{re: /\/day/i, prop: "daily"},
{re: /\/week/i, prop: "weekly"},
{re: /\/month/i, prop: "monthly"},
{re: /\/yeark/i, prop: "yearly"},
];
const headerEntry = this._getMutHeaderEntries({ent, cbMan, spellcastingEntry});
spellcastingEntry.headerEntries.push(headerEntry);
const perDuration = perDurations.find(({re}) => re.test(thisLine));
let hasAnyHeader = false;
ent.entries
.slice(1)
.forEach(line => {
line = line.replace(/,\s*\*/g, ",*"); // put asterisks on the correct side of commas
if (perDuration) {
hasAnyHeader = true;
let property = thisLine.substring(0, 1) + (/ each(?::| - )/.test(thisLine) ? "e" : "");
const value = this._getParsedSpells({thisLine, isMarkdown});
if (!spellcastingEntry[perDuration.prop]) spellcastingEntry[perDuration.prop] = {};
spellcastingEntry[perDuration.prop][property] = value;
} else if (/^Constant(?::| -) /.test(thisLine)) {
hasAnyHeader = true;
spellcastingEntry.constant = this._getParsedSpells({thisLine, isMarkdown});
} else if (/^At[- ][Ww]ill(?::| -) /.test(thisLine)) {
hasAnyHeader = true;
spellcastingEntry.will = this._getParsedSpells({thisLine, isMarkdown});
} else if (thisLine.includes("Cantrip")) {
hasAnyHeader = true;
const value = this._getParsedSpells({thisLine, isMarkdown});
if (!spellcastingEntry.spells) spellcastingEntry.spells = {"0": {"spells": []}};
spellcastingEntry.spells["0"].spells = value;
} else if (/[- ][Ll]evel/.test(thisLine) && /(?::| -) /.test(thisLine)) {
hasAnyHeader = true;
let property = thisLine.substring(0, 1);
const allSpells = this._getParsedSpells({thisLine, isMarkdown});
spellcastingEntry.spells = spellcastingEntry.spells || {};
const usesMeta = this._getUsesMeta({line, isMarkdown});
if (usesMeta) {
hasAnyHeader = true;
const out = {};
if (thisLine.includes(" slot")) {
const mWarlock = /^(\d)..(?:[- ][Ll]evel)?-(\d)..[- ][Ll]evel \((\d) (\d)..[- ][Ll]evel slots?\)/.exec(thisLine);
if (mWarlock) {
out.lower = parseInt(mWarlock[1]);
out.slots = parseInt(mWarlock[3]);
property = mWarlock[4];
} else {
const mSlots = /\((\d) slots?\)/.exec(thisLine);
if (!mSlots) throw new Error(`Could not find slot count!`);
out.slots = parseInt(mSlots[1]);
const value = this._getParsedSpells({line: usesMeta.lineRemaining});
MiscUtil.getOrSet(spellcastingEntry, usesMeta.prop, usesMeta.propPer, value);
return;
}
if (/^Constant(?::| -) /.test(line)) {
hasAnyHeader = true;
spellcastingEntry.constant = this._getParsedSpells({line, isMarkdown});
return;
}
if (/^At[- ][Ww]ill(?::| -) /.test(line)) {
hasAnyHeader = true;
spellcastingEntry.will = this._getParsedSpells({line, isMarkdown});
return;
}
if (line.includes("Cantrip")) {
hasAnyHeader = true;
const value = this._getParsedSpells({line, isMarkdown});
if (!spellcastingEntry.spells) spellcastingEntry.spells = {"0": {"spells": []}};
spellcastingEntry.spells["0"].spells = value;
return;
}
if (/[- ][Ll]evel/.test(line) && /(?::| -) /.test(line)) {
hasAnyHeader = true;
let property = line.substring(0, 1);
const allSpells = this._getParsedSpells({line, isMarkdown});
spellcastingEntry.spells = spellcastingEntry.spells || {};
const out = {};
if (line.includes(" slot")) {
const mWarlock = /^(\d)..(?:[- ][Ll]evel)?-(\d)..[- ][Ll]evel \((\d) (\d)..[- ][Ll]evel slots?\)/.exec(line);
if (mWarlock) {
out.lower = parseInt(mWarlock[1]);
out.slots = parseInt(mWarlock[3]);
property = mWarlock[4];
} else {
const mSlots = /\((\d) slots?\)/.exec(line);
if (!mSlots) throw new Error(`Could not find slot count!`);
out.slots = parseInt(mSlots[1]);
}
}
}
// add these last, to have nicer ordering
out.spells = allSpells;
// add these last, to have nicer ordering
out.spells = allSpells;
spellcastingEntry.spells[property] = out;
} else {
if (hasAnyHeader) {
if (!spellcastingEntry.footerEntries) spellcastingEntry.footerEntries = [];
spellcastingEntry.footerEntries.push(this._parseToHit(thisLine));
} else {
spellcastingEntry.headerEntries.push(this._parseToHit(thisLine));
spellcastingEntry.spells[property] = out;
return;
}
}
});
if (hasAnyHeader) {
(spellcastingEntry.footerEntries ||= []).push(this._parseToHit(line));
} else {
spellcastingEntry.headerEntries.push(this._parseToHit(line));
}
});
SpellcastingTraitConvert.mutSpellcastingAbility(spellcastingEntry);
SpellcastingTraitConvert._mutDisplayAs(spellcastingEntry, displayAs);
@@ -1462,9 +1476,84 @@ class SpellcastingTraitConvert {
return spellcastingEntry;
}
static _getParsedSpells ({thisLine, isMarkdown}) {
const mLabelSep = /(?::| -) /.exec(thisLine);
let spellPart = thisLine.substring((mLabelSep?.index || 0) + (mLabelSep?.[0]?.length || 0)).trim();
static _getMutHeaderEntries ({ent, cbMan, spellcastingEntry}) {
let line = this._parseToHit(ent.entries[0]);
const usesMeta = this._getUsesMeta({line: ent.name});
line = line
.replace(/(?<pre>casts? (?:the )?)(?<spell>[^.,?!:]+)(?<post>\.| spell |at[ -]will)/g, (...m) => {
const isWill = m.last().post.toLowerCase().replace(/-/g, " ") === "at will";
if (!usesMeta && !isWill) {
cbMan(`Found spell in header with no usage info: ${m.last().spell}`);
return m[0];
}
const ptSpells = m.last().spell
.split(" and ")
.map(sp => {
const value = this._getParsedSpells({line: sp});
const hidden = MiscUtil.getOrSet(spellcastingEntry, "hidden", []);
if (isWill) {
const tgt = MiscUtil.getOrSet(spellcastingEntry, "will", []);
tgt.push(...value);
if (!hidden.includes("will")) hidden.push("will");
} else {
const tgt = MiscUtil.getOrSet(spellcastingEntry, usesMeta.prop, usesMeta.propPer, []);
tgt.push(...value);
if (!hidden.includes(usesMeta.prop)) hidden.push(usesMeta.prop);
}
return value.join(", ");
})
.join(" and ");
return [
m.last().pre,
ptSpells,
m.last().post,
]
.join(" ")
.replace(/ +/g, " ");
});
return line;
}
static _getUsesMeta ({line}) {
const perDurations = [
{re: /(?<cnt>\d+)\/rest(?<ptEach> each)?/i, prop: "rest"},
{re: /(?<cnt>\d+)\/day(?<ptEach> each)?/i, prop: "daily"},
{re: /(?<cnt>\d+)\/week(?<ptEach> each)?/i, prop: "weekly"},
{re: /(?<cnt>\d+)\/month(?<ptEach> each)?/i, prop: "monthly"},
{re: /(?<cnt>\d+)\/yeark(?<ptEach> each)?/i, prop: "yearly"},
];
const metasPerDuration = perDurations
.map(({re, prop}) => ({m: re.exec(line), prop}))
.filter(({m}) => !!m);
if (!metasPerDuration.length) return null;
// Arbitrarily pick the first
const [metaPerDuration] = metasPerDuration;
const propPer = `${metaPerDuration.m.groups.cnt}${metaPerDuration.m.groups.ptEach ? "e" : ""}`;
return {
prop: metaPerDuration.prop,
propPer,
lineRemaining: line.slice(metaPerDuration.m.length),
};
}
static _getParsedSpells ({line, isMarkdown}) {
const mLabelSep = /(?::| -) /.exec(line);
let spellPart = line.substring((mLabelSep?.index || 0) + (mLabelSep?.[0]?.length || 0)).trim();
if (isMarkdown) {
const cleanPart = (part) => {
part = part.trim();

View File

@@ -1605,7 +1605,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_TEXTBOX,
null,
$(`<div class="panel-content-wrapper-inner overflow-y-hidden"/>`).append(NoteBox.make$Notebox(this.board, content)),
$(`<div class="panel-content-wrapper-inner ve-overflow-y-hidden"/>`).append(NoteBox.make$Notebox(this.board, content)),
title,
true,
);
@@ -2284,7 +2284,7 @@ class Panel {
if (!this.board.getConfirmTabClose() || (this.board.getConfirmTabClose() && confirm(`Are you sure you want to close tab "${this.tabDatas[ix].title}"?`))) this.doCloseTab(ix);
};
const $btnSelTab = $(`<span class="btn btn-default content-tab ve-flex ${tabCanRename ? "content-tab-can-rename" : ""}"><span class="content-tab-title overflow-ellipsis" title="${title}">${title}</span></span>`)
const $btnSelTab = $(`<span class="btn btn-default content-tab ve-flex ${tabCanRename ? "content-tab-can-rename" : ""}"><span class="content-tab-title ve-overflow-ellipsis" title="${title}">${title}</span></span>`)
.on("mousedown", (evt) => {
if (evt.which === 1) {
this.setActiveTab(ix);
@@ -3259,7 +3259,7 @@ class AddMenuSpecialTab extends AddMenuTab {
render () {
if (!this.$tab) {
const $tab = $(`<div class="ui-search__wrp-output underline-tabs overflow-y-auto pr-1" id="${this.tabId}"/>`);
const $tab = $(`<div class="ui-search__wrp-output underline-tabs ve-overflow-y-auto pr-1" id="${this.tabId}"/>`);
const $wrpRoller = $(`<div class="ui-modal__row"><span>Dice Roller <i class="text-muted">(pins the existing dice roller to a panel)</i></span></div>`).appendTo($tab);
const $btnRoller = $(`<button class="btn btn-primary btn-sm">Pin</button>`).appendTo($wrpRoller);
@@ -3972,8 +3972,8 @@ class AdventureOrBookView {
}
$getEle () {
this._$titlePrev = $(`<div class="dm-book__controls-title overflow-ellipsis text-right"/>`);
this._$titleNext = $(`<div class="dm-book__controls-title overflow-ellipsis"/>`);
this._$titlePrev = $(`<div class="dm-book__controls-title ve-overflow-ellipsis text-right"/>`);
this._$titleNext = $(`<div class="dm-book__controls-title ve-overflow-ellipsis"/>`);
const $btnPrev = $(`<button class="btn btn-xs btn-default mr-2" title="Previous Chapter"><span class="glyphicon glyphicon-chevron-left"/></button>`)
.click(() => this._handleButtonClick(-1));

View File

@@ -31,7 +31,7 @@ class CounterRoot extends CounterComponent {
const pod = this.getPod();
this._$wrpRows = $$`<div class="ve-flex-col w-100 h-100 overflow-y-auto relative"/>`;
this._$wrpRows = $$`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto relative"/>`;
this._childComps.forEach(it => it.render(this._$wrpRows, pod));
const $btnAdd = $(`<button class="btn btn-primary btn-xs"><span class="glyphicon glyphicon-plus"/> Add Counter</button>`)

View File

@@ -158,7 +158,7 @@ export class InitiativeTrackerCreatureViewer extends BaseComponent {
}
})().then(null);
const $stg = $$`<div class="ve-flex-col w-100 h-100 min-h-0 overflow-y-auto">
const $stg = $$`<div class="ve-flex-col w-100 h-100 min-h-0 ve-overflow-y-auto">
${dispCreature}
</div>`;

View File

@@ -666,9 +666,9 @@ class TimeTrackerRoot extends TimeTrackerBase {
render ($parent) {
$parent.empty();
const $wrpClock = $(`<div class="ve-flex-col w-100 h-100 overflow-y-auto">`);
const $wrpCalendar = $(`<div class="ve-flex-col w-100 h-100 overflow-y-auto ve-flex-h-center">`);
const $wrpSettings = $(`<div class="ve-flex-col w-100 h-100 overflow-y-auto">`);
const $wrpClock = $(`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto">`);
const $wrpCalendar = $(`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto ve-flex-h-center">`);
const $wrpSettings = $(`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto">`);
const pod = this.getPod();
@@ -1771,7 +1771,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
},
);
const $wrpCalendar = $(`<div class="overflow-y-auto smooth-scroll"/>`);
const $wrpCalendar = $(`<div class="ve-overflow-y-auto smooth-scroll"/>`);
const hookCalendar = (prop) => {
const timeInfo = getTimeInfo();
@@ -2239,7 +2239,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
this._parent.addHook("moons", hookMoons);
hookMoons();
const $wrpEvents = $(`<div class="ve-flex-col w-100 overflow-y-auto dm-time__day-entry-wrapper"/>`);
const $wrpEvents = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto dm-time__day-entry-wrapper"/>`);
const hookEvents = () => {
const todayEvents = getEvents(year, eventDay);
$wrpEvents.empty();
@@ -2260,7 +2260,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
this._parent.addHook("events", hookEvents);
hookEvents();
const $wrpEncounters = $(`<div class="ve-flex-col w-100 overflow-y-auto dm-time__day-entry-wrapper"/>`);
const $wrpEncounters = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto dm-time__day-entry-wrapper"/>`);
const hookEncounters = async () => {
await this._pLock("encounters");

View File

@@ -70,7 +70,7 @@ export class InitiativeTrackerConditionCustomEdit extends BaseComponent {
this._state.conditionsCustom = [...this._state.conditionsCustom, InitiativeTrackerConditionUtil.getNewRowState()];
});
const $wrpRows = $(`<div class="ve-flex-col h-100 min-h-0 overflow-y-auto"></div>`);
const $wrpRows = $(`<div class="ve-flex-col h-100 min-h-0 ve-overflow-y-auto"></div>`);
const compRows = new _RenderableCollectionConditionsCustomEdit({comp: this, $wrpRows});
this._addHookBase("conditionsCustom", () => compRows.render())();

View File

@@ -50,7 +50,7 @@ class _InitiativeTrackerMonsterAddCustomizer extends BaseComponent {
const $iptCustomName = ComponentUiUtil.$getIptStr(this, "customName");
$$($modalInner)`
<div class="ve-flex-col py-2 w-100 h-100 overflow-y-auto">
<div class="ve-flex-col py-2 w-100 h-100 ve-overflow-y-auto">
<label class="split-v-center mb-2">
<span class="w-200p text-right no-shrink mr-2 bold">Custom Name:</span>
${$iptCustomName}

View File

@@ -62,7 +62,7 @@ export class RenderableCollectionRowDataBase extends RenderableCollectionAsyncGe
/* -------------------------------------------- */
_$getWrpRow () {
return $(`<div class="dm-init__row overflow-hidden pr-1"></div>`);
return $(`<div class="dm-init__row ve-overflow-hidden pr-1"></div>`);
}
async _pPopulateRow ({comp, $wrpRow, entity}) {

View File

@@ -191,7 +191,7 @@ export class InitiativeTrackerSettings extends BaseComponent {
}
_pGetShowModalResults_renderSection_additionalCols_body ({$modalInner}) {
const $wrpRows = $(`<div class="pr-1 h-120p ve-flex-col overflow-y-auto relative"></div>`).appendTo($modalInner);
const $wrpRows = $(`<div class="pr-1 h-120p ve-flex-col ve-overflow-y-auto relative"></div>`).appendTo($modalInner);
this._addHookBase("isStatsAddColumns", () => $wrpRows.toggleVe(this._state.isStatsAddColumns))();
const renderableCollectionStatsCols = new _RenderableCollectionStatsCols(

View File

@@ -334,7 +334,7 @@ export class EncounterBuilderUi extends BaseComponent {
const $wrpRows = $(`<div class="ve-flex-col"></div>`);
const $stg = $$`<div class="w-70 overflow-x-auto ve-flex-col">
const $stg = $$`<div class="w-70 ve-overflow-x-auto ve-flex-col">
<div class="ve-flex-h-center mb-2 bb-1p small-caps ve-self-flex-start">
<div class="w-100p mr-1 h-ipt-xs no-shrink">Name</div>
<div class="w-40p ve-text-center mr-1 h-ipt-xs no-shrink">Level</div>

View File

@@ -214,6 +214,7 @@ class PageFilterSpells extends PageFilter {
case Parser.SP_TM_ROUND: multiplier = 6; break;
case Parser.SP_TM_MINS: multiplier = 60; break;
case Parser.SP_TM_HRS: multiplier = 3600; break;
case Parser.SP_TM_SPECIAL: multiplier = 1_000_000; break; // Arbitrary large number
}
if (time.length > 1) offset += 0.5;
return (multiplier * firstTime.number) + offset;
@@ -415,6 +416,7 @@ class PageFilterSpells extends PageFilter {
Parser.SP_TM_ROUND,
Parser.SP_TM_MINS,
Parser.SP_TM_HRS,
Parser.SP_TM_SPECIAL,
],
displayFn: Parser.spTimeUnitToFull,
itemSortFn: null,

View File

@@ -133,7 +133,7 @@ class ModalFilter {
get allData () { return this._allData; }
_$getWrpList () { return $(`<div class="list ui-list__wrp overflow-x-hidden overflow-y-auto h-100 min-h-0"></div>`); }
_$getWrpList () { return $(`<div class="list ui-list__wrp ve-overflow-x-hidden ve-overflow-y-auto h-100 min-h-0"></div>`); }
_$getColumnHeaderPreviewAll (opts) {
return $(`<button class="btn btn-default btn-xs ${opts.isBuildUi ? "ve-col-1" : "ve-col-0-5"}">${ListUiUtil.HTML_GLYPHICON_EXPAND}</button>`);
@@ -2613,7 +2613,7 @@ class SearchableFilter extends Filter {
const wrpValues = e_({
tag: "div",
clazz: "overflow-y-auto bt-0 absolute fltr-search__wrp-values",
clazz: "ve-overflow-y-auto bt-0 absolute fltr-search__wrp-values",
});
const fnsCleanup = [];
@@ -3440,7 +3440,7 @@ class AbilityScoreFilter extends FilterBase {
const wrpControls = this._getHeaderControls(opts);
this.__wrpPills = e_({tag: "div", clazz: `fltr__wrp-pills overflow-x-auto ve-flex-col w-100`});
this.__wrpPills = e_({tag: "div", clazz: `fltr__wrp-pills ve-overflow-x-auto ve-flex-col w-100`});
const hook = () => this.__wrpPills.toggleVe(!this._meta.isHidden);
this._addHook("meta", "isHidden", hook);
hook();

View File

@@ -203,6 +203,7 @@ class ItemsPage extends ListPage {
colTransforms: {
name: UtilsTableview.COL_TRANSFORM_NAME,
source: UtilsTableview.COL_TRANSFORM_SOURCE,
page: UtilsTableview.COL_TRANSFORM_PAGE,
rarity: {name: "Rarity"},
_type: {name: "Type", transform: it => [it._typeHtml || "", it._subTypeHtml || ""].filter(Boolean).join(", ")},
_attunement: {name: "Attunement", transform: it => it._attunement ? it._attunement.slice(1, it._attunement.length - 1) : ""},

View File

@@ -1187,7 +1187,7 @@ class LootGenUi extends BaseComponent {
}
_render_output ({$wrp}) {
this._$wrpOutputRows = $(`<div class="w-100 h-100 ve-flex-col overflow-y-auto smooth-scroll"></div>`);
this._$wrpOutputRows = $(`<div class="w-100 h-100 ve-flex-col ve-overflow-y-auto smooth-scroll"></div>`);
$$`<div class="ve-flex-col w-100 h-100">
<h4 class="my-0"><i>Output</i></h4>

View File

@@ -194,7 +194,7 @@ class MakeCards extends BaseComponent {
</div>`.appendTo($wrpContainer);
const $wrpList = $(`<div class="w-100 h-100"/>`);
$$`<div class="ve-flex-col h-100 w-100 overflow-y-auto mt-2 overflow-x-hidden">${$wrpList}</div>`.appendTo($wrpContainer);
$$`<div class="ve-flex-col h-100 w-100 ve-overflow-y-auto mt-2 ve-overflow-x-hidden">${$wrpList}</div>`.appendTo($wrpContainer);
this._list = new List({$iptSearch, $wrpList, isUseJquery: true});
this._list.init();

View File

@@ -317,7 +317,7 @@ class MapsPage extends BaseComponent {
hkAnyVisible();
$$($root.empty())`
<div class="ve-flex-col h-100 no-shrink maps-menu pr-4 py-3 shadow-big overflow-y-auto smooth-scroll scrollbar-stable mobile__w-100 mobile__my-4">
<div class="ve-flex-col h-100 no-shrink maps-menu pr-4 py-3 shadow-big ve-overflow-y-auto smooth-scroll scrollbar-stable mobile__w-100 mobile__my-4">
<label class="split-v-center pl-2 py-1">
<div class="mr-3 no-shrink">Image Scale</div>
${$sldImageScale}
@@ -333,7 +333,7 @@ class MapsPage extends BaseComponent {
${rendersSource.map(({$wrpMenu}) => $wrpMenu)}
</div>
<div class="w-100 h-100 mobile__h-initial overflow-y-auto smooth-scroll ve-flex-col">
<div class="w-100 h-100 mobile__h-initial ve-overflow-y-auto smooth-scroll ve-flex-col">
${$dispNoneVisible}
${rendersSource.map(({$wrpContent}) => $wrpContent)}
</div>

View File

@@ -332,12 +332,22 @@ class Omnisearch {
.join(" ");
}
static _isFauxPage (r) {
return !!r.hx;
}
static getResultHref (r) {
const isFauxPage = this._isFauxPage(r);
if (isFauxPage) return null;
return r.c === Parser.CAT_ID_PAGE ? r.u : `${Renderer.get().baseUrl}${UrlUtil.categoryToPage(r.c)}#${r.uh || r.u}`;
}
static $getResultLink (r) {
const isFauxPage = !!r.hx;
const isFauxPage = this._isFauxPage(r);
if (isFauxPage) return $(`<span tabindex="0" ${r.h ? this._renderLink_getHoverString(r.c, r.u, r.s, {isFauxPage}) : ""} class="omni__lnk-name help">${r.cf}: ${r.n}</span>`);
const href = r.c === Parser.CAT_ID_PAGE ? r.u : `${Renderer.get().baseUrl}${UrlUtil.categoryToPage(r.c)}#${r.uh || r.u}`;
const href = this.getResultHref(r);
return $(`<a href="${href}" ${r.h ? this._renderLink_getHoverString(r.c, r.u, r.s, {isFauxPage}) : ""} class="omni__lnk-name">${r.cf}: ${r.n}</a>`);
}

View File

@@ -2297,6 +2297,7 @@ Parser.SP_TM_REACTION = "reaction";
Parser.SP_TM_ROUND = "round";
Parser.SP_TM_MINS = "minute";
Parser.SP_TM_HRS = "hour";
Parser.SP_TM_SPECIAL = "special";
Parser.SP_TIME_SINGLETONS = [Parser.SP_TM_ACTION, Parser.SP_TM_B_ACTION, Parser.SP_TM_REACTION, Parser.SP_TM_ROUND];
Parser.SP_TIME_TO_FULL = {
[Parser.SP_TM_ACTION]: "Action",
@@ -2305,6 +2306,7 @@ Parser.SP_TIME_TO_FULL = {
[Parser.SP_TM_ROUND]: "Rounds",
[Parser.SP_TM_MINS]: "Minutes",
[Parser.SP_TM_HRS]: "Hours",
[Parser.SP_TM_SPECIAL]: "Special",
};
Parser.spTimeUnitToFull = function (timeUnit) {
return Parser._parse_aToB(Parser.SP_TIME_TO_FULL, timeUnit);
@@ -2326,6 +2328,7 @@ Parser.SP_TIME_TO_ABV = {
[Parser.SP_TM_ROUND]: "rnd",
[Parser.SP_TM_MINS]: "min",
[Parser.SP_TM_HRS]: "hr",
[Parser.SP_TM_SPECIAL]: "SPC",
};
Parser.spTimeUnitToAbv = function (timeUnit) {
return Parser._parse_aToB(Parser.SP_TIME_TO_ABV, timeUnit);
@@ -2674,6 +2677,7 @@ Parser.SRC_LK = "LK";
Parser.SRC_CoA = "CoA";
Parser.SRC_PiP = "PiP";
Parser.SRC_DitLCoT = "DitLCoT";
Parser.SRC_LRDT = "LRDT";
Parser.SRC_AL_PREFIX = "AL";
@@ -2853,6 +2857,7 @@ Parser.SOURCE_JSON_TO_FULL[Parser.SRC_LK] = "Lightning Keep";
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_CoA] = "Chains of Asmodeus";
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_PiP] = "Peril in Pinebrook";
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_DitLCoT] = "Descent into the Lost Caverns of Tsojcanth";
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_LRDT] = "Red Dragon's Tale: A LEGO Adventure";
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_ALCoS] = `${Parser.AL_PREFIX}Curse of Strahd`;
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_ALEE] = `${Parser.AL_PREFIX}Elemental Evil`;
Parser.SOURCE_JSON_TO_FULL[Parser.SRC_ALRoD] = `${Parser.AL_PREFIX}Rage of Demons`;
@@ -3007,6 +3012,7 @@ Parser.SOURCE_JSON_TO_ABV[Parser.SRC_LK] = "LK";
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_CoA] = "CoA";
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_PiP] = "PiP";
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_DitLCoT] = "DitLCoT";
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_LRDT] = "LRDT";
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_ALCoS] = "ALCoS";
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_ALEE] = "ALEE";
Parser.SOURCE_JSON_TO_ABV[Parser.SRC_ALRoD] = "ALRoD";
@@ -3160,6 +3166,7 @@ Parser.SOURCE_JSON_TO_DATE[Parser.SRC_LK] = "2023-09-26";
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_CoA] = "2023-10-30";
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_PiP] = "2023-11-20";
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_DitLCoT] = "2024-03-26";
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_LRDT] = "2024-04-01";
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_ALCoS] = "2016-03-15";
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_ALEE] = "2015-04-07";
Parser.SOURCE_JSON_TO_DATE[Parser.SRC_ALRoD] = "2015-09-15";
@@ -3257,6 +3264,7 @@ Parser.SOURCES_ADVENTURES = new Set([
Parser.SRC_CoA,
Parser.SRC_PiP,
Parser.SRC_DitLCoT,
Parser.SRC_LRDT,
Parser.SRC_HFStCM,
Parser.SRC_GHLoE,
Parser.SRC_DoDk,
@@ -3326,6 +3334,7 @@ Parser.SOURCES_PARTNERED_WOTC = new Set([
Parser.SRC_HWAitW,
Parser.SRC_ToB1_2023,
Parser.SRC_TD,
Parser.SRC_LRDT,
]);
// region Source categories
@@ -3372,6 +3381,7 @@ Parser.SOURCES_COMEDY = new Set([
Parser.SRC_MisMV1,
Parser.SRC_LK,
Parser.SRC_PiP,
Parser.SRC_LRDT,
]);
// Any opinionated set of sources that are "other settings"
@@ -3412,6 +3422,7 @@ Parser.SOURCES_NON_FR = new Set([
Parser.SRC_HWCS,
Parser.SRC_HWAitW,
Parser.SRC_ToB1_2023,
Parser.SRC_LRDT,
]);
// endregion
@@ -3552,6 +3563,7 @@ Parser.SOURCES_AVAILABLE_DOCS_ADVENTURE = {};
Parser.SRC_DoDk,
Parser.SRC_HWAitW,
Parser.SRC_QftIS,
Parser.SRC_LRDT,
].forEach(src => {
Parser.SOURCES_AVAILABLE_DOCS_ADVENTURE[src] = src;
Parser.SOURCES_AVAILABLE_DOCS_ADVENTURE[src.toLowerCase()] = src;

View File

@@ -74,6 +74,7 @@ class PsionicsPage extends ListPage {
colTransforms: {
name: UtilsTableview.COL_TRANSFORM_NAME,
source: UtilsTableview.COL_TRANSFORM_SOURCE,
page: UtilsTableview.COL_TRANSFORM_PAGE,
_text: {name: "Text", transform: (it) => Renderer.psionic.getBodyText(it), flex: 3},
},
},

View File

@@ -223,6 +223,8 @@ class RenderDecks {
const $wrpInfo = $$`<div class="stats stats--book decks-draw__wrp-desc mobile__hidden px-2 ve-text-center mb-4">${ptText}</div>`
.click(evt => evt.stopPropagation());
Renderer.dice.bindOnclickListener($wrpInfo[0]);
const $btnFlip = imgBack
? $(`<button class="btn btn-default btn-xs px-3" title="Flip Card"><i class="fas fa-rotate"></i> Flip</button>`)
.click(evt => {

View File

@@ -19,6 +19,8 @@ Renderer.dice = {
_isManualMode: false,
/* -------------------------------------------- */
// region Utilities
DICE: [4, 6, 8, 10, 12, 20, 100],
getNextDice (faces) {
@@ -34,6 +36,8 @@ Renderer.dice = {
},
// endregion
/* -------------------------------------------- */
// region DM Screen integration
_panel: null,
bindDmScreenPanel (panel, title) {
@@ -60,6 +64,27 @@ Renderer.dice = {
},
// endregion
/* -------------------------------------------- */
bindOnclickListener (ele) {
ele.addEventListener("click", (evt) => {
const eleDice = evt.target.hasAttribute("data-packed-dice")
? evt.target
// Tolerate e.g. Bestiary wrapped proficiency dice rollers
: evt.target.parentElement?.hasAttribute("data-packed-dice")
? evt.target.parentElement
: null;
if (!eleDice) return;
evt.preventDefault();
evt.stopImmediatePropagation();
Renderer.dice.pRollerClickUseData(evt, eleDice).then(null);
});
},
/* -------------------------------------------- */
/**
* Silently roll an expression and get the result.
* Note that this does not support dynamic variables (e.g. user proficiency bonus).

View File

@@ -373,7 +373,7 @@ class RenderMap {
`);
});
const $wrpCvs = $$`<div class="w-100 h-100 overflow-x-scroll overflow-y-scroll rd__scroller-viewer">
const $wrpCvs = $$`<div class="w-100 h-100 ve-overflow-x-scroll ve-overflow-y-scroll rd__scroller-viewer">
${$cvs}
</div>`
.on("mousewheel DOMMouseScroll", evt => {

View File

@@ -692,6 +692,12 @@ class RendererMarkdown {
this._recursiveRender(text, textStack, meta);
textStack[0] += `~~`;
break;
case "@s2":
case "@strikeDouble":
textStack[0] += `~~`;
this._recursiveRender(text, textStack, meta);
textStack[0] += `~~`;
break;
case "@note":
textStack[0] += "*";
this._recursiveRender(text, textStack, meta);

View File

@@ -1625,12 +1625,24 @@ globalThis.Renderer = function () {
this._recursiveRender(text, textStack, meta);
textStack[0] += `</s>`;
break;
case "@s2":
case "@strikeDouble":
textStack[0] += `<s class="ve-strike-double">`;
this._recursiveRender(text, textStack, meta);
textStack[0] += `</s>`;
break;
case "@u":
case "@underline":
textStack[0] += `<u>`;
this._recursiveRender(text, textStack, meta);
textStack[0] += `</u>`;
break;
case "@u2":
case "@underlineDouble":
textStack[0] += `<u class="ve-underline-double">`;
this._recursiveRender(text, textStack, meta);
textStack[0] += `</u>`;
break;
case "@sup":
textStack[0] += `<sup>`;
this._recursiveRender(text, textStack, meta);
@@ -2044,20 +2056,23 @@ globalThis.Renderer = function () {
};
this._renderLink_getHref = function (entry) {
let href;
if (entry.href.type === "internal") {
// baseURL is blank by default
href = `${this.baseUrl}${entry.href.path}#`;
const ptBase = `${this.baseUrl}${entry.href.path}`;
let ptHash = "";
if (entry.href.hash != null) {
href += entry.href.hashPreEncoded ? entry.href.hash : UrlUtil.encodeForHash(entry.href.hash);
ptHash += entry.href.hashPreEncoded ? entry.href.hash : UrlUtil.encodeForHash(entry.href.hash);
}
if (entry.href.subhashes != null) {
href += Renderer.utils.getLinkSubhashString(entry.href.subhashes);
ptHash += Renderer.utils.getLinkSubhashString(entry.href.subhashes);
}
} else if (entry.href.type === "external") {
href = entry.href.url;
if (!ptHash) return ptBase;
return `${ptBase}#${ptHash}`;
}
return href;
if (entry.href.type === "external") {
return entry.href.url;
}
return "";
};
this._renderLink_getHoverString = function (entry) {
@@ -2141,6 +2156,7 @@ Renderer._INLINE_HEADER_TERMINATORS = new Set([".", ",", "!", "?", ";", ":", `"`
Renderer._STYLE_TAG_ID_TO_STYLE = {
"small-caps": "small-caps",
"small": "ve-small",
"large": "ve-large",
"capitalize": "capitalize",
"dnd-font": "dnd-font",
};
@@ -4334,6 +4350,14 @@ Renderer.tag = class {
tagName = "strike";
};
static TagStrikethroughDoubleShort = class extends this._TagTextStyle {
tagName = "s2";
};
static TagStrikethroughDoubleLong = class extends this._TagTextStyle {
tagName = "strikeDouble";
};
static TagUnderlineShort = class extends this._TagTextStyle {
tagName = "u";
};
@@ -4342,6 +4366,14 @@ Renderer.tag = class {
tagName = "underline";
};
static TagUnderlineDoubleShort = class extends this._TagTextStyle {
tagName = "u2";
};
static TagUnderlineDoubleLong = class extends this._TagTextStyle {
tagName = "underlineDouble";
};
static TagSup = class extends this._TagTextStyle {
tagName = "sup";
};
@@ -4913,8 +4945,12 @@ Renderer.tag = class {
new this.TagItalicLong(),
new this.TagStrikethroughShort(),
new this.TagStrikethroughLong(),
new this.TagStrikethroughDoubleShort(),
new this.TagStrikethroughDoubleLong(),
new this.TagUnderlineShort(),
new this.TagUnderlineLong(),
new this.TagUnderlineDoubleShort(),
new this.TagUnderlineDoubleLong(),
new this.TagSup(),
new this.TagSub(),
new this.TagKbd(),
@@ -10412,7 +10448,7 @@ Renderer.recipe = class {
${entriesMeta.entryCooksNotes ? `<div class="w-100 ve-flex-col mt-4"><div class="ve-flex-vh-center bold mb-1 small-caps">Cook's Notes</div><div class="italic">${Renderer.get().render(entriesMeta.entryCooksNotes)}</div></div>` : ""}
</div>
<div class="pl-2 ve-flex-2 rd-recipes__wrp-instructions overflow-x-auto">
<div class="pl-2 ve-flex-2 rd-recipes__wrp-instructions ve-overflow-x-auto">
${Renderer.get().setFirstSection(true).render(entriesMeta.entryInstructions, 2)}
</div>
</div>`;
@@ -11621,7 +11657,7 @@ Renderer.hover = class {
});
const $wrpContent = $(`<div class="hwin__wrp-table"></div>`);
if (opts.height != null) $wrpContent.css("height", opts.height);
const $hovTitle = $(`<span class="window-title min-w-0 overflow-ellipsis" title="${`${opts.title || ""}`.qq()}">${opts.title || ""}</span>`);
const $hovTitle = $(`<span class="window-title min-w-0 ve-overflow-ellipsis" title="${`${opts.title || ""}`.qq()}">${opts.title || ""}</span>`);
const hoverWindow = {};
const hoverId = Renderer.hover._getNextId();

View File

@@ -13,6 +13,23 @@ class SearchPage {
this._render();
}
/* -------------------------------------------- */
static _PARAM_QUERY = "q";
static _PARAM_LUCKY = "lucky";
static _getSearchParams () {
const params = new URLSearchParams(location.search);
return Object.fromEntries(params);
}
static _setSearchParams (obj) {
const params = new URLSearchParams(obj);
location.search = params.toString();
}
/* -------------------------------------------- */
static _render_$getBtnToggleFilter (
{
propOmnisearch,
@@ -43,11 +60,13 @@ class SearchPage {
if (evt.key !== "Enter") return;
$btnSearch.click();
})
.val(decodeURIComponent(location.search.slice(1).replace(/\+/g, " ")));
.val(this._getSearchParams()[this._PARAM_QUERY]);
const $btnSearch = $(`<button class="btn btn-default"><span class="glyphicon glyphicon-search"></span></button>`)
.click(() => {
location.search = encodeURIComponent($iptSearch.val().trim().toLowerCase());
this._setSearchParams({
[this._PARAM_QUERY]: $iptSearch.val().trim().toLowerCase(),
});
});
const $btnHelp = $(`<button class="btn btn-default mr-2 mobile__hidden" title="Help"><span class="glyphicon glyphicon-info-sign"></span></button>`)
@@ -146,12 +165,14 @@ class SearchPage {
}
SearchPage._rowMetas = [];
if (!location.search.slice(1)) {
const params = this._getSearchParams();
if (!params[this._PARAM_QUERY]) {
SearchPage._$wrpResults.empty().append(this._getWrpResult_message("Enter a search to view results"));
return;
}
Omnisearch.pGetResults(decodeURIComponent(location.search.slice(1).replace(/\+/g, " ")))
Omnisearch.pGetResults(params[this._PARAM_QUERY])
.then(results => {
SearchPage._$wrpResults.empty();
@@ -160,6 +181,12 @@ class SearchPage {
return;
}
if (this._PARAM_LUCKY in params) {
const [result] = results;
window.location = `${Renderer.get().baseUrl}${Omnisearch.getResultHref(result.doc)}`;
return;
}
SearchPage._rowMetas = results.map(result => {
const r = result.doc;

View File

@@ -231,6 +231,7 @@ class SpellsPage extends ListPageMultiSource {
colTransforms: {
name: UtilsTableview.COL_TRANSFORM_NAME,
source: UtilsTableview.COL_TRANSFORM_SOURCE,
page: UtilsTableview.COL_TRANSFORM_PAGE,
level: {name: "Level", transform: (it) => Parser.spLevelToFull(it)},
time: {name: "Casting Time", transform: (it) => PageFilterSpells.getTblTimeStr(it[0])},
duration: {name: "Duration", transform: (it) => Parser.spDurationToFull(it)},

View File

@@ -2325,10 +2325,10 @@ StatGenUi.CompAsi = class extends BaseComponent {
}
render ($wrpAsi) {
const $wrpRowsAsi = $(`<div class="ve-flex-col w-100 overflow-y-auto"></div>`);
const $wrpRowsRace = $(`<div class="ve-flex-col w-100 overflow-y-auto"></div>`);
const $wrpRowsBackground = $(`<div class="ve-flex-col w-100 overflow-y-auto"></div>`);
const $wrpRowsCustom = $(`<div class="ve-flex-col w-100 overflow-y-auto"></div>`);
const $wrpRowsAsi = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto"></div>`);
const $wrpRowsRace = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto"></div>`);
const $wrpRowsBackground = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto"></div>`);
const $wrpRowsCustom = $(`<div class="ve-flex-col w-100 ve-overflow-y-auto"></div>`);
this._render_renderAsiFeatSection("common_cntAsi", "ability", $wrpRowsAsi);
this._render_renderAsiFeatSection("common_cntFeatsCustom", "custom", $wrpRowsCustom);

View File

@@ -1896,7 +1896,7 @@ class ManageBrewUi {
.click(evt => this._pHandleClick_btnListMass({evt, rdState}));
const $iptSearch = $(`<input type="search" class="search manbrew__search form-control" placeholder="Search ${this._brewUtil.DISPLAY_NAME}...">`);
const $cbAll = $(`<input type="checkbox">`);
const $wrpList = $(`<div class="list-display-only max-h-unset smooth-scroll overflow-y-auto h-100 min-h-0 brew-list brew-list--target manbrew__list relative ve-flex-col w-100 mb-3"></div>`);
const $wrpList = $(`<div class="list-display-only max-h-unset smooth-scroll ve-overflow-y-auto h-100 min-h-0 brew-list brew-list--target manbrew__list relative ve-flex-col w-100 mb-3"></div>`);
rdState.list = new List({
$iptSearch,

View File

@@ -17,6 +17,15 @@ class _DataLoaderConst {
static SOURCE_BREW_ALL_CURRENT = Symbol("SOURCE_BREW_ALL_CURRENT");
static ENTITY_NULL = Symbol("ENTITY_NULL");
static _SOURCES_ALL_NON_SITE = new Set([
this.SOURCE_PRERELEASE_ALL_CURRENT,
this.SOURCE_BREW_ALL_CURRENT,
]);
static isSourceAllNonSite (source) {
return this._SOURCES_ALL_NON_SITE.has(source);
}
}
class _DataLoaderInternalUtil {
@@ -638,6 +647,7 @@ class _DataTypeLoader {
async _pPrePopulate ({data, isPrerelease, isBrew}) { /* Implement as required */ }
async pGetSiteData ({pageClean, sourceClean}) {
if (_DataLoaderConst.isSourceAllNonSite(sourceClean)) return {};
const propCache = this._getSiteIdent({pageClean, sourceClean});
this._cache_pSiteData[propCache] = this._cache_pSiteData[propCache] || this._pGetSiteData({pageClean, sourceClean});
return this._cache_pSiteData[propCache];

View File

@@ -993,6 +993,8 @@ PropOrder._CONDITION = [
"basicRules",
"otherSources",
"color",
"entries",
"hasFluff",
@@ -1028,6 +1030,8 @@ PropOrder._STATUS = [
"srd",
"basicRules",
"color",
"entries",
];
PropOrder._CULT = [

View File

@@ -68,7 +68,7 @@ class UtilsTableview {
}
static _getTableHtml ({state, entities, colTransforms, sorter}) {
let stack = `<div class="overflow-y-auto w-100 h-100 ve-flex-col overflow-x-auto">
let stack = `<div class="ve-overflow-y-auto w-100 h-100 ve-flex-col ve-overflow-x-auto">
<table class="w-100 table-striped stats stats--book stats--book-large min-w-100 w-initial">
<thead>
<tr>${Object.values(colTransforms).map((c, i) => `<th data-col="${i}" class="px-2" colspan="${c.flex || 1}">${c.name}</th>`).join("")}</tr>
@@ -100,5 +100,6 @@ class UtilsTableview {
// region Default/generic transforms
static COL_TRANSFORM_NAME = {name: "Name"};
static COL_TRANSFORM_SOURCE = {name: "Source", transform: (it) => `<span class="${Parser.sourceJsonToColor(it)}" title="${Parser.sourceJsonToFull(it)}" ${Parser.sourceJsonToStyle(it)}>${Parser.sourceJsonToAbv(it)}</span>`};
static COL_TRANSFORM_PAGE = {name: "Page"};
// endregion
}

View File

@@ -1411,7 +1411,7 @@ class TabUiUtilSide extends TabUiUtilBase {
};
obj.__$getWrpTab = function ({tabMeta}) {
return $(`<div class="ve-flex-col w-100 h-100 ui-tab-side__wrp-tab ${tabMeta.isNoPadding ? "" : "px-3 py-2"} overflow-y-auto"></div>`);
return $(`<div class="ve-flex-col w-100 h-100 ui-tab-side__wrp-tab ${tabMeta.isNoPadding ? "" : "px-3 py-2"} ve-overflow-y-auto"></div>`);
};
obj.__renderTabs_addToParent = function ({$dispTabTitle, $parent, tabMetasOut}) {
@@ -5075,7 +5075,7 @@ class ComponentUiUtil {
.prop("disabled", !!opts.isDisabled)
.disableSpellcheck();
const $wrpChoices = $(`<div class="absolute ui-sel2__wrp-options overflow-y-scroll"></div>`);
const $wrpChoices = $(`<div class="absolute ui-sel2__wrp-options ve-overflow-y-scroll"></div>`);
const $wrp = $$`<div class="ve-flex relative ui-sel2__wrp w-100">
${$iptDisplay}
@@ -5586,7 +5586,7 @@ class ComponentUiUtil {
// Always return this as a "meta" object
const unhook = () => rowMetas.forEach(it => it.unhook());
return {
$ele: $$`<div class="ve-flex-col w-100 overflow-y-auto">${$eles}</div>`,
$ele: $$`<div class="ve-flex-col w-100 ve-overflow-y-auto">${$eles}</div>`,
$iptSearch,
rowMetas, // Return this to allow for creating custom UI
propIsAcceptable,
@@ -5911,7 +5911,7 @@ ComponentUiUtil.RangeSlider = class {
_getDispValue ({isVisible, side}) {
return e_({
tag: "div",
clazz: `overflow-hidden ui-slidr__disp-value no-shrink no-grow ve-flex-vh-center bold no-select ${isVisible ? `ui-slidr__disp-value--visible` : ""} ui-slidr__disp-value--${side}`,
clazz: `ve-overflow-hidden ui-slidr__disp-value no-shrink no-grow ve-flex-vh-center bold no-select ${isVisible ? `ui-slidr__disp-value--visible` : ""} ui-slidr__disp-value--${side}`,
});
}

View File

@@ -2,7 +2,7 @@
// in deployment, `IS_DEPLOYED = "<version number>";` should be set below.
globalThis.IS_DEPLOYED = undefined;
globalThis.VERSION_NUMBER = /* 5ETOOLS_VERSION__OPEN */"1.203.0"/* 5ETOOLS_VERSION__CLOSE */;
globalThis.VERSION_NUMBER = /* 5ETOOLS_VERSION__OPEN */"1.204.0"/* 5ETOOLS_VERSION__CLOSE */;
globalThis.DEPLOYED_IMG_ROOT = undefined;
// for the roll20 script to set
globalThis.IS_VTT = false;
@@ -915,7 +915,7 @@ globalThis.JqueryUtil = {
if (JqueryUtil._WRP_TOAST == null) {
JqueryUtil._WRP_TOAST = e_({
tag: "div",
clazz: "toast__container no-events w-100 overflow-y-hidden ve-flex-col",
clazz: "toast__container no-events w-100 ve-overflow-y-hidden ve-flex-col",
});
document.body.appendChild(JqueryUtil._WRP_TOAST);
}
@@ -7249,7 +7249,7 @@ class BookModeViewBase {
}
async _pGetContentElementMetas () {
const $wrpContent = $(`<div class="bkmv__scroller smooth-scroll overflow-y-auto print__overflow-visible ${this._isColumns ? "bkmv__wrp" : "ve-flex-col"} w-100 min-h-0"></div>`);
const $wrpContent = $(`<div class="bkmv__scroller smooth-scroll ve-overflow-y-auto print__overflow-visible ${this._isColumns ? "bkmv__wrp" : "ve-flex-col"} w-100 min-h-0"></div>`);
const $wrpContentOuter = $$`<div class="h-100 print__h-initial w-100 min-h-0 ve-flex-col print__ve-block">${$wrpContent}</div>`;
@@ -7700,20 +7700,7 @@ if (!IS_VTT && typeof window !== "undefined") {
});
window.addEventListener("load", () => {
document.body.addEventListener("click", (evt) => {
const eleDice = evt.target.hasAttribute("data-packed-dice")
? evt.target
// Tolerate e.g. Bestiary wrapped proficiency dice rollers
: evt.target.parentElement?.hasAttribute("data-packed-dice")
? evt.target.parentElement
: null;
if (!eleDice) return;
evt.preventDefault();
evt.stopImmediatePropagation();
Renderer.dice.pRollerClickUseData(evt, eleDice).then(null);
});
Renderer.dice.bindOnclickListener(document.body);
Renderer.events.bindGeneric();
});