journal-to-canvas-slideshow/scripts/SheetImageApp.js

316 lines
12 KiB
JavaScript
Raw Normal View History

2024-01-28 15:59:53 -06:00
"use strict";
import { log } from "./debug-mode.js";
import { HelperFunctions } from "./classes/HelperFunctions.js";
import { sheetImageActions, sheetControls } from "./SheetImageActions.js";
import { SheetImageDataController } from "./SheetImageDataController.js";
import { artTileManager, helpers } from "./data/ModuleManager.js";
import { ArtTileManager } from "./classes/ArtTileManager.js";
import { universalInterfaceActions } from "./data/Universal-Actions.js";
export class SheetImageApp {
static displayMethods = [
{
name: "anyScene",
icon: "fas fa-vector-square",
tooltip: "choose Art Tile in current scene to display image on",
},
{
name: "window",
icon: "fas fa-external-link-alt",
tooltip: "Display image in pop-out window",
},
{
name: "journalEntry",
icon: "fas fa-book-open",
tooltip: "display image in your chosen 'Art Journal'",
},
{
name: "artScene",
icon: "far fa-image",
tooltip: "display image in your chosen 'Art Scene'",
},
];
/**
*
* @param {*} app - the application (sheet) that this is being called from
* @param {*} html
*/
static async applyImageClasses(app, html) {
if (game.user.isGM) {
const whichSheets = await HelperFunctions.getSettingValue(
"artGallerySettings",
"sheetSettings.modularChoices"
);
const doc = app.document;
let onThisSheet = await HelperFunctions.getFlagValue(
doc,
"showControls",
"",
false
);
let documentName = doc.documentName;
documentName = documentName.charAt(0).toLowerCase() + documentName.slice(1);
// if (documentName === "item" && doc.parent) {
// //if it's an embedded item in a sheet
// return;
// }
// for v10 +
if (game.version >= 10) {
if (documentName === "journalEntryPage") {
documentName = "journalEntry";
onThisSheet = await HelperFunctions.getFlagValue(
doc.parent,
"showControls",
"",
false
);
}
}
let selectorString = "img, video, .lightbox-image";
if (whichSheets[documentName] || onThisSheet === true) {
if (onThisSheet) {
if (documentName === "journalEntry" && game.version < 10) {
html.find(selectorString).addClass("clickableImage");
} else {
html.find(selectorString).addClass("rightClickableImage");
}
//inject the controls into every image that has the clickableImage or rightClickableImage classes
Array.from(
html.find(".clickableImage, .rightClickableImage")
).forEach((img) => SheetImageApp.injectImageControls(img, app));
}
}
if (doc.documentName !== "JournalEntryPage") {
SheetImageApp.injectSheetWideControls(app);
}
}
}
static async applySheetFadeSettings(journalSheet) {
//get opacity, and whether or not journals should be faded
let opacityValue = (
await game.JTCS.utils.getSettingValue(
"artGallerySettings",
"sheetFadeOpacityData"
)
).value;
let shouldFadeImages = (
await game.JTCS.utils.getSettingValue(
"artGallerySettings",
"fadeSheetImagesData"
)
).chosen;
//set a CSS variable on the journal sheet to grab the opacity in css
let sheetElement = journalSheet.element;
sheetElement[0].style.setProperty("--journal-fade", opacityValue + "%");
//set the window content's data-attribute to "data-fade-all" so it fades the journal's opacity, and not just the background color
if (shouldFadeImages === "fadeAll") {
sheetElement.find(".window-content").attr("data-fade-all", true);
// sheetElementStyle.setProperty("--fade-all", true);
}
}
/**
* When the journal sheet renders, we're going to add controls over each image
* @param {HTMLElement} imgElement - the image HTML element
* @param {*} journalSheet - the journal sheet we're searching within
*/
static async injectImageControls(imgElement, journalSheet) {
let template = "modules/journal-to-canvas-slideshow/templates/image-controls.hbs";
// game.JTCS.templates["image-controls"]
const defaultArtTileID = await ArtTileManager.getDefaultArtTileID();
const imageName = await SheetImageDataController.convertImageSourceToID(
imgElement
);
imgElement.dataset.name = imageName;
//get the art tiles in the scene
let displayTiles = await ArtTileManager.getSceneSlideshowTiles("art", true);
displayTiles = displayTiles.filter((tile) => !tile.missing);
displayTiles = displayTiles.map((tile) => {
return {
tile: tile,
randomID: foundry.utils.randomID(),
};
});
let users = game.users.contents;
let renderHtml = await renderTemplate(template, {
currentSceneName: game.scenes.viewed.name,
displayMethods: SheetImageApp.displayMethods,
displayTiles: displayTiles,
defaultArtTileID: defaultArtTileID,
imgPath: imageName,
users: users,
// ...imageFlagData,
});
//wrap each image in a clickableImageContainer
$(imgElement).wrap("<div class='clickableImageContainer'></div>");
$(imgElement).parent().append(renderHtml);
await SheetImageApp.activateImageEventListeners({
controlsContainer: $(imgElement).parent(),
journalSheet: journalSheet,
imgElement: imgElement,
});
}
static async injectSheetWideControls(journalSheet) {
let template = game.JTCS.templates["sheet-wide-controls"];
await SheetImageApp.applySheetFadeSettings(journalSheet);
let isActive = await HelperFunctions.getFlagValue(
journalSheet.document,
"showControls",
"",
false
);
let controlsData = sheetControls.map((control) =>
control.toggle ? { ...control, active: isActive } : control
);
let renderHtml = await renderTemplate(template, {
controls: controlsData,
isActive,
});
let selector = ".window-content";
if (journalSheet.document.documentName === "JournalEntryPage") {
selector = ".journal-page-content";
}
let $editorElement = $(journalSheet.element[0].querySelector(selector));
$editorElement.prepend(renderHtml);
let controlsContainer = $("#sheet-controls");
await SheetImageApp.activateSheetWideEventListeners({
controlsContainer,
journalSheet,
isActive,
});
}
static async activateSheetWideEventListeners(options) {
const { journalSheet, isActive } = options;
const controlsContainer = journalSheet.element.find("#sheet-controls");
$(controlsContainer)
.off("click", "[data-action]")
.on("click", "[data-action]", async (event) => {
SheetImageApp.handleAction(event, journalSheet, "action", false);
});
const controlsToggleButton = $(controlsContainer).find(
"[data-action='sheet.click.toggleImageControls']"
)[0];
if (isActive) {
$(controlsToggleButton).addClass("active");
}
universalInterfaceActions.toggleHideAllSiblings(null, controlsToggleButton);
}
// handle any interaction event
static async handleAction(event, journalSheet, actionType = "action", isItem = true) {
event.preventDefault();
let targetElement = $(event.currentTarget);
let imgElement;
//"isItem" stands for if it's a sheet-wide control or an item-specific control
if (isItem) {
//if our target element is not an image, get the closest image from our clickableImageContainer parent
//else just get the current target itself
if (
targetElement.prop("nodeName") !== "IMG" ||
targetElement.prop("nodeName") !== "VIDEO"
) {
imgElement = targetElement[0]
.closest(".clickableImageContainer")
.querySelector("img, video");
} else {
imgElement = targetElement[0];
}
//if our target element is a label, get the input before it instead
targetElement.prop("nodeName") === "LABEL" &&
(targetElement = targetElement.prev());
}
let action = targetElement.data()[actionType];
let handlerPropertyString = "onClick";
switch (actionType) {
case "hoverAction":
handlerPropertyString = "onHover";
break;
case "changeAction":
handlerPropertyString = "onChange";
break;
}
let actionData = getProperty(sheetImageActions, action);
if (actionData && actionData.hasOwnProperty(handlerPropertyString)) {
//call the event handler stored on this object
let options = {
action: action,
app: journalSheet,
html: journalSheet.element,
...(imgElement && {
parentItem: imgElement.closest(".clickableImageContainer"),
}),
imgElement: imgElement,
};
actionData[handlerPropertyString](event, options);
}
}
/**
*
* @param data - the data object
*/
static async activateImageEventListeners(data) {
let { journalSheet, imgElement, controlsContainer } = data;
let html = journalSheet.element;
//add data actions to the images
$(imgElement).attr("data-hover-action", "image.hover.showTileIndicator");
$(imgElement).attr("data-action", "image.click.sendImageDataToDisplay");
$(controlsContainer)
.off("click contextmenu", "[data-action]")
.on(
"click contextmenu",
"[data-action]",
async (event) =>
await SheetImageApp.handleAction(event, journalSheet, "action")
);
$(controlsContainer)
.off("mouseenter mouseleave", "[data-hover-action]")
.on(
"mouseenter mouseleave",
"[data-hover-action]",
async (event) =>
await SheetImageApp.handleAction(event, journalSheet, "hoverAction")
);
$(controlsContainer)
.off("change", "[data-change-action]")
.on(
"change",
"[data-change-action]",
async (event) =>
await SheetImageApp.handleAction(event, journalSheet, "changeAction")
);
}
static async addFadeStylesToSheet(event) {
event.preventDefault();
let windowContent = event.currentTarget.closest(".window-content");
let faded =
windowContent.classList.contains("fade") ||
windowContent.classList.contains("fade-all");
if (faded) {
windowContent.classList.remove("fade");
} else {
windowContent.classList.add("fade");
}
}
}