Overview
Comment:Fix minor issues with new markdown features
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 1d4e24b8acbf147a6ce33fd5e7578155350b73c4c438269d6ac22a59d733f627
User & Date: bohwaz on 2023-02-25 03:25:32
Other Links: manifest | tags
Context
2023-02-25
03:34
Fix internal links in doc, and fix margins in default content.css check-in: 010b97faae user: bohwaz tags: trunk
03:25
Fix minor issues with new markdown features check-in: 1d4e24b8ac user: bohwaz tags: trunk
03:24
Rewrite Markdown/Skriv doc as Markdown check-in: c84a50faf2 user: bohwaz tags: trunk
Changes

Modified src/include/lib/Garradin/Web/Render/AbstractRender.php from [504bb9e915] to [b9ae79bdbd].

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
	}

	public function registerAttachment(string $uri)
	{
		Render::registerAttachment($this->file, $uri);
	}

	protected function resolveAttachment(string $uri)
	{
		$prefix = $this->current_path;
		$pos = strpos($uri, '/');

		if ($pos === 0) {
			// Absolute URL: treat it as absolute!
			$uri = ltrim($uri, '/');
		}
		else {
			// Handle relative URIs
			$uri = $prefix . '/' . $uri;
		}

		$this->registerAttachment($uri);

		return WWW_URL . $uri;
	}

	protected function resolveLink(string $uri) {
		$first = substr($uri, 0, 1);
		if ($first == '/' || $first == '!') {
			return Utils::getLocalURL($uri);
		}

		if (strpos(Utils::basename($uri), '.') === false) {
			$uri .= $this->link_suffix;







|


















|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
	}

	public function registerAttachment(string $uri)
	{
		Render::registerAttachment($this->file, $uri);
	}

	public function resolveAttachment(string $uri)
	{
		$prefix = $this->current_path;
		$pos = strpos($uri, '/');

		if ($pos === 0) {
			// Absolute URL: treat it as absolute!
			$uri = ltrim($uri, '/');
		}
		else {
			// Handle relative URIs
			$uri = $prefix . '/' . $uri;
		}

		$this->registerAttachment($uri);

		return WWW_URL . $uri;
	}

	public function resolveLink(string $uri) {
		$first = substr($uri, 0, 1);
		if ($first == '/' || $first == '!') {
			return Utils::getLocalURL($uri);
		}

		if (strpos(Utils::basename($uri), '.') === false) {
			$uri .= $this->link_suffix;

Modified src/include/lib/Garradin/Web/Render/Extensions.php from [1b51d29d6c] to [133aeb7c0e].

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

105
106
107
108
109
110
111
112
		}

		return call_user_func($this->list[$name], $block, $params, $content, $name, $object);
	}

	public function getTempTOC(bool $block, array $args): string
	{
		return sprintf('<<toc|%d|%d>>', $args['level'] ?? 0, array_key_exists('aside', $args));
	}

	public function replaceTempTOC(string $out, array $toc): string
	{
		if (false !== strpos($out, '<<toc') && preg_match_all('!<<toc\|(\d\|(?:0|1))>>!', $out, $match, PREG_PATTERN_ORDER)) {
			$types = array_unique($match[1] ?? []);

			foreach ($types as $t) {

				$str = $this->buildTOC(['level' => $t[0], 'aside' => $t[2]], $toc);
				$out = str_replace(sprintf('<<toc|%s>>', $t), $str, $out);
			}
		}

		return $out;
	}








|








>
|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
		}

		return call_user_func($this->list[$name], $block, $params, $content, $name, $object);
	}

	public function getTempTOC(bool $block, array $args): string
	{
		return sprintf('<<toc|%d|%d>>', $args['level'] ?? 0, array_key_exists('aside', $args) && $args['aside'] !== false);
	}

	public function replaceTempTOC(string $out, array $toc): string
	{
		if (false !== strpos($out, '<<toc') && preg_match_all('!<<toc\|(\d\|(?:0|1))>>!', $out, $match, PREG_PATTERN_ORDER)) {
			$types = array_unique($match[1] ?? []);

			foreach ($types as $t) {
				$args = ['level' => (int) $t[0], 'aside' => (bool) $t[2]];
				$str = $this->buildTOC($args, $toc);
				$out = str_replace(sprintf('<<toc|%s>>', $t), $str, $out);
			}
		}

		return $out;
	}

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
		}

		if ($level > 0) {
			$out .= "\n";
			$out .= str_repeat('</li></ol>', $level);
		}

		if (isset($args['aside'])) {
			$out = '<aside class="toc">' . $out . '</aside>';
		}
		else {
			$out = '<div class="toc">' . $out . '</div>';
		}

		return $out;







