diff --git a/src/modals/base.js b/src/modals/base.js
index b6de20967..92d748f3a 100644
--- a/src/modals/base.js
+++ b/src/modals/base.js
@@ -83,7 +83,7 @@ const BaseModal = View.extend({
if (ev) {
ev.preventDefault();
this.trigger_el = ev.target;
- this.trigger_el.classList.add('selected');
+ !u.hasClass('chat-image', this.trigger_el) && u.addClass('selected', this.trigger_el);
}
this.modal.show();
}
diff --git a/src/shared/message/styling.js b/src/shared/message/styling.js
index ed92f2dff..ac05ad766 100644
--- a/src/shared/message/styling.js
+++ b/src/shared/message/styling.js
@@ -23,12 +23,12 @@ const dont_escape = ['_', '>', '`', '~'];
const styling_templates = {
// m is the chatbox model
// i is the offset of this directive relative to the start of the original message
- 'emphasis': (txt, m, i) => html`_${renderStylingDirectiveBody(txt, m, i)}_`,
+ 'emphasis': (txt, i, mentions, options) => html`_${renderStylingDirectiveBody(txt, i, mentions, options)}_`,
'preformatted': txt => html`\`${txt}
\``,
'preformatted_block': txt => html`
\`\`\`
${txt}
\`\`\`
`,
- 'quote': (txt, m, i) => html`${renderStylingDirectiveBody(txt, m, i)}
`,
- 'strike': (txt, m, i) => html`~${renderStylingDirectiveBody(txt, m, i)}~`,
- 'strong': (txt, m, i) => html`*${renderStylingDirectiveBody(txt, m, i)}*`,
+ 'quote': (txt, i, mentions, options) => html`${renderStylingDirectiveBody(txt, i, mentions, options)}
`,
+ 'strike': (txt, i, mentions, options) => html`~${renderStylingDirectiveBody(txt, i, mentions, options)}~`,
+ 'strong': (txt, i, mentions, options) => html`*${renderStylingDirectiveBody(txt, i, mentions, options)}*`,
};
@@ -145,15 +145,15 @@ export function getDirectiveAndLength (text, i) {
export const isQuoteDirective = (d) => ['>', '>'].includes(d);
-export function getDirectiveTemplate (d, text, model, offset) {
+export function getDirectiveTemplate (d, text, offset, mentions, options) {
const template = styling_templates[styling_map[d].name];
if (isQuoteDirective(d)) {
const newtext = text
.replace(/\n>/g, '\n') // Don't show the directive itself
.replace(/\n$/, ''); // Trim line-break at the end
- return template(newtext, model, offset);
+ return template(newtext, offset, mentions, options);
} else {
- return template(text, model, offset);
+ return template(text, offset, mentions, options);
}
}
diff --git a/src/shared/message/text.js b/src/shared/message/text.js
index bd77f5e24..3a78ec3f8 100644
--- a/src/shared/message/text.js
+++ b/src/shared/message/text.js
@@ -39,25 +39,30 @@ export class MessageText extends String {
/**
* Create a new {@link MessageText} instance.
* @param { String } text - The text to be annotated
- * @param { Message } model - The model representing the message to which
- * this MessageText instance belongs
* @param { Integer } offset - The offset of this particular piece of text
* from the start of the original message text. This is necessary because
* MessageText instances can be nested when templates call directives
* which create new MessageText instances (as happens with XEP-393 styling directives).
- * @param { Boolean } show_images - Whether image URLs should be rendered as tags.
- * @param { Function } onImgLoad - Callback for when an inline rendered image has been loaded
- * @param { Function } onImgClick - Callback for when an inline rendered image has been clicked
+ * @param { Array } mentions - An array of mention references
+ * @param { Object } options
+ * @param { Object } options.nick - The current user's nickname (only relevant if the message is in a XEP-0045 MUC)
+ * @param { Boolean } options.render_styling - Whether XEP-0393 message styling should be applied to the message
+ * @param { Boolean } options.show_images - Whether image URLs should be rendered as tags.
+ * @param { Function } options.onImgClick - Callback for when an inline rendered image has been clicked
+ * @param { Function } options.onImgLoad - Callback for when an inline rendered image has been loaded
*/
- constructor (text, model, offset=0, show_images, onImgLoad, onImgClick) {
+ constructor (text, offset=0, mentions=[], options={}) {
super(text);
- this.model = model;
+ this.mentions = mentions;
+ this.nick = options?.nick;
this.offset = offset;
- this.onImgClick = onImgClick;
- this.onImgLoad = onImgLoad;
- this.references = [];
- this.show_images = show_images;
+ this.onImgClick = options?.onImgClick;
+ this.onImgLoad = options?.onImgLoad;
+ this.options = options;
this.payload = [];
+ this.references = [];
+ this.render_styling = options?.render_styling;
+ this.show_images = options?.show_images;
}
/**
@@ -136,21 +141,14 @@ export class MessageText extends String {
*/
addMentions (text, local_offset) {
const full_offset = local_offset+this.offset;
- if (!this.model.collection) {
- // This model doesn't belong to a collection anymore, so it must be
- // have been removed in the meantime and can be ignored.
- log.debug('addMentions: ignoring dangling model');
- return;
- }
- const nick = this.model.collection.chatbox.get('nick');
- this.model.get('references')?.forEach(ref => {
+ this.mentions?.forEach(ref => {
const begin = Number(ref.begin)-full_offset;
if (begin < 0 || begin >= full_offset+text.length) {
return;
}
const end = Number(ref.end)-full_offset;
const mention = text.slice(begin, end);
- if (mention === nick) {
+ if (mention === this.nick) {
this.addTemplateResult(
begin+local_offset,
end+local_offset,
@@ -171,9 +169,6 @@ export class MessageText extends String {
* them.
*/
addStyling () {
- if (this.model.get('is_unstyled') || !api.settings.get('allow_message_styling')) {
- return;
- }
let i = 0;
const references = [];
if (containsDirectives(this)) {
@@ -192,7 +187,7 @@ export class MessageText extends String {
const text = this.slice(slice_begin, slice_end);
references.push({
'begin': i,
- 'template': getDirectiveTemplate(d, text, this.model, offset),
+ 'template': getDirectiveTemplate(d, text, offset, this.mentions, this.options),
end,
});
i = end;
@@ -254,7 +249,7 @@ export class MessageText extends String {
*/
await api.trigger('beforeMessageBodyTransformed', this, {'Synchronous': true});
- this.addStyling();
+ this.render_styling && this.addStyling();
this.addAnnotations(this.addMentions);
this.addAnnotations(this.addHyperlinks);
this.addAnnotations(this.addMapURLs);
diff --git a/src/templates/directives/body.js b/src/templates/directives/body.js
index b9fea1389..907e1553b 100644
--- a/src/templates/directives/body.js
+++ b/src/templates/directives/body.js
@@ -18,14 +18,19 @@ class MessageBodyRenderer {
async transform () {
const show_images = api.settings.get('show_images_inline');
+ const render_styling = !this.model.get('is_unstyled') && api.settings.get('allow_message_styling');
const offset = 0;
const text = new MessageText(
this.text,
- this.model,
offset,
- show_images,
- () => this.onImageLoaded(),
- ev => this.component.showImageModal(ev)
+ this.model.get('references'),
+ {
+ 'nick': this.model.collection.chatbox.get('nick'),
+ 'onImgClick': () => this.onImageLoaded(),
+ 'onImgLoad': ev => this.component.showImageModal(ev),
+ render_styling,
+ show_images,
+ }
);
await text.addTemplates();
return text.payload;
diff --git a/src/templates/directives/styling.js b/src/templates/directives/styling.js
index ec5c73f2b..3777325d2 100644
--- a/src/templates/directives/styling.js
+++ b/src/templates/directives/styling.js
@@ -1,16 +1,17 @@
import { MessageText } from '../../shared/message/text.js';
-import { directive, html } from "lit-html";
+import { directive, html } from 'lit-html';
import { until } from 'lit-html/directives/until.js';
-
async function transform (t) {
await t.addTemplates();
return t.payload;
}
-function renderer (text, model, offset) {
- const t = new MessageText(text, model, offset, false);
+function renderer (text, offset, mentions, options) {
+ const t = new MessageText(text, offset, mentions, Object.assign(options, { 'show_images': false }));
return html`${until(transform(t), html`${t}`)}`;
}
-export const renderStylingDirectiveBody = directive((text, model, offset) => p => p.setValue(renderer(text, model, offset)));
+export const renderStylingDirectiveBody = directive((txt, offset, mentions, options) =>
+ p => p.setValue(renderer(txt, offset, mentions, options))
+);