aboutsummaryrefslogtreecommitdiff
path: root/src/services/html_converter/utility.service.js
blob: f104297183f17593b9e48359e2ebda2a9c10dece (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
 * Extract tag name from tag opener/closer.
 *
 * @param {String} tag - tag string, i.e. '<a href="...">'
 * @return {String} - tagname, i.e. "div"
 */
export const getTagName = (tag) => {
  const result = /(?:<\/(\w+)>|<(\w+)\s?.*?\/?>)/gi.exec(tag)
  return result && (result[1] || result[2])
}

/**
 * Extract attributes from tag opener.
 *
 * @param {String} tag - tag string, i.e. '<a href="...">'
 * @return {Object} - map of attributes key = attribute name, value = attribute value
 *   attributes without values represented as boolean true
 */
export const getAttrs = (tag, filter) => {
  const innertag = tag
    .substring(1, tag.length - 1)
    .replace(new RegExp('^' + getTagName(tag)), '')
    .replace(/\/?$/, '')
    .trim()
  const attrs = Array.from(innertag.matchAll(/([a-z0-9-]+)(?:=("[^"]+?"|'[^']+?'))?/gi))
    .map(([trash, key, value]) => [key, value])
    .map(([k, v]) => {
      if (!v) return [k, true]
      return [k, v.substring(1, v.length - 1)]
    })
  const defaultFilter = ([k, v]) => {
    const attrKey = k.toLowerCase()
    if (attrKey === 'style') return false
    if (attrKey === 'class') {
      return v === 'greentext' || v === 'cyantext'
    }
    return true
  }
  return Object.fromEntries(attrs.filter(filter || defaultFilter))
}

/**
 * Finds shortcodes in text
 *
 * @param {String} text - original text to find emojis in
 * @param {{ url: String, shortcode: Sring }[]} emoji - list of shortcodes to find
 * @param {Function} processor - function to call on each encountered emoji,
 *   function is passed single object containing matching emoji ({ url, shortcode })
 *   return value will be inserted into resulting array instead of :shortcode:
 * @return {Array} resulting array with non-emoji parts of text and whatever {processor}
 *   returned for emoji
 */
export const processTextForEmoji = (text, emojis, processor) => {
  const buffer = []
  let textBuffer = ''
  for (let i = 0; i < text.length; i++) {
    const char = text[i]
    if (char === ':') {
      const next = text.slice(i + 1)
      let found = false
      for (const emoji of emojis) {
        if (next.slice(0, emoji.shortcode.length + 1) === (emoji.shortcode + ':')) {
          found = emoji
          break
        }
      }
      if (found) {
        buffer.push(textBuffer)
        textBuffer = ''
        buffer.push(processor(found))
        i += found.shortcode.length + 1
      } else {
        textBuffer += char
      }
    } else {
      textBuffer += char
    }
  }
  if (textBuffer) buffer.push(textBuffer)
  return buffer
}