v13.0.24 - Le grand oubli d'Illysis #789
13
changelog.md
13
changelog.md
@@ -1,5 +1,18 @@
|
||||
# 13.0
|
||||
|
||||
## 13.0.24 - Le grand oubli d'Illysis
|
||||
|
||||
- ajout d'un bouton pour supprimer les anciens messages du tchat
|
||||
- correction de messages d'erreur 'User ... lacks permission' / 'Active Effect ... does not exist'
|
||||
- les joueurs peuvent affecter leurs enchantements aux objets enchantables de leur équipement
|
||||
- correction des boutons pour lancer les maladresses
|
||||
- utilisation des tables de compendium
|
||||
- correction des droits pour mise à jour du message
|
||||
- correction de la cuisine
|
||||
- reprise de l'image de cuisine dans l'équipement
|
||||
- prise en compte de la difficulté pour préparer la nourriture brute
|
||||
|
||||
|
||||
## 13.0.23 - Le marché d'Illysis
|
||||
|
||||
- Améliorations
|
||||
|
||||
@@ -1528,6 +1528,7 @@ body {
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls img,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls img {
|
||||
vertical-align: text-bottom;
|
||||
display: inline;
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
@@ -1540,10 +1541,17 @@ body {
|
||||
font-size: 0.8em;
|
||||
color: var(--color-controls-light);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls img:hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls img:hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover {
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls a:hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls a:hover {
|
||||
text-shadow: 1px 0px 0px #ff6600;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls a img:hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls a img:hover {
|
||||
opacity: 0.6;
|
||||
filter: drop-shadow(1px 1px 1px #009966) invert(0.8);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls a i:is(.fas, .far, .fa-solid, .fa-regular):hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls a i:is(.fas, .far, .fa-solid, .fa-regular):hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .rdd-roll-dialog .description-sort {
|
||||
|
||||
@@ -852,6 +852,7 @@
|
||||
// }
|
||||
|
||||
img {
|
||||
vertical-align: text-bottom;
|
||||
display: inline;
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
@@ -865,8 +866,16 @@
|
||||
color: var(--color-controls-light);
|
||||
}
|
||||
|
||||
img:hover,
|
||||
i:is(.fas, .far, .fa-solid, .fa-regular):hover {
|
||||
a:hover {
|
||||
text-shadow: 1px 0px 0px #ff6600;
|
||||
}
|
||||
|
||||
a img:hover{
|
||||
opacity: 0.6;
|
||||
filter: drop-shadow(1px 1px 1px #009966) invert(0.8);
|
||||
}
|
||||
|
||||
a i:is(.fas, .far, .fa-solid, .fa-regular):hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
||||
|
||||
|
||||
/**
|
||||
* Class providing helper methods to get the list of users, and
|
||||
* Class providing helper methods around the Chat message
|
||||
*/
|
||||
export class ChatUtility {
|
||||
|
||||
@@ -233,7 +233,12 @@ export class ChatUtility {
|
||||
static async setTimestamp(chatMessage) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
|
||||
}
|
||||
// TODO: find ChatLog to change the action for data-action flush
|
||||
|
||||
static getISODate(chatMessage) {
|
||||
const date = new Date(chatMessage.timestamp);
|
||||
return date?.toISOString().substring(0, 10)
|
||||
}
|
||||
|
||||
|
||||
// async flush() {
|
||||
// const question = game.i18n.localize("AreYouSure");
|
||||
|
||||
79
module/chat/dialog-flush-by-date.mjs
Normal file
79
module/chat/dialog-flush-by-date.mjs
Normal file
@@ -0,0 +1,79 @@
|
||||
import { ChatUtility } from "../chat-utility.js"
|
||||
import { Misc } from "../misc.js"
|
||||
import { RdDTimestamp } from "../time/rdd-timestamp.js"
|
||||
|
||||
const fields = foundry.applications.fields
|
||||
|
||||
export class DialogFlushByDate {
|
||||
|
||||
static async init() {
|
||||
Hooks.on("renderChatMessageHTML", async (app, html, msg) => await ChatUtility.onRenderChatMessage(app, html, msg))
|
||||
Hooks.on("createChatMessage", async (chatMessage, options, id) => await ChatUtility.onCreateChatMessage(chatMessage, options, id))
|
||||
Hooks.once("renderChatLog", async () => await DialogFlushByDate.onFirstRenderChatLog())
|
||||
}
|
||||
|
||||
static async onFirstRenderChatLog() {
|
||||
if (game.user.isGM) {
|
||||
const content = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat/button-flush-by-date.hbs')
|
||||
const flushButton = document.querySelector("#chat-controls button[data-action='flush']")
|
||||
flushButton.insertAdjacentHTML("afterend", content)
|
||||
flushButton.parentElement.querySelector("button[name='flush-by-date']")?.addEventListener(
|
||||
"click", e => {
|
||||
if (game.messages.size > 0) {
|
||||
DialogFlushByDate.create()
|
||||
}
|
||||
else {
|
||||
ui.notifications.info("Aucun message à supprimer!")
|
||||
}
|
||||
e.preventDefault()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
static async create() {
|
||||
const dates = DialogFlushByDate.getChatMessageDates(game.messages)
|
||||
|
||||
const selectGroup = fields.createFormGroup({
|
||||
input: fields.createSelectInput({
|
||||
options: dates.map(it => { return { label: `${it.dateTerre} | ${it.dateReve}`, value: it.timestamp } }),
|
||||
name: 'timestamp'
|
||||
}),
|
||||
label: 'Messages antérieurs au',
|
||||
hint: 'Supprimer les messages antérieurs à la date'
|
||||
})
|
||||
|
||||
const selected = await foundry.applications.api.DialogV2.input({
|
||||
window: { title: "Supprimer les messages du tchat" },
|
||||
content: selectGroup.outerHTML,
|
||||
ok: {
|
||||
label: "Supprimer",
|
||||
icon: "fa-solid fa-trash-can",
|
||||
}
|
||||
})
|
||||
if (selected) {
|
||||
const timestamp = Number.parseInt(selected.timestamp)
|
||||
const toDelete = game.messages.filter(it => it.timestamp < timestamp)
|
||||
toDelete.forEach(it => it.delete())
|
||||
}
|
||||
}
|
||||
|
||||
static getChatMessageDates(messages) {
|
||||
const datesTerre = Object.values(Misc.classifyFirst(messages,
|
||||
m => ChatUtility.getISODate(m),
|
||||
m => DialogFlushByDate.chatMessageDates(m)))
|
||||
const timestamps = new Set(datesTerre.map(it => it.timestamp))
|
||||
const datesReve = Object.values(Misc.classifyFirst(messages,
|
||||
m => RdDTimestamp.fromChatMessage(m).isoDate(),
|
||||
m => DialogFlushByDate.chatMessageDates(m)))
|
||||
const dates = [...datesTerre, ...datesReve.filter(it => !timestamps.has(it.timestamp))]
|
||||
return dates.sort(Misc.ascending(it => it.timestamp))
|
||||
}
|
||||
|
||||
static chatMessageDates(it) {
|
||||
return {
|
||||
timestamp: it.timestamp,
|
||||
dateTerre: new Date(it.timestamp).toLocaleDateString(),
|
||||
dateReve: RdDTimestamp.fromChatMessage(it).formatDate()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ITEM_TYPES, renderTemplate } from "../constants.js"
|
||||
import { ACTOR_TYPES, ITEM_TYPES, renderTemplate } from "../constants.js"
|
||||
import { RdDItemSort } from "../item-sort.js"
|
||||
import { Misc } from "../misc.js"
|
||||
|
||||
export const ACTION_ITEM_ENCHANTER = {
|
||||
code: 'item-enchanter', label: 'Enchanter', icon: it => 'fa-solid fa-sparkles',
|
||||
filter: it => game.user.isGM || DialogEnchanter.isEnchantable(it) && it.parent?.type != ACTOR_TYPES.commerce,
|
||||
filter: it => DialogEnchanter.isEnchantable(it) && it.parent?.type != ACTOR_TYPES.commerce,
|
||||
action: (item, actor) => DialogEnchanter.enchanter(item)
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,9 @@ const _EQUIPER = {
|
||||
}
|
||||
|
||||
const _CUISINER = {
|
||||
code: 'item-cuisiner', label: 'Cuisiner', icon: it => 'fa-solid fa-utensils',
|
||||
code: 'item-cuisiner', label: 'Cuisiner',
|
||||
img: it => 'systems/foundryvtt-reve-de-dragon/assets/actions/cuisine.svg',
|
||||
// icon: it => 'fa-solid fa-spoon',
|
||||
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
|
||||
action: (item, actor) => actor.preparerNourriture(item)
|
||||
}
|
||||
@@ -94,7 +96,7 @@ const _SORT_RESERVE = {
|
||||
}
|
||||
|
||||
export const COMMON_ACTIONS = [_EQUIPER]
|
||||
export const DEFAULT_ACTIONS = [_ACHETER, _SPACEHOLDER, _SPLIT, _VENDRE, _MONTRER, _EDIT, _DELETE]
|
||||
export const DEFAULT_ACTIONS = [_ACHETER, _SPLIT, _SPACEHOLDER, _VENDRE, _MONTRER, _EDIT, _DELETE]
|
||||
|
||||
export const ITEM_ACTIONS = {
|
||||
faune: [_CUISINER, _MANGER_CRU],
|
||||
@@ -119,11 +121,18 @@ export class ItemAction {
|
||||
&& (!action.optionsFilter || action.optionsFilter(options))
|
||||
}
|
||||
|
||||
static icon(action, item) {
|
||||
if (action && action.icon) {
|
||||
return action.icon(item)
|
||||
|
||||
static img(action, item) {
|
||||
if (action.placeholder){
|
||||
return ""
|
||||
}
|
||||
return undefined
|
||||
if (action?.img) {
|
||||
return `<img src="${action.img(item)}" />`
|
||||
}
|
||||
if (action?.icon) {
|
||||
return `<i class="${action.icon(item)}"></i>`
|
||||
}
|
||||
return action.label
|
||||
}
|
||||
|
||||
static async onActionItem(event, actor, options) {
|
||||
|
||||
@@ -134,12 +134,12 @@ export class Misc {
|
||||
return itemsBy
|
||||
}
|
||||
|
||||
static classifyFirst(items, classifier) {
|
||||
static classifyFirst(items, classifier, classified = it => it) {
|
||||
let itemsBy = {};
|
||||
for (const item of items) {
|
||||
const classification = classifier(item);
|
||||
if (!itemsBy[classification]) {
|
||||
itemsBy[classification] = item;
|
||||
itemsBy[classification] = classified(item);
|
||||
}
|
||||
}
|
||||
return itemsBy;
|
||||
@@ -180,11 +180,15 @@ export class Misc {
|
||||
return (a, b) => a + separator + b;
|
||||
}
|
||||
|
||||
static connectedGMOrUser(ownerId = undefined) {
|
||||
if (ownerId && game.user.id == ownerId) {
|
||||
return ownerId;
|
||||
static connectedUserOrGM(userId = undefined) {
|
||||
if (userId && game.user.id == userId) {
|
||||
return userId
|
||||
}
|
||||
return Misc.firstConnectedGM()?.id ?? game.user.id;
|
||||
return Misc.firstConnectedGM()?.id
|
||||
}
|
||||
|
||||
static connectedGMOrUser(userId = undefined) {
|
||||
return Misc.connectedUserOrGM(userId) ?? game.user.id
|
||||
}
|
||||
|
||||
static isRollModeHiddenToPlayer() {
|
||||
@@ -220,8 +224,10 @@ export class Misc {
|
||||
* and there is no connected GM
|
||||
*/
|
||||
static documentIfResponsible(document) {
|
||||
if (game.users.activeGM || (Misc.connectedGMs().length == 0 && Misc.isFirstOwnerPlayer(document))) {
|
||||
return document
|
||||
if (Misc.isFirstConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isFirstOwnerPlayer(document))) {
|
||||
if (document.isOwner) {
|
||||
return document
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
@@ -230,16 +236,16 @@ export class Misc {
|
||||
if (Misc.isOwnerPlayer(document)) {
|
||||
return await action(document)
|
||||
} else {
|
||||
return await orElse(document ?? {name: '<aucune sélection>'})
|
||||
return await orElse(document ?? { name: '<aucune sélection>' })
|
||||
}
|
||||
}
|
||||
|
||||
static isOwnerPlayer(document) {
|
||||
return document && document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
|
||||
return document?.isOwner
|
||||
}
|
||||
|
||||
static isFirstOwnerPlayer(document) {
|
||||
if (!document?.testUserPermission) {
|
||||
if (!document?.isOwner) {
|
||||
return false
|
||||
}
|
||||
return game.users.find(u => document.testUserPermission(u, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) == game.user
|
||||
@@ -249,7 +255,7 @@ export class Misc {
|
||||
* @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id
|
||||
*/
|
||||
static isFirstConnectedGM() {
|
||||
return game.user == game.users.activeGM
|
||||
return game.users.activeGM != undefined && game.user == game.users.activeGM
|
||||
}
|
||||
|
||||
static hasConnectedGM() {
|
||||
|
||||
@@ -90,6 +90,8 @@ import { Migrations } from './migrations.js'
|
||||
import RollDialog from "./roll/roll-dialog.mjs"
|
||||
import ChatRollResult from "./roll/chat-roll-result.mjs"
|
||||
import ExportPdf from "./actor/export-pdf/export-pdf.mjs"
|
||||
import { DialogFlushByDate } from "./chat/dialog-flush-by-date.mjs"
|
||||
import { Remote } from "./remote.mjs"
|
||||
|
||||
/**
|
||||
* RdD system
|
||||
@@ -181,6 +183,7 @@ export class SystemReveDeDragon {
|
||||
game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => {
|
||||
console.log(">>>>> MSG RECV", sockmsg)
|
||||
try {
|
||||
Remote.onSocketMessage(sockmsg)
|
||||
RdDUtility.onSocketMessage(sockmsg)
|
||||
RdDCombat.onSocketMessage(sockmsg)
|
||||
ChatUtility.onSocketMessage(sockmsg)
|
||||
@@ -300,6 +303,7 @@ export class SystemReveDeDragon {
|
||||
ExportPdf.init()
|
||||
RollDialog.init()
|
||||
ChatRollResult.init()
|
||||
DialogFlushByDate.init()
|
||||
}
|
||||
|
||||
initSettings() {
|
||||
|
||||
@@ -348,7 +348,7 @@ export class RdDUtility {
|
||||
// Items
|
||||
Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field));
|
||||
Handlebars.registerHelper('item-action-applies', (action, item, options) => ItemAction.applies(action, item, options))
|
||||
Handlebars.registerHelper('item-action-icon', (action, item) => ItemAction.icon(action, item))
|
||||
Handlebars.registerHelper('item-action-img', (action, item) => new Handlebars.SafeString(ItemAction.img(action, item)))
|
||||
Handlebars.registerHelper('item-name', (item) => item.nameDisplay)
|
||||
|
||||
// TMRs
|
||||
|
||||
53
module/remote.mjs
Normal file
53
module/remote.mjs
Normal file
@@ -0,0 +1,53 @@
|
||||
import { RdDBaseActor } from "./actor/base-actor.js";
|
||||
import { SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
export class Remote {
|
||||
|
||||
static onSocketMessage(sockmsg) {
|
||||
switch (sockmsg.msg) {
|
||||
case "msg_remote_call":
|
||||
return Remote.onRemoteCall(sockmsg.userId, sockmsg.data);
|
||||
}
|
||||
}
|
||||
|
||||
static remoteCall({ userId = undefined, documentName, documentId, tokenId = undefined, method, args }) {
|
||||
const callData = { documentName, documentId, tokenId, method, args }
|
||||
const sendToUserId = Misc.connectedUserOrGM(userId)
|
||||
if (sendToUserId == undefined) {
|
||||
ui.notifications.error(`Impossible d'envoyer un message à ${userId}`)
|
||||
}
|
||||
else if (sendToUserId == game.user.id) {
|
||||
Remote.onRemoteCall(game.user.id, callData)
|
||||
return false
|
||||
}
|
||||
else {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_remote_call", userId: sendToUserId, data: callData })
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
static onRemoteCall(userId, callData) {
|
||||
if (userId == game.user.id) {
|
||||
// Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
|
||||
const doc = Remote.getDoc(callData)
|
||||
if (doc) {
|
||||
const args = callData.args;
|
||||
const method = callData.method;
|
||||
console.info(`Remote.onRemoteCall: ${callData.documentName} ${callData.documentId}, appel de ${method}(`, ...args, ')')
|
||||
doc[method](...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static getDoc(callData) {
|
||||
switch (callData.documentName) {
|
||||
case 'Actor': return RdDBaseActor.getRealActor(callData.documentId, callData.tokenId)
|
||||
case 'Item': return game.items.get(callData.documentId)
|
||||
case 'RollTable': return game.tables.get(callData.documentId)
|
||||
case 'ChatMessage': return game.messages.get(callData.documentId)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import { Misc } from "../misc.js"
|
||||
import { RollBasicParts } from "./roll-basic-parts.mjs"
|
||||
import { RdDPossessionV2 } from "../rdd-possession-v2.mjs"
|
||||
import { Apprecier } from "../moral/apprecier.mjs"
|
||||
import { Remote } from "../remote.mjs"
|
||||
|
||||
export default class ChatRollResult {
|
||||
static init() {
|
||||
@@ -168,14 +169,21 @@ export default class ChatRollResult {
|
||||
async updateChatMessage(chatMessage, savedRoll) {
|
||||
RollDialog.loadRollData(savedRoll)
|
||||
savedRoll.dmg = savedRoll.current.attaque?.dmg
|
||||
|
||||
|
||||
await this.saveChatMessageRoll(chatMessage, savedRoll)
|
||||
|
||||
|
||||
this.prepareDisplay(savedRoll)
|
||||
chatMessage.update({ content: await this.buildRollHtml(savedRoll) })
|
||||
chatMessage.render(true)
|
||||
|
||||
const content = await this.buildRollHtml(savedRoll)
|
||||
Remote.remoteCall({
|
||||
userId: chatMessage.author.id,
|
||||
documentName: chatMessage.documentName,
|
||||
documentId: chatMessage.id,
|
||||
method: 'update',
|
||||
args: [{ content: content }, { render: true }]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
async saveChatMessageRoll(chatMessage, roll, impacts = undefined) {
|
||||
const save = RollDialog.saveParts(roll, impacts)
|
||||
await ChatUtility.setMessageData(chatMessage, 'rollData', save)
|
||||
|
||||
@@ -150,12 +150,13 @@ export class RollPartCuisine extends RollPartSelect {
|
||||
this.$selectPreparation(rollDialog.rollData, selectOptions[index]?.value)
|
||||
rollDialog.render()
|
||||
})
|
||||
|
||||
|
||||
checkboxFabriquer?.addEventListener("change", e => {
|
||||
current.fabriquer = e.currentTarget.checked
|
||||
})
|
||||
inputDiff?.addEventListener("change", e => {
|
||||
current.value = parseInt(e.currentTarget.value)
|
||||
rollDialog.render()
|
||||
})
|
||||
inputProportions?.addEventListener("change", e => {
|
||||
current.proportions = parseInt(e.currentTarget.value)
|
||||
|
||||
@@ -7,7 +7,7 @@ import { RollType } from "./roll-type.mjs"
|
||||
|
||||
export class RollTypeCuisine extends RollType {
|
||||
get code() { return ROLL_TYPE_CUISINE }
|
||||
get name() { return `Interpréter une oeuvre` }
|
||||
get name() { return `Cuisiner un plat` }
|
||||
|
||||
visible(rollData) { return rollData.active.actor.isPersonnage() }
|
||||
title(rollData) {
|
||||
|
||||
@@ -222,6 +222,9 @@ export class RdDTimestamp {
|
||||
})
|
||||
}
|
||||
|
||||
static fromChatMessage(chatMessage) {
|
||||
return new RdDTimestamp(chatMessage.getFlag(SYSTEM_RDD, 'rdd-timestamp'))
|
||||
}
|
||||
/**
|
||||
* Constructeur d'un timestamp.
|
||||
* Selon les paramètres, l'objet construit se base su:
|
||||
@@ -231,7 +234,7 @@ export class RdDTimestamp {
|
||||
* @param indexMinute: la minute de la journée à utiliser pour ce timestamp
|
||||
*
|
||||
*/
|
||||
constructor({ indexDate, indexMinute = undefined }) {
|
||||
constructor({ indexDate = 0, indexMinute = undefined }) {
|
||||
this.indexDate = indexDate
|
||||
this.indexMinute = indexMinute ?? 0
|
||||
}
|
||||
@@ -269,6 +272,10 @@ export class RdDTimestamp {
|
||||
};
|
||||
}
|
||||
|
||||
isoDate() {
|
||||
return `${this.annee.paddedString(4)}-${this.mois.paddedString(2)}-${this.jour.paddedString(2)}`
|
||||
}
|
||||
|
||||
formatDate() {
|
||||
const jour = this.jour + 1;
|
||||
const mois = RdDTimestamp.definition(this.mois).label;
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
<span class="item-actions-controls item-controls">
|
||||
{{#each item.actions as |action|}}
|
||||
{{#if action.placeholder}}
|
||||
|
||||
{{/if}}
|
||||
{{#if (item-action-applies action ../item ../options)}}
|
||||
{{#if action.placeholder}}
|
||||
{{else if (item-action-applies action ../item ../options)}}
|
||||
<a class="actionItem" data-tooltip="{{action.label}}" data-code="{{action.code}}">
|
||||
{{#if (item-action-icon action ../item)}}
|
||||
<i class="{{item-action-icon action ../item}}"></i>
|
||||
{{else}}
|
||||
{{action.label}}
|
||||
{{/if}}
|
||||
{{item-action-img action ../item}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
|
||||
4
templates/chat/button-flush-by-date.hbs
Normal file
4
templates/chat/button-flush-by-date.hbs
Normal file
@@ -0,0 +1,4 @@
|
||||
<button type="button" class="ui-control icon fa-solid fa-trash-can" name="flush-by-date"
|
||||
data-tooltip=""
|
||||
aria-label="Effacer le tchat par date"
|
||||
data-action="flush-by-date"></button>
|
||||
Reference in New Issue
Block a user