diff --git a/client/css/style.css b/client/css/style.css
index f3e20e0..d68446c 100644
--- a/client/css/style.css
+++ b/client/css/style.css
@@ -879,41 +879,54 @@ button {
/**
- * Colors
- * http://clrs.cc/
- */
-.color-0, .color-00 { color: #fff; }
-.color-1, .color-01 { color: #000; }
-.color-2, .color-02 { color: #001f3f; }
-.color-3, .color-03 { color: #2ecc40; }
-.color-4, .color-04 { color: #ff4136; }
-.color-5, .color-05 { color: #85144b; }
-.color-6, .color-06 { color: #b10dc9; }
-.color-7, .color-07 { color: #ff851b; }
-.color-8, .color-08 { color: #ffdc00; }
-.color-9, .color-09 { color: #01ff70; }
-.color-10 { color: #39cccc; }
-.color-11 { color: #7fdbff; }
-.color-12 { color: #0074d9; }
-.color-13 { color: #f012be; }
-.color-14 { color: #aaa; }
-.color-15 { color: #ddd; }
-.bg-0, .bg-00 { background: #fff; }
-.bg-1, .bg-01 { background: #000; }
-.bg-2, .bg-02 { background: #001f3f; }
-.bg-3, .bg-03 { background: #2ecc40; }
-.bg-4, .bg-04 { background: #ff4136; }
-.bg-5, .bg-05 { background: #85144b; }
-.bg-6, .bg-06 { background: #b10dc9; }
-.bg-7, .bg-07 { background: #ff851b; }
-.bg-8, .bg-08 { background: #ffdc00; }
-.bg-9, .bg-09 { background: #01ff70; }
-.bg-10 { background: #39cccc; }
-.bg-11 { background: #7fdbff; }
-.bg-12 { background: #0074d9; }
-.bg-13 { background: #f012be; }
-.bg-14 { background: #aaa; }
-.bg-15 { background: #ddd; }
+ * IRC Message Styling
+ * https://github.com/megawac/irc-style-parser
+ * Colours are credit to http://clrs.cc/
+ */
+.irc-fg0 { color: #fff; }
+.irc-fg1 { color: #000; }
+.irc-fg2 { color: #001f3f; }
+.irc-fg3 { color: #2ecc40; }
+.irc-fg4 { color: #ff4136; }
+.irc-fg5 { color: #85144b; }
+.irc-fg6 { color: #b10dc9; }
+.irc-fg7 { color: #ff851b; }
+.irc-fg8 { color: #ffdc00; }
+.irc-fg9 { color: #01ff70; }
+.irc-fg10 { color: #39cccc; }
+.irc-fg11 { color: #7fdbff; }
+.irc-fg12 { color: #0074d9; }
+.irc-fg13 { color: #f012be; }
+.irc-fg14 { color: #aaa; }
+.irc-fg15 { color: #ddd; }
+.irc-bg0 { background: #fff; }
+.irc-bg1 { background: #000; }
+.irc-bg2 { background: #001f3f; }
+.irc-bg3 { background: #2ecc40; }
+.irc-bg4 { background: #ff4136; }
+.irc-bg5 { background: #85144b; }
+.irc-bg6 { background: #b10dc9; }
+.irc-bg7 { background: #ff851b; }
+.irc-bg8 { background: #ffdc00; }
+.irc-bg9 { background: #01ff70; }
+.irc-bg10 { background: #39cccc; }
+.irc-bg11 { background: #7fdbff; }
+.irc-bg12 { background: #0074d9; }
+.irc-bg13 { background: #f012be; }
+.irc-bg14 { background: #aaa; }
+.irc-bg15 { background: #ddd; }
+
+.irc-bold {
+ font-weight: bold;
+}
+
+.irc-underline {
+ text-decoration: underline;
+}
+
+.irc-italic {
+ font-style:italic
+}
/**
* TrackpadScrollEmulator
diff --git a/client/js/libs/handlebars/parse.js b/client/js/libs/handlebars/parse.js
index b0950d5..5a01d44 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)?/, ["", ""]],
- ]
-};
-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;
+
+/**
+ * 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";
+
+
+function styleTemplate(settings) {
+ return "" + settings.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: "irc-fg" + colour,
+ back: "irc-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, "");
}