소스 검색

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.
JC Brand 4 년 전
부모
커밋
1fd3e3676a
5개의 변경된 파일43개의 추가작업 그리고 42개의 파일을 삭제
  1. 1 1
      src/modals/base.js
  2. 7 7
      src/shared/message/styling.js
  3. 20 25
      src/shared/message/text.js
  4. 9 4
      src/templates/directives/body.js
  5. 6 5
      src/templates/directives/styling.js

+ 1 - 1
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();
     }

+ 7 - 7
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`<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_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>`,
-    'strike': (txt, m, i) => html`<span class="styling-directive">~</span><del>${renderStylingDirectiveBody(txt, m, i)}</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>`,
+    'quote': (txt, i, mentions, options) => html`<blockquote>${renderStylingDirectiveBody(txt, i, mentions, options)}</blockquote>`,
+    '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, 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) => ['>', '&gt;'].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);
     }
 }
 

+ 20 - 25
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 <img> 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 <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);
-        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);

+ 9 - 4
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;

+ 6 - 5
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))
+);