logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git

tiny_post_html_processor.service.js (2695B)


  1. /**
  2. * This is a tiny purpose-built HTML parser/processor. This basically detects any type of visual newline and
  3. * allows it to be processed, useful for greentexting, mostly
  4. *
  5. * known issue: doesn't handle CDATA so nested CDATA might not work well
  6. *
  7. * @param {Object} input - input data
  8. * @param {(string) => string} processor - function that will be called on every line
  9. * @return {string} processed html
  10. */
  11. export const processHtml = (html, processor) => {
  12. const handledTags = new Set(['p', 'br', 'div'])
  13. const openCloseTags = new Set(['p', 'div'])
  14. let buffer = '' // Current output buffer
  15. const level = [] // How deep we are in tags and which tags were there
  16. let textBuffer = '' // Current line content
  17. let tagBuffer = null // Current tag buffer, if null = we are not currently reading a tag
  18. // Extracts tag name from tag, i.e. <span a="b"> => span
  19. const getTagName = (tag) => {
  20. const result = /(?:<\/(\w+)>|<(\w+)\s?[^/]*?\/?>)/gi.exec(tag)
  21. return result && (result[1] || result[2])
  22. }
  23. const flush = () => { // Processes current line buffer, adds it to output buffer and clears line buffer
  24. if (textBuffer.trim().length > 0) {
  25. buffer += processor(textBuffer)
  26. } else {
  27. buffer += textBuffer
  28. }
  29. textBuffer = ''
  30. }
  31. const handleBr = (tag) => { // handles single newlines/linebreaks/selfclosing
  32. flush()
  33. buffer += tag
  34. }
  35. const handleOpen = (tag) => { // handles opening tags
  36. flush()
  37. buffer += tag
  38. level.push(tag)
  39. }
  40. const handleClose = (tag) => { // handles closing tags
  41. flush()
  42. buffer += tag
  43. if (level[level.length - 1] === tag) {
  44. level.pop()
  45. }
  46. }
  47. for (let i = 0; i < html.length; i++) {
  48. const char = html[i]
  49. if (char === '<' && tagBuffer === null) {
  50. tagBuffer = char
  51. } else if (char !== '>' && tagBuffer !== null) {
  52. tagBuffer += char
  53. } else if (char === '>' && tagBuffer !== null) {
  54. tagBuffer += char
  55. const tagFull = tagBuffer
  56. tagBuffer = null
  57. const tagName = getTagName(tagFull)
  58. if (handledTags.has(tagName)) {
  59. if (tagName === 'br') {
  60. handleBr(tagFull)
  61. } else if (openCloseTags.has(tagName)) {
  62. if (tagFull[1] === '/') {
  63. handleClose(tagFull)
  64. } else if (tagFull[tagFull.length - 2] === '/') {
  65. // self-closing
  66. handleBr(tagFull)
  67. } else {
  68. handleOpen(tagFull)
  69. }
  70. }
  71. } else {
  72. textBuffer += tagFull
  73. }
  74. } else if (char === '\n') {
  75. handleBr(char)
  76. } else {
  77. textBuffer += char
  78. }
  79. }
  80. if (tagBuffer) {
  81. textBuffer += tagBuffer
  82. }
  83. flush()
  84. return buffer
  85. }