expanded and streamlined markdown rendering

pull/84/head
Ro 3 years ago
parent 0742e06c45
commit 7775c1d409

@ -13,6 +13,7 @@ include "../brain/data/Member.inc.php";
include "../brain/data/Auth.inc.php";
include "../brain/data/Render.inc.php";
include "../brain/data/Themes.inc.php";
include "../brain/data/Contents.inc.php";
include "../brain/utility/StringTools.inc.php";
include "../brain/utility/FileUploader.inc.php";
include "../brain/utility/DocTools.inc.php";
@ -24,24 +25,24 @@ include "../brain/utility/HandleCors.inc.php";
class App
{
public function __construct()
{
// set up cors
new HandleCors();
$app = AppFactory::create();
$twig = Twig::create("../brain/views/");
$app->add(TwigMiddleware::create($app, $twig));
//set up routing
$app->get(
"/[{first}[/{second}[/{third}[/{fourth}[/{fifth}]]]]]",
"\RouteControl:get"
);
$app->post(
"/[{first}[/{second}[/{third}[/{fourth}]]]]",
"\RouteControl:post"
);
//start the app
public function __construct()
{
// set up cors
new HandleCors();
$app = AppFactory::create();
$twig = Twig::create("../brain/views/");
$app->add(TwigMiddleware::create($app, $twig));
//set up routing
$app->get(
"/[{first}[/{second}[/{third}[/{fourth}[/{fifth}]]]]]",
"\RouteControl:get"
);
$app->post(
"/[{first}[/{second}[/{third}[/{fourth}]]]]",
"\RouteControl:post"
);
//start the app
$app->run();
}
$app->run();
}
}

