journal-to-canvas-slideshow/scripts/data/SlideshowConfigActions.js

881 lines
39 KiB
JavaScript

"use strict";
import { JTCSSettingsApplication } from "../classes/JTCSSettingsApplication.js";
import { JTCSActions } from "./JTCS-Actions.js";
import { Popover } from "../classes/PopoverGenerator.js";
import { universalInterfaceActions as UIA } from "./Universal-Actions.js";
import { HelperFunctions } from "../classes/HelperFunctions.js";
import { ImageDisplayManager } from "../classes/ImageDisplayManager.js";
import { ArtTileManager } from "../classes/ArtTileManager.js";
/**
* Show instructions
*/
export const extraActions = {
renderTileConfig: async (event, options = {}) => {
let { tileID } = options;
await ArtTileManager.renderTileConfig(tileID);
},
selectTile: async (event, options = {}) => {
let { tileID } = options;
await ArtTileManager.selectTile(tileID);
},
updateTileData: async (event, options = {}) => {
let clickedElement = $(event.currentTarget);
let { name, value } = event.currentTarget;
let { tileID, app, parentLI } = options;
let action = clickedElement.data().action || clickedElement.data().changeAction;
let { type } = $(parentLI).data();
let isNewTile = false;
let isBoundingTile = type === "frame";
if (action.includes("createNewTileData")) {
isNewTile = true;
tileID = `unlinked${foundry.utils.randomID()}`;
name = "displayName";
value = `Untitled ${type} Tile`;
} else {
// if we're already a Slideshow tile, look for our ID
tileID = clickedElement[0].closest(".tile-list-item, .popover").dataset.id;
}
if (tileID) {
let updateData = {
id: tileID,
[name]: value,
...(isNewTile ? { isBoundingTile: isBoundingTile } : {}),
};
await ArtTileManager.updateSceneTileFlags(updateData, tileID);
await app.renderWithData();
}
},
deleteTileData: async (event, options = {}) => {
const { app, tileID, parentLI } = options;
let type = parentLI.dataset.type;
let displayName = await ArtTileManager.getGalleryTileDataFromID(
tileID,
"displayName"
);
const templatePath = game.JTCS.templates["delete-confirmation-prompt"];
const buttons = {
cancel: {
label: "Cancel",
icon: "<i class='fas fa-undo'></i>",
},
delete: {
label: "Delete Gallery Tile",
icon: "<i class='fas fa-trash'></i>",
callback: async () => {
await ArtTileManager.deleteSceneTileData(tileID);
await app.renderWithData();
},
},
};
type = type.charAt(0).toUpperCase() + type.slice(1);
const data = {
icon: "fas fa-trash",
heading: "Delete Art Tile Data?",
destructiveActionText: `delete this ${type} tile data?`,
explanation: `This will permanently delete`,
lossDataList: [`${type} Tile '${displayName}'`],
explanation2: `With no way to get it back`,
buttons,
};
await HelperFunctions.createDialog("Delete Art Tile", templatePath, data);
},
highlightItemAndTile: async (event, options = {}) => {
let { parentLI, tileID, missing } = options;
// if (missing) {
// return;
// }
let { type, frameId: frameID } = $(parentLI).data();
let isLeave = event.type === "mouseleave" ? true : false;
// we want every hover over a tile to highlight the tiles it is linked to
let hoveredElement = $(event.currentTarget);
// let type = hoveredElement.data().type;
// let id = hoveredElement.data().id;
let otherListItems = [];
if (type === "frame") frameID = tileID;
if (frameID) {
otherListItems = Array.from(
hoveredElement[0].closest(".tilesInScene").querySelectorAll("li")
).filter(
//get list items with the opposite tile type
(item) => {
let passed = true;
if (item.dataset.type === type) {
passed = false;
}
if (item.dataset.flag === "ignoreHover") {
passed = false;
}
return passed;
}
);
//filter out list items
otherListItems = otherListItems.filter((element) => {
let dataset = Object.values({ ...element.dataset }).join(" ");
let match = false;
if (type === "art") {
//for art tiles, we're looking for frameTiles in the list that match the frame id
match = dataset.includes(frameID);
} else if (type === "frame") {
//for frame tiles, we're looking for art tiles in the list that have our id
match = dataset.includes(tileID);
}
return match;
});
}
// if (!tileID) {
// return;
// }
let tile;
if (!missing) tile = await ArtTileManager.getTileObjectByID(tileID);
if (isLeave) {
hoveredElement.removeClass("accent border-accent");
$(otherListItems).removeClass("accent border-accent");
if (!missing) game.JTCS.indicatorUtils.hideTileIndicator(tile);
} else {
hoveredElement.addClass("accent border-accent");
$(otherListItems).addClass("accent border-accent");
if (!missing) game.JTCS.indicatorUtils.showTileIndicator(tile);
}
},
setDefaultTileInScene: async (event, options = {}) => {
if (event.ctrlKey || event.metaKey) {
//if the ctrl or meta (cmd) key on mac is pressed
let { tileID, parentLI } = options;
let type = parentLI.dataset.type;
let tileInScene = await ArtTileManager.getTileObjectByID(tileID);
let displayName = await ArtTileManager.getGalleryTileDataFromID(
tileID,
"displayName"
);
if (tileInScene) {
await ArtTileManager.setDefaultArtTileID(tileID, game.scenes.viewed);
} else {
ui.notifications.warn(
`Gallery ${HelperFunctions.capitalizeEachWord(type)}
Tile "${displayName}"
must be linked to a tile in this scene
before it can be set as default`
);
}
}
},
showURLShareDialog: async (event, options = {}) => {
let wrappedActions = {};
let { displayActions } = JTCSActions;
for (let actionName in displayActions) {
wrappedActions[actionName] = { ...displayActions[actionName] };
//converting properties to fit the dialog's schema
wrappedActions[
actionName
].icon = `<i class='${displayActions[actionName].icon}'></i>`;
// wrappedActions[actionName].label = HelperFunctions.capitalizeEachWord(actionName, "");
wrappedActions[actionName].callback = async (html) => {
let urlInput = html.find("input[name='urlInput']");
let url = urlInput.val();
if (url !== "") {
await ImageDisplayManager.determineDisplayMethod({
method: actionName,
url: url,
});
}
};
}
delete wrappedActions.anyScene;
let buttons = {
...wrappedActions,
cancel: {
label: "Cancel",
},
};
let templatePath = game.JTCS.templates["share-url-partial"];
await HelperFunctions.createDialog("Share URL", templatePath, {
buttons: buttons,
partials: game.JTCS.templates,
value: "",
});
},
showInstructions: async (event, options = {}) => {
const { html, type, isDefault, missing, frameId, tileID } = options;
const areVisible = await HelperFunctions.getSettingValue(
"areConfigInstructionsVisible"
);
const instructionsElement = html.find("#JTCS-config-instructions");
const isLeave =
event.type === "mouseleave" || event.type === "mouseout" ? true : false;
if ((!instructionsElement && !isLeave) || !areVisible) {
//if the instructions element already exists and we're mousing over, or the instruction visibility has been toggled off
//return
return;
}
let instructionsContent = "<div class='instructions__content JTCS-hidden'>";
// add different instruction content depending on the tile's type (art or frame), whether it's unlinked/missing, and whether, if it's an art tile, it's currently set to the default art tile.
const defaultVariantText = isDefault ? "<em>another</em>" : "this";
switch (type) {
case "art":
instructionsContent += `<p id="isArtTile">
${isDefault ? "This art tile is set as Default." : ""}
<code>Ctr + Click</code> on ${defaultVariantText} <span class="art-color">Art Tile</span> to set it to <span class='default-color'>Default</span>.
<br/>
If you don't specify where a Sheet Image will display, it will automatically display on the <span class="default-color">"Default"</span>
<span class="art-color">Art Tile</span> in a scene.
</p>`;
break;
case "frame":
if (!missing) {
instructionsContent += `<p id="isFrameTile"><span class="frame-color">Frame tiles</span> act as "boundaries" for <span class="art-color">Art Tiles</span>, like a 'picture frame'. <br/>
When you link an <span class="art-color">Art Tile</span> to a <span class="frame-color">Frame tile</span>, the <span class="art-color">Art Tile</span> will get no larger than the <span class="frame-color">Frame Tile</span>.</p>`;
}
break;
}
if (missing) {
const tileName = await ArtTileManager.getGalleryTileDataFromID(
tileID,
"displayName"
);
let suffix = `<span class='${type}-color'>${HelperFunctions.capitalizeEachWord(
type
)} Tile "${tileName}"</span>`;
instructionsContent += `<p id="missing">This <span class='${type}-color'>${HelperFunctions.capitalizeEachWord(
type
)} Tile</span> tile is <b>unlinked</b> to any tile on the canvas in this scene.</p>
<ul>
<li>Click on <i class="fas fa-plus"></i> to add a new Tile object to the canvas, linked to ${suffix}</li>
<li>Click on <i class="fas fa-link"></i> to link a pre-existing Tile object on the canvas to ${suffix}</li>
</ul>
`;
}
if (type === "art" && !frameId)
instructionsContent += `<p id="noFrameTile">This <span class="art-color">Art Tile</span> will be bound by the scene's canvas.</p>`;
else if (type === "art" && frameId) {
const frameTileName = await ArtTileManager.getGalleryTileDataFromID(
frameId,
"displayName"
);
instructionsContent += `<p id="hasFrameTile">This <span class="art-color">Art Tile</span> will be bound by frame tile <span class="frame-color">${frameTileName}</span> </p>`;
}
instructionsContent += "</div>";
let content = instructionsElement.find(".instructions__content");
instructionsElement.contentHidden = true;
if (!isLeave) {
content.replaceWith(`${instructionsContent}`);
let element = instructionsElement[0];
UIA.toggleShowAnotherElement(event, {
parentItem: element,
targetClassSelector: "instructions__content",
fadeIn: false,
});
} else {
if (!instructionsElement.contentHidden) {
instructionsElement.contentHidden = true;
}
if (instructionsElement.timeout) {
clearTimeout(instructionsElement.timeout);
}
instructionsElement.timeout = setTimeout(async () => {
await UIA.fade(content, {
duration: 200,
isFadeOut: true,
onFadeOut: async () => {
content.replaceWith(
`<div class="instructions__content JTCS-hidden"></div>`
);
instructionsElement.contentHidden = true;
// content.addClass("JTCS-hidden");
},
});
}, 300);
}
},
toggleInstructionsVisible: async (event, options = {}) => {
let areVisible = await HelperFunctions.getSettingValue(
"areConfigInstructionsVisible"
);
await HelperFunctions.setSettingValue(
"areConfigInstructionsVisible",
!areVisible
);
UIA.toggleActiveStyles(event);
},
/**
* Lower the opacity of every other tile in the scene, to see this one more clearly
* This is disabled in v10, as the indicators are visible regardless
* @param {HTMLEvent} event - the triggering event
* @param {Object options - an options object
* @param {String} options.tileID - the ID of the Art Gallery tile we're operating upon
*/
toggleTilesOpacity: async (event, options = {}) => {
const { tileID } = options;
const btn = event.currentTarget;
const clickAction = btn.dataset.action;
const removeFade = btn.classList.contains("active") ? true : false;
const alphaValue = removeFade ? 1.0 : 0.5;
//get other buttons from other Tile Items that may be set to active, and so we can toggle them off
let otherToggleFadeButtons = btn
.closest(".tilesInScene")
.querySelectorAll(`[data-action='${clickAction}'].active`);
//filter any button that has the same parent tile item out
otherToggleFadeButtons = Array.from(otherToggleFadeButtons).filter(
(fadeBtn) => fadeBtn.closest(".tile-list-item").dataset.id !== tileID
);
const otherTiles = game.scenes.viewed.tiles.contents.filter(
(tile) => tile.id !== tileID
);
//check for game version
if (game.version >= 10) {
let update = otherTiles.map((data) => {
return {
_id: data.id,
alpha: alphaValue,
};
});
update.push({ _id: tileID, alpha: 1.0 });
await game.scenes.viewed.updateEmbeddedDocuments("Tile", update);
} else {
otherTiles.forEach((tile) => {
tile.object.alpha = alphaValue;
});
const ourTile = game.scenes.viewed.tiles.get(tileID);
ourTile.object.alpha = 1.0;
}
//toggle this button active
if (otherToggleFadeButtons.length > 0) {
UIA.clearOtherActiveStyles(
event,
btn,
`[data-action='${clickAction}']`,
".tilesInScene"
);
}
UIA.toggleActiveStyles(event);
//toggle any other active buttons to be inactive
// Array.from(otherToggleFadeButtons).forEach((el) => UIA.toggleActiveStyles(event, el));
},
toggleSheetOpacity: async (event, options = {}) => {
UIA.fadeSheetOpacity(event);
UIA.toggleActiveStyles(event);
},
};
export const slideshowDefaultSettingsData = {
globalActions: {
click: {
propertyString: "globalActions.click.actions",
actions: {
showURLShareDialog: {
icon: "fas fa-external-link-alt",
tooltipText: "Share a URL link with your players",
onClick: extraActions.showURLShareDialog,
},
showModuleSettings: {
icon: "fas fa-cog",
tooltipText: "Open JTCS Art Gallery Settings",
onClick: (event, options = {}) => {
UIA.renderAnotherApp("JTCSSettingsApp", JTCSSettingsApplication);
},
},
toggleInstructionsVisible: {
icon: "fas fa-eye-slash",
tooltipText: "toggle instruction visibility",
renderedInTemplate: true,
onClick: async (event, options) =>
await extraActions.toggleInstructionsVisible(event, options),
},
toggleSheetOpacity: {
icon: "fas fa-eye-slash",
tooltipText: "fade this application to better see the canvas",
onClick: async (event, options) =>
extraActions.toggleSheetOpacity(event, options),
},
// showArtScenes: {
// icon: "fas fa-map",
// tooltipText: "Show art scenes",
// onClick: async (event, options = {}) => {
// //display the art scenes (scenes that currently have slideshow data)
// let artScenes = await ArtTileManager.getAllScenesWithSlideshowData();
// let chosenArtScene = await HelperFunctions.getSettingValue(
// "artGallerySettings",
// "dedicatedDisplayData.scene.value"
// );
// let artSceneItems = {};
// artScenes.forEach((scene) => {
// artSceneItems[scene.name] = {
// icon: scene.thumbnail,
// dataset: {},
// };
// });
// let context = {
// propertyString: "globalActions.click.actions",
// items: artSceneItems,
// };
// let templateData = Popover.createTemplateData(parentLI, "item-menu", context);
// let elementData = { ...Popover.defaultElementData };
// elementData["popoverElement"] = {
// targetElement: null,
// hideEvents: [
// {
// eventName: "change",
// selector: "input",
// wrapperFunction: async (event) => {
// let url = event.currentTarget.value;
// let valid = HelperFunctions.manager.validateInput(url, "image");
// if (valid) {
// await ImageDisplayManager.updateTileObjectTexture(
// tileID,
// frameTileID,
// url,
// "anyTile"
// );
// } else {
// ui.notifications.error("URL not an image");
// //TODO: show error?
// }
// },
// },
// ],
// };
// let popover = await Popover.processPopoverData(
// event.currentTarget,
// app.element,
// templateData,
// elementData
// );
// popover[0].querySelector("input").focus({ focusVisible: true });
// },
// },
// showArtSheets: {},
createNewTileData: {
icon: "fas fa-plus",
tooltipText: "Create new tile data",
renderedInTemplate: true,
onClick: async (event, options) =>
await extraActions.updateTileData(event, options),
},
},
},
change: {
propertyString: "globalActions.change.actions",
actions: {
setArtScene: {
onChange: async (event, options = {}) => {
let { app } = options;
let value = event.currentTarget.value;
await HelperFunctions.setSettingValue(
"artGallerySettings",
value,
"dedicatedDisplayData.scene.value"
);
await app.renderWithData();
},
},
setArtJournal: {
onChange: async (event, options = {}) => {
let { app } = options;
let value = event.currentTarget.value;
await HelperFunctions.setSettingValue(
"artGallerySettings",
value,
"dedicatedDisplayData.journal.value"
);
await app.renderWithData();
},
},
},
},
hover: {
actions: {},
},
},
itemActions: {
change: {
propertyString: "itemActions.change.actions",
actions: {
setLinkedTile: {
onChange: async (event, options = {}) => {
let { app, tileID, targetElement } = options;
if (!targetElement) targetElement = event.currentTarget;
if (!app) app = game.JTCSlideshowConfig;
let selectedID = targetElement.value;
await ArtTileManager.updateTileDataID(tileID, selectedID);
if (app.rendered) {
await app.renderWithData();
}
},
},
setFrameTile: {
onChange: async (event, options) =>
await extraActions.updateTileData(event, options),
},
setDisplayName: {
onChange: async (event, options) => {
//validate the input first
let isValid = await UIA.validateInput(event, {
noWhitespaceStart: {
notificationType: "danger",
message:
"Please enter a name that doesn't start with a white space",
},
});
if (isValid) {
await extraActions.updateTileData(event, options);
}
},
},
shareURL: {
onChange: async (event, options = {}) => {
const { tileID, parentLI } = options;
const frameTileID = parentLI.dataset.frameId;
const url = event.currentTarget.value;
const valid = HelperFunctions.validateInput(url, "image");
if (valid) {
await ImageDisplayManager.updateTileObjectTexture(
tileID,
frameTileID,
url,
"anyScene"
);
} else {
ui.notifications.error("URL not an image");
}
},
},
},
},
hover: {
propertyString: "itemActions.hover.actions",
actions: {
highlightTile: {
onHover: async (event, options = {}) => {
let isLeave =
event.type === "mouseout" || event.type === "mouseleave";
let { targetElement } = options;
if (!targetElement) targetElement = event.currentTarget;
if (targetElement.tagName === "LABEL") {
targetElement = targetElement.previousElementSibling;
}
let tileID = targetElement.dataset.id;
let tile = await ArtTileManager.getTileObjectByID(tileID);
if (!isLeave) {
await game.JTCS.indicatorUtils.showTileIndicator(tile);
} else {
await game.JTCS.indicatorUtils.hideTileIndicator(tile);
}
},
},
highlightItemAndTile: {
//TODO: refactor the name of this property to include the "showInstructions" method
onHover: async (event, options = {}) => {
const dataset = $(options.parentLI).data();
await extraActions.highlightItemAndTile(event, {
...options,
...dataset,
});
await extraActions.showInstructions(event, {
...options,
...dataset,
});
},
},
},
},
click: {
//for buttons
propertyString: "itemActions.click.actions",
actions: {
setAsDefault: {
onClick: async (event, options = {}) => {
await extraActions.setDefaultTileInScene(event, options);
},
renderNever: true,
},
shareURLOnTile: {
icon: "fas fa-external-link-alt",
tooltipText: "Share image from a url on this tile",
onClick: async (event, options = {}) => {
let { tileID, parentLI, app, html } = options;
let frameTileID = parentLI.dataset.frameId;
let context = {
name: "shareUrl",
id: "shareURL",
changeAction: "itemActions.change.actions.shareURL",
label: "Share URL",
};
let templateData = Popover.createTemplateData(
parentLI,
"input-with-error",
context
);
let elementData = { ...Popover.defaultElementData };
elementData["popoverElement"] = {
targetElement: null,
// hideEvents: [
// {
// eventName: "change",
// selector: "input",
// wrapperFunction: async (event) => {
// let url = event.currentTarget.value;
// let valid = HelperFunctions.manager.validateInput(url, "image");
// if (valid) {
// await ImageDisplayManager.updateTileObjectTexture(
// tileID,
// frameTileID,
// url,
// "anyScene"
// );
// } else {
// ui.notifications.error("URL not an image");
// }
// },
// },
// ],
};
let popover = await Popover.processPopoverData(
// event.currentTarget,
event.target,
app.element,
templateData,
elementData
);
popover[0].querySelector("input").focus({ focusVisible: true });
await app.activateListeners(app.element);
},
overflow: false,
artTileOnly: true,
},
createNewGalleryTile: {
icon: "fas fa-plus",
tooltipText:
"Create a new tile object on the canvas in this scene, linked to this art gallery item",
overflow: false,
renderOnMissing: true,
onClick: async (event, options = {}) => {
let { tileID, parentLI, app } = options;
let isFrameTile = parentLI.dataset.type === "frame";
await ArtTileManager.createAndLinkSceneTile({
unlinkedDataID: tileID,
isFrameTile: isFrameTile,
});
await app.renderWithData();
},
},
showUnlinkedTiles: {
icon: "fas fa-link",
tooltipText:
"Show tiles objects on canvas that aren't linked to any art or frame tile data",
onClick: async (event, options = {}) => {
let { app, tileID, parentLI } = options;
let frameTileID;
if (!frameTileID) frameTileID = parentLI.dataset.frameId;
let artTileDataArray =
await ArtTileManager.getSceneSlideshowTiles("", true);
let unlinkedTilesIDs = await ArtTileManager.getUnlinkedTileIDs(
artTileDataArray
);
let context = {
artTileDataArray: artTileDataArray,
unlinkedTilesIDs: unlinkedTilesIDs,
};
let templateData = Popover.createTemplateData(
parentLI,
"tile-link-partial",
context
);
let elementData = { ...Popover.defaultElementData };
// elementData["popoverElement"].hideEvents.push({
// eventName: "change",
// selector: "input, input + label",
// wrapperFunction: async (event) => {},
// });
// -- RENDER THE POPOVER
let popover = await Popover.processPopoverData(
event.target,
app.element,
templateData,
elementData
);
await app.activateListeners(app.element);
popover[0].querySelector("input").focus({ focusVisible: true });
return;
},
overflow: false,
renderOnMissing: true,
},
toggleTilesOpacity: {
icon: "fas fa-clone",
tooltipText: "fade out other tiles in scene to better see this one",
onClick: async (event, options = {}) =>
extraActions.toggleTilesOpacity(event, options),
v9Only: true,
},
// the overflow menu should be last
toggleOverflowMenu: {
icon: "fas fa-ellipsis-v",
tooltipText: "show menu of extra options for this art tile",
overflow: false,
renderAlways: true,
onClick: async (event, options = {}) => {
const { app, tileID, parentLI } = options;
if (!tileID) tileID = parentLI.dataset.tileID;
const type = parentLI.dataset.type;
const parentItemMissing = parentLI.dataset.missing ? true : false;
const actions =
slideshowDefaultSettingsData.itemActions.click.actions;
let overflowActions = {};
for (let actionKey in actions) {
let { overflow, renderOnMissing, renderAlways, artTileOnly } =
actions[actionKey];
if (!renderOnMissing) renderOnMissing = false; //if render on missing is undefined, set it to false
const shouldRender = renderOnMissing === parentItemMissing; //fif the parent item's missing status and the button's conditional rendering status are equal
const mismatchedTypes = type === "frame" && artTileOnly; //if the item should only render on an art tile
if (
overflow &&
(shouldRender || renderAlways) &&
!mismatchedTypes
) {
//if it's an action to renderon the overflow menu
overflowActions[actionKey] = actions[actionKey];
}
}
const context = {
propertyString: "itemActions.click.actions",
items: overflowActions,
};
let templateData = Popover.createTemplateData(
parentLI,
"item-menu",
context
);
const elementData = { ...Popover.defaultElementData };
let popover = await Popover.processPopoverData(
event.target,
app.element,
templateData,
elementData
);
await app.activateListeners(app.element);
popover.focus({ focusVisible: true });
},
},
//overflow menu items
selectTile: {
text: "Select tile object",
tooltipText: "Select the tile object in this scene",
icon: "fas fa-vector-square",
overflow: true,
renderOnMissing: false,
onClick: async (event, options = {}) =>
await extraActions.selectTile(event, options),
},
fitTileToFrame: {
icon: "fas fa-expand",
tooltipText: "Fit this art tile to its frame",
onClick: async (event, options = {}) => {
const { parentLI, tileID } = options;
const { type, frameId } = $(parentLI).data();
if (type === "art") {
let path;
if (game.version >= 10) {
path = game.scenes.viewed.tiles.get(tileID).texture.src;
} else {
path = game.scenes.viewed.tiles.get(tileID).data.img;
}
await ImageDisplayManager.updateTileObjectTexture(
tileID,
frameId,
path,
"anyScene"
);
}
},
overflow: true,
artTileOnly: true,
},
renderTileConfig: {
text: "Render tile object config",
tooltipText:
"Render the config for the tile object linked to this tile",
icon: "fas fa-cog",
overflow: true,
onClick: async (event, options = {}) =>
await extraActions.renderTileConfig(event, options),
renderOnMissing: false,
},
clearTileImage: {
icon: "fas fa-times-circle",
text: "Clear Tile Image",
tooltipText:
"'Clear' this tile's image, or reset it to your chosen default",
overflow: true,
onClick: async (event, options = {}) => {
let { tileID } = options;
// let tileID = parentElement.dataset.id;
await ImageDisplayManager.clearTile(tileID);
},
extraClass: "danger-text",
},
// bringTileToFront: {
// text: "Bring tile to front",
// tooltipText: "Bring the linked tile to the front"
// icon: "fas fa-arrow-to-top",
// },
deleteTileData: {
icon: "fas fa-trash",
tooltipText: `delete this" this.type "tile data?" "<br/>"
"(this will not delete the tile object in the scene itself)`,
overflow: true,
renderAlways: true,
extraClass: "danger-text",
onClick: async (event, options = {}) =>
extraActions.deleteTileData(event, options),
},
},
},
},
};