diff --git a/client/css/style.css b/client/css/style.css
index f3e20e0c..2d8b281c 100644
--- a/client/css/style.css
+++ b/client/css/style.css
@@ -915,6 +915,18 @@ button {
.bg-14 { background: #aaa; }
.bg-15 { background: #ddd; }
+.irc-bold {
+ font-weight: bold;
+}
+
+.irc-underline {
+ text-decoration: underline;
+}
+
+.irc-italic {
+ font-style:italic
+}
+
/**
* TrackpadScrollEmulator
* Version: 1.0.6
diff --git a/client/js/libs/handlebars/parse.js b/client/js/libs/handlebars/parse.js
index b0950d54..a8e6a770 100644
--- a/client/js/libs/handlebars/parse.js
+++ b/client/js/libs/handlebars/parse.js
@@ -48,46 +48,96 @@ function uri(text) {
});
}
-var regex = {
- color: /\003([0-9]{1,2})[,]?([0-9]{1,2})?([^\003]+)/,
- terminator: /\x0D/,
- styles: [
- [/\002([^\002]+)(\002)?/, ["", ""]],
- [/\037([^\037]+)(\037)?/, ["", ""]],
- ]
+
+/**
+ * MIRC compliant colour and style parser
+ * Unfortuanately this is a non trivial operation
+ * See this branch for source and tests
+ * https://github.com/megawac/irc-style-parser/tree/shout
+ */
+var styleCheck_Re = /[\x00-\x1F]/,
+ back_re = /^(\d{1,2})(,(\d{1,2}))?/,
+ colourKey = "\x03", colour_re = /\x03/g,
+ // breaks all open styles ^O (\x0F)
+ styleBreak = "\x0F";
+
+
+var styleTemplate = function(settings) {
+ return "" + settings.text + "";
};
-function colors(text) {
- if (!text) {
- return text;
- }
- if (regex.terminator.test(text)) {
- return $.map(text.split(regex.terminator), colors);
- }
- if (regex.color.test(text)) {
- var match, bg;
- while (match = regex.color.exec(text)) {
- var color = "color-" + match[1];
- if (match[2]) {
- bg = match[2];
- }
- if (bg) {
- color += " bg-" + bg;
- }
- var text = text.replace(
- match[0],
- "" + match[3] + ""
- );
- }
- }
- for (var i in regex.styles) {
- var pattern = regex.styles[i][0];
- var style = regex.styles[i][1];
- if (pattern.test(text)) {
- var match;
- while (match = pattern.exec(text)) {
- text = text.replace(match[0], style[0] + match[1] + style[1]);
- }
- }
- }
- return text;
+
+var styles = [
+ ["normal", "\x00", ""], ["underline", "\x1F"],
+ ["bold", "\x02"], ["italic", "\x1D"]
+].map(function(style) {
+ var escaped = encodeURI(style[1]).replace("%", "\\x");
+ return {
+ name: style[0],
+ style: style[2] != null ? style[2] : "irc-" + style[0],
+ key: style[1],
+ keyregex: new RegExp(escaped + "(.*?)(" + escaped + "|$)")
+ };
+});
+
+//http://www.mirc.com/colors.html
+var colourMap = {};
+for (var colour = 0; colour < 16; colour++) {
+ colourMap[colour] = {
+ fore: "color-" + colour,
+ back: "bg-" + colour
+ };
+}
+
+function colors(line) {
+ // http://www.mirc.com/colors.html
+ // http://www.aviran.org/stripremove-irc-client-control-characters/
+ // https://github.com/perl6/mu/blob/master/examples/rules/Grammar-IRC.pm
+ // regexs are cruel to parse this thing
+
+ // already done?
+ if (!styleCheck_Re.test(line)) return line;
+
+ // split up by the irc style break character ^O
+ if (line.indexOf(styleBreak) >= 0) {
+ return line.split(styleBreak).map(colors).join("");
+ }
+
+ var result = line;
+ var parseArr = result.split(colourKey);
+ var text, match, colour, background = "";
+ for (var i = 0; i < parseArr.length; i++) {
+ text = parseArr[i];
+ match = text.match(back_re);
+ colour = match && colourMap[+match[1]];
+ if (!match || !colour) {
+ // ^C (no colour) ending. Escape current colour and carry on
+ background = "";
+ continue;
+ }
+ // set the background colour
+ // we don't overide the background local var to support nesting
+ if (colourMap[+match[3]]) {
+ background = " " + colourMap[+match[3]].back;
+ }
+ // update the parsed text result
+ result = result.replace(colourKey + text, styleTemplate({
+ style: colour.fore + background,
+ text: text.slice(match[0].length)
+ }));
+ }
+
+ // Matching styles (italics/bold/underline)
+ // if only colours were this easy...
+ styles.forEach(function(style) {
+ if (result.indexOf(style.key) < 0) return;
+ result = result.replace(style.keyregex, function(match, text) {
+ return styleTemplate({
+ "style": style.style,
+ "text": text
+ });
+ });
+ });
+
+ //replace the reminent colour terminations and be done with it
+ return result.replace(colour_re, "");
}