thelounge/client/js/libs/handlebars/parse.js

126 lines
3.4 KiB
JavaScript
Raw Normal View History

2016-12-18 16:53:28 +01:00
import Handlebars from "handlebars/runtime";
import URI from "urijs";
2016-12-18 16:53:28 +01:00
module.exports = function(text) {
text = Handlebars.Utils.escapeExpression(text);
text = colors(text);
text = channels(text);
text = uri(text);
return text;
};
2014-10-11 01:11:57 +02:00
2014-09-28 00:01:28 +02:00
function uri(text) {
2016-12-18 16:53:28 +01:00
return URI.withinString(text, function(url) {
2014-10-12 00:57:34 +02:00
if (url.indexOf("javascript:") === 0) {
2014-10-11 01:11:57 +02:00
return url;
2014-09-28 00:01:28 +02:00
}
2014-10-12 00:57:34 +02:00
var split = url.split("<");
url = "<a href='" + split[0].replace(/^www/, "http://www") + "' target='_blank' rel='noopener'>" + split[0] + "</a>";
if (split.length > 1) {
url += "<" + split.slice(1).join("<");
2014-10-12 00:57:34 +02:00
}
return url;
2014-10-11 01:11:57 +02:00
});
2014-09-28 00:01:28 +02:00
}
/**
* Channels names are strings of length up to fifty (50) characters.
* The only restriction on a channel name is that it SHALL NOT contain
* any spaces (' '), a control G (^G or ASCII 7), a comma (',').
* Channel prefix '&' is handled as '&amp;' because this parser is executed
* after entities in the message have been escaped. This prevents a couple of bugs.
*/
function channels(text) {
return text.replace(
2016-10-09 10:54:44 +02:00
/(^|\s|\x07|,)((?:#|&amp;)[^\x07\s,]{1,49})/g,
'$1<span class="inline-channel" role="button" tabindex="0" data-chan="$2">$2</span>'
);
}
/**
* 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 = /^([0-9]{1,2})(,([0-9]{1,2}))?/,
colourKey = "\x03",
// breaks all open styles ^O (\x0F)
styleBreak = "\x0F";
2014-12-11 04:35:17 +01:00
function styleTemplate(settings) {
return "<span class='" + settings.style + "'>" + settings.text + "</span>";
2014-12-11 04:35:17 +01:00
}
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] ? style[2] : "irc-" + style[0],
key: style[1],
keyregex: new RegExp(escaped + "(.*?)(" + escaped + "|$)")
};
});
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);
if (!match) {
// ^C (no colour) ending. Escape current colour and carry on
background = "";
continue;
}
2016-01-24 14:57:44 +01:00
colour = "irc-fg" + +match[1];
// set the background colour
if (match[3]) {
background = " irc-bg" + +match[3];
}
// update the parsed text result
result = result.replace(colourKey + text, styleTemplate({
style: colour + 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;
}
2016-10-09 10:54:44 +02:00
result = result.replace(style.keyregex, function(matchedTrash, matchedText) {
return styleTemplate({
2016-10-09 10:54:44 +02:00
style: style.style,
text: matchedText
});
});
});
return result;
2014-09-28 00:01:28 +02:00
}