FEATURE: generic theme component bbcode wrapper (#7400)
Usage: ``` [wrap=name foo=bar] hello world [/wrap] ```
This commit is contained in:
parent
e8f51815e5
commit
7334362b77
|
@ -16,3 +16,4 @@
|
|||
//= require ./pretty-text/engines/discourse-markdown/text-post-process
|
||||
//= require ./pretty-text/engines/discourse-markdown/image-protocol
|
||||
//= require ./pretty-text/engines/discourse-markdown/inject-line-number
|
||||
//= require ./pretty-text/engines/discourse-markdown/d-wrap
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import { parseBBCodeTag } from "pretty-text/engines/discourse-markdown/bbcode-block";
|
||||
|
||||
const WRAP_CLASS = "d-wrap";
|
||||
|
||||
function parseAttributes(tagInfo) {
|
||||
const attributes = tagInfo.attrs._default || "";
|
||||
|
||||
return (
|
||||
parseBBCodeTag(`[wrap wrap=${attributes}]`, 0, attributes.length + 12)
|
||||
.attrs || {}
|
||||
);
|
||||
}
|
||||
|
||||
function applyDataAttributes(token, state, attributes) {
|
||||
Object.keys(attributes).forEach(tag => {
|
||||
const value = state.md.utils.escapeHtml(attributes[tag]);
|
||||
tag = state.md.utils.escapeHtml(tag.replace(/[^a-z0-9\-]/g, ""));
|
||||
|
||||
if (value && tag && tag.length > 1) {
|
||||
token.attrs.push([`data-${tag}`, value]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const blockRule = {
|
||||
tag: "wrap",
|
||||
|
||||
before(state, tagInfo) {
|
||||
let token = state.push("wrap_open", "div", 1);
|
||||
token.attrs = [["class", WRAP_CLASS]];
|
||||
|
||||
applyDataAttributes(token, state, parseAttributes(tagInfo));
|
||||
},
|
||||
|
||||
after(state) {
|
||||
state.push("wrap_close", "div", -1);
|
||||
}
|
||||
};
|
||||
|
||||
const inlineRule = {
|
||||
tag: "wrap",
|
||||
|
||||
replace(state, tagInfo, content) {
|
||||
let token = state.push("wrap_open", "span", 1);
|
||||
token.attrs = [["class", WRAP_CLASS]];
|
||||
|
||||
applyDataAttributes(token, state, parseAttributes(tagInfo));
|
||||
|
||||
if (content) {
|
||||
token = state.push("text", "", 0);
|
||||
token.content = content;
|
||||
}
|
||||
|
||||
token = state.push("wrap_close", "span", -1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
export function setup(helper) {
|
||||
helper.registerPlugin(md => {
|
||||
md.inline.bbcode.ruler.push("inline-wrap", inlineRule);
|
||||
md.block.bbcode.ruler.push("block-wrap", blockRule);
|
||||
});
|
||||
|
||||
helper.whiteList([`div.${WRAP_CLASS}`, `span.${WRAP_CLASS}`, "span[data-*]"]);
|
||||
}
|
|
@ -1325,4 +1325,94 @@ HTML
|
|||
expect(cooked).to eq(html)
|
||||
end
|
||||
|
||||
describe "d-wrap" do
|
||||
it "wraps the [wrap] tag inline" do
|
||||
cooked = PrettyText.cook("[wrap=toc]taco[/wrap]")
|
||||
|
||||
html = <<~HTML
|
||||
<div class="d-wrap" data-wrap="toc">
|
||||
<p>taco</p>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
expect(cooked).to eq(html.strip)
|
||||
|
||||
cooked = PrettyText.cook("Hello [wrap=toc id=1]taco[/wrap] world")
|
||||
|
||||
html = <<~HTML
|
||||
<p>Hello <span class="d-wrap" data-wrap="toc" data-id="1">taco</span> world</p>
|
||||
HTML
|
||||
|
||||
expect(cooked).to eq(html.strip)
|
||||
end
|
||||
|
||||
it "wraps the [wrap] tag in block" do
|
||||
md = <<~MD
|
||||
[wrap=toc]
|
||||
taco
|
||||
[/wrap]
|
||||
MD
|
||||
|
||||
cooked = PrettyText.cook(md)
|
||||
|
||||
html = <<~HTML
|
||||
<div class="d-wrap" data-wrap="toc">
|
||||
<p>taco</p>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
expect(cooked).to eq(html.strip)
|
||||
end
|
||||
|
||||
it "wraps the [wrap] tag without content" do
|
||||
md = <<~MD
|
||||
[wrap=toc]
|
||||
[/wrap]
|
||||
MD
|
||||
|
||||
cooked = PrettyText.cook(md)
|
||||
|
||||
html = <<~HTML
|
||||
<div class="d-wrap" data-wrap="toc"></div>
|
||||
HTML
|
||||
|
||||
expect(cooked).to eq(html.strip)
|
||||
end
|
||||
|
||||
it "adds attributes as data-attributes" do
|
||||
cooked = PrettyText.cook("[wrap=toc name=\"pepper bell\" id=1]taco[/wrap]")
|
||||
|
||||
html = <<~HTML
|
||||
<div class="d-wrap" data-wrap="toc" data-name="pepper bell" data-id="1">
|
||||
<p>taco</p>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
expect(cooked).to eq(html.strip)
|
||||
end
|
||||
|
||||
it "prevents xss" do
|
||||
cooked = PrettyText.cook('[wrap=toc foo="<script>console.log(1)</script>"]taco[/wrap]')
|
||||
|
||||
html = <<~HTML
|
||||
<div class="d-wrap" data-wrap="toc" data-foo="&lt;script&gt;console.log(1)&lt;/script&gt;">
|
||||
<p>taco</p>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
expect(cooked).to eq(html.strip)
|
||||
end
|
||||
|
||||
it "allows a limited set of attributes chars" do
|
||||
cooked = PrettyText.cook('[wrap=toc fo@"èk-"!io=bar]taco[/wrap]')
|
||||
|
||||
html = <<~HTML
|
||||
<div class=\"d-wrap\" data-wrap=\"toc\" data-io=\"bar\">
|
||||
<p>taco</p>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
expect(cooked).to eq(html.strip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue