Merge branch 'tinyMDE'

Markdown UI via tinyMDE and Markdown render, Plus youtube embedding
This commit is contained in:
sørenpeter 2024-11-30 18:30:14 +01:00
commit eca76165db
11 changed files with 2318 additions and 324 deletions

1994
libs/Parsedown.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,155 +0,0 @@
<?php
/**
* Slimdown - A simple regex-based Markdown parser in PHP. Supports the
* following elements (and can be extended via `Slimdown::add_rule()`):
*
* - Headers
* - Links
* - Bold
* - Emphasis
* - Deletions
* - Quotes
* - Code blocks
* - Inline code
* - Blockquotes
* - Ordered/unordered lists
* - Horizontal rules
* - Images
*
* Author: Johnny Broadway <johnny@johnnybroadway.com>
* Website: https://github.com/jbroadway/slimdown
* License: MIT
*/
class Slimdown {
public static $rules = array (
'/```(.*?)```/s' => self::class .'::code_parse', // code blocks
'/\n(#+)\s+(.*)/' => self::class .'::header', // headers
'/\!\[([^\[]*?)\]\(([^\)]+)\)/' => self::class .'::img', // images
'/\[([^\[]+)\]\(([^\)]+)\)/' => self::class .'::link', // links
'/(\*\*|__)(?=(?:(?:[^`]*`[^`\r\n]*`)*[^`]*$))(?![^\/<]*>.*<\/.+>)(.*?)\1/' => '<strong>\2</strong>', // bold
'/(\*|_)(?=(?:(?:[^`]*`[^`\r\n]*`)*[^`]*$))(?![^\/<]*>.*<\/.+>)(.*?)\1/' => '<em>\2</em>', // emphasis
'/(\~\~)(?=(?:(?:[^`]*`[^`\r\n]*`)*[^`]*$))(?![^\/<]*>.*<\/.+>)(.*?)\1/' => '<del>\2</del>', // del
'/\:\"(.*?)\"\:/' => '<q>\1</q>', // quote
'/`(.*?)`/' => '<code>\1</code>', // inline code
'/\n\*(.*)/' => self::class .'::ul_list', // ul lists
'/\n[0-9]+\.(.*)/' => self::class .'::ol_list', // ol lists
'/\n(&gt;|\>)(.*)/' => self::class .'::blockquote', // blockquotes
'/\n-{5,}/' => "\n<hr />", // horizontal rule
'/\n([^\n]+)\n/' => self::class .'::para', // add paragraphs
'/<\/ul>\s?<ul>/' => '', // fix extra ul
'/<\/ol>\s?<ol>/' => '', // fix extra ol
'/<\/blockquote><blockquote>/' => "\n", // fix extra blockquote
'/<a href=\'(.*?)\'>/' => self::class .'::fix_link', // fix links
'/<img src=\'(.*?)\'/' => self::class .'::fix_img', // fix images
'/<p>{{{([0-9]+)}}}<\/p>/s' => self::class .'::reinsert_code_blocks' // re-insert code blocks
);
private static $code_blocks = [];
private static function code_parse ($regs) {
$item = $regs[1];
$item = htmlentities ($item, ENT_COMPAT);
$item = str_replace ("\n\n", '<br>', $item);
$item = str_replace ("\n", '<br>', $item);
while (mb_substr ($item, 0, 4) === '<br>') {
$item = mb_substr ($item, 4);
}
while (mb_substr ($item, -4) === '<br>') {
$item = mb_substr ($item, 0, -4);
}
// Store code blocks with placeholders to avoid other regexes affecting them
self::$code_blocks[] = sprintf ("<pre><code>%s</code></pre>", trim ($item));
return sprintf ("{{{%d}}}", count (self::$code_blocks) - 1);
}
private static function reinsert_code_blocks ($regs) {
// Reinsert the stored code blocks at the end
$index = $regs[1];
return self::$code_blocks[$index];
}
private static function para ($regs) {
$line = $regs[1];
$trimmed = trim ($line);
if (preg_match ('/^<\/?(ul|ol|li|h|p|bl|table|tr|th|td|code)/', $trimmed)) {
return "\n" . $line . "\n";
}
if (! empty ($trimmed)) {
//return sprintf ("\n<p>%s</p>\n", $trimmed);
return sprintf ("\n%s\n", $trimmed);
}
return $trimmed;
}
private static function ul_list ($regs) {
$item = $regs[1];
return sprintf ("\n<ul>\n\t<li>%s</li>\n</ul>", trim ($item));
}
private static function ol_list ($regs) {
$item = $regs[1];
return sprintf ("\n<ol>\n\t<li>%s</li>\n</ol>", trim ($item));
}
private static function blockquote ($regs) {
$item = $regs[2];
return sprintf ("\n<blockquote>%s</blockquote>", trim ($item));
}
private static function header ($regs) {
list ($tmp, $chars, $header) = $regs;
$level = strlen ($chars);
return sprintf ('<h%d>%s</h%d>', $level, trim ($header), $level);
}
private static function link ($regs) {
list ($tmp, $text, $link) = $regs;
// Substitute _ and * in links so they don't break the URLs
$link = str_replace (['_', '*'], ['{^^^}', '{~~~}'], $link);
return sprintf ('<a href=\'%s\'>%s</a>', $link, $text);
}
private static function img ($regs) {
list ($tmp, $text, $link) = $regs;
// Substitute _ and * in links so they don't break the URLs
$link = str_replace (['_', '*'], ['{^^^}', '{~~~}'], $link);
return sprintf ('<img src=\'%s\' alt=\'%s\' />', $link, $text);
//return sprintf ('<img src=\'/thumb?image=%s\' alt=\'%s\' />', $link, $text); // added support for thumbnail generation on the fly
}
private static function fix_link ($regs) {
// Replace substitutions so links are preserved
$fixed_link = str_replace (['{^^^}', '{~~~}'], ['_', '*'], $regs[1]);
return sprintf ('<a href=\'%s\'>', $fixed_link);
}
private static function fix_img ($regs) {
// Replace substitutions so links are preserved
$fixed_link = str_replace (['{^^^}', '{~~~}'], ['_', '*'], $regs[1]);
return sprintf ('<img src=\'%s\'', $fixed_link);
}
/**
* Add a rule.
*/
public static function add_rule ($regex, $replacement) {
self::$rules[$regex] = $replacement;
}
/**
* Render some Markdown into HTML.
*/
public static function render ($text) {
self::$code_blocks = [];
$text = "\n" . $text . "\n";
foreach (self::$rules as $regex => $replacement) {
if (is_callable ( $replacement)) {
$text = preg_replace_callback ($regex, $replacement, $text);
} else {
$text = preg_replace ($regex, $replacement, $text);
}
}
return trim ($text);
}
}

