load(); $this->shareCommonDataWithView(); } public function getSubBundles() { if (!isset($this->subBundles)) { $this->subBundles = $this->collectSubBundles(); } return $this->subBundles; } /** * Renders a complete HTML view of the bundle */ public function render() { $cacheKey = sprintf('render_%s', Str::slug($this->bundle->getPath())); return Cache::rememberForever($cacheKey, function () { $result = []; $totalPages = count(array_chunk($this->getSubBundles(), config('pagination.itemsPerPage'))); if ($totalPages > 1) { for ($currentPage = 1; $currentPage <= $totalPages; $currentPage++) { $this->prepareRender($currentPage); if ($currentPage === 1) { $result[$this->bundle->getPath()] = $this->renderPage(); } $page = sprintf('%spage/%s/', $this->bundle->getPath(), $currentPage); $result[$page] = $this->renderPage(); } } else { $this->prepareRender(1); $result[$this->bundle->getPath()] = $this->renderPage(); } return $result; }); } /** * Renders a card HTML view of the bundle, suitable to display in lists */ public function renderCard() { $this->prepareRenderCard(); return $this->renderView('article-card'); } /** * Return an instance of the creator, using specified data as input */ public static function make(Bundle $bundle): RendersBundle { return new static($bundle); } /** * Renders a complete HTML view of the bundle */ protected function prepareRender(int $currentPage = 1) { $this->bundle->markdown()->lint(); $coverRef = $this->bundle->metadata()->get('cover'); $cover = null; if (!empty($coverRef)) { $cover = $this->bundle->attachments(AttachmentsManager::Images)->getComponentByRef($coverRef, 'article'); } $date = $this->bundle->metadata()->get('date'); if (!empty($date)) { data_set($this->viewData, 'date', Carbon::parse($date)); } data_set($this->viewData, 'cover', $cover ? $cover->render() : null); data_set($this->viewData, 'body', $this->bundle->markdown()->render()); data_set($this->viewData, 'feedIsValid', Cache::get('feed_is_valid', false)); data_set($this->viewData, 'cssIsValid', Cache::get('css_is_valid', false)); if ($currentPage === 1) { $path = $this->bundle->getPath(); } else { $path = sprintf('%spage/%s/', $this->bundle->getPath(), $currentPage); } $cacheKey = sprintf('html_is_valid_%s', Str::slug($path)); data_set($this->viewData, 'htmlIsValid', Cache::get($cacheKey, false)); $this->handlePagination($currentPage); } /** * Renders a HTML card view of the bundle */ protected function prepareRenderCard() { $coverRef = $this->bundle->metadata()->get('cover'); $cover = null; if (!empty($coverRef)) { $cover = $this->bundle->attachments(AttachmentsManager::Images)->getComponentByRef($coverRef, 'listitem', ['nolink' => true]); } $date = $this->bundle->metadata()->get('date'); if (!empty($date)) { data_set($this->viewData, 'date', Carbon::parse($date)); } data_set($this->viewData, 'cover', $cover ? $cover->render() : null); data_set($this->viewData, 'section', $this->bundle->getSection()); } /** * Pre-fill view with data used by all renderers */ protected function shareCommonDataWithView(): void { data_set($this->viewData, 'siteTitle', $this->bundle->getSiteTitle()); data_set($this->viewData, 'articleTitle', $this->bundle->getArticleTitle()); data_set($this->viewData, 'bundle', $this->bundle); if (!empty($this->bundle->metadata('metadata')->get('Liens.Page originale'))) { $url = $this->bundle->metadata('metadata')->get('Liens.Page originale')[0]; $link = (new Link($url, null, $this->bundle))->toArray(); $link['url'] = $url; data_set($this->viewData, 'mainLink', $link); } } protected function handlePagination(int $currentPage = 1) { $itemsPerPage = config('pagination.itemsPerPage'); $subBundles = $this->getSubBundles(); if (!$this->bundle->exists() && empty($subBundles)) { throw new Exception(sprintf( 'Page %s does not exist in bundle %s', $this->bundle->getCurrentPage(), $this->bundle->getPath() )); } $totalPages = 1; if (!empty($subBundles)) { $chunks = array_chunk($subBundles, $itemsPerPage); if (!array_key_exists($currentPage - 1, $chunks) && $currentPage > 1) { throw new Exception(sprintf( 'Page %s does not exist in bundle %s', $currentPage - 1, $this->bundle->getPath() )); } $currentChunk = $chunks[$currentPage - 1]; $totalPages = count($chunks); } else { $currentChunk = []; } $bundles = []; if (!empty($currentChunk)) { $bundles = array_map(fn (string $path) => new Bundle($path, $this->bundle->getDisk()), $currentChunk); } $data = [ 'root' => $this->bundle->getPath(), 'itemsPerPage' => $itemsPerPage, 'currentPage' => $currentPage, 'totalPages' => $totalPages, 'items' => $bundles, ]; data_set($this->viewData, 'pagination', $data); $this->handleFilters($subBundles); } protected function handleFilters($subBundles) { } protected function collectSubBundles() { $subBundles = Bundle::findBundles($this->bundle->getDisk(), $this->bundle->getPath(), true); $subBundles = collect($subBundles) ->filter(fn (Bundle $bundle) => !empty($bundle->metadata()->get('date')) && $bundle->getPath() !== $this->bundle->getPath()) ->sort(function (Bundle $bundleA, Bundle $bundleB) { return Carbon::parse($bundleA->metadata()->get('date'))->lt(Carbon::parse($bundleB->metadata()->get('date'))); }) ->map(fn (Bundle $bundle) => $bundle->getPath()) ->toArray(); return $subBundles; } /** * Renders a full-page. Validates HTML */ protected function renderPage(?string $view = 'article') { $html = $this->renderView($view); $html5 = new HTML5([ // Required to use xpath, see // https://github.com/Masterminds/html5-php/issues/123 'disable_html_ns' => true, ]); $dom = $html5->loadHTML($html); $xpath = new DOMXPath($dom); $spans = $xpath->query('//pre/code/span[@class="line" and normalize-space(.) = ""]'); foreach ($spans as $span) { if ($span->isSameNode($span->parentNode->lastChild)) { $span->parentNode->removeChild($span); } } $html = $html5->saveHTML($dom); return $html; } /** * Render specific view */ protected function renderView(string $view) { return (string) view($view, $this->viewData); } }