mirror of
https://github.com/YunoHost/doc.git
synced 2024-09-03 20:06:26 +02:00
381 lines
13 KiB
PHP
381 lines
13 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Presentation Plugin, Content API
|
||
|
*
|
||
|
* PHP version 7
|
||
|
*
|
||
|
* @category API
|
||
|
* @package Grav\Plugin\PresentationPlugin
|
||
|
* @subpackage Grav\Plugin\PresentationPlugin\API
|
||
|
* @author Ole Vik <git@olevik.net>
|
||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||
|
* @link https://github.com/OleVik/grav-plugin-presentation
|
||
|
*/
|
||
|
|
||
|
namespace Grav\Plugin\PresentationPlugin\API;
|
||
|
|
||
|
use Grav\Common\Utils;
|
||
|
use Michelf\SmartyPants;
|
||
|
|
||
|
/**
|
||
|
* Content API
|
||
|
*
|
||
|
* Content API for aggregating content
|
||
|
*
|
||
|
* @category Extensions
|
||
|
* @package Grav\Plugin\PresentationPlugin\API
|
||
|
* @author Ole Vik <git@olevik.net>
|
||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||
|
* @link https://github.com/OleVik/grav-plugin-presentation
|
||
|
*/
|
||
|
class Content implements ContentInterface
|
||
|
{
|
||
|
/**
|
||
|
* Regular expressions
|
||
|
*/
|
||
|
const REGEX_FRAGMENT_SHORTCODE = '~\[fragment=*"*([a-zA-Z-]*)"*\](.*)"*\[\/fragment\]~im';
|
||
|
const REGEX_P_EMPTY = '/<p[^>]*>\n* *<\/p[^>]*>/im';
|
||
|
|
||
|
/**
|
||
|
* Instantiate Content API
|
||
|
*
|
||
|
* @param Grav $grav Grav-instance
|
||
|
* @param array $config Plugin configuration
|
||
|
* @param Parser $parser Parser utility
|
||
|
* @param Transport $transport Transport API
|
||
|
*/
|
||
|
public function __construct($grav, $config, $parser, $transport)
|
||
|
{
|
||
|
$this->grav = $grav;
|
||
|
$this->config = $config;
|
||
|
$this->parser = $parser;
|
||
|
$this->transport = $transport;
|
||
|
if ($this->grav['config']->get('system.pages.markdown.extra')) {
|
||
|
$this->parsedown = new \ParsedownExtra();
|
||
|
} else {
|
||
|
$this->parsedown = new \Parsedown();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates page-structure recursively
|
||
|
*
|
||
|
* @param string $route Route to page
|
||
|
* @param string $mode Reserved collection-mode for handling child-pages
|
||
|
* @param integer $depth Reserved placeholder for recursion depth
|
||
|
*
|
||
|
* @return array Page-structure with children
|
||
|
*/
|
||
|
public function buildTree(string $route, $mode = false, $depth = 0)
|
||
|
{
|
||
|
$page = $this->grav['page'];
|
||
|
$depth++;
|
||
|
$mode = '@page.self';
|
||
|
|
||
|
$config = $this->config;
|
||
|
if (isset($page->header()->Reveal)) {
|
||
|
$config = array_merge($config, $page->header()->Reveal);
|
||
|
}
|
||
|
if ($depth > 1) {
|
||
|
$mode = '@page.children';
|
||
|
}
|
||
|
$pages = $page->evaluate([$mode => $route]);
|
||
|
$pages = $pages->published()->order(
|
||
|
$config['order']['by'],
|
||
|
$config['order']['dir']
|
||
|
);
|
||
|
$paths = array();
|
||
|
foreach ($pages as $page) {
|
||
|
$route = $page->rawRoute();
|
||
|
$paths[$route]['depth'] = $depth;
|
||
|
$paths[$route]['title'] = $page->title();
|
||
|
$paths[$route]['menu'] = array(
|
||
|
'anchor' => $page->slug(),
|
||
|
'title' => $page->title()
|
||
|
);
|
||
|
$paths[$route]['route'] = $route;
|
||
|
$paths[$route]['slug'] = $page->slug();
|
||
|
$paths[$route]['path'] = $page->path();
|
||
|
$paths[$route]['header'] = $page->header();
|
||
|
if (isset($page->header()->type)) {
|
||
|
$paths[$route]['type'] = $page->header()->type;
|
||
|
}
|
||
|
if (isset($config['footer'])) {
|
||
|
$paths[$route]['footer'] = $config['footer'];
|
||
|
}
|
||
|
if (isset($page->header()->footer)) {
|
||
|
$paths[$route]['footer'] = $page->header()->footer;
|
||
|
}
|
||
|
if (!empty($paths[$route]['footer'])) {
|
||
|
$paths[$route]['footer'] = $this->grav['twig']->processTemplate(
|
||
|
$paths[$route]['footer'],
|
||
|
['page' => $page]
|
||
|
);
|
||
|
}
|
||
|
if (isset($this->config['process']) && $this->config['process'] == "markdown") {
|
||
|
$paths[$route]['content'] = $page->rawMarkdown();
|
||
|
} else {
|
||
|
$paths[$route]['content'] = $page->content();
|
||
|
}
|
||
|
if (!empty($paths[$route])) {
|
||
|
$children = $this->buildTree($route, $mode, $depth);
|
||
|
if (!empty($children)) {
|
||
|
$paths[$route]['children'] = $children;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (isset($config['styles'])
|
||
|
&& is_array($config['styles'])
|
||
|
&& !empty($config['styles'])
|
||
|
) {
|
||
|
foreach ($config['styles'] as $property => $value) {
|
||
|
$this->parser->styleProcessor($page->slug(), $property, $value);
|
||
|
}
|
||
|
}
|
||
|
if (!empty($paths)) {
|
||
|
return $paths;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create HTML to use with Reveal.js
|
||
|
*
|
||
|
* @param array $pages Page-structure with children
|
||
|
*
|
||
|
* @return string HTML-structure
|
||
|
*/
|
||
|
public function buildContent(array $pages)
|
||
|
{
|
||
|
include_once __DIR__ . '/../vendor/autoload.php';
|
||
|
$return = '';
|
||
|
foreach ($pages as $route => $page) {
|
||
|
ob_start();
|
||
|
$styleIndex = 0;
|
||
|
$styles = array();
|
||
|
$config = $this->config;
|
||
|
$config['route'] = $route;
|
||
|
$content = $page['content'];
|
||
|
if (preg_match(self::REGEX_FRAGMENT_SHORTCODE, $content)) {
|
||
|
$content = $this->processFragments($content);
|
||
|
}
|
||
|
if (isset($this->config['process']) && $this->config['process'] == "markdown") {
|
||
|
$content = $this->parsedown->text($content);
|
||
|
}
|
||
|
$breaks = explode('<hr />', $content);
|
||
|
if (count($breaks) > 0) {
|
||
|
$this->breakContent($page, $config, $breaks);
|
||
|
} else {
|
||
|
echo '<section>';
|
||
|
echo $content;
|
||
|
if (isset($page['footer'])) {
|
||
|
echo $page['footer'];
|
||
|
}
|
||
|
echo '</section>';
|
||
|
}
|
||
|
|
||
|
if (isset($page['header']->Reveal)) {
|
||
|
$config = array_merge($config, $page['header']->Reveal);
|
||
|
}
|
||
|
$return .= ob_get_contents();
|
||
|
ob_end_clean();
|
||
|
if (isset($page['children'])) {
|
||
|
$return .= $this->buildContent($page['children']);
|
||
|
}
|
||
|
}
|
||
|
return $return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create HTML from content
|
||
|
*
|
||
|
* @param array $page Grav Page-instance
|
||
|
* @param array $config Plugin- and slide-configuration
|
||
|
* @param array $breaks Slides from Markdown
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function breakContent(array $page, array $config, array $breaks)
|
||
|
{
|
||
|
$header = (array) $page['header'];
|
||
|
$horizontal = false;
|
||
|
if (isset($config['horizontal'])) {
|
||
|
$horizontal = $config['horizontal'];
|
||
|
}
|
||
|
if (isset($header['horizontal'])) {
|
||
|
$horizontal = $header['horizontal'];
|
||
|
}
|
||
|
if ($horizontal != true) {
|
||
|
echo '<section id="' . $page['slug'] . '" ';
|
||
|
echo 'data-title="' . $page['title'] . '">';
|
||
|
}
|
||
|
$index = 0;
|
||
|
foreach ($breaks as $break) {
|
||
|
$config['id'] = $page['slug'] . '-' . $index;
|
||
|
$config['class'] = '';
|
||
|
$hide = false;
|
||
|
$config['styles'] = array();
|
||
|
if ($this->config['unwrap_images']) {
|
||
|
$break = $this->parser::unwrapImage($break);
|
||
|
}
|
||
|
if (isset($page['header']->style)) {
|
||
|
$config['styles'] = array_merge(
|
||
|
$config['styles'],
|
||
|
$page['header']->style
|
||
|
);
|
||
|
}
|
||
|
if (isset($config['textsizing'])) {
|
||
|
if (isset($config['textsize']['scale'])) {
|
||
|
$config['class'] .= ' textsizing';
|
||
|
$scale = $config['textsize']['scale'];
|
||
|
}
|
||
|
if (isset($page['header']->textsize['scale'])) {
|
||
|
$config['class'] .= ' textsizing';
|
||
|
$scale = $page['header']->textsize['scale'];
|
||
|
}
|
||
|
if (isset($config['textsize']['modifier'])) {
|
||
|
$modifier = (float) $config['textsize']['modifier'];
|
||
|
}
|
||
|
if (isset($page['header']->textsize['modifier'])) {
|
||
|
$modifier = (float) $page['header']->textsize['modifier'];
|
||
|
}
|
||
|
if (!empty($scale) && !empty($modifier)) {
|
||
|
$this->parser->setModularScale(
|
||
|
$config['id'],
|
||
|
$scale ?? 1.25,
|
||
|
$modifier ?? 1
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
if (isset($page['header']->class) && !empty($page['header']->class)) {
|
||
|
foreach ($page['header']->class as $item) {
|
||
|
$config['class'] .= ' ' . $item;
|
||
|
}
|
||
|
}
|
||
|
if ($hide !== true) {
|
||
|
if ($horizontal == true) {
|
||
|
echo '<section>';
|
||
|
}
|
||
|
$this->buildSlide($page, $config, $break);
|
||
|
if ($horizontal == true) {
|
||
|
echo '</section>';
|
||
|
}
|
||
|
}
|
||
|
$index++;
|
||
|
}
|
||
|
if ($horizontal != true) {
|
||
|
echo '</section>';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create HTML for slides
|
||
|
*
|
||
|
* @param array $page Grav Page-instance
|
||
|
* @param array $config Plugin- and slide-configuration
|
||
|
* @param string $break Slides from Markdown
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function buildSlide(array $page, array $config, string $break)
|
||
|
{
|
||
|
$styles = $page['header']->style ??
|
||
|
$page['header']->styles ??
|
||
|
$page['header']->presentation['style'] ??
|
||
|
$page['header']->presentation['styles'] ??
|
||
|
[];
|
||
|
if (!empty($styles) && is_array($styles) && Utils::arrayIsAssociative($styles)) {
|
||
|
foreach ($styles as $property => $value) {
|
||
|
$this->parser->styleProcessor($config['id'], $property, $value, $page);
|
||
|
}
|
||
|
}
|
||
|
if ($config['shortcodes']) {
|
||
|
$break = self::pushNotes($break);
|
||
|
$shortcodes = $this->parser->processShortcodes($break, $config['id'], $page);
|
||
|
$break = $shortcodes['content'];
|
||
|
$break = SmartyPants::defaultTransform($break);
|
||
|
if ($this->transport->getDataAttribute($config['id'], 'data-hide')) {
|
||
|
$hide = true;
|
||
|
}
|
||
|
}
|
||
|
echo '<section id="' . $config['id'] . '" ';
|
||
|
if ($this->transport->getClasses($config['id'])) {
|
||
|
echo 'class="' . $this->transport->getClasses($config['id']) . '" ';
|
||
|
}
|
||
|
echo 'data-title="' . $page['title'] . '"';
|
||
|
if (isset($page['header']->textsize['scale'])) {
|
||
|
echo ' data-textsize-scale="' . (float) $page['header']->textsize['scale'] . '"';
|
||
|
if (isset($page['header']->textsize['modifier'])) {
|
||
|
echo ' data-textsize-modifier="' . (float) $page['header']->textsize['modifier'] . '"';
|
||
|
}
|
||
|
}
|
||
|
if (!empty($this->transport->getAriaAttributes($config['id']))) {
|
||
|
echo $this->transport->getAriaAttributes($config['id']);
|
||
|
}
|
||
|
if (!empty($this->transport->getDataAttributes($config['id']))) {
|
||
|
echo $this->transport->getDataAttributes($config['id']);
|
||
|
}
|
||
|
echo '>';
|
||
|
$break = preg_replace(self::REGEX_P_EMPTY, '', $break);
|
||
|
echo $break;
|
||
|
if (isset($page['footer'])) {
|
||
|
echo $page['footer'];
|
||
|
}
|
||
|
echo '</section>';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create HTML for fragments
|
||
|
*
|
||
|
* @param string $content Markdown content in Page
|
||
|
*
|
||
|
* @return string Processed contents
|
||
|
*/
|
||
|
public function processFragments(string $content)
|
||
|
{
|
||
|
$content = preg_replace(
|
||
|
self::REGEX_FRAGMENT_SHORTCODE,
|
||
|
'<span class="fragment \\1">\\2</span>',
|
||
|
$content
|
||
|
);
|
||
|
return $content;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create HTML from Notes-shortcodes
|
||
|
*
|
||
|
* @param string $content Markdown content in Page
|
||
|
*
|
||
|
* @return string Processed content
|
||
|
*/
|
||
|
public function pushNotes(string $content)
|
||
|
{
|
||
|
$content = str_replace('[notes]', '<aside class="notes">', $content);
|
||
|
$content = str_replace('[/notes]', '</aside>', $content);
|
||
|
return $content;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generate menu with anchors and titles from pages
|
||
|
*
|
||
|
* @param array $tree Page-structure with children
|
||
|
*
|
||
|
* @return array Slide-anchors with titles
|
||
|
*/
|
||
|
public function buildMenu(array $tree)
|
||
|
{
|
||
|
$items = array();
|
||
|
foreach ($tree as $key => $value) {
|
||
|
if (is_array($value['menu'])) {
|
||
|
$items[$value['menu']['anchor']] = $value['menu']['title'];
|
||
|
}
|
||
|
if (isset($value['children'])) {
|
||
|
$items[] = $this->buildMenu($value['children']);
|
||
|
}
|
||
|
}
|
||
|
return $items;
|
||
|
}
|
||
|
}
|