View file

@ -1,156 +0,0 @@
<?php
/**
* Slimdown - A simple regex-based Markdown parser in PHP. Supports the
* following elements (and can be extended via `Slimdown::add_rule()`):
*
* - Headers
* - Links
* - Bold
* - Emphasis
* - Deletions
* - Quotes
* - Code blocks
* - Inline code
* - Blockquotes
* - Ordered/unordered lists
* - Horizontal rules
* - Images
*
* Author: Johnny Broadway <johnny@johnnybroadway.com>
* Website: https://github.com/jbroadway/slimdown
* License: MIT
*/
class Slimdown {
public static $rules = array (
'/```(.*?)```/s' => self::class .'::code_parse', // code blocks
//'/\n(#+)(.*)/' => self::class .'::header', // headers
'/\n(#\s+)(.*)/' => self::class .'::header', // headers - only with a space between # and text, to avoid matching with `#hashtags`
//'/\!\[([^\[]+)\]\(([^\)]+)\)/' => self::class .'::img', // images
'/\!\[(.*?)\]\(([^\)]+)\)/' => self::class .'::img', // images 2
'/\[([^\[]+)\]\(([^\)]+)\)/' => self::class .'::link', // links
'/(\*\*|__)(?=(?:(?:[^`]*`[^`\r\n]*`)*[^`]*$))(?![^\/<]*>.*<\/.+>)(.*?)\1/' => '<strong>\2</strong>', // bold
'/(\*|_)(?=(?:(?:[^`]*`[^`\r\n]*`)*[^`]*$))(?![^\/<]*>.*<\/.+>)(.*?)\1/' => '<em>\2</em>', // emphasis
'/(\~\~)(?=(?:(?:[^`]*`[^`\r\n]*`)*[^`]*$))(?![^\/<]*>.*<\/.+>)(.*?)\1/' => '<del>\2</del>', // del
'/\:\"(.*?)\"\:/' => '<q>\1</q>', // quote
'/`(.*?)`/' => '<code>\1</code>', // inline code
'/\n\*(.*)/' => self::class .'::ul_list', // ul lists
'/\n[0-9]+\.(.*)/' => self::class .'::ol_list', // ol lists
'/\n(&gt;|\>)(.*)/' => self::class .'::blockquote', // blockquotes
'/\n-{5,}/' => "\n<hr />", // horizontal rule
'/\n([^\n]+)\n/' => self::class .'::para', // add paragraphs
'/<\/ul>\s?<ul>/' => '', // fix extra ul
'/<\/ol>\s?<ol>/' => '', // fix extra ol
'/<\/blockquote><blockquote>/' => "\n", // fix extra blockquote
'/<a href=\'(.*?)\'>/' => self::class .'::fix_link', // fix links
'/<img src=\'(.*?)\'/' => self::class .'::fix_img', // fix images
'/<p>{{{([0-9]+)}}}<\/p>/s' => self::class .'::reinsert_code_blocks' // re-insert code blocks
);
private static $code_blocks = [];
private static function code_parse ($regs) {
$item = $regs[1];
$item = htmlentities ($item, ENT_COMPAT);
$item = str_replace ("\n\n", '<br>', $item);
$item = str_replace ("\n", '<br>', $item);
while (mb_substr ($item, 0, 4) === '<br>') {
$item = mb_substr ($item, 4);
}
while (mb_substr ($item, -4) === '<br>') {
$item = mb_substr ($item, 0, -4);
}
// Store code blocks with placeholders to avoid other regexes affecting them
self::$code_blocks[] = sprintf ("<pre><code>%s</code></pre>", trim ($item));
return sprintf ("{{{%d}}}", count (self::$code_blocks) - 1);
}
private static function reinsert_code_blocks ($regs) {
// Reinsert the stored code blocks at the end
$index = $regs[1];
return self::$code_blocks[$index];
}
private static function para ($regs) {
$line = $regs[1];
$trimmed = trim ($line);
if (preg_match ('/^<\/?(ul|ol|li|h|p|bl|table|tr|th|td|code)/', $trimmed)) {
return "\n" . $line . "\n";
}
if (! empty ($trimmed)) {
//return sprintf ("\n<p>%s</p>\n", $trimmed);
return sprintf ("\n%s\n", $trimmed); // avoind addin <p>-tags and extra vetical margins
}
return $trimmed;
}
private static function ul_list ($regs) {
$item = $regs[1];
return sprintf ("\n<ul>\n\t<li>%s</li>\n</ul>", trim ($item));
}
private static function ol_list ($regs) {
$item = $regs[1];
return sprintf ("\n<ol>\n\t<li>%s</li>\n</ol>", trim ($item));
}
private static function blockquote ($regs) {
$item = $regs[2];
return sprintf ("\n<blockquote>%s</blockquote>", trim ($item));
}
private static function header ($regs) {
list ($tmp, $chars, $header) = $regs;
$level = strlen ($chars);
return sprintf ('<h%d>%s</h%d>', $level, trim ($header), $level);
}
private static function link ($regs) {
list ($tmp, $text, $link) = $regs;
// Substitute _ and * in links so they don't break the URLs
$link = str_replace (['_', '*'], ['{^^^}', '{~~~}'], $link);
return sprintf ('<a href=\'%s\'>%s</a>', $link, $text);
}
private static function img ($regs) {
list ($tmp, $text, $link) = $regs;
// Substitute _ and * in links so they don't break the URLs
$link = str_replace (['_', '*'], ['{^^^}', '{~~~}'], $link);
return sprintf ('<img src=\'%s\' alt=\'%s\' />', $link, $text);
}
private static function fix_link ($regs) {
// Replace substitutions so links are preserved
$fixed_link = str_replace (['{^^^}', '{~~~}'], ['_', '*'], $regs[1]);
return sprintf ('<a href=\'%s\'>', $fixed_link);
}
private static function fix_img ($regs) {
// Replace substitutions so links are preserved
$fixed_link = str_replace (['{^^^}', '{~~~}'], ['_', '*'], $regs[1]);
return sprintf ('<img src=\'%s\'', $fixed_link);
}
/**
* Add a rule.
*/
public static function add_rule ($regex, $replacement) {
self::$rules[$regex] = $replacement;
}
/**
* Render some Markdown into HTML.
*/
public static function render ($text) {
self::$code_blocks = [];
$text = "\n" . $text . "\n";
foreach (self::$rules as $regex => $replacement) {
if (is_callable ( $replacement)) {
$text = preg_replace_callback ($regex, $replacement, $text);
} else {
$text = preg_replace ($regex, $replacement, $text);
}
}
return trim ($text);
}
}

