diff --git a/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js b/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js index 995d96cef96..5d8bd8ff49b 100644 --- a/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js +++ b/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js @@ -664,13 +664,13 @@ eviltrout
assert.cooked( "># #category-hashtag\n", - '\n', + '#category-hashtag
\n
\n', "it handles category hashtags in simple quotes" ); assert.cooked( "# #category-hashtag", - '#category-hashtag
\n
b
\nc\n',
+ 'b
\nc\n',
"it handles headings with code blocks after them."
);
});
diff --git a/app/assets/javascripts/pretty-text/addon/allow-lister.js b/app/assets/javascripts/pretty-text/addon/allow-lister.js
index ab4fee7e798..698f64c5d73 100644
--- a/app/assets/javascripts/pretty-text/addon/allow-lister.js
+++ b/app/assets/javascripts/pretty-text/addon/allow-lister.js
@@ -130,6 +130,7 @@ export default class AllowLister {
// Only add to `default` when you always want your allowlist to occur. In other words,
// don't change this for a plugin or a feature that can be disabled
export const DEFAULT_LIST = [
+ "a.anchor",
"a.attachment",
"a.hashtag",
"a.mention",
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/anchor.js b/app/assets/javascripts/pretty-text/engines/discourse-markdown/anchor.js
new file mode 100644
index 00000000000..37924d263f8
--- /dev/null
+++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/anchor.js
@@ -0,0 +1,29 @@
+export function setup(helper) {
+ helper.registerPlugin((md) => {
+ md.core.ruler.push("anchor", (state) => {
+ for (let idx = 0; idx < state.tokens.length; idx++) {
+ if (state.tokens[idx].type !== "heading_open") {
+ continue;
+ }
+
+ const linkOpen = new state.Token("link_open", "a", 1);
+ const linkClose = new state.Token("link_close", "a", -1);
+
+ const slug = state.tokens[idx + 1].content
+ .toLowerCase()
+ .replace(/\s+/g, "-")
+ .replace(/[^\w\-]+/g, "")
+ .replace(/\-\-+/g, "-")
+ .replace(/^-+/, "")
+ .replace(/-+$/, "");
+
+ linkOpen.attrSet("name", slug);
+ linkOpen.attrSet("class", "anchor");
+ linkOpen.attrSet("href", "#" + slug);
+
+ state.tokens[idx + 1].children.unshift(linkClose);
+ state.tokens[idx + 1].children.unshift(linkOpen);
+ }
+ });
+ });
+}
diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss
index cbf07b9ee3d..0bd40e0f582 100644
--- a/app/assets/stylesheets/common/base/topic-post.scss
+++ b/app/assets/stylesheets/common/base/topic-post.scss
@@ -94,6 +94,20 @@ $quote-share-maxwidth: 150px;
h6 {
margin: 30px 0 10px;
line-height: $line-height-medium;
+
+ &:hover {
+ a.anchor {
+ &:before {
+ content: svg-uri(
+ ''
+ );
+ float: left;
+ margin-left: -20px;
+ padding-right: 4px;
+ position: absolute;
+ }
+ }
+ }
}
h1 {
diff --git a/plugins/poll/spec/lib/pretty_text_spec.rb b/plugins/poll/spec/lib/pretty_text_spec.rb
index d887b10e753..c5b25e09a93 100644
--- a/plugins/poll/spec/lib/pretty_text_spec.rb
+++ b/plugins/poll/spec/lib/pretty_text_spec.rb
@@ -189,8 +189,8 @@ describe PrettyText do
HTML
- expect(cooked).to include("\n", "") html.gsub!("
\n", "")