From 0b645d54c68d719a0ca67133a70653da099a4ead Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Fri, 28 Apr 2017 08:28:45 +0300 Subject: [PATCH] Add support for 0x04 hex colors Ref: https://modern.ircdocs.horse/formatting.html#hex-color --- .../handlebars/ircmessageparser/parseStyle.js | 34 ++++- client/js/libs/handlebars/parse.js | 18 ++- .../handlebars/ircmessageparser/parseStyle.js | 119 ++++++++++++++++++ 3 files changed, 167 insertions(+), 4 deletions(-) diff --git a/client/js/libs/handlebars/ircmessageparser/parseStyle.js b/client/js/libs/handlebars/ircmessageparser/parseStyle.js index d23d5bd6..a0f3fd08 100644 --- a/client/js/libs/handlebars/ircmessageparser/parseStyle.js +++ b/client/js/libs/handlebars/ircmessageparser/parseStyle.js @@ -3,6 +3,7 @@ // Styling control codes const BOLD = "\x02"; const COLOR = "\x03"; +const HEX_COLOR = "\x04"; const RESET = "\x0f"; const REVERSE = "\x16"; const ITALIC = "\x1d"; @@ -12,6 +13,9 @@ const UNDERLINE = "\x1f"; // integers, `XX` is the text color and `YY` is an optional background color. const colorRx = /^(\d{1,2})(?:,(\d{1,2}))?/; +// 6-char Hex color code matcher +const hexColorRx = /^([0-9a-f]{6})(?:,([0-9a-f]{6}))?/i; + // Represents all other control codes that to be ignored/filtered from the text const controlCodesRx = /[\u0000-\u001F]/g; @@ -26,12 +30,14 @@ function parseStyle(text) { // At any given time, these carry style information since last time a styling // control code was met. - let colorCodes, bold, textColor, bgColor, reverse, italic, underline; + let colorCodes, bold, textColor, bgColor, hexColor, hexBgColor, reverse, italic, underline; const resetStyle = () => { bold = false; textColor = undefined; bgColor = undefined; + hexColor = undefined; + hexBgColor = undefined; reverse = false; italic = false; underline = false; @@ -57,6 +63,8 @@ function parseStyle(text) { bold, textColor, bgColor, + hexColor, + hexBgColor, reverse, italic, underline, @@ -113,6 +121,28 @@ function parseStyle(text) { } break; + case HEX_COLOR: + emitFragment(); + + colorCodes = text.slice(position + 1).match(hexColorRx); + + if (colorCodes) { + hexColor = colorCodes[1].toUpperCase(); + if (colorCodes[2]) { + hexBgColor = colorCodes[2].toUpperCase(); + } + // Color code length is > 1, so bump the current position cursor by as + // much (and reset the start cursor for the current text block as well) + position += colorCodes[0].length; + start = position + 1; + } else { + // If no color codes were found, toggles back to no colors (like BOLD). + hexColor = undefined; + hexBgColor = undefined; + } + + break; + case REVERSE: emitFragment(); reverse = !reverse; @@ -139,7 +169,7 @@ function parseStyle(text) { return result; } -const properties = ["bold", "textColor", "bgColor", "italic", "underline", "reverse"]; +const properties = ["bold", "textColor", "bgColor", "hexColor", "hexBgColor", "italic", "underline", "reverse"]; function prepare(text) { return parseStyle(text) diff --git a/client/js/libs/handlebars/parse.js b/client/js/libs/handlebars/parse.js index 915a432c..426cbe4f 100644 --- a/client/js/libs/handlebars/parse.js +++ b/client/js/libs/handlebars/parse.js @@ -24,10 +24,24 @@ function createFragment(fragment) { if (fragment.underline) { classes.push("irc-underline"); } + + let attributes = classes.length ? ` class="${classes.join(" ")}"` : ""; const escapedText = Handlebars.Utils.escapeExpression(fragment.text); - if (classes.length) { - return `${escapedText}`; + + if (fragment.hexColor) { + attributes += ` style="color:#${fragment.hexColor}`; + + if (fragment.hexBgColor) { + attributes += `;background-color:#${fragment.hexBgColor}`; + } + + attributes += "\""; } + + if (attributes.length) { + return `${escapedText}`; + } + return escapedText; } diff --git a/test/client/js/libs/handlebars/ircmessageparser/parseStyle.js b/test/client/js/libs/handlebars/ircmessageparser/parseStyle.js index 6af289c4..e978cbcc 100644 --- a/test/client/js/libs/handlebars/ircmessageparser/parseStyle.js +++ b/test/client/js/libs/handlebars/ircmessageparser/parseStyle.js @@ -10,6 +10,8 @@ describe("parseStyle", () => { bold: false, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -30,6 +32,8 @@ describe("parseStyle", () => { bold: true, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -50,6 +54,8 @@ describe("parseStyle", () => { bold: false, textColor: 8, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -69,6 +75,8 @@ describe("parseStyle", () => { const expected = [{ textColor: 4, bgColor: 8, + hexColor: undefined, + hexBgColor: undefined, bold: false, reverse: false, italic: false, @@ -90,6 +98,8 @@ describe("parseStyle", () => { bold: false, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: true, underline: false, @@ -104,12 +114,101 @@ describe("parseStyle", () => { expect(actual).to.deep.equal(expected); }); + it("should parse hex colors", () => { + const input = "test \x04FFFFFFnice \x02\x04RES006 \x0303,04\x04ff00FFcolored\x04eeeaFF,001122 background\x04\x03\x02?"; + const expected = [{ + bold: false, + textColor: undefined, + bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, + reverse: false, + italic: false, + underline: false, + text: "test ", + + start: 0, + end: 5 + }, { + bold: false, + textColor: undefined, + bgColor: undefined, + hexColor: "FFFFFF", + hexBgColor: undefined, + reverse: false, + italic: false, + underline: false, + text: "nice ", + + start: 5, + end: 10 + }, { + bold: true, + textColor: undefined, + bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, + reverse: false, + italic: false, + underline: false, + text: "RES006 ", + + start: 10, + end: 17 + }, { + bold: true, + textColor: 3, + bgColor: 4, + hexColor: "FF00FF", + hexBgColor: undefined, + reverse: false, + italic: false, + underline: false, + text: "colored", + + start: 17, + end: 24 + }, { + bold: true, + textColor: 3, + bgColor: 4, + hexColor: "EEEAFF", + hexBgColor: "001122", + reverse: false, + italic: false, + underline: false, + text: " background", + + start: 24, + end: 35 + }, { + bold: false, + textColor: undefined, + bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, + reverse: false, + italic: false, + underline: false, + text: "?", + + start: 35, + end: 36 + }]; + + const actual = parseStyle(input); + + expect(actual).to.deep.equal(expected); + }); + it("should carry state corretly forward", () => { const input = "\x02bold\x038yellow\x02nonBold\x03default"; const expected = [{ bold: true, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -121,6 +220,8 @@ describe("parseStyle", () => { bold: true, textColor: 8, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -132,6 +233,8 @@ describe("parseStyle", () => { bold: false, textColor: 8, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -143,6 +246,8 @@ describe("parseStyle", () => { bold: false, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -163,6 +268,8 @@ describe("parseStyle", () => { bold: true, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -174,6 +281,8 @@ describe("parseStyle", () => { bold: false, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -185,6 +294,8 @@ describe("parseStyle", () => { bold: true, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -205,6 +316,8 @@ describe("parseStyle", () => { bold: true, textColor: 4, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: true, italic: true, underline: true, @@ -216,6 +329,8 @@ describe("parseStyle", () => { bold: false, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -236,6 +351,8 @@ describe("parseStyle", () => { bold: false, textColor: undefined, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false, @@ -258,6 +375,8 @@ describe("parseStyle", () => { bold: false, textColor: 12, bgColor: undefined, + hexColor: undefined, + hexBgColor: undefined, reverse: false, italic: false, underline: false,