View file

@ -169,7 +169,6 @@ a.author {
line-height: 1; line-height: 1;
} }
.profile p { .profile p {
margin: 0.2rem 0; margin: 0.2rem 0;
color: var(--text-light); color: var(--text-light);
@ -273,14 +272,33 @@ article .twt-msg {
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
article .twt-msg p {
margin: 0.25rem 0;
}
article .twt-msg > blockquote { article .twt-msg > blockquote {
margin: 0; margin: 0.5rem 0;
border-left: thick solid grey; border-left: thick solid grey;
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
display: inline-block; display: inline-block;
font-style: italic; font-style: italic;
} }
article .twt-msg ul,
article .twt-msg ol {
padding-left: 2rem;
}
article .twt-msg li {
padding-left: 0.5rem;
}
article .twt-msg pre {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
}
article .twt-msg img { article .twt-msg img {
margin: 0.25rem -0.25rem; margin: 0.25rem -0.25rem;
display: block; display: block;
@ -294,6 +312,14 @@ article .twt-msg > img:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
article .embed-video {
margin-top: 0.5rem;
display: block;
width: 100%;
aspect-ratio: 16/9;
border-radius: 0.25rem;
}
article small { article small {
font-size: small; font-size: small;
} }
@ -320,7 +346,7 @@ article small a:hover {
#new_twt { #new_twt {
border: none; border: none;
text-align: center /* text-align: center*/
} }
#new_twt input[type="submit"] { #new_twt input[type="submit"] {

233
libs/tiny-mde.css Normal file
View file

@ -0,0 +1,233 @@
.TinyMDE {
/* background-color:#fff;
color:#000;
font-size:16px;
line-height:24px;
outline: none;
padding:5px; */
color: var(--text);
background-color: var(--bg);
border: 1px solid var(--border);
font-size: inherit;
font-family: inherit;
padding: 0.5rem;
margin: 0.5rem 0;
border-radius: var(--standard-border-radius);
min-height: 6rem;
}
/*
.TMBlankLine {
height:24px;
}
.TMH1, .TMSetextH1 {
font-size:22px;
line-height:32px;
font-weight:bold;
margin-bottom:8px;
}
.TMSetextH1 {
margin-bottom:0px;
}
.TMSetextH1Marker {
margin-bottom:8px;
}
.TMH2, .TMSetextH2 {
font-size:20px;
line-height:28px;
font-weight:bold;
margin-bottom:4px;
}
*/
.TMMark_TMCode {
font-family: monospace;
font-size: 0.9em;
}
.TMFencedCodeBacktick, .TMFencedCodeTilde, .TMIndentedCode, .TMCode {
font-family: monospace;
font-size: 0.9em;
background-color: var(--accent-bg);
}
.TMCodeFenceBacktickOpen, .TMCodeFenceTildeOpen {
border-bottom: 1px solid var(--border);
font-family: monospace;
font-size:.9em;
}
.TMCodeFenceBacktickClose, .TMCodeFenceTildeClose {
border-top: 1px solid var(--border);
font-family: monospace;
font-size:.9em;
}
.TMInfoString {
color: var(--accent);
}
.TMCode {
border:1px solid var(--border);
border-radius: 2px;
}
.TMBlockquote {
font-style: italic;
border-left:2px solid var(--border);
padding-left:10px;
margin-left:10px;
}
/*
.TMMark {
color:#a0a0a0;
}
.TMMark_TMH1, .TMMark_TMH2 {
color:#ff8080;
}
*/
.TMMark_TMUL, .TMMark_TMOL {
color: var(--accent);
}
.TMImage {
text-decoration: underline;
text-decoration-color: #00ff00;
}
.TMLink {
text-decoration: underline;
text-decoration-color: var(--accent);
}
.TMLinkLabel {
text-decoration: underline;
font-family: monospace;
}
.TMLinkLabel_Definition, .TMLinkLabel_Valid {
color: #40c040;
}
.TMLinkLabel_Invalid {
color: #ff0000;
}
.TMLinkTitle {
font-style:italic;
}
.TMLinkDestination, .TMAutolink {
text-decoration: underline;
color: var(--accent);
}
/*
.TMHR {
position: relative;
}
.TMHR:before {
content: '';
position: absolute;
bottom: 50%;
left: 40%;
border-bottom: 2px solid #808080;
width: 20%;
z-index:0;
}
*/
.TMHTML, .TMHTMLBlock {
font-family:monospace;
font-size:.9em;
color:#8000ff;
}
.TMHTMLBlock {
color:#6000c0;
}
.TMCommandBar {
/* background-color:#f8f8f8;
height:24px;
border:4px solid #f8f8f8; */
box-sizing: content-box;
display:flex;
user-select: none;
overflow-x: scroll;
overflow-y: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
}
.TMCommandBar::-webkit-scrollbar {
display: none;
}
.TMCommandButton {
box-sizing: border-box;
display: inline-block;
height:24px;
width:24px;
padding:3px;
margin-right:4px;
color: var(--text-light);
fill: var(--text-light);
text-align: center;
cursor: pointer;
vertical-align: middle;
font-size:20px;
line-height:18px;
font-family: sans-serif;
}
.TMCommandDivider {
box-sizing: content-box;
height:24px;
margin-left:4px;
margin-right:8px;
width:0px;
/* border-left:1px solid var(--border);*/
/* border-right:1px solid #ffffff;*/
border-left:1px solid var(--border);
}
.TMCommandButton_Active {
font-weight: bold;
color: var(--accent-bg);
fill: var(--accent-bg);
background-color: var(--accent);
}
.TMCommandButton_Inactive {
/* background-color:#f8f8f8;*/
background-color: var(--accent-bg);
}
.TMCommandButton_Disabled {
/* color:#a0a0a0;
fill:#a0a0a0; */
color: var(--text-light);
fill: var(--text-light);
}
@media (hover: hover) {
.TMCommandButton_Active:hover,
.TMCommandButton_Disabled:hover,
.TMCommandButton_Inactive:hover {
/* background-color:#e0e0ff;*/
/* fill:#000000;*/
fill: var(--accent);
}
}

1
libs/tiny-mde.min.css vendored Normal file
View file

@ -0,0 +1 @@
.TinyMDE{background-color:#fff;color:#000;font-size:16px;line-height:24px;outline:none;padding:5px}.TMBlankLine{height:24px}.TMH1,.TMSetextH1{font-size:22px;font-weight:700;line-height:32px;margin-bottom:8px}.TMSetextH1{margin-bottom:0}.TMSetextH1Marker{margin-bottom:8px}.TMH2,.TMSetextH2{font-size:20px;font-weight:700;line-height:28px;margin-bottom:4px}.TMMark_TMCode{font-family:monospace;font-size:.9em}.TMCode,.TMFencedCodeBacktick,.TMFencedCodeTilde,.TMIndentedCode{background-color:#e0e0e0;font-family:monospace;font-size:.9em}.TMCodeFenceBacktickOpen,.TMCodeFenceTildeOpen{border-bottom:1px solid silver;font-family:monospace;font-size:.9em}.TMCodeFenceBacktickClose,.TMCodeFenceTildeClose{border-top:1px solid silver;font-family:monospace;font-size:.9em}.TMInfoString{color:#00f}.TMCode{border:1px solid silver;border-radius:2px}.TMBlockquote{border-left:2px solid silver;font-style:italic;margin-left:10px;padding-left:10px}.TMMark{color:#a0a0a0}.TMMark_TMH1,.TMMark_TMH2,.TMMark_TMOL,.TMMark_TMUL{color:#ff8080}.TMImage{text-decoration:underline;text-decoration-color:#0f0}.TMLink{text-decoration:underline;text-decoration-color:#00f}.TMLinkLabel{font-family:monospace;text-decoration:underline}.TMLinkLabel_Definition,.TMLinkLabel_Valid{color:#40c040}.TMLinkLabel_Invalid{color:red}.TMLinkTitle{font-style:italic}.TMAutolink,.TMLinkDestination{color:#00f;text-decoration:underline}.TMHR{position:relative}.TMHR:before{border-bottom:2px solid grey;bottom:50%;content:"";left:40%;position:absolute;width:20%;z-index:0}.TMHTML,.TMHTMLBlock{color:#8000ff;font-family:monospace;font-size:.9em}.TMHTMLBlock{color:#6000c0}.TMCommandBar{-ms-overflow-style:none;background-color:#f8f8f8;border:4px solid #f8f8f8;box-sizing:content-box;display:flex;height:24px;overflow-x:scroll;overflow-y:hidden;scrollbar-width:none;-webkit-user-select:none;user-select:none}.TMCommandBar::-webkit-scrollbar{display:none}.TMCommandButton{fill:#404040;box-sizing:border-box;color:#404040;cursor:pointer;display:inline-block;font-family:sans-serif;font-size:20px;height:24px;line-height:18px;margin-right:4px;padding:3px;text-align:center;vertical-align:middle;width:24px}.TMCommandDivider{border-left:1px solid silver;border-right:1px solid #fff;box-sizing:content-box;height:24px;margin-left:4px;margin-right:8px;width:0}.TMCommandButton_Active{fill:navy;background-color:#c0c0ff;color:navy;font-weight:700}.TMCommandButton_Inactive{background-color:#f8f8f8}.TMCommandButton_Disabled{fill:#a0a0a0;color:#a0a0a0}@media (hover:hover){.TMCommandButton_Active:hover,.TMCommandButton_Disabled:hover,.TMCommandButton_Inactive:hover{fill:#000;background-color:#e0e0ff}}

1
libs/tiny-mde.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -125,6 +125,8 @@ function getImagesFromTwt(string $twtString) {
function getTagsFromTwt(string $twtString) { function getTagsFromTwt(string $twtString) {
//$pattern = '/(?<!\()\B#\w+(?!\))/iu'; //$pattern = '/(?<!\()\B#\w+(?!\))/iu';
$pattern = '/(?<=\B)#(\w+)/'; $pattern = '/(?<=\B)#(\w+)/';
//$pattern = '/(?<=\s)#(\w+)/';
//$pattern = '/\s#(\w+)/';
//$pattern = "/\(#\w{7}\)/"; //$pattern = "/\(#\w{7}\)/";
//$pattern = '/(?<=\s|^)#(\w+)/'; //$pattern = '/(?<=\s|^)#(\w+)/';
// TODO: Fix so it does not match with url#fragments (\B vs \s) // TODO: Fix so it does not match with url#fragments (\B vs \s)
@ -181,8 +183,9 @@ function replaceLinksFromTwt(string $twtString) {
// 1. Look into how yarnd handles this // 1. Look into how yarnd handles this
// Regular expression pattern to match URLs // Regular expression pattern to match URLs
$pattern = '/(?<!\S)(\b(https?|ftp|gemini|spartan|gopher):\/\/\S+|\b(?!:\/\/)\w+(?:\.\w+)+(?:\/\S+)?)(?!\S)/'; //$pattern = '/(?<!\S)(\b(https?|ftp|gemini|spartan|gopher):\/\/\S+|\b(?!:\/\/)\w+(?:\.\w+)+(?:\/\S+)?)(?!\S)/';
$pattern = '/(?<!\S)(?<!href="|">)(?<!src=\")((http|ftp)+(s)?:\/\/[^<>\s]+)/is';
// Replace URLs with clickable links // Replace URLs with clickable links
$replacement = '<a href="$1">$1</a>'; $replacement = '<a href="$1">$1</a>';
$result = preg_replace($pattern, $replacement, $twtString); $result = preg_replace($pattern, $replacement, $twtString);
@ -209,7 +212,9 @@ function replaceImagesFromTwt(string $twtString) {
} }
function replaceTagsFromTwt(string $twtString) { function replaceTagsFromTwt(string $twtString) {
$pattern = '/#(\w+)?/'; //$pattern = '/#(\w+)?/';
$pattern = '/(?<=\s)#(\w+)/';
//$replacement = '<a href="#">#\1</a>'; // Dummy link //$replacement = '<a href="#">#\1</a>'; // Dummy link
$replacement = '<a href="?search=$1" class="tag">#${1}</a>'; $replacement = '<a href="?search=$1" class="tag">#${1}</a>';
$result = preg_replace($pattern, $replacement, $twtString); $result = preg_replace($pattern, $replacement, $twtString);
@ -217,6 +222,25 @@ function replaceTagsFromTwt(string $twtString) {
return $result; return $result;
} }
function embedYoutubeFromTwt(string $twtString) {
// original regex source: https://gist.github.com/afeld/1254889#gistcomment-1253992
$pattern = '/(?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/mi';
if(preg_match_all($pattern, $twtString, $youtubeLinks)) {
$youtubeLinks = array_unique($youtubeLinks[1]); // Remove dublicate cause by raw URLs conceverter to links
foreach ($youtubeLinks as $videoID) {
$twtString .= '<iframe loading="lazy" src="https://www.youtube.com/embed/'.$videoID.'" class="embed-video" allow="encrypted-media" title="" allowfullscreen="allowfullscreen" frameborder="0"></iframe>';
}
}
$result = $twtString;
return $result;
}
function getTimeElapsedString($timestamp, $full = false) { function getTimeElapsedString($timestamp, $full = false) {
$now = new DateTime; $now = new DateTime;
@ -407,12 +431,17 @@ function getTwtsFromTwtxtString($url) {
// For some reason I was having trouble finding this nomenclature // For some reason I was having trouble finding this nomenclature
// that's why I leave the UTF-8 representation for future reference // that's why I leave the UTF-8 representation for future reference
$twtContent = str_replace("\u{2028}", "\n<br>\n", $twtContent); //$twtContent = str_replace("\u{2028}", "\n<br>\n", $twtContent);
$twtContent = str_replace("\u{2028}", "\n", $twtContent);
$twtContent = replaceMarkdownLinksFromTwt($twtContent);
$twtContent = replaceImagesFromTwt($twtContent); //$twtContent = replaceMarkdownLinksFromTwt($twtContent);
//$twtContent = Slimdown::render($twtContent); //$twtContent = replaceImagesFromTwt($twtContent);
$twtContent = replaceLinksFromTwt($twtContent); // TODO:
$Parsedown = new Parsedown();
$twtContent = $Parsedown->text($twtContent);
$twtContent = embedYoutubeFromTwt($twtContent);
//$twtContent = replaceLinksFromTwt($twtContent);
// Get and remove the hash // Get and remove the hash
$hash = getReplyHashFromTwt($twtContent); $hash = getReplyHashFromTwt($twtContent);

View file

@ -20,7 +20,7 @@ declare (strict_types = 1);
require_once('libs/session.php'); require_once('libs/session.php');
require_once('libs/twtxt.php'); require_once('libs/twtxt.php');
require_once('libs/hash.php'); require_once('libs/hash.php');
require_once('libs/Slimdown.php'); require_once('libs/Parsedown.php');
const TWTS_PER_PAGE = 50; const TWTS_PER_PAGE = 50;

View file

@ -10,6 +10,11 @@ $profile = getTwtsFromTwtxtString($config['public_txt_url']);
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="<?= $baseURL ?>/media/logo.png"> <link rel="icon" type="image/x-icon" href="<?= $baseURL ?>/media/logo.png">
<?php if( isset($_SESSION['password'])) { ?>
<script src="<?= $baseURL ?>/libs/tiny-mde.min.js"></script>
<!-- <link rel="stylesheet" type="text/css" href="<?= $baseURL ?>/libs/tiny-mde.min.css" /> -->
<link rel="stylesheet" type="text/css" href="<?= $baseURL ?>/libs/tiny-mde.css" />
<?php } ?>
<link rel="stylesheet" type="text/css" href="<?= $baseURL ?>/libs/simple.css"> <link rel="stylesheet" type="text/css" href="<?= $baseURL ?>/libs/simple.css">
<link rel="stylesheet" type="text/css" href="<?= $baseURL ?>/libs/timeline.css"> <link rel="stylesheet" type="text/css" href="<?= $baseURL ?>/libs/timeline.css">
<link rel="stylesheet" type="text/css" href="<?= $baseURL ?>/custom.css"> <link rel="stylesheet" type="text/css" href="<?= $baseURL ?>/custom.css">

View file

@ -2,6 +2,7 @@
// TODO: Give a warning if the file is not found // TODO: Give a warning if the file is not found
$config = parse_ini_file('private/config.ini'); $config = parse_ini_file('private/config.ini');
if ($config['debug_mode']) { if ($config['debug_mode']) {
ini_set('display_errors', 1); ini_set('display_errors', 1);
ini_set('display_startup_errors', 1); ini_set('display_startup_errors', 1);
@ -151,12 +152,27 @@ if (isset($_GET['hash'])) {
<article id="new_twt"> <article id="new_twt">
<form method="POST"> <form method="POST">
<div id="posting"> <div id="posting">
<div id="toolbar"></div>
<textarea class="textinput" id="new_post" name="new_post" <textarea class="textinput" id="new_post" name="new_post"
rows="4" cols="100" autofocus required onfocus="var val=this.value; this.value=''; this.value= val;" rows="4" cols="100" autofocus required onfocus="var val=this.value; this.value=''; this.value= val;"
placeholder="Your twt"><?= $textareaValue ?></textarea> placeholder="Your twt"><?= $textareaValue ?></textarea>
<!-- <br> --> <!-- <br> -->
<input type="submit" value="Post" name="submit"> <input type="submit" value="Post" name="submit">
</div> </div>
<script type="text/javascript">
var tinyMDE = new TinyMDE.Editor({
element: "new_post",
// content: "Type your twt"
});
var commandBar = new TinyMDE.CommandBar({
element: "toolbar",
editor: tinyMDE,
commands: ['bold', 'italic', 'strikethrough', 'ul', 'ol', 'blockquote', 'code', '|', 'insertLink', 'insertImage'],
});
</script>
</form> </form>
</article> </article>