Better API for adding on to our Dialect
This commit is contained in:
parent
92d7953dd0
commit
8f94760cd4
|
@ -1,45 +1,19 @@
|
|||
/**
|
||||
This addition handles auto linking of text. When included, it will parse out links and create
|
||||
a hrefs for them.
|
||||
|
||||
@event register
|
||||
@namespace Discourse.Dialect
|
||||
**/
|
||||
Discourse.Dialect.on("register", function(event) {
|
||||
var urlReplacerArgs = {
|
||||
matcher: /(^|\s)((?:https?:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.])(?:[^\s()<>]+|\([^\s()<>]+\))+(?:\([^\s()<>]+\)|[^`!()\[\]{};:'".,<>?«»“”‘’\s]))/gm,
|
||||
spaceBoundary: true,
|
||||
|
||||
var dialect = event.dialect,
|
||||
MD = event.MD;
|
||||
emitter: function(matches) {
|
||||
var url = matches[2],
|
||||
displayUrl = url;
|
||||
|
||||
/**
|
||||
Parses out links from HTML.
|
||||
if (url.match(/^www/)) { url = "http://" + url; }
|
||||
return ['a', {href: url}, displayUrl];
|
||||
}
|
||||
};
|
||||
|
||||
@method autoLink
|
||||
@param {String} text the text match
|
||||
@param {Array} match the match found
|
||||
@param {Array} prev the previous jsonML
|
||||
@return {Array} an array containing how many chars we've replaced and the jsonML content for it.
|
||||
@namespace Discourse.Dialect
|
||||
**/
|
||||
dialect.inline['http'] = dialect.inline['www'] = function autoLink(text, match, prev) {
|
||||
|
||||
// We only care about links on boundaries
|
||||
if (prev && (prev.length > 0)) {
|
||||
var last = prev[prev.length - 1];
|
||||
if (typeof last === "string" && (!last.match(/\s$/))) { return; }
|
||||
}
|
||||
|
||||
var pattern = /(^|\s)((?:https?:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.])(?:[^\s()<>]+|\([^\s()<>]+\))+(?:\([^\s()<>]+\)|[^`!()\[\]{};:'".,<>?«»“”‘’\s]))/gm,
|
||||
m = pattern.exec(text);
|
||||
|
||||
if (m) {
|
||||
var url = m[2],
|
||||
displayUrl = m[2];
|
||||
|
||||
if (url.match(/^www/)) { url = "http://" + url; }
|
||||
return [m[0].length, ['a', {href: url}, displayUrl]];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
Discourse.Dialect.inlineRegexp(_.merge({start: 'http'}, urlReplacerArgs));
|
||||
Discourse.Dialect.inlineRegexp(_.merge({start: 'www'}, urlReplacerArgs));
|
||||
|
|
|
@ -1,76 +1,112 @@
|
|||
/**
|
||||
Regsiter all functionality for supporting BBCode in Discourse.
|
||||
Create a simple BBCode tag handler
|
||||
|
||||
@event register
|
||||
@namespace Discourse.Dialect
|
||||
@method replaceBBCode
|
||||
@param {tag} tag the tag we want to match
|
||||
@param {function} emitter the function that creates JsonML for the tag
|
||||
**/
|
||||
function replaceBBCode(tag, emitter) {
|
||||
Discourse.Dialect.inlineReplace({
|
||||
start: "[" + tag + "]",
|
||||
stop: "[/" + tag + "]",
|
||||
emitter: emitter
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a BBCode handler that accepts parameters. Passes them to the emitter.
|
||||
|
||||
@method replaceBBCodeParamsRaw
|
||||
@param {tag} tag the tag we want to match
|
||||
@param {function} emitter the function that creates JsonML for the tag
|
||||
**/
|
||||
function replaceBBCodeParamsRaw(tag, emitter) {
|
||||
Discourse.Dialect.inlineReplace({
|
||||
start: "[" + tag + "=",
|
||||
stop: "[/" + tag + "]",
|
||||
rawContents: true,
|
||||
emitter: function(contents) {
|
||||
var regexp = /^([^\]]+)\](.*)$/,
|
||||
m = regexp.exec(contents);
|
||||
|
||||
if (m) { return emitter.call(this, m[1], m[2]); }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a BBCode handler that accepts parameters. Passes them to the emitter.
|
||||
Processes the inside recursively so it can be nested.
|
||||
|
||||
@method replaceBBCodeParams
|
||||
@param {tag} tag the tag we want to match
|
||||
@param {function} emitter the function that creates JsonML for the tag
|
||||
**/
|
||||
function replaceBBCodeParams(tag, emitter) {
|
||||
replaceBBCodeParamsRaw(tag, function (param, contents) {
|
||||
return emitter(param, this.processInline(contents));
|
||||
});
|
||||
}
|
||||
|
||||
replaceBBCode('b', function(contents) { return ['span', {'class': 'bbcode-b'}].concat(contents); });
|
||||
replaceBBCode('i', function(contents) { return ['span', {'class': 'bbcode-i'}].concat(contents); });
|
||||
replaceBBCode('u', function(contents) { return ['span', {'class': 'bbcode-u'}].concat(contents); });
|
||||
replaceBBCode('s', function(contents) { return ['span', {'class': 'bbcode-s'}].concat(contents); });
|
||||
|
||||
replaceBBCode('ul', function(contents) { return ['ul'].concat(contents); });
|
||||
replaceBBCode('ol', function(contents) { return ['ol'].concat(contents); });
|
||||
replaceBBCode('li', function(contents) { return ['li'].concat(contents); });
|
||||
|
||||
replaceBBCode('spoiler', function(contents) { return ['span', {'class': 'spoiler'}].concat(contents); });
|
||||
|
||||
Discourse.Dialect.inlineReplace({
|
||||
start: '[img]',
|
||||
stop: '[/img]',
|
||||
rawContents: true,
|
||||
emitter: function(contents) { return ['img', {href: contents}]; }
|
||||
});
|
||||
|
||||
Discourse.Dialect.inlineReplace({
|
||||
start: '[email]',
|
||||
stop: '[/email]',
|
||||
rawContents: true,
|
||||
emitter: function(contents) { return ['a', {href: "mailto:" + contents, 'data-bbcode': true}, contents]; }
|
||||
});
|
||||
|
||||
Discourse.Dialect.inlineReplace({
|
||||
start: '[url]',
|
||||
stop: '[/url]',
|
||||
rawContents: true,
|
||||
emitter: function(contents) { return ['a', {href: contents, 'data-bbcode': true}, contents]; }
|
||||
});
|
||||
|
||||
|
||||
replaceBBCodeParamsRaw("url", function(param, contents) {
|
||||
return ['a', {href: param, 'data-bbcode': true}, contents];
|
||||
});
|
||||
|
||||
replaceBBCodeParamsRaw("email", function(param, contents) {
|
||||
return ['a', {href: "mailto:" + param, 'data-bbcode': true}, contents];
|
||||
});
|
||||
|
||||
replaceBBCodeParams("size", function(param, contents) {
|
||||
return ['span', {'class': "bbcode-size-" + param}].concat(contents);
|
||||
});
|
||||
|
||||
replaceBBCodeParams("color", function(param, contents) {
|
||||
// Only allow valid HTML colors.
|
||||
if (/^(\#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?)|(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)$/.test(param)) {
|
||||
return ['span', {style: "color: " + param}].concat(contents);
|
||||
} else {
|
||||
return ['span'].concat(contents);
|
||||
}
|
||||
});
|
||||
|
||||
Discourse.Dialect.on("register", function(event) {
|
||||
|
||||
var dialect = event.dialect,
|
||||
MD = event.MD;
|
||||
|
||||
var createBBCode = function(tag, builder, hasArgs) {
|
||||
return function(text, orig_match) {
|
||||
var bbcodePattern = new RegExp("\\[" + tag + "=?([^\\[\\]]+)?\\]([\\s\\S]*?)\\[\\/" + tag + "\\]", "igm");
|
||||
var m = bbcodePattern.exec(text);
|
||||
if (m && m[0]) {
|
||||
return [m[0].length, builder(m, this)];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var bbcodes = {'b': ['span', {'class': 'bbcode-b'}],
|
||||
'i': ['span', {'class': 'bbcode-i'}],
|
||||
'u': ['span', {'class': 'bbcode-u'}],
|
||||
's': ['span', {'class': 'bbcode-s'}],
|
||||
'spoiler': ['span', {'class': 'spoiler'}],
|
||||
'li': ['li'],
|
||||
'ul': ['ul'],
|
||||
'ol': ['ol']};
|
||||
|
||||
Object.keys(bbcodes).forEach(function(tag) {
|
||||
var element = bbcodes[tag];
|
||||
dialect.inline["[" + tag + "]"] = createBBCode(tag, function(m, self) {
|
||||
return element.concat(self.processInline(m[2]));
|
||||
});
|
||||
});
|
||||
|
||||
dialect.inline["[img]"] = createBBCode('img', function(m) {
|
||||
return ['img', {href: m[2]}];
|
||||
});
|
||||
|
||||
dialect.inline["[email]"] = createBBCode('email', function(m) {
|
||||
return ['a', {href: "mailto:" + m[2], 'data-bbcode': true}, m[2]];
|
||||
});
|
||||
|
||||
dialect.inline["[url]"] = createBBCode('url', function(m) {
|
||||
return ['a', {href: m[2], 'data-bbcode': true}, m[2]];
|
||||
});
|
||||
|
||||
dialect.inline["[url="] = createBBCode('url', function(m, self) {
|
||||
return ['a', {href: m[1], 'data-bbcode': true}].concat(self.processInline(m[2]));
|
||||
});
|
||||
|
||||
dialect.inline["[email="] = createBBCode('email', function(m, self) {
|
||||
return ['a', {href: "mailto:" + m[1], 'data-bbcode': true}].concat(self.processInline(m[2]));
|
||||
});
|
||||
|
||||
dialect.inline["[size="] = createBBCode('size', function(m, self) {
|
||||
return ['span', {'class': "bbcode-size-" + m[1]}].concat(self.processInline(m[2]));
|
||||
});
|
||||
|
||||
dialect.inline["[color="] = function(text, orig_match) {
|
||||
var bbcodePattern = new RegExp("\\[color=?([^\\[\\]]+)?\\]([\\s\\S]*?)\\[\\/color\\]", "igm"),
|
||||
m = bbcodePattern.exec(text);
|
||||
|
||||
if (m && m[0]) {
|
||||
if (!/^(\#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?)|(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)$/.test(m[1])) {
|
||||
return [m[0].length].concat(this.processInline(m[2]));
|
||||
}
|
||||
return [m[0].length, ['span', {style: "color: " + m[1]}].concat(this.processInline(m[2]))];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Support BBCode [code] blocks
|
||||
|
||||
|
|
|
@ -1,43 +1,25 @@
|
|||
/**
|
||||
Markdown.js doesn't seem to do bold and italics at the same time if you surround code with
|
||||
three asterisks. This adds that support.
|
||||
|
||||
@event register
|
||||
@namespace Discourse.Dialect
|
||||
markdown-js doesn't ensure that em/strong codes are present on word boundaries.
|
||||
So we create our own handlers here.
|
||||
**/
|
||||
Discourse.Dialect.on("register", function(event) {
|
||||
|
||||
var dialect = event.dialect,
|
||||
MD = event.MD;
|
||||
|
||||
|
||||
var inlineBuilder = function(symbol, tag, surround) {
|
||||
return function(text, match, prev) {
|
||||
if (prev && (prev.length > 0)) {
|
||||
var last = prev[prev.length - 1];
|
||||
if (typeof last === "string" && (!last.match(/\W$/))) { return; }
|
||||
}
|
||||
|
||||
var regExp = new RegExp("^\\" + symbol + "([^\\" + symbol + "]+)" + "\\" + symbol, "igm"),
|
||||
m = regExp.exec(text);
|
||||
|
||||
if (m) {
|
||||
|
||||
var contents = [tag].concat(this.processInline(m[1]));
|
||||
if (surround) {
|
||||
contents = [surround, contents];
|
||||
}
|
||||
|
||||
return [m[0].length, contents];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
dialect.inline['***'] = inlineBuilder('**', 'em', 'strong');
|
||||
dialect.inline['**'] = inlineBuilder('**', 'strong');
|
||||
dialect.inline['*'] = inlineBuilder('*', 'em');
|
||||
dialect.inline['_'] = inlineBuilder('_', 'em');
|
||||
|
||||
|
||||
|
||||
// Support for simultaneous bold and italics
|
||||
Discourse.Dialect.inlineReplace({
|
||||
between: '***',
|
||||
wordBoundary: true,
|
||||
emitter: function(contents) { return ['strong', ['em'].concat(contents)]; }
|
||||
});
|
||||
|
||||
// Builds a common markdown replacer
|
||||
var replaceMarkdown = function(match, tag) {
|
||||
Discourse.Dialect.inlineReplace({
|
||||
between: match,
|
||||
wordBoundary: true,
|
||||
emitter: function(contents) { return [tag].concat(contents) }
|
||||
});
|
||||
};
|
||||
|
||||
replaceMarkdown('**', 'strong');
|
||||
replaceMarkdown('*', 'em');
|
||||
replaceMarkdown('_', 'em');
|
||||
|
||||
|
|
|
@ -43,51 +43,67 @@
|
|||
**/
|
||||
var parser = window.BetterMarkdown,
|
||||
MD = parser.Markdown,
|
||||
|
||||
// Our dialect
|
||||
dialect = MD.dialects.Discourse = MD.subclassDialect( MD.dialects.Gruber ),
|
||||
initialized = false;
|
||||
|
||||
initialized = false,
|
||||
/**
|
||||
Initialize our dialects for processing.
|
||||
|
||||
/**
|
||||
Initialize our dialects for processing.
|
||||
@method initializeDialects
|
||||
**/
|
||||
function initializeDialects() {
|
||||
Discourse.Dialect.trigger('register', {dialect: dialect, MD: MD});
|
||||
MD.buildBlockOrder(dialect.block);
|
||||
MD.buildInlinePatterns(dialect.inline);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@method initializeDialects
|
||||
**/
|
||||
initializeDialects = function() {
|
||||
Discourse.Dialect.trigger('register', {dialect: dialect, MD: MD});
|
||||
MD.buildBlockOrder(dialect.block);
|
||||
MD.buildInlinePatterns(dialect.inline);
|
||||
initialized = true;
|
||||
},
|
||||
/**
|
||||
Parse a JSON ML tree, using registered handlers to adjust it if necessary.
|
||||
|
||||
/**
|
||||
Parse a JSON ML tree, using registered handlers to adjust it if necessary.
|
||||
@method parseTree
|
||||
@param {Array} tree the JsonML tree to parse
|
||||
@param {Array} path the path of ancestors to the current node in the tree. Can be used for matching.
|
||||
@param {Object} insideCounts counts what tags we're inside
|
||||
@returns {Array} the parsed tree
|
||||
**/
|
||||
function parseTree(tree, path, insideCounts) {
|
||||
if (tree instanceof Array) {
|
||||
Discourse.Dialect.trigger('parseNode', {node: tree, path: path, dialect: dialect, insideCounts: insideCounts || {}});
|
||||
|
||||
@method parseTree
|
||||
@param {Array} tree the JsonML tree to parse
|
||||
@param {Array} path the path of ancestors to the current node in the tree. Can be used for matching.
|
||||
@param {Object} insideCounts counts what tags we're inside
|
||||
@returns {Array} the parsed tree
|
||||
**/
|
||||
parseTree = function parseTree(tree, path, insideCounts) {
|
||||
if (tree instanceof Array) {
|
||||
Discourse.Dialect.trigger('parseNode', {node: tree, path: path, dialect: dialect, insideCounts: insideCounts || {}});
|
||||
path = path || [];
|
||||
insideCounts = insideCounts || {};
|
||||
|
||||
path = path || [];
|
||||
insideCounts = insideCounts || {};
|
||||
path.push(tree);
|
||||
tree.slice(1).forEach(function (n) {
|
||||
var tagName = n[0];
|
||||
insideCounts[tagName] = (insideCounts[tagName] || 0) + 1;
|
||||
parseTree(n, path, insideCounts);
|
||||
insideCounts[tagName] = insideCounts[tagName] - 1;
|
||||
});
|
||||
path.pop();
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
path.push(tree);
|
||||
tree.slice(1).forEach(function (n) {
|
||||
var tagName = n[0];
|
||||
insideCounts[tagName] = (insideCounts[tagName] || 0) + 1;
|
||||
parseTree(n, path, insideCounts);
|
||||
insideCounts[tagName] = insideCounts[tagName] - 1;
|
||||
});
|
||||
path.pop();
|
||||
}
|
||||
return tree;
|
||||
};
|
||||
/**
|
||||
Returns true if there's an invalid word boundary for a match.
|
||||
|
||||
@method invalidBoundary
|
||||
@param {Object} args our arguments, including whether we care about boundaries
|
||||
@param {Array} prev the previous content, if exists
|
||||
@returns {Boolean} whether there is an invalid word boundary
|
||||
**/
|
||||
function invalidBoundary(args, prev) {
|
||||
|
||||
if (!args.wordBoundary && !args.spaceBoundary) { return; }
|
||||
|
||||
var last = prev[prev.length - 1];
|
||||
if (typeof last !== "string") { return; }
|
||||
|
||||
if (args.wordBoundary && (!last.match(/\W$/))) { return true; }
|
||||
if (args.spaceBoundary && (!last.match(/\s$/))) { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
An object used for rendering our dialects.
|
||||
|
@ -110,7 +126,51 @@ Discourse.Dialect = {
|
|||
dialect.options = opts;
|
||||
var tree = parser.toHTMLTree(text, 'Discourse');
|
||||
return parser.renderJsonML(parseTree(tree));
|
||||
},
|
||||
|
||||
inlineRegexp: function(args) {
|
||||
dialect.inline[args.start] = function(text, match, prev) {
|
||||
if (invalidBoundary(args, prev)) { return; }
|
||||
|
||||
args.matcher.lastIndex = 0;
|
||||
var m = args.matcher.exec(text);
|
||||
if (m) {
|
||||
var result = args.emitter.call(this, m);
|
||||
if (result) {
|
||||
return [m[0].length, result];
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
inlineReplace: function(args) {
|
||||
var start = args.start || args.between,
|
||||
stop = args.stop || args.between,
|
||||
startLength = start.length;
|
||||
|
||||
dialect.inline[start] = function(text, match, prev) {
|
||||
if (invalidBoundary(args, prev)) { return; }
|
||||
|
||||
var endPos = text.indexOf(stop, startLength);
|
||||
if (endPos === -1) { return; }
|
||||
|
||||
var between = text.slice(startLength, endPos);
|
||||
|
||||
// If rawcontents is set, don't process inline
|
||||
if (!args.rawContents) {
|
||||
between = this.processInline(between);
|
||||
}
|
||||
|
||||
var contents = args.emitter.call(this, between);
|
||||
if (contents) {
|
||||
return [endPos + startLength + 1, contents];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
RSVP.EventTarget.mixin(Discourse.Dialect);
|
||||
|
||||
|
||||
|
|
|
@ -2,47 +2,20 @@
|
|||
Supports Discourse's custom @mention syntax for calling out a user in a post.
|
||||
It will add a special class to them, and create a link if the user is found in a
|
||||
local map.
|
||||
|
||||
@event register
|
||||
@namespace Discourse.Dialect
|
||||
**/
|
||||
Discourse.Dialect.on("register", function(event) {
|
||||
Discourse.Dialect.inlineRegexp({
|
||||
start: '@',
|
||||
matcher: /^(@[A-Za-z0-9][A-Za-z0-9_]{2,14})/m,
|
||||
wordBoundary: true,
|
||||
|
||||
var dialect = event.dialect,
|
||||
MD = event.MD;
|
||||
emitter: function(matches) {
|
||||
var username = matches[1],
|
||||
mentionLookup = this.dialect.options.mentionLookup || Discourse.Mention.lookupCache;
|
||||
|
||||
/**
|
||||
Parses out @username mentions.
|
||||
|
||||
@method parseMentions
|
||||
@param {String} text the text match
|
||||
@param {Array} match the match found
|
||||
@param {Array} prev the previous jsonML
|
||||
@return {Array} an array containing how many chars we've replaced and the jsonML content for it.
|
||||
@namespace Discourse.Dialect
|
||||
**/
|
||||
dialect.inline['@'] = function parseMentions(text, match, prev) {
|
||||
|
||||
// We only care about mentions on word boundaries
|
||||
if (prev && (prev.length > 0)) {
|
||||
var last = prev[prev.length - 1];
|
||||
if (typeof last === "string" && (!last.match(/\W$/))) { return; }
|
||||
if (mentionLookup(username.substr(1))) {
|
||||
return ['a', {'class': 'mention', href: Discourse.getURL("/users/") + username.substr(1).toLowerCase()}, username];
|
||||
} else {
|
||||
return ['span', {'class': 'mention'}, username];
|
||||
}
|
||||
|
||||
var pattern = /^(@[A-Za-z0-9][A-Za-z0-9_]{2,14})(?=(\W|$))/m,
|
||||
m = pattern.exec(text);
|
||||
|
||||
if (m) {
|
||||
var username = m[1],
|
||||
mentionLookup = dialect.options.mentionLookup || Discourse.Mention.lookupCache;
|
||||
|
||||
if (mentionLookup(username.substr(1))) {
|
||||
return [username.length, ['a', {'class': 'mention', href: Discourse.getURL("/users/") + username.substr(1).toLowerCase()}, username]];
|
||||
} else {
|
||||
return [username.length, ['span', {'class': 'mention'}, username]];
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
});
|
|
@ -10,33 +10,28 @@ Discourse.Dialect.on("parseNode", function(event) {
|
|||
insideCounts = event.insideCounts,
|
||||
linebreaks = opts.traditional_markdown_linebreaks || Discourse.SiteSettings.traditional_markdown_linebreaks;
|
||||
|
||||
if (!linebreaks) {
|
||||
// We don't add line breaks inside a pre
|
||||
if (insideCounts.pre > 0) { return; }
|
||||
if (linebreaks || (insideCounts.pre > 0) || (node.length < 1)) { return; }
|
||||
|
||||
if (node.length > 1) {
|
||||
for (var j=1; j<node.length; j++) {
|
||||
var textContent = node[j];
|
||||
for (var j=1; j<node.length; j++) {
|
||||
var textContent = node[j];
|
||||
|
||||
if (typeof textContent === "string") {
|
||||
|
||||
if (textContent === "\n") {
|
||||
node[j] = ['br'];
|
||||
} else {
|
||||
var split = textContent.split(/\n+/);
|
||||
if (split.length) {
|
||||
var spliceInstructions = [j, 1];
|
||||
for (var i=0; i<split.length; i++) {
|
||||
if (split[i].length > 0) {
|
||||
spliceInstructions.push(split[i]);
|
||||
if (i !== split.length-1) { spliceInstructions.push(['br']); }
|
||||
}
|
||||
}
|
||||
node.splice.apply(node, spliceInstructions);
|
||||
if (typeof textContent === "string") {
|
||||
if (textContent === "\n") {
|
||||
node[j] = ['br'];
|
||||
} else {
|
||||
var split = textContent.split(/\n+/);
|
||||
if (split.length) {
|
||||
var spliceInstructions = [j, 1];
|
||||
for (var i=0; i<split.length; i++) {
|
||||
if (split[i].length > 0) {
|
||||
spliceInstructions.push(split[i]);
|
||||
if (i !== split.length-1) { spliceInstructions.push(['br']); }
|
||||
}
|
||||
}
|
||||
node.splice.apply(node, spliceInstructions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -17,6 +17,9 @@ test('basic bbcode', function() {
|
|||
format("[img]http://eviltrout.com/eviltrout.png[/img]", "<img src=\"http://eviltrout.com/eviltrout.png\"/>", "links images");
|
||||
format("[url]http://bettercallsaul.com[/url]", "<a href=\"http://bettercallsaul.com\">http://bettercallsaul.com</a>", "supports [url] without a title");
|
||||
format("[email]eviltrout@mailinator.com[/email]", "<a href=\"mailto:eviltrout@mailinator.com\">eviltrout@mailinator.com</a>", "supports [email] without a title");
|
||||
format("[b]evil [i]trout[/i][/b]",
|
||||
"<span class=\"bbcode-b\">evil <span class=\"bbcode-i\">trout</span></span>",
|
||||
"allows embedding of tags");
|
||||
});
|
||||
|
||||
test('lists', function() {
|
||||
|
@ -28,7 +31,7 @@ test('color', function() {
|
|||
format("[color=#00f]blue[/color]", "<span style=\"color: #00f\">blue</span>", "supports [color=] with a short hex value");
|
||||
format("[color=#ffff00]yellow[/color]", "<span style=\"color: #ffff00\">yellow</span>", "supports [color=] with a long hex value");
|
||||
format("[color=red]red[/color]", "<span style=\"color: red\">red</span>", "supports [color=] with an html color");
|
||||
format("[color=javascript:alert('wat')]noop[/color]", "noop", "it performs a noop on invalid input");
|
||||
format("[color=javascript:alert('wat')]noop[/color]", "<span>noop</span>", "it performs a noop on invalid input");
|
||||
});
|
||||
|
||||
test('tags with arguments', function() {
|
||||
|
|
Loading…
Reference in New Issue