@ -76,11 +76,7 @@ class DashControl
if (Session::active()) {
$currentPage = isset($args["fourth"]) ? $args["fourth"] : 1;
$filter = isset($args["third"]) ? $args["third"] : "all";
$data = (new Book("../content/pages"))->getPages(
$currentPage,
4,
$filter
);
$data = (new Book())->getPages($currentPage, 4, $filter);
$template = "dash/book.twig";
$pageOptions = [
"entryCount" => $data["entryCount"],
@ -102,9 +98,10 @@ class DashControl
$template = "dash/page-edit.twig";
$mode = $args["third"];
$uuid = $args["fourth"];
switch ($mode) {
case "edit":
$page = (new Book("../content/pages"))->findPageById($uuid);
$page = (new Book())->findPageById($uuid);
$views = [];
if (str_contains($page["layout"], "index")) {
$views = (new Themes())->getCustomIndex();
@ -128,7 +125,7 @@ class DashControl
);
$display = new \Twig\Environment($loader, []);
$book = new Book("../content/pages");
$book = new Book();
$page = $book->findPageById($uuid);
$pageOptions = Sorting::page($page);
$preview =
@ -172,7 +169,7 @@ class DashControl
$pageOptions = [
"title" => "Welcome Back",
"status" => Session::active(),
"data" => (new Book("../content/pages"))->getPages(1, 4),
"data" => (new Book())->getPages(1, 4),
];
} else {
$pageOptions = [

@ -65,7 +65,7 @@ class IndexControl
default:
//check layout to see what page should be rendered
$template = $settings["global"]["theme"] . "/page.twig";
$book = new Book("../content/pages");
$book = new Book();
$page = $book->findPageBySlug($args["third"]);
$pageOptions = Sorting::page($page);
@ -74,7 +74,7 @@ class IndexControl
} else {
//index
$template = $settings["global"]["theme"] . "/index.twig";
$book = new Book("../content/pages");
$book = new Book("");
$page = $book->findPageBySlug();
$pageOptions = Sorting::page($page);
}

@ -1,29 +1,12 @@
<?php
use Mni\FrontYAML\Parser;
use function _\orderBy;
use function _\filter;
use function _\find;
class Book
{
public $files = [];
public function __construct($folder)
{
$this->read($folder);
}
public function read($folder)
public function __construct()
{
$folders = glob("$folder/*", GLOB_ONLYDIR);
foreach ($folders as $folder) {
//$this->files[] = $folder . "/";
$this->read($folder);
}
$files = array_filter(glob("$folder/*md"), "is_file");
foreach ($files as $file) {
$this->files[] = $file;
}
}
public function findPageById(string $uuid)
@ -274,49 +257,9 @@ class Book
}
public function getContents()
{
//move page collection to utiltiy class
$parser = new Parser();
$contents = [];
foreach ($this->files as $file) {
$doc = $parser->parse(file_get_contents($file), false);
$meta = $doc->getYAML();
$page = [
"id" => $meta["id"],
"uuid" => $meta["uuid"],
"title" => $meta["title"],
"feature" => $meta["feature"],
"path" => $meta["path"],
"layout" => $meta["layout"],
"tags" => $meta["tags"],
"author" => $meta["author"],
"created" => date("Y M D d", $meta["created"]),
"updated" => date("Y M D d", $meta["updated"]),
"rawCreated" => $meta["created"],
"rawUpdated" => $meta["updated"],
"createdYear" => date("Y", $meta["created"]),
"createdMonth" => date("m", $meta["created"]),
"deleted" => $meta["deleted"],
"menu" => $meta["menu"],
"featured" => $meta["featured"],
"published" => $meta["published"],
"slug" => $meta["slug"],
"filePath" => $file,
"content" => $doc->getContent(),
];
//checks for duplicates
$uuid = $meta["uuid"];
$found = current(
array_filter($contents, function ($item) use ($uuid) {
return isset($item["uuid"]) && $uuid == $item["uuid"];
})
);
// if uuid is not present, add it
if (!$found) {
array_push($contents, $page);
}
}
$contents = orderBy($contents, ["id"], ["desc"]);
//test new contents data class
//$new = (new Contents("../content/pages"))->getAll();
$contents = (new Contents("../content/pages"))->getAll();
return $contents;
}
}

@ -0,0 +1,120 @@
<?php
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
use League\CommonMark\Extension\Attributes\AttributesExtension;
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
use League\CommonMark\MarkdownConverter;
use League\CommonMark\CommonMarkConverter;
use function _\orderBy;
class Contents
{
public $files = [];
public $config = [];
public function __construct($folder)
{
$this->read($folder);
}
public function read($folder)
{
$folders = glob("$folder/*", GLOB_ONLYDIR);
foreach ($folders as $folder) {
//$this->files[] = $folder . "/";
$this->read($folder);
}
$files = array_filter(glob("$folder/*md"), "is_file");
foreach ($files as $file) {
$this->files[] = $file;
}
}
function getAll()
{
$environment = new Environment($this->config);
$environment->addExtension(new CommonMarkCoreExtension());
// Add the extension
$environment->addExtension(new FrontMatterExtension());
//Add Strikethrough rendering
$environment->addExtension(new StrikethroughExtension());
//add attributes to elements in markdown
$environment->addExtension(new AttributesExtension());
// Instantiate the converter engine and start converting some Markdown!
$converter = new MarkdownConverter($environment);
$contents = [];
foreach ($this->files as $file) {
//get meta and html from file
$result = $converter->convertToHtml(file_get_contents($file));
$meta = [];
if ($result instanceof RenderedContentWithFrontMatter) {
$meta = $result->getFrontMatter();
}
//get raw markdown from file
$frontMatterExtension = new FrontMatterExtension();
$parsed = $frontMatterExtension
->getFrontMatterParser()
->parse(file_get_contents($file));
//never trust the front end. clean it up
$sanitizer = HtmlSanitizer\Sanitizer::create([
"extensions" => ["basic", "image", "list", "code"],
"tags" => [
"img" => [
"allowed_attributes" => ["src", "alt", "title", "class"],
"allowed_hosts" => null,
"allow_relative_links" => true,
],
],
]);
$scrubbed = $sanitizer->sanitize($result->getContent());
//sort attributes into page object
$page = [
"id" => $meta["id"],
"uuid" => $meta["uuid"],
"title" => $meta["title"],
"feature" => $meta["feature"],
"path" => $meta["path"],
"layout" => $meta["layout"],
"tags" => $meta["tags"],
"author" => $meta["author"],
"created" => date("Y M D d", $meta["created"]),
"updated" => date("Y M D d", $meta["updated"]),
"rawCreated" => $meta["created"],
"rawUpdated" => $meta["updated"],
"createdYear" => date("Y", $meta["created"]),
"createdMonth" => date("m", $meta["created"]),
"deleted" => $meta["deleted"],
"menu" => $meta["menu"],
"featured" => $meta["featured"],
"published" => $meta["published"],
"slug" => $meta["slug"],
"filePath" => $file,
"content" => $parsed->getContent(),
"html" => $scrubbed,
];
//checks for duplicates
$uuid = $meta["uuid"];
$found = current(
array_filter($contents, function ($item) use ($uuid) {
return isset($item["uuid"]) && $uuid == $item["uuid"];
})
);
// if uuid is not present, add it
if (!$found) {
array_push($contents, $page);
}
}
$contents = orderBy($contents, ["id"], ["desc"]);
return $contents;
}
}

@ -69,129 +69,24 @@ class Render
public function renderPages()
{
$pages = (new Book("../content/pages"))->getContents();
$pages = (new Book())->getContents();
$recent = [];
$featured = [];
$limit = 4;
foreach ($pages as $page) {
//TODO: Plugin Sorting Class for page options
if (!$page["deleted"] && $page["published"]) {
if (count($recent) < $limit) {
array_push($recent, [
"path" => $page["path"],
"slug" => $page["slug"],
"title" => $page["title"],
"feature" => $page["feature"],
]);
}
if ($page["featured"] == true) {
if (count($featured) < $limit) {
array_push($featured, [
"path" => $page["path"],
"slug" => $page["slug"],
"title" => $page["title"],
"feature" => $page["feature"],
]);
}
}
$taglist = explode(",", $page["tags"]);
$tags = [];
foreach ($taglist as $tag) {
$label = trim($tag);
array_push($tags, [
"label" => $label . " ",
"slug" => StringTools::safeString($label),
]);
}
$meta = [
"who" => $page["author"],
"when" => $page["created"],
"tags" => $tags,
];
//render markdown content and clean it
$parser = new Parser();
$rendered = $parser->parse($page["content"]);
$sanitizer = HtmlSanitizer\Sanitizer::create([
"extensions" => ["basic", "image", "list", "code"],
"tags" => [
"img" => [
"allowed_attributes" => ["src", "alt", "title", "class"],
"allowed_hosts" => null,
"allow_relative_links" => true,
],
],
]);
$scrubbed = $sanitizer->sanitize($rendered->getContent());
//var_dump($scrubbed);
//just clean renderd string for now, Sanitize doesn't like relative img urls
//so another option is needed
$cleaned = strip_tags($rendered->getContent(), [
"a",
"br",
"p",
"strong",
"br",
"img",
"iframe",
"ul",
"li",
"i",
"em",
"h1",
"h2",
"h3",
"pre",
"code",
]);
//$cleaned = preg_replace('/(?:\r\n|[\r\n]){2,}/', "\n\n", $cleaned);
//$cleaned = html_entity_decode($cleaned, ENT_QUOTES, "UTF-8");
//if page feature isn't empty, replace page info meta image
if ($page["feature"] != "" || $page["feature"] != null) {
$this->pageInfo["image"] =
$this->pageInfo["baseURL"] . $page["feature"];
}
if ($page["layout"] == "index") {
$template = $this->theme . "/index.twig";
$location = "../public/index.html";
$dir = null;
//
$pageOptions = [
"title" => $page["title"],
"background" => $page["feature"],
"content" => $scrubbed,
"meta" => $meta,
"recent" => $recent,
"featured" => $featured,
"info" => $this->pageInfo,
"menu" => $this->menu,
];
} else {
$template = $this->theme . "/" . $page["layout"] . ".twig";
$location =
"../public/" . $page["path"] . "/" . $page["slug"] . ".html";
$dir = "../public/" . $page["path"];
$pageOptions = [
"title" => $page["title"],
"background" => $page["feature"],
"content" => $cleaned,
"meta" => $meta,
"info" => $this->pageInfo,
"menu" => $this->menu,
];
}
$html = $this->twig->render($template, $pageOptions);
DocTools::writeHTML($location, $html, $dir);
$pageOptions = Sorting::page($page);
$template = $this->theme . "/" . $page["layout"] . ".twig";
if (str_contains($page["layout"], "index")) {
$location = "../public/index.html";
$dir = null;
} else {
$location =
"../public/" . $page["path"] . "/" . $page["slug"] . ".html";
$dir = "../public/" . $page["path"];
}
$html = $this->twig->render($template, $pageOptions);
DocTools::writeHTML($location, $html, $dir);
}
}
@ -247,7 +142,8 @@ class Render
public function renderIndex()
{
$pages = (new Book("../content/pages"))->getContents();
//TODO: Need to fix this to account for new index templating system
$pages = (new Book())->getContents();
$index = find($pages, ["layout" => "index"]);
$template = $this->theme . "/index.twig";
$location = "../public/index.html";

@ -179,7 +179,7 @@ class Sorting
$recent = [];
$featured = [];
$limit = 4;
$pages = (new Book("../content/pages"))->getContents();
$pages = (new Book())->getContents();
foreach ($pages as $item) {
if (!$item["deleted"] && $item["published"]) {
if (count($recent) < $limit) {
@ -205,7 +205,7 @@ class Sorting
$pageOptions = [
"title" => $page["title"],
"background" => $page["feature"],
"content" => $cleaned,
"content" => $page["html"], //$cleaned,
"meta" => $meta,
"recent" => $recent,
"featured" => $featured,
@ -220,7 +220,7 @@ class Sorting
$pageOptions = [
"title" => $page["title"],
"background" => $page["feature"],
"content" => $cleaned,
"content" => $page["html"], //$cleaned,
"meta" => $meta,
"info" => $pageInfo,
"menu" => $settings["menu"],

@ -24,6 +24,8 @@
"rbdwllr/reallysimplejwt": "^4.0",
"fightbulc/moment": "^1.33",
"tgalopin/html-sanitizer": "^1.4",
"phpmailer/phpmailer": "^6.4"
"phpmailer/phpmailer": "^6.4",
"league/commonmark": "^2.1",
"symfony/yaml": "^5.4"
}
}

479
composer.lock generated

@ -4,8 +4,83 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "24c8af725f56866613f3d512ed306db4",
"content-hash": "aaecaa98ed680188418b8aff96553235",
"packages": [
{
"name": "dflydev/dot-access-data",
"version": "v3.0.1",
"source": {
"type": "git",
"url": "https://github.com/dflydev/dflydev-dot-access-data.git",
"reference": "0992cc19268b259a39e86f296da5f0677841f42c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/0992cc19268b259a39e86f296da5f0677841f42c",
"reference": "0992cc19268b259a39e86f296da5f0677841f42c",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.42",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.3",
"scrutinizer/ocular": "1.6.0",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^3.14"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Dflydev\\DotAccessData\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dragonfly Development Inc.",
"email": "info@dflydev.com",
"homepage": "http://dflydev.com"
},
{
"name": "Beau Simensen",
"email": "beau@dflydev.com",
"homepage": "http://beausimensen.com"
},
{
"name": "Carlos Frutos",
"email": "carlos@kiwing.it",
"homepage": "https://github.com/cfrutos"
},
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com"
}
],
"description": "Given a deep data structure, access data by dot notation.",
"homepage": "https://github.com/dflydev/dflydev-dot-access-data",
"keywords": [
"access",
"data",
"dot",
"notation"
],
"support": {
"issues": "https://github.com/dflydev/dflydev-dot-access-data/issues",
"source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.1"
},
"time": "2021-08-13T13:06:58+00:00"
},
{
"name": "erusev/parsedown",
"version": "1.7.4",
@ -169,6 +244,191 @@
},
"time": "2021-03-27T13:10:08+00:00"
},
{
"name": "league/commonmark",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "819276bc54e83c160617d3ac0a436c239e479928"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/819276bc54e83c160617d3ac0a436c239e479928",
"reference": "819276bc54e83c160617d3ac0a436c239e479928",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"league/config": "^1.1.1",
"php": "^7.4 || ^8.0",
"psr/event-dispatcher": "^1.0",
"symfony/polyfill-php80": "^1.15"
},
"require-dev": {
"cebe/markdown": "^1.0",
"commonmark/cmark": "0.30.0",
"commonmark/commonmark.js": "0.30.0",
"composer/package-versions-deprecated": "^1.8",
"erusev/parsedown": "^1.0",
"ext-json": "*",
"github/gfm": "0.29.0",
"michelf/php-markdown": "^1.4",
"phpstan/phpstan": "^0.12.88 || ^1.0.0",
"phpunit/phpunit": "^9.5.5",
"scrutinizer/ocular": "^1.8.1",
"symfony/finder": "^5.3",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0",
"unleashedtech/php-coding-standard": "^3.1",
"vimeo/psalm": "^4.7.3"
},
"suggest": {
"symfony/yaml": "v2.3+ required if using the Front Matter extension"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.2-dev"
}
},
"autoload": {
"psr-4": {
"League\\CommonMark\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
}
],
"description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)",
"homepage": "https://commonmark.thephpleague.com",
"keywords": [
"commonmark",
"flavored",
"gfm",
"github",
"github-flavored",
"markdown",
"md",
"parser"
],
"support": {
"docs": "https://commonmark.thephpleague.com/",
"forum": "https://github.com/thephpleague/commonmark/discussions",
"issues": "https://github.com/thephpleague/commonmark/issues",
"rss": "https://github.com/thephpleague/commonmark/releases.atom",
"source": "https://github.com/thephpleague/commonmark"
},
"funding": [
{
"url": "https://www.colinodell.com/sponsor",
"type": "custom"
},
{
"url": "https://www.paypal.me/colinpodell/10.00",
"type": "custom"
},
{
"url": "https://github.com/colinodell",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/league/commonmark",
"type": "tidelift"
}
],
"time": "2021-12-05T18:25:20+00:00"
},
{
"name": "league/config",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/config.git",
"reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/config/zipball/a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e",
"reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e",
"shasum": ""
},
"require": {
"dflydev/dot-access-data": "^3.0.1",
"nette/schema": "^1.2",
"php": "^7.4 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.90",
"phpunit/phpunit": "^9.5.5",
"scrutinizer/ocular": "^1.8.1",
"unleashedtech/php-coding-standard": "^3.1",
"vimeo/psalm": "^4.7.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.2-dev"
}
},
"autoload": {
"psr-4": {
"League\\Config\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
}
],
"description": "Define configuration arrays with strict schemas and access values with dot notation",
"homepage": "https://config.thephpleague.com",
"keywords": [
"array",
"config",
"configuration",
"dot",
"dot-access",
"nested",
"schema"
],
"support": {
"docs": "https://config.thephpleague.com/",
"issues": "https://github.com/thephpleague/config/issues",
"rss": "https://github.com/thephpleague/config/releases.atom",
"source": "https://github.com/thephpleague/config"
},
"funding": [
{
"url": "https://www.colinodell.com/sponsor",
"type": "custom"
},
{
"url": "https://www.paypal.me/colinpodell/10.00",
"type": "custom"
},
{
"url": "https://github.com/colinodell",
"type": "github"
}
],
"time": "2021-08-14T12:15:32+00:00"
},
{
"name": "league/uri-parser",
"version": "1.4.1",
@ -401,6 +661,153 @@
},
"time": "2020-12-04T10:52:19+00:00"
},
{
"name": "nette/schema",
"version": "v1.2.2",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/9a39cef03a5b34c7de64f551538cbba05c2be5df",
"reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df",
"shasum": ""
},
"require": {
"nette/utils": "^2.5.7 || ^3.1.5 || ^4.0",
"php": ">=7.1 <8.2"
},
"require-dev": {
"nette/tester": "^2.3 || ^2.4",
"phpstan/phpstan-nette": "^0.12",
"tracy/tracy": "^2.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "📐 Nette Schema: validating data structures against a given Schema.",
"homepage": "https://nette.org",
"keywords": [
"config",
"nette"
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.2.2"
},
"time": "2021-10-15T11:40:02+00:00"
},
{
"name": "nette/utils",
"version": "v3.2.6",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "2f261e55bd6a12057442045bf2c249806abc1d02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/2f261e55bd6a12057442045bf2c249806abc1d02",
"reference": "2f261e55bd6a12057442045bf2c249806abc1d02",
"shasum": ""
},
"require": {
"php": ">=7.2 <8.2"
},
"conflict": {
"nette/di": "<3.0.6"
},
"require-dev": {
"nette/tester": "~2.0",
"phpstan/phpstan": "^1.0",
"tracy/tracy": "^2.3"
},
"suggest": {
"ext-gd": "to use Image",
"ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
"ext-json": "to use Nette\\Utils\\Json",
"ext-mbstring": "to use Strings::lower() etc...",
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
"homepage": "https://nette.org",
"keywords": [
"array",
"core",
"datetime",
"images",
"json",
"nette",
"paginator",
"password",
"slugify",
"string",
"unicode",
"utf-8",
"utility",
"validation"
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v3.2.6"
},
"time": "2021-11-24T15:47:23+00:00"
},
{
"name": "nikic/fast-route",
"version": "v1.3.0",
@ -582,6 +989,56 @@
},
"time": "2021-11-05T16:47:00+00:00"
},
{
"name": "psr/event-dispatcher",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/event-dispatcher.git",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
"shasum": ""
},
"require": {
"php": ">=7.2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\EventDispatcher\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Standard interfaces for event handling.",
"keywords": [
"events",
"psr",
"psr-14"
],
"support": {
"issues": "https://github.com/php-fig/event-dispatcher/issues",
"source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
},
"time": "2019-01-08T18:20:26+00:00"
},
{
"name": "psr/http-factory",
"version": "1.0.1",
@ -2225,28 +2682,28 @@
},
{
"name": "symfony/yaml",
"version": "v5.3.6",
"version": "v5.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7"
"reference": "b9eb163846a61bb32dfc147f7859e274fab38b58"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7",
"reference": "4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7",
"url": "https://api.github.com/repos/symfony/yaml/zipball/b9eb163846a61bb32dfc147f7859e274fab38b58",
"reference": "b9eb163846a61bb32dfc147f7859e274fab38b58",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1",
"symfony/polyfill-ctype": "~1.8"
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"symfony/console": "<4.4"
"symfony/console": "<5.3"
},
"require-dev": {
"symfony/console": "^4.4|^5.0"
"symfony/console": "^5.3|^6.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
@ -2280,7 +2737,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v5.3.6"
"source": "https://github.com/symfony/yaml/tree/v5.4.2"
},
"funding": [
{
@ -2296,7 +2753,7 @@
"type": "tidelift"
}
],
"time": "2021-07-29T06:20:01+00:00"
"time": "2021-12-16T21:58:21+00:00"
},
{
"name": "tgalopin/html-sanitizer",

@ -24,7 +24,7 @@
</span>
{% for page in data.pages %}
{% if dynamicRender is defined %}
{% if dynamicRender %}
{% if dynamicRender == 'true' %}
<a href="{{ "/"~item.year~"/"~data.month~"/"~page.slug }}">{{page.title}}</a><br />
{% else %}
<a href="{{ "/"~item.year~"/"~data.month~"/"~page.slug~".html" }}">{{page.title}}</a><br />

@ -35,7 +35,7 @@
{% if menu is defined %}
{% for link in menu %}
{% if dynamicRender is defined %}
{% if dynamicRender %}
{% if dynamicRender == 'true' %}
<a href="{{"/"~link.path~"/"~link.slug}}" class="menu-link">{{link.title}}</a><br />
{% else %}
<a href="{{"/"~link.path~"/"~link.slug~".html"}}" class="menu-link">{{link.title}}</a><br />
@ -60,7 +60,7 @@
<footer>
<div class="inner">
{% if dynamicRender is defined %}
{% if dynamicRender %}
{% if dynamicRender == 'true' %}
<a href="/archives">Archives</a><br />
{% else %}
<a href="/archives.html">Archives</a><br />

@ -18,7 +18,7 @@
<span>RECENT</span><br />
{% for item in recent %}
{% if dynamicRender is defined %}
{% if dynamicRender %}
{% if dynamicRender == 'true' %}
<a href="{{ "/"~item.path~"/"~item.slug}}"> {{item.title}} </a><br />
{% else %}
<a href="{{ "/"~item.path~"/"~item.slug~".html" }}"> {{item.title}} </a><br />
@ -34,7 +34,7 @@
<span>FEATURED</span><br />
{% for item in featured %}
{% if dynamicRender is defined %}
{% if dynamicRender %}
{% if dynamicRender == 'true' %}
<a href="{{ "/"~item.path~"/"~item.slug}}"> {{item.title}} </a><br />
{% else %}
<a href="{{ "/"~item.path~"/"~item.slug~".html" }}"> {{item.title}} </a><br />

@ -20,7 +20,7 @@
<strong>tags: </strong>
{% for tag in meta['tags'] %}
{% if dynamicRender is defined %}
{% if dynamicRender %}
{% if dynamicRender == 'true' %}
<a href="{{ "/tags/"~tag.slug }}">{{ tag.label }}</a>
{% else %}
<a href="{{ "/tags/"~tag.slug~".html" }}">{{ tag.label }}</a>

@ -19,7 +19,7 @@
<strong>tags: </strong>
{% for tag in meta['tags'] %}
{% if dynamicRender is defined %}
{% if dynamicRender %}
{% if dynamicRender == 'false' %}
<a href="{{ "/tags/"~tag.slug }}">{{ tag.label }}</a>
{% else %}
<a href="{{ "/tags/"~tag.slug~".html" }}">{{ tag.label }}</a>

@ -14,7 +14,7 @@
<div class="page">
{% for tag in tag_list %}
{% if dynamicRender is defined %}
{% if dynamicRender %}
{% if dynamicRender == 'true' %}
<a href="{{"/"~tag.path~"/"~tag.slug}}">{{tag.title}}</a><br />
{% else %}
<a href="{{"/"~tag.path~"/"~tag.slug~".html"}}">{{tag.title}}</a><br />

Loading…
Cancel
Save