Move away from an enricher in favour of the chatMessage hook handling (closes #23)
This commit is contained in:
parent
97f8e293d2
commit
064b4c1304
1 changed files with 64 additions and 61 deletions
|
|
@ -3,8 +3,6 @@ import { __ID__ } from "../consts.mjs";
|
||||||
import { Logger } from "../utils/Logger.mjs";
|
import { Logger } from "../utils/Logger.mjs";
|
||||||
import { preventTweakRegistration } from "../utils/preRegisterTweak.mjs";
|
import { preventTweakRegistration } from "../utils/preRegisterTweak.mjs";
|
||||||
|
|
||||||
// const { DialogV2 } = foundry.applications.api;
|
|
||||||
|
|
||||||
const key = `chatImageLinks`;
|
const key = `chatImageLinks`;
|
||||||
const IMAGE_TYPES = [
|
const IMAGE_TYPES = [
|
||||||
`png`,
|
`png`,
|
||||||
|
|
@ -18,6 +16,9 @@ export function chatImageLinks() {
|
||||||
status[key] = SettingStatusEnum.Unknown;
|
status[key] = SettingStatusEnum.Unknown;
|
||||||
if (preventTweakRegistration(key)) { return };
|
if (preventTweakRegistration(key)) { return };
|
||||||
|
|
||||||
|
/** @type {number|null} */
|
||||||
|
let hookID = null;
|
||||||
|
|
||||||
// #region Registration
|
// #region Registration
|
||||||
Logger.log(`Registering setting: ${key}`);
|
Logger.log(`Registering setting: ${key}`);
|
||||||
game.settings.register(__ID__, key, {
|
game.settings.register(__ID__, key, {
|
||||||
|
|
@ -28,6 +29,13 @@ export function chatImageLinks() {
|
||||||
default: true,
|
default: true,
|
||||||
config: true,
|
config: true,
|
||||||
requiresReload: true,
|
requiresReload: true,
|
||||||
|
onChange: (newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
hookID = Hooks.on(`chatMessage`, chatMessageHandler);
|
||||||
|
} else if (hookID != null) {
|
||||||
|
Hooks.off(`chatMessage`, hookID);
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
game.settings.register(__ID__, key + `-showPromptAgain`, {
|
game.settings.register(__ID__, key + `-showPromptAgain`, {
|
||||||
|
|
@ -40,76 +48,71 @@ export function chatImageLinks() {
|
||||||
|
|
||||||
// #region Implementation
|
// #region Implementation
|
||||||
if (game.settings.get(__ID__, key)) {
|
if (game.settings.get(__ID__, key)) {
|
||||||
Logger.log(`setting:${key} | Adding text enricher`);
|
Logger.log(`setting:${key} | Adding chat message listener`);
|
||||||
|
Hooks.on(`chatMessage`, chatMessageHandler);
|
||||||
// MARK: Enricher
|
|
||||||
const pattern = new RegExp(
|
|
||||||
`(?<!=|")(image:\\/\\/.*\\.(?:${IMAGE_TYPES.join(`|`)}))`,
|
|
||||||
`gi`,
|
|
||||||
);
|
|
||||||
|
|
||||||
CONFIG.TextEditor.enrichers.push({
|
|
||||||
pattern,
|
|
||||||
replaceParent: true,
|
|
||||||
enricher: async (url) => {
|
|
||||||
Logger.debug(url);
|
|
||||||
url = url[0].replace(/^image:\/\//, ``);
|
|
||||||
const secure = `https://${url}`;
|
|
||||||
const insecure = `http://${url}`;
|
|
||||||
|
|
||||||
if (await isAcceptableImage(secure)) {
|
|
||||||
const img = document.createElement(`img`);
|
|
||||||
img.src = secure;
|
|
||||||
img.alt = secure;
|
|
||||||
return img;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (await isAcceptableImage(insecure)) {
|
|
||||||
const img = document.createElement(`img`);
|
|
||||||
img.src = insecure;
|
|
||||||
img.alt = insecure;
|
|
||||||
return img;
|
|
||||||
};
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// MARK: Chat Input
|
|
||||||
// Hooks.on(`chatMessage`, (chatLog, message, options) => {
|
|
||||||
// if (!game.settings.get(__ID__, key)) { return };
|
|
||||||
|
|
||||||
// const match = message.match(pattern);
|
|
||||||
// if (!match) { return };
|
|
||||||
|
|
||||||
// DialogV2.wait({
|
|
||||||
// rejectClose: false,
|
|
||||||
// content: game.i18n.localize(`OFT.dialogs.chatImageLinks.didYouKnowImageLink`),
|
|
||||||
// buttons: [
|
|
||||||
// { action: ``, label: `OFT.dialogs.chatImageLinks.convertAndDontShowAgain` },
|
|
||||||
// { action: ``, label: `OFT.dialogs.chatImageLinks.justConvert` },
|
|
||||||
// { action: ``, label: `OFT.dialogs.chatImageLinks.ignoreAndDontShowAgain` },
|
|
||||||
// { action: ``, label: `OFT.dialogs.chatImageLinks.disableEntirely` },
|
|
||||||
// ],
|
|
||||||
// })
|
|
||||||
// .then((selected) => {
|
|
||||||
// chatLog.processMessage(message, options);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
// #endregion Implementation
|
// #endregion Implementation
|
||||||
|
|
||||||
status[key] = SettingStatusEnum.Registered;
|
status[key] = SettingStatusEnum.Registered;
|
||||||
};
|
};
|
||||||
|
|
||||||
// #region Helpers
|
// #region Helpers
|
||||||
|
const pattern = new RegExp(
|
||||||
|
`https?:\\/\\/\\S*\\.(?:${IMAGE_TYPES.join(`|`)})`,
|
||||||
|
`gi`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// MARK: Mutate & Resend
|
||||||
|
const handled = new Set();
|
||||||
|
async function mutateAndResendMessage(chatLog, message, options) {
|
||||||
|
const match = message.match(pattern);
|
||||||
|
if (!match) { return };
|
||||||
|
|
||||||
|
const validMatches = new Set();
|
||||||
|
|
||||||
|
const matches = message.match(pattern);
|
||||||
|
for (const match of matches) {
|
||||||
|
if (await isAcceptableImage(match)) {
|
||||||
|
validMatches.add(match);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
message = message.replaceAll(
|
||||||
|
pattern,
|
||||||
|
(url) => {
|
||||||
|
if (!validMatches.has(url)) {
|
||||||
|
return url;
|
||||||
|
};
|
||||||
|
return `<img src="${url}" alt="${url}">`;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
handled.add(message);
|
||||||
|
chatLog.processMessage(message, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
// MARK: Chat Message
|
||||||
|
/**
|
||||||
|
* Must be synchronous since it is a hook handler, but the mutation +
|
||||||
|
* resending can be done asynchronously since it doesn't matter how
|
||||||
|
* long it takes.
|
||||||
|
*/
|
||||||
|
function chatMessageHandler(chatLog, message, options) {
|
||||||
|
if (!game.settings.get(__ID__, key)) { return };
|
||||||
|
if (handled.has(message)) { return };
|
||||||
|
mutateAndResendMessage(chatLog, message, options);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// MARK: isAcceptableImage
|
||||||
async function isAcceptableImage(url) {
|
async function isAcceptableImage(url) {
|
||||||
|
if (!URL.canParse(url)) { return false };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, { method: `HEAD` });
|
const response = await fetch(url, { method: `HEAD` });
|
||||||
const contentType = response.headers.get(`Content-Type`);
|
const contentType = response.headers.get(`Content-Type`);
|
||||||
Logger.debug(`Image data:`, { url, contentType });
|
Logger.debug(`Image data:`, { url, contentType });
|
||||||
|
|
||||||
let [ superType, subtype ] = contentType.split(`/`);
|
let [ superType, subtype ] = contentType.split(`/`);
|
||||||
if (superType !== `image`) {
|
if (superType !== `image`) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue