Update the MesageText class to not require a Model object
This allows us to use it to transform any piece of text and not just text from a chat message.
This commit is contained in:
parent
16e7133e31
commit
1fd3e3676a
@ -83,7 +83,7 @@ const BaseModal = View.extend({
|
|||||||
if (ev) {
|
if (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.trigger_el = ev.target;
|
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();
|
this.modal.show();
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,12 @@ const dont_escape = ['_', '>', '`', '~'];
|
|||||||
const styling_templates = {
|
const styling_templates = {
|
||||||
// m is the chatbox model
|
// m is the chatbox model
|
||||||
// i is the offset of this directive relative to the start of the original message
|
// i is the offset of this directive relative to the start of the original message
|
||||||
'emphasis': (txt, m, i) => html`<span class="styling-directive">_</span><i>${renderStylingDirectiveBody(txt, m, i)}</i><span class="styling-directive">_</span>`,
|
'emphasis': (txt, i, mentions, options) => html`<span class="styling-directive">_</span><i>${renderStylingDirectiveBody(txt, i, mentions, options)}</i><span class="styling-directive">_</span>`,
|
||||||
'preformatted': txt => html`<span class="styling-directive">\`</span><code>${txt}</code><span class="styling-directive">\`</span>`,
|
'preformatted': txt => html`<span class="styling-directive">\`</span><code>${txt}</code><span class="styling-directive">\`</span>`,
|
||||||
'preformatted_block': txt => html`<div class="styling-directive">\`\`\`</div><code class="block">${txt}</code><div class="styling-directive">\`\`\`</div>`,
|
'preformatted_block': txt => html`<div class="styling-directive">\`\`\`</div><code class="block">${txt}</code><div class="styling-directive">\`\`\`</div>`,
|
||||||
'quote': (txt, m, i) => html`<blockquote>${renderStylingDirectiveBody(txt, m, i)}</blockquote>`,
|
'quote': (txt, i, mentions, options) => html`<blockquote>${renderStylingDirectiveBody(txt, i, mentions, options)}</blockquote>`,
|
||||||
'strike': (txt, m, i) => html`<span class="styling-directive">~</span><del>${renderStylingDirectiveBody(txt, m, i)}</del><span class="styling-directive">~</span>`,
|
'strike': (txt, i, mentions, options) => html`<span class="styling-directive">~</span><del>${renderStylingDirectiveBody(txt, i, mentions, options)}</del><span class="styling-directive">~</span>`,
|
||||||
'strong': (txt, m, i) => html`<span class="styling-directive">*</span><b>${renderStylingDirectiveBody(txt, m, i)}</b><span class="styling-directive">*</span>`,
|
'strong': (txt, i, mentions, options) => html`<span class="styling-directive">*</span><b>${renderStylingDirectiveBody(txt, i, mentions, options)}</b><span class="styling-directive">*</span>`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -145,15 +145,15 @@ export function getDirectiveAndLength (text, i) {
|
|||||||
export const isQuoteDirective = (d) => ['>', '>'].includes(d);
|
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];
|
const template = styling_templates[styling_map[d].name];
|
||||||
if (isQuoteDirective(d)) {
|
if (isQuoteDirective(d)) {
|
||||||
const newtext = text
|
const newtext = text
|
||||||
.replace(/\n>/g, '\n') // Don't show the directive itself
|
.replace(/\n>/g, '\n') // Don't show the directive itself
|
||||||
.replace(/\n$/, ''); // Trim line-break at the end
|
.replace(/\n$/, ''); // Trim line-break at the end
|
||||||
return template(newtext, model, offset);
|
return template(newtext, offset, mentions, options);
|
||||||
} else {
|
} else {
|
||||||
return template(text, model, offset);
|
return template(text, offset, mentions, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,25 +39,30 @@ export class MessageText extends String {
|
|||||||
/**
|
/**
|
||||||
* Create a new {@link MessageText} instance.
|
* Create a new {@link MessageText} instance.
|
||||||
* @param { String } text - The text to be annotated
|
* @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
|
* @param { Integer } offset - The offset of this particular piece of text
|
||||||
* from the start of the original message text. This is necessary because
|
* from the start of the original message text. This is necessary because
|
||||||
* MessageText instances can be nested when templates call directives
|
* MessageText instances can be nested when templates call directives
|
||||||
* which create new MessageText instances (as happens with XEP-393 styling directives).
|
* which create new MessageText instances (as happens with XEP-393 styling directives).
|
||||||
* @param { Boolean } show_images - Whether image URLs should be rendered as <img> tags.
|
* @param { Array } mentions - An array of mention references
|
||||||
* @param { Function } onImgLoad - Callback for when an inline rendered image has been loaded
|
* @param { Object } options
|
||||||
* @param { Function } onImgClick - Callback for when an inline rendered image has been clicked
|
* @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 <img> 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);
|
super(text);
|
||||||
this.model = model;
|
this.mentions = mentions;
|
||||||
|
this.nick = options?.nick;
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
this.onImgClick = onImgClick;
|
this.onImgClick = options?.onImgClick;
|
||||||
this.onImgLoad = onImgLoad;
|
this.onImgLoad = options?.onImgLoad;
|
||||||
this.references = [];
|
this.options = options;
|
||||||
this.show_images = show_images;
|
|
||||||
this.payload = [];
|
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) {
|
addMentions (text, local_offset) {
|
||||||
const full_offset = local_offset+this.offset;
|
const full_offset = local_offset+this.offset;
|
||||||
if (!this.model.collection) {
|
this.mentions?.forEach(ref => {
|
||||||
// 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 => {
|
|
||||||
const begin = Number(ref.begin)-full_offset;
|
const begin = Number(ref.begin)-full_offset;
|
||||||
if (begin < 0 || begin >= full_offset+text.length) {
|
if (begin < 0 || begin >= full_offset+text.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const end = Number(ref.end)-full_offset;
|
const end = Number(ref.end)-full_offset;
|
||||||
const mention = text.slice(begin, end);
|
const mention = text.slice(begin, end);
|
||||||
if (mention === nick) {
|
if (mention === this.nick) {
|
||||||
this.addTemplateResult(
|
this.addTemplateResult(
|
||||||
begin+local_offset,
|
begin+local_offset,
|
||||||
end+local_offset,
|
end+local_offset,
|
||||||
@ -171,9 +169,6 @@ export class MessageText extends String {
|
|||||||
* them.
|
* them.
|
||||||
*/
|
*/
|
||||||
addStyling () {
|
addStyling () {
|
||||||
if (this.model.get('is_unstyled') || !api.settings.get('allow_message_styling')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const references = [];
|
const references = [];
|
||||||
if (containsDirectives(this)) {
|
if (containsDirectives(this)) {
|
||||||
@ -192,7 +187,7 @@ export class MessageText extends String {
|
|||||||
const text = this.slice(slice_begin, slice_end);
|
const text = this.slice(slice_begin, slice_end);
|
||||||
references.push({
|
references.push({
|
||||||
'begin': i,
|
'begin': i,
|
||||||
'template': getDirectiveTemplate(d, text, this.model, offset),
|
'template': getDirectiveTemplate(d, text, offset, this.mentions, this.options),
|
||||||
end,
|
end,
|
||||||
});
|
});
|
||||||
i = end;
|
i = end;
|
||||||
@ -254,7 +249,7 @@ export class MessageText extends String {
|
|||||||
*/
|
*/
|
||||||
await api.trigger('beforeMessageBodyTransformed', this, {'Synchronous': true});
|
await api.trigger('beforeMessageBodyTransformed', this, {'Synchronous': true});
|
||||||
|
|
||||||
this.addStyling();
|
this.render_styling && this.addStyling();
|
||||||
this.addAnnotations(this.addMentions);
|
this.addAnnotations(this.addMentions);
|
||||||
this.addAnnotations(this.addHyperlinks);
|
this.addAnnotations(this.addHyperlinks);
|
||||||
this.addAnnotations(this.addMapURLs);
|
this.addAnnotations(this.addMapURLs);
|
||||||
|
@ -18,14 +18,19 @@ class MessageBodyRenderer {
|
|||||||
|
|
||||||
async transform () {
|
async transform () {
|
||||||
const show_images = api.settings.get('show_images_inline');
|
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 offset = 0;
|
||||||
const text = new MessageText(
|
const text = new MessageText(
|
||||||
this.text,
|
this.text,
|
||||||
this.model,
|
|
||||||
offset,
|
offset,
|
||||||
show_images,
|
this.model.get('references'),
|
||||||
() => this.onImageLoaded(),
|
{
|
||||||
ev => this.component.showImageModal(ev)
|
'nick': this.model.collection.chatbox.get('nick'),
|
||||||
|
'onImgClick': () => this.onImageLoaded(),
|
||||||
|
'onImgLoad': ev => this.component.showImageModal(ev),
|
||||||
|
render_styling,
|
||||||
|
show_images,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
await text.addTemplates();
|
await text.addTemplates();
|
||||||
return text.payload;
|
return text.payload;
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import { MessageText } from '../../shared/message/text.js';
|
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';
|
import { until } from 'lit-html/directives/until.js';
|
||||||
|
|
||||||
|
|
||||||
async function transform (t) {
|
async function transform (t) {
|
||||||
await t.addTemplates();
|
await t.addTemplates();
|
||||||
return t.payload;
|
return t.payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderer (text, model, offset) {
|
function renderer (text, offset, mentions, options) {
|
||||||
const t = new MessageText(text, model, offset, false);
|
const t = new MessageText(text, offset, mentions, Object.assign(options, { 'show_images': false }));
|
||||||
return html`${until(transform(t), html`${t}`)}`;
|
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))
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user