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:
parent
f6753d3d46
commit
73946e5402
|
@ -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"))];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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='a'><script>alert('test');//'=\"a\"><blockquote></blockquote></aside>",
|
||||
"It will not create a script tag within an attribute");
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue