parser: Add spoiler syntax, and fix regexes for other inline extensions

This commit is contained in:
Starbeamrainbowlabs 2020-05-23 20:38:01 +01:00
parent 764680b3c3
commit 48567a96a8
Signed by: sbrl
GPG Key ID: 1BE5172E637709C2
4 changed files with 84 additions and 4 deletions

View File

@ -389,6 +389,8 @@ register_module([
<tr><td><code>Some text ==marked text== more text</code></td><td>Some text <mark>marked text</mark> more text</td><td>Marked / highlighted text</td></tr>
<tr><td><code>[ ] Unticked checkbox</code></td><td>An unticked checkbox. Must be at the beginning of a line or directly after a list item (e.g. <code> - </code> or <code>1. </code>).</td></tr>
<tr><td><code>[x] Ticked checkbox</code></td><td>An ticked checkbox. The same rules as unticked checkboxes apply here too.</td></tr>
<tr><td><code>some text &gt;!spoiler text!&lt; more text</code></td><td>A spoiler. Users much click it to reveal the content hidden beneath.</td></tr>
<tr><td><code>some text ||spoiler text|| more text</code></td><td>Alternative spoiler syntax inspired by <a href='https://support.discord.com/hc/en-us/articles/360022320632-Spoiler-Tags-'>Discord</a>.</td></tr>
</table>
<p>Note that the all image image syntax above can be mixed and matched to your liking. The <code>caption</code> option in particular must come last or next to last.</p>
<h4>Templating</h4>
@ -506,6 +508,9 @@ class PeppermintParsedown extends ParsedownExtra
$this->addInlineType("=", "Mark");
$this->addInlineType("^", "Superscript");
$this->addInlineType("~", "Subscript");
$this->addInlineType(">", "Spoiler", true);
$this->addInlineType("|", "Spoiler", true);
}
/**
@ -783,7 +788,9 @@ class PeppermintParsedown extends ParsedownExtra
* ██ ███████ ██ ██ ██
*/
protected function inlineMark($fragment) {
if(preg_match('/==([^=]+)==/', $fragment["text"], $matches) !== 1)
// A question mark makes the PCRE 1-or-more + there lazy instead of greedy.
// Ref https://www.rexegg.com/regex-quantifiers.html#greedytrap
if(preg_match('/==([^=]+?)==/', $fragment["text"], $matches) !== 1)
return;
$marked_text = $matches[1];
@ -817,7 +824,7 @@ class PeppermintParsedown extends ParsedownExtra
* ██████ ██████ ██ ██ ██ ██ ██
*/
protected function inlineSuperscript($fragment) {
if(preg_match('/\^([^^]+)\^/', $fragment["text"], $matches) !== 1)
if(preg_match('/\^([^^]+?)\^/', $fragment["text"], $matches) !== 1)
return;
$superscript_text = $matches[1];
@ -836,7 +843,7 @@ class PeppermintParsedown extends ParsedownExtra
return $result;
}
protected function inlineSubscript($fragment) {
if(preg_match('/~([^~]+)~/', $fragment["text"], $matches) !== 1)
if(preg_match('/~([^~]+?)~/', $fragment["text"], $matches) !== 1)
return;
$subscript_text = $matches[1];
@ -855,6 +862,41 @@ class PeppermintParsedown extends ParsedownExtra
return $result;
}
/*
* ███████ ██████ ██████ ██ ██ ███████ ██████
* ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
* ███████ ██████ ██ ██ ██ ██ █████ ██████
* ██ ██ ██ ██ ██ ██ ██ ██ ██
* ███████ ██ ██████ ██ ███████ ███████ ██ ██
*/
protected function inlineSpoiler($fragment) {
if(preg_match('/(?:\|\||>!)([^|]+?)(?:\|\||!<)/', $fragment["text"], $matches) !== 1)
return;
$spoiler_text = $matches[1];
$id = "spoiler-".crypto_id(24);
$result = [
"extent" => strlen($matches[0]),
"element" => [
"name" => "a",
"attributes" => [
"id" => $id,
"class" => "spoiler",
"href" => "#$id"
],
"handler" => [
"function" => "lineElements",
"argument" => $spoiler_text,
"destination" => "elements"
]
]
];
return $result;
}
/*
* ██ ███ ██ ████████ ███████ ██████ ███ ██ █████ ██
* ██ ████ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██

View File

@ -227,6 +227,19 @@ a.redlink:link{
a.redlink:visited{
color:rgb(130, 15, 15);
}
.spoiler { background: #333333; border-radius: 0.2em; color: transparent; }
.spoiler:target { background: transparent; color: inherit; }
/* Ref https://devdocs.io/html/element/del#Accessibility_concerns it's better than nothing, but I'm not happy with it. How would a screen reader user skipt he spsoiler if they don't want to hear it? */
.spoiler::before, .spoiler::after {
clip-path: inset(100%); clip: rect(1px, 1px, 1px, 1px);
position: absolute; width: 1px; height: 1px;
overflow: hidden; white-space: nowrap;
}
.spoiler::before { content: " [spoiler start] "; }
.spoiler::after { content: " [spoiler end] "; }
.matching-tags-display{
display:flex;
margin:0 -2em;

View File

@ -182,6 +182,19 @@ a.interwiki_link { color: var(--accent-d1); }
a.interwiki_link:visited { color: var(--accent-d2); }
a.interwiki_link:active { color: var(--accent-d3); }
.spoiler { background: var(--accent-a2); border: 0.1em dashed var(--accent-b1); border-radius: 0.2em; color: transparent !important; text-decoration: none; }
.spoiler:target { color: inherit !important; }
/* Ref https://devdocs.io/html/element/del#Accessibility_concerns it's better than nothing, but I'm not happy with it. How would a screen reader user skipt he spsoiler if they don't want to hear it? */
.spoiler::before, .spoiler::after {
clip-path: inset(100%); clip: rect(1px, 1px, 1px, 1px);
position: absolute; width: 1px; height: 1px;
overflow: hidden; white-space: nowrap;
}
.spoiler::before { content: " [spoiler start] "; }
.spoiler::after { content: " [spoiler end] "; }
.matching-tags-display { display: flex; margin: 0 -2em; padding: 1em 2em; background: hsla(30, 84%, 72%, 0.75); }
.matching-tags-display > label { flex: 0; font-weight: bold; color: var(--accent-a3); }
.matching-tags-display > .tags { flex: 2; }
@ -194,7 +207,7 @@ a.interwiki_link:active { color: var(--accent-d3); }
.search-context { min-height: 3em; max-height: 20em; overflow: hidden; }
.editform { position: relative; }
textarea[name=content] { resize: none; }
textarea[name=content] { resize: none; min-height: 75vh; }
.fit-text-mirror { position: absolute; top: 0; left: -10000vw; word-wrap: break-word; white-space: pre-wrap; }
.awesomplete { width: 100%; color: var(--text-dark); }

View File

@ -113,6 +113,18 @@ th, td { padding: 0.25em 0.45em; }
pre, code, input, textarea { font-size: 1rem; }
img, video, audio { max-width: 100%; }
.spoiler { background: #333333; border-radius: 0.2em; color: transparent; }
.spoiler:target { background: transparent; color: inherit; }
/* Ref https://devdocs.io/html/element/del#Accessibility_concerns it's better than nothing, but I'm not happy with it. How would a screen reader user skipt he spsoiler if they don't want to hear it? */
.spoiler::before, .spoiler::after {
clip-path: inset(100%); clip: rect(1px, 1px, 1px, 1px);
position: absolute; width: 1px; height: 1px;
overflow: hidden; white-space: nowrap;
}
.spoiler::before { content: " [spoiler start] "; }
.spoiler::after { content: " [spoiler end] "; }
main label { font-weight: bold; display: inline-block; min-width: 12em; }
textarea { min-height: 10em; }