{"version":3,"file":"main.js","mappings":"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","sources":["webpack:///../common/Settings.ts","webpack:///../common/libWrapperShared.ts","webpack:///./src/Util.ts","webpack:///./src/archive/DFChatArchive.ts","webpack:///./src/archive/DFChatArchiveManager.ts","webpack:///./src/archive/DFChatArchiveNew.ts","webpack:///./src/archive/DFChatArchiveViewer.ts","webpack:///./src/archive/df-chat-archive.ts","webpack:///./src/chat-time/chat-time.ts","webpack:///./src/edit/DFChatEditor.ts","webpack:///./src/edit/df-chat-edit.ts","webpack:///./src/font-size/font-size.ts","webpack:///./src/logger/DFAdventureLogConfig.ts","webpack:///./src/logger/DFAdventureLogProcessor.ts","webpack:///./src/logger/df-adventure-log.ts","webpack:///./src/merge/chat-merge.ts","webpack:///./src/player-color/PlayerColor.ts","webpack:///./src/privacy/df-chat-privacy.ts","webpack:///./src/scroll-manage/ChatHistoryOptimizer.ts","webpack:///./src/scroll-manage/scroll-manage.ts","webpack:///./src/send/send-button.ts","webpack:///./src/whisper-trunc/whisper-trunc.ts","webpack:///webpack/bootstrap","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///webpack/runtime/make namespace object","webpack:///./src/df-chat-enhance.ts"],"sourcesContent":["\ndeclare global {\n\tinterface LenientGlobalVariableTypes {\n\t\tgame: never;\n\t\tcanvas: never;\n\t}\n\tinterface String {\n\t\t/** Localizes the string via the global `game.i18n.localize()` function. */\n\t\tlocalize(): string\n\t}\n\ttype AnyFunction = (...args: any) => any;\n}\n\nexport default class SETTINGS {\n\tstatic MOD_NAME: string;\n\tstatic init(moduleName: string) {\n\t\tthis.MOD_NAME = moduleName;\n\t\tif (!String.prototype.localize) {\n\t\t\tString.prototype.localize = function () {\n\t\t\t\treturn game.i18n.localize(this.valueOf());\n\t\t\t};\n\t\t}\n\t}\n\tstatic register<T>(key: string, config: ClientSettings.PartialSettingConfig<T>) { game.settings.register(SETTINGS.MOD_NAME, key, config); }\n\tstatic registerMenu(key: string, config: ClientSettings.PartialSettingSubmenuConfig) { game.settings.registerMenu(SETTINGS.MOD_NAME, key, config); }\n\tstatic get<T>(key: string): T { return <T>game.settings.get(SETTINGS.MOD_NAME, key); }\n\tstatic async set<T>(key: string, value: T): Promise<T> { return await game.settings.set(SETTINGS.MOD_NAME, key, value); }\n\tstatic default<T>(key: string): T { return <T>game.settings.settings.get(SETTINGS.MOD_NAME + '.' + key).default; }\n\t/** helper for referencing a Typed constructor for the `type` field of a setting { type: SETTINGS.typeOf<MyClass>() } */\n\tstatic typeOf<T>(): ConstructorOf<T> { return Object as any; }\n}\n","import SETTINGS from \"./Settings\";\n\ntype Wrapper = (...args: any) => unknown;\ntype Handler = (wrapped: Wrapper, ...args: any) => unknown;\n\nclass Registration {\n\tnextId = 0;\n\twrappers = new Map<number, Handler>();\n\n\thandler(context: any, wrapped: Wrapper, ...args: any): Promise<unknown> | unknown {\n\t\tlet current = wrapped;\n\t\tfor (const wrapper of this.wrappers.values()) {\n\t\t\tconst next = current;\n\t\t\tcurrent = (...args: any) => wrapper.call(context, next, ...args);\n\t\t}\n\t\treturn current.call(context, ...args);\n\t}\n}\n\nexport default class libWrapperShared {\n\tprivate static registrations = new Map<string, Registration>();\n\n\tstatic register(target: string, handler: Handler) {\n\t\tlet registration = this.registrations.get(target);\n\t\tif (!registration) {\n\t\t\tregistration = new Registration();\n\t\t\tlibWrapper.register(SETTINGS.MOD_NAME, target,\n\t\t\t\tfunction (this: any, wrapped: Wrapper, ...args: any) { return registration.handler(this, wrapped, ...args); }, 'WRAPPER');\n\t\t\tthis.registrations.set(target, registration);\n\t\t}\n\t\tconst id = registration.nextId++;\n\t\tregistration.wrappers.set(id, handler);\n\t\treturn id;\n\t}\n\n\tstatic unregister(target: string, id: number): boolean {\n\t\tconst registration = this.registrations.get(target);\n\t\tif (!registration) return false;\n\t\tregistration.wrappers.delete(id);\n\t\tif (registration.wrappers.size === 0) {\n\t\t\tlibWrapper.unregister(SETTINGS.MOD_NAME, target, false);\n\t\t\tthis.registrations.delete(target);\n\t\t}\n\t\treturn true;\n\t}\n}","export default class UTIL {\n\tstatic async requestReload() {\n\t\tif (await Dialog.confirm({\n\t\t\ttitle: \"DF_CHAT_ENHANCE.ReloadGameTitle\".localize(),\n\t\t\tcontent: \"DF_CHAT_ENHANCE.ReloadGameContent\".localize(),\n\t\t\tdefaultYes: true\n\t\t})) {\n\t\t\twindow.location.reload();\n\t\t}\n\t}\n\n\tstatic reloadChatLog() {\n\t\t// @ts-expect-error\n\t\tui.chat._lastId = null;\n\t\tui.chat._state = Application.RENDER_STATES.NONE;\n\t\tui.chat.render(true);\n\t}\n}","import { ChatMessageData } from \"@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs\";\nimport SETTINGS from \"../../../common/Settings\";\n\nexport interface DFChatArchiveEntry {\n\tid: number;\n\tname: string;\n\tvisible: boolean;\n\tfilename: string;\n\tfilepath: string;\n}\n\n\nclass ArchiveFolderMenu extends FormApplication {\n\tstatic get defaultOptions() {\n\t\treturn mergeObject(FormApplication.defaultOptions as Partial<FormApplicationOptions>, {\n\t\t\twidth: 400,\n\t\t\theight: 125,\n\t\t\tresizable: false,\n\t\t\tminimizable: false,\n\t\t\ttitle: 'DF_CHAT_ARCHIVE.Settings.ArchiveFolder_Name',\n\t\t\ttemplate: \"modules/df-chat-enhance/templates/archive-folder.hbs\",\n\t\t\tsubmitOnClose: false,\n\t\t\tsubmitOnChange: false,\n\t\t\tcloseOnSubmit: true\n\t\t}) as FormApplicationOptions;\n\t}\n\n\tprivate folder = SETTINGS.get<string>(DFChatArchive.PREF_FOLDER);\n\tprivate source = SETTINGS.get<string>(DFChatArchive.PREF_FOLDER_SOURCE);\n\n\tgetData(_options: any): any {\n\t\treturn { path: this.folder };\n\t}\n\n\tasync _renderInner(data: any): Promise<JQuery<HTMLElement>> {\n\t\tconst html = await super._renderInner(data);\n\t\tconst input = html.find('input#dfce-ca-folder-path')[0] as HTMLInputElement;\n\t\thtml.find('label>button').on('click', async event => {\n\t\t\tevent.preventDefault();\n\t\t\tconst fp = new FilePicker(<any>{\n\t\t\t\ttitle: 'DF_CHAT_ARCHIVE.Settings.ArchiveFolder_Name',\n\t\t\t\ttype: 'folder',\n\t\t\t\tfield: input,\n\t\t\t\tcallback: async (path: string) => {\n\t\t\t\t\tthis.source = fp.activeSource;\n\t\t\t\t\tthis.folder = path;\n\t\t\t\t},\n\t\t\t\tbutton: event.currentTarget\n\t\t\t});\n\t\t\tawait fp.browse(SETTINGS.get(DFChatArchive.PREF_FOLDER));\n\t\t});\n\t\treturn html;\n\t}\n\tprotected async _updateObject() {\n\t\tawait SETTINGS.set<string>(DFChatArchive.PREF_FOLDER, this.folder);\n\t\tawait SETTINGS.set<string>(DFChatArchive.PREF_FOLDER_SOURCE, this.source);\n\t}\n}\n\nexport class DFChatArchive {\n\tprivate static readonly PREF_LOGS = 'logs';\n\tprivate static readonly PREF_CID = 'currentId';\n\tstatic readonly PREF_FOLDER = 'archiveFolder';\n\tstatic readonly PREF_FOLDER_SOURCE = 'archiveFolderSource';\n\tprivate static readonly PREF_FOLDER_MENU = 'archiveFolderMenu';\n\tprivate static _updateListener: () => void = null;\n\n\tprivate static get DATA_FOLDER(): FilePicker.SourceType { return SETTINGS.get(DFChatArchive.PREF_FOLDER_SOURCE); }\n\n\tstatic setUpdateListener(listener: () => void) {\n\t\tthis._updateListener = listener;\n\t}\n\n\tstatic registerSettings() {\n\t\tSETTINGS.register(this.PREF_LOGS, {\n\t\t\tscope: 'world',\n\t\t\tconfig: false,\n\t\t\ttype: Object,\n\t\t\tdefault: [],\n\t\t\tonChange: () => {\n\t\t\t\tif (this._updateListener != null)\n\t\t\t\t\tthis._updateListener();\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register(this.PREF_CID, {\n\t\t\tscope: 'world',\n\t\t\tconfig: false,\n\t\t\ttype: Number,\n\t\t\tdefault: 0\n\t\t});\n\n\t\tSETTINGS.registerMenu(this.PREF_FOLDER_MENU, {\n\t\t\tlabel: 'DF_CHAT_ARCHIVE.Settings.ArchiveFolder_Name',\n\t\t\thint: 'DF_CHAT_ARCHIVE.Settings.ArchiveFolder_Hint',\n\t\t\trestricted: true,\n\t\t\ttype: <any>ArchiveFolderMenu\n\t\t});\n\n\t\tSETTINGS.register(this.PREF_FOLDER, {\n\t\t\tscope: 'world',\n\t\t\tconfig: false,\n\t\t\ttype: String,\n\t\t\tdefault: `worlds/${game.world.id}/chat-archive`,\n\t\t\tonChange: async () => {\n\t\t\t\tawait this.createArchiveFolderIfMissing();\n\t\t\t\tif (this._updateListener != null)\n\t\t\t\t\tthis._updateListener();\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register(this.PREF_FOLDER_SOURCE, {\n\t\t\tscope: 'world',\n\t\t\tconfig: false,\n\t\t\ttype: String,\n\t\t\tdefault: 'data',\n\t\t});\n\t\tthis.createArchiveFolderIfMissing();\n\t}\n\n\tprivate static async createArchiveFolderIfMissing() {\n\t\tconst folder: string = SETTINGS.get(this.PREF_FOLDER);\n\t\tawait FilePicker.browse(this.DATA_FOLDER, folder)\n\t\t\t.catch(async _ => {\n\t\t\t\tif (!await FilePicker.createDirectory(this.DATA_FOLDER, folder, {}))\n\t\t\t\t\tthrow new Error('Could not access the archive folder: ' + folder);\n\t\t\t});\n\t}\n\n\tstatic getLogs(): DFChatArchiveEntry[] { return SETTINGS.get<DFChatArchiveEntry[]>(this.PREF_LOGS); }\n\tstatic getArchive(id: number): DFChatArchiveEntry { return this.getLogs().find(x => x.id == id); }\n\tstatic exists(id: number): boolean { return !!this.getLogs().find(x => x.id == id); }\n\n\tprivate static async _generateChatArchiveFile(id: number, name: string, chats: ChatMessage[] | ChatMessageData[], visible: boolean): Promise<DFChatArchiveEntry> {\n\t\t// Get the folder path\n\t\tconst folderPath = SETTINGS.get<string>(this.PREF_FOLDER);\n\t\t// Replace special characters in name to underscores\n\t\tconst safeName = name.replace(/[^ a-z0-9-_()[\\]<>]/gi, '_');\n\t\t// Generate the system safe filename\n\t\tconst fileName = encodeURI(`${id}_${safeName}.json`);\n\t\t// Create the File and contents\n\t\tconst file = new File([JSON.stringify(chats, null, '')], fileName, { type: 'application/json' });\n\t\tconst response: { path?: string; message?: string } = <any>await FilePicker.upload(this.DATA_FOLDER, folderPath, file);\n\t\tif (!response.path) {\n\t\t\tconsole.error(`Could not create archive ${fileName}\\nReason: ${response}`);\n\t\t\tthrow new Error('Could not upload the archive to server: ' + fileName);\n\t\t}\n\t\tconst entry: DFChatArchiveEntry = {\n\t\t\tid: id,\n\t\t\tname: name,\n\t\t\tvisible: visible,\n\t\t\tfilepath: response.path,\n\t\t\tfilename: fileName\n\t\t};\n\t\treturn entry;\n\t}\n\n\tstatic async createChatArchive(name: string, chats: ChatMessage[], visible: boolean): Promise<DFChatArchiveEntry> {\n\t\tconst newId = SETTINGS.get<number>(this.PREF_CID) + 1;\n\t\tSETTINGS.set(this.PREF_CID, newId);\n\t\tconst entry = await this._generateChatArchiveFile(newId, name, chats, visible);\n\t\tconst logs = SETTINGS.get<DFChatArchiveEntry[]>(this.PREF_LOGS);\n\t\tlogs.push(entry);\n\t\tawait SETTINGS.set(this.PREF_LOGS, logs);\n\t\tif (this._updateListener != null)\n\t\t\tthis._updateListener();\n\t\treturn entry;\n\t}\n\n\tstatic async getArchiveContents(archive: DFChatArchiveEntry): Promise<(ChatMessage | ChatMessageData)[]> {\n\t\tconst response = await fetch(archive.filepath);\n\t\tconst data = await response.json().catch(error => console.error(`Failed to read JSON for archive ${archive.filepath}\\n${error}`));\n\t\tif (response.ok)\n\t\t\treturn data as (ChatMessage | ChatMessageData)[];\n\t\telse\n\t\t\tthrow new Error('Could not access the archive from server side: ' + archive.filepath);\n\t}\n\n\tstatic async updateChatArchive(archive: DFChatArchiveEntry, newChatData?: (ChatMessage | ChatMessageData)[]): Promise<DFChatArchiveEntry> {\n\t\tif (!this.getLogs().find(x => x.id == archive.id))\n\t\t\tthrow new Error('Could not locate an archive for the given ID: ' + archive.id.toString());\n\t\t// If we are updating the contents of an archive\n\t\tif (newChatData) {\n\t\t\tconst folderPath = SETTINGS.get<string>(this.PREF_FOLDER);\n\t\t\tconst file = new File([JSON.stringify(newChatData)], archive.filename, { type: 'application/json' });\n\t\t\tconst response: {\n\t\t\t\tpath?: string;\n\t\t\t\tmessage?: string;\n\t\t\t} = <any>await FilePicker.upload(this.DATA_FOLDER, folderPath, file, {});\n\t\t\tif (!response.path)\n\t\t\t\tthrow new Error('Could not upload the archive to server side: ' + archive.id.toString());\n\t\t}\n\t\tconst logs = this.getLogs();\n\t\tconst idx = logs.findIndex(x => x.id === archive.id);\n\t\tif (idx < 0) return archive;\n\t\tlogs[idx] = archive;\n\t\tawait SETTINGS.set(DFChatArchive.PREF_LOGS, logs);\n\t\treturn archive;\n\t}\n\n\tstatic async deleteAll() {\n\t\tconst folderPath = SETTINGS.get<string>(this.PREF_FOLDER);\n\t\tconst logs = SETTINGS.get<DFChatArchiveEntry[]>(this.PREF_LOGS);\n\t\t// Can not delete files currently, truncate instead to make filtering easier.\n\t\tawait Promise.all(logs.map(archive => {\n\t\t\tconst file = new File([''], archive.filename, { type: 'application/json' });\n\t\t\treturn FilePicker.upload(this.DATA_FOLDER, folderPath, file, {});\n\t\t}));\n\t\tawait SETTINGS.set(this.PREF_LOGS, []);\n\t\tif (this._updateListener != null)\n\t\t\tthis._updateListener();\n\t}\n\n\tstatic async deleteChatArchive(id: number) {\n\t\tconst folderPath = SETTINGS.get<string>(this.PREF_FOLDER);\n\t\tconst logs = SETTINGS.get<DFChatArchiveEntry[]>(this.PREF_LOGS);\n\t\tconst entryIdx = logs.findIndex(x => x.id === id);\n\t\tif (entryIdx < 0) {\n\t\t\tconsole.error(`Could not find entry for ID#${id}`);\n\t\t\treturn;\n\t\t}\n\t\tconst entry = logs[entryIdx];\n\t\t// Cannot delete file currently, instead truncate the file and move along.\n\t\tconst file = new File([''], entry.filename, { type: 'application/json' });\n\t\tawait FilePicker.upload(this.DATA_FOLDER, folderPath, file, {});\n\t\tlogs.splice(entryIdx, 1);\n\t\tawait SETTINGS.set(this.PREF_LOGS, logs);\n\t\tif (this._updateListener != null)\n\t\t\tthis._updateListener();\n\t}\n}\n","import SETTINGS from \"../../../common/Settings\";\nimport { DFChatArchive } from \"./DFChatArchive\";\nimport DFChatArchiveViewer from \"./DFChatArchiveViewer\";\n\nexport default class DFChatArchiveManager extends Application {\n\tstatic readonly PREF_REVERSE_SORT = 'dfca-manager-reverseSort';\n\tstatic chatViewers: Map<number, DFChatArchiveViewer> = new Map();\n\n\tstatic get defaultOptions() {\n\t\treturn mergeObject(Application.defaultOptions as Partial<ApplicationOptions>, {\n\t\t\ttemplate: \"modules/df-chat-enhance/templates/archive-manager.hbs\",\n\t\t\tresizable: true,\n\t\t\tminimizable: true,\n\t\t\twidth: 300,\n\t\t\theight: 500,\n\t\t\ttitle: \"DF_CHAT_ARCHIVE.ArchiveManager_Title\".localize()\n\t\t}) as ApplicationOptions;\n\t}\n\n\tgetData(options?: any) {\n\t\tconst data = super.getData(options);\n\t\tlet messages = DFChatArchive.getLogs();\n\t\tif (!game.user.isGM)\n\t\t\tmessages = messages.filter(x => x.visible);\n\t\tmessages = messages.sort((a, b) => a.name.localeCompare(b.name));\n\t\tconst reverseSort = SETTINGS.get<boolean>(DFChatArchiveManager.PREF_REVERSE_SORT);\n\t\tmergeObject(data, {\n\t\t\tmessages: reverseSort ? messages.reverse() : messages,\n\t\t\tisGM: game.user.isGM,\n\t\t\treverseSort\n\t\t});\n\t\treturn data;\n\t}\n\n\tprivate _subscribeView(element: JQuery) {\n\t\telement.on('click', function () {\n\t\t\tconst id = parseInt($(this).attr('data-id'));\n\t\t\tif (isNaN(id) || !DFChatArchive.exists(id)) {\n\t\t\t\tui.notifications.error('DF_CHAT_ARCHIVE.ArchiveManager_ErrorBadId'.localize());\n\t\t\t\tthrow Error(`Invalid id for Chat Archive: '${$(this).attr('data-id')}'`);\n\t\t\t}\n\t\t\tif (DFChatArchiveManager.chatViewers.has(id)) {\n\t\t\t\tDFChatArchiveManager.chatViewers.get(id).bringToTop();\n\t\t\t} else {\n\t\t\t\tDFChatArchiveManager.chatViewers.set(id, new DFChatArchiveViewer(DFChatArchive.getArchive(id), view => {\n\t\t\t\t\tDFChatArchiveManager.chatViewers.delete(view.archive.id);\n\t\t\t\t}));\n\t\t\t\tDFChatArchiveManager.chatViewers.get(id).render(true);\n\t\t\t}\n\t\t});\n\t}\n\tprivate _subscribeDelete(element: JQuery) {\n\t\telement.on('click', async function () {\n\t\t\tconst id = parseInt($(this).attr('data-id'));\n\t\t\tif (isNaN(id) || !DFChatArchive.exists(id)) {\n\t\t\t\tui.notifications.error('DF_CHAT_ARCHIVE.ArchiveManager_ErrorBadId'.localize());\n\t\t\t\tthrow Error(`Invalid id for Chat Archive: '${$(this).attr('data-id')}'`);\n\t\t\t}\n\t\t\tconst archive = DFChatArchive.getArchive(id);\n\t\t\tawait Dialog.confirm({\n\t\t\t\ttitle: 'DF_CHAT_ARCHIVE.ArchiveManager_ConfirmDeleteArchiveTitle'.localize(),\n\t\t\t\tcontent: 'DF_CHAT_ARCHIVE.ArchiveManager_ConfirmDeleteArchiveContent'.localize().replace('{name}', archive.name),\n\t\t\t\tdefaultYes: false,\n\t\t\t\tyes: async () => await DFChatArchive.deleteChatArchive(id)\n\t\t\t});\n\t\t});\n\t}\n\n\tactivateListeners(html: JQuery) {\n\t\tDFChatArchive.setUpdateListener(this._archiveChanged.bind(this));\n\t\tif (DFChatArchive.getLogs().length > 0)\n\t\t\thtml.find('p.dfca-no-items').hide();\n\t\thtml.find('a[data-type=\"view\"]').each((i, element) => { this._subscribeView($(element)); });\n\t\thtml.find('a[data-type=\"delete\"]').each((i, element) => { this._subscribeDelete($(element)); });\n\t\thtml.find('#dfca-delete-all').on('click', async function () {\n\t\t\tawait Dialog.confirm({\n\t\t\t\ttitle: 'DF_CHAT_ARCHIVE.ArchiveManager_ConfirmDeleteAllTitle'.localize(),\n\t\t\t\tcontent: 'DF_CHAT_ARCHIVE.ArchiveManager_ConfirmDeleteAllMessage1'.localize(),\n\t\t\t\tdefaultYes: false,\n\t\t\t\tyes: async () => {\n\t\t\t\t\tawait Dialog.confirm({\n\t\t\t\t\t\ttitle: 'DF_CHAT_ARCHIVE.ArchiveManager_ConfirmDeleteAllTitle'.localize(),\n\t\t\t\t\t\tcontent: 'DF_CHAT_ARCHIVE.ArchiveManager_ConfirmDeleteAllMessage2'.localize(),\n\t\t\t\t\t\tdefaultYes: false,\n\t\t\t\t\t\tyes: async () => {\n\t\t\t\t\t\t\tawait DFChatArchive.deleteAll();\n\t\t\t\t\t\t\tui.notifications.info('DF_CHAT_ARCHIVE.ArchiveManager_ConfirmDeleteAllComplete'.localize());\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\tconst asc = html.find('#dfca-sort-asc');\n\t\tconst dsc = html.find('#dfca-sort-dsc');\n\t\tasc.on('click', async () => {\n\t\t\tawait SETTINGS.set(DFChatArchiveManager.PREF_REVERSE_SORT, true);\n\t\t\tasc.hide();\n\t\t\tdsc.show();\n\t\t\tthis.render();\n\t\t});\n\t\tdsc.on('click', async () => {\n\t\t\tawait SETTINGS.set(DFChatArchiveManager.PREF_REVERSE_SORT, false);\n\t\t\tdsc.hide();\n\t\t\tasc.show();\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tclose(options?: any): Promise<void> {\n\t\tDFChatArchive.setUpdateListener(null);\n\t\treturn super.close(options);\n\t}\n\n\tprivate async _archiveChanged() {\n\t\tlet logs = DFChatArchive.getLogs();\n\t\tif (!game.user.isGM)\n\t\t\tlogs = logs.filter(x => x.visible);\n\t\tconst archiveContainer = this.element.find('#dfca-archives');\n\t\tarchiveContainer.empty();\n\t\t// Add new items\n\t\tfor (const archive of logs) {\n\t\t\tconst visible = archive.visible === true\n\t\t\t\t? `<i class=\"dfca-visible fas fa-users\" title=\"${'DF_CHAT_ARCHIVE.ArchiveManager_VisibleToPlayers'.localize()}\"></i>` : '';\n\t\t\tconst html = $(`\n\t\t<li class=\"dfca-archive-item\" data-id=\"${archive.id}\">\n\t\t\t<div>\n\t\t\t\t<a class=\"button dfca-view\" data-type=\"view\" data-id=\"${archive.id}\"><i class=\"fas fa-eye\"></i>\n\t\t\t\t\t<span>${archive.name}</span>\n\t\t\t\t</a>\n\t\t\t\t${visible}\n\t\t\t\t<a class=\"button dfca-delete\" data-type=\"delete\" data-id=\"${archive.id}\"><i class=\"fas fa-trash\"></i></a>\n\t\t\t</div>\n\t\t</li>`);\n\t\t\tthis._subscribeView(html.find('a[data-type=\"view\"]'));\n\t\t\tthis._subscribeDelete(html.find('a[data-type=\"delete\"]'));\n\t\t\tarchiveContainer.append(html);\n\t\t}\n\t\tif (archiveContainer[0].children.length == 0)\n\t\t\tthis.element.find('p.dfca-no-items').show();\n\t\telse\n\t\t\tthis.element.find('p.dfca-no-items').hide();\n\t}\n}","import { DFChatArchive } from \"./DFChatArchive\";\nimport SETTINGS from \"../../../common/Settings\";\n\nexport default class DFChatArchiveNew extends FormApplication<FormApplicationOptions, { shouldDelete: boolean }> {\n\tstatic readonly PREF_DELETE = 'new-should-delete';\n\tstatic readonly PREF_HIDE_EXPORT = 'hide-export';\n\tstatic get defaultOptions() {\n\t\treturn mergeObject(FormApplication.defaultOptions, {\n\t\t\ttemplate: \"modules/df-chat-enhance/templates/archive-new.hbs\",\n\t\t\tresizable: false,\n\t\t\tminimizable: false,\n\t\t\ttitle: \"DF_CHAT_ARCHIVE.ArchiveNew_Title\".localize()\n\t\t});\n\t}\n\n\tstatic registerSettings() {\n\t\tSETTINGS.register(DFChatArchiveNew.PREF_DELETE, {\n\t\t\tconfig: false,\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tdefault: true\n\t\t});\n\t}\n\n\tgetData(options?: any) {\n\t\treturn mergeObject(super.getData(options), {\n\t\t\tshouldDelete: SETTINGS.get(DFChatArchiveNew.PREF_DELETE) as boolean\n\t\t});\n\t}\n\n\tasync _updateObject(_event?: any, formData?: any) {\n\t\tSETTINGS.set(DFChatArchiveNew.PREF_DELETE, formData.delete);\n\n\t\tconst name = formData.name;\n\t\tif (!name) {\n\t\t\tui.notifications.warn('DF_CHAT_ARCHIVE.ArchiveNew_ErrorNameMissing'.localize());\n\t\t\tthrow Error('DF_CHAT_ARCHIVE.ArchiveNew_ErrorNameMissing'.localize());\n\t\t}\n\n\t\tlet chats = <ChatMessage[]>[...(ui.chat.collection.values())];\n\n\t\t// If we are selecting a date range\n\t\tif (formData['date-or-all'] === 'date') {\n\t\t\tconst fromDate = new Date(formData.from).getTime();\n\t\t\tconst toDate = new Date(formData.to).getTime();\n\t\t\tif (isNaN(fromDate) || isNaN(toDate)) {\n\t\t\t\tui.notifications.warn('DF_CHAT_ARCHIVE.ArchiveNew_ErrorDatesMissing'.localize());\n\t\t\t\tthrow Error('Missing \"from\" and/or \"to\" dates');\n\t\t\t}\n\t\t\tchats = chats.filter((value) => value.data.timestamp >= fromDate && value.data.timestamp <= toDate);\n\t\t}\n\n\t\tui.notifications.info('DF_CHAT_ARCHIVE.ArchiveNew_NoticeSuccess'.localize().replace('{0}', name));\n\t\ttry {\n\t\t\tawait DFChatArchive.createChatArchive(name, chats, formData['visible']);\n\t\t}\n\t\tcatch (e) {\n\t\t\t// We have failed to create an archive so we should return immediately\n\t\t\treturn;\n\t\t}\n\t\t// If we don't want to delete the messages, return\n\t\tif (!formData.delete) return;\n\n\t\tgame.messages.flush();\n\t}\n\n\t_renderInner(data: { shouldDelete: boolean }): Promise<JQuery<HTMLElement>> {\n\t\treturn super._renderInner(data)\n\t\t\t.then((html) => {\n\t\t\t\tconst from = html.find('#dfca-from');\n\t\t\t\tconst to = html.find('#dfca-to');\n\t\t\t\thtml.find('#dfca-all').on('change', () => {\n\t\t\t\t\tfrom.prop('disabled', true);\n\t\t\t\t\tto.prop('disabled', true);\n\t\t\t\t\tthis._recalculateDimensions();\n\t\t\t\t});\n\t\t\t\thtml.find('#dfca-date').on('change', () => {\n\t\t\t\t\tfrom.prop('disabled', false);\n\t\t\t\t\tto.prop('disabled', false);\n\t\t\t\t\tthis._recalculateDimensions();\n\t\t\t\t});\n\t\t\t\treturn html;\n\t\t\t});\n\t}\n}","import { ChatMessageData } from '@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs';\nimport { DFChatArchive, DFChatArchiveEntry } from './DFChatArchive';\n\nexport default class DFChatArchiveViewer extends Application {\n\tarchive: DFChatArchiveEntry;\n\tmessages: ChatMessageData[];\n\tonCloseCallBack: (view: DFChatArchiveViewer) => void;\n\tconstructor(archive: DFChatArchiveEntry, onCloseCallBack: (view: DFChatArchiveViewer) => void) {\n\t\tsuper();\n\t\tthis.archive = archive;\n\t\tthis.onCloseCallBack = onCloseCallBack;\n\t}\n\n\tstatic get defaultOptions() {\n\t\treturn mergeObject(Application.defaultOptions as Partial<ApplicationOptions>, {\n\t\t\ttemplate: \"modules/df-chat-enhance/templates/archive-viewer.hbs\",\n\t\t\twidth: 300,\n\t\t\theight: 500,\n\t\t\tresizable: true,\n\t\t\ttitle: 'DF_CHAT_ARCHIVE.ArchiveViewer_Title',\n\t\t\tclasses: ['df-chat-log-window']\n\t\t}) as ApplicationOptions;\n\t}\n\n\tgetData(options = {}) {\n\t\tsuper.getData(options);\n\t\treturn {\n\t\t\tname: this.archive.name,\n\t\t\tisGM: game.user.isGM,\n\t\t\tvisible: this.archive.visible ?? false,\n\t\t\tlogId: 'df-chat-log-' + this.archive.id\n\t\t};\n\t}\n\n\t// convert a Unicode string to a string in which\n\t// each 16-bit unit occupies only one byte\n\t/**\n\t * Converts a UTF-16 string to an ASCii string containing the binary data of the UTF-16 text.\n\t * @param data UTF-16 data\n\t * @returns Binary data coerced into a string\n\t */\n\tprivate static toBinary(data: string): string {\n\t\tconst codeUnits = new Uint16Array(data.length);\n\t\tfor (let i = 0; i < codeUnits.length; i++) {\n\t\t\tcodeUnits[i] = data.charCodeAt(i);\n\t\t}\n\t\tconst charCodes = new Uint8Array(codeUnits.buffer);\n\t\tlet result = '';\n\t\tfor (let i = 0; i < charCodes.byteLength; i++) {\n\t\t\tresult += String.fromCharCode(charCodes[i]);\n\t\t}\n\t\treturn result;\n\t}\n\n\t_renderInner(data: any): Promise<JQuery> {\n\t\treturn (super._renderInner(data) as Promise<JQuery>)\n\t\t\t.then(async (html: JQuery<HTMLElement>) => {\n\t\t\t\thtml.find(\"#visible-df-chat-log-\" + this.archive.id).on('change', async (element) => {\n\t\t\t\t\tthis.archive.visible = (element.target as HTMLInputElement).checked;\n\t\t\t\t\tawait DFChatArchive.updateChatArchive(this.archive);\n\t\t\t\t});\n\t\t\t\thtml.find(\"#edit\").on('click', async () => {\n\t\t\t\t\tsetTimeout(async () => {\n\t\t\t\t\t\tconst dialog = new Dialog({\n\t\t\t\t\t\t\ttitle: \"DF_CHAT_ARCHIVE.ArchiveViewer_NameEdit_Title\".localize(),\n\t\t\t\t\t\t\tcontent: `<input id=\"name\" type=\"text\" value=\"${this.archive.name}\"/>`,\n\t\t\t\t\t\t\tbuttons: {\n\t\t\t\t\t\t\t\tsave: {\n\t\t\t\t\t\t\t\t\ticon: '<i class=\"fas fa-save\"></i>',\n\t\t\t\t\t\t\t\t\tlabel: 'DF_CHAT_ARCHIVE.ArchiveViewer_NameEdit_Save'.localize(),\n\t\t\t\t\t\t\t\t\tcallback: async (html) => {\n\t\t\t\t\t\t\t\t\t\tthis.archive.name = $(html).find('#name').val() as string;\n\t\t\t\t\t\t\t\t\t\tawait dialog.close();\n\t\t\t\t\t\t\t\t\t\tawait DFChatArchive.updateChatArchive(this.archive);\n\t\t\t\t\t\t\t\t\t\tawait this.render(false);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tclose: {\n\t\t\t\t\t\t\t\t\ticon: '<i class=\"fas fa-times\"></i>',\n\t\t\t\t\t\t\t\t\tlabel: 'DF_CHAT_ARCHIVE.ArchiveViewer_NameEdit_Cancel'.localize(),\n\t\t\t\t\t\t\t\t\tcallback: async () => {\n\t\t\t\t\t\t\t\t\t\tawait dialog.close();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tdefault: 'save'\n\t\t\t\t\t\t});\n\t\t\t\t\t\tdialog.render(true);\n\t\t\t\t\t}, 1);\n\t\t\t\t});\n\t\t\t\thtml.find('#print').on('click', async () => {\n\t\t\t\t\tconst clone = html.find('#df-chat-log').clone();\n\t\t\t\t\tclone.addClass('df-chat-print');\n\t\t\t\t\t$('body').hide();\n\t\t\t\t\t$('html').addClass('df-chat-print');\n\t\t\t\t\t$('html').append(clone);\n\t\t\t\t\twindow.print();\n\t\t\t\t\tclone.remove();\n\t\t\t\t\t$('html').removeClass('df-chat-print');\n\t\t\t\t\t$('body').show();\n\t\t\t\t});\n\t\t\t\thtml.find('#merge').on('click', async () => {\n\t\t\t\t\tif (DFChatArchive.getLogs().length == 1) {\n\t\t\t\t\t\tui.notifications.info('DF_CHAT_ARCHIVE.ArchiveViewer_Merge_OnlyOneArchive'.localize());\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst dialog: Dialog = new Dialog({\n\t\t\t\t\t\ttitle: 'DF_CHAT_ARCHIVE.ArchiveViewer_Merge_Title'.localize(),\n\t\t\t\t\t\tdefault: 'merge',\n\t\t\t\t\t\tcontent: await renderTemplate('modules/df-chat-enhance/templates/archive-merge.hbs', {\n\t\t\t\t\t\t\tid: this.archive.id,\n\t\t\t\t\t\t\tname: this.archive.name,\n\t\t\t\t\t\t\tarchives: DFChatArchive.getLogs().filter(x => x.id != this.archive.id)\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tbuttons: {\n\t\t\t\t\t\t\tcancel: {\n\t\t\t\t\t\t\t\ticon: '<i class=\"fas fa-times\"></i>',\n\t\t\t\t\t\t\t\tlabel: 'DF_CHAT_ARCHIVE.ArchiveViewer_Merge_Cancel'.localize(),\n\t\t\t\t\t\t\t\tcallback: async () => await dialog.close()\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmerge: {\n\t\t\t\t\t\t\t\ticon: '<i class=\"fas fa-sitemap\"></i>',\n\t\t\t\t\t\t\t\tlabel: 'DF_CHAT_ARCHIVE.ArchiveViewer_Merge_Merge'.localize(),\n\t\t\t\t\t\t\t\tcallback: async (html) => {\n\t\t\t\t\t\t\t\t\tconst val = $(html).find('#archive').val() as string;\n\t\t\t\t\t\t\t\t\tif (isNaN(parseInt(val))) return;\n\t\t\t\t\t\t\t\t\tconst id = parseInt(val);\n\t\t\t\t\t\t\t\t\tconst source = DFChatArchive.getLogs().find(x => x.id == id);\n\t\t\t\t\t\t\t\t\tconst currentChats = await DFChatArchive.getArchiveContents(this.archive);\n\t\t\t\t\t\t\t\t\tconst sourceChats = await DFChatArchive.getArchiveContents(source);\n\t\t\t\t\t\t\t\t\tconst mergedChats = (currentChats as ChatMessageData[])\n\t\t\t\t\t\t\t\t\t\t.concat(sourceChats as ChatMessageData[])\n\t\t\t\t\t\t\t\t\t\t.sort((a, b) => a.timestamp - b.timestamp);\n\t\t\t\t\t\t\t\t\tawait DFChatArchive.updateChatArchive(this.archive, mergedChats);\n\t\t\t\t\t\t\t\t\tthis.render(true);\n\t\t\t\t\t\t\t\t\tif (($(html).find('#delete-' + this.archive.id)[0] as HTMLInputElement).checked) {\n\t\t\t\t\t\t\t\t\t\tawait DFChatArchive.deleteChatArchive(id);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tawait dialog.render(true);\n\t\t\t\t});\n\n\t\t\t\thtml.find('#html').on('click', () => {\n\t\t\t\t\tconst data = $('<div></div>').append(html.find('#df-chat-log').clone()).html();\n\t\t\t\t\tconst anchor = document.createElement('a');\n\t\t\t\t\tanchor.download = encodeURI(this.archive.name) + '.html';\n\t\t\t\t\t// anchor.href = \"data:text/html;base64,\" + btoa(unescape(encodeURIComponent(data)));\n\t\t\t\t\tanchor.href = \"data:text/html,\" + encodeURIComponent(data);\n\t\t\t\t\tanchor.click();\n\t\t\t\t});\n\n\t\t\t\tconst log = html.find('#df-chat-log');\n\t\t\t\tconst messageHtml = [];\n\t\t\t\tthis.messages = (await DFChatArchive.getArchiveContents(this.archive) as ChatMessageData[])\n\t\t\t\t\t.filter(x => game.user.isGM || x.user === game.userId || x.type !== CONST.CHAT_MESSAGE_TYPES.WHISPER || x.whisper.some(x => x === game.userId));\n\n\t\t\t\tconst deletionList: string[] = [];\n\t\t\t\tconst deleteButton = html.find('#dfal-save-changes');\n\t\t\t\tfor (const value of this.messages as ChatMessageData[]) {\n\t\t\t\t\tconst chatMessage = value instanceof ChatMessage ? value : new ChatMessage(value);\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\tconst html = await chatMessage.getHTML();\n\t\t\t\t\t\t// if we only have 1 message, don't allow it to be deleted. They might as well just delete the archive\n\t\t\t\t\t\tif (this.messages.length == 1)\n\t\t\t\t\t\t\thtml.find('a.message-delete').hide();\n\t\t\t\t\t\thtml.find('a.message-delete').on('click', (event: JQuery.ClickEvent) => {\n\t\t\t\t\t\t\tconst messageHtml = $(event.target.parentElement?.parentElement?.parentElement?.parentElement);\n\t\t\t\t\t\t\tconst buttonIcon = $(event.target);\n\t\t\t\t\t\t\tif (messageHtml.hasClass('dfal-deleted')) {\n\t\t\t\t\t\t\t\tmessageHtml.removeClass('dfal-deleted');\n\t\t\t\t\t\t\t\tbuttonIcon.removeClass('fa-redo-alt');\n\t\t\t\t\t\t\t\tbuttonIcon.addClass('fa-trash');\n\t\t\t\t\t\t\t\tdeletionList.splice(deletionList.findIndex(x => x === messageHtml.attr('data-message-id')), 1);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tmessageHtml.addClass('dfal-deleted');\n\t\t\t\t\t\t\t\tbuttonIcon.removeClass('fa-trash');\n\t\t\t\t\t\t\t\tbuttonIcon.addClass('fa-redo-alt');\n\t\t\t\t\t\t\t\tdeletionList.push(messageHtml.attr('data-message-id'));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (deletionList.length > 0) deleteButton.show();\n\t\t\t\t\t\t\telse deleteButton.hide();\n\t\t\t\t\t\t});\n\t\t\t\t\t\tmessageHtml.push(html);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.error(`Chat message ${chatMessage.id} failed to render.\\n${err})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Prepend the HTML\n\t\t\t\tlog.prepend(messageHtml);\n\n\t\t\t\tdeleteButton.hide();\n\t\t\t\tdeleteButton.on('click', async () => {\n\t\t\t\t\tif (deletionList.length === this.messages.length) {\n\t\t\t\t\t\tui.notifications.warn('DF_CHAT_ARCHIVE.ArchiveViewer_Error_Delete_All'.localize());\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tDialog.confirm({\n\t\t\t\t\t\ttitle: \"DF_CHAT_ARCHIVE.ArchiveViewer_DeleteTitle\".localize(),\n\t\t\t\t\t\tcontent: \"DF_CHAT_ARCHIVE.ArchiveViewer_DeleteContent\".localize(),\n\t\t\t\t\t\tdefaultYes: false,\n\t\t\t\t\t\tyes: async () => {\n\t\t\t\t\t\t\tfor (const id of deletionList) {\n\t\t\t\t\t\t\t\tconst message = html.find(`li[data-message-id=\"${id}\"]`);\n\t\t\t\t\t\t\t\tmessage.hide(500, () => message.remove());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.messages = this.messages.filter((x: any) => !deletionList.includes(x._id));\n\t\t\t\t\t\t\tawait DFChatArchive.updateChatArchive(this.archive, this.messages);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\treturn html;\n\t\t\t});\n\t}\n\tclose(options?: Application.CloseOptions): Promise<void> {\n\t\tthis.onCloseCallBack(this);\n\t\treturn super.close(options);\n\t}\n}","import DFChatArchiveNew from \"./DFChatArchiveNew\";\nimport DFChatArchiveManager from \"./DFChatArchiveManager\";\nimport { DFChatArchive } from \"./DFChatArchive\";\nimport SETTINGS from \"../../../common/Settings\";\n\n\nexport function init() {\n\n\tlet archiveNew: DFChatArchiveNew = null;\n\tlet archiveManager: DFChatArchiveManager = null;\n\n\tDFChatArchive.registerSettings();\n\tDFChatArchiveNew.registerSettings();\n\n\tSETTINGS.register(DFChatArchiveNew.PREF_HIDE_EXPORT, {\n\t\tname: 'DF_CHAT_ARCHIVE.Settings.HideExport',\n\t\tscope: 'world',\n\t\ttype: Boolean,\n\t\tdefault: false,\n\t\tconfig: true,\n\t\tonChange: (newValue) => {\n\t\t\tif (!newValue)\n\t\t\t\t$('#chat-controls .export-log').show();\n\t\t\telse\n\t\t\t\t$('#chat-controls .export-log').hide();\n\t\t}\n\t});\n\n\tSETTINGS.register(DFChatArchiveManager.PREF_REVERSE_SORT, {\n\t\tscope: 'world',\n\t\ttype: Boolean,\n\t\tdefault: false,\n\t\tconfig: false\n\t});\n\n\tHooks.on('renderChatLog', function (chatLog: ChatLog, html: JQuery<HTMLElement>) {\n\t\tconst archiveButton = $(`<a class=\"button chat-archive\" title=\"${'DF_CHAT_ARCHIVE.ExportButtonTitle'.localize()}\">\n\t\t<i class=\"fas fa-archive\"></i></a>`);\n\t\tarchiveButton.on('click', () => {\n\t\t\tif (archiveNew == null) {\n\t\t\t\tarchiveNew = new DFChatArchiveNew({});\n\t\t\t\tarchiveNew.render(true);\n\t\t\t} else {\n\t\t\t\tarchiveNew.bringToTop();\n\t\t\t}\n\t\t});\n\t\thtml.find('.control-buttons')\n\t\t\t.prepend(archiveButton)\n\t\t\t.attr('style', 'flex:0 0 auto;');\n\t\tif (SETTINGS.get(DFChatArchiveNew.PREF_HIDE_EXPORT)) {\n\t\t\thtml.find('.control-buttons .export-log').hide();\n\t\t}\n\t});\n\n\tHooks.on('renderSettings', function (settings: Settings, html: JQuery<HTMLElement>) {\n\t\tconst archiveManagerHtml = $(`<div id=\"df-chat-enhance-settings\" style=\"margin:0\">\n\t<h4>${'DF_CHAT_ARCHIVE.ChatEnhanceSettingGroup'.localize()}</h4>\n\t<button data-action=\"archive\"><i class=\"fas fa-archive\"></i>${'DF_CHAT_ARCHIVE.OpenChatArchive'.localize()}</button>\n</div>`);\n\t\tarchiveManagerHtml.on('click', () => {\n\t\t\tif (archiveManager == null || ![Application.RENDER_STATES.RENDERED, Application.RENDER_STATES.RENDERING].includes((<any>archiveManager)._state)) {\n\t\t\t\tarchiveManager = new DFChatArchiveManager();\n\t\t\t\tarchiveManager.render(true);\n\t\t\t} else {\n\t\t\t\tarchiveManager.bringToTop();\n\t\t\t}\n\t\t});\n\t\thtml.find('#settings-game').append(archiveManagerHtml);\n\t});\n\tHooks.on('closeDFChatArchiveNew', () => { archiveNew = null; });\n\tHooks.on('closeDFChatArchiveManager', () => { archiveNew = null; });\n\tHooks.on(`renderDFChatArchiveNew`, function (app: any, html: JQuery) {\n\t\thtml.find('input[type=\"text\"]')[0].focus();\n\t});\n}\n","import { ChatMessageData } from \"@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs\";\nimport SETTINGS from \"../../../common/Settings\";\nimport UTIL from \"../Util\";\n\nexport default class ChatTime {\n\n\tprivate static readonly PREF_ENABLED = 'ChatTime.UseSimpleCalender';\n\tprivate static readonly PREF_FORMAT = 'ChatTime.SimpleCalendarFormat';\n\tprivate static readonly FLAG_CHAT_TIME = 'ChatTime.WorldTime';\n\n\tprivate static get enabled() { return SETTINGS.get(this.PREF_ENABLED); }\n\tprivate static get simpleCalendarActive() { return !!game.modules.get('foundryvtt-simple-calendar')?.active; }\n\n\tstatic ready() {\n\t\tif (!this.simpleCalendarActive && game.user.isGM && this.enabled)\n\t\t\tui.notifications.warn('DF_CHAT_TIME.ErrorSimpleCalendarMissing', { permanent: true, localize: true });\n\t}\n\n\tstatic init() {\n\t\tSETTINGS.register(this.PREF_ENABLED, {\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tname: \"DF_CHAT_TIME.EnabledName\",\n\t\t\thint: \"DF_CHAT_TIME.EnabledHint\",\n\t\t\tdefault: false,\n\t\t\tconfig: true,\n\t\t\tonChange: UTIL.reloadChatLog\n\t\t});\n\n\t\tSETTINGS.register(this.PREF_FORMAT, {\n\t\t\tscope: 'world',\n\t\t\ttype: String,\n\t\t\tname: 'DF_CHAT_TIME.FormatName',\n\t\t\thint: 'DF_CHAT_TIME.FormatHint',\n\t\t\tdefault: 'YYYY, MMM DD, HH:mm',\n\t\t\tconfig: this.simpleCalendarActive,\n\t\t\tonChange: UTIL.reloadChatLog\n\t\t});\n\n\t\tlibWrapper.register(SETTINGS.MOD_NAME, 'ChatMessage.implementation.create',\n\t\t\t(wrapped: (...args: any) => unknown, chatData: Partial<ChatMessageData>, createOptions: any) => {\n\t\t\t\tchatData.flags = chatData.flags ?? {};\n\t\t\t\tchatData.flags[SETTINGS.MOD_NAME] = {};\n\t\t\t\t(chatData.flags[SETTINGS.MOD_NAME] as any)[this.FLAG_CHAT_TIME] = game.time.worldTime;\n\t\t\t\treturn wrapped(chatData, createOptions);\n\t\t\t}, 'WRAPPER');\n\n\t\tHooks.on('renderChatMessage', (message: ChatMessage, html: JQuery<HTMLElement>, _data: any) => {\n\t\t\tif (!this.simpleCalendarActive || !this.enabled) return;\n\t\t\tconst simpleTimestamp = <number>message.getFlag(SETTINGS.MOD_NAME, this.FLAG_CHAT_TIME);\n\t\t\tif (simpleTimestamp === undefined) return;\n\t\t\tconst timeElement = html.find('.message-timestamp');\n\t\t\tconst simpleTimeElement = $(`<time class=\"dfce-simple-timestamp\">${SimpleCalendar.api.formatDateTime(\n\t\t\t\tSimpleCalendar.api.timestampToDate(simpleTimestamp), SETTINGS.get<string>(this.PREF_FORMAT)\n\t\t\t)}</time>`);\n\t\t\ttimeElement.after(simpleTimeElement);\n\t\t\ttimeElement.hide();\n\t\t});\n\t}\n}","import { ChatMessageData } from \"@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs\";\nimport SETTINGS from \"../../../common/Settings\";\nimport DFChatEdit from \"./df-chat-edit\";\n\n\ndeclare namespace marked {\n\tfunction parse(md: string, options: any): string;\n}\n\nexport default class DFChatEditor extends FormApplication {\n\tprivate chatMessage: ChatMessageData & ChatMessage;\n\tpublic static readonly PREF_MARKDOWN = 'edit-markdown';\n\n\t/**\n\t * Assign the default options which are supported by the entity edit sheet.\n\t * @returns The default options for this FormApplication class\n\t * @override\n\t * @see {@link Application.defaultOptions}\n\t */\n\tstatic get defaultOptions(): FormApplicationOptions {\n\t\treturn mergeObject(FormApplication.defaultOptions as Partial<FormApplicationOptions>, {\n\t\t\tcloseOnSubmit: true,\n\t\t\teditable: true,\n\t\t\tresizable: true,\n\t\t\twidth: 400,\n\t\t\tpopOut: true,\n\t\t\ttitle: 'DF_CHAT_EDIT.Editor_Title',\n\t\t\ttemplate: 'modules/df-chat-enhance/templates/chat-edit.hbs'\n\t\t}) as FormApplicationOptions;\n\t}\n\n\tconstructor(chatMessage: ChatMessageData & ChatMessage) {\n\t\tsuper({});\n\t\tthis.chatMessage = chatMessage;\n\t}\n\n\t/** @override */\n\tgetData(options?: any): any {\n\n\t\t// Collect the different Actor types and the labels for those types\n\t\tconst types = Object.keys(CONFIG.Actor.typeLabels).map(type => {\n\t\t\treturn { type, label: CONFIG.Actor.typeLabels[type], actors: [] };\n\t\t});\n\t\t// Organize the actors in the current scene into those type categories\n\t\tfor (const type of types) {\n\t\t\ttype.actors = game.scenes.viewed.tokens.contents.filter(x => x.actor.type === type.type).map(x => ({\n\t\t\t\tid: 'token-' + x.id,\n\t\t\t\tname: x.name\n\t\t\t}));\n\t\t}\n\n\t\tlet selected = '';\n\t\tif (this.chatMessage.user)\n\t\t\tselected = 'user-' + this.chatMessage.user;\n\t\tif (this.chatMessage.speaker.token)\n\t\t\tselected = 'token-' + this.chatMessage.speaker.token;\n\n\t\treturn mergeObject(options, {\n\t\t\tselected,\n\t\t\tplayers: game.users.map(x => ({ id: 'user-' + x.id, name: x.name })),\n\t\t\tactorGroups: types.filter(x => x.actors.length > 0),\n\t\t\tmessageText: this.chatMessage.content\n\t\t\t\t.replace(/< *br *\\/?>/gm, '\\n')\n\t\t\t\t.replace(/<p +class=\"df-edited\">.+/, '')\n\t\t});\n\t}\n\n\t/** @override */\n\tactivateListeners(html: JQuery): void {\n\t\tsuper.activateListeners(html);\n\t\thtml.find('#cancel').on('click', async () => await this.close());\n\t}\n\n\t/** @override */\n\tasync _updateObject(_event?: any, formData?: { content: string, speaker: string }) {\n\t\tlet data = formData.content as string;\n\t\tif (SETTINGS.get(DFChatEditor.PREF_MARKDOWN)) {\n\t\t\tdata = DFChatEditor.processMarkdown(data)[1];\n\t\t} else {\n\t\t\tdata = data.replace(/\\r?\\n/gm, '<br/>');\n\t\t}\n\t\tif (SETTINGS.get<boolean>(DFChatEdit.PREF_SHOW_EDITED) && data.search(/<p +class=\"df-edited\">/) < 0) {\n\t\t\tdata += `<p class=\"df-edited\">${'DF_CHAT_EDIT.EditedFlag'.localize()}</p>`;\n\t\t}\n\n\t\tlet speaker = undefined;\n\t\tlet user = undefined;\n\t\tif (formData.speaker.startsWith('user-')) {\n\t\t\tuser = game.users.get(formData.speaker.substring('user-'.length)).id;\n\t\t\t// @ts-expect-error\n\t\t\tspeaker = ChatMessage._getSpeakerFromUser({ user });\n\t\t} else\n\t\t\tspeaker = ChatMessage.getSpeaker({ token: game.scenes.viewed.tokens.get(formData.speaker.substring('token-'.length)) });\n\t\tif (speaker.alias === undefined)\n\t\t\tspeaker.alias = null;\n\t\tthis.chatMessage.update({ content: data, speaker, user });\n\t}\n\t/** @override */\n\tclose(options?: FormApplication.CloseOptions) {\n\t\tdelete (<any>this.chatMessage).chatEditor;\n\t\treturn super.close(options);\n\t}\n\n\tpublic static processMarkdown(message: string) {\n\t\tconst originalMessage = message;\n\t\tmessage = marked.parse(message, {\n\t\t\theaderIds: false,\n\t\t\tbreaks: true\n\t\t}).trimEnd();\n\t\tif (message.startsWith('<p>'))\n\t\t\tmessage = message.substr(3);\n\t\tif (message.endsWith('</p>'))\n\t\t\tmessage = message.substr(0, message.length - 4);\n\t\tconst newLine = /(<\\/?[ a-z]+>)\\n(<\\/?[ a-z]+>?)/;\n\t\twhile (newLine.test(message))\n\t\t\tmessage = message.replace(newLine, '$1$2');\n\t\treturn [originalMessage, message];\n\t}\n}","import { ChatMessageData } from \"@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs\";\nimport SETTINGS from \"../../../common/Settings\";\nimport DFChatEditor from './DFChatEditor';\n\nconst PREF_EDIT_ALLOWED = 'edit-allowed';\nconst PREF_GM_ALL = 'gm-edit-all';\nconst PREF_IGNORE_HTML = 'edit-ignore-html';\n\nexport default class DFChatEdit {\n\tstatic readonly PREF_SHOW_EDITED = 'DFChatEdit.ShowEditedLable';\n\n\tstatic ready() {\n\t\tSETTINGS.register(DFChatEditor.PREF_MARKDOWN, {\n\t\t\tname: 'DF_CHAT_EDIT.Settings_MarkdownName',\n\t\t\thint: 'DF_CHAT_EDIT.Settings_MarkdownHint',\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tconfig: true,\n\t\t\tscope: 'world'\n\t\t});\n\t\tSETTINGS.register(PREF_EDIT_ALLOWED, {\n\t\t\tname: 'DF_CHAT_EDIT.Settings_AllowEditName',\n\t\t\thint: 'DF_CHAT_EDIT.Settings_AllowEditHint',\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tscope: 'world',\n\t\t\tconfig: true\n\t\t});\n\t\tSETTINGS.register(PREF_GM_ALL, {\n\t\t\tname: 'DF_CHAT_EDIT.Settings_GMEditAllName',\n\t\t\thint: 'DF_CHAT_EDIT.Settings_GMEditAllHint',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t\tconfig: true,\n\t\t\tscope: 'world'\n\t\t});\n\t\tSETTINGS.register(PREF_IGNORE_HTML, {\n\t\t\tname: 'DF_CHAT_EDIT.Settings_IgnoreHtmlName',\n\t\t\thint: 'DF_CHAT_EDIT.Settings_IgnoreHtmlHint',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t\tconfig: true,\n\t\t\tscope: 'world'\n\t\t});\n\t\tSETTINGS.register(this.PREF_SHOW_EDITED, {\n\t\t\tname: 'DF_CHAT_EDIT.Settings_ShowEditedLabelName',\n\t\t\thint: 'DF_CHAT_EDIT.Settings_ShowEditedLabelHint',\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tconfig: true,\n\t\t\tscope: 'world'\n\t\t});\n\n\t\tlibWrapper.register(SETTINGS.MOD_NAME, 'ChatLog.prototype._onChatKeyDown', (wrapper: (..._: any) => void, ...args: any) => {\n\t\t\tconst event = args[0] as KeyboardEvent;\n\t\t\t// We have used the Shift+Up combo to edit previously sent message\n\t\t\tif (event.code === \"ArrowUp\" && event.ctrlKey) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tlet messages = <(ChatMessageData & ChatMessage)[]><any[]>[...(ui.chat.collection.values())];\n\t\t\t\t// Perform an inverted sort ( n<0 before, n=0 same, n>0 after )\n\t\t\t\tmessages = messages.sort((a, b) => b.timestamp - a.timestamp);\n\t\t\t\tconst message = messages.find(x => x.user === game.user.id);\n\t\t\t\tif (!message) return;\n\t\t\t\tDFChatEdit.editChatMessage.bind(message)();\n\t\t\t}\n\t\t\telse\n\t\t\t\twrapper(...args);\n\t\t}, 'MIXED');\n\n\t\tlibWrapper.register(SETTINGS.MOD_NAME, 'ChatLog.prototype.processMessage', function (this: ChatLog, wrapper: AnyFunction, message: string) {\n\t\t\tlet originalMessage: string = null;\n\t\t\tif (SETTINGS.get(DFChatEditor.PREF_MARKDOWN)) {\n\t\t\t\tif (message.trim().startsWith('/')) {\n\t\t\t\t\tconst token = message.split(' ')[0].trim();\n\t\t\t\t\tswitch (token) {\n\t\t\t\t\t\tcase '/ooc': /* fall-through */\n\t\t\t\t\t\tcase '/ic': /* fall-through */\n\t\t\t\t\t\tcase '/emote': /* fall-through */\n\t\t\t\t\t\tcase '/whisper': /* fall-through */\n\t\t\t\t\t\tcase '/w':\n\t\t\t\t\t\t\t[originalMessage, message] = DFChatEditor.processMarkdown(message.substr(token.length));\n\t\t\t\t\t\t\toriginalMessage = `${token} ${originalMessage.trimStart()}`;\n\t\t\t\t\t\t\tmessage = `${token} ${message.trimStart()}`;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'log': /* fall-through */\n\t\t\t\t\t\tcase 'gmlog': /* fall-through */\n\t\t\t\t\t\tcase '/gmroll': /* fall-through */\n\t\t\t\t\t\tcase '/blindroll': /* fall-through */\n\t\t\t\t\t\tcase '/selfroll': /* fall-through */\n\t\t\t\t\t\tcase '/r': /* fall-through */\n\t\t\t\t\t\tcase '/roll': /* fall-through */\n\t\t\t\t\t\tdefault: break;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t[originalMessage, message] = DFChatEditor.processMarkdown(message);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst result = wrapper(message);\n\t\t\tif (originalMessage) {\n\t\t\t\tthis._sentMessages.splice(0, 1);\n\t\t\t\tthis._sentMessages.unshift(originalMessage);\n\t\t\t}\n\t\t\treturn result;\n\t\t}, 'WRAPPER');\n\t}\n\n\tstatic appendChatContextMenuOptions(options: ContextMenu.Item[]) {\n\t\toptions.push({\n\t\t\tname: 'DF_CHAT_EDIT.ContextOption',\n\t\t\ticon: '<i class=\"fas fa-pencil-alt\"></i>',\n\t\t\tcondition: (header) => {\n\t\t\t\tconst chatData = <ChatMessageData & ChatMessage><any>ui.chat.collection.get($(header).attr('data-message-id'));\n\t\t\t\treturn this.processChatMessage(chatData);\n\t\t\t},\n\t\t\tcallback: (header) => {\n\t\t\t\tconst chatData = <ChatMessageData & ChatMessage><any>ui.chat.collection.get($(header).attr('data-message-id'));\n\t\t\t\tDFChatEdit.editChatMessage.bind(chatData)();\n\t\t\t\treturn {};\n\t\t\t}\n\t\t});\n\t}\n\n\t// Will be bound to the instance of ChatMessage we are observing\n\tstatic async editChatMessage(this: ChatMessageData & ChatMessage) {\n\t\t// Double check permissions\n\t\tif (!SETTINGS.get(PREF_EDIT_ALLOWED)) {\n\t\t\tui.notifications.warn('DF_CHAT_EDIT.Error_NoPermission'.localize());\n\t\t\treturn;\n\t\t}\n\t\tif ((<any>this).chatEditor) {\n\t\t\t(<any>this).chatEditor.bringToTop();\n\t\t} else {\n\t\t\t(<any>this).chatEditor = new DFChatEditor(this);\n\t\t\tawait (<any>this).chatEditor._render(true);\n\t\t}\n\t\t(<any>this).chatEditor.element.find('textarea').focus();\n\t}\n\n\tstatic isHTML(str: string): boolean {\n\t\tconst doc = new DOMParser().parseFromString(str, \"text/html\");\n\t\treturn Array.from(doc.body.childNodes).some(node => {\n\t\t\treturn (node instanceof HTMLElement && !node.classList.contains('df-edited'))\n\t\t\t\t&& !(node instanceof HTMLBRElement)\n\t\t\t\t&& node.nodeType === 1;\n\t\t});\n\t}\n\n\tstatic processChatMessage(chatMessage: ChatMessageData & ChatMessage/*, html: JQuery<HTMLElement>*/): boolean {\n\t\t// If we are catching the render of an archived message\n\t\tif (!ui.chat.collection.has(chatMessage.id))\n\t\t\treturn false;\n\t\t// Ignore rolls and other people's messages, unless we are the GM and PREF_GM_ALL is true\n\t\tif (!SETTINGS.get(PREF_EDIT_ALLOWED) || chatMessage.isRoll\n\t\t\t|| (chatMessage.user.id !== game.userId && !(game.user.isGM && SETTINGS.get(PREF_GM_ALL))))\n\t\t\treturn false;\n\t\t// If we ignore html and message contains html, return\n\t\tif (SETTINGS.get(PREF_IGNORE_HTML) && DFChatEdit.isHTML(chatMessage.content)) return false;\n\t\treturn true;\n\t}\n}\n","import SETTINGS from \"../../../common/Settings\";\n\nexport default class FontSizePatch {\n\n\tprivate static readonly PREF_SIZE = 'FontSizePatch.FontSize';\n\n\tstatic init() {\n\t\tSETTINGS.register<number>(this.PREF_SIZE, {\n\t\t\tname: 'DF_CHAT_FONT_SIZE.FontSizeName'.localize(),\n\t\t\thint: 'DF_CHAT_FONT_SIZE.FontSizeHint'.localize(),\n\t\t\tconfig: true,\n\t\t\ttype: Number,\n\t\t\tscope: 'client',\n\t\t\trange: {\n\t\t\t\tmin: 10,\n\t\t\t\tmax: 30,\n\t\t\t\tstep: 0.5\n\t\t\t},\n\t\t\tdefault: 14,\n\t\t\tonChange: (newSize) => this.updateFontSize(newSize)\n\t\t});\n\t\tthis.updateFontSize(SETTINGS.get<number>(this.PREF_SIZE));\n\t}\n\n\tprivate static updateFontSize(size: number) {\n\t\t(<HTMLElement>document.querySelector(':root')).style.setProperty('--dfce-chat-font-size', size.toString() + 'px');\n\t}\n}","import SETTINGS from \"../../../common/Settings\";\nimport DFAdventureLogProcessor from \"./DFAdventureLogProcessor\";\n\n\nexport default class DFAdventureLogConfig extends FormApplication {\n\tstatic readonly PREF_JOURNAL = 'log-journal';\n\tstatic readonly PREF_JOURNAL_GM = 'gmlog-journal';\n\tstatic readonly PREF_CONFIG = 'log-config-menu';\n\n\tstatic get defaultOptions() {\n\t\treturn mergeObject(FormApplication.defaultOptions as Partial<FormApplicationOptions>, {\n\t\t\ttemplate: \"modules/df-chat-enhance/templates/log-config.hbs\",\n\t\t\tresizable: false,\n\t\t\tminimizable: false,\n\t\t\ttitle: \"DF_CHAT_LOG.Config_Title\".localize()\n\t\t}) as FormApplicationOptions;\n\t}\n\n\tstatic setupSettings() {\n\t\tSETTINGS.register(DFAdventureLogConfig.PREF_JOURNAL, {\n\t\t\tscope: 'world',\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t\tconfig: false\n\t\t});\n\t\tSETTINGS.register(DFAdventureLogConfig.PREF_JOURNAL_GM, {\n\t\t\tscope: 'world',\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t\tconfig: false\n\t\t});\n\t\tSETTINGS.registerMenu(DFAdventureLogConfig.PREF_CONFIG, {\n\t\t\trestricted: true,\n\t\t\ttype: <any>DFAdventureLogConfig,\n\t\t\tlabel: \"DF_CHAT_LOG.Config_Title\",\n\t\t\ticon: 'fas fa-edit'\n\t\t});\n\t}\n\n\tgetData(options?: any) {\n\t\tconst data = super.getData(options);\n\t\tconst keys = game.journal.contents.filter(x => x.pages.contents.some(y => y.type === 'text')).map(x => x.id);\n\t\tconst selectedLog = (SETTINGS.get(DFAdventureLogConfig.PREF_JOURNAL) as string | undefined)?.split('.');\n\t\tconst selectedGMLog = (SETTINGS.get(DFAdventureLogConfig.PREF_JOURNAL_GM) as string | undefined)?.split('.');\n\t\tlet logJournals: any[] = [];\n\t\tlet logJournalPages: any[] = [];\n\t\tlet gmlogJournals: any[] = [];\n\t\tlet gmlogJournalPages: any[] = [];\n\t\tfor (const key of keys) {\n\t\t\tlogJournals.push({\n\t\t\t\tid: key,\n\t\t\t\tname: game.journal.get(key).name,\n\t\t\t\tselected: selectedLog && key === selectedLog[0]\n\t\t\t});\n\t\t\tif (selectedLog && key === selectedLog[0]) {\n\t\t\t\tlogJournalPages = game.journal.get(key).pages.contents.map(x => ({\n\t\t\t\t\tid: key + '.' + x.id,\n\t\t\t\t\tname: x.name,\n\t\t\t\t\tselected: x.id === selectedLog[1]\n\t\t\t\t}));\n\t\t\t}\n\t\t\tgmlogJournals.push({\n\t\t\t\tid: key,\n\t\t\t\tname: game.journal.get(key).name,\n\t\t\t\tselected: selectedGMLog && key === selectedGMLog[0]\n\t\t\t});\n\t\t\tif (selectedGMLog && key === selectedGMLog[0]) {\n\t\t\t\tgmlogJournalPages = game.journal.get(key).pages.contents.map(x => ({\n\t\t\t\t\tid: key + '.' + x.id,\n\t\t\t\t\tname: x.name,\n\t\t\t\t\tselected: x.id === selectedGMLog[1]\n\t\t\t\t}));\n\t\t\t}\n\t\t}\n\t\tlogJournals = logJournals.sort((a, b) => a.name.localeCompare(b.name));\n\t\tgmlogJournals = gmlogJournals.sort((a, b) => a.name.localeCompare(b.name));\n\n\t\tmergeObject(data as any, {\n\t\t\tlogJournals,\n\t\t\tlogJournalPages,\n\t\t\tgmlogJournals,\n\t\t\tgmlogJournalPages\n\t\t});\n\t\treturn data;\n\t}\n\n\tprivate fillPageList(journalId: string, element: JQuery<HTMLSelectElement>) {\n\t\telement.children().remove();\n\t\tconst journal = game.journal.get(journalId);\n\t\tif (!journal) return;\n\t\tfor (const page of journal.pages.contents.filter(x => x.type == 'text')) {\n\t\t\telement.append(`<option value=\"${journalId}.${page.id}\">${page.name}</option>`);\n\t\t}\n\t}\n\n\tactivateListeners(html: JQuery<HTMLElement>): void {\n\t\thtml.find('#dfal-journal').on('change', event => {\n\t\t\tconst journalId = (event.currentTarget as HTMLSelectElement).value;\n\t\t\tconst pageElement = html.find<HTMLSelectElement>('#dfal-journal-page');\n\t\t\tthis.fillPageList(journalId, pageElement);\n\t\t});\n\t\thtml.find('#dfal-journal-gm').on('change', event => {\n\t\t\tconst journalId = (event.currentTarget as HTMLSelectElement).value;\n\t\t\tconst pageElement = html.find<HTMLSelectElement>('#dfal-journal-gm-page');\n\t\t\tthis.fillPageList(journalId, pageElement);\n\t\t});\n\t}\n\n\tasync _updateObject(_event?: any, formData?: any) {\n\t\tconst logJournal = formData['dfal-journal-page'];\n\t\tconst gmlogJournal = formData['dfal-journal-gm-page'];\n\t\tconst clear = formData['dfal-clear'];\n\t\tconst gmClear = formData['dfal-clear-gm'];\n\t\tSETTINGS.set(DFAdventureLogConfig.PREF_JOURNAL, logJournal);\n\t\tSETTINGS.set(DFAdventureLogConfig.PREF_JOURNAL_GM, gmlogJournal);\n\t\tawait DFAdventureLogConfig.initializeJournal(logJournal, clear, false, false);\n\t\tawait DFAdventureLogConfig.initializeJournal(gmlogJournal, gmClear, true, false);\n\t}\n\n\tstatic async initializeJournal(id: string, clear: boolean, isGMOnly: boolean, isPlayerLog: boolean) {\n\t\tconst journalId = id?.split('.');\n\t\tif (!journalId || journalId.length < 2 || !game.journal.has(journalId[0])) return;\n\t\tconst journal = game.journal.get(journalId[0]).pages.get(journalId[1]);\n\t\tif (clear || journal.text.content === null)\n\t\t\tjournal.text.content = '';\n\t\tconst html = $(journal.text.content);\n\t\tconst article = html.find('article[class=\"df-adventure-log\"]');\n\t\tif (article.length != 0) {\n\t\t\tawait DFAdventureLogProcessor.resortLog();\n\t\t\treturn;\n\t\t}\n\t\tawait journal.update({\n\t\t\t'text.content': journal.text.content + `\n\t\t\t<section>\n\t\t\t\t<h2>${game.i18n.localize(isGMOnly ? 'DF_CHAT_LOG.GMLog_Header' : isPlayerLog ? 'DF_CHAT_LOG.PLog_Header' : 'DF_CHAT_LOG.Log_Header')}</h2>\n\t\t\t\t<section class=\"df-adventure-log\"></section>\n\t\t\t\t<hr />\n\t\t\t</section>\n\t\t\t`\n\t\t});\n\t}\n}","\nimport { ChatMessageData, ChatMessageDataConstructorData } from \"@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs/chatMessageData\";\nimport SETTINGS from \"../../../common/Settings\";\nimport DFChatEditor from \"../edit/DFChatEditor\";\nimport DFAdventureLogConfig from './DFAdventureLogConfig';\n\ndeclare global {\n\tnamespace SimpleCalendar.api {\n\t\tfunction formatDateTime(time: {\n\t\t\tyear: number,\n\t\t\tmonth: number,\n\t\t\tday: number,\n\t\t\thour: number,\n\t\t\tminute: number,\n\t\t\tsecond: number\n\t\t}): { date: string, time: string }\n\t\tfunction formatDateTime(time: {\n\t\t\tyear: number,\n\t\t\tmonth: number,\n\t\t\tday: number,\n\t\t\thour: number,\n\t\t\tminute: number,\n\t\t\tsecond: number\n\t\t}, format: string): string\n\t\tfunction timestamp(): number\n\t\tfunction timestampToDate(timestamp: number): {\n\t\t\tyear: number,\n\t\t\tmonth: number,\n\t\t\tday: number,\n\t\t\thour: number,\n\t\t\tminute: number,\n\t\t\tsecond: number\n\t\t}\n\t}\n}\n\ndeclare global {\n\tinterface String {\n\t\ttrimStart(): string\n\t}\n}\nif (!String.prototype.trimStart) {\n\tString.prototype.trimStart = function () {\n\t\tconst whitespace = [' ', '\\n', '\\r'];\n\t\tlet index = -1;\n\t\tfor (let c = 0; c < this.length; c++) {\n\t\t\tif (whitespace.every(x => x !== this[c])) break;\n\t\t\tindex = c;\n\t\t}\n\t\treturn this.substr(index + 1);\n\t};\n}\n\ndeclare interface ChatCommand {\n\tcommandKey: string;\n\tshouldDisplayToChat: boolean;\n\tinvokeOnCommand: () => void;\n\tcreatedMessageType: number;\n\ticonClass: string;\n\tdescription: string;\n\tgmOnly: boolean;\n}\n\ndeclare class ChatCommands {\n\t/**\n\t * Registers a Chat Command to be handled\n\t */\n\tregisterCommand(command: ChatCommand): void;\n\t/**\n\t * Deregister a Chat Command\n\t */\n\tderegisterCommand(command: ChatCommand): void;\n\tcreateCommandFromData(data: any): ChatCommand;\n}\n\ndeclare class GameExt extends Game {\n\tchatCommands: ChatCommands;\n}\n\nexport default class DFAdventureLogProcessor {\n\tstatic readonly PREF_ENABLE = 'enable-command';\n\tstatic readonly PREF_GMONLY = 'df-log-gmonly';\n\tstatic readonly PREF_GMONLY_WHISPER = 'df-log-gmonly-whisper';\n\tstatic readonly PREF_MESSAGES = 'df-log-messages';\n\tstatic readonly PREF_SORTDESC = 'df-log-sortdesc';\n\tstatic readonly PREF_DISABLE_FORMATTING = 'df-log-disable-format';\n\tstatic readonly PREF_DISABLE_AUTHOR = 'df-log-disable-author';\n\tstatic readonly PREF_SIMPLE_CALENDAR = 'df-log-use-simple-calendar';\n\tstatic readonly PREF_USE_TIME = 'df-log-use-time';\n\tstatic readonly PREF_PLAYER_LOG_JOURNAL = 'PlayerAdventureLog';\n\tstatic logCommand: ChatCommand = null;\n\tstatic gmlogCommand: ChatCommand = null;\n\tstatic plogCommand: ChatCommand = null;\n\n\tstatic appendChatContextMenuOptions(options: ContextMenu.Item[]) {\n\t\toptions.push({\n\t\t\tname: 'DF_CHAT_LOG.ContextMenu_AsEvent',\n\t\t\ticon: '<i style=\"color:SeaGreen\" class=\"fas fa-edit\"></i>',\n\t\t\tcondition: () => {\n\t\t\t\tconst enabled = SETTINGS.get(DFAdventureLogProcessor.PREF_ENABLE);\n\t\t\t\tconst isGM = game.user.isGM;\n\t\t\t\tconst gmOnly = SETTINGS.get(DFAdventureLogProcessor.PREF_GMONLY);\n\t\t\t\treturn enabled && (!gmOnly || isGM);\n\t\t\t},\n\t\t\tcallback: (header) => {\n\t\t\t\tconst chatData = <ChatMessageData><any>ui.chat.collection.get($(header).attr('data-message-id'));\n\t\t\t\tDFAdventureLogProcessor.commandProcessor(chatData.content, false, false);\n\t\t\t\treturn {};\n\t\t\t}\n\t\t});\n\t\toptions.push({\n\t\t\tname: 'DF_CHAT_LOG.ContextMenu_AsQuote',\n\t\t\ticon: '<i style=\"color:SeaGreen\" class=\"fas fa-quote-right\"></i>',\n\t\t\tcondition: () => {\n\t\t\t\tconst enabled = SETTINGS.get(DFAdventureLogProcessor.PREF_ENABLE);\n\t\t\t\tconst isGM = game.user.isGM;\n\t\t\t\tconst gmOnly = SETTINGS.get(DFAdventureLogProcessor.PREF_GMONLY);\n\t\t\t\treturn enabled && (!gmOnly || isGM);\n\t\t\t},\n\t\t\tcallback: (header) => {\n\t\t\t\tconst chatData = <ChatMessageData><any>ui.chat.collection.get($(header).attr('data-message-id'));\n\t\t\t\tif (chatData.content.trimStart().startsWith('\"'))\n\t\t\t\t\tDFAdventureLogProcessor.commandProcessor('q ' + chatData.content, false, false);\n\t\t\t\telse\n\t\t\t\t\tDFAdventureLogProcessor.commandProcessor(`q \"${game.users.get(chatData.user).name}\" ${chatData.content}`, false, false);\n\t\t\t\treturn {};\n\t\t\t}\n\t\t});\n\t\toptions.push({\n\t\t\tname: 'DF_CHAT_LOG.ContextMenu_AsGmEvent',\n\t\t\ticon: '<i style=\"color:FireBrick\" class=\"fas fa-edit\"></i>',\n\t\t\tcondition: () => {\n\t\t\t\tconst enabled = SETTINGS.get(DFAdventureLogProcessor.PREF_ENABLE);\n\t\t\t\tconst isGM = game.user.isGM;\n\t\t\t\treturn enabled && isGM;\n\t\t\t},\n\t\t\tcallback: (header) => {\n\t\t\t\tconst chatData = <ChatMessageData><any>ui.chat.collection.get($(header).attr('data-message-id'));\n\t\t\t\tDFAdventureLogProcessor.commandProcessor(chatData.content, true, false);\n\t\t\t\treturn {};\n\t\t\t}\n\t\t});\n\t\toptions.push({\n\t\t\tname: 'DF_CHAT_LOG.ContextMenu_AsGmQuote',\n\t\t\ticon: '<i style=\"color:FireBrick\" class=\"fas fa-quote-right\"></i>',\n\t\t\tcondition: () => {\n\t\t\t\tconst enabled = SETTINGS.get(DFAdventureLogProcessor.PREF_ENABLE);\n\t\t\t\tconst isGM = game.user.isGM;\n\t\t\t\treturn enabled && isGM;\n\t\t\t},\n\t\t\tcallback: (header) => {\n\t\t\t\tconst chatData = <ChatMessageData><any>ui.chat.collection.get($(header).attr('data-message-id'));\n\t\t\t\tif (chatData.content.trimStart().startsWith('\"'))\n\t\t\t\t\tDFAdventureLogProcessor.commandProcessor('q ' + chatData.content, true, false);\n\t\t\t\telse\n\t\t\t\t\tDFAdventureLogProcessor.commandProcessor(`q \"${game.users.get(chatData.user).name}\" ${chatData.content}`, true, false);\n\t\t\t\treturn {};\n\t\t\t}\n\t\t});\n\t}\n\n\tstatic setupSettings() {\n\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_ENABLE, {\n\t\t\tscope: 'world',\n\t\t\tname: 'DF_CHAT_LOG.Setting.EnableTitle',\n\t\t\thint: 'DF_CHAT_LOG.Setting.EnableHint',\n\t\t\tconfig: true,\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tonChange: (enabled: boolean) => {\n\t\t\t\tif (!enabled && !!DFAdventureLogProcessor.logCommand)\n\t\t\t\t\tDFAdventureLogProcessor.deregisterCommand();\n\t\t\t\telse\n\t\t\t\t\tDFAdventureLogProcessor.registerCommand();\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_GMONLY, {\n\t\t\tname: 'DF_CHAT_LOG.Setting.GmOnlyTitle',\n\t\t\thint: 'DF_CHAT_LOG.Setting.GmOnlyHint',\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t\tconfig: true,\n\t\t\tonChange: (gmOnly) => {\n\t\t\t\tif (gmOnly && !game.user.isGM)\n\t\t\t\t\tDFAdventureLogProcessor.deregisterCommand();\n\t\t\t\telse\n\t\t\t\t\tDFAdventureLogProcessor.registerCommand();\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_GMONLY_WHISPER, {\n\t\t\tname: 'DF_CHAT_LOG.Setting.GmOnlyWhisperName',\n\t\t\thint: 'DF_CHAT_LOG.Setting.GmOnlyWhisperHint',\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t\tconfig: true\n\t\t});\n\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_USE_TIME, {\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tname: \"DF_CHAT_LOG.Setting.UseTimeName\",\n\t\t\thint: \"DF_CHAT_LOG.Setting.UseTimeHint\",\n\t\t\tdefault: true,\n\t\t\tconfig: true\n\t\t});\n\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_MESSAGES, {\n\t\t\tname: 'DF_CHAT_LOG.Setting.PrintMessagesName',\n\t\t\thint: 'DF_CHAT_LOG.Setting.PrintMessagesHint',\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tconfig: true\n\t\t});\n\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_SORTDESC, {\n\t\t\tname: 'DF_CHAT_LOG.Setting.SortDescendingName',\n\t\t\thint: 'DF_CHAT_LOG.Setting.SortDescendingHint',\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t\tconfig: true,\n\t\t\tonChange: () => this.resortLog()\n\t\t});\n\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_DISABLE_FORMATTING, {\n\t\t\tname: 'DF_CHAT_LOG.Setting.DisableFormatName'.localize(),\n\t\t\thint: 'DF_CHAT_LOG.Setting.DisableFormatHint'.localize(),\n\t\t\tconfig: true,\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false\n\t\t});\n\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_DISABLE_AUTHOR, {\n\t\t\tname: 'DF_CHAT_LOG.Setting.DisableEntryAuthorName'.localize(),\n\t\t\thint: 'DF_CHAT_LOG.Setting.DisableEntryAuthorHint'.localize(),\n\t\t\tconfig: true,\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false\n\t\t});\n\t\t// If Simple Calendar is enabled\n\t\tif (game.modules.get('foundryvtt-simple-calendar')?.active) {\n\t\t\tSETTINGS.register(DFAdventureLogProcessor.PREF_SIMPLE_CALENDAR, {\n\t\t\t\tscope: 'world',\n\t\t\t\ttype: Boolean,\n\t\t\t\tname: \"DF_CHAT_LOG.Setting.SimpleCalendarName\",\n\t\t\t\thint: \"DF_CHAT_LOG.Setting.SimpleCalendarHint\",\n\t\t\t\tdefault: false,\n\t\t\t\tconfig: true\n\t\t\t});\n\t\t}\n\n\t\tHooks.on('closeDFAdventureLogConfig', () => { DFAdventureLogProcessor.logConfig = null; });\n\t\tif ((game as GameExt).chatCommands)\n\t\t\tDFAdventureLogProcessor.registerCommand();\n\t\telse\n\t\t\tHooks.on('chatCommandsReady', function () { DFAdventureLogProcessor.registerCommand(); });\n\t}\n\n\tstatic deregisterCommand() {\n\t\t(game as GameExt).chatCommands.deregisterCommand(DFAdventureLogProcessor.logCommand);\n\t\t(game as GameExt).chatCommands.deregisterCommand(DFAdventureLogProcessor.plogCommand);\n\t\tif (DFAdventureLogProcessor.gmlogCommand)\n\t\t\t(game as GameExt).chatCommands.deregisterCommand(DFAdventureLogProcessor.gmlogCommand);\n\t\tDFAdventureLogProcessor.logCommand = null;\n\t\tDFAdventureLogProcessor.plogCommand = null;\n\t\tDFAdventureLogProcessor.gmlogCommand = null;\n\t}\n\tstatic registerCommand() {\n\t\tif (!SETTINGS.get(DFAdventureLogProcessor.PREF_ENABLE))\n\t\t\treturn;\n\t\tif (SETTINGS.get(DFAdventureLogProcessor.PREF_GMONLY) && !game.user.isGM)\n\t\t\treturn;\n\t\tif (DFAdventureLogProcessor.logCommand)\n\t\t\treturn;\n\n\t\tDFAdventureLogProcessor.logCommand = (game as GameExt).chatCommands.createCommandFromData({\n\t\t\tcommandKey: \"/log\",\n\t\t\tinvokeOnCommand: async (_cl: any, msg: string, _cd: any) => await DFAdventureLogProcessor.commandProcessor(msg, false, false),\n\t\t\tshouldDisplayToChat: false,\n\t\t\ticonClass: \"fa-edit\",\n\t\t\tdescription: \"DF_CHAT_LOG.CommandDescription\".localize()\n\t\t});\n\t\t(game as GameExt).chatCommands.registerCommand(DFAdventureLogProcessor.logCommand);\n\n\t\tDFAdventureLogProcessor.plogCommand = (game as GameExt).chatCommands.createCommandFromData({\n\t\t\tcommandKey: \"/plog\",\n\t\t\tinvokeOnCommand: async (_cl: any, msg: string, _cd: any) => await DFAdventureLogProcessor.commandProcessor(msg, false, true),\n\t\t\tshouldDisplayToChat: false,\n\t\t\ticonClass: \"fa-edit\",\n\t\t\tdescription: \"DF_CHAT_LOG.PCCommandDescription\".localize()\n\t\t});\n\t\t(game as GameExt).chatCommands.registerCommand(DFAdventureLogProcessor.plogCommand);\n\n\t\t// If we are not the GM, early return to avoid registering the /gmlog command\n\t\tif (!game.user.isGM) return;\n\t\t// Register the /gmlog command\n\t\tDFAdventureLogProcessor.gmlogCommand = (game as GameExt).chatCommands.createCommandFromData({\n\t\t\tcommandKey: \"/gmlog\",\n\t\t\tinvokeOnCommand: async (_cl: any, msg: string, _cd: any) => await DFAdventureLogProcessor.commandProcessor(msg, true, false),\n\t\t\tshouldDisplayToChat: false,\n\t\t\ticonClass: \"fa-edit\",\n\t\t\tdescription: \"DF_CHAT_LOG.GMCommandDescription\".localize()\n\t\t});\n\t\t(game as GameExt).chatCommands.registerCommand(DFAdventureLogProcessor.gmlogCommand);\n\t}\n\n\tprivate static _getTimestamp() {\n\t\tconst useTime = SETTINGS.get(DFAdventureLogProcessor.PREF_USE_TIME);\n\t\tif (game.modules.get('foundryvtt-simple-calendar')?.active && SETTINGS.get(DFAdventureLogProcessor.PREF_SIMPLE_CALENDAR)) {\n\t\t\tconst stamp = SimpleCalendar.api.formatDateTime(SimpleCalendar.api.timestampToDate(SimpleCalendar.api.timestamp()));\n\t\t\treturn useTime ? `${stamp.date} ${stamp.time}` : stamp.date;\n\t\t}\n\t\telse if (useTime)\n\t\t\treturn new Date().toLocaleString('sv').replace(',', '').replace(/ ([AP])/, '$1');\n\t\telse {\n\t\t\treturn new Date().toLocaleString('sv').replace(',', '').replace(/ ([AP])/, '$1').split(' ')[0];\n\t\t}\n\t}\n\n\tprivate static logConfig: DFAdventureLogConfig = null;\n\tstatic async commandProcessor(messageText: string, gmLog: boolean, isPlayerLog: boolean, preventPostToChat = false): Promise<void> {\n\t\tmessageText = messageText.trim();\n\t\tconst tokens = messageText.split(' ');\n\n\t\tif (!SETTINGS.get(DFAdventureLogProcessor.PREF_ENABLE)) {\n\t\t\t(game as GameExt).chatCommands.deregisterCommand(DFAdventureLogProcessor.logCommand);\n\t\t\tui.notifications.warn('DF_CHAT_LOG.Error.Disabled'.localize());\n\t\t\treturn;\n\t\t}\n\n\t\t// If the user did not enter anything, send them a help message\n\t\tif (messageText.length == 0 || tokens.every(x => x.length == 0)) {\n\t\t\tsetTimeout(async () => {\n\t\t\t\tawait Dialog.prompt({\n\t\t\t\t\ttitle: 'DF_CHAT_LOG.HelpDialog_Title'.localize(),\n\t\t\t\t\tlabel: 'OK',\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-empty-function\n\t\t\t\t\tcallback: () => { },\n\t\t\t\t\tcontent: await renderTemplate(`modules/df-chat-enhance/templates/lang/log-help.${'DF_CHAT_ENHANCE.LANG'.localize()}.hbs`, {\n\t\t\t\t\t\tisGM: game.user.isGM\n\t\t\t\t\t}),\n\t\t\t\t\toptions: { width: 800 }\n\t\t\t\t});\n\t\t\t}, 1);\n\t\t\treturn;\n\t\t}\n\n\t\tconst speaker = ChatMessage.getSpeaker(<any>{ user: game.user });\n\t\tconst messageData: DeepPartial<ChatMessageDataConstructorData> = {\n\t\t\tflavor: '',\n\t\t\tuser: game.user.id,\n\t\t\tspeaker: speaker,\n\t\t\ttype: CONST.CHAT_MESSAGE_TYPES.OOC,\n\t\t\tcontent: '',\n\t\t};\n\t\tlet line: string;\n\t\tconst disableFormatting = SETTINGS.get(DFAdventureLogProcessor.PREF_DISABLE_FORMATTING);\n\t\tconst disableAuthor = isPlayerLog || SETTINGS.get(DFAdventureLogProcessor.PREF_DISABLE_AUTHOR);\n\t\tswitch (tokens[0].toLowerCase()) {\n\t\t\tcase 'config':\n\t\t\t\tif (!game.user.isGM) {\n\t\t\t\t\tui.notifications.warn('DF_CHAT_LOG.Error.ConfigGmOnly'.localize());\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsetTimeout(async () => {\n\t\t\t\t\tif (DFAdventureLogProcessor.logConfig)\n\t\t\t\t\t\tDFAdventureLogProcessor.logConfig.bringToTop();\n\t\t\t\t\telse {\n\t\t\t\t\t\tDFAdventureLogProcessor.logConfig = new DFAdventureLogConfig({});\n\t\t\t\t\t\tDFAdventureLogProcessor.logConfig.render(true);\n\t\t\t\t\t}\n\t\t\t\t}, 1);\n\t\t\t\treturn;\n\t\t\tcase 'q':\n\t\t\tcase 'quote':\n\t\t\t\tmessageText = messageText.replace(tokens[0], '').trimStart();\n\t\t\t\tlet source: string;\n\t\t\t\t// If the token starts with a quote, but does not end with one\n\t\t\t\tif (tokens[1][0] === '\"' && tokens[1][tokens[1].length - 1] !== '\"') {\n\t\t\t\t\t// Extract the quoted Source\n\t\t\t\t\tlet index = -1;\n\t\t\t\t\tfor (let c = 1; c < messageText.length; c++) {\n\t\t\t\t\t\tif (messageText[c] === '\"') {\n\t\t\t\t\t\t\tindex = c;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (index < 0) {\n\t\t\t\t\t\tui.notifications.error('DF_CHAT_LOG.Error.MissingQuote'.localize().replace('{0}', tokens[1]));\n\t\t\t\t\t\tsetTimeout(() => $('#chat-message').val('/log q ' + messageText), 1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsource = messageText.slice(0, index + 1);\n\t\t\t\t\tmessageText = messageText.slice(index + 1).trimStart();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tsource = tokens[1];\n\t\t\t\tmessageText = DFChatEditor.processMarkdown(messageText)[1].replace(source, '').trim();\n\t\t\t\t// Remove any double-quotes surrounding the source token\n\t\t\t\tsource = source.replace(/\"/gm, '');\n\t\t\t\tmessageData.flavor = `${game.user.name} quoted ${source}`;\n\t\t\t\tmessageData.content = `<span class=\"dfal-qu\">${messageText}</span>`;\n\t\t\t\tif (messageText.length == 0) {\n\t\t\t\t\tui.notifications.error('DF_CHAT_LOG.Error.MissingMessage'.localize());\n\t\t\t\t\tsetTimeout(() => $('#chat-message').val(`/log q \"${source}\" ${messageText}`), 1);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tline = 'DF_CHAT_LOG.Log_Quote';\n\t\t\t\tif (disableFormatting) line += '_Bland';\n\t\t\t\tif (disableAuthor) line += '_NoAuth';\n\t\t\t\tline = line.localize();\n\t\t\t\tline = line.replace('{0}', this._getTimestamp());\n\t\t\t\tline = line.replace('{1}', game.user.name);\n\t\t\t\tline = line.replace('{2}', source);\n\t\t\t\tmessageText = line.replace('{3}', messageText);\n\t\t\t\tbreak;\n\t\t\tcase 'e':\n\t\t\tcase 'event':\n\t\t\t\tmessageText = messageText.replace(tokens[0], '').trim();\n\t\t\t// fallthrough\n\t\t\tdefault:\n\t\t\t\tmessageText = DFChatEditor.processMarkdown(messageText)[1].trim();\n\t\t\t\tmessageData.flavor = 'Event Logged';\n\t\t\t\tmessageData.content = `<span class=\"dfal-ev\">${messageText}</span>`;\n\t\t\t\tline = 'DF_CHAT_LOG.Log_Event';\n\t\t\t\tif (disableFormatting) line += '_Bland';\n\t\t\t\tif (disableAuthor) line += '_NoAuth';\n\t\t\t\tline = line.localize();\n\t\t\t\tline = line.replace('{0}', this._getTimestamp());\n\t\t\t\tline = line.replace('{1}', game.user.name);\n\t\t\t\tmessageText = line.replace('{2}', messageText);\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// fetch the log to submit to\n\t\tconst journalId = (isPlayerLog ? game.user.getFlag(SETTINGS.MOD_NAME, this.PREF_PLAYER_LOG_JOURNAL) as string :\n\t\t\tSETTINGS.get<string>(gmLog ? DFAdventureLogConfig.PREF_JOURNAL_GM : DFAdventureLogConfig.PREF_JOURNAL))\n\t\t\t?.split('.');\n\t\tif (!journalId || !game.journal.has(journalId[0])) {\n\t\t\tif (isPlayerLog)\n\t\t\t\tui.notifications.error('DF_CHAT_LOG.Error.NoPlayerJournalSet'.localize());\n\t\t\telse if (game.user.isGM)\n\t\t\t\tui.notifications.error('DF_CHAT_LOG.Error.NoJournalSetGM'.localize(), { permanent: true });\n\t\t\telse\n\t\t\t\tui.notifications.warn('DF_CHAT_LOG.Error.NoJournalSet'.localize());\n\t\t\treturn;\n\t\t}\n\t\tconst journal = game.journal.get(journalId[0]).pages.get(journalId[1]);\n\t\tlet html = $(journal.text.content);\n\t\tconst messageHtml = $(messageText);\n\t\tlet section = html.find('section.df-adventure-log');\n\t\tif (section.length == 0) {\n\t\t\tawait DFAdventureLogConfig.initializeJournal(journalId.join('.'), false, gmLog, isPlayerLog);\n\t\t\thtml = $(journal.text.content);\n\t\t\tsection = html.find('section.df-adventure-log');\n\t\t}\n\t\tconst descending = SETTINGS.get(this.PREF_SORTDESC) as boolean;\n\t\tif (descending) section.prepend(messageHtml); else section.append(messageHtml);\n\t\tawait journal.update({ 'text.content': $('<div></div>').append(html).html() });\n\t\tconst rollType = game.settings.get(\"core\", \"rollMode\");\n\t\tif (game.user.isGM) {\n\t\t\tif (\n\t\t\t\t// If the roll type is anything but Public\n\t\t\t\trollType !== 'publicroll'\n\t\t\t\t// If logs are GM Only and the Whisper All settings is true\n\t\t\t\t|| (SETTINGS.get(DFAdventureLogProcessor.PREF_GMONLY) &&\n\t\t\t\t\tSETTINGS.get(DFAdventureLogProcessor.PREF_GMONLY_WHISPER))\n\t\t\t) {\n\t\t\t\t// Make the message a whisper\n\t\t\t\tmessageData.whisper = [game.user.id];\n\t\t\t}\n\t\t}\n\t\t// All GM and Player logs are whispered\n\t\tif (isPlayerLog || gmLog) {\n\t\t\tmessageData.whisper = [game.user.id];\n\t\t}\n\t\t// Post message to chat if Messages are enabled\n\t\tif (!preventPostToChat && SETTINGS.get(DFAdventureLogProcessor.PREF_MESSAGES))\n\t\t\tawait ChatMessage.create(messageData, {});\n\t}\n\n\tstatic async resortLog() {\n\t\tconst descending = SETTINGS.get(this.PREF_SORTDESC) as boolean;\n\t\tconst journalAll = (SETTINGS.get(DFAdventureLogConfig.PREF_JOURNAL) as string)?.split('.');\n\t\tconst journalGM = (SETTINGS.get(DFAdventureLogConfig.PREF_JOURNAL_GM) as string)?.split('.');\n\n\t\tconst journalSort = async (journal: JournalEntryPage) => {\n\t\t\tconst html = $(journal.text?.content);\n\t\t\tconst article = html.find('article.df-adventure-log');\n\t\t\tconst result = (article.find('p') as any).sort(function (a: HTMLElement, b: HTMLElement) {\n\t\t\t\treturn descending ?\n\t\t\t\t\t$(b).find('span.dfal-ts').text().localeCompare($(a).find('span.dfal-ts').text()) :\n\t\t\t\t\t$(a).find('span.dfal-ts').text().localeCompare($(b).find('span.dfal-ts').text());\n\n\t\t\t});\n\t\t\tarticle.html(result);\n\t\t\tawait journal.update({ 'text.content': $('<div></div>').append(html).html() });\n\t\t};\n\n\t\tif (game.journal.has(journalAll[0]))\n\t\t\tawait journalSort(game.journal.get(journalAll[0]).pages.get(journalAll[1]));\n\t\tif (game.journal.has(journalGM[0]))\n\t\t\tawait journalSort(game.journal.get(journalGM[0]).pages.get(journalGM[1]));\n\t}\n}","import libWrapperShared from \"../../../common/libWrapperShared\";\nimport SETTINGS from \"../../../common/Settings\";\nimport DFAdventureLogConfig from \"./DFAdventureLogConfig\";\nimport DFAdventureLogProcessor from \"./DFAdventureLogProcessor\";\n\ninterface AdventurLogApi {\n\tevent(message: string, postToChat?: boolean): Promise<void>\n\tpevent(message: string, postToChat?: boolean): Promise<void>\n\tgmevent(message: string, postToChat?: boolean): Promise<void>\n\tquote(speaker: string, message: string, postToChat?: boolean): Promise<void>\n\tpquote(speaker: string, message: string, postToChat?: boolean): Promise<void>\n\tgmquote(speaker: string, message: string, postToChat?: boolean): Promise<void>\n}\ndeclare global {\n\tconst AdventureLog: AdventurLogApi;\n}\n\nexport function init() {\n\tconst api: AdventurLogApi = {\n\t\tevent: (async function (message: string, postToChat = false) {\n\t\t\tDFAdventureLogProcessor.commandProcessor('event ' + message, false, false, !postToChat);\n\t\t}).bind(DFAdventureLogProcessor),\n\n\t\tpevent: (async function (message: string, postToChat = false) {\n\t\t\tDFAdventureLogProcessor.commandProcessor('event ' + message, false, true, !postToChat);\n\t\t}).bind(DFAdventureLogProcessor),\n\n\t\tgmevent: (async function (message: string, postToChat = false) {\n\t\t\tif (game.user.isGM)\n\t\t\t\tDFAdventureLogProcessor.commandProcessor('event ' + message, true, false, !postToChat);\n\t\t\telse ui.notifications.warn(\"DF_CHAT_LOG.Error.ApiLog_NotGm\".localize());\n\t\t}).bind(DFAdventureLogProcessor),\n\n\t\tquote: (async function (speaker: string, message: string, postToChat = false) {\n\t\t\tDFAdventureLogProcessor.commandProcessor(`quote \"${speaker}\" ${message}`, false, false, !postToChat);\n\t\t}).bind(DFAdventureLogProcessor),\n\n\t\tpquote: (async function (speaker: string, message: string, postToChat = false) {\n\t\t\tDFAdventureLogProcessor.commandProcessor(`quote \"${speaker}\" ${message}`, false, true, !postToChat);\n\t\t}).bind(DFAdventureLogProcessor),\n\n\t\tgmquote: (async function (speaker: string, message: string, postToChat = false) {\n\t\t\tif (game.user.isGM)\n\t\t\t\tDFAdventureLogProcessor.commandProcessor(`quote \"${speaker}\" ${message}`, true, false, !postToChat);\n\t\t\telse ui.notifications.warn(\"DF_CHAT_LOG.Error.ApiLog_NotGm\".localize());\n\t\t}).bind(DFAdventureLogProcessor)\n\t};\n\t// @ts-expect-error\n\twindow.AdventureLog = api;\n}\nexport function ready() {\n\tif (!game.modules.get('lib-wrapper')?.active) return;\n\tDFAdventureLogConfig.setupSettings();\n\tDFAdventureLogProcessor.setupSettings();\n\n\tHooks.on('renderUserConfig', (_app: UserConfig, html: JQuery<HTMLElement>, data: UserConfig.Data<any>) => {\n\t\tconst journal = (<string>data.user.getFlag(SETTINGS.MOD_NAME, DFAdventureLogProcessor.PREF_PLAYER_LOG_JOURNAL))?.split('.');\n\t\tconst template = Handlebars.compile(`\n<div class=\"form-group\">\n\t<label for=\"dfce-player-log\">Player Log Journal</label>\n\t<div class=\"form-fields\">\n\t\t<select id=\"dfce-player-log\" name=\"player-log\">\n\t\t\t{{#each journals}}\n\t\t\t<option value=\"{{id}}\" {{#if selected}} selected{{/if}}>{{name}}</option>\n\t\t\t{{/each}}\n\t\t</select>\n\t</div>\n</div>\n<div class=\"form-group\">\n\t<label for=\"dfce-player-log-page\">Player Log Journal Page</label>\n\t<div class=\"form-fields\">\n\t\t<select id=\"dfce-player-log-page\" name=\"player-log-page\">\n\t\t\t{{#each pages}}\n\t\t\t<option value=\"{{id}}\"{{#if selected}} selected{{/if}}>{{name}}</option>\n\t\t\t{{/each}}\n\t\t</select>\n\t</div>\n</div>\n`);\n\t\tconst journals = ui.journal.documents\n\t\t\t.filter(x => x.testUserPermission(data.user, CONST.DOCUMENT_PERMISSION_LEVELS.OBSERVER))\n\t\t\t.filter(x => x.pages.contents.some(y => y.type === 'text'));\n\t\tconst journalSelection = $(template({\n\t\t\tselected: journal ?? '',\n\t\t\tjournals: [{ id: '', name: '---', selected: !journal }].concat(journals.map(x => ({\n\t\t\t\tid: x.id,\n\t\t\t\tname: x.name,\n\t\t\t\tselected: x.id === journal[0]\n\t\t\t}))),\n\t\t\tpages: journal ? journals.find(x => x.id == journal[0]).pages.contents.filter(x => x.type === 'text').map(x => ({\n\t\t\t\tid: x.id,\n\t\t\t\tname: x.name,\n\t\t\t\tselected: x.id === journal[1]\n\t\t\t})) : []\n\t\t}, {\n\t\t\tallowProtoMethodsByDefault: true,\n\t\t\tallowProtoPropertiesByDefault: true\n\t\t}));\n\t\thtml.find('#characters').parent().before(journalSelection);\n\t\tjournalSelection.find('#dfce-player-log').on('change', event => {\n\t\t\tconst journalId = (event.currentTarget as HTMLSelectElement).value;\n\t\t\tconst pageElement = journalSelection.find('#dfce-player-log-page');\n\t\t\tpageElement.children().remove();\n\t\t\tif (!journalId || journalId.length === 0) return;\n\t\t\tfor (const page of game.journal.get(journalId).pages.contents.filter(x => x.type === 'text')) {\n\t\t\t\tpageElement.append(`<option value=\"${journalId}.${page.id}\">${page.name}</option>`);\n\t\t\t}\n\t\t});\n\t});\n\n\tlibWrapperShared.register('UserConfig.prototype._updateObject',\n\t\tasync function (this: UserConfig, wrapped: (...args: any) => any, event: any, formData: { \"player-log-page\": string }) {\n\t\t\tawait this.object.setFlag(SETTINGS.MOD_NAME, DFAdventureLogProcessor.PREF_PLAYER_LOG_JOURNAL, formData[\"player-log-page\"]);\n\t\t\treturn await wrapped(event, formData);\n\t\t});\n\n\tmigrateDataV9toV10();\n}\n\nasync function migrateDataV9toV10() {\n\tif (!game.user.isGM) return;\n\tlet journalId = SETTINGS.get<string>(DFAdventureLogConfig.PREF_JOURNAL);\n\tif (checkJournal(journalId))\n\t\tawait SETTINGS.set<string>(DFAdventureLogConfig.PREF_JOURNAL, await migrateJournalV9toV10(journalId));\n\tjournalId = SETTINGS.get<string>(DFAdventureLogConfig.PREF_JOURNAL_GM);\n\tif (checkJournal(journalId))\n\t\tawait SETTINGS.set<string>(DFAdventureLogConfig.PREF_JOURNAL_GM, await migrateJournalV9toV10(journalId));\n\n\tfor (const user of game.users) {\n\t\tjournalId = <string>user.getFlag(SETTINGS.MOD_NAME, DFAdventureLogProcessor.PREF_PLAYER_LOG_JOURNAL);\n\t\tif (!checkJournal(journalId)) continue;\n\t\tjournalId = await migrateJournalV9toV10(journalId);\n\t\tif (!journalId)\n\t\t\tawait user.unsetFlag(SETTINGS.MOD_NAME, DFAdventureLogProcessor.PREF_PLAYER_LOG_JOURNAL);\n\t\telse\n\t\t\tawait user.setFlag(SETTINGS.MOD_NAME, DFAdventureLogProcessor.PREF_PLAYER_LOG_JOURNAL, journalId);\n\t}\n}\n\nfunction checkJournal(id: string) { return id && id.split('.').length < 2; }\n\nasync function migrateJournalV9toV10(id: string): Promise<string | null> {\n\tconst journal = game.journal.get(id);\n\tif (!journal) return null;\n\tconst page = journal.pages.contents.find(x => x.type == 'text');\n\tif (!page) return null;\n\treturn journal.id + '.' + page.id;\n}\n","import { ChatMessageData } from \"@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs\";\nimport libWrapperShared from \"../../../common/libWrapperShared\";\nimport SETTINGS from \"../../../common/Settings\";\nimport DFChatArchiveManager from \"../archive/DFChatArchiveManager\";\n\n\nexport default class ChatMerge {\n\n\tprivate static readonly PREF_ENABLED = 'chat-merge-enabled';\n\tprivate static readonly PREF_SPLIT_SPEAKER = 'chat-merge-split-speaker';\n\tprivate static readonly PREF_EPOCH = 'chat-merge-epoch';\n\tprivate static readonly PREF_ALLOW_ROLLS = 'chat-merge-allowRolls';\n\tprivate static readonly PREF_SEPARATE = 'chat-merge-separateWithBorder';\n\tprivate static readonly PREF_HOVER = 'chat-merge-showhover';\n\tprivate static readonly PREF_SHOW_HEADER = 'chat-merge-showheader';\n\n\tprivate static get _enabled(): boolean { return SETTINGS.get(this.PREF_ENABLED); }\n\tprivate static get _epoch(): number { return SETTINGS.get(this.PREF_EPOCH); }\n\tprivate static get _allowRolls(): string { return SETTINGS.get(this.PREF_ALLOW_ROLLS); }\n\tprivate static get _separateWithBorder(): boolean { return SETTINGS.get(this.PREF_SEPARATE); }\n\tprivate static get _showHover(): boolean { return SETTINGS.get(this.PREF_HOVER); }\n\tprivate static get _showHeader(): boolean { return SETTINGS.get(this.PREF_SHOW_HEADER); }\n\n\tstatic init() {\n\t\tSETTINGS.register(this.PREF_ENABLED, {\n\t\t\tname: 'DF_CHAT_MERGE.EnableName',\n\t\t\thint: 'DF_CHAT_MERGE.EnableHint',\n\t\t\tconfig: true,\n\t\t\tscope: 'client',\n\t\t\tdefault: true,\n\t\t\ttype: Boolean,\n\t\t\tonChange: () => this._processAllMessage()\n\t\t});\n\t\tSETTINGS.register(this.PREF_SHOW_HEADER, {\n\t\t\tname: 'DF_CHAT_MERGE.ShowHeaderName',\n\t\t\thint: 'DF_CHAT_MERGE.ShowHeaderHint',\n\t\t\tconfig: true,\n\t\t\tscope: 'client',\n\t\t\tdefault: false,\n\t\t\ttype: Boolean,\n\t\t\tonChange: (newValue: boolean) => {\n\t\t\t\tconst style = (<HTMLElement>document.querySelector(':root')).style;\n\t\t\t\tstyle.setProperty('--dfce-cm-header', newValue ? '' : 'none');\n\t\t\t\tif (game.user.isGM) {\n\t\t\t\t\tstyle.setProperty('--dfce-cm-header-delete', newValue ? '' : '0');\n\t\t\t\t\tstyle.setProperty('--dfce-cm-header-delete-pad', newValue ? '' : '16px');\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register(this.PREF_SPLIT_SPEAKER, {\n\t\t\tname: 'DF_CHAT_MERGE.SplitSpeakerName',\n\t\t\thint: 'DF_CHAT_MERGE.SplitSpeakerHint',\n\t\t\tconfig: true,\n\t\t\tscope: 'client',\n\t\t\tdefault: true,\n\t\t\ttype: Boolean,\n\t\t\tonChange: () => this._processAllMessage()\n\t\t});\n\t\tSETTINGS.register<string>(this.PREF_ALLOW_ROLLS, {\n\t\t\tname: 'DF_CHAT_MERGE.AllowRollsName',\n\t\t\thint: 'DF_CHAT_MERGE.AllowRollsHint',\n\t\t\tconfig: true,\n\t\t\tscope: 'client',\n\t\t\tdefault: 'rolls',\n\t\t\ttype: String,\n\t\t\tchoices: {\n\t\t\t\tnone: 'DF_CHAT_MERGE.AllowRollsOptions.none'.localize(),\n\t\t\t\trolls: 'DF_CHAT_MERGE.AllowRollsOptions.rolls'.localize(),\n\t\t\t\tall: 'DF_CHAT_MERGE.AllowRollsOptions.all'.localize()\n\t\t\t},\n\t\t\tonChange: () => this._processAllMessage()\n\t\t});\n\t\tSETTINGS.register(this.PREF_SEPARATE, {\n\t\t\tname: 'DF_CHAT_MERGE.SeparateName',\n\t\t\thint: 'DF_CHAT_MERGE.SeparateHint',\n\t\t\tconfig: true,\n\t\t\tscope: 'client',\n\t\t\tdefault: false,\n\t\t\ttype: Boolean,\n\t\t\tonChange: (newValue: boolean) => {\n\t\t\t\tconst style = (<HTMLElement>document.querySelector(':root')).style;\n\t\t\t\tstyle.setProperty('--dfce-cm-separation', newValue ? '' : '0');\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register(this.PREF_HOVER, {\n\t\t\tname: 'DF_CHAT_MERGE.HoverName',\n\t\t\thint: 'DF_CHAT_MERGE.HoverHint',\n\t\t\tconfig: true,\n\t\t\tscope: 'client',\n\t\t\tdefault: true,\n\t\t\ttype: Boolean,\n\t\t\tonChange: (newValue: boolean) => {\n\t\t\t\tconst style = (<HTMLElement>document.querySelector(':root')).style;\n\t\t\t\tnewValue ? style.removeProperty('--dfce-cm-hover-shadow') : style.setProperty('--dfce-cm-hover-shadow', '0px');\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register<number>(this.PREF_EPOCH, {\n\t\t\tname: 'DF_CHAT_MERGE.EpochName',\n\t\t\thint: 'DF_CHAT_MERGE.EpochHint',\n\t\t\tconfig: true,\n\t\t\tscope: 'client',\n\t\t\tdefault: 10,\n\t\t\ttype: Number,\n\t\t\trange: {\n\t\t\t\tmin: 1,\n\t\t\t\tmax: 60,\n\t\t\t\tstep: 1\n\t\t\t},\n\t\t\tonChange: () => this._processAllMessage()\n\t\t});\n\n\t\tlibWrapperShared.register('ChatLog.prototype.deleteMessage', this._deleteMessage.bind(this));\n\t\tHooks.on(\"renderChatMessage\", this._renderChatMessage);\n\t}\n\tstatic ready() {\n\t\tconst style = (<HTMLElement>document.querySelector(':root')).style;\n\t\tstyle.setProperty('--dfce-cm-separation', this._separateWithBorder ? '' : '0');\n\t\tthis._showHover ? style.removeProperty('--dfce-cm-hover-shadow') : style.setProperty('--dfce-cm-hover-shadow', '0px');\n\t\tstyle.setProperty('--dfce-cm-header', this._showHeader ? '' : 'none');\n\t\tif (game.user.isGM) {\n\t\t\tstyle.setProperty('--dfce-cm-header-delete', this._showHeader ? '' : '0');\n\t\t\tstyle.setProperty('--dfce-cm-header-delete-pad', this._showHeader ? '' : '16px');\n\t\t}\n\t\tthis._processAllMessage(ui.chat.element);\n\t\tHooks.on('renderChatLog', (_: any, html: JQuery<HTMLElement>) => this._processAllMessage(html));\n\t\tHooks.on('renderDFChatArchiveViewer', (_: any, html: JQuery<HTMLElement>) => this._processAllMessage(html));\n\t}\n\n\tprivate static _deleteMessage(wrapper: (arg0: any, arg1: any) => any, messageId: string, { deleteAll = false } = {}) {\n\t\t// Ignore the Delete All process. Everything is being obliterated, who cares about the styling\n\t\tif (!deleteAll && this._enabled) {\n\t\t\tconst element = document.querySelector(`li[data-message-id=\"${messageId}\"`);\n\t\t\t// If we were a TOP\n\t\t\tif (element?.classList?.contains('dfce-cm-top')) {\n\t\t\t\telement.classList.remove('dfce-cm-top');\n\t\t\t\t// If the next element was a middle, make it a top\n\t\t\t\tif (element.nextElementSibling.classList.contains('dfce-cm-middle')) {\n\t\t\t\t\telement.nextElementSibling.classList.remove('dfce-cm-middle');\n\t\t\t\t\telement.nextElementSibling.classList.add('dfce-cm-top');\n\t\t\t\t}\n\t\t\t\t// Otherwise, it was a bottom and should now become a normal message again\n\t\t\t\telse element.nextElementSibling.classList.remove('dfce-cm-bottom');\n\t\t\t}\n\t\t\t// If we were a BOTTOM\n\t\t\telse if (element?.classList?.contains('dfce-cm-bottom')) {\n\t\t\t\telement.classList.remove('dfce-cm-bottom');\n\t\t\t\t// If the previous element was a middle, make it a bottom\n\t\t\t\tif (element.previousElementSibling.classList.contains('dfce-cm-middle')) {\n\t\t\t\t\telement.previousElementSibling.classList.remove('dfce-cm-middle');\n\t\t\t\t\telement.previousElementSibling.classList.add('dfce-cm-bottom');\n\t\t\t\t}\n\t\t\t\t// Otherwise, it was a top and should now become a normal message again\n\t\t\t\telse element.previousElementSibling.classList.remove('dfce-cm-top');\n\t\t\t}\n\t\t\t// If we were a MIDDLE, let the above and below snug and they'll be fine\n\t\t\telse if (element?.classList?.contains('dfce-cm-middle'))\n\t\t\t\telement.classList.remove('dfce-cm-middle');\n\t\t}\n\t\treturn wrapper(messageId, { deleteAll });\n\t}\n\n\tprivate static _processAllMessage(element?: JQuery<HTMLElement>) {\n\t\telement = element ?? $(document.body);\n\t\t// Remove the old CSS class designations\n\t\telement.find('.dfce-cm-top').removeClass('dfce-cm-top');\n\t\telement.find('.dfce-cm-middle').removeClass('dfce-cm-middle');\n\t\telement.find('.dfce-cm-bottom').removeClass('dfce-cm-bottom');\n\t\t// If we are disabled, return\n\t\tif (!ChatMerge._enabled) return;\n\t\t// Collect all rendered chat messages\n\t\tconst messages = element.find('li.chat-message');\n\t\t// Return if there are no messages rendered\n\t\tif (messages.length === 0) return;\n\t\t// Make sure to set the hover colour for the first message since we skip it in the processor bellow.\n\t\tif (messages[0].hasAttribute('style')) {\n\t\t\tmessages[0].style.setProperty('--dfce-mc-border-color', messages[0].style.borderColor);\n\t\t}\n\t\t// Process each message after the first\n\t\tfor (let c = 1; c < messages.length; c++) {\n\t\t\t// Update styling of the chat messages\n\t\t\tthis._styleChatMessages(\n\t\t\t\tgame.messages.get(messages[c].getAttribute('data-message-id')),\n\t\t\t\tmessages[c],\n\t\t\t\tgame.messages.get(messages[c - 1].getAttribute('data-message-id')),\n\t\t\t\tmessages[c - 1]);\n\t\t}\n\t}\n\n\tprivate static _renderChatMessage(message: ChatMessageData, html: JQuery<HTMLElement>, _cmd: ChatMessageData) {\n\t\tif (!ChatMerge._enabled) return;\n\t\t// Find the most recent message in the chat log\n\t\tconst partnerElem = $(`li.chat-message`).last()[0];\n\t\t// If there is no message, return\n\t\tif (partnerElem === null || partnerElem === undefined) return;\n\t\t// get the ChatMessage document associated with the html\n\t\tconst partner = game.messages.get(partnerElem.getAttribute('data-message-id'));\n\t\tif (!message || !partner) return;\n\t\t// Update styling of the chat messages\n\t\tChatMerge._styleChatMessages(message, html[0], partner, partnerElem);\n\t}\n\n\tprivate static _inTimeFrame(current: number, previous: number): boolean {\n\t\treturn current > previous && (current - previous) < (this._epoch * 1000);\n\t}\n\n\tprivate static _isValidMessage(current: ChatMessageData, previous: ChatMessageData): boolean {\n\t\tconst rolls = this._allowRolls;\n\t\tconst splitSpeaker = SETTINGS.get<boolean>(this.PREF_SPLIT_SPEAKER);\n\t\tlet userCompare = false;\n\n\t\tconst currData = current ?? <ChatMessageData><any>current;\n\t\tconst prevData = previous ?? <ChatMessageData><any>previous;\n\n\t\t// If either message is a Midi-QoL message, ignore it\n\t\tif ((currData?.flags && (currData.flags as Record<string, any>)['midi-qol']) || (prevData?.flags && (prevData.flags as Record<string, any>)['midi-qol']))\n\t\t\treturn false;\n\n\t\tif (splitSpeaker) {\n\t\t\t// this is a bit complex, basically we want to group by actors, but if you're not using an actor, group by user instead\n\t\t\tuserCompare = ( // If actors are equal and NOT null\n\t\t\t\tcurrData.speaker.actor === prevData.speaker.actor\n\t\t\t\t&& !!currData.speaker.actor\n\t\t\t) ||\n\t\t\t\t( // If BOTH actors are null and users are equal\n\t\t\t\t\t!currData.speaker.actor\n\t\t\t\t\t&& !prevData.speaker.actor\n\t\t\t\t\t&& currData.user === prevData.user\n\t\t\t\t);\n\t\t} else {\n\t\t\t// If we are not splitting by speaker, just do the simple option of comparing the users\n\t\t\tuserCompare = currData.user === prevData.user;\n\t\t}\n\t\treturn userCompare\n\t\t\t&& this._inTimeFrame(currData.timestamp, prevData.timestamp)\n\t\t\t// Check for merging with roll types\n\t\t\t&& (rolls === 'all'\n\t\t\t\t|| (rolls === 'rolls' && current.isRoll === previous.isRoll)\n\t\t\t\t|| (rolls === 'none' && !current.isRoll && !previous.isRoll));\n\t}\n\n\tprivate static _styleChatMessages(curr: ChatMessageData, currElem: HTMLElement, prev: ChatMessageData, prevElem: HTMLElement) {\n\t\tif (currElem.hasAttribute('style')) {\n\t\t\tcurrElem.style.setProperty('--dfce-mc-border-color', currElem.style.borderColor);\n\t\t}\n\t\t// If we are running in a Chat Archive\n\t\tif (curr === undefined && prev === undefined) {\n\t\t\tconst logId = parseInt(/df-chat-log-(\\d+)/.exec(currElem.parentElement.parentElement.id)[1]);\n\t\t\tif (isNaN(logId)) return;\n\t\t\tconst chatLog = DFChatArchiveManager.chatViewers.get(logId);\n\t\t\tcurr = <ChatMessageData>chatLog.messages.find(x =>\n\t\t\t\t(x.id ?? x._id) == currElem.dataset.messageId);\n\t\t\tprev = <ChatMessageData>chatLog.messages.find(x =>\n\t\t\t\t(x.id ?? x._id) == prevElem.dataset.messageId);\n\t\t}\n\t\tif (!ChatMerge._isValidMessage(curr, prev)) return;\n\t\tif (prevElem.classList.contains('dfce-cm-bottom')) {\n\t\t\tprevElem.classList.remove('dfce-cm-bottom');\n\t\t\tprevElem.classList.add('dfce-cm-middle');\n\t\t} else prevElem.classList.add('dfce-cm-top');\n\t\tcurrElem.classList.add('dfce-cm-bottom');\n\t}\n}","import libWrapperShared from \"../../../common/libWrapperShared\";\nimport SETTINGS from \"../../../common/Settings\";\nimport UTIL from '../Util';\n\nexport default class PlayerColor {\n\tstatic readonly PREF_TINT_BG = 'PlayerColor_TintBackground';\n\tstatic readonly PREF_BORDER_STYLE = 'PlayerColor.BorderStyle';\n\tstatic readonly FLAG_CHAT_COLOR = 'chat-color';\n\n\tstatic init() {\n\t\tSETTINGS.register(PlayerColor.PREF_TINT_BG, {\n\t\t\tconfig: true,\n\t\t\tname: 'DF_CHAT_PLAYER_COLOR.SettingTintBackgroundName',\n\t\t\thint: 'DF_CHAT_PLAYER_COLOR.SettingTintBackgroundHint',\n\t\t\tscope: 'world',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t\tonChange: UTIL.reloadChatLog\n\t\t});\n\t\tSETTINGS.register<string>(PlayerColor.PREF_BORDER_STYLE, {\n\t\t\tname: 'DF_CHAT_PLAYER_COLOR.SettingBorderStyleName',\n\t\t\thint: 'DF_CHAT_PLAYER_COLOR.SettingBorderStyleHint',\n\t\t\tconfig: true,\n\t\t\ttype: String,\n\t\t\tchoices: {\n\t\t\t\tall: 'DF_CHAT_PLAYER_COLOR.BorderStyle.all',\n\t\t\t\tmine: 'DF_CHAT_PLAYER_COLOR.BorderStyle.mine',\n\t\t\t\tnone: 'DF_CHAT_PLAYER_COLOR.BorderStyle.none'\n\t\t\t},\n\t\t\tdefault: 'all',\n\t\t\tscope: 'client',\n\t\t\tonChange: UTIL.reloadChatLog\n\t\t});\n\n\t\tHooks.on('renderUserConfig', (app: UserConfig, html: JQuery<HTMLElement>, data: UserConfig.Data<any>) => {\n\t\t\tconst color = data.user.getFlag(SETTINGS.MOD_NAME, PlayerColor.FLAG_CHAT_COLOR) ?? '';\n\t\t\thtml.find('input[name=\"color\"]').parent().parent().after(`\n<div class=\"form-group\">\n\t<label for=\"chat-color\">${'DF_CHAT_PLAYER_COLOR.Label'.localize()}</label>\n\t<div class=\"form-fields\">\n\t\t<input class=\"color\" id=\"chat-color\" type=\"text\" name=\"chat-color\" value=\"${color}\">\n\t\t<input type=\"color\" value=\"${color}\" data-edit=\"chat-color\">\n\t</div>\n</div>`);\n\t\t\tconst chatField = html.find('#chat-color');\n\t\t\tconst chatPicker = html.find('[data-edit=\"chat-color\"]');\n\t\t\t// Make sure to update the color selector if a manual entry occurs\n\t\t\tchatField.on('change', () => chatPicker.val(chatField.val()));\n\t\t\t// Resize the window to encompass the new fields\n\t\t\tapp.element[0].style.height = '';\n\t\t\tapp.setPosition({});\n\t\t});\n\n\t\tlibWrapperShared.register('UserConfig.prototype._updateObject',\n\t\t\tasync function (this: UserConfig, wrapped: (arg0: any, arg1: any) => any, event: any, formData: { \"chat-color\": string }): Promise<void> {\n\t\t\t\tawait this.object.setFlag(SETTINGS.MOD_NAME, PlayerColor.FLAG_CHAT_COLOR, formData[\"chat-color\"]);\n\t\t\t\tawait wrapped(event, formData);\n\t\t\t});\n\n\t\tlibWrapper.register(SETTINGS.MOD_NAME, 'ChatMessage.prototype.getHTML', async function (this: ChatMessage, wrapper: (...arg: any) => Promise<JQuery<HTMLElement>>, ...args: any) {\n\t\t\tconst html = await wrapper(...args);\n\t\t\t// If the message has no user bound to it, then it is likely some kind of other message being created by a module. Just return immediately.\n\t\t\tif (!this.user) return html;\n\t\t\tlet chatColor = (<string>this.user.getFlag(SETTINGS.MOD_NAME, PlayerColor.FLAG_CHAT_COLOR))?.trim();\n\t\t\t// If it is a valid color\n\t\t\tif (!chatColor || !/#[a-fA-F0-9]{6,8}/.test(chatColor))\n\t\t\t\tchatColor = this.user.color;\n\n\t\t\t// Set the border colour to its default\n\t\t\tlet borderColour = '#6f6c66';\n\t\t\tswitch (SETTINGS.get<string>(PlayerColor.PREF_BORDER_STYLE)) {\n\t\t\t\tcase 'none': break;\n\t\t\t\tcase 'mine':\n\t\t\t\t\tif (game.userId !== this.data.user) break;\n\t\t\t\t// fallthrough\n\t\t\t\tcase 'all':\n\t\t\t\t\tborderColour = chatColor;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\thtml[0].style.borderColor = borderColour;\n\n\t\t\t// Set the hover border colour to what ever the border colour is\n\t\t\thtml[0].style.setProperty('--dfce-mc-border-color', borderColour);\n\t\t\tif (SETTINGS.get(PlayerColor.PREF_TINT_BG)) {\n\t\t\t\thtml[0].style.backgroundColor = chatColor;\n\t\t\t\thtml[0].style.backgroundImage = 'url(../ui/parchment.jpg)';\n\t\t\t\thtml[0].style.backgroundRepeat = 'repeat';\n\t\t\t\thtml[0].style.backgroundBlendMode = 'screen';\n\t\t\t}\n\t\t\treturn html;\n\t\t}, 'WRAPPER');\n\t}\n}\n","import SETTINGS from \"../../../common/Settings\";\nimport UTIL from \"../Util\";\n\n\nconst ICONS_FOR_KNOWN_ROLL_TYPES: {\n\t[key: string]: string;\n\tpublicroll: string;\n\tgmroll: string;\n\tblindroll: string;\n\tselfroll: string;\n} = {\n\tpublicroll: 'fas fa-dice-d20',\n\tgmroll: 'fas fa-user-secret',\n\tblindroll: 'fas fa-user-ninja',\n\tselfroll: 'fas fa-ghost'\n};\n\ninterface ChatLogData {\n\tuser: User,\n\trollMode: string,\n\trollModes: any,\n\tisStream: boolean\n}\n\nexport default class ChatRollPrivacy {\n\tstatic setup() {\n\t\tgame.keybindings.register(SETTINGS.MOD_NAME, \"roll-mode.publicroll\", {\n\t\t\tname: 'Public Roll',\n\t\t\teditable: [{ key: 'KeyQ', modifiers: [KeyboardManager.MODIFIER_KEYS.ALT] }],\n\t\t\tnamespace: 'Roll Type Shortcuts',\n\t\t\tonDown: () => {\n\t\t\t\t$('#dfcp-rt-buttons > button[data-id=\"publicroll\"]').trigger('click');\n\t\t\t}\n\t\t});\n\t\tgame.keybindings.register(SETTINGS.MOD_NAME, \"roll-mode.gmroll\", {\n\t\t\tname: 'Private GM Roll',\n\t\t\teditable: [{ key: 'KeyW', modifiers: [KeyboardManager.MODIFIER_KEYS.ALT] }],\n\t\t\tnamespace: 'Roll Type Shortcuts',\n\t\t\tonDown: () => {\n\t\t\t\t$('#dfcp-rt-buttons > button[data-id=\"gmroll\"]').trigger('click');\n\t\t\t}\n\t\t});\n\t\tgame.keybindings.register(SETTINGS.MOD_NAME, \"roll-mode.blindroll\", {\n\t\t\tname: 'Blind GM Roll',\n\t\t\teditable: [{ key: 'KeyE', modifiers: [KeyboardManager.MODIFIER_KEYS.ALT] }],\n\t\t\tnamespace: 'Roll Type Shortcuts',\n\t\t\tonDown: () => {\n\t\t\t\t$('#dfcp-rt-buttons > button[data-id=\"blindroll\"]').trigger('click');\n\t\t\t}\n\t\t});\n\t\tgame.keybindings.register(SETTINGS.MOD_NAME, \"roll-mode.selfroll\", {\n\t\t\tname: 'Self Roll',\n\t\t\teditable: [{ key: 'KeyR', modifiers: [KeyboardManager.MODIFIER_KEYS.ALT] }],\n\t\t\tnamespace: 'Roll Type Shortcuts',\n\t\t\tonDown: () => {\n\t\t\t\t$('#dfcp-rt-buttons > button[data-id=\"selfroll\"]').trigger('click');\n\t\t\t}\n\t\t});\n\t}\n\n\tstatic init() {\n\t\tSETTINGS.register('enabled', {\n\t\t\tname: 'DF_CHAT_PRIVACY.Settings_EnableTitle',\n\t\t\thint: 'DF_CHAT_PRIVACY.Settings_EnableHint',\n\t\t\tscope: 'client',\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tconfig: true,\n\t\t\tonChange: UTIL.requestReload\n\t\t});\n\t\tSETTINGS.register('replace-buttons', {\n\t\t\tname: 'DF_CHAT_PRIVACY.Settings_ReplaceButtonsTitle',\n\t\t\thint: 'DF_CHAT_PRIVACY.Settings_ReplaceButtonsHint',\n\t\t\tscope: 'client',\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tconfig: true,\n\t\t\tonChange: UTIL.requestReload\n\t\t});\n\t\n\t\tif (SETTINGS.get('enabled') === false)\n\t\t\treturn;\n\t\n\t\tHooks.on('renderChatLog', this._handleChatLogRendering);\n\t}\n\n\n\tprivate static calcColour(current: number, count: number): string {\n\t\treturn `rgb(${(current / count) * 255},${(1 - (current / count)) * 255},0)`;\n\t}\n\n\tprivate static async _handleChatLogRendering(chat: ChatLog, html: JQuery<HTMLElement>, data: ChatLogData) {\n\t\tconst modes = Object.keys(data.rollModes);\n\t\tconst buttons: any[] = [];\n\t\tconst iconKeys = Object.keys(ICONS_FOR_KNOWN_ROLL_TYPES);\n\t\tfor (let c = 0; c < modes.length; c++) {\n\t\t\tconst rt = modes[c];\n\t\t\tif (!(rt in ICONS_FOR_KNOWN_ROLL_TYPES)) {\n\t\t\t\tconsole.warn(Error(`Unknown roll type '${rt}'`));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuttons.push({\n\t\t\t\trt: rt,\n\t\t\t\tname: data.rollModes[rt],\n\t\t\t\tactive: data.rollMode === rt,\n\t\t\t\ticon: ICONS_FOR_KNOWN_ROLL_TYPES[rt],\n\t\t\t\tcolour: ChatRollPrivacy.calcColour(iconKeys.findIndex(x => x == rt), iconKeys.length)\n\t\t\t});\n\t\t}\n\t\tconst buttonHtml = $(await renderTemplate('modules/df-chat-enhance/templates/privacy-button.hbs', { buttons }));\n\t\tbuttonHtml.find('button').on('click', function () {\n\t\t\tconst rollType = $(this).attr('data-id');\n\t\t\tgame.settings.set(\"core\", \"rollMode\", <any>rollType);\n\t\t\tbuttonHtml.find('button.active').removeClass('active');\n\t\t\t$(this).addClass('active');\n\t\t});\n\t\thtml.find('select[name=rollMode]').after(buttonHtml);\n\t\thtml.find('select[name=rollMode]').remove();\n\t\n\t\tif (!SETTINGS.get('replace-buttons'))\n\t\t\treturn;\n\t\n\t\t// Adjust the button container to remove the extra margin since those buttons are now moving in.\n\t\tbuttonHtml.attr('style', 'margin:0 0 0 0.5em');\n\t\n\t\t// Convert the old <a> tag elements to <button> tags\n\t\tlet first = true;\n\t\thtml.find('#chat-controls div.control-buttons a').each(function () {\n\t\t\tconst html = $(this).html();\n\t\t\tconst classes = $(this).attr('class');\n\t\t\tconst title = $(this).attr('title');\n\t\t\tconst style = $(this).attr('style');\n\t\t\tconst click = ($ as any)._data(this, 'events')['click'][0].handler;\n\t\t\tconst button = $(`<button class=\"${classes}\" title=\"${title}\" style=\"${style}\">${html}</button>`);\n\t\t\tbutton.on('click', click);\n\t\t\t// Add a small margin between the first button and the RollTypes\n\t\t\tif (first) {\n\t\t\t\tbutton.attr('style', 'margin-left:0.5em');\n\t\t\t\tfirst = false;\n\t\t\t}\n\t\t\tbuttonHtml.append(button);\n\t\t});\n\t\n\t\thtml.find('#chat-controls div.control-buttons').remove();\n\t}\n}\n","import SETTINGS from \"../../../common/Settings\";\nimport UTIL from \"../Util\";\n\nexport default class ChatHistoryOptimizer {\n\n\tprivate static readonly PREF_ENABLED = 'ChatHistoryOptimizer.Enabled';\n\tprivate static readonly PREF_HISTORY_SIZE = 'ChatHistoryOptimizer.HistorySize';\n\n\tstatic init() {\n\n\t\tSETTINGS.register(this.PREF_ENABLED, {\n\t\t\tname: 'DF_CHAT_SCROLL.HistoryFixEnabledName',\n\t\t\thint: 'DF_CHAT_SCROLL.HistoryFixEnabledHint',\n\t\t\tconfig: true,\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tscope: 'world',\n\t\t\tonChange: UTIL.requestReload\n\t\t});\n\t\tSETTINGS.register<number>(this.PREF_HISTORY_SIZE, {\n\t\t\tname: 'DF_CHAT_SCROLL.HistorySizeName',\n\t\t\thint: 'DF_CHAT_SCROLL.HistorySizeHint',\n\t\t\tconfig: true,\n\t\t\ttype: Number,\n\t\t\tdefault: CONFIG.ChatMessage.batchSize,\n\t\t\trange: {\n\t\t\t\tmin: CONFIG.ChatMessage.batchSize,\n\t\t\t\tmax: CONFIG.ChatMessage.batchSize * 5,\n\t\t\t\tstep: CONFIG.ChatMessage.batchSize\n\t\t\t},\n\t\t\tscope: 'world',\n\t\t\tonChange: () => $('#chat-log').trigger('scroll')\n\t\t});\n\n\t\tif (!SETTINGS.get(this.PREF_ENABLED)) return;\n\n\t\tlibWrapper.register(SETTINGS.MOD_NAME, 'ChatLog.prototype._onScrollLog', this._ChatLog_onScrollLog, 'MIXED');\n\n\t\t/**\n\t\t// This is used for DEBUG purposes only\n\t\t// Displays the number of messages being rendered in the Chat Log\n\t\tHooks.on('renderChatLog', (_: any, html: JQuery) => {\n\t\t\thtml.find('#scrollToBottom').after('<div class=\"dfce-chat-count\" style=\"flex:0;text-align:center\"></div>');\n\t\t});\n\t\tthis._displayMessageCounts(0);\n\t\t/**/\n\t}\n\n\tprivate static _ChatLog_onScrollLog(this: ChatLog, wrapped: (event: any) => Promise<void>, event: any): Promise<void> {\n\t\tif (!this.rendered) return Promise.resolve();\n\t\tconst maxMessageCount = SETTINGS.get<number>(ChatHistoryOptimizer.PREF_HISTORY_SIZE);\n\t\t// Ignore all scroll events when there are not enough messages to even batch\n\t\tif (this.collection.size <= CONFIG.ChatMessage.batchSize) return wrapped(event);\n\t\tconst log = event.target as HTMLElement;\n\t\tconst messages = $(log).find('li.chat-message');\n\n\t\t// Grab the top most message based on current scroll position\n\t\tlet topMessageIndex = -1;\n\n\t\t//! NOTICE! The message list is inverted, it is sorted OLDEST to NEWEST,\n\t\t//! so message[0] is at the very top of the chat log, and message[n] is\n\t\t//! at the very bottom of the chat log.\n\n\t\t// We try to start as close to the actual top message as we can, then traverse either up or down from there\n\t\tconst pct = log.scrollTop / log.scrollHeight;\n\t\tconst chatViewTop = log.scrollTop + messages[0].offsetTop;\n\t\tlet c = Math.trunc(messages.length * pct);\n\t\t// If the estimate is too high up the log, we traverse down\n\t\tif (messages[c].offsetTop < chatViewTop) {\n\t\t\tfor (; c < messages.length; c++) {\n\t\t\t\tif (\n\t\t\t\t\t// If this message is at/on the scroll top\n\t\t\t\t\t(messages[c].offsetTop <= chatViewTop && messages[c].offsetTop + messages[c].offsetHeight >= chatViewTop) ||\n\t\t\t\t\t// If the previous message is above the view, and this one is in the view\n\t\t\t\t\t(c - 1 >= 0 && messages[c].offsetTop >= chatViewTop && messages[c - 1].offsetTop + messages[c - 1].offsetHeight)\n\t\t\t\t) {\n\t\t\t\t\ttopMessageIndex = c;\n\t\t\t\t\t// We should break as soon as we find it\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Otherwise we traverse up the chat log\n\t\telse {\n\t\t\tfor (; c >= 0; c--) {\n\t\t\t\tif (\n\t\t\t\t\t// If this message is at/on the scroll top\n\t\t\t\t\t(messages[c].offsetTop <= chatViewTop && messages[c].offsetTop + messages[c].offsetHeight >= chatViewTop) ||\n\t\t\t\t\t// If the previous message is above the view, and this one is in the view\n\t\t\t\t\t(c - 1 >= 0 && messages[c].offsetTop >= chatViewTop && messages[c - 1].offsetTop + messages[c - 1].offsetHeight)\n\t\t\t\t) {\n\t\t\t\t\ttopMessageIndex = c;\n\t\t\t\t\t// We should break as soon as we find it\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// If we found nothing\n\t\tif (topMessageIndex < 0) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\t// Check if we should load more messages\n\t\tif (topMessageIndex < (CONFIG.ChatMessage.batchSize / 4) && messages.length < this.collection.size) {\n\t\t\t// Add Messages\n\t\t\treturn this._renderBatch(this.element, CONFIG.ChatMessage.batchSize);\n\t\t}\n\t\t// If we don't want to load more, check if we should delete some\n\t\telse if (topMessageIndex > maxMessageCount) {\n\t\t\tconst count = topMessageIndex - (maxMessageCount - 1);\n\t\t\t// Set the Last ID for batch rendering\n\t\t\tthis._lastId = messages[count].dataset.messageId;\n\t\t\t// Remove the messages\n\t\t\tmessages.slice(0, count).remove();\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n\n\tprivate static _lastFrame = 0;\n\tprivate static _displayMessageCounts(time: number) {\n\t\tif (ChatHistoryOptimizer._lastFrame + 500 < time) {\n\t\t\tChatHistoryOptimizer._lastFrame = time;\n\t\t\t$('.dfce-chat-count').each(function (_, element: HTMLElement) {\n\t\t\t\tconst msgCount = $(element).siblings('#chat-log').find('li.chat-message').length;\n\t\t\t\telement.innerText = `${msgCount} / ${ui.chat.collection.size}`;\n\t\t\t});\n\t\t}\n\t\trequestAnimationFrame(ChatHistoryOptimizer._displayMessageCounts);\n\t}\n}","import { ChatMessageData } from \"@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs\";\nimport libWrapperShared from \"../../../common/libWrapperShared\";\nimport SETTINGS from \"../../../common/Settings\";\nimport ChatHistoryOptimizer from \"./ChatHistoryOptimizer\";\n\ndeclare class ChatLogExt extends ChatLog {\n\t_scrollToBottomButton: JQuery<HTMLElement>;\n}\n\nexport default class ScrollManage {\n\tprivate static readonly PREF_ENABLED = 'scroll-manage-enabled';\n\tprivate static readonly PREF_SCROLL_IF_YOU = 'scroll-manage-scroll-if-you';\n\tprivate static readonly ScrollThreshold = 50;\n\t// private static _scrollToBottomButton: JQuery<HTMLElement>;\n\tprivate static _deleteMessageRegistrationID: number | null = null;\n\n\n\tstatic get enabled(): boolean { return SETTINGS.get(this.PREF_ENABLED); }\n\tstatic get scrollToBottomIfYouSendMessage(): boolean { return SETTINGS.get(this.PREF_SCROLL_IF_YOU); }\n\n\tstatic init() {\n\t\tHooks.on('renderChatLog', this._renderChatLog.bind(this));\n\n\t\tSETTINGS.register(this.PREF_ENABLED, {\n\t\t\tname: 'DF_CHAT_SCROLL.EnableName',\n\t\t\thint: 'DF_CHAT_SCROLL.EnableHint',\n\t\t\tscope: 'world',\n\t\t\tconfig: true,\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tonChange: (newValue) => {\n\t\t\t\tif (newValue) this.register();\n\t\t\t\telse this.unregister();\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register(this.PREF_SCROLL_IF_YOU, {\n\t\t\tname: 'DF_CHAT_SCROLL.ScrollIfYouName',\n\t\t\thint: 'DF_CHAT_SCROLL.ScrollIfYouHint',\n\t\t\tscope: 'world',\n\t\t\tconfig: true,\n\t\t\ttype: Boolean,\n\t\t\tdefault: true\n\t\t});\n\n\t\tChatHistoryOptimizer.init();\n\t}\n\n\tstatic ready() {\n\t\tif (this.enabled)\n\t\t\tthis.register();\n\t}\n\n\tprivate static register() {\n\t\tlibWrapper.register(SETTINGS.MOD_NAME, 'ChatLog.prototype.postOne', this._ChatLog_postOne, 'OVERRIDE');\n\t\tlibWrapper.register(SETTINGS.MOD_NAME, 'ChatLog.prototype.scrollBottom', this._ChatLog_scrollBottom, 'OVERRIDE');\n\t\tthis._deleteMessageRegistrationID = libWrapperShared.register('ChatLog.prototype.deleteMessage', this._ChatLog_deleteMessage);\n\t}\n\tprivate static unregister() {\n\t\tlibWrapper.unregister(SETTINGS.MOD_NAME, 'ChatLog.prototype.postOne', false);\n\t\tlibWrapper.unregister(SETTINGS.MOD_NAME, 'ChatLog.prototype.scrollBottom', false);\n\t\tlibWrapperShared.unregister('ChatLog.prototype.deleteMessage', this._deleteMessageRegistrationID);\n\t}\n\n\tprivate static _renderChatLog(app: ChatLogExt, html: JQuery<HTMLElement>) {\n\t\tapp._scrollToBottomButton = $(`<div id=\"scrollToBottom\" style=\"display:none\">\n\t<span>${'DF_CHAT_SCROLL.NewMessage'.localize()}</span> ${'DF_CHAT_SCROLL.ScrollButton'.localize()}\n</div>`);\n\t\tapp._scrollToBottomButton.on('click', () => {\n\t\t\tconst el = app.element;\n\t\t\tconst log = el.length ? el[0].querySelector(\"#chat-log\") : null;\n\t\t\tif (log) {\n\t\t\t\tlog.scrollTo({ behavior: \"smooth\", top: log.scrollHeight });\n\t\t\t}\n\t\t});\n\t\thtml.find('div#chat-controls').before(app._scrollToBottomButton);\n\n\t\thtml.find('ol#chat-log').on('scroll', (event) => {\n\t\t\tif (!app._scrollToBottomButton) return;\n\t\t\tconst element = <HTMLOListElement>event.currentTarget;\n\t\t\t// Ignore events when the scroll height is too small to matter\n\t\t\tif (element.clientHeight > element.scrollHeight - this.ScrollThreshold) return;\n\t\t\tif (element.scrollTop < (element.scrollHeight - element.clientHeight) - this.ScrollThreshold)\n\t\t\t\tapp._scrollToBottomButton.show();\n\t\t\telse {\n\t\t\t\tapp._scrollToBottomButton.hide();\n\t\t\t\tapp._scrollToBottomButton.removeClass('new');\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate static _ChatLog_scrollBottom(this: ChatLogExt) {\n\t\tconst el = this.element;\n\t\tconst log = el.length ? el[0].querySelector(\"#chat-log\") : null;\n\t\t// If we are already at the bottom, perform the scroll\n\t\tif (this._scrollToBottomButton.is(':hidden'))\n\t\t\tsetTimeout(() => log.scrollTo({ behavior: 'smooth', top: log.scrollHeight }), 100);\n\t\t// Otherwise do not scroll, but do trigger a scroll event.\n\t\t// Some modules might use this function after manually adding message content to the ChatLog\n\t\telse $('#chat #chat-log').trigger('scroll');\n\t}\n\n\tprivate static async _ChatLog_postOne(this: ChatLogExt, message: ChatMessageData & ChatMessage, notify = false) {\n\t\tif (!message.visible) return;\n\n\t\t// Track internal flags\n\t\tif (!this._lastId) this._lastId = message.id; // Ensure that new messages don't result in batched scrolling\n\t\tif ((message.whisper || []).includes(game.user.id) && !message.isRoll) {\n\t\t\tthis._lastWhisper = message;\n\t\t}\n\n\t\t// Render the message to the log\n\t\tconst element = this.element.find(\"#chat-log\");\n\t\tconst atBottom = element[0].scrollTop >= ((element[0].scrollHeight - element[0].clientHeight) - ScrollManage.ScrollThreshold);\n\t\tconst html = await (<any>message).getHTML();\n\t\telement.append(html);\n\t\tif (atBottom || (ScrollManage.scrollToBottomIfYouSendMessage && message.isAuthor))\n\t\t\telement[0].scrollTo({ top: element[0].scrollHeight, behavior: 'smooth' });\n\t\t// this.scrollBottom();\n\t\telse {\n\t\t\tthis._scrollToBottomButton.addClass('new');\n\t\t}\n\n\t\t// Post notification\n\t\tif (notify) this.notify(message);\n\n\t\t// Update popout tab\n\t\tif (this._popout) await (<any>this._popout).postOne(message, false);\n\t\tif (this.popOut) this.setPosition();\n\t}\n\n\tprivate static _ChatLog_deleteMessage(this: ChatLogExt, wrapped: (...args: any) => unknown, messageId: string, { deleteAll = false }: { deleteAll?: boolean } = {}): unknown {\n\t\tconst result = wrapped(messageId, { deleteAll });\n\t\t// Ignore singular message deletions, only react to a Delete All event.\n\t\t// Also ignore the deletion if the scroll-to-bottom element is already hidden\n\t\tif (!deleteAll || this._scrollToBottomButton.is(':hidden')) return result;\n\t\tthis._scrollToBottomButton.hide();\n\t\tthis._scrollToBottomButton.removeClass('new');\n\t\treturn result;\n\t}\n}","import SETTINGS from \"../../../common/Settings\";\n\nexport default class SendButton {\n\tprivate static readonly PREF_ENABLED = 'SendButton.Enabled';\n\tstatic init() {\n\t\tSETTINGS.register(this.PREF_ENABLED, {\n\t\t\tname: 'DF_CHAT_SEND_BUTTON.EnabledName'.localize(),\n\t\t\thint: 'DF_CHAT_SEND_BUTTON.EnabledHint'.localize(),\n\t\t\tconfig: true,\n\t\t\tscope: 'client',\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t\tonChange: (isActive) => {\n\t\t\t\tif (isActive) {\n\t\t\t\t\tthis._renderChatLog(ui.chat, $('#sidebar #chat'));\n\t\t\t\t\tconst popout = $('#chat-popout');\n\t\t\t\t\tif (popout.length > 0)\n\t\t\t\t\t\tthis._renderChatLog(ui.chat, popout);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$('.dfce-send-btn').remove();\n\t\t\t\t\t$<HTMLTextAreaElement>('#chat-message').each((_a, textarea) => {\n\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t$(textarea).off('input', textarea.dfce_handler);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tHooks.on('renderChatLog', this._renderChatLog.bind(this));\n\t}\n\n\tprivate static _renderChatLog(app: ChatLog, html: JQuery<HTMLElement>) {\n\t\tif (!SETTINGS.get<boolean>(this.PREF_ENABLED)) return;\n\t\tconst sendButton = $('<button class=\"dfce-send-btn\"><i class=\"fas fa-paper-plane\"></i></button>');\n\t\tsendButton.attr('title', 'DF_CHAT_SEND_BUTTON.ButtonTitle'.localize());\n\t\thtml.find('#chat-form').append(sendButton);\n\n\t\tconst textarea = html.find<HTMLTextAreaElement>('#chat-message');\n\t\tsendButton.prop('disabled', textarea[0].textLength <= 0 || textarea[0].value.trim().length <= 0);\n\n\t\tsendButton.on('click', async event => {\n\t\t\tevent.preventDefault();\n\t\t\t// @ts-expect-error\n\t\t\tawait ui.chat._onChatKeyDown(<any>{\n\t\t\t\tcode: 'Enter',\n\t\t\t\tcurrentTarget: textarea[0],\n\t\t\t\toriginalEvent: <any>{\n\t\t\t\t\tisComposing: false\n\t\t\t\t},\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-empty-function\n\t\t\t\tpreventDefault: () => { }\n\t\t\t});\n\t\t\tsetTimeout(() => textarea.trigger('input'), 100);\n\t\t});\n\n\t\tconst handler = (event: JQuery.TriggeredEvent<HTMLTextAreaElement, undefined, HTMLTextAreaElement, HTMLTextAreaElement>) => {\n\t\t\tconst element = (event.currentTarget as HTMLTextAreaElement);\n\t\t\tsendButton.prop('disabled', element.textLength <= 0 || element.value.trim().length <= 0);\n\t\t};\n\t\t// @ts-expect-error\n\t\ttextarea[0].dfce_handler = handler;\n\t\ttextarea.on('input', handler);\n\t\ttextarea.on('change', handler);\n\t}\n}","import { ChatMessageData } from \"@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs\";\nimport SETTINGS from \"../../../common/Settings\";\n\n\nconst TEMPLATE = \"$0: $1 (+$2 more)\";\nconst LENGTH_ADJUST = ' '.length - 1;\n\n\nexport default class WhisperTruncation {\n\n\tprivate static readonly PREF_ENABLED = 'whisper-trunc_enabled';\n\tprivate static readonly PREF_CHAR_LIMIT = 'whisper-trunc_char-limit';\n\n\tstatic init() {\n\t\tHooks.on('renderChatMessage', this._messageRender.bind(this));\n\t\tSETTINGS.register(this.PREF_ENABLED, {\n\t\t\tname: 'DF_CHAT_WHISPER_TRUNC.SettingEnabledName',\n\t\t\thint: 'DF_CHAT_WHISPER_TRUNC.SettingEnabledHint',\n\t\t\tconfig: true,\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tscope: 'world',\n\t\t\tonChange: async () => {\n\t\t\t\t(<any>ui.chat)._state = 0;\n\t\t\t\t(<any>ui.chat)._lastId = null;\n\t\t\t\tawait ui.chat.render(true);\n\t\t\t}\n\t\t});\n\t\tSETTINGS.register(this.PREF_CHAR_LIMIT, {\n\t\t\tname: 'DF_CHAT_WHISPER_TRUNC.SettingCharLimitName',\n\t\t\thint: 'DF_CHAT_WHISPER_TRUNC.SettingCharLimitHint',\n\t\t\tconfig: true,\n\t\t\ttype: Number,\n\t\t\tdefault: 50,\n\t\t\tscope: 'world',\n\t\t\tonChange: async () => {\n\t\t\t\t(<any>ui.chat)._state = 0;\n\t\t\t\t(<any>ui.chat)._lastId = null;\n\t\t\t\tawait ui.chat.render(true);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate static _messageRender(message: ChatMessageData, html: JQuery<HTMLElement>, _cmd: ChatMessageData) {\n\t\t// ignore regular messages, or whispers with only 1 recipient\n\t\tif (!SETTINGS.get(this.PREF_ENABLED) || !(message.whisper) || message.whisper.length <= 1) return;\n\t\tconst users = message.whisper.map(x => game.users.get(x));\n\t\tlet accum = users[0].name;\n\t\tlet title = this._formatTitle(accum, users.length - 1);\n\t\tlet c = 1;\n\t\tconst CHAR_LIMIT = SETTINGS.get<number>(this.PREF_CHAR_LIMIT);\n\t\tfor (; c < users.length; c++) {\n\t\t\t// Append name to names string\n\t\t\tconst tmpNames = accum + ', ' + users[c].name;\n\t\t\t// Generate a temp title\n\t\t\tconst tmpTitle = this._formatTitle(tmpNames, users.length - c - 1);\n\t\t\t// If the potential title is too large, break so we can use the previous iteration's results\n\t\t\tif (tmpTitle.length - LENGTH_ADJUST > CHAR_LIMIT) break;\n\t\t\t// Set the accum and title to the newly generated values\n\t\t\taccum = tmpNames;\n\t\t\ttitle = tmpTitle;\n\t\t}\n\t\t// If we never ran out of room, exit\n\t\tif (c === users.length) return;\n\t\t// Update the HTML\n\t\tconst newHeader = `<span class=\"whisper-to\" title=\"${users.slice(c).map(x => x.name).join(', ')}\">${title}</span>`;\n\t\thtml.find('span.whisper-to').replaceWith(newHeader);\n\t}\n\n\tprivate static _formatTitle(names: string, count: number): string {\n\t\treturn count > 0\n\t\t\t? TEMPLATE\n\t\t\t\t.replace('$0', 'CHAT.To'.localize())\n\t\t\t\t.replace('$1', names)\n\t\t\t\t.replace('$2', count.toString())\n\t\t\t: names;\n\t}\n}","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import * as DFChatArchive from \"./archive/df-chat-archive\";\nimport DFChatEdit from \"./edit/df-chat-edit\";\nimport * as DFAdventureLog from \"./logger/df-adventure-log\";\nimport DFAdventureLogProcessor from \"./logger/DFAdventureLogProcessor\";\nimport ChatMerge from \"./merge/chat-merge\";\nimport ChatRollPrivacy from \"./privacy/df-chat-privacy\";\nimport ScrollManage from \"./scroll-manage/scroll-manage\";\nimport SETTINGS from \"../../common/Settings\";\nimport WhisperTruncation from \"./whisper-trunc/whisper-trunc\";\nimport PlayerColor from './player-color/PlayerColor';\nimport SendButton from \"./send/send-button\";\nimport FontSizePatch from \"./font-size/font-size\";\nimport ChatTime from \"./chat-time/chat-time\";\nSETTINGS.init('df-chat-enhance');\n\ndeclare global {\n\tinterface Application {\n\t\t_recalculateDimensions(): void;\n\t}\n}\n\n(<any>Application.prototype)._recalculateDimensions = function () {\n\tthis.element[0].style.height = '';\n\tthis.element[0].style.width = '';\n\tthis.setPosition({});\n};\n\nHooks.once('setup', function () {\n\tChatRollPrivacy.setup();\n});\n\nHooks.once('init', function () {\n\t/**\n\t * Order here matters! The archive adds a button to the\n\t * chat window, while the privacy changes those buttons\n\t * from <a> tags to <button> tags if enabled.\n\t */\n\tDFChatArchive.init();\n\tChatRollPrivacy.init();\n\tDFAdventureLog.init();\n\tChatMerge.init();\n\tScrollManage.init();\n\tWhisperTruncation.init();\n\tPlayerColor.init();\n\tSendButton.init();\n\tFontSizePatch.init();\n\tChatTime.init();\n\n\tlibWrapper.register(SETTINGS.MOD_NAME, 'ChatLog.prototype._getEntryContextOptions', function (wrapped: (...args: any) => ContextMenu.Item[], ...args: any) {\n\t\tconst options = wrapped(...args);\n\t\tDFChatEdit.appendChatContextMenuOptions(options);\n\t\tDFAdventureLogProcessor.appendChatContextMenuOptions(options);\n\t\treturn options;\n\t}, 'WRAPPER');\n});\n\nHooks.once('ready', function () {\n\tif (!game.modules.get('lib-wrapper')?.active) {\n\t\tconsole.error('Missing libWrapper module dependency');\n\t\tif (game.user.isGM)\n\t\t\tui.notifications.error('DF_CHAT_LOG.Error.LibWrapperMissing'.localize());\n\t}\n\tDFAdventureLog.ready();\n\tDFChatEdit.ready();\n\tChatMerge.ready();\n\tScrollManage.ready();\n\tChatTime.ready();\n});\n"],"names":["SETTINGS","static","moduleName","this","MOD_NAME","String","prototype","localize","game","i18n","valueOf","key","config","settings","register","registerMenu","get","value","set","default","Object","Registration","nextId","wrappers","Map","handler","context","wrapped","args","current","wrapper","values","next","call","libWrapperShared","target","registration","registrations","libWrapper","id","delete","size","unregister","UTIL","Dialog","confirm","title","content","defaultYes","window","location","reload","ui","chat","_lastId","_state","Application","RENDER_STATES","NONE","render","ArchiveFolderMenu","FormApplication","folder","DFChatArchive","PREF_FOLDER","source","PREF_FOLDER_SOURCE","defaultOptions","mergeObject","width","height","resizable","minimizable","template","submitOnClose","submitOnChange","closeOnSubmit","getData","_options","path","async","data","html","super","_renderInner","input","find","on","event","preventDefault","fp","FilePicker","type","field","callback","activeSource","button","currentTarget","browse","DATA_FOLDER","listener","_updateListener","PREF_LOGS","scope","onChange","PREF_CID","Number","PREF_FOLDER_MENU","label","hint","restricted","world","createArchiveFolderIfMissing","catch","_","createDirectory","Error","getLogs","x","name","chats","visible","folderPath","safeName","replace","fileName","encodeURI","file","File","JSON","stringify","response","upload","console","error","filepath","filename","newId","entry","_generateChatArchiveFile","logs","push","archive","fetch","json","ok","newChatData","toString","idx","findIndex","Promise","all","map","entryIdx","splice","DFChatArchiveManager","options","messages","user","isGM","filter","sort","a","b","localeCompare","reverseSort","PREF_REVERSE_SORT","reverse","_subscribeView","element","parseInt","$","attr","isNaN","notifications","chatViewers","has","bringToTop","view","_subscribeDelete","yes","activateListeners","_archiveChanged","bind","length","hide","each","i","info","asc","dsc","show","close","archiveContainer","empty","append","children","DFChatArchiveNew","PREF_DELETE","Boolean","shouldDelete","_event","formData","warn","collection","fromDate","Date","from","getTime","toDate","to","timestamp","e","flush","then","prop","_recalculateDimensions","PREF_HIDE_EXPORT","DFChatArchiveViewer","constructor","onCloseCallBack","classes","logId","codeUnits","Uint16Array","charCodeAt","charCodes","Uint8Array","buffer","result","byteLength","fromCharCode","checked","setTimeout","dialog","buttons","save","icon","val","clone","addClass","print","remove","removeClass","renderTemplate","archives","cancel","merge","currentChats","sourceChats","mergedChats","concat","anchor","document","createElement","download","href","encodeURIComponent","click","log","messageHtml","userId","CONST","CHAT_MESSAGE_TYPES","WHISPER","whisper","some","deletionList","deleteButton","chatMessage","ChatMessage","getHTML","parentElement","buttonIcon","hasClass","err","prepend","message","includes","_id","init","archiveNew","archiveManager","newValue","Hooks","chatLog","archiveButton","archiveManagerHtml","RENDERED","RENDERING","app","focus","ChatTime","enabled","PREF_ENABLED","simpleCalendarActive","modules","active","permanent","PREF_FORMAT","chatData","createOptions","flags","FLAG_CHAT_TIME","time","worldTime","_data","simpleTimestamp","getFlag","undefined","timeElement","simpleTimeElement","SimpleCalendar","api","formatDateTime","timestampToDate","after","DFChatEditor","editable","popOut","types","keys","CONFIG","Actor","typeLabels","actors","scenes","viewed","tokens","contents","actor","selected","speaker","token","players","users","actorGroups","messageText","PREF_MARKDOWN","processMarkdown","search","startsWith","substring","_getSpeakerFromUser","getSpeaker","alias","update","chatEditor","originalMessage","marked","parse","headerIds","breaks","trimEnd","substr","endsWith","newLine","test","PREF_EDIT_ALLOWED","PREF_GM_ALL","PREF_IGNORE_HTML","DFChatEdit","PREF_SHOW_EDITED","code","ctrlKey","editChatMessage","trim","split","trimStart","_sentMessages","unshift","condition","header","processChatMessage","_render","str","doc","DOMParser","parseFromString","Array","body","childNodes","node","HTMLElement","classList","contains","HTMLBRElement","nodeType","isRoll","isHTML","FontSizePatch","PREF_SIZE","range","min","max","step","newSize","updateFontSize","querySelector","style","setProperty","DFAdventureLogConfig","PREF_JOURNAL","PREF_JOURNAL_GM","PREF_CONFIG","journal","pages","y","selectedLog","selectedGMLog","logJournals","logJournalPages","gmlogJournals","gmlogJournalPages","fillPageList","journalId","page","pageElement","logJournal","gmlogJournal","clear","gmClear","initializeJournal","isGMOnly","isPlayerLog","text","whitespace","index","c","every","DFAdventureLogProcessor","PREF_ENABLE","gmOnly","PREF_GMONLY","commandProcessor","logCommand","deregisterCommand","registerCommand","PREF_GMONLY_WHISPER","PREF_USE_TIME","PREF_MESSAGES","PREF_SORTDESC","resortLog","PREF_DISABLE_FORMATTING","PREF_DISABLE_AUTHOR","PREF_SIMPLE_CALENDAR","logConfig","chatCommands","plogCommand","gmlogCommand","createCommandFromData","commandKey","invokeOnCommand","_cl","msg","_cd","shouldDisplayToChat","iconClass","description","useTime","stamp","date","toLocaleString","gmLog","preventPostToChat","prompt","messageData","flavor","OOC","line","disableFormatting","disableAuthor","toLowerCase","slice","_getTimestamp","PREF_PLAYER_LOG_JOURNAL","section","join","rollType","create","descending","journalAll","journalGM","journalSort","article","postToChat","pevent","gmevent","quote","pquote","gmquote","AdventureLog","ready","_app","Handlebars","compile","journals","documents","testUserPermission","DOCUMENT_PERMISSION_LEVELS","OBSERVER","journalSelection","allowProtoMethodsByDefault","allowProtoPropertiesByDefault","parent","before","object","setFlag","migrateDataV9toV10","checkJournal","migrateJournalV9toV10","unsetFlag","ChatMerge","_enabled","_epoch","PREF_EPOCH","_allowRolls","PREF_ALLOW_ROLLS","_separateWithBorder","PREF_SEPARATE","_showHover","PREF_HOVER","_showHeader","PREF_SHOW_HEADER","_processAllMessage","PREF_SPLIT_SPEAKER","choices","none","rolls","removeProperty","_deleteMessage","_renderChatMessage","messageId","deleteAll","nextElementSibling","add","previousElementSibling","hasAttribute","borderColor","_styleChatMessages","getAttribute","_cmd","partnerElem","last","partner","previous","splitSpeaker","userCompare","currData","prevData","_inTimeFrame","curr","currElem","prev","prevElem","exec","dataset","_isValidMessage","PlayerColor","PREF_TINT_BG","PREF_BORDER_STYLE","mine","color","FLAG_CHAT_COLOR","chatField","chatPicker","setPosition","chatColor","borderColour","backgroundColor","backgroundImage","backgroundRepeat","backgroundBlendMode","ICONS_FOR_KNOWN_ROLL_TYPES","publicroll","gmroll","blindroll","selfroll","ChatRollPrivacy","keybindings","modifiers","KeyboardManager","MODIFIER_KEYS","ALT","namespace","onDown","trigger","_handleChatLogRendering","count","modes","rollModes","iconKeys","rt","rollMode","colour","calcColour","buttonHtml","first","ChatHistoryOptimizer","PREF_HISTORY_SIZE","batchSize","_ChatLog_onScrollLog","rendered","resolve","maxMessageCount","topMessageIndex","pct","scrollTop","scrollHeight","chatViewTop","offsetTop","Math","trunc","offsetHeight","_renderBatch","_lastFrame","msgCount","siblings","innerText","requestAnimationFrame","_displayMessageCounts","ScrollManage","scrollToBottomIfYouSendMessage","PREF_SCROLL_IF_YOU","_renderChatLog","_ChatLog_postOne","_ChatLog_scrollBottom","_deleteMessageRegistrationID","_ChatLog_deleteMessage","_scrollToBottomButton","el","scrollTo","behavior","top","clientHeight","ScrollThreshold","is","notify","_lastWhisper","atBottom","isAuthor","_popout","postOne","SendButton","isActive","popout","_a","textarea","off","dfce_handler","sendButton","textLength","_onChatKeyDown","originalEvent","isComposing","LENGTH_ADJUST","WhisperTruncation","_messageRender","PREF_CHAR_LIMIT","accum","_formatTitle","CHAR_LIMIT","tmpNames","tmpTitle","newHeader","replaceWith","names","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","exports","module","__webpack_modules__","d","definition","o","defineProperty","enumerable","obj","hasOwnProperty","r","Symbol","toStringTag","once"],"sourceRoot":""}
|