diff --git a/client/js/libs/handlebars/ircmessageparser/merge.js b/client/js/libs/handlebars/ircmessageparser/merge.js index fd1a6877..890df86c 100644 --- a/client/js/libs/handlebars/ircmessageparser/merge.js +++ b/client/js/libs/handlebars/ircmessageparser/merge.js @@ -13,23 +13,34 @@ function assign(textPart, fragment) { return Object.assign({}, fragment, {start, end, text}); } -// Merge the style fragments withing the text parts, taking into account +function sortParts(a, b) { + return a.start - b.start || b.end - a.end; +} + +// Merge the style fragments within the text parts, taking into account // boundaries and text sections that have not matched to links or channels. // For example, given a string "foobar" where "foo" and "bar" have been // identified as parts (channels, links, etc.) and "fo", "ob" and "ar" have 3 // different styles, the first resulting part will contain fragments "fo" and // "o", and the second resulting part will contain "b" and "ar". "o" and "b" // fragments will contain duplicate styling attributes. -function merge(textParts, styleFragments) { - // Re-build the overall text (without control codes) from the style fragments - const cleanText = styleFragments.reduce((acc, frag) => acc + frag.text, ""); - +function merge(textParts, styleFragments, cleanText) { // Every section of the original text that has not been captured in a "part" // is filled with "text" parts, dummy objects with start/end but no extra // metadata. const allParts = textParts + .sort(sortParts) // Sort all parts identified based on their position in the original text .concat(fill(textParts, cleanText)) - .sort((a, b) => a.start - b.start); + .sort(sortParts) // Sort them again after filling in unstyled text + .reduce((prev, curr) => { + const intersection = prev.some((p) => anyIntersection(p, curr)); + + if (intersection) { + return prev; + } + + return prev.concat([curr]); + }, []); // Distribute the style fragments within the text parts return allParts.map((textPart) => { diff --git a/client/js/libs/handlebars/parse.js b/client/js/libs/handlebars/parse.js index bd825047..0a08769a 100644 --- a/client/js/libs/handlebars/parse.js +++ b/client/js/libs/handlebars/parse.js @@ -2,7 +2,6 @@ const Handlebars = require("handlebars/runtime"); const parseStyle = require("./ircmessageparser/parseStyle"); -const anyIntersection = require("./ircmessageparser/anyIntersection"); const findChannels = require("./ircmessageparser/findChannels"); const findLinks = require("./ircmessageparser/findLinks"); const findEmoji = require("./ircmessageparser/findEmoji"); @@ -85,25 +84,14 @@ module.exports = function parse(text, users) { const emojiParts = findEmoji(cleanText); const nameParts = findNames(cleanText, (users || [])); - // Sort all parts identified based on their position in the original text const parts = channelParts .concat(linkParts) .concat(emojiParts) - .concat(nameParts) - .sort((a, b) => a.start - b.start || b.end - a.end) - .reduce((prev, curr) => { - const intersection = prev.some((p) => anyIntersection(p, curr)); - - if (intersection) { - return prev; - } - - return prev.concat([curr]); - }, []); + .concat(nameParts); // Merge the styling information with the channels / URLs / nicks / text objects and // generate HTML strings with the resulting fragments - return merge(parts, styleFragments).map((textPart) => { + return merge(parts, styleFragments, cleanText).map((textPart) => { // Create HTML strings with styling information const fragments = textPart.fragments.map(createFragment).join(""); diff --git a/test/client/js/libs/handlebars/ircmessageparser/merge.js b/test/client/js/libs/handlebars/ircmessageparser/merge.js index bcf79ca5..4125b6cc 100644 --- a/test/client/js/libs/handlebars/ircmessageparser/merge.js +++ b/test/client/js/libs/handlebars/ircmessageparser/merge.js @@ -56,7 +56,7 @@ describe("merge", () => { }], }]; - const actual = merge(textParts, styleFragments); + const actual = merge(textParts, styleFragments, styleFragments.map((fragment) => fragment.text).join("")); expect(actual).to.deep.equal(expected); });