This commit is contained in:
TheGiddyLimit
2024-06-23 22:13:57 +01:00
parent ed9833eefc
commit e5844f8a3f
279 changed files with 38254 additions and 7675 deletions

View File

@@ -24,7 +24,7 @@ async function onJsonLoad (data) {
BookUtil.bookIndex = data?.adventure || [];
$(`.book-head-message`).text(`Select an adventure from the list on the left`);
$(`#page__subtitle`).text(`Select an adventure from the list on the left`);
$(`.book-loading-message`).text(`Select an adventure to begin`);
BookUtil.bookIndexPrerelease = (await PrereleaseUtil.pGetBrewProcessed())?.adventure || [];

View File

@@ -211,13 +211,13 @@ class BestiaryPageBookView extends ListPageBookView {
const $btnDownloadMarkdown = $(`<button class="btn btn-default btn-sm">Download as Markdown</button>`)
.click(async () => DataUtil.userDownloadText("bestiary.md", await pGetAsMarkdown()));
const $btnCopyMarkdown = $(`<button class="btn btn-default btn-sm px-2" title="Copy Markdown to Clipboard"><span class="glyphicon glyphicon-copy"/></button>`)
const $btnCopyMarkdown = $(`<button class="btn btn-default btn-sm px-2" title="Copy Markdown to Clipboard"><span class="glyphicon glyphicon-copy"></span></button>`)
.click(async () => {
await MiscUtil.pCopyTextToClipboard(await pGetAsMarkdown());
JqueryUtil.showCopiedEffect($btnCopyMarkdown);
});
const $btnDownloadMarkdownSettings = $(`<button class="btn btn-default btn-sm px-2" title="Markdown Settings"><span class="glyphicon glyphicon-cog"/></button>`)
const $btnDownloadMarkdownSettings = $(`<button class="btn btn-default btn-sm px-2" title="Markdown Settings"><span class="glyphicon glyphicon-cog"></span></button>`)
.click(async () => RendererMarkdown.pShowSettingsModal());
$$`<div class="ve-flex-v-center btn-group ml-2">
@@ -306,8 +306,8 @@ class BestiaryPage extends ListPageMultiSource {
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)},
ac: {name: "AC", transform: ac => Parser.acToFull(ac)},
hp: {name: "HP", transform: hp => Renderer.monster.getRenderedHp(hp)},
ac: {name: "AC", transform: ac => ac != null ? Parser.acToFull(ac) : ""},
hp: {name: "HP", transform: hp => hp != null ? Renderer.monster.getRenderedHp(hp) : ""},
_speed: {name: "Speed", transform: mon => Parser.getSpeedString(mon)},
...Parser.ABIL_ABVS.mergeMap(ab => ({[ab]: {name: Parser.attAbvToFull(ab)}})),
_save: {name: "Saving Throws", transform: mon => Renderer.monster.getSavesPart(mon)},
@@ -913,14 +913,14 @@ class BestiaryPage extends ListPageMultiSource {
};
// append footer first to be behind buttons
const $footer = $(`<div class="mon__token-footer"/>`);
const $footer = $(`<div class="mon__token-footer"></div>`);
const $wrpFooter = $$`<div class="mon__wrp-token-footer">${$footer}</div>`.hide().appendTo($lnkToken);
const $btnLeft = $$`<div class="mon__btn-token-cycle mon__btn-token-cycle--left"><span class="glyphicon glyphicon-chevron-left"/></div>`
const $btnLeft = $$`<div class="mon__btn-token-cycle mon__btn-token-cycle--left"><span class="glyphicon glyphicon-chevron-left"></span></div>`
.click(evt => handleClick(evt, -1)).appendTo($lnkToken)
.hide();
const $btnRight = $$`<div class="mon__btn-token-cycle mon__btn-token-cycle--right"><span class="glyphicon glyphicon-chevron-right"/></div>`
const $btnRight = $$`<div class="mon__btn-token-cycle mon__btn-token-cycle--right"><span class="glyphicon glyphicon-chevron-right"></span></div>`
.click(evt => handleClick(evt, 1)).appendTo($lnkToken);
}
}

View File

@@ -24,7 +24,7 @@ async function onJsonLoad (data) {
BookUtil.bookIndex = data?.book || [];
$(`.book-head-message`).text(`Select a book from the list on the left`);
$(`#page__subtitle`).text(`Select a book from the list on the left`);
$(`.book-loading-message`).text(`Select a book to begin`);
BookUtil.bookIndexPrerelease = (await PrereleaseUtil.pGetBrewProcessed())?.book || [];

View File

@@ -260,7 +260,7 @@ class BookUtil {
static _showBookContent_renderNavButtons ({isTop, ixChapter, bookId, data}) {
const tdStyle = `padding-${isTop ? "top" : "bottom"}: 6px; padding-left: 9px; padding-right: 9px;`;
const $wrpControls = $(`<div class="split"/>`).appendTo($(`<td colspan="6" style="${tdStyle}"/>`).appendTo($(`<tr/>`).appendTo(BookUtil.$dispBook)));
const $wrpControls = $(`<div class="split"></div>`).appendTo($(`<td colspan="6" style="${tdStyle}"></td>`).appendTo($(`<tr></tr>`).appendTo(BookUtil.$dispBook)));
const showPrev = ~ixChapter && ixChapter > 0;
BookUtil.curRender.controls.$btnsPrv = BookUtil.curRender.controls.$btnsPrv || [];
@@ -310,10 +310,10 @@ class BookUtil {
let $btnPrev;
if (BookUtil.referenceId) {
$btnPrev = $(`<button class="btn btn-xxs btn-default"><span class="glyphicon glyphicon-chevron-left"/></button>`)
$btnPrev = $(`<button class="btn btn-xxs btn-default"><span class="glyphicon glyphicon-chevron-left"></span></button>`)
.click(() => this._showBookContent_goToPage({mod: -1, bookId, ixChapter}));
} else {
$btnPrev = $(`<a href="#${this._showBookContent_goToPage({mod: -1, isGetHref: true, bookId, ixChapter})}" class="btn btn-xxs btn-default"><span class="glyphicon glyphicon-chevron-left"/></a>`)
$btnPrev = $(`<a href="#${this._showBookContent_goToPage({mod: -1, isGetHref: true, bookId, ixChapter})}" class="btn btn-xxs btn-default"><span class="glyphicon glyphicon-chevron-left"></span></a>`)
.click(() => MiscUtil.scrollPageTop());
}
$btnPrev
@@ -324,10 +324,10 @@ class BookUtil {
let $btnNext;
if (BookUtil.referenceId) {
$btnNext = $(`<button class="btn btn-xxs btn-default"><span class="glyphicon glyphicon-chevron-right"/></button>`)
$btnNext = $(`<button class="btn btn-xxs btn-default"><span class="glyphicon glyphicon-chevron-right"></span></button>`)
.click(() => this._showBookContent_goToPage({mod: 1, bookId, ixChapter}));
} else {
$btnNext = $(`<a href="#${this._showBookContent_goToPage({mod: 1, isGetHref: true, bookId, ixChapter})}" class="btn btn-xxs btn-default"><span class="glyphicon glyphicon-chevron-right"/></a>`)
$btnNext = $(`<a href="#${this._showBookContent_goToPage({mod: 1, isGetHref: true, bookId, ixChapter})}" class="btn btn-xxs btn-default"><span class="glyphicon glyphicon-chevron-right"></span></a>`)
.click(() => MiscUtil.scrollPageTop());
}
$btnNext
@@ -359,7 +359,7 @@ class BookUtil {
$btnToggleNarrow.toggleClass("active", this._isNarrow);
$(`#pagecontent`).toggleClass(`bk__stats--narrow`, this._isNarrow);
};
const $btnToggleNarrow = $(`<button class="btn btn-xs btn-default" title="Toggle Narrow Reading Width"><span class="glyphicon glyphicon-resize-small"/></button>`)
const $btnToggleNarrow = $(`<button class="btn btn-xs btn-default" title="Toggle Narrow Reading Width"><span class="glyphicon glyphicon-resize-small"></span></button>`)
.click(() => {
this._isNarrow = !this._isNarrow;
hdlNarrowUpdate();
@@ -399,7 +399,7 @@ class BookUtil {
]);
}
const $btnMenu = $(`<button class="btn btn-xs btn-default" title="Other Options"><span class="glyphicon glyphicon-option-vertical"/></button>`)
const $btnMenu = $(`<button class="btn btn-xs btn-default" title="Other Options"><span class="glyphicon glyphicon-option-vertical"></span></button>`)
.click(evt => ContextUtil.pOpenMenu(evt, this._TOP_MENU));
$$`<div class="no-print ve-flex-v-center btn-group">${$btnEntireBook}${$btnToggleNarrow}${$btnMenu}</div>`.appendTo($wrpControls);
@@ -494,7 +494,7 @@ class BookUtil {
static initScrollTopFloat () {
const $wrpScrollTop = Omnisearch.addScrollTopFloat();
BookUtil.$wrpFloatControls = $(`<div class="ve-flex-vh-center w-100 mb-2 btn-group"/>`).prependTo($wrpScrollTop);
BookUtil.$wrpFloatControls = $(`<div class="ve-flex-vh-center w-100 mb-2 btn-group"></div>`).prependTo($wrpScrollTop);
}
// custom loading to serve multiple sources
@@ -605,8 +605,8 @@ class BookUtil {
static async _booksHashChange_pHandleFound ({fromIndex, homebrewData, bookId, hashParts, $contents, isNewBook}) {
document.title = `${fromIndex.name} - 5etools`;
$(`.book-head-header`).html(this._booksHashChange_getCleanName(fromIndex));
$(`.book-head-message`).html("Browse content. Press F to find, and G to go to page.");
$(`#page__title`).html(this._booksHashChange_getCleanName(fromIndex));
$(`#page__subtitle`).html("Browse content. Press F to find, and G to go to page.");
await this._pLoadChapter(fromIndex, bookId, hashParts, homebrewData, $contents);
NavBar.highlightCurrentPage();
if (isNewBook) MiscUtil.scrollPageTop();
@@ -723,7 +723,7 @@ class BookUtil {
$(`span.temp`).contents().unwrap();
BookUtil._lastHighlight = null;
if (BookUtil._$findAll) BookUtil._$findAll.remove();
BookUtil._$findAll = $(`<div class="f-all-wrapper"/>`)
BookUtil._$findAll = $(`<div class="f-all-wrapper"></div>`)
.on("click", (e) => {
e.stopPropagation();
});
@@ -751,8 +751,8 @@ class BookUtil {
if (found.length) {
$results.show();
found.forEach(f => {
const $row = $(`<p class="f-result"/>`);
const $ptLink = $(`<span/>`);
const $row = $(`<p class="f-result"></p>`);
const $ptLink = $(`<span></span>`);
const isLitTitle = f.headerMatches && !f.page;
const $link = $(
`<a href="#${BookUtil.Search.getResultHash(bookId, f)}">
@@ -763,7 +763,7 @@ class BookUtil {
$row.append($ptLink);
if (!isPageMode && f.previews) {
const $ptPreviews = $(`<a href="#${BookUtil.Search.getResultHash(bookId, f)}"/>`);
const $ptPreviews = $(`<a href="#${BookUtil.Search.getResultHash(bookId, f)}"></a>`);
const re = new RegExp(f.term.escapeRegexp(), "gi");
$ptPreviews.on("click", evt => {
@@ -861,7 +861,7 @@ class BookUtil {
</a>
<div class="ve-flex-v-center">
<a href="${this._getHrefShowAll(book.id)}" class="bk__contents_show_all px-2 py-1p ve-flex-v-center lst__wrp-cells lst__row-inner" title="View Entire ${BookUtil.contentType.uppercaseFirst()} (Warning: Slow)">
<span class="glyphicon glyphicon glyphicon-book" style="top: 0;"/>
<span class="glyphicon glyphicon glyphicon-book" style="top: 0;"></span>
</a>
${BookUtil.curRender.$btnToggleExpandAll}
</div>

View File

@@ -4,12 +4,12 @@ window.addEventListener("load", () => {
if (typeof [].flat !== "function") {
const $body = $(`body`);
$body.addClass("edge__body");
const $btnClose = $(`<button class="btn btn-danger edge__btn-close"><span class="glyphicon glyphicon-remove"/></button>`)
const $btnClose = $(`<button class="btn btn-danger edge__btn-close"><span class="glyphicon glyphicon-remove"></span></button>`)
.click(() => {
$overlay.remove();
$body.removeClass("edge__body");
});
const $overlay = $(`<div class="ve-flex-col ve-flex-vh-center relative edge__overlay"/>`);
const $overlay = $(`<div class="ve-flex-col ve-flex-vh-center relative edge__overlay"></div>`);
$btnClose.appendTo($overlay);
$overlay.append(`<div class="ve-flex-col ve-flex-vh-center">
<div class="edge__title mb-2">UPDATE YOUR BROWSER</div>

13
js/changelog.js Normal file
View File

@@ -0,0 +1,13 @@
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
DataUtil.loadJSON(`${Renderer.get().baseUrl}data/changelog.json`)
.then(changelog => {
const $wrp = $(`#pagecontent`).empty();
UtilsChangelog.renderChangelog(changelog, $wrp);
});
});

View File

@@ -982,7 +982,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
<tr><th class="border" colspan="15"></th></tr>
<tr><th class="cls-tbl__disp-name" colspan="15">${cls.name}</th></tr>
<tr>
<th colspan="3"/> <!-- spacer to match the 3 default cols (level, prof, features) -->
<th colspan="3"></th> <!-- spacer to match the 3 default cols (level, prof, features) -->
${$tblGroupHeaders}
</tr>
<tr>
@@ -1012,7 +1012,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
const $thGroupHeader = tableGroup.title
? $(`<th class="cls-tbl__col-group" colspan="${colLabels.length}">${tableGroup.title}</th>`)
// if there's no title, add a spacer
: $(`<th colspan="${colLabels.length}"/>`);
: $(`<th colspan="${colLabels.length}"></th>`);
$tblGroupHeaders.push($thGroupHeader);
// Render column headers (bottom section)
@@ -1104,7 +1104,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
hkSetHref();
// Make a dummy for the last item
const $dispComma = ixFeature === lvlFeaturesFilt.length - 1 ? $(`<span/>`) : $(`<span class="mr-1">,</span>`);
const $dispComma = ixFeature === lvlFeaturesFilt.length - 1 ? $(`<span></span>`) : $(`<span class="mr-1">,</span>`);
return {
$wrpLink: $$`<div class="inline-block">${$lnk}${$dispComma}</div>`,
$dispComma,
@@ -1331,7 +1331,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
equip.default && equip.default.length ? `<ul class="pl-4"><li>${equip.default.map(it => Renderer.get().render(it)).join("</li><li>")}</ul>` : "",
equip.goldAlternative != null ? `<p>Alternatively, you may start with ${Renderer.get().render(equip.goldAlternative)} gp to buy your own equipment.</p>` : "",
].filter(Boolean).join("");
const $dispRendered = $(`<div/>`);
const $dispRendered = $(`<div></div>`);
$ptEquipment = $$`<tr>
<td class="cls-side__section" colspan="6">
@@ -1472,7 +1472,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
// endregion
// region subclasses
const $wrpScTabs = $(`<div class="ve-flex-v-center ve-flex-wrap mr-2 w-100"/>`).appendTo($wrp);
const $wrpScTabs = $(`<div class="ve-flex-v-center ve-flex-wrap mr-2 w-100"></div>`).appendTo($wrp);
this._listSubclass = new List({$wrpList: $wrpScTabs, isUseJquery: true, fnSort: ClassesPage._fnSortSubclassFilterItems});
cls.subclasses.forEach((sc, i) => {
@@ -1481,7 +1481,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
this._listSubclass.addItem(listItem);
});
const $dispCount = $(`<div class="text-muted m-1 cls-tabs__sc-not-shown ve-flex-vh-center"/>`);
const $dispCount = $(`<div class="text-muted m-1 cls-tabs__sc-not-shown ve-flex-vh-center"></div>`);
this._listSubclass.addItem(new ListItem(
-1,
$dispCount,
@@ -1521,7 +1521,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
async _render_pInitSubclassControls ($wrp) {
const cls = this.activeClass;
const $btnSelAll = $(`<button class="btn btn-xs btn-default" title="Select All (SHIFT to filter for and include most recent; CTRL to select official plus homebrew)"><span class="glyphicon glyphicon-check"/></button>`)
const $btnSelAll = $(`<button class="btn btn-xs btn-default" title="Select All (SHIFT to filter for and include most recent; CTRL to select official plus homebrew)"><span class="glyphicon glyphicon-check"></span></button>`)
.click(evt => {
const allStateKeys = cls.subclasses.map(sc => UrlUtil.getStateKeySubclass(sc));
if (evt.shiftKey) {
@@ -1608,7 +1608,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
filterSets.forEach((it, i) => $selFilterPreset.append(`<option value="${i}">${it.name}</option>`));
$selFilterPreset.val("-1");
const $btnReset = $(`<button class="btn btn-xs btn-default" title="Reset Selection"><span class="glyphicon glyphicon-refresh"/></button>`)
const $btnReset = $(`<button class="btn btn-xs btn-default" title="Reset Selection"><span class="glyphicon glyphicon-refresh"></span></button>`)
.click(() => {
this._proxyAssign("state", "_state", "__state", cls.subclasses.mergeMap(sc => ({[UrlUtil.getStateKeySubclass(sc)]: false})));
});
@@ -1618,9 +1618,9 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
// Remove the temporary "hidden" class used to prevent popping
this._listSubclass.items.forEach(it => it.ele.showVe());
const $btnToggleSources = ComponentUiUtil.$getBtnBool(this, "isShowScSources", {$ele: $(`<button class="btn btn-xs btn-default ve-flex-1" title="Show Subclass Sources"><span class="glyphicon glyphicon-book"/></button>`)});
const $btnToggleSources = ComponentUiUtil.$getBtnBool(this, "isShowScSources", {$ele: $(`<button class="btn btn-xs btn-default ve-flex-1" title="Show Subclass Sources"><span class="glyphicon glyphicon-book"></span></button>`)});
const $btnShuffle = $(`<button title="Feeling Lucky?" class="btn btn-xs btn-default ve-flex-1"><span class="glyphicon glyphicon-random"/></button>`)
const $btnShuffle = $(`<button title="Feeling Lucky?" class="btn btn-xs btn-default ve-flex-1"><span class="glyphicon glyphicon-random"></span></button>`)
.click(() => {
if (!this._listSubclass.visibleItems.length) return JqueryUtil.doToast({content: "No subclasses to choose from!", type: "warning"});
@@ -1665,7 +1665,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
if (this._state[stateKey] == null) this._state[stateKey] = false;
const $dispName = $(`<div title="${ClassesPage.getBtnTitleSubclass(sc)}"/>`);
const $dispName = $(`<div title="${ClassesPage.getBtnTitleSubclass(sc)}"></div>`);
const $dispSource = $(`<div class="ml-1" title="${Parser.sourceJsonToFull(sc.source)}">(${Parser.sourceJsonToAbv(sc.source)})</div>`);
const hkSourcesVisible = () => {
$dispName.text(this._state.isShowScSources ? ClassesPage.getBaseShortName(sc) : sc.shortName);
@@ -1725,7 +1725,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
// Auto-hide the outline on small screens
if (Renderer.hover.isSmallScreen()) this._state.isHideOutline = true;
const $dispShowHide = $(`<div class="cls-nav__disp-toggle"/>`);
const $dispShowHide = $(`<div class="cls-nav__disp-toggle"></div>`);
const $wrpHeadInner = $$`<div class="cls-nav__head-inner split">
<div>Outline</div>
${$dispShowHide}
@@ -1736,7 +1736,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
${$wrpHeadInner}
<hr class="cls-nav__hr">
</div>`.appendTo(this._$wrpOutline);
const $wrpBody = $(`<div class="nav-body"/>`).appendTo(this._$wrpOutline);
const $wrpBody = $(`<div class="nav-body"></div>`).appendTo(this._$wrpOutline);
const hkShowHide = () => {
$wrpHead.toggleClass("cls-nav__head--active", !this._state.isHideOutline);
@@ -2108,7 +2108,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
if (cls.otherSources) {
const text = Renderer.utils.getSourceAndPageHtml(cls);
const $trClassFeature = $(`<tr data-feature-type="class"><td colspan="6"/></tr>`)
const $trClassFeature = $(`<tr data-feature-type="class"><td colspan="6"></td></tr>`)
.fastSetHtml(`<hr class="hr-1"><b>Class source:</b> ${text}`)
.appendTo($content);
}
@@ -2147,7 +2147,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
if (source === cls.source) return {isSkip: true};
},
fn: () => {
return $(`<tr data-scroll-id="${ixLvl}-${ixFeature}" data-feature-type="class" class="cls-main__linked-titles"><td colspan="6"/></tr>`)
return $(`<tr data-scroll-id="${ixLvl}-${ixFeature}" data-feature-type="class" class="cls-main__linked-titles"><td colspan="6"></td></tr>`)
.fastSetHtml(Renderer.get().setDepthTracker(depthArr, {additionalProps: ["isReprinted"], additionalPropsInherited: ["_isStandardSource", "isClassFeatureVariant"]}).render(feature))
.appendTo($content);
},
@@ -2161,7 +2161,7 @@ class ClassesPage extends MixinComponentGlobalState(MixinBaseComponent(MixinProx
$trClassFeature.attr("data-feature-type", "gain-subclass");
// Add a placeholder feature to display when no subclasses are active
const $trSubclassFeature = $(`<tr class="cls-main__sc-feature" data-subclass-none-message="true"><td colspan="6"/></tr>`)
const $trSubclassFeature = $(`<tr class="cls-main__sc-feature" data-subclass-none-message="true"><td colspan="6"></td></tr>`)
.fastSetHtml(Renderer.get().setDepthTracker([]).render({type: "entries", entries: [{name: `{@note No Subclass Selected}`, type: "entries", entries: [`{@note <span class="clickable roller" data-jump-select-a-subclass="true">Select a subclass</span> to view its feature(s) here.}`]}]}))
.appendTo($content);

View File

@@ -73,7 +73,7 @@ class BaseConverter extends BaseComponent {
/* -------------------------------------------- */
renderSidebar (parent, $parent) {
const $wrpSidebar = $(`<div class="w-100 ve-flex-col"/>`).appendTo($parent);
const $wrpSidebar = $(`<div class="w-100 ve-flex-col"></div>`).appendTo($parent);
const hkShowSidebar = () => $wrpSidebar.toggleClass("hidden", parent.get("converter") !== this._converterId);
parent.addHook("converter", hkShowSidebar);
hkShowSidebar();
@@ -158,7 +158,7 @@ class BaseConverter extends BaseComponent {
_renderSidebarSourcePart (parent, $wrpSidebar) {
if (!this._hasSource) return;
const $wrpSourceOverlay = $(`<div class="h-100 w-100"/>`);
const $wrpSourceOverlay = $(`<div class="h-100 w-100"></div>`);
let modalMeta = null;
const rebuildStageSource = (options) => {
@@ -191,10 +191,10 @@ class BaseConverter extends BaseComponent {
<select class="form-control input-xs"><option value="">(None)</option></select>`
.change(() => this._state.source = $selSource.val());
$(`<option/>`, {val: "5e_divider", text: `\u2014`, disabled: true}).appendTo($selSource);
$(`<option></option>`, {val: "5e_divider", text: `\u2014`, disabled: true}).appendTo($selSource);
Object.keys(Parser.SOURCE_JSON_TO_FULL)
.forEach(src => $(`<option/>`, {val: src, text: Parser.sourceJsonToFull(src)}).appendTo($selSource));
.forEach(src => $(`<option></option>`, {val: src, text: Parser.sourceJsonToFull(src)}).appendTo($selSource));
const hkAvailSources = () => {
const curSources = new Set($selSource.find(`option`).map((i, e) => $(e).val()));
@@ -217,7 +217,7 @@ class BaseConverter extends BaseComponent {
const $optBrewLast = $selSource.find(`option[disabled]`).prev();
optionsToAdd.forEach(source => {
const fullSource = BrewUtil2.sourceJsonToSource(source);
$(`<option/>`, {val: fullSource.json, text: fullSource.full}).insertAfter($optBrewLast);
$(`<option></option>`, {val: fullSource.json, text: fullSource.full}).insertAfter($optBrewLast);
});
}
@@ -1367,7 +1367,7 @@ class ConverterUi extends BaseComponent {
ConverterUiUtil.renderSideMenuDivider($mnu);
// endregion
const $wrpConverters = $(`<div class="w-100 ve-flex-col"/>`).appendTo($mnu);
const $wrpConverters = $(`<div class="w-100 ve-flex-col"></div>`).appendTo($mnu);
Object
.keys(this._converters)
.sort(SortUtil.ascSortLower)

View File

@@ -255,6 +255,8 @@ class AcConvert {
case "natural & tailored leather":
case "canny defense": // Dungeons of Drakkenheim
return fromLow;
case "plate armor of bhaal": return "plate armor of Bhaal";
// endregion
// region homebrew

View File

@@ -57,8 +57,8 @@ function addMonsterFeatures (mfData) {
});
// when clicking a row in the "Monster Statistics by Challenge Rating" table
$("#msbcr tr").not(":has(th)").click(function () {
if (!confirm("This will reset the calculator. Are you sure?")) return;
$("#msbcr tr").not(":has(th)").click(async function () {
if (!await InputUiUtil.pGetUserBoolean({title: "Reset", htmlDescription: "This will reset the calculator. Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
$("#expectedcr").val($(this).children("td:eq(0)").html());
const [minHp, maxHp] = $(this).children("td:eq(4)").html().split("-").map(it => parseInt(it));
$("#hp").val(minHp + (maxHp - minHp) / 2);
@@ -156,11 +156,10 @@ function addMonsterFeatures (mfData) {
$("#monsterfeatures .crc__wrp_mon_features input").change(calculateCr);
$("#crcalc_reset").click(() => {
confirm("Are you sure?") && (() => {
window.location = "";
parseUrl();
})();
$("#crcalc_reset").click(async () => {
if (!await InputUiUtil.pGetUserBoolean({title: "Reset", htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
window.location = "";
parseUrl();
});
parseUrl();

View File

@@ -768,12 +768,16 @@ class SideMenu {
const $wrpResizeH = $(`<div class="w-100 mb-2 split-v-center"><div class="sidemenu__row__label">Height</div></div>`).appendTo(this.$mnu);
const $iptHeight = $(`<input class="form-control" type="number" value="${this.board.height}">`).appendTo($wrpResizeH);
this.$iptHeight = $iptHeight;
const $wrpSetDim = $(`<div class="w-100 split-v-center"/>`).appendTo(this.$mnu);
const $wrpSetDim = $(`<div class="w-100 split-v-center"></div>`).appendTo(this.$mnu);
const $btnSetDim = $(`<button class="btn btn-primary" style="width: 100%;">Set Dimensions</div>`).appendTo($wrpSetDim);
$btnSetDim.on("click", () => {
$btnSetDim.on("click", async () => {
const w = Number($iptWidth.val());
const h = Number($iptHeight.val());
if ((w > 10 || h > 10) && !window.confirm("That's a lot of panels. You sure?")) return;
if (w > 10 || h > 10) {
if (!await InputUiUtil.pGetUserBoolean({title: "Too Many Panels", htmlDescription: "That's a lot of panels. Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
}
this.board.setDimensions(w, h);
});
renderDivider();
@@ -782,7 +786,7 @@ class SideMenu {
const $btnFullscreen = $(`<button class="btn btn-primary">Toggle Fullscreen</button>`).appendTo($wrpFullscreen);
this.board.$btnFullscreen = $btnFullscreen;
$btnFullscreen.on("click", () => this.board.doToggleFullscreen());
const $btnLockPanels = $(`<button class="btn btn-danger" title="Lock Panels"><span class="glyphicon glyphicon-lock"/></button>`).appendTo($wrpFullscreen);
const $btnLockPanels = $(`<button class="btn btn-danger" title="Lock Panels"><span class="glyphicon glyphicon-lock"></span></button>`).appendTo($wrpFullscreen);
this.board.$btnLockPanels = $btnLockPanels;
$btnLockPanels.on("click", () => {
this.board.isLocked = !this.board.isLocked;
@@ -798,8 +802,8 @@ class SideMenu {
});
renderDivider();
const $wrpSaveLoad = $(`<div class="w-100"/>`).appendTo(this.$mnu);
const $wrpSaveLoadFile = $(`<div class="w-100 mb-2 ve-flex-vh-center-around"/>`).appendTo($wrpSaveLoad);
const $wrpSaveLoad = $(`<div class="w-100"></div>`).appendTo(this.$mnu);
const $wrpSaveLoadFile = $(`<div class="w-100 mb-2 ve-flex-vh-center-around"></div>`).appendTo($wrpSaveLoad);
const $btnSaveFile = $(`<button class="btn btn-primary">Save to File</button>`).appendTo($wrpSaveLoadFile);
$btnSaveFile.on("click", () => {
DataUtil.userDownload(`dm-screen`, this.board.getSaveableState(), {fileType: "dm-screen"});
@@ -814,7 +818,7 @@ class SideMenu {
this.board.doReset();
await this.board.pDoLoadStateFrom(jsons[0]);
});
const $wrpSaveLoadUrl = $(`<div class="w-100 ve-flex-vh-center-around"/>`).appendTo($wrpSaveLoad);
const $wrpSaveLoadUrl = $(`<div class="w-100 ve-flex-vh-center-around"></div>`).appendTo($wrpSaveLoad);
const $btnSaveLink = $(`<button class="btn btn-primary">Save to URL</button>`).appendTo($wrpSaveLoadUrl);
$btnSaveLink.on("click", async () => {
const encoded = `${window.location.href.split("#")[0]}#${encodeURIComponent(JSON.stringify(this.board.getSaveableState()))}`;
@@ -827,16 +831,15 @@ class SideMenu {
this.board.$cbConfirmTabClose = $(`<input type="checkbox" class="sidemenu__row__label__cb">`).appendTo($wrpCbConfirm.find(`label`));
renderDivider();
const $wrpReset = $(`<div class="w-100 split-v-center"/>`).appendTo(this.$mnu);
const $wrpReset = $(`<div class="w-100 split-v-center"></div>`).appendTo(this.$mnu);
const $btnReset = $(`<button class="btn btn-danger" style="width: 100%;">Reset Screen</button>`).appendTo($wrpReset);
$btnReset.on("click", () => {
if (window.confirm("Are you sure?")) {
this.board.doReset();
}
$btnReset.on("click", async () => {
if (!await InputUiUtil.pGetUserBoolean({title: "Reset", htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
this.board.doReset();
});
renderDivider();
this.$wrpHistory = $(`<div class="sidemenu__history"/>`).appendTo(this.$mnu);
this.$wrpHistory = $(`<div class="sidemenu__history"></div>`).appendTo(this.$mnu);
}
doUpdateDimensions () {
@@ -857,10 +860,10 @@ class SideMenu {
});
}
this.board.exiledPanels.forEach((p, i) => {
const $wrpHistItem = $(`<div class="sidemenu__history-item"/>`).appendTo(this.$wrpHistory);
const $cvrHistItem = $(`<div class="sidemenu__history-item-cover"/>`).appendTo($wrpHistItem);
const $btnRemove = $(`<div class="panel-history-control-remove-wrapper"><span class="panel-history-control-remove glyphicon glyphicon-remove" title="Remove"/></div>`).appendTo($cvrHistItem);
const $ctrlMove = $(`<div class="panel-history-control-middle" title="Move"/>`).appendTo($cvrHistItem);
const $wrpHistItem = $(`<div class="sidemenu__history-item"></div>`).appendTo(this.$wrpHistory);
const $cvrHistItem = $(`<div class="sidemenu__history-item-cover"></div>`).appendTo($wrpHistItem);
const $btnRemove = $(`<div class="panel-history-control-remove-wrapper"><span class="panel-history-control-remove glyphicon glyphicon-remove" title="Remove"></span></div>`).appendTo($cvrHistItem);
const $ctrlMove = $(`<div class="panel-history-control-middle" title="Move"></div>`).appendTo($cvrHistItem);
$btnRemove.on("click", () => {
this.board.exiledPanels[i].destroy();
@@ -1205,8 +1208,8 @@ class Panel {
const fn = Renderer.hover.getFnRenderCompact(page);
const $contentInner = $(`<div class="panel-content-wrapper-inner"/>`);
const $contentStats = $(`<table class="w-100 stats"/>`).appendTo($contentInner);
const $contentInner = $(`<div class="panel-content-wrapper-inner"></div>`);
const $contentStats = $(`<table class="w-100 stats"></table>`).appendTo($contentInner);
$contentStats.append(fn(it));
const fnBind = Renderer.hover.getFnBindListenersCompact(page);
@@ -1397,8 +1400,8 @@ class Panel {
hash,
).then(it => {
ScaleCreature.scale(it, targetCr).then(initialRender => {
const $contentInner = $(`<div class="panel-content-wrapper-inner"/>`);
const $contentStats = $(`<table class="w-100 stats"/>`).appendTo($contentInner);
const $contentInner = $(`<div class="panel-content-wrapper-inner"></div>`);
const $contentStats = $(`<table class="w-100 stats"></table>`).appendTo($contentInner);
$contentStats.append(Renderer.monster.getCompactRenderedString(initialRender, {isShowScalers: true, isScaledCr: true}));
this._stats_bindCrScaleClickHandler(it, meta, $contentInner, $contentStats);
@@ -1428,8 +1431,8 @@ class Panel {
hash,
).then(it => {
ScaleSpellSummonedCreature.scale(it, summonSpellLevel).then(scaledMon => {
const $contentInner = $(`<div class="panel-content-wrapper-inner"/>`);
const $contentStats = $(`<table class="w-100 stats"/>`).appendTo($contentInner);
const $contentInner = $(`<div class="panel-content-wrapper-inner"></div>`);
const $contentStats = $(`<table class="w-100 stats"></table>`).appendTo($contentInner);
$contentStats.append(Renderer.monster.getCompactRenderedString(scaledMon, {isShowScalers: true, isScaledSpellSummon: true}));
this._stats_doUpdateSummonScaleDropdowns(scaledMon, $contentStats);
@@ -1461,8 +1464,8 @@ class Panel {
hash,
).then(it => {
ScaleClassSummonedCreature.scale(it, summonClassLevel).then(scaledMon => {
const $contentInner = $(`<div class="panel-content-wrapper-inner"/>`);
const $contentStats = $(`<table class="w-100 stats"/>`).appendTo($contentInner);
const $contentInner = $(`<div class="panel-content-wrapper-inner"></div>`);
const $contentStats = $(`<table class="w-100 stats"></table>`).appendTo($contentInner);
$contentStats.append(Renderer.monster.getCompactRenderedString(scaledMon, {isShowScalers: true, isScaledClassSummon: true}));
this._stats_doUpdateSummonScaleDropdowns(scaledMon, $contentStats);
@@ -1554,7 +1557,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_ROLLBOX,
null,
$(`<div class="panel-content-wrapper-inner"/>`).append(Renderer.dice.get$Roller().addClass("rollbox-panel")),
$(`<div class="panel-content-wrapper-inner"></div>`).append(Renderer.dice.get$Roller().addClass("rollbox-panel")),
title || "Dice Roller",
true,
!!title,
@@ -1565,7 +1568,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_COUNTER,
state,
$(`<div class="panel-content-wrapper-inner"/>`).append(Counter.$getCounter(this.board, state)),
$(`<div class="panel-content-wrapper-inner"></div>`).append(Counter.$getCounter(this.board, state)),
title || "Counter",
true,
);
@@ -1575,7 +1578,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_UNIT_CONVERTER,
state,
$(`<div class="panel-content-wrapper-inner"/>`).append(UnitConverter.make$Converter(this.board, state)),
$(`<div class="panel-content-wrapper-inner"></div>`).append(UnitConverter.make$Converter(this.board, state)),
title || "Unit Converter",
true,
);
@@ -1585,7 +1588,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_MONEY_CONVERTER,
state,
$(`<div class="panel-content-wrapper-inner"/>`).append(MoneyConverter.make$Converter(this.board, state)),
$(`<div class="panel-content-wrapper-inner"></div>`).append(MoneyConverter.make$Converter(this.board, state)),
title || "Money Converter",
true,
);
@@ -1595,7 +1598,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_TIME_TRACKER,
state,
$(`<div class="panel-content-wrapper-inner"/>`).append(TimeTracker.$getTracker(this.board, state)),
$(`<div class="panel-content-wrapper-inner"></div>`).append(TimeTracker.$getTracker(this.board, state)),
title || "Time Tracker",
true,
);
@@ -1605,7 +1608,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_TEXTBOX,
null,
$(`<div class="panel-content-wrapper-inner ve-overflow-y-hidden"/>`).append(NoteBox.make$Notebox(this.board, content)),
$(`<div class="panel-content-wrapper-inner ve-overflow-y-hidden"></div>`).append(NoteBox.make$Notebox(this.board, content)),
title,
true,
);
@@ -1639,7 +1642,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_TWITCH_CHAT,
meta,
$(`<div class="panel-content-wrapper-inner"><iframe src="${url}?parent=${location.hostname}" frameborder="0" scrolling="no" id="${channelId}"/></div>`),
$(`<div class="panel-content-wrapper-inner"><iframe src="${url}?parent=${location.hostname}" frameborder="0" scrolling="no" id="${channelId}"></iframe></div>`),
title,
true,
);
@@ -1650,7 +1653,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_GENERIC_EMBED,
meta,
$(`<div class="panel-content-wrapper-inner"><iframe src="${url}"/></div>`),
$(`<div class="panel-content-wrapper-inner"><iframe src="${url}"></iframe></div>`),
title,
true,
);
@@ -1658,10 +1661,10 @@ class Panel {
doPopulate_Image (url, title = "Image") {
const meta = {u: url};
const $wrpPanel = $(`<div class="panel-content-wrapper-inner"/>`);
const $wrpImage = $(`<div class="panel-content-wrapper-img"/>`).appendTo($wrpPanel);
const $wrpPanel = $(`<div class="panel-content-wrapper-inner"></div>`);
const $wrpImage = $(`<div class="panel-content-wrapper-img"></div>`).appendTo($wrpPanel);
const $img = $(`<img src="${url}" alt="${title}" loading="lazy">`).appendTo($wrpImage);
const $iptReset = $(`<button class="panel-zoom-reset btn btn-xs btn-default"><span class="glyphicon glyphicon-refresh"/></button>`).appendTo($wrpPanel);
const $iptReset = $(`<button class="panel-zoom-reset btn btn-xs btn-default"><span class="glyphicon glyphicon-refresh"></span></button>`).appendTo($wrpPanel);
const $iptRange = $(`<input type="range" class="panel-zoom-slider">`).appendTo($wrpPanel);
this.set$ContentTab(
PANEL_TYP_IMAGE,
@@ -1683,7 +1686,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_ADVENTURE_DYNAMIC_MAP,
state,
$(`<div class="panel-content-wrapper-inner"/>`).append(DmMapper.$getMapper(this.board, state)),
$(`<div class="panel-content-wrapper-inner"></div>`).append(DmMapper.$getMapper(this.board, state)),
title || "Map Viewer",
true,
);
@@ -1693,7 +1696,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_ERROR,
state,
$(`<div class="panel-content-wrapper-inner"/>`).append(`<div class="w-100 h-100 ve-flex-vh-center text-danger"><div>${state.message}</div></div>`),
$(`<div class="panel-content-wrapper-inner"></div>`).append(`<div class="w-100 h-100 ve-flex-vh-center text-danger"><div>${state.message}</div></div>`),
title,
true,
);
@@ -1704,7 +1707,7 @@ class Panel {
this.set$ContentTab(
PANEL_TYP_BLANK,
meta,
$(`<div class="dm-blank__panel"/>`),
$(`<div class="dm-blank__panel"></div>`),
title,
true,
);
@@ -2094,22 +2097,22 @@ class Panel {
};
function doInitialRender () {
const $pnl = $(`<div data-panelId="${this.id}" class="dm-screen-panel min-w-0 min-h-0" empty="true"/>`);
const $pnl = $(`<div data-panelId="${this.id}" class="dm-screen-panel min-w-0 min-h-0" empty="true"></div>`);
this.$pnl = $pnl;
const $ctrlBar = $(`<div class="panel-control-bar"/>`).appendTo($pnl);
this.$pnlTitle = $(`<div class="panel-control-bar panel-control-title"/>`).appendTo($pnl).click(() => this.$pnlTitle.toggleClass("panel-control-title--bumped"));
this.$pnlAddTab = $(`<div class="panel-control-bar panel-control-addtab"><div class="panel-control-icon glyphicon glyphicon-plus" title="Add Tab"/></div>`).click(() => {
const $ctrlBar = $(`<div class="panel-control-bar"></div>`).appendTo($pnl);
this.$pnlTitle = $(`<div class="panel-control-bar panel-control-title"></div>`).appendTo($pnl).click(() => this.$pnlTitle.toggleClass("panel-control-title--bumped"));
this.$pnlAddTab = $(`<div class="panel-control-bar panel-control-addtab"><div class="panel-control-icon glyphicon glyphicon-plus" title="Add Tab"></div></div>`).click(() => {
this.setIsTabs(true);
this.setDirty(true);
this.render();
openAddMenu();
}).appendTo($pnl);
const $ctrlMove = $(`<div class="panel-control-icon glyphicon glyphicon-move" title="Move"/>`).appendTo($ctrlBar);
const $ctrlMove = $(`<div class="panel-control-icon glyphicon glyphicon-move" title="Move"></div>`).appendTo($ctrlBar);
$ctrlMove.on("click", () => {
this.toggleMovable();
});
const $ctrlEmpty = $(`<div class="panel-control-icon glyphicon glyphicon-remove" title="Close"/>`).appendTo($ctrlBar);
const $ctrlEmpty = $(`<div class="panel-control-icon glyphicon glyphicon-remove" title="Close"></div>`).appendTo($ctrlBar);
$ctrlEmpty.on("click", () => {
this.getReplacementPanel();
});
@@ -2118,9 +2121,9 @@ class Panel {
this.joyMenu = joyMenu;
joyMenu.initialise();
const $wrpContent = $(`<div class="panel-content-wrapper"/>`).appendTo($pnl);
const $wrpBtnAdd = $(`<div class="panel-add"/>`).appendTo($wrpContent);
const $btnAdd = $(`<span class="btn-panel-add glyphicon glyphicon-plus"/>`)
const $wrpContent = $(`<div class="panel-content-wrapper"></div>`).appendTo($pnl);
const $wrpBtnAdd = $(`<div class="panel-add"></div>`).appendTo($wrpContent);
const $btnAdd = $(`<span class="btn-panel-add glyphicon glyphicon-plus"></span>`)
.on("click", () => {
openAddMenu();
})
@@ -2144,13 +2147,13 @@ class Panel {
this.$btnAddInner = $btnAdd;
this.$pnlWrpContent = $wrpContent;
const $wrpTabs = $(`<div class="content-tab-bar ve-flex"/>`).hideVe().appendTo($pnl);
const $wrpTabsInner = $(`<div class="content-tab-bar-inner"/>`).on("wheel", (evt) => {
const $wrpTabs = $(`<div class="content-tab-bar ve-flex"></div>`).hideVe().appendTo($pnl);
const $wrpTabsInner = $(`<div class="content-tab-bar-inner"></div>`).on("wheel", (evt) => {
const delta = evt.originalEvent.deltaY;
const curr = $wrpTabsInner.scrollLeft();
$wrpTabsInner.scrollLeft(Math.max(0, curr + delta));
}).appendTo($wrpTabs);
const $btnTabAdd = $(`<button class="btn btn-default content-tab"><span class="glyphicon glyphicon-plus"/></button>`)
const $btnTabAdd = $(`<button class="btn btn-default content-tab"><span class="glyphicon glyphicon-plus"></span></button>`)
.click(() => openAddMenu()).appendTo($wrpTabsInner);
this.$pnlWrpTabs = $wrpTabs;
this.$pnlTabs = $wrpTabsInner;
@@ -2280,8 +2283,11 @@ class Panel {
_get$BtnSelTab (ix, title, tabCanRename) {
title = title || "[Untitled]";
const doCloseTabWithConfirmation = () => {
if (!this.board.getConfirmTabClose() || (this.board.getConfirmTabClose() && confirm(`Are you sure you want to close tab "${this.tabDatas[ix].title}"?`))) this.doCloseTab(ix);
const doCloseTabWithConfirmation = async () => {
if (this.board.getConfirmTabClose()) {
if (!await InputUiUtil.pGetUserBoolean({title: "Close Tab", htmlDescription: `Are you sure you want to close tab "${this.tabDatas[ix].title}"?`, textYes: "Yes", textNo: "Cancel"})) return;
}
this.doCloseTab(ix);
};
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>`)
@@ -2303,7 +2309,7 @@ class Panel {
}
}
});
const $btnCloseTab = $(`<span class="glyphicon glyphicon-remove content-tab-remove"/>`)
const $btnCloseTab = $(`<span class="glyphicon glyphicon-remove content-tab-remove"></span>`)
.on("mousedown", (evt) => {
if (evt.button === 0) {
evt.stopPropagation();
@@ -2986,13 +2992,13 @@ class AddMenu {
render () {
if (!this._$menuInner) {
this._$menuInner = $(`<div class="ve-flex-col w-100 h-100">`);
const $tabBar = $(`<div class="panel-addmenu-bar"/>`).appendTo(this._$menuInner);
this.$tabView = $(`<div class="panel-addmenu-view"/>`).appendTo(this._$menuInner);
const $tabBar = $(`<div class="panel-addmenu-bar"></div>`).appendTo(this._$menuInner);
this.$tabView = $(`<div class="panel-addmenu-view"></div>`).appendTo(this._$menuInner);
this.tabs.forEach(t => {
t.render();
const $head = $(`<button class="btn btn-default panel-addmenu-tab-head">${t.label}</button>`).appendTo($tabBar);
const $body = $(`<div class="panel-addmenu-tab-body"/>`).appendTo($tabBar);
const $body = $(`<div class="panel-addmenu-tab-body"></div>`).appendTo($tabBar);
$body.append(t.get$Tab);
t.$head = $head;
t.$body = $body;
@@ -3056,9 +3062,9 @@ class AddMenuVideoTab extends AddMenuTab {
render () {
if (!this.$tab) {
const $tab = $(`<div class="ui-search__wrp-output underline-tabs" id="${this.tabId}"/>`);
const $tab = $(`<div class="ui-search__wrp-output underline-tabs" id="${this.tabId}"></div>`);
const $wrpYT = $(`<div class="ui-modal__row"/>`).appendTo($tab);
const $wrpYT = $(`<div class="ui-modal__row"></div>`).appendTo($tab);
const $iptUrlYT = $(`<input class="form-control" placeholder="Paste YouTube URL">`)
.on("keydown", (e) => {
if (e.which === 13) $btnAddYT.click();
@@ -3081,7 +3087,7 @@ class AddMenuVideoTab extends AddMenuTab {
}
});
const $wrpTwitch = $(`<div class="ui-modal__row"/>`).appendTo($tab);
const $wrpTwitch = $(`<div class="ui-modal__row"></div>`).appendTo($tab);
const $iptUrlTwitch = $(`<input class="form-control" placeholder="Paste Twitch URL">`)
.on("keydown", (e) => {
if (e.which === 13) $btnAddTwitch.click();
@@ -3124,7 +3130,7 @@ class AddMenuVideoTab extends AddMenuTab {
}
});
const $wrpGeneric = $(`<div class="ui-modal__row"/>`).appendTo($tab);
const $wrpGeneric = $(`<div class="ui-modal__row"></div>`).appendTo($tab);
const $iptUrlGeneric = $(`<input class="form-control" placeholder="Paste any URL">`)
.on("keydown", (e) => {
if (e.which === 13) $iptUrlGeneric.click();
@@ -3157,10 +3163,10 @@ class AddMenuImageTab extends AddMenuTab {
render () {
if (!this.$tab) {
const $tab = $(`<div class="ui-search__wrp-output underline-tabs" id="${this.tabId}"/>`);
const $tab = $(`<div class="ui-search__wrp-output underline-tabs" id="${this.tabId}"></div>`);
// region Imgur
const $wrpImgur = $(`<div class="ui-modal__row"/>`).appendTo($tab);
const $wrpImgur = $(`<div class="ui-modal__row"></div>`).appendTo($tab);
$(`<span>Imgur (Anonymous Upload) <i class="text-muted">(accepts <a href="https://help.imgur.com/hc/articles/115000083326" target="_blank" rel="noopener noreferrer">imgur-friendly formats</a>)</i></span>`).appendTo($wrpImgur);
const $iptFile = $(`<input type="file" class="hidden">`).on("change", (evt) => {
const input = evt.target;
@@ -3213,7 +3219,7 @@ class AddMenuImageTab extends AddMenuTab {
// endregion
// region URL
const $wrpUtl = $(`<div class="ui-modal__row"/>`).appendTo($tab);
const $wrpUtl = $(`<div class="ui-modal__row"></div>`).appendTo($tab);
const $iptUrl = $(`<input class="form-control" placeholder="Paste image URL">`)
.on("keydown", (e) => {
if (e.which === 13) $btnAddUrl.click();
@@ -3234,7 +3240,7 @@ class AddMenuImageTab extends AddMenuTab {
});
// endregion
$(`<hr class="hr-2"/>`).appendTo($tab);
$(`<hr class="hr-2">`).appendTo($tab);
// region Adventure dynamic viewer
const $btnSelectAdventure = $(`<button class="btn btn-primary btn-sm">Add</button>`)
@@ -3259,7 +3265,7 @@ class AddMenuSpecialTab extends AddMenuTab {
render () {
if (!this.$tab) {
const $tab = $(`<div class="ui-search__wrp-output underline-tabs ve-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}"></div>`);
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);
@@ -3267,7 +3273,7 @@ class AddMenuSpecialTab extends AddMenuTab {
Renderer.dice.bindDmScreenPanel(this.menu.pnl);
this.menu.doClose();
});
$(`<hr class="hr-2"/>`).appendTo($tab);
$(`<hr class="hr-2">`).appendTo($tab);
const $btnTracker = $(`<button class="btn btn-primary btn-sm">Add</button>`)
.on("click", async () => {
@@ -3317,7 +3323,7 @@ class AddMenuSpecialTab extends AddMenuTab {
${$btnPlayerTrackerV0}
</div>`.appendTo($tab);
$(`<hr class="hr-2"/>`).appendTo($tab);
$(`<hr class="hr-2">`).appendTo($tab);
const $btnSublist = $(`<button class="btn btn-primary btn-sm">Add</button>`)
.click(async evt => {
@@ -3330,7 +3336,7 @@ class AddMenuSpecialTab extends AddMenuTab {
${$btnSublist}
</div>`.appendTo($tab);
$(`<hr class="hr-2"/>`).appendTo($tab);
$(`<hr class="hr-2">`).appendTo($tab);
const $btnSwitchToEmbedTag = $(`<button class="btn btn-default btn-xxs">embed</button>`)
.click(() => {
@@ -3343,7 +3349,7 @@ class AddMenuSpecialTab extends AddMenuTab {
this.menu.pnl.doPopulate_TextBox();
this.menu.doClose();
});
$(`<hr class="hr-2"/>`).appendTo($tab);
$(`<hr class="hr-2">`).appendTo($tab);
const $wrpUnitConverter = $(`<div class="ui-modal__row"><span>Unit Converter</span></div>`).appendTo($tab);
const $btnUnitConverter = $(`<button class="btn btn-primary btn-sm">Add</button>`).appendTo($wrpUnitConverter);
@@ -3366,7 +3372,7 @@ class AddMenuSpecialTab extends AddMenuTab {
this.menu.doClose();
});
$(`<hr class="hr-2"/>`).appendTo($tab);
$(`<hr class="hr-2">`).appendTo($tab);
const $wrpTimeTracker = $(`<div class="ui-modal__row"><span>In-Game Clock/Calendar</span></div>`).appendTo($tab);
const $btnTimeTracker = $(`<button class="btn btn-primary btn-sm">Add</button>`).appendTo($wrpTimeTracker);
@@ -3375,7 +3381,7 @@ class AddMenuSpecialTab extends AddMenuTab {
this.menu.doClose();
});
$(`<hr class="hr-2"/>`).appendTo($tab);
$(`<hr class="hr-2">`).appendTo($tab);
const $wrpBlank = $(`<div class="ui-modal__row"><span class="help" title="For those who don't like plus signs.">Blank Space</span></div>`).appendTo($tab);
$(`<button class="btn btn-primary btn-sm">Add</button>`)
@@ -3589,8 +3595,8 @@ class AddMenuSearchTab extends AddMenuTab {
};
if (!this.$tab) {
const $tab = $(`<div class="ui-search__wrp-output" id="${this.tabId}"/>`);
const $wrpCtrls = $(`<div class="ui-search__wrp-controls ui-search__wrp-controls--in-tabs"/>`).appendTo($tab);
const $tab = $(`<div class="ui-search__wrp-output" id="${this.tabId}"></div>`);
const $wrpCtrls = $(`<div class="ui-search__wrp-controls ui-search__wrp-controls--in-tabs"></div>`).appendTo($tab);
const $selCat = $(`
<select class="form-control ui-search__sel-category">
@@ -3606,7 +3612,7 @@ class AddMenuSearchTab extends AddMenuTab {
});
const $srch = $(`<input class="ui-search__ipt-search search form-control" autocomplete="off" placeholder="Search...">`).blurOnEsc().appendTo($wrpCtrls);
const $results = $(`<div class="ui-search__wrp-results"/>`).appendTo($tab);
const $results = $(`<div class="ui-search__wrp-results"></div>`).appendTo($tab);
SearchWidget.bindAutoSearch($srch, {
flags,
@@ -3856,12 +3862,12 @@ class UnitConverter {
let ixConv = state.c || 0;
let dirConv = state.d || 0;
const $wrpConverter = $(`<div class="dm-unitconv dm__panel-bg split-column"/>`);
const $wrpConverter = $(`<div class="dm-unitconv dm__panel-bg split-column"></div>`);
const $tblConvert = $(`<table class="w-100 table-striped"/>`).appendTo($wrpConverter);
const $tbodyConvert = $(`<tbody/>`).appendTo($tblConvert);
const $tblConvert = $(`<table class="w-100 table-striped"></table>`).appendTo($wrpConverter);
const $tbodyConvert = $(`<tbody></tbody>`).appendTo($tblConvert);
units.forEach((u, i) => {
const $tr = $(`<tr class="row clickable"/>`).appendTo($tbodyConvert);
const $tr = $(`<tr class="row clickable"></tr>`).appendTo($tbodyConvert);
const clickL = () => {
ixConv = i;
dirConv = 0;
@@ -3878,10 +3884,10 @@ class UnitConverter {
$(`<td class="ve-col-3 code">×${u.x2.padStart(5)}</td>`).click(clickR).appendTo($tr);
});
const $wrpIpt = $(`<div class="split dm-unitconv__wrp-ipt"/>`).appendTo($wrpConverter);
const $wrpIpt = $(`<div class="split dm-unitconv__wrp-ipt"></div>`).appendTo($wrpConverter);
const $wrpLeft = $(`<div class="split-column dm-unitconv__wrp-ipt-inner"/>`).appendTo($wrpIpt);
const $lblLeft = $(`<span class="bold"/>`).appendTo($wrpLeft);
const $wrpLeft = $(`<div class="split-column dm-unitconv__wrp-ipt-inner"></div>`).appendTo($wrpIpt);
const $lblLeft = $(`<span class="bold"></span>`).appendTo($wrpLeft);
const $iptLeft = $(`<textarea class="dm-unitconv__ipt form-control">${state.i || ""}</textarea>`).appendTo($wrpLeft);
const $btnSwitch = $(`<button class="btn btn-primary dm-unitconv__btn-switch">⇆</button>`).click(() => {
@@ -3889,9 +3895,9 @@ class UnitConverter {
updateDisplay();
}).appendTo($wrpIpt);
const $wrpRight = $(`<div class="split-column dm-unitconv__wrp-ipt-inner"/>`).appendTo($wrpIpt);
const $lblRight = $(`<span class="bold"/>`).appendTo($wrpRight);
const $iptRight = $(`<textarea class="dm-unitconv__ipt form-control" disabled style="background: #0000"/>`).appendTo($wrpRight);
const $wrpRight = $(`<div class="split-column dm-unitconv__wrp-ipt-inner"></div>`).appendTo($wrpIpt);
const $lblRight = $(`<span class="bold"></span>`).appendTo($wrpRight);
const $iptRight = $(`<textarea class="dm-unitconv__ipt form-control" disabled style="background: #0000"></textarea>`).appendTo($wrpRight);
const updateDisplay = () => {
const it = units[ixConv];
@@ -3972,15 +3978,15 @@ class AdventureOrBookView {
}
$getEle () {
this._$titlePrev = $(`<div class="dm-book__controls-title ve-overflow-ellipsis text-right"/>`);
this._$titleNext = $(`<div class="dm-book__controls-title ve-overflow-ellipsis"/>`);
this._$titlePrev = $(`<div class="dm-book__controls-title ve-overflow-ellipsis text-right"></div>`);
this._$titleNext = $(`<div class="dm-book__controls-title ve-overflow-ellipsis"></div>`);
const $btnPrev = $(`<button class="btn btn-xs btn-default mr-2" title="Previous Chapter"><span class="glyphicon glyphicon-chevron-left"/></button>`)
const $btnPrev = $(`<button class="btn btn-xs btn-default mr-2" title="Previous Chapter"><span class="glyphicon glyphicon-chevron-left"></span></button>`)
.click(() => this._handleButtonClick(-1));
const $btnNext = $(`<button class="btn btn-xs btn-default" title="Next Chapter"><span class="glyphicon glyphicon-chevron-right"/></button>`)
const $btnNext = $(`<button class="btn btn-xs btn-default" title="Next Chapter"><span class="glyphicon glyphicon-chevron-right"></span></button>`)
.click(() => this._handleButtonClick(1));
this._$wrpContent = $(`<div class="h-100"/>`);
this._$wrpContent = $(`<div class="h-100"></div>`);
this._$wrpContentOuter = $$`<div class="h-100 dm-book__wrp-content">
<table class="w-100 stats stats--book stats--book-hover"><tr class="text"><td colspan="6">${this._$wrpContent}</td></tr></table>
</div>`;

View File

@@ -1,6 +1,6 @@
export class Counter {
static $getCounter (board, state) {
const $wrpPanel = $(`<div class="w-100 h-100 dm-cnt__root dm__panel-bg dm__data-anchor"/>`) // root class used to identify for saving
const $wrpPanel = $(`<div class="w-100 h-100 dm-cnt__root dm__panel-bg dm__data-anchor"></div>`) // root class used to identify for saving
.data("getState", () => counters.getSaveableState());
const counters = new CounterRoot(board, $wrpPanel);
counters.setStateFrom(state);
@@ -31,10 +31,10 @@ class CounterRoot extends CounterComponent {
const pod = this.getPod();
this._$wrpRows = $$`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto relative"/>`;
this._$wrpRows = $$`<div class="ve-flex-col w-100 h-100 ve-overflow-y-auto relative"></div>`;
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>`)
const $btnAdd = $(`<button class="btn btn-primary btn-xs"><span class="glyphicon glyphicon-plus"></span> Add Counter</button>`)
.click(() => {
const comp = new CounterRow(this._board, this._$wrpPanel);
this._childComps.push(comp);
@@ -43,7 +43,7 @@ class CounterRoot extends CounterComponent {
});
$$`<div class="w-100 h-100 ve-flex-col px-2 pb-3">
<div class="no-shrink pt-4"/>
<div class="no-shrink pt-4"></div>
${this._$wrpRows}
<div class="no-shrink ve-flex-h-right">${$btnAdd}</div>
</div>`.appendTo($parent);
@@ -123,13 +123,13 @@ class CounterRow extends CounterComponent {
this._addHookBase("max", hookDisplayMinMax);
hookDisplayMinMax();
const $btnDown = $(`<button class="btn btn-danger btn-xs"><span class="glyphicon glyphicon-minus"/></button>`)
const $btnDown = $(`<button class="btn btn-danger btn-xs"><span class="glyphicon glyphicon-minus"></span></button>`)
.click(() => this._state.current--);
const $btnUp = $(`<button class="btn btn-success btn-xs"><span class="glyphicon glyphicon-plus"/></button>`)
const $btnUp = $(`<button class="btn btn-success btn-xs"><span class="glyphicon glyphicon-plus"></span></button>`)
.click(() => this._state.current++);
const $btnRemove = $(`<button class="btn btn-danger btn-xxs"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-danger btn-xxs"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
const {removeRow} = this._parent;
removeRow(this);

View File

@@ -85,7 +85,7 @@ export class InitiativeTrackerCreatureViewer extends BaseComponent {
title: "Select Tracker",
});
const $selTracker = $(`<select class="form-control input-xs mr-1">
const $selTracker = $(`<select class="form-control input-xs mb-2">
<option value="-1" disabled>Select tracker</option>
${$elesData.map(($e, i) => `<option value="${i}">${$e.data("getSummary")()}</option>`).join("")}
</select>`)
@@ -107,8 +107,8 @@ export class InitiativeTrackerCreatureViewer extends BaseComponent {
${$btnSubmit}
`;
const ixSel = await pGetResolved();
if (ixSel == null) return;
const [isDataEntered, ixSel] = await pGetResolved();
if (!isDataEntered || ixSel == null) return;
this._setLinkedTrackerFromEle({$eleData: $elesData[ixSel]});
});

View File

@@ -1,6 +1,6 @@
export class DmMapper {
static $getMapper (board, state) {
const $wrpPanel = $(`<div class="w-100 h-100 dm-map__root dm__panel-bg dm__data-anchor"/>`) // root class used to identify for saving
const $wrpPanel = $(`<div class="w-100 h-100 dm-map__root dm__panel-bg dm__data-anchor"></div>`) // root class used to identify for saving
.data("getState", () => mapper.getSaveableState());
const mapper = new DmMapperRoot(board, $wrpPanel);
mapper.setStateFrom(state);

View File

@@ -23,7 +23,7 @@ export class MoneyConverter {
}).reverse();
const DEFAULT_CURRENCY = 3;
const $wrpConverter = $(`<div class="dm_money dm__panel-bg split-column"/>`);
const $wrpConverter = $(`<div class="dm_money dm__panel-bg split-column"></div>`);
const doUpdate = () => {
if (!$wrpRows.find(`.dm-money__row`).length) {
@@ -144,7 +144,7 @@ export class MoneyConverter {
const buildCurrency$Select = (isOutput) => $(`<select class="form-control input-sm" style="padding: 5px">${isOutput ? `<option value="-1">(No conversion)</option>` : ""}${CURRENCY.map((c, i) => `<option value="${i}">${c.n}</option>`).join("")}</select>`);
const addRow = (currency, count) => {
const $row = $(`<div class="dm-money__row"/>`).appendTo($wrpRows);
const $row = $(`<div class="dm-money__row"></div>`).appendTo($wrpRows);
const $iptCount = $(`<input type="number" step="1" placeholder="Coins" class="form-control input-sm">`).appendTo($row).change(doUpdate);
if (count != null) $iptCount.val(count);
const $selCurrency = buildCurrency$Select().appendTo($row).change(doUpdate);
@@ -155,18 +155,18 @@ export class MoneyConverter {
});
};
const $wrpRows = $(`<div class="dm-money__rows"/>`).appendTo($wrpConverter);
const $wrpRows = $(`<div class="dm-money__rows"></div>`).appendTo($wrpConverter);
const $wrpCtrl = $(`<div class="split dm-money__ctrl"/>`).appendTo($wrpConverter);
const $wrpCtrlLhs = $(`<div class="dm-money__ctrl__lhs split-child" style="width: 66%;"/>`).appendTo($wrpCtrl);
const $wrpBtnAddSettings = $(`<div class="split"/>`).appendTo($wrpCtrlLhs);
const $btnAddRow = $(`<button class="btn btn-primary btn-sm" title="Add Row"><span class="glyphicon glyphicon-plus"/></button>`)
const $wrpCtrl = $(`<div class="split dm-money__ctrl"></div>`).appendTo($wrpConverter);
const $wrpCtrlLhs = $(`<div class="dm-money__ctrl__lhs split-child" style="width: 66%;"></div>`).appendTo($wrpCtrl);
const $wrpBtnAddSettings = $(`<div class="split"></div>`).appendTo($wrpCtrlLhs);
const $btnAddRow = $(`<button class="btn btn-primary btn-sm" title="Add Row"><span class="glyphicon glyphicon-plus"></span></button>`)
.appendTo($wrpBtnAddSettings)
.click(() => {
addRow();
doUpdate();
});
const $btnSettings = $(`<button class="btn btn-default btn-sm" title="Settings"><span class="glyphicon glyphicon-cog"/></button>`)
const $btnSettings = $(`<button class="btn btn-default btn-sm" title="Settings"><span class="glyphicon glyphicon-cog"></span></button>`)
.appendTo($wrpBtnAddSettings)
.click(() => {
const {$modalInner} = UiUtil.getShowModal({
@@ -184,7 +184,7 @@ export class MoneyConverter {
JqueryUtil.showCopiedEffect($iptOut);
});
const $wrpCtrlRhs = $(`<div class="dm-money__ctrl__rhs split-child" style="width: 33%;"/>`).appendTo($wrpCtrl);
const $wrpCtrlRhs = $(`<div class="dm-money__ctrl__rhs split-child" style="width: 33%;"></div>`).appendTo($wrpCtrl);
const $iptSplit = $(`<input type="number" min="1" step="1" placeholder="Split Between..." class="form-control input-sm">`).appendTo($wrpCtrlRhs).change(doUpdate);
const $selOut = buildCurrency$Select(true).appendTo($wrpCtrlRhs).change(doUpdate);

View File

@@ -10,8 +10,8 @@ import {DmScreenUtil} from "./dmscreen-util.js";
// region v1
export class InitiativeTrackerPlayerV1 {
static $getPanelElement (board, state) {
const $meta = $(`<div class="initp__meta"/>`).hide();
const $head = $(`<div class="initp__header"/>`).hide();
const $meta = $(`<div class="initp__meta"></div>`).hide();
const $head = $(`<div class="initp__header"></div>`).hide();
const $rows = $(`<div class="ve-flex-col"></div>`).hide();
const $wrpTracker = $$`<div class="initp__wrp_active">
@@ -184,8 +184,8 @@ class InitiativeTrackerPlayerMessageHandlerScreenV1 extends InitiativeTrackerPla
// region v0
export class InitiativeTrackerPlayerV0 {
static $getPanelElement (board, state) {
const $meta = $(`<div class="initp__meta"/>`).hide();
const $head = $(`<div class="initp__header"/>`).hide();
const $meta = $(`<div class="initp__meta"></div>`).hide();
const $head = $(`<div class="initp__header"></div>`).hide();
const $rows = $(`<div class="ve-flex-col"></div>`).hide();
const $wrpTracker = $$`<div class="initp__wrp_active">

View File

@@ -27,7 +27,7 @@ export class TimerTrackerMoonSpriteLoader {
export class TimeTracker {
static $getTracker (board, state) {
const $wrpPanel = $(`<div class="w-100 h-100 dm-time__root dm__panel-bg dm__data-anchor"/>`) // root class used to identify for saving
const $wrpPanel = $(`<div class="w-100 h-100 dm-time__root dm__panel-bg dm__data-anchor"></div>`) // root class used to identify for saving
.data("getState", () => tracker.getSaveableState());
const tracker = new TimeTrackerRoot(board, $wrpPanel);
state = TimeTrackerUtil.getMigratedState(state);
@@ -441,7 +441,7 @@ class TimeTrackerBase extends TimeTrackerComponent {
}
static $getCvsMoon (moonInfo) {
const $canvas = $(`<canvas title="${moonInfo.name.escapeQuotes()}\u2014${moonInfo.phaseName}" class="dm-time__cvs-moon" width="${TimeTrackerBase._MOON_RENDER_RES}" height="${TimeTrackerBase._MOON_RENDER_RES}"/>`);
const $canvas = $(`<canvas title="${moonInfo.name.escapeQuotes()}\u2014${moonInfo.phaseName}" class="dm-time__cvs-moon" width="${TimeTrackerBase._MOON_RENDER_RES}" height="${TimeTrackerBase._MOON_RENDER_RES}"></canvas>`);
const c = $canvas[0];
const ctx = c.getContext("2d");
@@ -694,7 +694,10 @@ class TimeTrackerRoot extends TimeTrackerBase {
hookShowTab();
const $btnReset = $(`<button class="btn btn-xs btn-danger" title="Reset Clock/Calendar Time to First Day"><span class="glyphicon glyphicon-refresh"></span></button>`)
.click(() => confirm("Are you sure?") && Object.assign(this._state, {time: 0, isBrowseMode: false, browseTime: null}));
.click(async () => {
if (!await InputUiUtil.pGetUserBoolean({title: "Reset", htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
Object.assign(this._state, {time: 0, isBrowseMode: false, browseTime: null});
});
$$`<div class="ve-flex-col h-100">
<div class="ve-flex p-1 no-shrink">
@@ -820,11 +823,11 @@ class TimeTrackerRoot_Clock extends TimeTrackerComponent {
}, 1000);
this._$wrpPanel.data("onDestroy", () => clearInterval(this._ivTimer));
const $dispReadableDate = $(`<div class="small-caps"/>`);
const $dispReadableYear = $(`<div class="small-caps small text-muted mb-2"/>`);
const $wrpMoons = $(`<div class="ve-flex ve-flex-wrap w-100 no-shrink ve-flex-vh-center mb-3"/>`);
const $dispReadableDate = $(`<div class="small-caps"></div>`);
const $dispReadableYear = $(`<div class="small-caps small text-muted mb-2"></div>`);
const $wrpMoons = $(`<div class="ve-flex ve-flex-wrap w-100 no-shrink ve-flex-vh-center mb-3"></div>`);
const $wrpDayNight = $(`<div class="ve-flex w-100 no-shrink ve-flex-h-center ve-flex-v-baseline mt-2"/>`);
const $wrpDayNight = $(`<div class="ve-flex w-100 no-shrink ve-flex-h-center ve-flex-v-baseline mt-2"></div>`);
const getSecsToNextDay = (timeInfo) => {
const {
@@ -910,12 +913,12 @@ class TimeTrackerRoot_Clock extends TimeTrackerComponent {
const $iptMinutes = $getIpt("minutesPerHour", "numMinutes", "secsPerMinute");
const $iptSeconds = $getIpt("secondsPerMinute", "numSecs");
const $wrpDays = $(`<div class="small-caps ve-text-center mb-1"/>`);
const $wrpDays = $(`<div class="small-caps ve-text-center mb-1"></div>`);
const $wrpHours = $$`<div class="ve-flex ve-flex-vh-center">${$iptHours}</div>`;
const $wrpMinutes = $$`<div class="ve-flex ve-flex-vh-center">${$iptMinutes}</div>`;
const $wrpSeconds = $$`<div class="ve-flex ve-flex-vh-center">${$iptSeconds}</div>`;
const $wrpEventsEncounters = $(`<div class="ve-flex-vh-center relative ve-flex-wrap dm-time__wrp-clock-events"/>`);
const $wrpEventsEncounters = $(`<div class="ve-flex-vh-center relative ve-flex-wrap dm-time__wrp-clock-events"></div>`);
const $hrEventsEncounters = $(`<hr class="hr-2">`);
// cache rendering
@@ -1221,7 +1224,7 @@ class TimeTrackerRoot_Clock_Weather extends TimeTrackerComponent {
this._parent = parent;
const {getTimeInfo} = parent;
const $btnRandomise = $(`<button class="btn btn-xxs btn-default dm-time__btn-random-weather" title="Roll Weather (SHIFT to Reroll Using Previous Settings)"><span class="fal fa-dice"/></button>`)
const $btnRandomise = $(`<button class="btn btn-xxs btn-default dm-time__btn-random-weather" title="Roll Weather (SHIFT to Reroll Using Previous Settings)"><span class="fal fa-dice"></span></button>`)
.click(async evt => {
const randomState = await TimeTrackerRoot_Clock_RandomWeather.pGetUserInput(
{
@@ -1239,7 +1242,7 @@ class TimeTrackerRoot_Clock_Weather extends TimeTrackerComponent {
Object.assign(this._state, randomState);
});
const $btnTemperature = $(`<button class="btn btn-default btn-sm dm-time__btn-weather mr-2"/>`)
const $btnTemperature = $(`<button class="btn btn-default btn-sm dm-time__btn-weather mr-2"></button>`)
.click(async () => {
let ixCur = TimeTrackerRoot_Clock_Weather._TEMPERATURES.indexOf(this._state.temperature);
if (!~ixCur) ixCur = 2;
@@ -1265,12 +1268,12 @@ class TimeTrackerRoot_Clock_Weather extends TimeTrackerComponent {
if (!~ix) ix = 0;
const meta = TimeTrackerRoot_Clock_Weather._TEMPERATURE_META[ix];
$btnTemperature.addClass(meta.class);
$btnTemperature.title(this._state.temperature.uppercaseFirst()).html(`<div class="fal ${meta.icon}"/>`);
$btnTemperature.title(this._state.temperature.uppercaseFirst()).html(`<div class="fal ${meta.icon}"></div>`);
};
this._addHookBase("temperature", hookTemperature);
hookTemperature();
const $btnPrecipitation = $(`<button class="btn btn-default btn-sm dm-time__btn-weather mr-2"/>`)
const $btnPrecipitation = $(`<button class="btn btn-default btn-sm dm-time__btn-weather mr-2"></button>`)
.click(async () => {
const {
numHours,
@@ -1312,13 +1315,13 @@ class TimeTrackerRoot_Clock_Weather extends TimeTrackerComponent {
let ix = TimeTrackerRoot_Clock_Weather._PRECIPICATION.indexOf(this._state.precipitation);
if (!~ix) ix = 0;
const meta = TimeTrackerRoot_Clock_Weather._PRECIPICATION_META[ix];
$btnPrecipitation.title(TimeTrackerUtil.revSlugToText(this._state.precipitation)).html(`<div class="fal ${useNightIcon && meta.iconNight ? meta.iconNight : meta.icon}"/>`);
$btnPrecipitation.title(TimeTrackerUtil.revSlugToText(this._state.precipitation)).html(`<div class="fal ${useNightIcon && meta.iconNight ? meta.iconNight : meta.icon}"></div>`);
};
this._addHookBase("precipitation", hookPrecipitation);
this._parent.addHook("time", hookPrecipitation);
hookPrecipitation();
const $btnWindDirection = $(`<button class="btn btn-default btn-sm dm-time__btn-weather"/>`)
const $btnWindDirection = $(`<button class="btn btn-default btn-sm dm-time__btn-weather"></button>`)
.click(async () => {
const bearing = await TimeTrackerUtil.pGetUserWindBearing(this._state.windDirection);
if (bearing != null) this._state.windDirection = bearing;
@@ -1329,14 +1332,14 @@ class TimeTrackerRoot_Clock_Weather extends TimeTrackerComponent {
if (ixCur) {
const speedClass = ixCur >= 5 ? "fas" : ixCur >= 3 ? "far" : "fal";
$btnWindDirection.html(`<div class="${speedClass} fa-arrow-up" style="transform: rotate(${this._state.windDirection}deg);"/>`);
} else $btnWindDirection.html(`<div class="fal fa-ellipsis-h"/>`);
$btnWindDirection.html(`<div class="${speedClass} fa-arrow-up" style="transform: rotate(${this._state.windDirection}deg);"></div>`);
} else $btnWindDirection.html(`<div class="fal fa-ellipsis-h"></div>`);
};
this._addHookBase("windDirection", hookWindDirection);
this._addHookBase("windSpeed", hookWindDirection);
hookWindDirection();
const $btnWindSpeed = $(`<button class="btn btn-default btn-xs"/>`)
const $btnWindSpeed = $(`<button class="btn btn-default btn-xs"></button>`)
.click(async () => {
let ixCur = TimeTrackerRoot_Clock_Weather._WIND_SPEEDS.indexOf(this._state.windSpeed);
if (!~ixCur) ixCur = 0;
@@ -1366,7 +1369,7 @@ class TimeTrackerRoot_Clock_Weather extends TimeTrackerComponent {
this._parent.addHook("unitsWindSpeed", hookWindSpeed);
hookWindSpeed();
const $hovEnvEffects = $(`<div><span class="glyphicon glyphicon-info-sign"/></div>`);
const $hovEnvEffects = $(`<div><span class="glyphicon glyphicon-info-sign"></span></div>`);
const $wrpEnvEffects = $$`<div class="mt-2">${$hovEnvEffects}</div>`;
let hoverMetaEnvEffects = null;
const hookEnvEffects = () => {
@@ -1570,13 +1573,13 @@ class TimeTrackerRoot_Clock_RandomWeather extends BaseComponent {
return $btn;
});
const $btnWindDirection = $(`<button class="btn btn-default btn-sm dm-time__btn-weather"/>`)
const $btnWindDirection = $(`<button class="btn btn-default btn-sm dm-time__btn-weather"></button>`)
.click(async () => {
const bearing = await TimeTrackerUtil.pGetUserWindBearing(this._state.prevailingWindDirection);
if (bearing != null) this._state.prevailingWindDirection = bearing;
});
const hookWindDirection = () => {
$btnWindDirection.html(`<div class="far fa-arrow-up" style="transform: rotate(${this._state.prevailingWindDirection}deg);"/>`);
$btnWindDirection.html(`<div class="far fa-arrow-up" style="transform: rotate(${this._state.prevailingWindDirection}deg);"></div>`);
};
this._addHookBase("prevailingWindDirection", hookWindDirection);
hookWindDirection();
@@ -1755,8 +1758,8 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
// cache info to avoid re-rendering the calendar every second
let lastRenderMeta = null;
const $dispDayReadableDate = $(`<div class="small-caps"/>`);
const $dispYear = $(`<div class="small-caps text-muted small"/>`);
const $dispDayReadableDate = $(`<div class="small-caps"></div>`);
const $dispYear = $(`<div class="small-caps text-muted small"></div>`);
const {$wrpDateControls, $iptYear, $iptMonth, $iptDay} = TimeTrackerRoot_Calendar.getDateControls(this._parent);
const $btnBrowseMode = ComponentUiUtil.$getBtnBool(
@@ -1771,7 +1774,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
},
);
const $wrpCalendar = $(`<div class="ve-overflow-y-auto smooth-scroll"/>`);
const $wrpCalendar = $(`<div class="ve-overflow-y-auto smooth-scroll"></div>`);
const hookCalendar = (prop) => {
const timeInfo = getTimeInfo();
@@ -2057,7 +2060,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
let $ele;
if (i < 0 || i >= daysInMonth) {
$ele = $(`<div class="m-1"/>`);
$ele = $(`<div class="m-1"></div>`);
} else {
const eventDay = monthStartDayOfYear + i;
const moonDay = numDays - (date - i);
@@ -2074,7 +2077,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
return TimeTrackerBase.$getCvsMoon(m).addClass("dm-time__calendar-moon-phase");
} else if (i === 1) {
const otherMoons = activeMoons.length - 1;
return `<div class="dm-time__calendar-moon-phase text-muted" title="${otherMoons} additional moon${otherMoons === 1 ? "" : "s"} not shown"><span class="glyphicon glyphicon-plus"/></div>`;
return `<div class="dm-time__calendar-moon-phase text-muted" title="${otherMoons} additional moon${otherMoons === 1 ? "" : "s"} not shown"><span class="glyphicon glyphicon-plus"></span></div>`;
}
});
@@ -2125,7 +2128,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
doClose();
});
const $btnAddEvent = $(`<button class="btn btn-xs btn-primary"><span class="glyphicon glyphicon-plus"/> Add Event</button>`)
const $btnAddEvent = $(`<button class="btn btn-xs btn-primary"><span class="glyphicon glyphicon-plus"></span> Add Event</button>`)
.click(() => {
const nxtPos = Object.keys(this._parent.get("events")).length;
const nuEvent = TimeTrackerBase.getGenericEvent(nxtPos, year, eventDay);
@@ -2202,7 +2205,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
}),
]);
const $btnAddEncounter = $(`<button class="btn btn-xs btn-success"><span class="glyphicon glyphicon-plus"/> Add Encounter</button>`)
const $btnAddEncounter = $(`<button class="btn btn-xs btn-success"><span class="glyphicon glyphicon-plus"></span> Add Encounter</button>`)
.click(evt => ContextUtil.pOpenMenu(evt, menuEncounter));
const $btnAddEncounterAtTime = $(`<button class="btn btn-xs btn-success">At Time...</button>`)
@@ -2221,7 +2224,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
});
const $hrMoons = $(`<hr class="hr-2 no-shrink">`);
const $wrpMoons = $(`<div class="ve-flex ve-flex-wrap w-100 no-shrink ve-flex-v-center"/>`);
const $wrpMoons = $(`<div class="ve-flex ve-flex-wrap w-100 no-shrink ve-flex-v-center"></div>`);
const hookMoons = () => {
const todayMoonInfos = getMoonInfos(moonDay);
$wrpMoons.empty();
@@ -2239,7 +2242,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
this._parent.addHook("moons", hookMoons);
hookMoons();
const $wrpEvents = $(`<div class="ve-flex-col w-100 ve-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"></div>`);
const hookEvents = () => {
const todayEvents = getEvents(year, eventDay);
$wrpEvents.empty();
@@ -2260,7 +2263,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
this._parent.addHook("events", hookEvents);
hookEvents();
const $wrpEncounters = $(`<div class="ve-flex-col w-100 ve-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"></div>`);
const hookEncounters = async () => {
await this._pLock("encounters");
@@ -2281,10 +2284,10 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
})
.val(encounter.displayName == null ? encounter.name : encounter.displayName);
const $btnRunEncounter = $(`<button class="btn btn-xs btn-default mr-2 ${encounter.countUses > 0 ? "disabled" : ""}" title="${encounter.countUses > 0 ? "(Encounter has been used)" : "Run Encounter (Add to Initiative Tracker)"}"><span class="glyphicon glyphicon-play"/></button>`)
const $btnRunEncounter = $(`<button class="btn btn-xs btn-default mr-2 ${encounter.countUses > 0 ? "disabled" : ""}" title="${encounter.countUses > 0 ? "(Encounter has been used)" : "Run Encounter (Add to Initiative Tracker)"}"><span class="glyphicon glyphicon-play"></span></button>`)
.click(() => TimeTrackerRoot_Calendar.pDoRunEncounter(this._parent, encounter));
const $btnResetUse = $(`<button class="btn btn-xs btn-default mr-2 ${encounter.countUses === 0 ? "disabled" : ""}" title="Reset Usage"><span class="glyphicon glyphicon-refresh"/></button>`)
const $btnResetUse = $(`<button class="btn btn-xs btn-default mr-2 ${encounter.countUses === 0 ? "disabled" : ""}" title="Reset Usage"><span class="glyphicon glyphicon-refresh"></span></button>`)
.click(() => {
if (encounter.countUses === 0) return;
@@ -2292,7 +2295,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
this._parent.triggerMapUpdate("encounters");
});
const $btnSaveToFile = $(`<button class="btn btn-xs btn-default mr-3" title="Download Encounter File"><span class="glyphicon glyphicon-download"/></button>`)
const $btnSaveToFile = $(`<button class="btn btn-xs btn-default mr-3" title="Download Encounter File"><span class="glyphicon glyphicon-download"></span></button>`)
.click(async () => {
const toSave = await TimeTrackerRoot_Calendar._pGetDereferencedEncounter(encounter);
@@ -2332,7 +2335,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
);
}
const $btnMove = $(`<button class="btn btn-xs btn-default mr-2 no-shrink"><span class="glyphicon glyphicon-move" title="Move Encounter"/></button>`)
const $btnMove = $(`<button class="btn btn-xs btn-default mr-2 no-shrink"><span class="glyphicon glyphicon-move" title="Move Encounter"></span></button>`)
.click(() => {
this._render_openDayModal_openCalendarPicker({
title: "Choose Encounter Day",
@@ -2347,7 +2350,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
});
});
const $btnDelete = $(`<button class="btn btn-xs btn-danger" title="Delete Encounter"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnDelete = $(`<button class="btn btn-xs btn-danger" title="Delete Encounter"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
encounter.isDeleted = true;
this._parent.triggerMapUpdate("encounters");
@@ -2613,7 +2616,7 @@ class TimeTrackerRoot_Calendar extends TimeTrackerComponent {
const {$wrpDateControls, $iptYear, $iptMonth} = TimeTrackerRoot_Calendar.getDateControls(tempPod, {isHideWeeks: true, isHideDays: true});
$wrpDateControls.addClass("mb-2").appendTo($modalInner);
const $wrpCalendar = $(`<div/>`).appendTo($modalInner);
const $wrpCalendar = $(`<div></div>`).appendTo($modalInner);
const hookCalendar = () => {
const timeInfo = tempPod.getTimeInfo();
@@ -2750,7 +2753,7 @@ class TimeTrackerRoot_Settings extends TimeTrackerComponent {
const btnHideHooks = [];
const $getBtnHide = (prop, $ele, ...$eles) => {
const $btn = $(`<button class="btn btn-xs btn-default" title="Hide Section"><span class="glyphicon glyphicon-eye-close"/></button>`)
const $btn = $(`<button class="btn btn-xs btn-default" title="Hide Section"><span class="glyphicon glyphicon-eye-close"></span></button>`)
.click(() => this._parent.set(prop, !this._parent.get(prop)));
const hook = () => {
const isHidden = this._parent.get(prop);
@@ -2765,8 +2768,8 @@ class TimeTrackerRoot_Settings extends TimeTrackerComponent {
const $getBtnReset = (...props) => {
return $(`<button class="btn btn-xs btn-default mr-2">Reset Section</button>`)
.click(() => {
if (!confirm("Are you sure?")) return;
.click(async () => {
if (!await InputUiUtil.pGetUserBoolean({title: "Reset", htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
props.forEach(prop => this._parent.set(prop, TimeTrackerBase._DEFAULT_STATE[prop]));
});
};
@@ -2874,7 +2877,7 @@ class TimeTrackerRoot_Settings extends TimeTrackerComponent {
<div class="ve-flex w-100 mb-1 mt-1">
<div class="w-100 ve-flex-v-center">Name</div>
<div class="w-25 no-shrink ve-text-center mr-2">Days</div>
<div class="dm-time__spc-drag-header no-shrink mr-2"/>
<div class="dm-time__spc-drag-header no-shrink mr-2"></div>
${metaMonths.$btnAdd.addClass("no-shrink")}
</div>
${metaMonths.$wrpRows}
@@ -3018,7 +3021,7 @@ class TimeTrackerRoot_Settings extends TimeTrackerComponent {
}
_render_$getBtnAddChild ({prop, name, fnGetGeneric}) {
return $(`<button class="btn btn-xs btn-primary" title="Add ${name}"><span class="glyphicon glyphicon-plus"/></button>`)
return $(`<button class="btn btn-xs btn-primary" title="Add ${name}"><span class="glyphicon glyphicon-plus"></span></button>`)
.click(() => {
const nxt = fnGetGeneric(this._parent.get(prop).length);
this._parent.set(prop, [...this._parent.get(prop), nxt]);
@@ -3046,14 +3049,14 @@ class TimeTrackerRoot_Settings_Day extends RenderableCollectionTimeTracker {
const $padDrag = DragReorderUiUtil.$getDragPadOpts(() => $wrpRow, this._dragMeta);
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Day"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Day"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => this._comp._state.days = this._comp._state.days.filter(it => it !== entity));
const $wrpRow = $$`<div class="ve-flex my-1 dm-time__row-delete">
${$iptName}
${$padDrag}
${$btnRemove}
<div class="dm-time__spc-button"/>
<div class="dm-time__spc-button"></div>
</div>`.appendTo(this._$wrpRows);
return {
@@ -3081,7 +3084,7 @@ class TimeTrackerRoot_Settings_Month extends RenderableCollectionTimeTracker {
const $padDrag = DragReorderUiUtil.$getDragPadOpts(() => $wrpRow, this._dragMeta);
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Month"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Month"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => this._comp._state.months = this._comp._state.months.filter(it => it !== entity));
const $wrpRow = $$`<div class="ve-flex my-1 dm-time__row-delete">
@@ -3089,7 +3092,7 @@ class TimeTrackerRoot_Settings_Month extends RenderableCollectionTimeTracker {
${$iptDays}
${$padDrag}
${$btnRemove}
<div class="dm-time__spc-button"/>
<div class="dm-time__spc-button"></div>
</div>`.appendTo(this._$wrpRows);
return {
@@ -3113,7 +3116,7 @@ class TimeTrackerRoot_Settings_Event extends TimeTrackerComponent {
$wrpEntries.toggleClass("hidden", !isShown);
};
const $dispEntries = $(`<div class="stats stats--book dm-time__wrp-event-entries"/>`);
const $dispEntries = $(`<div class="stats stats--book dm-time__wrp-event-entries"></div>`);
const hookEntries = () => {
$dispEntries.html(Renderer.get().render({entries: MiscUtil.copy(this._state.entries)}));
doShowHideEntries();
@@ -3130,7 +3133,7 @@ class TimeTrackerRoot_Settings_Event extends TimeTrackerComponent {
const hookName = () => $iptName.val(this._state.name || "(Unnamed event)");
this._addHookBase("name", hookName);
const $btnShowHide = $(`<button class="btn btn-xs btn-default mr-2 no-shrink"><span class="glyphicon glyphicon-eye-close"/></button>`)
const $btnShowHide = $(`<button class="btn btn-xs btn-default mr-2 no-shrink"><span class="glyphicon glyphicon-eye-close"></span></button>`)
.click(() => this._state.isHidden = !this._state.isHidden);
const hookShowHide = () => {
$btnShowHide.toggleClass("active", !!this._state.isHidden);
@@ -3138,7 +3141,7 @@ class TimeTrackerRoot_Settings_Event extends TimeTrackerComponent {
};
this._addHookBase("isHidden", hookShowHide);
const $btnEdit = $(`<button class="btn btn-xs btn-default mr-2 no-shrink"><span class="glyphicon glyphicon-pencil" title="Edit Event"/></button>`)
const $btnEdit = $(`<button class="btn btn-xs btn-default mr-2 no-shrink"><span class="glyphicon glyphicon-pencil" title="Edit Event"></span></button>`)
.click(() => this.doOpenEditModal());
const $cbHasTime = $(`<input type="checkbox">`)
@@ -3171,7 +3174,7 @@ class TimeTrackerRoot_Settings_Event extends TimeTrackerComponent {
);
}
const $btnMove = $(`<button class="btn btn-xs btn-default mr-2 no-shrink"><span class="glyphicon glyphicon-move" title="Move Event"/></button>`)
const $btnMove = $(`<button class="btn btn-xs btn-default mr-2 no-shrink"><span class="glyphicon glyphicon-move" title="Move Event"></span></button>`)
.click(() => {
fnOpenCalendarPicker({
title: "Choose Event Day",
@@ -3185,7 +3188,7 @@ class TimeTrackerRoot_Settings_Event extends TimeTrackerComponent {
});
});
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Event"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Event"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => this._state.isDeleted = true);
hookEntries();
@@ -3232,7 +3235,7 @@ class TimeTrackerRoot_Settings_Event extends TimeTrackerComponent {
});
const $iptName = ComponentUiUtil.$getIptStr(fauxComponent, "name", {$ele: $(`<input class="form-control input-xs form-control--minimal mb-2 no-shrink">`)});
const $iptEntries = ComponentUiUtil.$getIptEntries(fauxComponent, "entries", {$ele: $(`<textarea class="form-control input-xs form-control--minimal resize-none mb-2 h-100"/>`)});
const $iptEntries = ComponentUiUtil.$getIptEntries(fauxComponent, "entries", {$ele: $(`<textarea class="form-control input-xs form-control--minimal resize-none mb-2 h-100"></textarea>`)});
const $btnOk = $(`<button class="btn btn-default">Save</button>`)
.click(() => doClose(true));
@@ -3281,7 +3284,7 @@ class TimeTrackerRoot_Settings_Season extends RenderableCollectionTimeTracker {
const $iptDaysStart = $getIptDays("startDay");
const $iptDaysEnd = $getIptDays("endDay");
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Season"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Season"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => this._comp._state.seasons = this._comp._state.seasons.filter(it => it !== entity));
const $wrpRow = $$`<div class="ve-flex my-1">
@@ -3317,7 +3320,7 @@ class TimeTrackerRoot_Settings_Year extends RenderableCollectionTimeTracker {
const $iptYear = ComponentUiUtil.$getIptInt(comp, "year", 1, {$ele: $(`<input class="form-control input-xs form-control--minimal text-right mr-2 w-25 no-shrink">`), offset: 1, min: 1});
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Year"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Year"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => this._comp._state.years = this._comp._state.years.filter(it => it !== entity));
const $wrpRow = $$`<div class="ve-flex my-1">
@@ -3353,7 +3356,7 @@ class TimeTrackerRoot_Settings_Era extends RenderableCollectionTimeTracker {
const $iptYearsStart = $getIptYears("startYear");
const $iptYearsEnd = $getIptYears("endYear");
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Year"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Year"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => this._comp._state.eras = this._comp._state.eras.filter(it => it !== entity));
const $wrpRow = $$`<div class="ve-flex my-1">
@@ -3389,7 +3392,7 @@ class TimeTrackerRoot_Settings_Moon extends RenderableCollectionTimeTracker {
const $iptPhaseOffset = ComponentUiUtil.$getIptInt(comp, "phaseOffset", 0, {$ele: $(`<input class="form-control input-xs form-control--minimal text-right mr-2 w-25 no-shrink">`)});
const $iptPeriod = ComponentUiUtil.$getIptInt(comp, "period", 1, {$ele: $(`<input class="form-control input-xs form-control--minimal text-right mr-2 w-25 no-shrink">`), min: TimeTrackerBase._MIN_TIME, max: TimeTrackerBase._MAX_TIME});
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Moon"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger no-shrink" title="Delete Moon"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => this._comp._state.moons = this._comp._state.moons.filter(it => it !== entity));
const $wrpRow = $$`<div class="ve-flex my-1">

View File

@@ -13,15 +13,12 @@ class PageFilterBackgrounds extends PageFilter {
super();
this._skillFilter = new Filter({header: "Skill Proficiencies", displayFn: StrUtil.toTitleCase});
this._toolFilter = new Filter({header: "Tool Proficiencies", displayFn: PageFilterBackgrounds._getToolDisplayText.bind(PageFilterBackgrounds)});
this._languageFilter = new Filter({
header: "Language Proficiencies",
displayFn: it => it === "anyStandard"
? "Any Standard"
: it === "anyExotic"
? "Any Exotic"
: StrUtil.toTitleCase(it),
this._prereqFilter = new Filter({
header: "Prerequisite",
items: [...FilterCommon.PREREQ_FILTER_ITEMS],
});
this._toolFilter = new Filter({header: "Tool Proficiencies", displayFn: PageFilterBackgrounds._getToolDisplayText.bind(PageFilterBackgrounds)});
this._languageFilter = FilterCommon.getLanguageProficienciesFilter();
this._asiFilter = new AbilityScoreFilter({header: "Ability Scores"});
this._otherBenefitsFilter = new Filter({header: "Other Benefits"});
this._miscFilter = new Filter({header: "Miscellaneous", items: ["Has Info", "Has Images", "SRD", "Basic Rules", "Legacy"], isMiscFilter: true});
@@ -30,6 +27,8 @@ class PageFilterBackgrounds extends PageFilter {
static mutateForFilters (bg) {
bg._fSources = SourceFilter.getCompleteFilterSources(bg);
bg._fPrereq = FilterCommon.getFilterValuesPrerequisite(bg.prerequisite);
const {summary: skillDisplay, collection: skills} = Renderer.generic.getSkillSummary({
skillProfs: bg.skillProficiencies,
skillToolLanguageProfs: bg.skillToolLanguageProficiencies,
@@ -69,6 +68,7 @@ class PageFilterBackgrounds extends PageFilter {
if (isExcluded) return;
this._sourceFilter.addItem(bg._fSources);
this._prereqFilter.addItem(bg._fPrereq);
this._skillFilter.addItem(bg._fSkills);
this._toolFilter.addItem(bg._fTools);
this._languageFilter.addItem(bg._fLangs);
@@ -79,6 +79,7 @@ class PageFilterBackgrounds extends PageFilter {
async _pPopulateBoxOptions (opts) {
opts.filters = [
this._sourceFilter,
this._prereqFilter,
this._skillFilter,
this._toolFilter,
this._languageFilter,
@@ -92,6 +93,7 @@ class PageFilterBackgrounds extends PageFilter {
return this._filterBox.toDisplay(
values,
bg._fSources,
bg._fPrereq,
bg._fSkills,
bg._fTools,
bg._fLangs,

View File

@@ -37,6 +37,8 @@ class FilterCommon {
});
}
/* -------------------------------------------- */
static _CONDS = [
"blinded",
"charmed",
@@ -67,6 +69,8 @@ class FilterCommon {
});
}
/* -------------------------------------------- */
static mutateForFilters_damageVulnResImmune_player (ent) {
this.mutateForFilters_damageVuln_player(ent);
this.mutateForFilters_damageRes_player(ent);
@@ -109,6 +113,49 @@ class FilterCommon {
if (typeof it === "string") return allSet.add(it);
if (it.choose?.from) it.choose?.from.forEach(itSub => this._recurseResVulnImm(allSet, itSub));
}
/* -------------------------------------------- */
static PREREQ_FILTER_ITEMS = ["Ability", "Race", "Psionics", "Proficiency", "Special", "Spellcasting"];
static _PREREQ_KEY_TO_FULL = {
"other": "Special",
"otherSummary": "Special",
"spellcasting2020": "Spellcasting",
"spellcastingFeature": "Spellcasting",
"spellcastingPrepared": "Spellcasting",
"level": "Class", // We assume that any filter with meaningful level requirements will have these in a separate filter
"itemType": "Item Type",
"itemProperty": "Item Property",
};
/**
* @param {Array<object>} prerequisite
* @param {Set} ignoredKeys
*/
static getFilterValuesPrerequisite (prerequisite, {ignoredKeys = null} = {}) {
return Array.from(
new Set((prerequisite || [])
.flatMap(it => Object.keys(it))),
)
.filter(k => ignoredKeys == null || !ignoredKeys.has(k))
.map(it => (this._PREREQ_KEY_TO_FULL[it] || it).uppercaseFirst());
}
/* -------------------------------------------- */
static _LANG_TO_DISPLAY = {
"anyStandard": "Any Standard",
"anyExotic": "Any Exotic",
"anyLanguage": "Any",
};
static getLanguageProficienciesFilter () {
return new Filter({
header: "Language Proficiencies",
displayFn: it => this._LANG_TO_DISPLAY[it] || StrUtil.toTitleCase(it),
});
}
}
globalThis.FilterCommon = FilterCommon;

View File

@@ -2,12 +2,7 @@
class PageFilterFeats extends PageFilter {
// region static
static _PREREQ_KEY_TO_FULL = {
"other": "Special",
"spellcasting2020": "Spellcasting",
"spellcastingFeature": "Spellcasting",
"spellcastingPrepared": "Spellcasting",
};
static _PREREQ_KEYs_OTHER_IGNORED = new Set(["level"]);
// endregion
constructor () {
@@ -32,7 +27,7 @@ class PageFilterFeats extends PageFilter {
});
this._otherPrereqFilter = new Filter({
header: "Other",
items: ["Ability", "Race", "Psionics", "Proficiency", "Special", "Spellcasting"],
items: [...FilterCommon.PREREQ_FILTER_ITEMS],
});
this._levelFilter = new Filter({
header: "Level",
@@ -64,9 +59,12 @@ class PageFilterFeats extends PageFilter {
const prereqText = Renderer.utils.prerequisite.getHtml(feat.prerequisite, {isListMode: true}) || VeCt.STR_NONE;
feat._fPrereqOther = [...new Set((feat.prerequisite || []).flatMap(it => Object.keys(it)))]
.map(it => (this._PREREQ_KEY_TO_FULL[it] || it).uppercaseFirst());
if (feat.prerequisite) feat._fPrereqLevel = feat.prerequisite.filter(it => it.level != null).map(it => `Level ${it.level.level ?? it.level}`);
feat._fPrereqOther = FilterCommon.getFilterValuesPrerequisite(feat.prerequisite, {ignoredKeys: this._PREREQ_KEYs_OTHER_IGNORED});
feat._fPrereqLevel = feat.prerequisite
? feat.prerequisite
.filter(it => it.level != null)
.map(it => `Level ${it.level.level ?? it.level}`)
: [];
feat._fBenifits = [
feat.resist ? "Damage Resistance" : null,
feat.immune ? "Damage Immunity" : null,
@@ -102,7 +100,8 @@ class PageFilterFeats extends PageFilter {
this._sourceFilter.addItem(feat.source);
this._categoryFilter.addItem(feat.category);
if (feat.prerequisite) this._levelFilter.addItem(feat._fPrereqLevel);
this._levelFilter.addItem(feat._fPrereqLevel);
this._otherPrereqFilter.addItem(feat._fPrereqOther);
this._vulnerableFilter.addItem(feat._fVuln);
this._resistFilter.addItem(feat._fRes);
this._immuneFilter.addItem(feat._fImm);

View File

@@ -5330,6 +5330,9 @@ class MultiFilter extends FilterBase {
if (!this.__$wrpFilter) return;
this.__$wrpFilter.toggleClass("fltr__hidden--search", numVisible === 0);
}
_doTeardown () { this._filters.forEach(it => it._doTeardown()); }
trimState_ () { this._filters.forEach(it => it.trimState_()); }
}
MultiFilter._DETAULT_STATE = {
mode: "and",

View File

@@ -61,7 +61,7 @@ class LangDemoUi {
.change(() => saveContext())
.val(value);
const $btnDel = $(`<button class="btn btn-xs btn-danger" tabindex="-1"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnDel = $(`<button class="btn btn-xs btn-danger" tabindex="-1"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
const ix = LangDemoUi._metasContext.indexOf(out);
if (~ix) {

View File

@@ -119,7 +119,7 @@ class LanguagesPage extends ListPage {
fnPopulate: () => {
this._$pgContent.empty().append(Renderer.utils.getBorderTr());
this._$pgContent.append(Renderer.utils.getNameTr(ent));
const $td = $(`<td colspan="6" class="text"/>`);
const $td = $(`<td colspan="6" class="text"></td>`);
$$`<tr class="text">${$td}</tr>`.appendTo(this._$pgContent);
this._$pgContent.append(Renderer.utils.getBorderTr());
@@ -130,7 +130,7 @@ class LanguagesPage extends ListPage {
return;
}
const $styleFont = $(`<style/>`);
const $styleFont = $(`<style></style>`);
let lastStyleIndex = null;
let lastStyleClass = null;

View File

@@ -800,7 +800,7 @@ function sectFamily () {
let famIndex = 1;
const $btnSuppFam = $(`<button class="btn btn-xs btn-default btn-supp-fam no-print"></button>`).on("click", async () => {
const supDetails = await getPersonDetails();
const $wrpRes = $(`<div class="life__output-wrp-border p-3 my-2"/>`);
const $wrpRes = $(`<div class="life__output-wrp-border p-3 my-2"></div>`);
$wrpRes.append(`<h5 class="mt-0">Family Member Roll ${famIndex++}</h5>`);
$wrpRes.append(joinParaList(supDetails));
$btnSuppFam.css("margin-bottom", 5);

View File

@@ -2006,7 +2006,7 @@ class ListPage {
];
const menu = ContextUtil.getMenu(actions);
const $btnOptions = $(`<button class="btn btn-default btn-xs btn-stats-name" title="Other Options"><span class="glyphicon glyphicon-option-vertical"/></button>`)
const $btnOptions = $(`<button class="btn btn-default btn-xs btn-stats-name" title="Other Options"><span class="glyphicon glyphicon-option-vertical"></span></button>`)
.click(evt => ContextUtil.pOpenMenu(evt, menu));
return $$`<div class="ve-flex-v-center btn-group ml-2">${$btnOptions}</div>`;
@@ -2204,7 +2204,7 @@ class ListPageBookView extends BookModeViewBase {
if (i < parts.length - 1) {
if ((charLimit -= part.length) < 0) {
if (RendererMarkdown.getSetting("isAddPageBreaks")) out.push("", "\\pagebreak", "");
if (VetoolsConfig.get("markdown", "isAddPageBreaks")) out.push("", "\\pagebreak", "");
charLimit = RendererMarkdown.CHARS_PER_PAGE;
}
}
@@ -2217,13 +2217,13 @@ class ListPageBookView extends BookModeViewBase {
const $btnDownloadMarkdown = $(`<button class="btn btn-default btn-sm">Download as Markdown</button>`)
.click(() => DataUtil.userDownloadText(`${UrlUtil.getCurrentPage().replace(".html", "")}.md`, this._getVisibleAsMarkdown()));
const $btnCopyMarkdown = $(`<button class="btn btn-default btn-sm px-2" title="Copy Markdown to Clipboard"><span class="glyphicon glyphicon-copy"/></button>`)
const $btnCopyMarkdown = $(`<button class="btn btn-default btn-sm px-2" title="Copy Markdown to Clipboard"><span class="glyphicon glyphicon-copy"></span></button>`)
.click(async () => {
await MiscUtil.pCopyTextToClipboard(this._getVisibleAsMarkdown());
JqueryUtil.showCopiedEffect($btnCopyMarkdown);
});
const $btnDownloadMarkdownSettings = $(`<button class="btn btn-default btn-sm px-2" title="Markdown Settings"><span class="glyphicon glyphicon-cog"/></button>`)
const $btnDownloadMarkdownSettings = $(`<button class="btn btn-default btn-sm px-2" title="Markdown Settings"><span class="glyphicon glyphicon-cog"></span></button>`)
.click(async () => RendererMarkdown.pShowSettingsModal());
return $$`<div class="ve-flex-v-center btn-group ml-3">

View File

@@ -783,7 +783,7 @@ class CreatureBuilder extends Builder {
return $selType.val();
};
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Row"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Row"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
chooseTypeRows.splice(chooseTypeRows.indexOf(out), 1);
$wrp.empty().remove();
@@ -830,7 +830,7 @@ class CreatureBuilder extends Builder {
setState();
}
});
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Row"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Row"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
tagRows.splice(tagRows.indexOf(out), 1);
$wrp.empty().remove();
@@ -918,7 +918,7 @@ class CreatureBuilder extends Builder {
const alignmentRows = [];
const $wrpRows = $(`<div/>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($rowInner);
if ((this._state.alignment && this._state.alignment.some(it => it && (it.special != null || it.alignment !== undefined))) || !~CreatureBuilder.__$getAlignmentInput__getAlignmentIx(this._state.alignment)) {
this._state.alignment.forEach(alignment => CreatureBuilder.__$getAlignmentInput__getAlignmentRow(doUpdateState, alignmentRows, alignment).$wrp.appendTo($wrpRows));
@@ -926,7 +926,7 @@ class CreatureBuilder extends Builder {
CreatureBuilder.__$getAlignmentInput__getAlignmentRow(doUpdateState, alignmentRows, this._state.alignment).$wrp.appendTo($wrpRows);
}
const $wrpBtnAdd = $(`<div/>`).appendTo($rowInner);
const $wrpBtnAdd = $(`<div></div>`).appendTo($rowInner);
$(`<button class="btn btn-xs btn-default">Add Alignment</button>`)
.appendTo($wrpBtnAdd)
.click(() => {
@@ -1018,7 +1018,7 @@ class CreatureBuilder extends Builder {
const $stageSpecial = $$`<div>${$iptSpecial}</div>`.toggleVe(initialMode === "2");
initialMode === "2" && alignment && $iptSpecial.val(alignment.special);
const $btnRemove = $(`<button class="btn btn-xs btn-danger mkbru__btn-rm-row mb-2" title="Remove Alignment"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger mkbru__btn-rm-row mb-2" title="Remove Alignment"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
alignmentRows.splice(alignmentRows.indexOf(out), 1);
$wrp.empty().remove();
@@ -1045,10 +1045,10 @@ class CreatureBuilder extends Builder {
const acRows = [];
const $wrpRows = $(`<div/>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($rowInner);
this._state.ac.forEach(ac => CreatureBuilder.__$getAcInput__getAcRow(ac, acRows, doUpdateState).$wrp.appendTo($wrpRows));
const $wrpBtnAdd = $(`<div/>`).appendTo($rowInner);
const $wrpBtnAdd = $(`<div></div>`).appendTo($rowInner);
$(`<button class="btn btn-xs btn-default">Add Armor Class Source</button>`)
.appendTo($wrpBtnAdd)
.click(() => {
@@ -1152,7 +1152,7 @@ class CreatureBuilder extends Builder {
// "FROM" CONTROLS
const fromRows = [];
const $wrpFromRows = $(`<div/>`);
const $wrpFromRows = $(`<div></div>`);
if (ac && ac.from) ac.from.forEach(f => CreatureBuilder.__$getAcInput__getFromRow(f, fromRows, doUpdateState).$wrpFrom.appendTo($wrpFromRows));
const $btnAddFrom = $(`<button class="btn btn-xs btn-default mb-2">Add Another Feature/Item</button>`)
@@ -1166,7 +1166,7 @@ class CreatureBuilder extends Builder {
</div>`.toggleVe(initialMode === "1");
// REMOVE CONTROLS
const $btnRemove = $(`<button class="btn btn-xs btn-danger mkbru__btn-rm-row mb-2" title="Remove AC Source"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger mkbru__btn-rm-row mb-2" title="Remove AC Source"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
acRows.splice(acRows.indexOf(out), 1);
$wrp.empty().remove();
@@ -1224,7 +1224,7 @@ class CreatureBuilder extends Builder {
searchWidget.doFocus();
});
const $btnRemove = $(`<button class="btn btn-xs btn-danger mkbru__btn-rm-row--nested-1 ml-2" title="Remove AC Feature/Item"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger mkbru__btn-rm-row--nested-1 ml-2" title="Remove AC Feature/Item"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
fromRows.splice(fromRows.indexOf(outFrom), 1);
$wrpFrom.empty().remove();
@@ -1343,7 +1343,7 @@ class CreatureBuilder extends Builder {
doUpdateState();
});
const $btnAutoSimpleFormula = $(`<button class="btn btn-xs btn-default ${this._meta.autoCalc.hpModifier ? "active" : ""}" title="Auto-calculate modifier from Constitution"><span class="glyphicon glyphicon-refresh"/></button>`)
const $btnAutoSimpleFormula = $(`<button class="btn btn-xs btn-default ${this._meta.autoCalc.hpModifier ? "active" : ""}" title="Auto-calculate modifier from Constitution"><span class="glyphicon glyphicon-refresh"></span></button>`)
.click(() => {
if (this._meta.autoCalc.hpModifier) {
this._meta.autoCalc.hpModifier = false;
@@ -1362,7 +1362,7 @@ class CreatureBuilder extends Builder {
doUpdateState();
});
const $btnAutoSimpleAverage = $(`<button class="btn btn-xs btn-default ${this._meta.autoCalc.hpAverageSimple ? "active" : ""}" title="Auto-calculate"><span class="glyphicon glyphicon-refresh"/></button>`)
const $btnAutoSimpleAverage = $(`<button class="btn btn-xs btn-default ${this._meta.autoCalc.hpAverageSimple ? "active" : ""}" title="Auto-calculate"><span class="glyphicon glyphicon-refresh"></span></button>`)
.click(() => {
if (this._meta.autoCalc.hpAverageSimple) {
this._meta.autoCalc.hpAverageSimple = false;
@@ -1415,7 +1415,7 @@ class CreatureBuilder extends Builder {
doUpdateState();
});
const $btnAutoComplexAverage = $(`<button class="btn btn-xs btn-default ${this._meta.autoCalc.hpAverageComplex ? "active" : ""}" title="Auto-calculate from Formula"><span class="glyphicon glyphicon-refresh"/></button>`)
const $btnAutoComplexAverage = $(`<button class="btn btn-xs btn-default ${this._meta.autoCalc.hpAverageComplex ? "active" : ""}" title="Auto-calculate from Formula"><span class="glyphicon glyphicon-refresh"></span></button>`)
.click(() => {
if (this._meta.autoCalc.hpAverageComplex) {
this._meta.autoCalc.hpAverageComplex = false;
@@ -1732,7 +1732,7 @@ class CreatureBuilder extends Builder {
})
.val(this._state.passive || 0);
const $btnAuto = $(`<button class="btn btn-default btn-xs ${this._meta.autoCalc.passivePerception ? "active" : ""}" title="Auto-Calculate Passive Perception"><span class="glyphicon glyphicon-refresh"/></button>`)
const $btnAuto = $(`<button class="btn btn-default btn-xs ${this._meta.autoCalc.passivePerception ? "active" : ""}" title="Auto-Calculate Passive Perception"><span class="glyphicon glyphicon-refresh"></span></button>`)
.click(() => {
if (this._meta.autoCalc.passivePerception) {
delete this._meta.autoCalc.passivePerception;
@@ -1770,8 +1770,8 @@ class CreatureBuilder extends Builder {
const [$row, $rowInner] = BuilderUi.getLabelledRowTuple(rowName, {isMarked: true});
const groups = [];
const $wrpGroups = $(`<div/>`).appendTo($rowInner);
const $wrpControls = $(`<div/>`).appendTo($rowInner);
const $wrpGroups = $(`<div></div>`).appendTo($rowInner);
const $wrpControls = $(`<div></div>`).appendTo($rowInner);
const doUpdateState = () => {
const out = groups.map(it => it.getState());
@@ -1866,20 +1866,20 @@ class CreatureBuilder extends Builder {
.change(() => doUpdateState());
const $iptNotePost = $(`<input class="form-control input-xs form-control--minimal mr-2" placeholder="Post- note">`)
.change(() => doUpdateState());
const $btnRemove = $(`<button class="btn btn-xs btn-danger mkbru__btn-rm-row" title="Remove ${shortName} Group"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger mkbru__btn-rm-row" title="Remove ${shortName} Group"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
groups.splice(groups.indexOf(out), 1);
$ele.remove();
doUpdateState();
});
const $wrpChildren = $(`<div class="ve-flex-col"/>`);
const $wrpChildren = $(`<div class="ve-flex-col"></div>`);
const $wrpControls = $$`<div class="mb-2 ve-flex-v-center">${$btnAddChild}${$btnAddChildGroup}${$iptNotePre}${$iptNotePost}${$btnRemove}</div>`;
const $ele = (() => {
const $base = $$`<div class="ve-flex-col ${depth ? "" : "mkbru__wrp-rows"}">${$wrpControls}${$wrpChildren}</div>`;
if (!depth) return $base;
else return $$`<div class="ve-flex-v-center w-100"><div class="mkbru_mon__row-indent"/>${$base}</div>`;
else return $$`<div class="ve-flex-v-center w-100"><div class="mkbru_mon__row-indent"></div>${$base}</div>`;
})();
if (initial) {
@@ -1897,7 +1897,7 @@ class CreatureBuilder extends Builder {
}
static __$getDefencesInput__getNodeItem (shortName, children, doUpdateState, type, value) {
const $btnRemove = $(`<button class="btn btn-xxs btn-danger" title="Remove ${shortName} Entry"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xxs btn-danger" title="Remove ${shortName} Entry"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
children.splice(children.indexOf(out), 1);
$ele.remove();
@@ -2159,7 +2159,7 @@ class CreatureBuilder extends Builder {
cb();
});
const $btnAuto = $(`<button class="btn btn-xs btn-default ${this._meta.autoCalc.proficiency ? "active" : ""}" title="Auto-calculate from Challenge Rating (DMG p. 274)"><span class="glyphicon glyphicon-refresh"/></button>`)
const $btnAuto = $(`<button class="btn btn-xs btn-default ${this._meta.autoCalc.proficiency ? "active" : ""}" title="Auto-calculate from Challenge Rating (DMG p. 274)"><span class="glyphicon glyphicon-refresh"></span></button>`)
.click(() => {
if (this._meta.autoCalc.proficiency) {
this._meta.autoCalc.proficiency = false;
@@ -2203,8 +2203,8 @@ class CreatureBuilder extends Builder {
const [$row, $rowInner] = BuilderUi.getLabelledRowTuple("Spellcasting", {isMarked: true});
const traitRows = [];
const $wrpRows = $(`<div/>`).appendTo($rowInner);
const $wrpControls = $(`<div/>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($rowInner);
const $wrpControls = $(`<div></div>`).appendTo($rowInner);
const $btnAddRow = $(`<button class="btn btn-xs btn-default">Add Spellcasting Trait</button>`)
.appendTo($wrpControls)
@@ -2391,12 +2391,12 @@ class CreatureBuilder extends Builder {
const $btnAddSpell = $(`<button class="btn btn-xs btn-default">Add...</button>`)
.click((evt) => ContextUtil.pOpenMenu(evt, menu));
const $iptHeader = $(`<textarea class="form-control form-control--minimal resize-vertical mb-2" placeholder="Header text"/>`)
const $iptHeader = $(`<textarea class="form-control form-control--minimal resize-vertical mb-2" placeholder="Header text"></textarea>`)
.toggleVe(!!(trait && trait.headerEntries))
.change(() => doUpdateState());
if (trait && trait.headerEntries) $iptHeader.val(UiUtil.getEntriesAsText(trait.headerEntries));
const $iptFooter = $(`<textarea class="form-control form-control--minimal resize-vertical mb-2" placeholder="Footer text"/>`)
const $iptFooter = $(`<textarea class="form-control form-control--minimal resize-vertical mb-2" placeholder="Footer text"></textarea>`)
.toggleVe(!!(trait && trait.footerEntries))
.change(() => doUpdateState());
if (trait && trait.footerEntries) $iptFooter.val(UiUtil.getEntriesAsText(trait.footerEntries));
@@ -2405,12 +2405,14 @@ class CreatureBuilder extends Builder {
const $wrpSubRows = $$`<div class="ve-flex-col"></div>`;
const $wrpSubRowsOuter = $$`<div class="ve-flex-col">${$iptHeader}${$wrpSubRows}${$iptFooter}</div>`;
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Trait"><span class="glyphicon glyphicon-trash"/></button>`)
.click(() => {
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Trait"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(async () => {
const currState = getState();
if (currState) {
delete currState.name; // ignore name key
if ((currState.headerEntries || currState.footerEntries || Object.keys(currState).some(it => it !== "headerEntries" && it !== "footerEntries")) && !confirm("Are you sure?")) return;
if ((currState.headerEntries || currState.footerEntries || Object.keys(currState).some(it => it !== "headerEntries" && it !== "footerEntries"))) {
if (!await InputUiUtil.pGetUserBoolean({title: "Remove Trait", htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
}
}
traitRows.splice(traitRows.indexOf(out), 1);
@@ -2471,9 +2473,9 @@ class CreatureBuilder extends Builder {
} else return null;
};
const $wrpItems = $(`<div class="ve-flex-col"/>`);
const $wrpItems = $(`<div class="ve-flex-col"></div>`);
const $btnAdd = $(`<button class="btn btn-xxs btn-default mr-2" title="Add Spell"><span class="glyphicon glyphicon-plus"/></button>`)
const $btnAdd = $(`<button class="btn btn-xxs btn-default mr-2" title="Add Spell"><span class="glyphicon glyphicon-plus"></span></button>`)
.click(async () => {
const options = {};
@@ -2489,7 +2491,7 @@ class CreatureBuilder extends Builder {
}
});
const $btnRemove = $(`<button class="btn btn-xxs btn-danger" title="Remove Spell Group"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xxs btn-danger" title="Remove Spell Group"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
spellRows.splice(spellRows.indexOf(out), 1);
$ele.empty().remove();
@@ -2568,7 +2570,7 @@ class CreatureBuilder extends Builder {
out.$ele = $$`<div class="ve-flex mkbru_mon__spell-header-wrp mr-4">
<div class="italic">${Parser.spLevelToFull(meta.level)}-level Spells</div>
<div class="ve-flex-v-center text-muted small ml-auto"><span>(</span>${$iptSlots}<span class="mr-2">Slots</span></div>
<div class="mkbru_mon__spell-header-divider mr-2"/>
<div class="mkbru_mon__spell-header-divider mr-2"></div>
<label class="ve-flex-v-center text-muted small"><span class="mr-1">Warlock?</span>${$cbWarlock}<span>)</span></label>
</div>`;
out.getKeyPath = () => ["spells", `${meta.level}`, "spells"];
@@ -2597,7 +2599,7 @@ class CreatureBuilder extends Builder {
<div class="ve-flex-v-center mkbru__wrp-btn-xxs">${$btnAdd}${$btnRemove}</div>
</div>
${$wrpItems}
<div class="mkbru_mon__spell-divider mb-2"/>
<div class="mkbru_mon__spell-divider mb-2"></div>
</div>`;
if (data) data.forEach(spell => addItem(spell));
@@ -2618,7 +2620,7 @@ class CreatureBuilder extends Builder {
})
.hideVe();
const $btnToggleEdit = $(`<button class="btn btn-xxs btn-default mr-2" title="Toggle Edit Mode"><span class="glyphicon glyphicon-pencil"/></button>`)
const $btnToggleEdit = $(`<button class="btn btn-xxs btn-default mr-2" title="Toggle Edit Mode"><span class="glyphicon glyphicon-pencil"></span></button>`)
.click(() => {
$btnToggleEdit.toggleClass("active");
$iptSpell.toggleVe($btnToggleEdit.hasClass("active"));
@@ -2627,7 +2629,7 @@ class CreatureBuilder extends Builder {
const $wrpRender = $(`<div class="mr-2">${getHtml()}</div>`);
const $btnRemove = $(`<button class="btn btn-xxs btn-danger" title="Remove Spell"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xxs btn-danger" title="Remove Spell"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
rowItems.splice(rowItems.indexOf(out), 1);
$ele.empty().remove();
@@ -2785,8 +2787,9 @@ class CreatureBuilder extends Builder {
});
const $btnReset = $(`<button class="btn btn-sm btn-danger">Reset</button>`)
.click(() => {
if (!confirm("Are you sure?")) return;
.click(async () => {
if (!await InputUiUtil.pGetUserBoolean({title: "Reset", htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
setState({
iptName: "",
cbMelee: true,
@@ -3018,11 +3021,11 @@ class CreatureBuilder extends Builder {
const entryRows = [];
const $wrpRowsOuter = $(`<div class="relative"/>`).appendTo($rowInner);
const $wrpRows = $(`<div/>`).appendTo($wrpRowsOuter);
const $wrpRowsOuter = $(`<div class="relative"></div>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($wrpRowsOuter);
const rowOptions = {prop: options.prop, shortName: options.shortName, $wrpRowsOuter};
const $wrpBtnAdd = $(`<div/>`).appendTo($rowInner);
const $wrpBtnAdd = $(`<div></div>`).appendTo($rowInner);
$(`<button class="btn btn-xs btn-default">Add ${options.shortName}</button>`)
.appendTo($wrpBtnAdd)
.click(() => {
@@ -3096,15 +3099,17 @@ class CreatureBuilder extends Builder {
$wrpRowsOuter: options.$wrpRowsOuter,
}) : null;
const $iptEntries = $(`<textarea class="form-control form-control--minimal resize-vertical mb-2"/>`)
const $iptEntries = $(`<textarea class="form-control form-control--minimal resize-vertical mb-2"></textarea>`)
.change(() => doUpdateState());
if (entry && entry.entries) $iptEntries.val(UiUtil.getEntriesAsText(entry.entries));
const $btnRemove = $(`<button class="btn btn-xs btn-danger mb-2" title="Remove ${options.shortName}"><span class="glyphicon glyphicon-trash"/></button>`)
.click(() => {
const $btnRemove = $(`<button class="btn btn-xs btn-danger mb-2" title="Remove ${options.shortName}"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(async () => {
const currState = getState();
if (currState && currState.entries && !confirm("Are you sure?")) return;
if (currState && currState.entries) {
if (!await InputUiUtil.pGetUserBoolean({title: `Remove ${options.shortName}`, htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
}
entryRows.splice(entryRows.indexOf(out), 1);
$ele.empty().remove();
doUpdateState();
@@ -3364,7 +3369,7 @@ class CreatureBuilder extends Builder {
cb();
};
const $wrpIpts = $(`<div class="ve-flex-col w-100 mr-2"/>`);
const $wrpIpts = $(`<div class="ve-flex-col w-100 mr-2"></div>`);
const inputs = [];
Parser.ENVIRONMENTS.forEach(val => {
const $cb = $(`<input class="mkbru__ipt-cb mkbru_mon__cb-environment" type="checkbox">`)
@@ -3403,7 +3408,7 @@ class CreatureBuilder extends Builder {
const $cb = $(`<input class="mkbru__ipt-cb hidden" type="checkbox">`)
.prop("checked", true);
const $btnRemove = $(`<button class="btn btn-danger btn-xxs"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-danger btn-xxs"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
out.$ele.remove();
envRows.splice(envRows.indexOf(out), 1);
@@ -3480,11 +3485,11 @@ class CreatureBuilder extends Builder {
tabs.forEach(it => it.$wrpTab.appendTo($wrp));
// statblock
const $tblMon = $(`<table class="w-100 stats monster"/>`).appendTo(statTab.$wrpTab);
const $tblMon = $(`<table class="w-100 stats monster"></table>`).appendTo(statTab.$wrpTab);
RenderBestiary.$getRenderedCreature(this._state, {isSkipExcludesRender: true}).appendTo($tblMon);
// info
const $tblInfo = $(`<table class="w-100 stats"/>`).appendTo(infoTab.$wrpTab);
const $tblInfo = $(`<table class="w-100 stats"></table>`).appendTo(infoTab.$wrpTab);
Renderer.utils.pBuildFluffTab({
isImageTab: false,
$content: $tblInfo,
@@ -3493,7 +3498,7 @@ class CreatureBuilder extends Builder {
});
// images
const $tblImages = $(`<table class="w-100 stats"/>`).appendTo(imageTab.$wrpTab);
const $tblImages = $(`<table class="w-100 stats"></table>`).appendTo(imageTab.$wrpTab);
Renderer.utils.pBuildFluffTab({
isImageTab: true,
$content: $tblImages,
@@ -3502,7 +3507,7 @@ class CreatureBuilder extends Builder {
});
// data
const $tblData = $(`<table class="w-100 stats stats--book mkbru__wrp-output-tab-data"/>`).appendTo(dataTab.$wrpTab);
const $tblData = $(`<table class="w-100 stats stats--book mkbru__wrp-output-tab-data"></table>`).appendTo(dataTab.$wrpTab);
const asJson = Renderer.get().render({
type: "entries",
entries: [
@@ -3518,7 +3523,7 @@ class CreatureBuilder extends Builder {
$tblData.append(Renderer.utils.getBorderTr());
// markdown
const $tblMarkdown = $(`<table class="w-100 stats stats--book mkbru__wrp-output-tab-data"/>`).appendTo(markdownTab.$wrpTab);
const $tblMarkdown = $(`<table class="w-100 stats stats--book mkbru__wrp-output-tab-data"></table>`).appendTo(markdownTab.$wrpTab);
$tblMarkdown.append(Renderer.utils.getBorderTr());
$tblMarkdown.append(`<tr><td colspan="6">${this._getRenderedMarkdownCode()}</td></tr>`);
$tblMarkdown.append(Renderer.utils.getBorderTr());

View File

@@ -157,11 +157,11 @@ class LegendaryGroupBuilder extends Builder {
tabs.forEach(it => it.$wrpTab.appendTo($wrp));
// Legendary Group
const $tblLegGroup = $(`<table class="w-100 stats"/>`).appendTo(legGroupTab.$wrpTab);
const $tblLegGroup = $(`<table class="w-100 stats"></table>`).appendTo(legGroupTab.$wrpTab);
RenderBestiary.$getRenderedLegendaryGroup(this._state).appendTo($tblLegGroup);
// Data
const $tblData = $(`<table class="stats stats--book mkbru__wrp-output-tab-data"/>`).appendTo(dataTab.$wrpTab);
const $tblData = $(`<table class="stats stats--book mkbru__wrp-output-tab-data"></table>`).appendTo(dataTab.$wrpTab);
const asCode = Renderer.get().render({
type: "entries",
entries: [

View File

@@ -319,10 +319,10 @@ class SpellBuilder extends Builder {
const otherSourceRows = [];
const $wrpRows = $(`<div/>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($rowInner);
(this._state.otherSources || []).forEach(it => this.__$getOtherSourcesInput__getOtherSourceRow(doUpdateState, otherSourceRows, it).$wrp.appendTo($wrpRows));
const $wrpBtnAdd = $(`<div/>`).appendTo($rowInner);
const $wrpBtnAdd = $(`<div></div>`).appendTo($rowInner);
$(`<button class="btn btn-xs btn-default">Add Other Source</button>`)
.appendTo($wrpBtnAdd)
.click(() => {
@@ -355,7 +355,7 @@ class SpellBuilder extends Builder {
const out = {getOtherSource};
const $wrpBtnRemove = $(`<div class="text-right mb-2"/>`);
const $wrpBtnRemove = $(`<div class="text-right mb-2"></div>`);
const $wrp = $$`<div class="ve-flex-col mkbru__wrp-rows mkbru__wrp-rows--removable">
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Source</span>${$selSource}</div>
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Page</span>${$iptPage}</div>
@@ -378,10 +378,10 @@ class SpellBuilder extends Builder {
const timeRows = [];
const $wrpRows = $(`<div/>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($rowInner);
this._state.time.forEach(time => SpellBuilder.__$getTimeInput__getTimeRow(doUpdateState, timeRows, time).$wrp.appendTo($wrpRows));
const $wrpBtnAdd = $(`<div/>`).appendTo($rowInner);
const $wrpBtnAdd = $(`<div></div>`).appendTo($rowInner);
$(`<button class="btn btn-xs btn-default">Add Casting Time</button>`)
.appendTo($wrpBtnAdd)
.click(() => {
@@ -430,7 +430,7 @@ class SpellBuilder extends Builder {
<span class="mr-2 mkbru__sub-name--33">Condition</span>${$iptCond}
</div>`.toggleVe(ixInitial === 2);
const $wrpBtnRemove = $(`<div class="text-right mb-2"/>`);
const $wrpBtnRemove = $(`<div class="text-right mb-2"></div>`);
const $wrp = $$`<div class="ve-flex-col mkbru__wrp-rows mkbru__wrp-rows--removable">
<div class="ve-flex-v-center mb-2">${$iptNum}${$selUnit}</div>
${$stageCond}
@@ -646,10 +646,10 @@ class SpellBuilder extends Builder {
const durationRows = [];
const $wrpRows = $(`<div/>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($rowInner);
this._state.duration.forEach(duration => SpellBuilder.__$getDurationInput__getDurationRow(doUpdateState, durationRows, duration).$wrp.appendTo($wrpRows));
const $wrpBtnAdd = $(`<div/>`).appendTo($rowInner);
const $wrpBtnAdd = $(`<div></div>`).appendTo($rowInner);
$(`<button class="btn btn-xs btn-default">Add Duration</button>`)
.appendTo($wrpBtnAdd)
.click(() => {
@@ -721,7 +721,7 @@ class SpellBuilder extends Builder {
// ENDS
const endRows = [];
const $wrpEndRows = $(`<div class="ve-flex-col"/>`);
const $wrpEndRows = $(`<div class="ve-flex-col"></div>`);
const $btnAddEnd = $(`<button class="btn btn-xs btn-default">Add &quot;Until&quot; Clause</button>`)
.click(() => {
SpellBuilder.__$getDurationInput__getDurationRow__getEndRow(doUpdateState, endRows, "dispel").$wrp.appendTo($wrpEndRows);
@@ -735,7 +735,7 @@ class SpellBuilder extends Builder {
const out = {getDuration};
const $wrpBtnRemove = $(`<div class="text-right mb-2"/>`);
const $wrpBtnRemove = $(`<div class="text-right mb-2"></div>`);
const $wrp = $$`<div class="ve-flex-col mkbru__wrp-rows mkbru__wrp-rows--removable">
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Duration Type</span>${$selDurationType}</div>
${$stageAmount}
@@ -761,7 +761,7 @@ class SpellBuilder extends Builder {
const out = {getEnd};
const $wrpBtnRemove = $(`<div/>`);
const $wrpBtnRemove = $(`<div></div>`);
const $wrp = $$`<div class="ve-flex">
<div class="mkbru__sub-name--33 mr-2"></div>
<div class="mb-2 ve-flex-v-center w-100">${$selEndType}${$wrpBtnRemove}</div>
@@ -792,7 +792,7 @@ class SpellBuilder extends Builder {
};
// CLASSES
const $wrpRowsCls = $(`<div/>`).appendTo($rowInnerCls);
const $wrpRowsCls = $(`<div></div>`).appendTo($rowInnerCls);
const doRefreshCls = () => {
$wrpRowsCls.empty();
classRows.splice(0, classRows.length);
@@ -800,7 +800,7 @@ class SpellBuilder extends Builder {
};
doRefreshCls();
const $wrpBtnAddCls = $(`<div/>`).appendTo($rowInnerCls);
const $wrpBtnAddCls = $(`<div></div>`).appendTo($rowInnerCls);
$(`<button class="btn btn-xs btn-default">Add Class</button>`)
.appendTo($wrpBtnAddCls)
.click(() => {
@@ -809,7 +809,7 @@ class SpellBuilder extends Builder {
});
// SUBCLASSES
const $wrpRowsSc = $(`<div/>`).appendTo($rowInnerSc);
const $wrpRowsSc = $(`<div></div>`).appendTo($rowInnerSc);
const doRefreshSc = () => {
$wrpRowsSc.empty();
subclassRows.splice(0, subclassRows.length);
@@ -817,7 +817,7 @@ class SpellBuilder extends Builder {
};
doRefreshSc();
const $wrpBtnAddSc = $(`<div/>`).appendTo($rowInnerSc);
const $wrpBtnAddSc = $(`<div></div>`).appendTo($rowInnerSc);
$(`<button class="btn btn-xs btn-default">Add Subclass</button>`)
.appendTo($wrpBtnAddSc)
.click(() => {
@@ -843,7 +843,7 @@ class SpellBuilder extends Builder {
const out = {getClass};
const $wrpBtnRemove = $(`<div class="text-right mb-2"/>`);
const $wrpBtnRemove = $(`<div class="text-right mb-2"></div>`);
const $wrp = $$`<div class="ve-flex-col mkbru__wrp-rows mkbru__wrp-rows--removable">
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Class Name</span>${$iptClass}</div>
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Class Source</span>${$selClassSource}</div>
@@ -897,7 +897,7 @@ class SpellBuilder extends Builder {
const out = {getSubclass};
const $wrpBtnRemove = $(`<div class="text-right mb-2"/>`);
const $wrpBtnRemove = $(`<div class="text-right mb-2"></div>`);
const $wrp = $$`<div class="ve-flex-col mkbru__wrp-rows">
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Class Name</span>${$iptClass}</div>
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Class Source</span>${$selClassSource}</div>
@@ -926,7 +926,7 @@ class SpellBuilder extends Builder {
const raceRows = [];
const $wrpRows = $(`<div/>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($rowInner);
const doRefresh = () => {
$wrpRows.empty();
@@ -935,7 +935,7 @@ class SpellBuilder extends Builder {
};
doRefresh();
const $wrpBtnAdd = $(`<div/>`).appendTo($rowInner);
const $wrpBtnAdd = $(`<div></div>`).appendTo($rowInner);
$(`<button class="btn btn-xs btn-default">Add Race</button>`)
.appendTo($wrpBtnAdd)
.click(() => {
@@ -975,7 +975,7 @@ class SpellBuilder extends Builder {
const out = {getRace};
const $wrpBtnRemove = $(`<div class="text-right mb-2"/>`);
const $wrpBtnRemove = $(`<div class="text-right mb-2"></div>`);
const $wrp = $$`<div class="ve-flex-col mkbru__wrp-rows">
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Name</span>${$iptRace}</div>
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Source</span>${$selSource}</div>
@@ -1042,7 +1042,7 @@ class SpellBuilder extends Builder {
const out = {getIdentObject};
const $wrpBtnRemove = $(`<div class="text-right mb-2"/>`);
const $wrpBtnRemove = $(`<div class="text-right mb-2"></div>`);
const $wrp = $$`<div class="ve-flex-col mkbru__wrp-rows">
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Name</span>${$iptName}</div>
<div class="ve-flex-v-center mb-2"><span class="mr-2 mkbru__sub-name--33">Source</span>${$selSource}</div>
@@ -1201,14 +1201,14 @@ class SpellBuilder extends Builder {
tabs.forEach(it => it.$wrpTab.appendTo($wrp));
// Spell
const $tblSpell = $(`<table class="w-100 stats"/>`).appendTo(spellTab.$wrpTab);
const $tblSpell = $(`<table class="w-100 stats"></table>`).appendTo(spellTab.$wrpTab);
// Make a copy of the spell, and add the data that would be displayed in the spells page
const procSpell = MiscUtil.copy(this._state);
Renderer.spell.initBrewSources(procSpell);
RenderSpells.$getRenderedSpell(procSpell, this._subclassLookup, {isSkipExcludesRender: true}).appendTo($tblSpell);
// Info
const $tblInfo = $(`<table class="w-100 stats"/>`).appendTo(infoTab.$wrpTab);
const $tblInfo = $(`<table class="w-100 stats"></table>`).appendTo(infoTab.$wrpTab);
Renderer.utils.pBuildFluffTab({
isImageTab: false,
$content: $tblInfo,
@@ -1217,7 +1217,7 @@ class SpellBuilder extends Builder {
});
// Images
const $tblImages = $(`<table class="w-100 stats"/>`).appendTo(imageTab.$wrpTab);
const $tblImages = $(`<table class="w-100 stats"></table>`).appendTo(imageTab.$wrpTab);
Renderer.utils.pBuildFluffTab({
isImageTab: true,
$content: $tblImages,
@@ -1226,7 +1226,7 @@ class SpellBuilder extends Builder {
});
// Data
const $tblData = $(`<table class="w-100 stats stats--book mkbru__wrp-output-tab-data"/>`).appendTo(dataTab.$wrpTab);
const $tblData = $(`<table class="w-100 stats stats--book mkbru__wrp-output-tab-data"></table>`).appendTo(dataTab.$wrpTab);
const asCode = Renderer.get().render({
type: "entries",
entries: [
@@ -1242,7 +1242,7 @@ class SpellBuilder extends Builder {
$tblData.append(Renderer.utils.getBorderTr());
// Markdown
const $tblMarkdown = $(`<table class="w-100 stats stats--book mkbru__wrp-output-tab-data"/>`).appendTo(markdownTab.$wrpTab);
const $tblMarkdown = $(`<table class="w-100 stats stats--book mkbru__wrp-output-tab-data"></table>`).appendTo(markdownTab.$wrpTab);
$tblMarkdown.append(Renderer.utils.getBorderTr());
$tblMarkdown.append(`<tr><td colspan="6">${this._getRenderedMarkdownCode()}</td></tr>`);
$tblMarkdown.append(Renderer.utils.getBorderTr());

View File

@@ -247,7 +247,7 @@ class PageUi {
$$`<div class="w-100">${$btnSourceAdd}</div>`.appendTo($mnu);
$mnu.append(PageUi.__$getSideMenuDivider(true));
this._$menuInner = $(`<div/>`).appendTo($mnu);
this._$menuInner = $(`<div></div>`).appendTo($mnu);
if (prevMode) await this._pSetActiveBuilder(prevMode);
}
@@ -453,7 +453,7 @@ class Builder extends ProxyBase {
DataUtil.userDownloadText(`${DataUtil.getCleanFilename(BrewUtil2.sourceJsonToFull(this._ui.source))}.md`, mdOut);
});
const $btnSettings = $(`<button class="btn btn-default btn-xs mb-2"><span class="glyphicon glyphicon-cog"/></button>`)
const $btnSettings = $(`<button class="btn btn-default btn-xs mb-2"><span class="glyphicon glyphicon-cog"></span></button>`)
.click(() => RendererMarkdown.pShowSettingsModal());
return $$`<div class="ve-flex-v-center btn-group">${$btnDownload}${$btnSettings}</div>`;
@@ -520,7 +520,7 @@ class Builder extends ProxyBase {
return;
}
const $btnEdit = $(`<button class="btn btn-xs btn-default mr-2" title="Edit"><span class="glyphicon glyphicon-pencil"/></button>`)
const $btnEdit = $(`<button class="btn btn-xs btn-default mr-2" title="Edit"><span class="glyphicon glyphicon-pencil"></span></button>`)
.click(async () => {
if (
this.getOnNavMessage()
@@ -616,10 +616,10 @@ class Builder extends ProxyBase {
),
]);
const $btnBurger = $(`<button class="btn btn-xs btn-default mr-2" title="More Options"><span class="glyphicon glyphicon-option-vertical"/></button>`)
const $btnBurger = $(`<button class="btn btn-xs btn-default mr-2" title="More Options"><span class="glyphicon glyphicon-option-vertical"></span></button>`)
.click(evt => ContextUtil.pOpenMenu(evt, menu));
const $btnDelete = $(`<button class="btn btn-xs btn-danger" title="Delete"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnDelete = $(`<button class="btn btn-xs btn-danger" title="Delete"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(async () => {
if (!await InputUiUtil.pGetUserBoolean({title: "Delete Entity", htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
@@ -772,7 +772,7 @@ class Builder extends ProxyBase {
static $getBtnRemoveRow (doUpdateState, rowArr, row, $wrpRow, title, opts) {
opts = opts || {};
return $(`<button class="btn ${opts.isExtraSmall ? "btn-xxs" : "btn-xs"} btn-danger ${opts.isProtectLast ? "mkbru__btn-rm-row" : ""}" title="Remove ${title}"><span class="glyphicon glyphicon-trash"/></button>`)
return $(`<button class="btn ${opts.isExtraSmall ? "btn-xxs" : "btn-xs"} btn-danger ${opts.isProtectLast ? "mkbru__btn-rm-row" : ""}" title="Remove ${title}"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
rowArr.splice(rowArr.indexOf(row), 1);
$wrpRow.empty().remove();
@@ -806,12 +806,12 @@ class Builder extends ProxyBase {
doUpdateState();
};
const $wrpRowsOuter = $(`<div class="relative"/>`);
const $wrpRows = $(`<div class="ve-flex-col"/>`).appendTo($wrpRowsOuter);
const $wrpRowsOuter = $(`<div class="relative"></div>`);
const $wrpRows = $(`<div class="ve-flex-col"></div>`).appendTo($wrpRowsOuter);
const rowOptions = {$wrpRowsOuter};
const $iptEntries = $(`<textarea class="form-control form-control--minimal resize-vertical mb-2"/>`)
const $iptEntries = $(`<textarea class="form-control form-control--minimal resize-vertical mb-2"></textarea>`)
.change(() => doUpdateState());
const $btnAddImage = $(`<button class="btn btn-xs btn-default">Add Image</button>`)
@@ -854,7 +854,7 @@ class Builder extends ProxyBase {
}
}
const $btnPreview = $(`<button class="btn btn-xs btn-default mr-2" title="Preview Image"><span class="glyphicon glyphicon-fullscreen"/></button>`)
const $btnPreview = $(`<button class="btn btn-xs btn-default mr-2" title="Preview Image"><span class="glyphicon glyphicon-fullscreen"></span></button>`)
.click((evt) => {
const toRender = getState();
if (!toRender) return JqueryUtil.doToast({content: "Please enter an image URL", type: "warning"});
@@ -871,7 +871,7 @@ class Builder extends ProxyBase {
);
});
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Image"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Image"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
imageRows.splice(imageRows.indexOf(out), 1);
out.$ele.empty().remove();
@@ -978,8 +978,8 @@ class BuilderUi {
const eleType = options.eleType || "div";
const $rowInner = $(`<div class="${options.isRow ? "ve-flex" : "ve-flex-col"} w-100"/>`);
const $row = $$`<div class="mb-2 mkbru__row stripe-even"><${eleType} class="mkbru__wrp-row ve-flex-v-center"><span class="mr-2 mkbru__row-name ve-shrink-10 ${options.isMarked ? `mkbru__row-name--marked` : ""} ${options.title ? "help" : ""}" ${options.title ? `title="${options.title}"` : ""}>${name}</span>${options.isMarked ? `<div class="mkbru__row-mark mr-2"/>` : ""}${$rowInner}</${eleType}></div>`;
const $rowInner = $(`<div class="${options.isRow ? "ve-flex" : "ve-flex-col"} w-100"></div>`);
const $row = $$`<div class="mb-2 mkbru__row stripe-even"><${eleType} class="mkbru__wrp-row ve-flex-v-center"><span class="mr-2 mkbru__row-name ve-shrink-10 ${options.isMarked ? `mkbru__row-name--marked` : ""} ${options.title ? "help" : ""}" ${options.title ? `title="${options.title}"` : ""}>${name}</span>${options.isMarked ? `<div class="mkbru__row-mark mr-2"></div>` : ""}${$rowInner}</${eleType}></div>`;
return [$row, $rowInner];
}
@@ -1067,10 +1067,10 @@ class BuilderUi {
fnRender();
};
const $wrpRows = $(`<div/>`).appendTo($rowInner);
const $wrpRows = $(`<div></div>`).appendTo($rowInner);
initialState.forEach(string => BuilderUi._$getStateIptStringArray_getRow(doUpdateState, stringRows, string).$wrp.appendTo($wrpRows));
const $wrpBtnAdd = $(`<div/>`).appendTo($rowInner);
const $wrpBtnAdd = $(`<div></div>`).appendTo($rowInner);
$(`<button class="btn btn-xs btn-default">Add ${options.shortName}</button>`)
.appendTo($wrpBtnAdd)
.click(() => {
@@ -1095,7 +1095,7 @@ class BuilderUi {
.change(() => doUpdateState());
if (initialString && initialString.trim()) $iptString.val(initialString);
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Row"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnRemove = $(`<button class="btn btn-xs btn-danger" title="Remove Row"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
stringRows.splice(stringRows.indexOf(out), 1);
$wrp.empty().remove();
@@ -1183,7 +1183,7 @@ class BuilderUi {
const [$row, $rowInner] = BuilderUi.getLabelledRowTuple(name, {isMarked: true});
const initialState = MiscUtil.get(state, ...path) || [];
const $wrpIpts = $(`<div class="ve-flex-col w-100 mr-2"/>`).appendTo($rowInner);
const $wrpIpts = $(`<div class="ve-flex-col w-100 mr-2"></div>`).appendTo($rowInner);
const inputs = [];
options.vals.forEach(val => {
const $cb = $(`<input class="mkbru__ipt-cb" type="checkbox">`)
@@ -1239,7 +1239,7 @@ class BuilderUi {
}
static $getUpButton (cbUpdate, rows, myRow) {
return $(`<button class="btn btn-xs btn-default mkbru__btn-up-row ml-2" title="Move Up"><span class="glyphicon glyphicon-arrow-up"/></button>`)
return $(`<button class="btn btn-xs btn-default mkbru__btn-up-row ml-2" title="Move Up"><span class="glyphicon glyphicon-arrow-up"></span></button>`)
.click(() => {
const ix = rows.indexOf(myRow);
const cache = rows[ix - 1];
@@ -1250,7 +1250,7 @@ class BuilderUi {
}
static $getDownButton (cbUpdate, rows, myRow) {
return $(`<button class="btn btn-xs btn-default mkbru__btn-down-row ml-2" title="Move Down"><span class="glyphicon glyphicon-arrow-down"/></button>`)
return $(`<button class="btn btn-xs btn-default mkbru__btn-down-row ml-2" title="Move Down"><span class="glyphicon glyphicon-arrow-down"></span></button>`)
.click(() => {
const ix = rows.indexOf(myRow);
const cache = rows[ix + 1];
@@ -1278,14 +1278,14 @@ class BuilderUi {
});
dragMeta.on = true;
dragMeta.$wrap = $(`<div class="ve-flex-col ui-drag__wrp-drag-block"/>`).appendTo(options.$wrpRowsOuter);
dragMeta.$wrap = $(`<div class="ve-flex-col ui-drag__wrp-drag-block"></div>`).appendTo(options.$wrpRowsOuter);
dragMeta.$dummies = [];
const ixRow = rows.indexOf(myRow);
rows.forEach((row, i) => {
const dimensions = {w: row.$ele.outerWidth(true), h: row.$ele.outerHeight(true)};
const $dummy = $(`<div class="${i === ixRow ? "ui-drag__wrp-drag-dummy--highlight" : "ui-drag__wrp-drag-dummy--lowlight"}"/>`)
const $dummy = $(`<div class="${i === ixRow ? "ui-drag__wrp-drag-dummy--highlight" : "ui-drag__wrp-drag-dummy--lowlight"}"></div>`)
.width(dimensions.w).height(dimensions.h)
.mouseup(() => {
if (dragMeta.on) {

View File

@@ -74,7 +74,7 @@ class MakeCards extends BaseComponent {
const kColor = `color_${entityType}`;
const kIcon = `icon_${entityType}`;
const $iptColor = ComponentUiUtil.$getIptColor(this, kColor).addClass("cards-cfg__ipt-color");
const $dispIcon = $(`<div class="cards__disp-btn-icon"/>`);
const $dispIcon = $(`<div class="cards__disp-btn-icon"></div>`);
const $btnChooseIcon = $$`<button class="btn btn-xs btn-default cards__btn-choose-icon">${$dispIcon}</button>`
.click(async () => {
const icon = await MakeCards._pGetUserIcon(this._state[kIcon]);
@@ -101,16 +101,16 @@ class MakeCards extends BaseComponent {
const menuSearch = ContextUtil.getMenu(this._render_getContextMenuOptions());
const $iptSearch = $(`<input type="search" class="form-control mr-2" placeholder="Search cards...">`);
const $btnAdd = $(`<button class="btn btn-primary mr-2"><span class="glyphicon glyphicon-plus"/> Add</button>`)
const $btnAdd = $(`<button class="btn btn-primary mr-2"><span class="glyphicon glyphicon-plus"></span> Add</button>`)
.click(evt => ContextUtil.pOpenMenu(evt, menuSearch));
const $btnReset = $(`<button class="btn btn-danger mr-2"><span class="glyphicon glyphicon-trash"/> Reset</button>`)
.click(() => {
if (!confirm("Are you sure?")) return;
const $btnReset = $(`<button class="btn btn-danger mr-2"><span class="glyphicon glyphicon-trash"></span> Reset</button>`)
.click(async () => {
if (!await InputUiUtil.pGetUserBoolean({title: "Reset", htmlDescription: "Are you sure?", textYes: "Yes", textNo: "Cancel"})) return;
this._list.removeAllItems();
this._list.update();
this._doSaveStateDebounced();
});
const $btnExport = $(`<button class="btn btn-default"><span class="glyphicon glyphicon-download"/> Export JSON</button>`)
const $btnExport = $(`<button class="btn btn-default"><span class="glyphicon glyphicon-download"></span> Export JSON</button>`)
.click(() => {
const toDownload = this._list.items.map(it => {
const entityMeta = MakeCards._AVAILABLE_TYPES[it.values.entityType];
@@ -190,10 +190,10 @@ class MakeCards extends BaseComponent {
<div class="ve-col-1-1 mr-2 ve-flex-vh-center">Color</div>
<div class="ve-col-1-1 mr-2 ve-flex-vh-center">Icon</div>
<div class="ve-col-1 mr-2 ve-flex-vh-center">Count</div>
<div class="ve-col-1-1 ve-flex-v-center ve-flex-h-right"/>
<div class="ve-col-1-1 ve-flex-v-center ve-flex-h-right"></div>
</div>`.appendTo($wrpContainer);
const $wrpList = $(`<div class="w-100 h-100"/>`);
const $wrpList = $(`<div class="w-100 h-100"></div>`);
$$`<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});
@@ -319,7 +319,7 @@ class MakeCards extends BaseComponent {
this._doSaveStateDebounced();
};
const $dispIcon = $(`<div class="cards__disp-btn-icon"/>`)
const $dispIcon = $(`<div class="cards__disp-btn-icon"></div>`)
.css("background-image", `url('${MakeCards._getIconPath(cardMeta.icon)}')`);
const $btnIcon = $$`<button class="btn btn-default btn-xs cards__btn-choose-icon">${$dispIcon}</button>`
.click(async () => {
@@ -341,7 +341,7 @@ class MakeCards extends BaseComponent {
})
.val(cardMeta.count);
const $btnCopy = $(`<button class="btn btn-default btn-xs mr-2" title="Copy JSON (SHIFT to view JSON)"><span class="glyphicon glyphicon-copy"/></button>`)
const $btnCopy = $(`<button class="btn btn-default btn-xs mr-2" title="Copy JSON (SHIFT to view JSON)"><span class="glyphicon glyphicon-copy"></span></button>`)
.click(async evt => {
const entityMeta = MakeCards._AVAILABLE_TYPES[listItem.values.entityType];
const toCopy = {
@@ -371,7 +371,7 @@ class MakeCards extends BaseComponent {
JqueryUtil.showCopiedEffect($btnCopy, "Copied JSON!");
}
});
const $btnDelete = $(`<button class="btn btn-danger btn-xs" title="Remove"><span class="glyphicon glyphicon-trash"/></button>`)
const $btnDelete = $(`<button class="btn btn-danger btn-xs" title="Remove"><span class="glyphicon glyphicon-trash"></span></button>`)
.click(() => {
this._list.removeItemByIndex(uid);
this._list.update();
@@ -631,7 +631,7 @@ class MakeCards extends BaseComponent {
source: icon_names,
items: "16",
fnGetItemPrefix: (iconName) => {
return `<span class="cards__disp-typeahead-icon mr-2" style="background-image: url('${MakeCards._getIconPath(iconName)}')"/> `;
return `<span class="cards__disp-typeahead-icon mr-2" style="background-image: url('${MakeCards._getIconPath(iconName)}')"></span> `;
},
});

View File

@@ -7,7 +7,7 @@ class ManageBrew {
static async pRender () {
const manager = new ManageBrewUi({brewUtil: BrewUtil2});
return manager.pRender($(`#brewmanager`).empty());
return manager.pRender($(`#manager`).empty());
}
}

View File

@@ -7,7 +7,7 @@ class ManagePrerelease {
static async pRender () {
const manager = new ManageBrewUi({brewUtil: PrereleaseUtil});
return manager.pRender($(`#prereleasemanager`).empty());
return manager.pRender($(`#manager`).empty());
}
}

View File

@@ -272,7 +272,13 @@ class MapsPage extends BaseComponent {
}
_getSearchName ({sourceMeta}) {
return this._getTitleName({sourceMeta}).toLowerCase().trim();
return [
this._getTitleName({sourceMeta}),
Parser.sourceJsonToAbv(sourceMeta.source),
]
.join(" - ")
.toLowerCase()
.trim();
}
_isVisibleSourceSearch ({searchName}) { return searchName.includes(this._state.search.trim().toLowerCase()); }

View File

@@ -15,7 +15,7 @@ class NavBar {
static _onLoad () {
NavBar._dropdowns = [...NavBar._navbar.querySelectorAll(`li.dropdown--navbar`)];
document.addEventListener("click", () => NavBar._dropdowns.forEach(ele => ele.classList.remove("open")));
document.addEventListener("click", () => NavBar._closeAllDropdowns());
NavBar._clearAllTimers();
@@ -123,19 +123,11 @@ class NavBar {
this._addElement_button(
NavBar._CAT_SETTINGS,
{
html: styleSwitcher.getDayNightButtonText(),
click: (evt) => NavBar.InteractionManager._onClick_button_dayNight(evt),
context: (evt) => NavBar.InteractionManager._onContext_button_dayNight(evt),
className: "nightModeToggle",
},
);
this._addElement_button(
NavBar._CAT_SETTINGS,
{
html: styleSwitcher.getActiveWide() === true ? "Disable Wide Mode" : "Enable Wide Mode (Experimental)",
click: (evt) => NavBar.InteractionManager._onClick_button_wideMode(evt),
className: "wideModeToggle",
title: "This feature is unsupported. Expect bugs.",
html: "Preferences",
click: () => {
ConfigUi.show();
NavBar._closeAllDropdowns();
},
},
);
this._addElement_divider(NavBar._CAT_SETTINGS);
@@ -395,7 +387,7 @@ class NavBar {
a.setAttribute("target", "_blank");
a.classList.add("inline-split-v-center");
a.classList.add("w-100");
a.innerHTML = `<span>${aText}</span><span class="glyphicon glyphicon-new-window"/>`;
a.innerHTML = `<span>${aText}</span><span class="glyphicon glyphicon-new-window"></span>`;
}
li.appendChild(a);
@@ -618,6 +610,10 @@ class NavBar {
else NavBar._openDropdown(ele);
}
static _closeAllDropdowns () {
NavBar._dropdowns.forEach(ele => ele.classList.remove("open"));
}
static _openDropdown (ele) {
const lisOpen = [];

View File

@@ -644,7 +644,7 @@ class Omnisearch {
static addScrollTopFloat () {
// "To top" button
const $btnToTop = $(`<button class="btn btn-sm btn-default" title="To Top"><span class="glyphicon glyphicon-arrow-up"/></button>`)
const $btnToTop = $(`<button class="btn btn-sm btn-default" title="To Top"><span class="glyphicon glyphicon-arrow-up"></span></button>`)
.click(() => MiscUtil.scrollPageTop());
const $wrpTop = $$`<div class="bk__to-top no-print">

View File

@@ -1683,6 +1683,8 @@ Parser.monSpellcastingTagToFull = function (tag) {
Parser.MON_MISC_TAG_TO_FULL = {
"AOE": "Has Areas of Effect",
"CUR": "Inflicts Curse",
"DIS": "Inflicts Disease",
"HPR": "Has HP Reduction",
"MW": "Has Weapon Attacks, Melee",
"RW": "Has Weapon Attacks, Ranged",

7
js/privacy-policy.js Normal file
View File

@@ -0,0 +1,7 @@
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
});

View File

@@ -48,7 +48,7 @@ class RenderDeities {
${entriesMeta.entriesAttributes.map(entry => `<tr><td colspan="6">${Renderer.get().render(entry)}</td></tr>`).join("")}
${deity.symbolImg ? `<tr><td colspan="6">${renderer.render({entries: [deity.symbolImg]})}<div class="mb-2"/></td></tr>` : ""}
${deity.symbolImg ? `<tr><td colspan="6">${renderer.render({entries: [deity.symbolImg]})}<div class="mb-2"></div></td></tr>` : ""}
${renderStack.length ? `<tr class="text"><td class="pt-2" colspan="6">${renderStack.join("")}</td></tr>` : ""}
`;
}

View File

@@ -36,7 +36,7 @@ class RenderItems {
<td class="text-right" colspan="4">${textRight}</td>
</tr>` : `<tr><td colspan="6" class="${textRight ? "text-right" : ""}">${textLeft || textRight}</td></tr>`}
${renderedText ? `<tr><td class="divider" colspan="6"><div/></td></tr>
${renderedText ? `<tr><td class="divider" colspan="6"><div></div></td></tr>
<tr class="text"><td colspan="6">${renderedText}</td></tr>` : ""}
${Renderer.utils.getPageTr(item, {tag: "item", fnUnpackUid: (uid) => DataUtil.proxy.unpackUid("item", uid, "item")})}
${Renderer.utils.getBorderTr()}

View File

@@ -132,7 +132,7 @@ class RenderMap {
const X = 0;
const Y = 1;
const $cvs = $(`<canvas class="p-0 m-0"/>`);
const $cvs = $(`<canvas class="p-0 m-0"></canvas>`);
const cvs = $cvs[0];
cvs.width = mapData.width;
cvs.height = mapData.height;
@@ -345,16 +345,16 @@ class RenderMap {
});
});
const $btnZoomMinus = $(`<button class="btn btn-xs btn-default"><span class="glyphicon glyphicon-zoom-out"/> Zoom Out</button>`)
const $btnZoomMinus = $(`<button class="btn btn-xs btn-default"><span class="glyphicon glyphicon-zoom-out"></span> Zoom Out</button>`)
.click(() => zoomChange("out"));
const $btnZoomPlus = $(`<button class="btn btn-xs btn-default"><span class="glyphicon glyphicon-zoom-in"/> Zoom In</button>`)
const $btnZoomPlus = $(`<button class="btn btn-xs btn-default"><span class="glyphicon glyphicon-zoom-in"></span> Zoom In</button>`)
.click(() => zoomChange("in"));
const $btnZoomReset = $(`<button class="btn btn-xs btn-default" title="Reset Zoom"><span class="glyphicon glyphicon-search"/> Reset Zoom</button>`)
const $btnZoomReset = $(`<button class="btn btn-xs btn-default" title="Reset Zoom"><span class="glyphicon glyphicon-search"></span> Reset Zoom</button>`)
.click(() => zoomChange("reset"));
const $btnHelp = $(`<button class="btn btn-xs btn-default ml-auto mr-4" title="Help"><span class="glyphicon glyphicon-info-sign"/> Help</button>`)
const $btnHelp = $(`<button class="btn btn-xs btn-default ml-auto mr-4" title="Help"><span class="glyphicon glyphicon-info-sign"></span> Help</button>`)
.click(evt => {
const {$modalInner} = UiUtil.getShowModal({
title: "Help",

View File

@@ -2,15 +2,7 @@
// TODO implement remaining methods
class RendererMarkdown {
static async pInit () {
const settings = await StorageUtil.pGet("bookViewSettingsMarkdown") || Object.entries(RendererMarkdown._CONFIG).mergeMap(([k, v]) => ({[k]: v.default}));
Object.assign(RendererMarkdown, settings);
RendererMarkdown._isInit = true;
}
static checkInit () {
if (!RendererMarkdown._isInit) throw new Error(`RendererMarkdown has not been initialised!`);
}
static CHARS_PER_PAGE = 5500;
getLineBreak () { return "\n"; }
@@ -34,8 +26,6 @@ class RendererMarkdown {
set isSkipStylingItemLinks (val) { this._isSkipStylingItemLinks = val; }
static get () {
RendererMarkdown.checkInit();
return new RendererMarkdown().setFnPostProcess(RendererMarkdown._fnPostProcess);
}
@@ -639,26 +629,23 @@ class RendererMarkdown {
// region primitives
_renderString (entry, textStack, meta, options) {
switch (RendererMarkdown._tagRenderMode || 0) {
// render tags where possible
case 0: {
this._renderString_renderMode0(entry, textStack, meta, options);
switch (VetoolsConfig.get("markdown", "tagRenderMode") || "convertMarkdown") {
case "convertMarkdown": {
this._renderString_renderModeConvertMarkdown(entry, textStack, meta, options);
break;
}
// leave tags as-is
case 1: {
case "ignore": {
textStack[0] += entry;
break;
}
// strip tags
case 2: {
case "convertText": {
textStack[0] += Renderer.stripTags(entry);
break;
}
}
}
_renderString_renderMode0 (entry, textStack, meta, options) {
_renderString_renderModeConvertMarkdown (entry, textStack, meta, options) {
const tagSplit = Renderer.splitByTags(entry);
const len = tagSplit.length;
for (let i = 0; i < len; ++i) {
@@ -786,64 +773,10 @@ class RendererMarkdown {
// region Static options
static async pShowSettingsModal () {
RendererMarkdown.checkInit();
const {$modalInner} = UiUtil.getShowModal({
title: "Markdown Settings",
cbClose: () => RendererMarkdown.__$wrpSettings.detach(),
});
if (!RendererMarkdown.__$wrpSettings) {
const _compMarkdownSettings = BaseComponent.fromObject({
_tagRenderMode: RendererMarkdown._tagRenderMode,
_isAddColumnBreaks: RendererMarkdown._isAddColumnBreaks,
});
const compMarkdownSettings = _compMarkdownSettings.getPod();
const saveMarkdownSettingsDebounced = MiscUtil.debounce(() => StorageUtil.pSet("bookViewSettingsMarkdown", _compMarkdownSettings.toObject()), 100);
compMarkdownSettings.addHookAll(() => {
Object.assign(RendererMarkdown, compMarkdownSettings.getState());
saveMarkdownSettingsDebounced();
});
const $rows = Object.entries(RendererMarkdown._CONFIG)
.map(([k, v]) => {
let $ipt;
switch (v.type) {
case "boolean": {
$ipt = ComponentUiUtil.$getCbBool(_compMarkdownSettings, k).addClass("mr-1");
break;
}
case "enum": {
$ipt = ComponentUiUtil.$getSelEnum(_compMarkdownSettings, k, {values: v.values, fnDisplay: v.fnDisplay});
break;
}
default: throw new Error(`Unhandled input type!`);
}
return $$`<div class="m-1 stripe-even"><label class="split-v-center">
<div class="w-100 mr-2">${v.name}</div>
${$ipt.addClass("max-w-33")}
</label></div>`;
});
RendererMarkdown.__$wrpSettings = $$`<div class="ve-flex-v-col w-100 h-100">${$rows}</div>`;
}
RendererMarkdown.__$wrpSettings.appendTo($modalInner);
ConfigUi.show({settingsGroupIds: ["markdown"]});
}
// endregion
static getSetting (key) { return this[`_${key}`]; }
}
RendererMarkdown._isInit = false;
RendererMarkdown.CHARS_PER_PAGE = 5500;
RendererMarkdown.__$wrpSettings = null;
RendererMarkdown._TAG_RENDER_MODES = ["Convert to Markdown", "Leave As-Is", "Convert to Text"];
RendererMarkdown._CONFIG = {
_tagRenderMode: {default: 0, name: "Tag Handling (<code>@tag</code>)", fnDisplay: ix => RendererMarkdown._TAG_RENDER_MODES[ix], type: "enum", values: [0, 1, 2]},
_isAddColumnBreaks: {default: false, name: "Add GM Binder Column Breaks (<code>\\columnbreak</code>)", type: "boolean"},
_isAddPageBreaks: {default: false, name: "Add GM Binder Page Breaks (<code>\\pagebreak</code>)", type: "boolean"},
};
if (typeof window !== "undefined") window.addEventListener("load", () => RendererMarkdown.pInit());
RendererMarkdown.utils = class {
static getPageText (it) {
@@ -964,7 +897,7 @@ ${mon.pbNote || Parser.crToNumber(mon.cr) < VeCt.CR_CUSTOM ? `>- **Proficiency B
let breakablePart = `${traitsPart}${actionsPart}${bonusActionsPart}${reactionsPart}${legendaryActionsPart}${mythicActionsPart}${legendaryGroupLairPart}${legendaryGroupRegionalPart}${footerPart}`;
if (RendererMarkdown.getSetting("isAddColumnBreaks")) {
if (VetoolsConfig.get("markdown", "isAddColumnBreaks")) {
let charAllowanceFirstCol = 2200 - unbreakablePart.length;
const breakableLines = breakablePart.split("\n");
@@ -1102,7 +1035,7 @@ ${mon.pbNote || Parser.crToNumber(mon.cr) < VeCt.CR_CUSTOM ? `>- **Proficiency B
const out = [monEntry];
const isAddPageBreaks = RendererMarkdown.getSetting("isAddPageBreaks");
const isAddPageBreaks = VetoolsConfig.get("markdown", "isAddPageBreaks");
if (fluffText) {
// Insert a page break before every fluff section
if (isAddPageBreaks) out.push("", "\\pagebreak", "");

View File

@@ -3143,21 +3143,29 @@ Renderer.utils = class {
return fluff;
}
static async _pGetFluff ({entity, fluffProp} = {}) {
const fluffEntity = await DataLoader.pCacheAndGet(fluffProp, entity.source, UrlUtil.URL_TO_HASH_BUILDER[fluffProp](entity));
static async _pGetFluff ({entity, fluffProp, lockToken2} = {}) {
const fluffEntity = await DataLoader.pCacheAndGet(fluffProp, entity.source, UrlUtil.URL_TO_HASH_BUILDER[fluffProp](entity), {lockToken2});
if (fluffEntity) return fluffEntity;
if (entity._versionBase_name && entity._versionBase_source) {
return DataLoader.pCacheAndGet(fluffProp, entity.source, UrlUtil.URL_TO_HASH_BUILDER[fluffProp]({
name: entity._versionBase_name,
source: entity._versionBase_source,
}));
return DataLoader.pCacheAndGet(
fluffProp,
entity.source,
UrlUtil.URL_TO_HASH_BUILDER[fluffProp]({
name: entity._versionBase_name,
source: entity._versionBase_source,
}),
{
lockToken2,
},
);
}
return null;
}
static async pGetFluff ({entity, pFnPostProcess, fluffProp} = {}) {
// TODO(Future) move into `DataLoader`; cleanup `lockToken2` usage
static async pGetFluff ({entity, pFnPostProcess, fluffProp, lockToken2 = null} = {}) {
const predefinedFluff = await Renderer.utils.pGetPredefinedFluff(entity, fluffProp);
if (predefinedFluff) {
if (pFnPostProcess) return pFnPostProcess(predefinedFluff);
@@ -6430,16 +6438,16 @@ Renderer.race = class {
opts = opts || {};
const out = [];
races.forEach(r => {
races.forEach(race => {
// FIXME(Deprecated) Backwards compatibility for old race data; remove at some point
if (r.size && typeof r.size === "string") r.size = [r.size];
if (race.size && typeof race.size === "string") race.size = [race.size];
// Ignore `"lineage": true`, as it is only used for filters
if (r.lineage && r.lineage !== true) {
r = MiscUtil.copyFast(r);
if (race.lineage && race.lineage !== true) {
race = MiscUtil.copyFast(race);
if (r.lineage === "VRGR") {
r.ability = r.ability || [
if (race.lineage === "VRGR") {
race.ability = race.ability || [
{
choose: {
weighted: {
@@ -6457,8 +6465,8 @@ Renderer.race = class {
},
},
];
} else if (r.lineage === "UA1") {
r.ability = r.ability || [
} else if (race.lineage === "UA1") {
race.ability = race.ability || [
{
choose: {
weighted: {
@@ -6470,60 +6478,60 @@ Renderer.race = class {
];
}
r.entries = r.entries || [];
r.entries.push({
race.entries = race.entries || [];
race.entries.push({
type: "entries",
name: "Languages",
entries: ["You can speak, read, and write Common and one other language that you and your DM agree is appropriate for your character."],
});
r.languageProficiencies = r.languageProficiencies || [{"common": true, "anyStandard": 1}];
race.languageProficiencies = race.languageProficiencies || [{"common": true, "anyStandard": 1}];
}
if (r.subraces && !r.subraces.length) delete r.subraces;
if (race.subraces && !race.subraces.length) delete race.subraces;
if (r.subraces) {
r.subraces.forEach(sr => {
sr.source = sr.source || r.source;
if (race.subraces) {
race.subraces.forEach(sr => {
sr.source = sr.source || race.source;
sr._isSubRace = true;
});
r.subraces.sort((a, b) => SortUtil.ascSortLower(a.name || "_", b.name || "_") || SortUtil.ascSortLower(Parser.sourceJsonToAbv(a.source), Parser.sourceJsonToAbv(b.source)));
race.subraces.sort((a, b) => SortUtil.ascSortLower(a.name || "_", b.name || "_") || SortUtil.ascSortLower(Parser.sourceJsonToAbv(a.source), Parser.sourceJsonToAbv(b.source)));
}
if (opts.isAddBaseRaces && r.subraces) {
const baseRace = MiscUtil.copyFast(r);
if (opts.isAddBaseRaces && race.subraces) {
const baseRace = MiscUtil.copyFast(race);
baseRace._isBaseRace = true;
const isAnyNoName = r.subraces.some(it => !it.name);
const isAnyNoName = race.subraces.some(it => !it.name);
if (isAnyNoName) {
baseRace._rawName = baseRace.name;
baseRace.name = `${baseRace.name} (Base)`;
}
const nameCounts = {};
r.subraces.filter(sr => sr.name).forEach(sr => nameCounts[sr.name.toLowerCase()] = (nameCounts[sr.name.toLowerCase()] || 0) + 1);
nameCounts._ = r.subraces.filter(sr => !sr.name).length;
race.subraces.filter(sr => sr.name).forEach(sr => nameCounts[sr.name.toLowerCase()] = (nameCounts[sr.name.toLowerCase()] || 0) + 1);
nameCounts._ = race.subraces.filter(sr => !sr.name).length;
const lst = {
type: "list",
items: r.subraces.map(sr => {
items: race.subraces.map(sr => {
const count = nameCounts[(sr.name || "_").toLowerCase()];
const idName = Renderer.race.getSubraceName(r.name, sr.name);
const idName = Renderer.race.getSubraceName(race.name, sr.name);
return `{@race ${idName}|${sr.source}${count > 1 ? `|${idName} (<span title="${Parser.sourceJsonToFull(sr.source).escapeQuotes()}">${Parser.sourceJsonToAbv(sr.source)}</span>)` : ""}}`;
}),
};
Renderer.race._mutBaseRaceEntries(baseRace, lst);
baseRace._subraces = r.subraces.map(sr => ({name: Renderer.race.getSubraceName(r.name, sr.name), source: sr.source}));
baseRace._subraces = race.subraces.map(sr => ({name: Renderer.race.getSubraceName(race.name, sr.name), source: sr.source}));
delete baseRace.subraces;
out.push(baseRace);
}
out.push(...Renderer.race._mergeSubraces(r));
out.push(...Renderer.race._mergeSubraces(race));
});
return out;
@@ -8954,6 +8962,10 @@ Renderer.item = class {
Renderer.item._createSpecificVariants_mergeVulnerableResistImmune({specificVariant, inherits});
// Inherit fluff
if (genericVariant.hasFluff) specificVariant.hasFluff = genericVariant.hasFluff;
if (genericVariant.hasFluffImages) specificVariant.hasFluffImages = genericVariant.hasFluffImages;
// track the specific variant on the parent generic, to later render as part of the stats
genericVariant.variants = genericVariant.variants || [];
if (!genericVariant.variants.some(it => it.base?.name === baseItem.name && it.base?.source === baseItem.source)) genericVariant.variants.push({base: baseItem, specificVariant});
@@ -9460,11 +9472,20 @@ Renderer.item = class {
return false;
}
static pGetFluff (item) {
return Renderer.utils.pGetFluff({
static async pGetFluff (item) {
const fluffItem = await Renderer.utils.pGetFluff({
entity: item,
fluffProp: "itemFluff",
});
if (fluffItem) return fluffItem;
if (!item._variantName) return null;
// Inherit generic variant fluff
return Renderer.utils.pGetFluff({
entity: {name: item._variantName, source: item.source},
fluffProp: "itemFluff",
});
}
};
@@ -10981,6 +11002,7 @@ Renderer.generic = class {
skillToolLanguageProfs,
setValid: new Set(this.FEATURE__SKILLS_ALL),
setValidAny: this._SKILL_TOOL_LANGUAGE_KEYS__SKILL_ANY,
anyAlt: "anySkill",
isShort,
hoverTag: "skill",
});
@@ -10992,6 +11014,7 @@ Renderer.generic = class {
skillToolLanguageProfs,
setValid: new Set(this.FEATURE__TOOLS_ALL),
setValidAny: this._SKILL_TOOL_LANGUAGE_KEYS__TOOL_ANY,
anyAlt: "anyTool",
isShort,
});
}
@@ -11002,11 +11025,12 @@ Renderer.generic = class {
skillToolLanguageProfs,
setValid: new Set(this.FEATURE__LANGUAGES_ALL),
setValidAny: this._SKILL_TOOL_LANGUAGE_KEYS__LANGAUGE_ANY,
anyAlt: "anyLanguage",
isShort,
});
}
static _summariseProfs ({profGroupArr, skillToolLanguageProfs, setValid, setValidAny, isShort, hoverTag}) {
static _summariseProfs ({profGroupArr, skillToolLanguageProfs, setValid, setValidAny, anyAlt, isShort, hoverTag}) {
if (!profGroupArr?.length && !skillToolLanguageProfs?.length) return {summary: "", collection: []};
const collectionSet = new Set();
@@ -11026,13 +11050,13 @@ Renderer.generic = class {
const chooseProfs = vMapped.from
.filter(s => !isValidate || setValid.has(s))
.map(s => {
collectionSet.add(s);
collectionSet.add(this._summariseProfs_getCollectionKey(s, anyAlt));
return this._summariseProfs_getEntry({str: s, isShort, hoverTag});
});
return `${isShort ? `${i === 0 ? "C" : "c"}hoose ` : ""}${v.count || 1} ${isShort ? `of` : `from`} ${chooseProfs.joinConjunct(", ", " or ")}`;
}
collectionSet.add(k);
collectionSet.add(this._summariseProfs_getCollectionKey(k, anyAlt));
return this._summariseProfs_getEntry({str: k, isShort, hoverTag});
});
@@ -11052,6 +11076,10 @@ Renderer.generic = class {
return {summary, collection: [...collectionSet].sort(SortUtil.ascSortLower)};
}
static _summariseProfs_getCollectionKey (k, anyAlt) {
return k === anyAlt ? "any" : k;
}
static _summariseProfs_sortKeys (a, b, {setValidAny = null} = {}) {
if (a === b) return 0;
if (a === "choose") return 2;

View File

@@ -204,9 +204,12 @@ class StatGenUi extends BaseComponent {
};
}
_roll_getRolledStats () {
async _roll_pGetRolledStats () {
const wrpTree = Renderer.dice.lang.getTree3(this._state.rolled_formula);
if (!wrpTree) return this._$rollIptFormula.addClass("form-control--error");
if (!wrpTree) {
this._$rollIptFormula.addClass("form-control--error");
return;
}
const rolls = [];
for (let i = 0; i < this._state.rolled_rollCount; i++) {
@@ -287,9 +290,15 @@ class StatGenUi extends BaseComponent {
})
.change(() => this._$rollIptFormula.removeClass("form-control--error"));
const lockRoll = new VeLock();
const $btnRoll = $(`<button class="btn btn-primary bold">Roll</button>`)
.click(() => {
this._state.rolled_rolls = this._roll_getRolledStats();
.click(async () => {
try {
await lockRoll.pLock();
this._state.rolled_rolls = await this._roll_pGetRolledStats();
} finally {
lockRoll.unlock();
}
});
const $btnRandom = $(`<button class="btn btn-xs btn-default mt-2">Randomly Assign</button>`)
@@ -723,7 +732,7 @@ class StatGenUi extends BaseComponent {
};
this._proxyAssignSimple("state", nxtState);
});
$(`<option/>`, {value: -1, text: "\u2014"}).appendTo($selRolled);
$(`<option></option>`, {value: -1, text: "\u2014"}).appendTo($selRolled);
let $optionsRolled = [];
const hkRolls = () => {
@@ -731,7 +740,7 @@ class StatGenUi extends BaseComponent {
this._state.rolled_rolls.forEach((it, i) => {
const cntPrevRolls = this._state.rolled_rolls.slice(0, i).filter(r => r.total === it.total).length;
const $opt = $(`<option/>`, {value: i, text: `${it.total}${cntPrevRolls ? Parser.numberToSubscript(cntPrevRolls) : ""}`}).appendTo($selRolled);
const $opt = $(`<option></option>`, {value: i, text: `${it.total}${cntPrevRolls ? Parser.numberToSubscript(cntPrevRolls) : ""}`}).appendTo($selRolled);
$optionsRolled.push($opt);
});
@@ -769,9 +778,9 @@ class StatGenUi extends BaseComponent {
};
this._proxyAssignSimple("state", nxtState);
});
$(`<option/>`, {value: -1, text: "\u2014"}).appendTo($selArray);
$(`<option></option>`, {value: -1, text: "\u2014"}).appendTo($selArray);
StatGenUi._STANDARD_ARRAY.forEach((it, i) => $(`<option/>`, {value: i, text: it}).appendTo($selArray));
StatGenUi._STANDARD_ARRAY.forEach((it, i) => $(`<option></option>`, {value: i, text: it}).appendTo($selArray));
const hookIxArray = () => {
const ix = this._state[propAbilSelectedScoreIx] == null ? -1 : this._state[propAbilSelectedScoreIx];
@@ -972,7 +981,7 @@ class StatGenUi extends BaseComponent {
this._parent._addHookBase(this._propIxAbilityScoreSet, hkIxEntity);
hkIxEntity();
const {$wrp: $selEntity, fnUpdateHidden: fnUpdateSelEntityHidden} = ComponentUiUtil.$getSelSearchable(
const {$wrp: $selEntity, setFnFilter: setFnFilterEntity} = ComponentUiUtil.$getSelSearchable(
this._parent,
this._propIxEntity,
{
@@ -989,8 +998,12 @@ class StatGenUi extends BaseComponent {
const doApplyFilterToSelEntity = () => {
const f = this._parent[this._propModalFilter].pageFilter.filterBox.getValues();
const isHiddenPerEntity = this._parent[this._propData].map(it => !this._parent[this._propModalFilter].pageFilter.toDisplay(f, it));
fnUpdateSelEntityHidden(isHiddenPerEntity, false);
setFnFilterEntity(value => {
if (value == null) return true;
const ent = this._parent[this._propData][value];
return this._parent[this._propModalFilter].pageFilter.toDisplay(f, ent);
});
};
this._parent[this._propModalFilter].pageFilter.filterBox.on(FilterBox.EVNT_VALCHANGE, () => doApplyFilterToSelEntity());
@@ -1041,9 +1054,14 @@ class StatGenUi extends BaseComponent {
const hkSetValuesSelAbilitySet = () => {
const entity = this._parent[this._propEntity];
$stgAbilityScoreSet.toggleVe(!!entity && entity.ability?.length > 1);
// Set to empty array between real sets, as otherwise two matching sets of list indices
// will be considered "the same list," even though their display will ultimately be different.
// Using a blank list here forces any real list to cause a refresh.
setValuesSelAbilitySet([]);
setValuesSelAbilitySet(
[...new Array(entity?.ability?.length || 0)].map((_, ix) => ix),
{isForce: true},
);
};
this._parent._addHookBase(this._propIxEntity, hkSetValuesSelAbilitySet);

View File

@@ -1,6 +1,77 @@
"use strict";
class StyleSwitcher {
static _STORAGE_DAY_NIGHT = "StyleSwitcher_style";
static _STORAGE_IS_MANUAL_MODE = "StyleSwitcher_style-is-manual-mode";
static _STORAGE_WIDE = "StyleSwitcher_style-wide";
static _STYLE_DAY = "day";
static _STYLE_NIGHT = "night";
static _STYLE_NIGHT_ALT = "nightAlt";
static _STYLE_NIGHT_CLEAN = "nightClean";
static _NIGHT_CLASS = "ve-night-mode";
static _NIGHT_CLASS_STANDARD = "ve-night-mode--standard";
static _NIGHT_CLASS_ALT = "ve-night-mode--classic";
static _NIGHT_CLASS_CLEAN = "ve-night-mode--clean";
static _WIDE_ID = "style-switch__wide";
static _STYLES = [
this._STYLE_DAY,
this._STYLE_NIGHT,
this._STYLE_NIGHT_ALT,
this._STYLE_NIGHT_CLEAN,
];
static _STYLE_TO_DISPLAY_NAME = {
[this._STYLE_DAY]: "Day Mode",
[this._STYLE_NIGHT]: "Night Mode",
[this._STYLE_NIGHT_ALT]: "Night Mode (Classic)",
[this._STYLE_NIGHT_CLEAN]: "Night Mode (Clean)",
};
static _STYLE_CLASSES = [
this._NIGHT_CLASS,
this._NIGHT_CLASS_STANDARD,
this._NIGHT_CLASS_ALT,
this._NIGHT_CLASS_CLEAN,
];
/* -------------------------------------------- */
static getSelStyle () {
const selStyle = e_({
tag: "select",
clazz: "form-control input-xs",
children: Object.entries(this._STYLE_TO_DISPLAY_NAME)
.map(([id, name]) => ee`<option value="${id}">${name}</option>`),
change: () => {
styleSwitcher._setActiveDayNight(selStyle.val());
StyleSwitcher.storage.setItem(StyleSwitcher._STORAGE_IS_MANUAL_MODE, true);
},
})
.val(styleSwitcher.currentStylesheet);
return selStyle;
}
/* -------------------------------------------- */
static getCbWide () {
const cbWide = e_({
tag: "input",
type: "checkbox",
change: () => {
styleSwitcher._setActiveWide(cbWide.checked);
},
});
return cbWide;
}
/* -------------------------------------------- */
constructor () {
this.currentStylesheet = StyleSwitcher._STYLE_DAY;
@@ -30,15 +101,16 @@ class StyleSwitcher {
_setActiveDayNight (style) {
this.currentStylesheet = style;
this.constructor._STYLE_CLASSES
.forEach(clazzName => document.documentElement.classList.remove(clazzName));
switch (style) {
case StyleSwitcher._STYLE_DAY: {
document.documentElement.classList.remove(StyleSwitcher._NIGHT_CLASS);
document.documentElement.classList.remove(StyleSwitcher._NIGHT_CLASS_ALT);
break;
}
case StyleSwitcher._STYLE_NIGHT: {
document.documentElement.classList.add(StyleSwitcher._NIGHT_CLASS);
document.documentElement.classList.remove(StyleSwitcher._NIGHT_CLASS_ALT);
document.documentElement.classList.add(StyleSwitcher._NIGHT_CLASS_STANDARD);
break;
}
case StyleSwitcher._STYLE_NIGHT_ALT: {
@@ -46,10 +118,13 @@ class StyleSwitcher {
document.documentElement.classList.add(StyleSwitcher._NIGHT_CLASS_ALT);
break;
}
case StyleSwitcher._STYLE_NIGHT_CLEAN: {
document.documentElement.classList.add(StyleSwitcher._NIGHT_CLASS);
document.documentElement.classList.add(StyleSwitcher._NIGHT_CLASS_CLEAN);
break;
}
}
StyleSwitcher._setButtonText("nightModeToggle", this.getDayNightButtonText(style));
StyleSwitcher.storage.setItem(StyleSwitcher._STORAGE_DAY_NIGHT, this.currentStylesheet);
this._fnsOnChange.forEach(fn => fn());
@@ -58,16 +133,9 @@ class StyleSwitcher {
getDayNightClassNames () {
switch (this.currentStylesheet) {
case StyleSwitcher._STYLE_DAY: return "";
case StyleSwitcher._STYLE_NIGHT: return StyleSwitcher._NIGHT_CLASS;
case StyleSwitcher._STYLE_NIGHT: return [StyleSwitcher._NIGHT_CLASS, StyleSwitcher._NIGHT_CLASS_STANDARD].join(" ");
case StyleSwitcher._STYLE_NIGHT_ALT: return [StyleSwitcher._NIGHT_CLASS, StyleSwitcher._NIGHT_CLASS_ALT].join(" ");
}
}
getDayNightButtonText () {
switch (this.currentStylesheet) {
case StyleSwitcher._STYLE_NIGHT_ALT: return "Day Mode";
case StyleSwitcher._STYLE_DAY: return "Night Mode";
case StyleSwitcher._STYLE_NIGHT: return "Night Mode (Alt)";
case StyleSwitcher._STYLE_NIGHT_CLEAN: return [StyleSwitcher._NIGHT_CLASS, StyleSwitcher._NIGHT_CLASS_CLEAN].join(" ");
}
}
@@ -77,9 +145,14 @@ class StyleSwitcher {
}
cycleDayNightMode (direction) {
const newStyle = direction === -1
? this.currentStylesheet === StyleSwitcher._STYLE_DAY ? StyleSwitcher._STYLE_NIGHT_ALT : this.currentStylesheet === StyleSwitcher._STYLE_NIGHT ? StyleSwitcher._STYLE_DAY : StyleSwitcher._STYLE_NIGHT
: this.currentStylesheet === StyleSwitcher._STYLE_DAY ? StyleSwitcher._STYLE_NIGHT : this.currentStylesheet === StyleSwitcher._STYLE_NIGHT ? StyleSwitcher._STYLE_NIGHT_ALT : StyleSwitcher._STYLE_DAY;
const ixCur = this.constructor._STYLES.indexOf(this.currentStylesheet);
const ixNxt = ixCur === 0
? this.constructor._STYLES.length - 1
: ixCur === this.constructor._STYLES.length - 1
? 0
: ixCur + direction;
const newStyle = this.constructor._STYLES[ixNxt];
this._setActiveDayNight(newStyle);
StyleSwitcher.storage.setItem(StyleSwitcher._STORAGE_IS_MANUAL_MODE, true);
}
@@ -143,15 +216,6 @@ class StyleSwitcher {
getActiveWide () { return document.getElementById(StyleSwitcher._WIDE_ID) != null; }
// endregion
}
StyleSwitcher._STORAGE_DAY_NIGHT = "StyleSwitcher_style";
StyleSwitcher._STORAGE_IS_MANUAL_MODE = "StyleSwitcher_style-is-manual-mode";
StyleSwitcher._STORAGE_WIDE = "StyleSwitcher_style-wide";
StyleSwitcher._STYLE_DAY = "day";
StyleSwitcher._STYLE_NIGHT = "night";
StyleSwitcher._STYLE_NIGHT_ALT = "nightAlt";
StyleSwitcher._NIGHT_CLASS = "ve-night-mode";
StyleSwitcher._NIGHT_CLASS_ALT = "ve-night-mode--alt";
StyleSwitcher._WIDE_ID = "style-switch__wide";
try {
StyleSwitcher.storage = window.localStorage;

5
js/utils-config.js Normal file
View File

@@ -0,0 +1,5 @@
import {VetoolsConfig} from "./utils-config/utils-config-config.js";
import {ConfigUi} from "./utils-config/utils-config-ui.js";
globalThis.VetoolsConfig = VetoolsConfig;
globalThis.ConfigUi = ConfigUi;

View File

@@ -0,0 +1,10 @@
export class UtilConfigHelpers {
static packSettingId (groupId, configId) {
return `${groupId}.${configId}`;
}
static unpackSettingId (settingId) {
const [groupId, configId] = settingId.split(".");
return {groupId, configId};
}
}

View File

@@ -0,0 +1,38 @@
export class ConfigSettingsGroup {
constructor (
{
groupId,
name,
configSettings,
},
) {
this._groupId = groupId;
this._name = name;
this._configSettings = configSettings;
this._configSettings
.forEach(configSetting => configSetting.setGroupId(this._groupId));
}
get groupId () { return this._groupId; }
render (rdState, {isLast = false} = {}) {
const wrpRows = ee`<div></div>`;
ee`<div class="w-100">
<h4>${this._name}</h4>
${wrpRows}
${isLast ? null : `<hr class="hr-3 mb-1">`}
</div>`
.appendTo(rdState.wrp);
this._configSettings
.forEach(configSetting => configSetting.render(rdState, wrpRows));
}
mutDefaults (config) {
const group = config[this._groupId] ||= {};
this._configSettings
.forEach(configSetting => configSetting.mutDefaults(group));
}
}

View File

@@ -0,0 +1,66 @@
import {SETTINGS_GROUPS} from "./utils-config-registry.js";
import {UtilConfigHelpers} from "./util-config-helpers.js";
export class VetoolsConfig {
static _STORAGE_KEY = "config";
static _CONFIG = null;
static _init () {
if (this._CONFIG) return;
this._CONFIG = StorageUtil.syncGet(this._STORAGE_KEY) || {};
SETTINGS_GROUPS
.forEach(settingsGroup => settingsGroup.mutDefaults(this._CONFIG));
}
/* -------------------------------------------- */
static get (groupId, configId) {
this._init();
return MiscUtil.get(this._CONFIG, groupId, configId);
}
static set (groupId, configId, val) {
this._init();
MiscUtil.set(this._CONFIG, groupId, configId, val);
this._save();
}
/* -------------------------------------------- */
static _save () {
StorageUtil.syncSet(this._STORAGE_KEY, this._CONFIG);
}
static _saveThrottled = MiscUtil.throttle(this._save.bind(this), 50);
/* -------------------------------------------- */
static getConfigComp () {
this._init();
const state = {};
Object.entries(this._CONFIG)
.forEach(([groupId, groupTo]) => {
Object.entries(groupTo)
.forEach(([configId, val]) => {
state[UtilConfigHelpers.packSettingId(groupId, configId)] = MiscUtil.copyFast(val);
});
});
const comp = BaseComponent.fromObject(state, "*");
comp._addHookAllBase(() => {
Object.entries(comp._state)
.forEach(([settingId, v]) => {
const {groupId, configId} = UtilConfigHelpers.unpackSettingId(settingId);
MiscUtil.set(this._CONFIG, groupId, configId, v);
});
this._saveThrottled();
});
return comp;
}
}

View File

@@ -0,0 +1,74 @@
import {ConfigSettingsGroup} from "./util-config-settings-group.js";
import {ConfigSettingBoolean, ConfigSettingEnum, ConfigSettingExternal} from "./utils-config-setting-base.js";
const settingsGroupStyleSwitcher = new ConfigSettingsGroup({
groupId: "styleSwitcher",
name: "Appearance",
configSettings: [
new (
class extends ConfigSettingExternal {
_configId = "theme";
_name = "Theme";
_help = "The color theme to be applied.";
_isRowLabel = true;
_getEleExternal () { return StyleSwitcher.getSelStyle(); }
}
)(),
new (
class extends ConfigSettingExternal {
_configId = "isWideMode";
_name = "Wide Mode (Experimental)";
_help = "This feature is unsupported. Expect bugs.";
_isRowLabel = true;
_getEleExternal () { return StyleSwitcher.getCbWide(); }
}
)(),
],
});
const _MARKDOWN_TAG_RENDER_MODES = {
"convertMarkdown": "Convert to Markdown",
"ignore": "Leave As-Is",
"convertText": "Convert to Text",
};
const settingsGroupMarkdown = new ConfigSettingsGroup({
groupId: "markdown",
name: "Markdown",
configSettings: [
new ConfigSettingEnum({
configId: "tagRenderMode",
name: `Tag Handling (<code>@tag</code>)`,
help: `THe output to produce when rendering a 5etools "@tag".`,
isRowLabel: true,
default: "convertMarkdown",
values: [
"convertMarkdown",
"ignore",
"convertText",
],
fnDisplay: it => _MARKDOWN_TAG_RENDER_MODES[it] || it,
}),
new ConfigSettingBoolean({
configId: "isAddColumnBreaks",
name: `Add GM Binder Column Breaks (<code>\\\\columnbreak</code>)`,
help: `If "\\\\columnbreak"s should be added to exported Markdown, at an approximate column breakpoint.`,
isRowLabel: true,
default: false,
}),
new ConfigSettingBoolean({
configId: "isAddPageBreaks",
name: `Add GM Binder Page Breaks (<code>\\\\pagebreak</code>)`,
help: `If "\\\\pagebreak"s should be added to exported Markdown, at an approximate page breakpoint.`,
isRowLabel: true,
default: false,
}),
],
});
export const SETTINGS_GROUPS = [
settingsGroupStyleSwitcher,
settingsGroupMarkdown,
];

View File

@@ -0,0 +1,118 @@
import {UtilConfigHelpers} from "./util-config-helpers.js";
// TODO rename this file
/** @abstract */
class _ConfigSettingBase {
_groupId;
_configId;
_name;
_help;
_isRowLabel = false;
constructor (
{
configId,
name,
help,
isRowLabel,
} = {},
) {
this._configId = configId;
this._name = name;
this._help = help;
this._isRowLabel = isRowLabel;
}
setGroupId (groupId) { this._groupId = groupId; }
/* -------------------------------------------- */
render (rdState, wrpRows) {
const tag = this._isRowLabel ? "label" : "div";
ee`<${tag} class="py-1 w-100 split-v-center" title="${this._help.qq()}">
${this._renderLabel(rdState)}
${this._renderUi(rdState)}
</${tag}>`
.appendTo(wrpRows);
}
_renderLabel (rdState) {
return `<div class="w-66 no-shrink mr-2">${this._name}</div>`;
}
/**
* @abstract
* @return {HTMLElementModified}
*/
_renderUi (rdState) { throw new Error("Unimplemented!"); }
/* -------------------------------------------- */
/** @abstract */
mutDefaults (group) {
throw new Error("Unimplemented!");
}
}
/** @abstract */
export class ConfigSettingExternal extends _ConfigSettingBase {
_renderUi (rdState) { return this._getEleExternal(); }
/**
* @abstract
* @return {HTMLElementModified}
*/
_getEleExternal () { throw new Error("Unimplemented!"); }
mutDefaults (group) { /* No-op */ }
}
/** @abstract */
class _ConfigSettingStandardBase extends _ConfigSettingBase {
_default;
constructor (opts) {
super(opts);
this._default = opts.default;
}
mutDefaults (group) {
if (group[this._configId] !== undefined) return;
group[this._configId] = this._default;
}
}
export class ConfigSettingBoolean extends _ConfigSettingStandardBase {
_renderUi (rdState) {
const prop = UtilConfigHelpers.packSettingId(this._groupId, this._configId);
return ComponentUiUtil.getCbBool(rdState.comp, prop);
}
}
export class ConfigSettingEnum extends _ConfigSettingStandardBase {
_values;
_fnDisplay;
constructor ({values, fnDisplay, ...rest}) {
super(rest);
this._values = values;
this._fnDisplay = fnDisplay;
}
_renderUi (rdState) {
const prop = UtilConfigHelpers.packSettingId(this._groupId, this._configId);
return ComponentUiUtil.getSelEnum(
rdState.comp,
prop,
{
values: this._values,
fnDisplay: this._fnDisplay,
},
);
}
}

View File

@@ -0,0 +1,79 @@
import {VetoolsConfig} from "./utils-config-config.js";
import {SETTINGS_GROUPS} from "./utils-config-registry.js";
class _ConfigRenderState {
wrp;
comp;
constructor (
{
wrp,
comp,
},
) {
this.wrp = wrp;
this.comp = comp;
}
}
export class ConfigUi {
constructor (
{
settingsGroups,
},
) {
this._settingsGroups = settingsGroups;
}
render (wrp) {
const rdState = new _ConfigRenderState({
wrp,
comp: VetoolsConfig.getConfigComp(),
});
this._settingsGroups
.forEach((configSection, i, arr) => {
configSection.render(rdState, {isLast: i === arr.length - 1});
});
}
/* -------------------------------------------- */
/**
* @param {?string[]} settingsGroupIds Subset of group IDs to display
*/
static show (
{
settingsGroupIds = null,
} = {},
) {
const settingsGroups = settingsGroupIds
? SETTINGS_GROUPS
.filter(group => settingsGroupIds.includes(group.groupId))
: SETTINGS_GROUPS;
const ui = new this({
settingsGroups,
});
const {$modalInner, $modalFooter, doClose} = UiUtil.getShowModal({
isUncappedWidth: true,
isUncappedHeight: true,
title: "Preferences",
headerType: 3,
isHeaderBorder: true,
overlayColor: "transparent",
hasFooter: true,
});
ui.render($modalInner[0]);
const btnClose = ee`<button class="btn btn-default btn-sm ml-auto">Close</button>`
.onn("click", () => doClose());
ee`<div class="py-1 w-100 ve-flex-v-center">
${btnClose}
</div>`
.appendTo($modalFooter[0]);
}
}

View File

@@ -988,13 +988,6 @@ class _DataTypeLoaderLanguage extends _DataTypeLoaderPredefined {
_loader = "language";
}
class _DataTypeLoaderRecipe extends _DataTypeLoaderPredefined {
static PROPS = ["recipe"];
static PAGE = UrlUtil.PG_RECIPES;
_loader = "recipe";
}
class _DataTypeLoaderMultiSource extends _DataTypeLoader {
_prop;
@@ -1452,6 +1445,59 @@ class _DataTypeLoaderCustomDeck extends _DataTypeLoaderCustomRawable {
}
}
class _DataTypeLoaderRecipe extends _DataTypeLoaderCustomRawable {
static PROPS = ["raw_recipe", "recipe"];
static PAGE = UrlUtil.PG_RECIPES;
static _PROPS_RAWABLE = ["recipe"];
async _pGetRawSiteData () { return DataUtil.recipe.loadRawJSON(); }
async _pGetPostCacheData_obj ({obj, lockToken2}) {
if (!obj) return null;
const out = {};
if (obj.raw_recipe?.length) out.recipe = await obj.raw_recipe.pSerialAwaitMap(ent => this.constructor._pGetDereferencedRecipeData(ent, {lockToken2}));
return out;
}
static async _pGetDereferencedRecipeData (recipe, {lockToken2}) {
recipe = MiscUtil.copyFast(recipe);
Renderer.recipe.populateFullIngredients(recipe);
const fluff = await this._pGetDereferencedFluffData(recipe, {lockToken2});
if (fluff) recipe.fluff = fluff;
return recipe;
}
static async _pGetDereferencedFluffData (recipe, {lockToken2}) {
const fluff = await Renderer.utils.pGetFluff({
entity: recipe,
fluffProp: "recipeFluff",
lockToken2,
});
if (!fluff) return null;
const cpyFluff = MiscUtil.copyFast(fluff);
delete cpyFluff.name;
delete cpyFluff.source;
return cpyFluff;
}
async pGetPostCacheData ({siteData = null, prereleaseData = null, brewData = null, lockToken2}) {
return {
siteDataPostCache: await this._pGetPostCacheData_obj_withCache({obj: siteData, lockToken2, propCache: "site"}),
prereleaseDataPostCache: await this._pGetPostCacheData_obj({obj: prereleaseData, lockToken2}),
brewDataPostCache: await this._pGetPostCacheData_obj({obj: brewData, lockToken2}),
};
}
}
class _DataTypeLoaderCustomQuickref extends _DataTypeLoader {
static PROPS = ["reference", "referenceData"];
static PAGE = UrlUtil.PG_QUICKREF;

View File

@@ -1,6 +1,151 @@
"use strict";
function getFnListSort (prop) {
switch (prop) {
case "spell":
case "roll20Spell":
case "foundrySpell":
case "spellList":
case "monster":
case "foundryMonster":
case "monsterFluff":
case "monsterTemplate":
case "makebrewCreatureTrait":
case "makebrewCreatureAction":
case "action":
case "foundryAction":
case "background":
case "legendaryGroup":
case "language":
case "languageScript":
case "name":
case "condition":
case "disease":
case "status":
case "cult":
case "boon":
case "feat":
case "foundryFeat":
case "vehicle":
case "vehicleUpgrade":
case "foundryVehicleUpgrade":
case "backgroundFluff":
case "featFluff":
case "optionalfeatureFluff":
case "conditionFluff":
case "spellFluff":
case "itemFluff":
case "languageFluff":
case "vehicleFluff":
case "objectFluff":
case "raceFluff":
case "item":
case "foundryItem":
case "baseitem":
case "magicvariant":
case "foundryMagicvariant":
case "itemGroup":
case "itemMastery":
case "object":
case "optionalfeature":
case "foundryOptionalfeature":
case "psionic":
case "reward":
case "foundryReward":
case "rewardFluff":
case "variantrule":
case "race":
case "foundryRace":
case "foundryRaceFeature":
case "table":
case "trap":
case "trapFluff":
case "hazard":
case "hazardFluff":
case "charoption":
case "charoptionFluff":
case "recipe":
case "recipeFluff":
case "sense":
case "skill":
case "deck":
case "citation":
case "foundryMap":
return SortUtil.ascSortGenericEntity.bind(SortUtil);
case "deity":
return SortUtil.ascSortDeity.bind(SortUtil);
case "card":
return SortUtil.ascSortCard.bind(SortUtil);
case "class":
case "classFluff":
case "foundryClass":
return (a, b) => SortUtil.ascSortDateString(Parser.sourceJsonToDate(b.source), Parser.sourceJsonToDate(a.source)) || SortUtil.ascSortLower(a.name, b.name) || SortUtil.ascSortLower(a.source, b.source);
case "subclass":
case "subclassFluff":
case "foundrySubclass":
return (a, b) => SortUtil.ascSortDateString(Parser.sourceJsonToDate(b.source), Parser.sourceJsonToDate(a.source)) || SortUtil.ascSortLower(a.name, b.name);
case "classFeature":
case "foundryClassFeature":
return (a, b) => SortUtil.ascSortLower(a.classSource, b.classSource)
|| SortUtil.ascSortLower(a.className, b.className)
|| SortUtil.ascSort(a.level, b.level)
|| SortUtil.ascSortGenericEntity(a, b);
case "subclassFeature":
case "foundrySubclassFeature":
return (a, b) => SortUtil.ascSortLower(a.classSource, b.classSource)
|| SortUtil.ascSortLower(a.className, b.className)
|| SortUtil.ascSortLower(a.subclassSource, b.subclassSource)
|| SortUtil.ascSortLower(a.subclassShortName, b.subclassShortName)
|| SortUtil.ascSort(a.level, b.level)
|| SortUtil.ascSort(a.header || 0, b.header || 0)
|| SortUtil.ascSortGenericEntity(a, b);
case "subrace": return (a, b) => SortUtil.ascSortLower(a.raceName, b.raceName)
|| SortUtil.ascSortLower(a.raceSource, b.raceSource)
|| SortUtil.ascSortLower(a.name || "", b.name || "")
|| SortUtil.ascSortLower(a.source, b.source);
case "backgroundFeature": return (a, b) => SortUtil.ascSortLower(a.backgroundName, b.backgroundName)
|| SortUtil.ascSortLower(a.backgroundSource, b.backgroundSource)
|| SortUtil.ascSortGenericEntity(a, b);
case "encounter":
return SortUtil.ascSortEncounter.bind(SortUtil);
case "adventure": return SortUtil.ascSortAdventure.bind(SortUtil);
case "book": return SortUtil.ascSortBook.bind(SortUtil);
case "adventureData":
case "bookData":
return SortUtil.ascSortBookData.bind(SortUtil);
case "monsterfeatures":
return (a, b) => SortUtil.ascSortLower(a.name, b.name);
default: throw new Error(`Unhandled prop "${prop}"`);
}
}
class PropOrder {
static _getKeyProp (keyInfo) {
return typeof keyInfo === "string" ? keyInfo : keyInfo.key;
}
/* -------------------------------------------- */
/**
* @param obj
* @param [opts] Options object.
* @param [opts.fnUnhandledKey] Function to call on each unhandled key.
* @param [opts.isFoundryPrefixProps] If root keys should be treated as having a "foundry" prefix.
*/
static getOrderedRoot (obj, opts) {
opts ||= {};
return this._getOrdered(obj, PropOrder._ROOT, opts, "root");
}
static hasOrderRoot (obj) {
return PropOrder._ROOT
.filter(keyInfo => !(keyInfo instanceof PropOrder._IgnoredKey))
.some(keyInfo => obj[this._getKeyProp(keyInfo)] != null);
}
/* -------------------------------------------- */
/**
* @param obj
* @param dataProp
@@ -8,7 +153,7 @@ class PropOrder {
* @param [opts.fnUnhandledKey] Function to call on each unhandled key.
*/
static getOrdered (obj, dataProp, opts) {
opts = opts || {};
opts ||= {};
const order = PropOrder._PROP_TO_LIST[dataProp];
if (!order) throw new Error(`Unhandled prop "${dataProp}"`);
@@ -16,44 +161,79 @@ class PropOrder {
return this._getOrdered(obj, order, opts, dataProp);
}
static _getOrdered (obj, order, opts, path) {
static _getModifiedProp ({keyInfo, isFoundryPrefixProps}) {
const prop = this._getKeyProp(keyInfo);
if (!isFoundryPrefixProps || prop.startsWith("_")) return prop;
return prop.replace(/^foundry/, "").lowercaseFirst();
}
static _getOrdered (obj, order, opts, logPath) {
const out = {};
const keySet = new Set(Object.keys(obj));
const seenKeys = new Set();
order.forEach(k => {
if (typeof k === "string") {
seenKeys.add(k);
if (keySet.has(k)) out[k] = obj[k];
} else {
const key = k.key;
seenKeys.add(key);
order
.forEach(keyInfo => {
const prop = this._getKeyProp(keyInfo);
const propMod = this._getModifiedProp({keyInfo, isFoundryPrefixProps: opts.isFoundryPrefixProps});
if (keySet.has(key)) {
if (!obj[key]) return out[key] = obj[key]; // Handle nulls
if (opts.isFoundryPrefixProps && !prop.startsWith("_") && !prop.startsWith("foundry")) return;
if (k instanceof PropOrder._ObjectKey) {
const nxtPath = `${path}.${key}`;
if (k.fnGetOrder) out[key] = this._getOrdered(obj[key], k.fnGetOrder(obj[key]), opts, nxtPath);
else if (k.order) out[key] = this._getOrdered(obj[key], k.order, opts, nxtPath);
else out[key] = obj[key];
} else if (k instanceof PropOrder._ArrayKey) {
const nxtPath = `${path}[n].${key}`;
if (k.fnGetOrder) out[key] = obj[key].map(it => this._getOrdered(it, k.fnGetOrder(obj[key]), opts, nxtPath));
else if (k.order) out[key] = obj[key].map(it => this._getOrdered(it, k.order, opts, nxtPath));
else out[key] = obj[key];
if (!keySet.has(propMod)) return;
seenKeys.add(propMod);
if (k.fnSort && out[key] instanceof Array) out[key].sort(k.fnSort);
} else throw new Error(`Unimplemented!`);
if (typeof keyInfo === "string") {
out[propMod] = obj[propMod];
return;
}
}
});
if (!obj[propMod]) return out[propMod] = obj[propMod]; // Handle nulls
const optsNxt = {
...opts,
// Only used at the root
isFoundryPrefixProps: false,
};
if (keyInfo instanceof PropOrder._ObjectKey) {
const logPathNxt = `${logPath}.${prop}${propMod !== prop ? ` (${propMod})` : ""}`;
if (keyInfo.fnGetOrder) out[propMod] = this._getOrdered(obj[propMod], keyInfo.fnGetOrder(obj[propMod]), optsNxt, logPathNxt);
else if (keyInfo.order) out[propMod] = this._getOrdered(obj[propMod], keyInfo.order, optsNxt, logPathNxt);
else out[propMod] = obj[propMod];
return;
}
if (keyInfo instanceof PropOrder._ArrayKey) {
const logPathNxt = `${logPath}[n].${prop}${propMod !== prop ? ` (${propMod})` : ""}`;
if (keyInfo.fnGetOrder) out[propMod] = obj[propMod].map(it => this._getOrdered(it, keyInfo.fnGetOrder(obj[propMod]), optsNxt, logPathNxt));
else if (keyInfo.order) out[propMod] = obj[propMod].map(it => this._getOrdered(it, keyInfo.order, optsNxt, logPathNxt));
else out[propMod] = obj[propMod];
if (keyInfo.fnSort && out[propMod] instanceof Array) out[propMod].sort(keyInfo.fnSort);
return;
}
if (keyInfo instanceof PropOrder._IgnoredKey) {
out[propMod] = obj[propMod];
return;
}
throw new Error(`Unimplemented!`);
});
// ensure any non-orderable keys are maintained
const otherKeys = CollectionUtil.setDiff(keySet, seenKeys);
[...otherKeys].forEach(k => {
out[k] = obj[k];
if (opts.fnUnhandledKey) opts.fnUnhandledKey(`${path}.${k}`);
[...otherKeys].forEach(prop => {
out[prop] = obj[prop];
if (!opts.fnUnhandledKey) return;
const propMod = opts.isFoundryPrefixProps ? `foundry${prop.uppercaseFirst()}` : prop;
const logPathNxt = `${logPath}.${prop}${propMod !== prop ? ` (${propMod})` : ""}`;
opts.fnUnhandledKey(logPathNxt);
});
return out;
@@ -115,6 +295,22 @@ PropOrder._ArrayKey = class {
this.order = opts.order;
this.fnSort = opts.fnSort;
}
static getRootKey (prop) {
return new this(
prop,
{
fnGetOrder: () => PropOrder._PROP_TO_LIST[prop],
fnSort: getFnListSort(prop),
},
);
}
};
PropOrder._IgnoredKey = class {
constructor (key) {
this.key = key;
}
};
PropOrder._PROPS_FOUNDRY_DATA = [
@@ -157,6 +353,10 @@ PropOrder._FOUNDRY_GENERIC = [
"flags",
"img",
new PropOrder._ObjectKey("subEntities", {
fnGetOrder: () => PropOrder._ROOT,
}),
"_merge",
];
PropOrder._FOUNDRY_GENERIC_FEATURE = [
@@ -179,6 +379,10 @@ PropOrder._FOUNDRY_GENERIC_FEATURE = [
fnGetOrder: () => PropOrder._ENTRY_DATA_OBJECT,
}),
new PropOrder._ObjectKey("subEntities", {
fnGetOrder: () => PropOrder._ROOT,
}),
"_merge",
];
PropOrder._MONSTER = [
@@ -743,6 +947,11 @@ PropOrder._FOUNDRY_CLASS = [
"source",
"system",
"effects",
"flags",
"img",
"advancement",
"chooseSystem",
"isChooseSystemRenderEntries",
@@ -786,6 +995,9 @@ PropOrder._SUBCLASS = [
"preparedSpellsProgression",
"cantripProgression",
"spellsKnownProgression",
"spellsKnownProgressionFixed",
"spellsKnownProgressionFixedAllowLowerLevel",
"spellsKnownProgressionFixedByLevel",
"additionalSpells",
@@ -830,6 +1042,11 @@ PropOrder._FOUNDRY_SUBCLASS = [
"className",
"classSource",
"system",
"effects",
"flags",
"img",
"advancement",
"chooseSystem",
"isChooseSystemRenderEntries",
@@ -947,7 +1164,9 @@ PropOrder._FOUNDRY_CLASS_FEATURE = [
"actorDataMod",
"actorTokenMod",
"subEntities",
new PropOrder._ObjectKey("subEntities", {
fnGetOrder: () => PropOrder._ROOT,
}),
];
PropOrder._FOUNDRY_SUBCLASS_FEATURE = [
"name",
@@ -978,7 +1197,9 @@ PropOrder._FOUNDRY_SUBCLASS_FEATURE = [
"actorDataMod",
"actorTokenMod",
"subEntities",
new PropOrder._ObjectKey("subEntities", {
fnGetOrder: () => PropOrder._ROOT,
}),
];
PropOrder._LANGUAGE = [
"name",
@@ -2143,4 +2364,164 @@ PropOrder._PROP_TO_LIST = {
"foundryMap": PropOrder._FOUNDRY_MAP,
};
PropOrder._ROOT = [
"$schema",
new PropOrder._ObjectKey("_meta", {
fnGetOrder: () => PropOrder._META,
}),
// region Player options
PropOrder._ArrayKey.getRootKey("class"),
PropOrder._ArrayKey.getRootKey("foundryClass"),
PropOrder._ArrayKey.getRootKey("classFluff"),
PropOrder._ArrayKey.getRootKey("subclass"),
PropOrder._ArrayKey.getRootKey("foundrySubclass"),
PropOrder._ArrayKey.getRootKey("subclassFluff"),
PropOrder._ArrayKey.getRootKey("classFeature"),
PropOrder._ArrayKey.getRootKey("foundryClassFeature"),
PropOrder._ArrayKey.getRootKey("subclassFeature"),
PropOrder._ArrayKey.getRootKey("foundrySubclassFeature"),
PropOrder._ArrayKey.getRootKey("optionalfeature"),
PropOrder._ArrayKey.getRootKey("optionalfeatureFluff"),
PropOrder._ArrayKey.getRootKey("foundryOptionalfeature"),
PropOrder._ArrayKey.getRootKey("background"),
PropOrder._ArrayKey.getRootKey("backgroundFeature"),
PropOrder._ArrayKey.getRootKey("backgroundFluff"),
PropOrder._ArrayKey.getRootKey("race"),
PropOrder._ArrayKey.getRootKey("subrace"),
PropOrder._ArrayKey.getRootKey("foundryRace"),
PropOrder._ArrayKey.getRootKey("foundryRaceFeature"),
PropOrder._ArrayKey.getRootKey("raceFluff"),
new PropOrder._IgnoredKey("raceFluffMeta"),
PropOrder._ArrayKey.getRootKey("feat"),
PropOrder._ArrayKey.getRootKey("foundryFeat"),
PropOrder._ArrayKey.getRootKey("featFluff"),
PropOrder._ArrayKey.getRootKey("reward"),
PropOrder._ArrayKey.getRootKey("foundryReward"),
PropOrder._ArrayKey.getRootKey("rewardFluff"),
PropOrder._ArrayKey.getRootKey("charoption"),
PropOrder._ArrayKey.getRootKey("charoptionFluff"),
// endregion
// region General entities
PropOrder._ArrayKey.getRootKey("spell"),
PropOrder._ArrayKey.getRootKey("spellFluff"),
PropOrder._ArrayKey.getRootKey("foundrySpell"),
PropOrder._ArrayKey.getRootKey("spellList"),
PropOrder._ArrayKey.getRootKey("baseitem"),
PropOrder._ArrayKey.getRootKey("item"),
PropOrder._ArrayKey.getRootKey("itemGroup"),
PropOrder._ArrayKey.getRootKey("magicvariant"),
PropOrder._ArrayKey.getRootKey("itemFluff"),
PropOrder._ArrayKey.getRootKey("foundryItem"),
PropOrder._ArrayKey.getRootKey("foundryMagicvariant"),
new PropOrder._IgnoredKey("itemProperty"),
new PropOrder._IgnoredKey("reducedItemProperty"),
new PropOrder._IgnoredKey("itemType"),
new PropOrder._IgnoredKey("itemTypeAdditionalEntries"),
new PropOrder._IgnoredKey("reducedItemType"),
new PropOrder._IgnoredKey("itemEntry"),
PropOrder._ArrayKey.getRootKey("itemMastery"),
new PropOrder._IgnoredKey("linkedLootTables"),
PropOrder._ArrayKey.getRootKey("deck"),
PropOrder._ArrayKey.getRootKey("card"),
PropOrder._ArrayKey.getRootKey("deity"),
PropOrder._ArrayKey.getRootKey("language"),
PropOrder._ArrayKey.getRootKey("languageScript"),
PropOrder._ArrayKey.getRootKey("languageFluff"),
// endregion
// region GM-specific
PropOrder._ArrayKey.getRootKey("monster"),
PropOrder._ArrayKey.getRootKey("monsterFluff"),
PropOrder._ArrayKey.getRootKey("foundryMonster"),
PropOrder._ArrayKey.getRootKey("legendaryGroup"),
PropOrder._ArrayKey.getRootKey("monsterTemplate"),
PropOrder._ArrayKey.getRootKey("object"),
PropOrder._ArrayKey.getRootKey("objectFluff"),
PropOrder._ArrayKey.getRootKey("vehicle"),
PropOrder._ArrayKey.getRootKey("vehicleUpgrade"),
PropOrder._ArrayKey.getRootKey("foundryVehicleUpgrade"),
PropOrder._ArrayKey.getRootKey("vehicleFluff"),
PropOrder._ArrayKey.getRootKey("cult"),
PropOrder._ArrayKey.getRootKey("boon"),
PropOrder._ArrayKey.getRootKey("trap"),
PropOrder._ArrayKey.getRootKey("trapFluff"),
PropOrder._ArrayKey.getRootKey("hazard"),
PropOrder._ArrayKey.getRootKey("hazardFluff"),
PropOrder._ArrayKey.getRootKey("encounter"),
PropOrder._ArrayKey.getRootKey("name"),
// endregion
// region Rules
PropOrder._ArrayKey.getRootKey("variantrule"),
PropOrder._ArrayKey.getRootKey("table"),
PropOrder._ArrayKey.getRootKey("condition"),
PropOrder._ArrayKey.getRootKey("conditionFluff"),
PropOrder._ArrayKey.getRootKey("disease"),
PropOrder._ArrayKey.getRootKey("status"),
PropOrder._ArrayKey.getRootKey("action"),
PropOrder._ArrayKey.getRootKey("foundryAction"),
PropOrder._ArrayKey.getRootKey("skill"),
PropOrder._ArrayKey.getRootKey("sense"),
PropOrder._ArrayKey.getRootKey("citation"),
PropOrder._ArrayKey.getRootKey("adventure"),
PropOrder._ArrayKey.getRootKey("adventureData"),
PropOrder._ArrayKey.getRootKey("book"),
PropOrder._ArrayKey.getRootKey("bookData"),
// endregion
// region Other
PropOrder._ArrayKey.getRootKey("recipe"),
PropOrder._ArrayKey.getRootKey("recipeFluff"),
// endregion
// region Legacy content
PropOrder._ArrayKey.getRootKey("psionic"),
new PropOrder._IgnoredKey("psionicDisciplineFocus"),
new PropOrder._IgnoredKey("psionicDisciplineActive"),
// endregion
// region Tooling
PropOrder._ArrayKey.getRootKey("makebrewCreatureTrait"),
PropOrder._ArrayKey.getRootKey("makebrewCreatureAction"),
PropOrder._ArrayKey.getRootKey("monsterfeatures"),
// endregion
// region Roll20-specific
PropOrder._ArrayKey.getRootKey("roll20Spell"),
// endregion
// region Non-brew data
new PropOrder._IgnoredKey("blocklist"),
// endregion
// region Misc ignored keys
new PropOrder._IgnoredKey("data"),
// endregion
];
globalThis.PropOrder = PropOrder;

View File

@@ -1,8 +1,9 @@
"use strict";
class UtilsTableview {
static _State = class {
static _RenderState = class {
constructor () {
this.comp = null;
this.rows = [];
this.metasCbs = [];
}
@@ -17,63 +18,92 @@ class UtilsTableview {
isEmpty: true,
});
const state = new UtilsTableview._State();
const rdState = new UtilsTableview._RenderState();
state.metasCbs = Object.values(colTransforms)
.map((c, i) => {
const $cb = $(`<input type="checkbox" class="mr-2" checked>`)
.click(() => {
const $eles = $modal.find(`[data-col="${i}"]`);
$eles.toggleVe($cb.prop("checked"));
});
rdState.comp = BaseComponent.fromObject(
Object.keys(colTransforms).mergeMap(k => ({[k]: true})),
);
const $cbAll = $(`<input type="checkbox" title="Select All" checked>`)
.on("click", () => {
const val = $cbAll.prop("indeterminate") ? false : $cbAll.prop("checked");
rdState.comp._proxyAssignSimple(
"state",
Object.keys(colTransforms).mergeMap(k => ({[k]: val})),
);
});
rdState.metasCbs = Object.entries(colTransforms)
.map(([prop, meta]) => {
const $cb = ComponentUiUtil.$getCbBool(rdState.comp, prop);
const $wrp = $$`<label class="px-2 py-1 no-wrap ve-flex-inline-v-center">
${$cb}
<span>${c.name}</span>
<span>${meta.name}</span>
</label>`;
return {$wrp, $cb, name: c.name};
return {$wrp, name: meta.name};
});
Object.keys(colTransforms)
.forEach((prop, i) => {
rdState.comp._addHookBase(prop, () => {
const propsSelected = Object.keys(colTransforms).map(prop => rdState.comp._state[prop]);
if (propsSelected.every(Boolean)) $cbAll.prop("checked", true);
else if (propsSelected.every(it => !it)) $cbAll.prop("checked", false);
else $cbAll.prop("indeterminate", true).prop("checked", true);
const $eles = $modal.find(`[data-col="${i}"]`);
$eles.toggleVe(rdState.comp._state[prop]);
});
});
const $btnCsv = $(`<button class="btn btn-primary">Download CSV</button>`).click(() => {
DataUtil.userDownloadText(`${title}.csv`, this._getAsCsv({state}));
DataUtil.userDownloadText(`${title}.csv`, this._getAsCsv({colTransforms, rdState}));
});
const $btnCopy = $(`<button class="btn btn-primary">Copy CSV to Clipboard</button>`).click(async () => {
await MiscUtil.pCopyTextToClipboard(this._getAsCsv({state}));
await MiscUtil.pCopyTextToClipboard(this._getAsCsv({colTransforms, rdState}));
JqueryUtil.showCopiedEffect($btnCopy);
});
$$($modal)`<div class="split-v-center my-3">
<div class="ve-flex-v-center ve-flex-wrap">${state.metasCbs.map(({$wrp}) => $wrp)}</div>
const $wrpRows = $(`<div class="ve-overflow-y-auto w-100 h-100 ve-flex-col ve-overflow-x-auto"></div>`);
$$($modal)`<div class="ve-flex-v-center my-3">
<label class="ve-flex-vh-center pl-2 pr-3 h-100">${$cbAll}</label>
<div class="vr-2 ml-0 h-100"></div>
<div class="ve-flex-v-center ve-flex-wrap w-100 min-w-0">${rdState.metasCbs.map(({$wrp}) => $wrp)}</div>
<div class="vr-2 h-100"></div>
<div class="btn-group no-shrink ve-flex-v-center ml-3">
${$btnCsv}
${$btnCopy}
</div>
</div>
<hr class="hr-1">`;
<hr class="hr-1">
${$wrpRows}
`;
const tableHtml = this._getTableHtml({state, entities, colTransforms, sorter});
$modal.append(tableHtml);
const tableHtml = this._getTableHtml({rdState, entities, colTransforms, sorter});
$wrpRows.fastSetHtml(tableHtml);
}
static _getAsCsv ({state}) {
const headersActive = state.metasCbs.map(({$cb, name}, i) => {
if (!$cb.prop("checked")) return null;
return {name, ix: i};
}).filter(Boolean);
static _getAsCsv ({colTransforms, rdState}) {
const headersActive = Object.entries(colTransforms)
.map(([prop, meta], ix) => ({name: meta.name, ix, isSelected: rdState.comp._state[prop]}))
.filter(({isSelected}) => isSelected);
const parser = new DOMParser();
const rows = state.rows.map(row => headersActive.map(({ix}) => parser.parseFromString(`<div>${row[ix]}</div>`, "text/html").documentElement.textContent));
const rows = rdState.rows.map(row => headersActive.map(({ix}) => parser.parseFromString(`<div>${row[ix]}</div>`, "text/html").documentElement.textContent));
return DataUtil.getCsv(headersActive.map(({name}) => name), rows);
}
static _getTableHtml ({state, entities, colTransforms, sorter}) {
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>
</thead>
<tbody>`;
static _getTableHtml ({rdState, entities, colTransforms, sorter}) {
let stack = `<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>
</thead>
<tbody>`;
const listCopy = [...entities];
if (sorter) listCopy.sort(sorter);
@@ -86,13 +116,11 @@ class UtilsTableview {
row.push(val);
return `<td data-col="${i}" class="px-2" colspan="${c.flex || 1}">${val || ""}</td>`;
}).join("");
state.rows.push(row);
rdState.rows.push(row);
stack += `</tr>`;
});
stack += `</tbody>
</table>
</div>`;
stack += `</tbody></table>`;
return stack;
}

File diff suppressed because it is too large Load Diff

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.207.2"/* 5ETOOLS_VERSION__CLOSE */;
globalThis.VERSION_NUMBER = /* 5ETOOLS_VERSION__OPEN */"1.208.0"/* 5ETOOLS_VERSION__CLOSE */;
globalThis.DEPLOYED_IMG_ROOT = undefined;
// for the roll20 script to set
globalThis.IS_VTT = false;
@@ -731,6 +731,108 @@ Math.seed = Math.seed || function (s) {
};
};
class TemplateUtil {
static initJquery () {
/**
* Template strings which can contain jQuery objects.
* Usage: $$`<div>Press this button: ${$btn}</div>`
* or: $$($ele)`<div>Press this button: ${$btn}</div>`
* @return {jQuery}
*/
globalThis.$$ = (parts, ...args) => {
if (parts instanceof jQuery || parts instanceof Node) {
return (...passed) => {
const parts2 = [...passed[0]];
const args2 = passed.slice(1);
parts2[0] = `<div>${parts2[0]}`;
parts2.last(`${parts2.last()}</div>`);
const eleParts = parts instanceof jQuery ? parts[0] : parts;
const $temp = $$(parts2, ...args2);
$temp.children().each((i, e) => eleParts.appendChild(e));
return $(eleParts);
};
}
// Note that passing in a jQuery collection of multiple elements is not supported
const partsNxt = parts instanceof jQuery ? parts[0] : parts;
const argsNxt = args
.map(arg => {
if (arg instanceof Array) return arg.flatMap(argSub => argSub instanceof jQuery ? argSub.get() : argSub);
return arg instanceof jQuery ? arg.get() : arg;
});
return $(ee(partsNxt, ...argsNxt));
};
}
/* -------------------------------------------- */
static initVanilla () {
/**
* Template strings which can contain DOM elements.
* Usage: ee`<div>Press this button: ${btn}</div>`
* or: ee(ele)`<div>Press this button: ${btn}</div>`
* @return {HTMLElementModified}
*/
globalThis.ee = (parts, ...args) => {
if (parts instanceof Node) {
return (...passed) => {
const parts2 = [...passed[0]];
const args2 = passed.slice(1);
parts2[0] = `<div>${parts2[0]}`;
parts2.last(`${parts2.last()}</div>`);
const eleTmp = ee(parts2, ...args2);
Array.from(eleTmp.childNodes).forEach(node => parts.appendChild(node));
return e_({ele: parts});
};
}
const eles = [];
let ixArg = 0;
const raw = parts
.reduce((html, p) => {
const myIxArg = ixArg++;
if (args[myIxArg] == null) return `${html}${p}`;
if (args[myIxArg] instanceof Array) return `${html}${args[myIxArg].map(arg => TemplateUtil._ee_handleArg(eles, arg)).join("")}${p}`;
else return `${html}${TemplateUtil._ee_handleArg(eles, args[myIxArg])}${p}`;
});
const eleTmpTemplate = document.createElement("template");
eleTmpTemplate.innerHTML = raw;
const {content: eleTmp} = eleTmpTemplate;
// debugger
Array.from(eleTmp.querySelectorAll(`[data-r="true"]`))
.forEach((node, i) => node.replaceWith(eles[i]));
const childNodes = Array.from(eleTmp.childNodes);
childNodes.forEach(node => document.adoptNode(node));
// If the caller has passed in a single element, return it
if (childNodes.length === 1) return e_({ele: childNodes[0]});
// If the caller has passed in multiple elements with no wrapper, return an array
return childNodes
.map(childNode => e_({ele: childNode}));
};
}
static _ee_handleArg (eles, arg) {
if (arg instanceof Node) {
eles.push(arg);
return `<${arg.tagName} data-r="true"></${arg.tagName}>`;
}
return arg;
}
}
globalThis.TemplateUtil = TemplateUtil;
globalThis.JqueryUtil = {
_isEnhancementsInit: false,
initEnhancements () {
@@ -739,58 +841,8 @@ globalThis.JqueryUtil = {
JqueryUtil.addSelectors();
/**
* Template strings which can contain jQuery objects.
* Usage: $$`<div>Press this button: ${$btn}</div>`
* @return jQuery
*/
window.$$ = function (parts, ...args) {
if (parts instanceof jQuery || parts instanceof HTMLElement) {
return (...passed) => {
const parts2 = [...passed[0]];
const args2 = passed.slice(1);
parts2[0] = `<div>${parts2[0]}`;
parts2.last(`${parts2.last()}</div>`);
const $temp = $$(parts2, ...args2);
$temp.children().each((i, e) => $(e).appendTo(parts));
return parts;
};
} else {
const $eles = [];
let ixArg = 0;
const handleArg = (arg) => {
if (arg instanceof $) {
$eles.push(arg);
return `<${arg.tag()} data-r="true"></${arg.tag()}>`;
} else if (arg instanceof HTMLElement) {
return handleArg($(arg));
} else return arg;
};
const raw = parts.reduce((html, p) => {
const myIxArg = ixArg++;
if (args[myIxArg] == null) return `${html}${p}`;
if (args[myIxArg] instanceof Array) return `${html}${args[myIxArg].map(arg => handleArg(arg)).join("")}${p}`;
else return `${html}${handleArg(args[myIxArg])}${p}`;
});
const $res = $(raw);
if ($res.length === 1) {
if ($res.attr("data-r") === "true") return $eles[0];
else $res.find(`[data-r=true]`).replaceWith(i => $eles[i]);
} else {
// Handle case where user has passed in a bunch of elements with no outer wrapper
const $tmp = $(`<div></div>`);
$tmp.append($res);
$tmp.find(`[data-r=true]`).replaceWith(i => $eles[i]);
return $tmp.children();
}
return $res;
}
};
TemplateUtil.initVanilla();
TemplateUtil.initJquery();
$.fn.extend({
// avoid setting input type to "search" as it visually offsets the contents of the input
@@ -1023,6 +1075,44 @@ globalThis.ElementUtil = {
"disabled",
]),
/**
* @typedef {HTMLElement} HTMLElementModified
* @extends {HTMLElement}
*
* @property {function(HTMLElement): HTMLElementModified} appends
* @property {function(HTMLElement): HTMLElementModified} appendTo
* @property {function(HTMLElement): HTMLElementModified} prependTo
* @property {function(HTMLElement): HTMLElementModified} insertAfter
*
* @property {function(string): HTMLElementModified} addClass
* @property {function(string): HTMLElementModified} removeClass
* @property {function(string, ?boolean): HTMLElementModified} toggleClass
*
* @property {function(): HTMLElementModified} showVe
* @property {function(): HTMLElementModified} hideVe
* @property {function(?boolean): HTMLElementModified} toggleVe
*
* @property {function(): HTMLElementModified} empty
* @property {function(): HTMLElementModified} detach
*
* @property {function(string, string): HTMLElementModified} attr
* @property {function(*=): *} val
*
* @property {function(?string): (HTMLElementModified|string)} html
* @property {function(?string): (HTMLElementModified|string)} txt
*
* @property {function(string): HTMLElementModified} tooltip
* @property {function(): HTMLElementModified} disableSpellcheck
*
* @property {function(string, function): HTMLElementModified} onn
* @property {function(function): HTMLElementModified} onClick
* @property {function(function): HTMLElementModified} onContextmenu
* @property {function(function): HTMLElementModified} onChange
* @property {function(function): HTMLElementModified} onKeydown
* @property {function(function): HTMLElementModified} onKeyup
*
* @return {HTMLElementModified}
*/
getOrModify ({
tag,
clazz,
@@ -1110,7 +1200,7 @@ globalThis.ElementUtil = {
ele.txt = ele.txt || ElementUtil._txt.bind(ele);
ele.tooltip = ele.tooltip || ElementUtil._tooltip.bind(ele);
ele.disableSpellcheck = ele.disableSpellcheck || ElementUtil._disableSpellcheck.bind(ele);
ele.on = ele.on || ElementUtil._onX.bind(ele);
ele.onn = ele.onn || ElementUtil._onX.bind(ele);
ele.onClick = ele.onClick || ElementUtil._onX.bind(ele, "click");
ele.onContextmenu = ele.onContextmenu || ElementUtil._onX.bind(ele, "contextmenu");
ele.onChange = ele.onChange || ElementUtil._onX.bind(ele, "change");
@@ -3664,13 +3754,28 @@ globalThis.DataUtil = {
},
_mutAddProps (data) {
if (data && typeof data === "object") {
for (const k in data) {
if (data[k] instanceof Array) {
for (const it of data[k]) {
if (typeof it !== "object") continue;
it.__prop = k;
}
if (!data || typeof data !== "object") return;
for (const k in data) {
if (!(data[k] instanceof Array)) continue;
for (const it of data[k]) {
if (typeof it !== "object") continue;
it.__prop = k;
}
}
},
_verifyMerged (data) {
if (!data || typeof data !== "object") return;
for (const k in data) {
if (!(data[k] instanceof Array)) continue;
for (const it of data[k]) {
if (typeof it !== "object") continue;
if (it._copy) {
setTimeout(() => { throw new Error(`Unresolved "_copy" in entity: ${JSON.stringify(it)}`); });
}
}
}
@@ -3706,7 +3811,10 @@ globalThis.DataUtil = {
async pDoMetaMerge (ident, data, options) {
DataUtil._mutAddProps(data);
DataUtil._merging[ident] = DataUtil._merging[ident] || DataUtil._pDoMetaMerge(ident, data, options);
const isFresh = !DataUtil._merging[ident];
DataUtil._merging[ident] ||= DataUtil._pDoMetaMerge(ident, data, options);
await DataUtil._merging[ident];
const out = DataUtil._merged[ident];
@@ -3717,6 +3825,8 @@ globalThis.DataUtil = {
delete DataUtil._merged[ident];
}
if (isFresh) DataUtil._verifyMerged(out);
return out;
},
@@ -3957,6 +4067,8 @@ globalThis.DataUtil = {
return DataUtil._pLoadByMeta_pGetPrereleaseBrew(source);
}
case "race": {
// FIXME(Future) this should really `loadRawJSON`, but this breaks existing brew.
// Consider a large-scale migration in future.
const data = await DataUtil.race.loadJSON({isAddBaseRaces: true});
if (data[prop] && data[prop].some(it => it.source === source)) return data;
return DataUtil._pLoadByMeta_pGetPrereleaseBrew(source);
@@ -4093,8 +4205,7 @@ globalThis.DataUtil = {
if (!it) {
if (options.isErrorOnMissing) {
// In development/script mode, throw an exception
if (!IS_DEPLOYED && !IS_VTT) throw new Error(`Could not find "${page}" entity "${entry._copy.name}" ("${entry._copy.source}") to copy in copier "${entry.name}" ("${entry.source}")`);
throw new Error(`Could not find "${page}" entity "${entry._copy.name}" ("${entry._copy.source}") to copy in copier "${entry.name}" ("${entry.source}")`);
}
return;
}
@@ -4113,9 +4224,10 @@ globalThis.DataUtil = {
_pMergeCopy_search (impl, page, entryList, entry, options) {
const entryHash = UrlUtil.URL_TO_HASH_BUILDER[page](entry._copy);
return entryList.find(it => {
const hash = UrlUtil.URL_TO_HASH_BUILDER[page](it);
impl._mergeCache[hash] = it;
return entryList.find(ent => {
const hash = UrlUtil.URL_TO_HASH_BUILDER[page](ent);
// Avoid clobbering existing caches, as we assume "earlier = better"
impl._mergeCache[hash] ||= ent;
return hash === entryHash;
});
},
@@ -4270,6 +4382,26 @@ globalThis.DataUtil = {
} else throw new Error(`${msgPtFailed} One of "names" or "items" must be provided!`);
}
static _doMod_renameArr ({copyTo, copyFrom, modInfo, msgPtFailed, prop, isThrow = true}) {
this._doEnsureArray({obj: modInfo, prop: "renames"});
if (!copyTo[prop]) {
if (isThrow) throw new Error(`${msgPtFailed} Could not find "${prop}" array`);
return;
}
modInfo.renames
.forEach(rename => {
const ent = copyTo[prop].find(ent => ent?.name === rename.rename);
if (!ent) {
if (isThrow) throw new Error(`${msgPtFailed} Could not find "${prop}" item with name "${rename.rename}" to rename`);
return;
}
ent.name = rename.with;
});
}
static _doMod_calculateProp ({copyTo, copyFrom, modInfo, msgPtFailed, prop}) {
copyTo[prop] = copyTo[prop] || {};
const toExec = modInfo.formula.replace(/<\$([^$]+)\$>/g, (...m) => {
@@ -4576,7 +4708,7 @@ globalThis.DataUtil = {
static _doMod_setProp ({copyTo, copyFrom, modInfo, msgPtFailed, prop}) {
const propPath = modInfo.prop.split(".");
if (prop !== "*") propPath.unshift(prop);
if (prop != null && prop !== "*") propPath.unshift(prop);
MiscUtil.set(copyTo, ...propPath, MiscUtil.copyFast(modInfo.value));
}
@@ -4599,6 +4731,7 @@ globalThis.DataUtil = {
case "appendIfNotExistsArr": return this._doMod_appendIfNotExistsArr({copyTo, copyFrom, modInfo, msgPtFailed, prop});
case "insertArr": return this._doMod_insertArr({copyTo, copyFrom, modInfo, msgPtFailed, prop});
case "removeArr": return this._doMod_removeArr({copyTo, copyFrom, modInfo, msgPtFailed, prop});
case "renameArr": return this._doMod_renameArr({copyTo, copyFrom, modInfo, msgPtFailed, prop});
case "calculateProp": return this._doMod_calculateProp({copyTo, copyFrom, modInfo, msgPtFailed, prop});
case "scalarAddProp": return this._doMod_scalarAddProp({copyTo, copyFrom, modInfo, msgPtFailed, prop});
case "scalarMultProp": return this._doMod_scalarMultProp({copyTo, copyFrom, modInfo, msgPtFailed, prop});
@@ -5535,19 +5668,17 @@ globalThis.DataUtil = {
static _PAGE = UrlUtil.PG_RACES;
static _FILENAME = "races.json";
static _loadCache = {};
static _pIsLoadings = {};
static _psLoadJson = {};
static async loadJSON ({isAddBaseRaces = false} = {}) {
if (!DataUtil.race._pIsLoadings[isAddBaseRaces]) {
DataUtil.race._pIsLoadings[isAddBaseRaces] = (async () => {
DataUtil.race._loadCache[isAddBaseRaces] = DataUtil.race.getPostProcessedSiteJson(
await this.loadRawJSON(),
{isAddBaseRaces},
);
})();
}
await DataUtil.race._pIsLoadings[isAddBaseRaces];
return DataUtil.race._loadCache[isAddBaseRaces];
const cacheKey = `site-${isAddBaseRaces}`;
DataUtil.race._psLoadJson[cacheKey] ||= (async () => {
return DataUtil.race.getPostProcessedSiteJson(
await this.loadRawJSON(),
{isAddBaseRaces},
);
})();
return DataUtil.race._psLoadJson[cacheKey];
}
static getPostProcessedSiteJson (rawRaceData, {isAddBaseRaces = false} = {}) {
@@ -5567,11 +5698,15 @@ globalThis.DataUtil = {
}
static async loadPrerelease ({isAddBaseRaces = true} = {}) {
return DataUtil.race._loadPrereleaseBrew({isAddBaseRaces, brewUtil: typeof PrereleaseUtil !== "undefined" ? PrereleaseUtil : null});
const cacheKey = `prerelease-${isAddBaseRaces}`;
this._psLoadJson[cacheKey] ||= DataUtil.race._loadPrereleaseBrew({isAddBaseRaces, brewUtil: typeof PrereleaseUtil !== "undefined" ? PrereleaseUtil : null});
return this._psLoadJson[cacheKey];
}
static async loadBrew ({isAddBaseRaces = true} = {}) {
return DataUtil.race._loadPrereleaseBrew({isAddBaseRaces, brewUtil: typeof BrewUtil2 !== "undefined" ? BrewUtil2 : null});
const cacheKey = `brew-${isAddBaseRaces}`;
this._psLoadJson[cacheKey] ||= DataUtil.race._loadPrereleaseBrew({isAddBaseRaces, brewUtil: typeof BrewUtil2 !== "undefined" ? BrewUtil2 : null});
return this._psLoadJson[cacheKey];
}
static async _loadPrereleaseBrew ({isAddBaseRaces = true, brewUtil} = {}) {
@@ -5653,60 +5788,22 @@ globalThis.DataUtil = {
static _FILENAME = "recipes.json";
static async loadJSON () {
const rawData = await super.loadJSON();
return {recipe: await DataUtil.recipe.pGetPostProcessedRecipes(rawData.recipe)};
}
static async pGetPostProcessedRecipes (recipes) {
if (!recipes?.length) return;
recipes = MiscUtil.copyFast(recipes);
// Apply ingredient properties
recipes.forEach(r => Renderer.recipe.populateFullIngredients(r));
const out = [];
// region Merge together main data and fluff, as we render the fluff in the main tab
for (const r of recipes) {
const fluff = await Renderer.utils.pGetFluff({
entity: r,
fluffProp: "recipeFluff",
});
if (!fluff) {
out.push(r);
continue;
}
const cpyR = MiscUtil.copyFast(r);
cpyR.fluff = MiscUtil.copyFast(fluff);
delete cpyR.fluff.name;
delete cpyR.fluff.source;
out.push(cpyR);
}
//
return out;
return DataUtil.recipe._pLoadJson = DataUtil.recipe._pLoadJson || (async () => {
return {
recipe: await DataLoader.pCacheAndGetAllSite("recipe"),
};
})();
}
static async loadPrerelease () {
return this._loadPrereleaseBrew({brewUtil: typeof PrereleaseUtil !== "undefined" ? PrereleaseUtil : null});
return {
recipe: await DataLoader.pCacheAndGetAllPrerelease("recipe"),
};
}
static async loadBrew () {
return this._loadPrereleaseBrew({brewUtil: typeof BrewUtil2 !== "undefined" ? BrewUtil2 : null});
}
static async _loadPrereleaseBrew ({brewUtil}) {
if (!brewUtil) return {};
const brew = await brewUtil.pGetBrewProcessed();
if (!brew?.recipe?.length) return brew;
return {
...brew,
recipe: await DataUtil.recipe.pGetPostProcessedRecipes(brew.recipe),
recipe: await DataLoader.pCacheAndGetAllBrew("recipe"),
};
}
},