The frontend/UI server, written in JS using the MarkoJS library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
3.4 KiB

  1. const EventEmitter = require("events");
  2. let linkSignal = null;
  3. module.exports = class {
  4. onCreate(input) {
  5. this.state = {
  6. shortName: "",
  7. name: "",
  8. text: "",
  9. nameSuffix: "",
  10. modal: null,
  11. removed: false,
  12. multipart: false,
  13. anchored: false,
  14. prevWasText: false,
  15. }
  16. this.mounted = false;
  17. this.updatePost(input)
  18. }
  19. open(modal) {
  20. this.state.modal = modal
  21. }
  22. close() {
  23. this.state.modal = null
  24. }
  25. move(toPosition) {
  26. this.emit("move", toPosition)
  27. }
  28. remove() {
  29. this.state.removed = true
  30. this.emit("remove")
  31. }
  32. edited(data) {
  33. this.emit("edited", data)
  34. }
  35. onInput(input) {
  36. if (this.state == null) {
  37. return
  38. }
  39. const timediff = Date.parse(input.post.time) - Date.parse(input.prev.time)
  40. this.state.multipart = (input.post.nick == input.prev.nick && input.prev.multipart !== false) && (Math.abs(timediff) < 60000);
  41. this.state.prevWasText = (input.prev.kind === "text");
  42. this.updatePost(input)
  43. }
  44. onMount() {
  45. this.linkSignalCallback = () => {
  46. this.state.anchored = false
  47. }
  48. if (linkSignal == null) {
  49. linkSignal = new EventEmitter()
  50. linkSignal.setMaxListeners(10000)
  51. }
  52. linkSignal.on("signal", this.linkSignalCallback)
  53. this.state.anchored = window.location.hash.slice(1) === this.input.post.id;
  54. }
  55. onUnmount() {
  56. linkSignal.removeListener("signal", this.linkSignalCallback)
  57. }
  58. link() {
  59. linkSignal.emit("signal")
  60. this.state.anchored = true
  61. }
  62. updatePost(input) {
  63. this.state.shortName = input.post.nick.split("_").shift()
  64. this.state.name = input.post.nick
  65. this.state.nameSuffix = ""
  66. this.state.text = input.post.text.replace(/\x02/g, "**").replace(/\x1D/g, "*").replace(/\`/g, "\\`").trim();
  67. // Fix Ctrl-Bs
  68. let left = false
  69. this.state.text = this.state.text.replace(/\s*\*\*\s*/g, str => {
  70. left = !left
  71. if (left) {
  72. return " **"
  73. } else if (!left) {
  74. return "** "
  75. }
  76. return str
  77. })
  78. if (this.state.text.startsWith("|")) {
  79. this.state.name = ""
  80. this.state.text = this.state.text.slice(1).trim();
  81. }
  82. if (input.post.kind === "text" && !this.state.text.includes("\"") && !this.state.text.includes("\''") && !this.state.text.includes("|")) {
  83. const colonIndex = this.state.text.indexOf(": ");
  84. if (colonIndex != -1 && colonIndex < this.state.text.indexOf(" ")) {
  85. this.state.text = this.state.text.replace(": ", ": \"") + "\"";
  86. } else {
  87. this.state.text = '"' + this.state.text + '"'
  88. }
  89. }
  90. if (this.state.text.charAt(0) == this.state.text.charAt(0).toUpperCase()) {
  91. this.state.name = ""
  92. }
  93. if (!input.post.nick.startsWith("=")) {
  94. const postNick = input.post.nick.replace("'s", "").replace("s'", "s")
  95. for (const character of input.characters) {
  96. for (const nick of character.nicks) {
  97. if (nick === postNick) {
  98. this.state.name = character.name
  99. this.state.shortName = character.shortName
  100. if (input.post.nick.endsWith("'s") || input.post.nick.endsWith("'")) {
  101. this.state.nameSuffix = (character.shortName.endsWith("s") || character.shortName.endsWith("z")) ? "'" : "'s"
  102. }
  103. return
  104. }
  105. }
  106. }
  107. }
  108. }
  109. kindClass(prefix) {
  110. if (this.input.post == null) {
  111. return
  112. }
  113. return `${prefix}${this.input.post.kind.replace(".", "-")}`
  114. }
  115. }