quoting fixes

- allow bbcode quotes to be nested
- don't allow the '=' to be omitted from quotes
- fix some css that made assumptions about nested quotes
This commit is contained in:
Ben Lubar 2014-05-27 21:46:31 -05:00
parent f6753d3d46
commit 73946e5402
5 changed files with 64 additions and 29 deletions

View File

@ -105,6 +105,7 @@ replaceBBCodeParams("size", function(param, contents) {
Discourse.Dialect.replaceBlock({
start: /(\[code\])([\s\S]*)/igm,
stop: '[/code]',
rawContents: true,
emitter: function(blockContents) {
return ['p', ['pre'].concat(blockContents.join("\n"))];

View File

@ -305,6 +305,7 @@ Discourse.Dialect = {
Discourse.Dialect.replaceBlock({
start: /(\[code\])([\s\S]*)/igm,
stop: '[/code]',
rawContents: true,
emitter: function(blockContents) {
return ['p', ['pre'].concat(blockContents)];
@ -314,9 +315,10 @@ Discourse.Dialect = {
@method replaceBlock
@param {Object} args Our replacement options
@param {String} [opts.start] The starting regexp we want to find
@param {String} [opts.stop] The ending token we want to find
@param {Function} [opts.emitter] The emitting function to transform the contents of the block into jsonML
@param {RegExp} [args.start] The starting regexp we want to find
@param {String} [args.stop] The ending token we want to find
@param {Boolean} [args.rawContents] True to skip recursive processing
@param {Function} [args.emitter] The emitting function to transform the contents of the block into jsonML
**/
replaceBlock: function(args) {
@ -327,7 +329,7 @@ Discourse.Dialect = {
if (!m) { return; }
var startPos = block.indexOf(m[0]),
var startPos = args.start.lastIndex - m[0].length,
leading,
blockContents = [],
result = [],
@ -351,14 +353,11 @@ Discourse.Dialect = {
lineNumber++;
var blockClosed = false;
if (next.length > 0) {
for (var i=0; i<next.length; i++) {
if (next[i].indexOf(args.stop) >= 0) {
blockClosed = true;
break;
}
for (var i=0; i<next.length; i++) {
if (next[i].indexOf(args.stop) >= 0) {
blockClosed = true;
break;
}
}
@ -367,33 +366,52 @@ Discourse.Dialect = {
return;
}
var numOpen = 1;
while (next.length > 0) {
var b = next.shift(),
blockLine = b.lineNumber,
diff = ((typeof blockLine === "undefined") ? lineNumber : blockLine) - lineNumber,
endFound = b.indexOf(args.stop),
leadingContents = b.slice(0, endFound),
trailingContents = b.slice(endFound+args.stop.length);
trailingContents = b.slice(endFound+args.stop.length),
m2;
if (endFound >= 0) { blockClosed = true; }
if (endFound === -1) {
leadingContents = b;
}
args.start.lastIndex = 0;
if (m2 = (args.start).exec(leadingContents)) {
numOpen++;
args.start.lastIndex -= m2[0].length - 1;
while (m2 = (args.start).exec(leadingContents)) {
numOpen++;
args.start.lastIndex -= m2[0].length - 1;
}
}
if (endFound >= 0) { numOpen--; }
for (var j=1; j<diff; j++) {
blockContents.push("");
}
lineNumber = blockLine + b.split("\n").length - 1;
if (endFound !== -1) {
if (endFound >= 0) {
if (trailingContents) {
next.unshift(MD.mk_block(trailingContents.replace(/^\s+/, "")));
}
blockContents.push(leadingContents.replace(/\s+$/, ""));
break;
if (numOpen === 0) {
break;
}
blockContents.push(args.stop);
} else {
blockContents.push(b);
}
}
var emitterResult = args.emitter.call(this, blockContents, m, dialect.options);
if (emitterResult) {
result.push(emitterResult);

View File

@ -5,16 +5,16 @@
var esc = Handlebars.Utils.escapeExpression;
Discourse.Dialect.replaceBlock({
start: new RegExp("\\[quote=?([^\\[\\]]+)?\\]([\\s\\S]*)", "igm"),
start: new RegExp("\\[quote(=[^\\[\\]]+)?\\]([\\s\\S]*)", "igm"),
stop: '[/quote]',
emitter: function(blockContents, matches, options) {
var params = {'class': 'quote'},
username;
username = null;
if (matches[1]) {
var paramsString = matches[1].replace(/\"/g, ''),
paramsSplit = paramsString.split(/\, */);
var paramsString = matches[1].replace(/^=|\"/g, ''),
paramsSplit = paramsString.split(/\,\s*/);
username = paramsSplit[0];
@ -38,25 +38,37 @@ Discourse.Dialect.replaceBlock({
avatarImg = options.lookupAvatar(username);
}
while (blockContents.length && (typeof blockContents[0] === "string" || blockContents[0] instanceof String)) {
blockContents[0] = String(blockContents[0]).replace(/^\s+/, '');
if (!blockContents[0].length) {
blockContents.shift();
} else {
break;
}
}
var contents = ['blockquote'];
if (blockContents.length) {
var self = this;
if (blockContents && (typeof blockContents[0] === "string")) {
blockContents[0] = blockContents[0].replace(/^[\s]*/, '');
}
var nextContents = blockContents.slice(1);
blockContents = this.processBlock(blockContents[0], nextContents).concat(nextContents);
blockContents.forEach(function (bc) {
var processed = self.processInline(bc);
if (processed.length) {
contents.push(['p'].concat(processed));
if (typeof bc === "string" || bc instanceof String) {
var processed = self.processInline(String(bc));
if (processed.length) {
contents.push(['p'].concat(processed));
}
} else {
contents.push(bc);
}
});
}
// If there's no username just return a simple quote
if (!username) {
return ['p', ['aside', params, contents ]];
return ['p', ['aside', params, contents]];
}
return ['p', ['aside', params,

View File

@ -686,7 +686,7 @@ blockquote { /* solo quotes */
}
.quote { /* quotes with attribution */
blockquote {
&>blockquote {
margin-top: 0;
padding-top: 0;
p:first-of-type {margin:0;}
@ -708,6 +708,10 @@ blockquote { /* solo quotes */
background: darken(scale-color-diff(), 5%);
border-left: 5px solid darken(scale-color-diff(), 12%);
}
aside.quote>blockquote, aside.quote>.title {
border-left: 0;
}
}
}

View File

@ -99,7 +99,7 @@ test("quotes", function() {
"<aside class=\"quote\"><blockquote><p><em>test</em></p></blockquote></aside>",
"it doesn't insert a new line for italics");
format("[quote,script='a'><script>alert('test');//':a][/quote]",
format("[quote=,script='a'><script>alert('test');//':a][/quote]",
"<aside class=\"quote\" data-script=&#x27;a&#x27;&gt;&lt;script&gt;alert(&#x27;test&#x27;);//&#x27;=\"a\"><blockquote></blockquote></aside>",
"It will not create a script tag within an attribute");
});