Skip to content

Commit 0166a62

Browse files
authored
Merge pull request #1806 from codidact/0valt/1804/kbd
Allow <kbd> tags to be rendered in posts
2 parents ec377c3 + e8de9f9 commit 0166a62

File tree

8 files changed

+177
-92
lines changed

8 files changed

+177
-92
lines changed

app/assets/javascripts/posts.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
// IF YOU CHANGE THESE VALUES YOU MUST ALSO CHANGE app/helpers/posts_helper.rb
2-
const ALLOWED_TAGS = ['a', 'p', 'span', 'b', 'i', 'em', 'strong', 'hr', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
3-
'blockquote', 'img', 'strike', 'del', 'code', 'pre', 'br', 'ul', 'ol', 'li', 'sup', 'sub', 'section', 'details',
4-
'summary', 'ins', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 's'];
5-
const ALLOWED_ATTR = ['id', 'class', 'href', 'title', 'src', 'height', 'width', 'alt', 'rowspan', 'colspan', 'lang',
6-
'start', 'dir'];
71
// this is a list of constructors to ignore even if they are removed by sanitizer (mostly comments & body)
82
const IGNORE_UNSUPPORTED = [Comment, HTMLBodyElement];
93

@@ -269,8 +263,8 @@ $(() => {
269263
const converter = window.converter;
270264
const unsafe_html = converter.render(text);
271265
const html = DOMPurify.sanitize(unsafe_html, {
272-
ALLOWED_TAGS,
273-
ALLOWED_ATTR
266+
ALLOWED_TAGS: QPixel.ALLOWED_POST_TAGS,
267+
ALLOWED_ATTR: QPixel.ALLOWED_POST_ATTRS
274268
});
275269

276270
const removedElements = [...new Set(DOMPurify.removed

app/assets/stylesheets/application.scss

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,27 @@ mjx-container {
286286
overflow-x: auto;
287287
overflow-y: hidden;
288288
}
289+
290+
kbd {
291+
border: {
292+
color: $muted-graphic;
293+
radius: 0.25em;
294+
style: solid;
295+
width: 1px;
296+
};
297+
font: {
298+
family: $font-stack-code;
299+
size: map-get($font-sizes, 'xxs');
300+
};
301+
margin: {
302+
left: 0.15em;
303+
right: 0.15em;
304+
};
305+
padding: {
306+
top: 0.1em;
307+
bottom: 0.1em;
308+
left: 0.25em;
309+
right: 0.25em;
310+
};
311+
vertical-align: text-bottom;
312+
}

app/helpers/posts_helper.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,16 @@ def max_title_length(_category)
7777
end
7878

7979
class PostScrubber < Rails::Html::PermitScrubber
80+
ALLOWED_ATTRS = %w[id class href title src height width alt rowspan colspan lang start dir].freeze
81+
82+
ALLOWED_TAGS = %w[a p span b i em strong hr h1 h2 h3 h4 h5 h6 blockquote img
83+
strike del code pre br ul ol li sup sub kbd
84+
section details summary ins table thead tbody tr th td s].freeze
85+
8086
def initialize
8187
super
82-
# IF YOU CHANGE THESE VALUES YOU MUST ALSO CHANGE app/assets/javascripts/posts.js
83-
self.tags = %w[a p span b i em strong hr h1 h2 h3 h4 h5 h6 blockquote img strike del code pre br ul ol li sup sub
84-
section details summary ins table thead tbody tr th td s]
85-
self.attributes = %w[id class href title src height width alt rowspan colspan lang start dir]
88+
self.tags = ALLOWED_TAGS
89+
self.attributes = ALLOWED_ATTRS
8690
end
8791

8892
def skip_node?(node)

app/views/layouts/_head.html.erb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@
3535
<%= javascript_include_tag 'application' %>
3636
<script src="https://cdn.jsdelivr.net/npm/@codidact/co-design@latest/js/co-design.js" defer></script>
3737

38+
<script type="application/javascript">
39+
window.QPixel ||= {};
40+
41+
Object.defineProperty(QPixel, 'ALLOWED_POST_ATTRS', {
42+
configurable: false,
43+
value: Object.freeze(<%= raw PostsHelper::PostScrubber::ALLOWED_ATTRS %>),
44+
writable: false,
45+
});
46+
47+
Object.defineProperty(QPixel, 'ALLOWED_POST_TAGS', {
48+
configurable: false,
49+
value: Object.freeze(<%= raw PostsHelper::PostScrubber::ALLOWED_TAGS %>),
50+
writable: false,
51+
});
52+
</script>
53+
3854
<% if SiteSetting['SyntaxHighlightingEnabled'] %>
3955
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.0.1/styles/default.min.css">
4056
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.0.1/highlight.min.js"></script>

app/views/posts/_form.html.erb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
post : a Post instance to work on (either via .new or .find - doesn't matter if it has content or not)
66
submit_path : the URL to submit the form to (must accept POST requests)
77
post_type : a PostType instance describing the requested post type
8-
category : a Category instance, required if the post type has a category, indicating which category to post in
9-
parent : a Post instance containing the parent for this post (required if the post type has a parent)
10-
inline_parent : optional, default true: display an inline copy of the parent? (if present)
11-
type_summary : optional, default true: display a summary of the requested post type?
12-
edit_comment : optional, default false: include a field for an edit comment?
8+
? category : a Category instance, required if the post type has a category, indicating which category to post in
9+
? parent : a Post instance containing the parent for this post (required if the post type has a parent)
10+
? inline_parent : optional, default true: display an inline copy of the parent? (if present)
11+
? type_summary : optional, default true: display a summary of the requested post type?
12+
? edit_comment : optional, default false: include a field for an edit comment?
1313
"%>
1414

1515
<%

db/seeds.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ def ensure_system_user_abilities
9292
end
9393

9494
if type == Post && ENV['UPDATE_POSTS'] == 'true'
95-
puts "Running full Posts update..."
96-
9795
seed['body'] = ApplicationController.helpers.render_markdown(seed['body_markdown'])
9896

9997
system_usr = User.find(-1)
Lines changed: 111 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,124 @@
1-
<p
2-
>Posts on Codidact, including questions, answers, articles, tag wikis, help pages, and user
3-
profiles, support the use of the following HTML tags:</p
4-
>
1+
<p>
2+
Posts, including questions, answers, articles, tag wikis, help pages, and user profiles, support the use of the
3+
following HTML tags:
4+
</p>
55
<ul>
6-
<li><code>a</code></li>
7-
<li><code>p</code></li>
8-
<li><code>span</code></li>
9-
<li><code>b</code></li>
10-
<li><code>i</code></li>
11-
<li><code>em</code></li>
12-
<li><code>s</code></li>
13-
<li><code>strong</code></li>
14-
<li><code>hr</code></li>
15-
<li
16-
><code>h1</code>, <code>h2</code>, <code>h3</code>, <code>h4</code>, <code>h5</code>,
17-
<code>h6</code></li
18-
>
19-
<li><code>blockquote</code></li>
20-
<li><code>img</code></li>
21-
<li><code>strike</code></li>
22-
<li><code>del</code>, <code>ins</code></li>
23-
<li><code>code</code></li>
24-
<li><code>pre</code></li>
25-
<li><code>br</code></li>
26-
<li><code>ul</code>, <code>ol</code>, <code>li</code></li>
27-
<li><code>sup</code>, <code>sub</code></li>
28-
<li><code>section</code></li>
29-
<li><code>details</code>, <code>summary</code></li>
30-
<li
31-
><code>table</code>, <code>thead</code>, <code>tbody</code>, <code>tr</code>,
32-
<code>th</code>, <code>td</code></li
33-
>
6+
<li><code>a</code></li>
7+
<li><code>p</code></li>
8+
<li><code>span</code></li>
9+
<li><code>b</code></li>
10+
<li><code>i</code></li>
11+
<li><code>em</code></li>
12+
<li><code>s</code></li>
13+
<li><code>strong</code></li>
14+
<li><code>hr</code></li>
15+
<li>
16+
<code>h1</code>
17+
,
18+
<code>h2</code>
19+
,
20+
<code>h3</code>
21+
,
22+
<code>h4</code>
23+
,
24+
<code>h5</code>
25+
,
26+
<code>h6</code>
27+
</li>
28+
<li><code>blockquote</code></li>
29+
<li><code>img</code></li>
30+
<li><code>strike</code></li>
31+
<li>
32+
<code>del</code>
33+
,
34+
<code>ins</code>
35+
</li>
36+
<li><code>code</code></li>
37+
<li><code>kbd</code></li>
38+
<li><code>pre</code></li>
39+
<li><code>br</code></li>
40+
<li>
41+
<code>ul</code>
42+
,
43+
<code>ol</code>
44+
,
45+
<code>li</code>
46+
</li>
47+
<li>
48+
<code>sup</code>
49+
,
50+
<code>sub</code>
51+
</li>
52+
<li><code>section</code></li>
53+
<li>
54+
<code>details</code>
55+
,
56+
<code>summary</code>
57+
</li>
58+
<li>
59+
<code>table</code>
60+
,
61+
<code>thead</code>
62+
,
63+
<code>tbody</code>
64+
,
65+
<code>tr</code>
66+
,
67+
<code>th</code>
68+
,
69+
<code>td</code>
70+
</li>
3471
</ul>
3572
<p>These tags may have the following attributes:</p>
3673
<ul>
37-
<li><code>id</code></li>
38-
<li><code>class</code></li>
39-
<li><code>href</code></li>
40-
<li><code>title</code></li>
41-
<li><code>src</code></li>
42-
<li><code>height</code></li>
43-
<li><code>width</code></li>
44-
<li><code>alt</code></li>
45-
<li><code>dir</code></li>
46-
<li><code>lang</code></li>
47-
<li><code>start</code></li>
48-
<li><code>rowspan</code></li>
49-
<li><code>colspan</code></li>
74+
<li><code>id</code></li>
75+
<li><code>class</code></li>
76+
<li><code>href</code></li>
77+
<li><code>title</code></li>
78+
<li><code>src</code></li>
79+
<li><code>height</code></li>
80+
<li><code>width</code></li>
81+
<li><code>alt</code></li>
82+
<li><code>dir</code></li>
83+
<li><code>lang</code></li>
84+
<li><code>start</code></li>
85+
<li><code>rowspan</code></li>
86+
<li><code>colspan</code></li>
5087
</ul>
5188
<p>Shorter text forms, such as comments, support the following HTML tags:</p>
5289
<ul>
53-
<li><code>a</code></li>
54-
<li><code>b</code></li>
55-
<li><code>i</code></li>
56-
<li><code>em</code></li>
57-
<li><code>strong</code></li>
58-
<li><code>strike</code></li>
59-
<li><code>del</code></li>
60-
<li><code>code</code></li>
90+
<li><code>a</code></li>
91+
<li><code>b</code></li>
92+
<li><code>i</code></li>
93+
<li><code>em</code></li>
94+
<li><code>strong</code></li>
95+
<li><code>strike</code></li>
96+
<li><code>del</code></li>
97+
<li><code>code</code></li>
6198
</ul>
6299
<p>These tags may have the following attributes:</p>
63100
<ul>
64-
<li><code>href</code></li>
65-
<li><code>title</code></li>
101+
<li><code>href</code></li>
102+
<li><code>title</code></li>
66103
</ul>
67104
<hr />
68-
<p
69-
>HTML tags that do not appear on this list will be stripped out and not displayed if they are
70-
included in posts or comments. The source code for supported tags in posts can be found in
71-
<a href="https://github.com/codidact/qpixel/blob/develop/app/helpers/posts_helper.rb#L46"
72-
><code>posts_helper.rb</code></a
73-
>, and for comments in
74-
<a href="https://github.com/codidact/qpixel/blob/develop/app/helpers/comments_helper.rb#L81"
75-
><code>comments_helper.rb</code></a
76-
>.</p
77-
>
105+
<p>
106+
HTML tags not on this list will be stripped out and not displayed if they are included in posts or comments. The
107+
source code for supported tags in posts can be found in
108+
<a href="https://github.com/codidact/qpixel/blob/develop/app/helpers/posts_helper.rb#L79">
109+
<code>posts_helper.rb</code>
110+
</a>
111+
, and for comments in
112+
<a href="https://github.com/codidact/qpixel/blob/develop/app/helpers/comments_helper.rb#L195">
113+
<code>comments_helper.rb</code>
114+
</a>
115+
.
116+
</p>
78117
<hr />
79-
<p
80-
><sub
81-
>Much of the content of this page came from
82-
<a href="https://meta.codidact.com/posts/277420/277424#answer-277424"
83-
>this answer by luap42</a
84-
>.</sub
85-
></p
86-
>
118+
<p>
119+
<sub>
120+
Much of the content of this page came from
121+
<a href="https://meta.codidact.com/posts/277420/277424#answer-277424">this answer by luap42</a>
122+
.
123+
</sub>
124+
</p>

global.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,17 @@ interface GetThreadContentOptions {
263263
}
264264

265265
interface QPixel {
266+
// constants
267+
268+
/**
269+
* List of HTML tags allowed in posts, supplied by the server
270+
*/
271+
readonly ALLOWED_POST_TAGS?: readonly string[]
272+
/**
273+
* List of attributes allowed on HTML tags in posts, supplied by the server
274+
*/
275+
readonly ALLOWED_POST_ATTRS?: readonly string[]
276+
266277
// private properties
267278
_filters?: QPixelFlag[] | null;
268279
_pendingUserResponse?: Promise<Response> | null;

0 commit comments

Comments
 (0)