|







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
		}

		if ($level > 0) {
			$out .= "\n";
			$out .= str_repeat('</li></ol>', $level);
		}

		if (isset($args['aside']) && $args['aside'] !== false) {
			$out = '<aside class="toc">' . $out . '</aside>';
		}
		else {
			$out = '<div class="toc">' . $out . '</div>';
		}

		return $out;
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
		$svg = substr($name, -4) == '.svg';
		$thumb_url = null;

		if (!$svg) {
			$thumb_url = sprintf('%s?%spx', $url, $size);
		}

		$out = sprintf('<a href="%s" class="internal-image" target="_image"><img src="%s" alt="%s" loading="lazy" style="max-width: %dpx; max-height: %4$dpx;" /></a>',
			htmlspecialchars($url),
			htmlspecialchars($thumb_url ?? $url),
			htmlspecialchars($caption ?? ''),
			$size
		);

		if (!empty($align)) {
			if ($caption) {
				$caption = sprintf('<figcaption>%s</figcaption>', htmlspecialchars($caption));
			}








|


|
<







201
202
203
204
205
206
207
208
209
210
211

212
213
214
215
216
217
218
		$svg = substr($name, -4) == '.svg';
		$thumb_url = null;

		if (!$svg) {
			$thumb_url = sprintf('%s?%spx', $url, $size);
		}

		$out = sprintf('<a href="%s" class="internal-image" target="_image"><img src="%s" alt="%s" loading="lazy" /></a>',
			htmlspecialchars($url),
			htmlspecialchars($thumb_url ?? $url),
			htmlspecialchars($caption ?? '')

		);

		if (!empty($align)) {
			if ($caption) {
				$caption = sprintf('<figcaption>%s</figcaption>', htmlspecialchars($caption));
			}

276
277
278
279
280
281
282




283
284
285
286
287
288
289
		if (isset($args['column'])) {
			$style .= 'grid-column: ' . htmlspecialchars($args['column']);
		}

		if (isset($args['row'])) {
			$style .= 'grid-row: ' . htmlspecialchars($args['row']);
		}





		return sprintf('<article class="web-block" style="%s">', $style);
	}

	public function grid(bool $block, array $args, ?string $content, string $name): string
	{
		if (!$block) {







>
>
>
>







276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
		if (isset($args['column'])) {
			$style .= 'grid-column: ' . htmlspecialchars($args['column']);
		}

		if (isset($args['row'])) {
			$style .= 'grid-row: ' . htmlspecialchars($args['row']);
		}

		if (isset($args['align'])) {
			$style .= 'align-self: ' . htmlspecialchars($args['align']);
		}

		return sprintf('<article class="web-block" style="%s">', $style);
	}

	public function grid(bool $block, array $args, ?string $content, string $name): string
	{
		if (!$block) {
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
		// Automatic template from simple string:
		// !! = 2 columns, #!! = 1 50% column, two 25% columns
		if (isset($args[0]) || isset($args['short'])) {
			$template = $args[0] ?? $args['short'];
			$template = preg_replace('/[^!#]/', '', $template);
			$l = strlen($template);
			$fraction = ceil(100*(1/$l)) / 100;
			$template = str_replace('!', sprintf('minmax(10px, %sfr) ', $fraction), $template);
			$template = preg_replace_callback('/(#+)/', fn ($match) => sprintf('minmax(10px, %sfr) ', $fraction * strlen($match[1])), $template);
			$style .= 'none / ' . trim($template);
		}
		elseif (isset($args['template'])) {
			$style .= $args['template'];
		}
		else {
			$style .= '1fr';







|
|







315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
		// Automatic template from simple string:
		// !! = 2 columns, #!! = 1 50% column, two 25% columns
		if (isset($args[0]) || isset($args['short'])) {
			$template = $args[0] ?? $args['short'];
			$template = preg_replace('/[^!#]/', '', $template);
			$l = strlen($template);
			$fraction = ceil(100*(1/$l)) / 100;
			$template = str_replace('!', sprintf('minmax(0, %sfr) ', $fraction), $template);
			$template = preg_replace_callback('/(#+)/', fn ($match) => sprintf('minmax(0, %sfr) ', $fraction * strlen($match[1])), $template);
			$style .= 'none / ' . trim($template);
		}
		elseif (isset($args['template'])) {
			$style .= $args['template'];
		}
		else {
			$style .= '1fr';

Modified src/include/lib/Garradin/Web/Render/Markdown.php from [19b50a56e6] to [44246cbd45].

1
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
<?php

namespace Garradin\Web\Render;

use Garradin\Entities\Files\File;

use Garradin\Plugin;

use Garradin\Utils;
use Garradin\Files\Files;

use const Garradin\{ADMIN_URL, WWW_URL};

class Markdown extends AbstractRender
{
	public function render(?string $content = null): string
	{
		$parsedown = Parsedown::instance();
		$parsedown->setBreaksEnabled(true);
		$parsedown->setUrlsLinked(true);
		$parsedown->setSafeMode(true);

		$str = $content ?? $this->file->fetch();

		$ext = new Extensions($this);
		$parsedown->setExtensions($ext);

		$str = $parsedown->text($str);

		unset($parsedown);

		$str = preg_replace_callback(';<a href="((?!https?://|\w+:|#).+?)">;i', function ($matches) {
			return sprintf('<a href="%s" target="_parent">', htmlspecialchars($this->resolveLink(htmlspecialchars_decode($matches[1]))));
		}, $str);

		return sprintf('<div class="web-content">%s</div>', $str);
	}
}




|
|
<
>
|
<
|
<
|
<
|













>









1
2
3
4
5
6

7
8

9

10

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

namespace Garradin\Web\Render;

class Markdown extends AbstractRender
{

	/**
	 * Used by doc_md_to_html.php script

	 */

	public $toc = [];


	public function render(?string $content = null): string
	{
		$parsedown = Parsedown::instance();
		$parsedown->setBreaksEnabled(true);
		$parsedown->setUrlsLinked(true);
		$parsedown->setSafeMode(true);

		$str = $content ?? $this->file->fetch();

		$ext = new Extensions($this);
		$parsedown->setExtensions($ext);

		$str = $parsedown->text($str);
		$this->toc = $parsedown->toc;
		unset($parsedown);

		$str = preg_replace_callback(';<a href="((?!https?://|\w+:|#).+?)">;i', function ($matches) {
			return sprintf('<a href="%s" target="_parent">', htmlspecialchars($this->resolveLink(htmlspecialchars_decode($matches[1]))));
		}, $str);

		return sprintf('<div class="web-content">%s</div>', $str);
	}
}

Modified src/include/lib/Garradin/Web/Render/Parsedown.php from [53a82565df] to [411378b7d5].

281
282
283
284
285
286
287
288
289
290
291


292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

		// Comments
		if (preg_match('/<!--.*?-->/', $text, $match)) {
			return ['element' => ['rawHtml' => ''], 'extent', strlen($match[0])];
		}

		// Skip if not a tag
		if (!preg_match('!(</?(\w+?))([^>]*)>!', $text, $match)) {
			return null;
		}



		if (!array_key_exists($match[2], self::ALLOWED_INLINE_TAGS)) {
			return null;
		}

		$attributes = $this->_filterHTMLAttributes($match[2], self::ALLOWED_INLINE_TAGS[$match[2]], $match[3]);

		return [
			'element' => [
				'rawHtml' => $match[1] . '>',
				'allowRawHtmlInSafeMode' => true,
				'attributes' => $attributes,
			],
			'extent' => strlen($match[0]),
		];
	}








|



>
>
|



|



|







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309

		// Comments
		if (preg_match('/<!--.*?-->/', $text, $match)) {
			return ['element' => ['rawHtml' => ''], 'extent', strlen($match[0])];
		}

		// Skip if not a tag
		if (!preg_match('!</?(\w+)([^>]*)>!', $text, $match)) {
			return null;
		}

		$name = $match[1];

		if (!array_key_exists($name, self::ALLOWED_INLINE_TAGS)) {
			return null;
		}

		$attributes = $this->_filterHTMLAttributes($name, self::ALLOWED_INLINE_TAGS[$name], $match[2]);

		return [
			'element' => [
				'rawHtml' => '<' . $name . '>',
				'allowRawHtmlInSafeMode' => true,
				'attributes' => $attributes,
			],
			'extent' => strlen($match[0]),
		];
	}

343
344
345
346
347
348
349


















350
351
352
353
354
355



356
357
358
359
360
361
362
				'attributes' => $attributes,
				'autobreak' => true,
				'text' => '',
			],
		];
	}



















	protected function inlineText($text)
	{
		$text = CommonModifiers::typo($text);
		return parent::inlineText($text);
	}




	protected function blockHeader($line): ?array
	{
		$block = parent::blockHeader($line);

		if (!is_array($block)) {
			return $block;
		}







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






>
>
>







345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
				'attributes' => $attributes,
				'autobreak' => true,
				'text' => '',
			],
		];
	}

	/**
	 * Open external links in new page
	 */
    protected function inlineLink($Excerpt)
    {
    	$e = parent::inlineLink($Excerpt);

    	if (strstr($e['element']['attributes']['href'], ':')) {
    		$e['element']['attributes']['target'] = '_blank';
    		$e['element']['attributes']['rel'] = 'nofollow,noreferrer';
    	}

    	return $e;
    }

    /**
     * Add typo modifier to text
     */
	protected function inlineText($text)
	{
		$text = CommonModifiers::typo($text);
		return parent::inlineText($text);
	}

	/**
	 * Use headers to populate TOC
	 */
	protected function blockHeader($line): ?array
	{
		$block = parent::blockHeader($line);

		if (!is_array($block)) {
			return $block;
		}

Modified src/include/lib/Garradin/Web/Render/Skriv.php from [464a4423d5] to [e0371ff3e2].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace Garradin\Web\Render;

use Garradin\Entities\Files\File;

use Garradin\Plugin;
use Garradin\UserTemplate\CommonModifiers;

use KD2\SkrivLite;
use KD2\Garbage2xhtml;

use const Garradin\{ADMIN_URL, WWW_URL};

class Skriv extends AbstractRender
{
	static protected $skriv = null;
	protected Extensions $extensions;

	public function __construct(?File $file = null, ?string $user_prefix = null)





<
<



<
<
<







1
2
3
4
5


6
7
8



9
10
11
12
13
14
15
<?php

namespace Garradin\Web\Render;

use Garradin\Entities\Files\File;


use Garradin\UserTemplate\CommonModifiers;

use KD2\SkrivLite;




class Skriv extends AbstractRender
{
	static protected $skriv = null;
	protected Extensions $extensions;

	public function __construct(?File $file = null, ?string $user_prefix = null)

Modified src/www/skel-dist/content.css from [398a260315] to [c4bf95203b].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * Ce fichier contient les styles CSS qui s'appliquent au contenu des articles et catégorie,
 * que ce soit sur le site public ou dans la prévisualisation de l'administration.
 *
 * Généralement il n'est pas nécessaire de le modifier.
 */

.protected-contact::before {
    content: attr(data-a) "\0040" attr(data-b) "." attr(data-c);
}

.web-content p, .web-content h1, .web-content h2, .web-content h3, .web-content h4, .web-content h5, .web-content h6,
.web-content ul, .web-content ol, .web-content table, .web-content blockquote, .web-content pre {
    margin: 0;
    margin-bottom: .8em;
}

.web-content ul, .web-content ol, .web-content dd {
    margin-left: 2em;
}

.web-content ul {













|
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
/**
 * Ce fichier contient les styles CSS qui s'appliquent au contenu des articles et catégorie,
 * que ce soit sur le site public ou dans la prévisualisation de l'administration.
 *
 * Généralement il n'est pas nécessaire de le modifier.
 */

.protected-contact::before {
    content: attr(data-a) "\0040" attr(data-b) "." attr(data-c);
}

.web-content p, .web-content h1, .web-content h2, .web-content h3, .web-content h4, .web-content h5, .web-content h6,
.web-content ul, .web-content ol, .web-content table, .web-content blockquote, .web-content pre {
    margin: 1rem 0;

}

.web-content ul, .web-content ol, .web-content dd {
    margin-left: 2em;
}

.web-content ul {
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
    font-style: italic;
    color: #666;
    margin-top: 2pt;
}

.web-content figure.image.img-center {
    max-width: 500px;
    margin: 1em auto 1em auto;
}

.web-content figure.image.img-left {
    max-width: 200px;
    float: left;
    margin: 0 8pt 4pt 0;
    clear: left;







|







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    font-style: italic;
    color: #666;
    margin-top: 2pt;
}

.web-content figure.image.img-center {
    max-width: 500px;
    margin: 1rem auto;
}

.web-content figure.image.img-left {
    max-width: 200px;
    float: left;
    margin: 0 8pt 4pt 0;
    clear: left;
340
341
342
343
344
345
346
347
348
349
350
351
352
@media handheld, screen and (max-width: 980px) {
    .imageBrowser figure {
        max-width: 100%;
        max-height: 100%;
    }
}

@media screen and (min-width: 60rem) {
    .web-grid {
        /* Get template from variable, which is defined style attribute */
        grid-template: var(--grid-template);
    }
}







|





339
340
341
342
343
344
345
346
347
348
349
350
351
@media handheld, screen and (max-width: 980px) {
    .imageBrowser figure {
        max-width: 100%;
        max-height: 100%;
    }
}

@media screen and (min-width: 800px) {
    .web-grid {
        /* Get template from variable, which is defined style attribute */
        grid-template: var(--grid-template);
    }
}