code.gitea.io/gitea@v1.22.3/web_src/js/features/comp/TextExpander.js (about)

     1  import {matchEmoji, matchMention} from '../../utils/match.js';
     2  import {emojiString} from '../emoji.js';
     3  
     4  export function initTextExpander(expander) {
     5    expander?.addEventListener('text-expander-change', ({detail: {key, provide, text}}) => {
     6      if (key === ':') {
     7        const matches = matchEmoji(text);
     8        if (!matches.length) return provide({matched: false});
     9  
    10        const ul = document.createElement('ul');
    11        ul.classList.add('suggestions');
    12        for (const name of matches) {
    13          const emoji = emojiString(name);
    14          const li = document.createElement('li');
    15          li.setAttribute('role', 'option');
    16          li.setAttribute('data-value', emoji);
    17          li.textContent = `${emoji} ${name}`;
    18          ul.append(li);
    19        }
    20  
    21        provide({matched: true, fragment: ul});
    22      } else if (key === '@') {
    23        const matches = matchMention(text);
    24        if (!matches.length) return provide({matched: false});
    25  
    26        const ul = document.createElement('ul');
    27        ul.classList.add('suggestions');
    28        for (const {value, name, fullname, avatar} of matches) {
    29          const li = document.createElement('li');
    30          li.setAttribute('role', 'option');
    31          li.setAttribute('data-value', `${key}${value}`);
    32  
    33          const img = document.createElement('img');
    34          img.src = avatar;
    35          li.append(img);
    36  
    37          const nameSpan = document.createElement('span');
    38          nameSpan.textContent = name;
    39          li.append(nameSpan);
    40  
    41          if (fullname && fullname.toLowerCase() !== name) {
    42            const fullnameSpan = document.createElement('span');
    43            fullnameSpan.classList.add('fullname');
    44            fullnameSpan.textContent = fullname;
    45            li.append(fullnameSpan);
    46          }
    47  
    48          ul.append(li);
    49        }
    50  
    51        provide({matched: true, fragment: ul});
    52      }
    53    });
    54    expander?.addEventListener('text-expander-value', ({detail}) => {
    55      if (detail?.item) {
    56        // add a space after @mentions as it's likely the user wants one
    57        const suffix = detail.key === '@' ? ' ' : '';
    58        detail.value = `${detail.item.getAttribute('data-value')}${suffix}`;
    59      }
    60    });
    61  }