Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions config/vufind/Notices.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ styles:
# classes: my-custom-css-class my-other-custom-css-class

# Notices can be configured here. You can use the following options:
# - content: The message to be displayed.
# - translations: To support multiple languages use this option instead of content.
# - content: The message to be displayed. It can be translated using the language files.
# - translations: To configure multiple languages in this file use this option instead of content.
# This is an associative array. Keys are language codes and values are
# the translated messages. The notices will only be displayed if the selected language
# is included in the keys. If the value is left empty the translation will be chosen
# based on the language fallback configuration in config.ini.
# - contentType: Specifies how the messages should be displayed. The default is "text". The options are
# - "text": The message will be display as is. HTML will be escaped.
# - "html": HTML in messages will not be escaped.
# - "markdown": Messages will be rendered using Markdown.
# - style: Specifies one of the styles above.
# - position: Specifies the position of the notice. By default, the notices are displayed above the main content.
# Currently, the only other option that is available is "header", but you can add more possible position
Expand All @@ -31,3 +35,18 @@ notices:
# de: Willkommen in unserem Katalog!
# es:
# en: Welcome to our catalog!
# Example 3
# - style: info
# content: >
# ## This is the catalog of our library
#
# -------------------------------------
#
# You can
#
# * **search** for books
#
# * **request** books
#
# * create **favorite** lists
# contentType: markdown
79 changes: 52 additions & 27 deletions module/VuFind/src/VuFind/View/Helper/Root/Content.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@

namespace VuFind\View\Helper\Root;

use Laminas\View\Helper\AbstractHelper;
use Laminas\View\Exception\InvalidArgumentException;
use Laminas\View\Helper\EscapeHtml;
use VuFind\ContentBlock\TemplateBased;
use VuFind\ServiceManager\Factory\Autowire;

/**
* Content View Helper to resolve translated pages.
Expand All @@ -43,44 +45,46 @@
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/
class Content extends AbstractHelper
class Content
{
/**
* TemplateBased instance to resolve translated pages.
*
* @var TemplateBased
*/
protected $templateBasedBlock;

/**
* Context View Helper instance to resolve translated pages.
* Constructor
*
* @var Context
* @param TemplateBased $templateBasedBlock TemplateBased instance to resolve translated pages.
* @param Context $contextHelper Context View Helper instance to resolve translated pages.
* @param EscapeHtml $escapeHtmlHelper Escape HTML view helper
* @param Markdown $markdownHelper Markdown view helper
*/
protected $contextHelper;
public function __construct(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably target this branch against dev-12.0 due to the BC-breaking changes to this helper... unless you feel strongly that we should roll this out early with a changelog warning. (I could be persuaded either way; I think it's relatively unlikely that anyone has locally extended the helper, but it's good to be fairly strict about semantic versioning when we can be).

#[Autowire(container: \VuFind\ContentBlock\PluginManager::class)]
protected TemplateBased $templateBasedBlock,
#[Autowire(container: 'ViewHelperManager')]
protected Context $contextHelper,
#[Autowire(container: 'ViewHelperManager')]
protected EscapeHtml $escapeHtmlHelper,
#[Autowire(container: 'ViewHelperManager')]
protected Markdown $markdownHelper
) {
}

/**
* Constructor
* Make helper invokable.
*
* @param TemplateBased $block TemplateBased ContentBlock
* @param Context $contextHelper Context view helper
* @return static
*/
public function __construct(
TemplateBased $block,
Context $contextHelper
) {
$this->templateBasedBlock = $block;
$this->contextHelper = $contextHelper;
public function __invoke(): static
{
return $this;
}

/**
* Search for a translated template and render it using a temporary context.
*
* @param string $pageName Name of the page
* @param string $pathPrefix Path where the template should be located
* @param array $context Optional array of context variables
* @param array $pageDetails Optional output variable for additional info
* @param string $pattern Optional file system pattern to search page
* @param string $pageName Name of the page
* @param string $pathPrefix Path where the template should be located
* @param array $context Optional array of context variables
* @param ?array $pageDetails Optional output variable for additional info
* @param ?string $pattern Optional file system pattern to search page
*
* @return string Rendered template output
*/
Expand All @@ -90,7 +94,7 @@ public function renderTranslated(
array $context = [],
?array &$pageDetails = [],
?string $pattern = null
) {
): string {
if (!str_ends_with($pathPrefix, '/')) {
$pathPrefix .= '/';
}
Expand All @@ -105,4 +109,25 @@ public function renderTranslated(
$context + $pageDetails
);
}

/**
* Apply encoding to the content based on the provided content type.
*
* @param string $contentType Content type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we list legal values here?

Suggested change
* @param string $contentType Content type
* @param string $contentType Content type (text, html, or markdown)

* @param string $content Content
*
* @return string
*/
public function handleContentType(string $contentType, string $content): string
{
if (empty($content)) {
return '';
}
return match ($contentType) {
'text' => ($this->escapeHtmlHelper)($content),
'html' => $content,
'markdown' => ($this->markdownHelper)(($this->escapeHtmlHelper)($content))->getContent(),
default => throw new InvalidArgumentException('Invalid content type: ' . $contentType),
};
}
}
79 changes: 0 additions & 79 deletions module/VuFind/src/VuFind/View/Helper/Root/ContentFactory.php

This file was deleted.

10 changes: 6 additions & 4 deletions module/VuFind/src/VuFind/View/Helper/Root/Notices.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

namespace VuFind\View\Helper\Root;

use Laminas\View\Helper\EscapeHtml;
use Laminas\View\Renderer\PhpRenderer;
use VuFind\Content\NoticeManager;
use VuFind\I18n\Translator\TranslatorAwareInterface;
Expand Down Expand Up @@ -63,15 +62,15 @@ class Notices implements TranslatorAwareInterface
*
* @param NoticeManager $noticeManager Notice manager
* @param PhpRenderer $renderer PhpRenderer
* @param EscapeHtml $escapeHtml EscapeHtml view helper
* @param Content $contentHelper Content view helper
*/
public function __construct(
#[Autowire(service: NoticeManager::class)]
protected NoticeManager $noticeManager,
#[Autowire(service: PhpRenderer::class)]
protected PhpRenderer $renderer,
#[Autowire(container: 'ViewHelperManager')]
protected EscapeHtml $escapeHtml
protected Content $contentHelper,
) {
}

Expand Down Expand Up @@ -123,7 +122,10 @@ public function renderNotice(array $notice): string
if ($content === null) {
return '';
}
$content = ($this->escapeHtml)($content);
$content = $this->contentHelper->handleContentType(
$notice['contentType'] ?? 'text',
$this->translate($content)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible there might be scenarios where we would not want to translate the content? (Certainly, passing a big chunk of markdown as a translation key isn't going to work -- though it shouldn't cause harm either). Might we want a config setting to explicitly toggle translation, or is that overkill?

);
$classes = '';
if ($style = $notice['style'] ?? null) {
$classes = $this->noticeManager->getConfig()['styles'][$style]['classes']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ public function testConfiguredNoticesWithTranslations(): void
'Notices' => [
'notices' =>
[
[
'style' => 'warning',
'content' => 'ils_offline_status',
],
[
'style' => 'success',
'translations' => [
Expand All @@ -127,6 +131,11 @@ public function testConfiguredNoticesWithTranslations(): void
$page = $session->getPage();
$this->waitForPageLoad($page);

// Test default translation
$notice = $this->findCssAndGetText($page, '.notices .alert-warning');
$this->assertSame('Our Library Management System is currently under maintenance.', $notice);

// Test configured translation
$notice = $this->findCssAndGetText($page, '.notices .alert-success');
$this->assertSame('English Content', $notice);

Expand All @@ -148,13 +157,64 @@ public function testConfiguredNoticesWithTranslations(): void
$this->unFindCss($page, '.notices .alert-success');
}

/**
* Test content types for notices.
*
* @return void
*/
public function testContentTypesForConfiguredNotices(): void
{
$this->changeConfigs($this->getCacheClearPermissionConfig());
$this->clearCache('yaml');
$this->changeYamlConfigs(
[
'Notices' => [
'notices' =>
[
[
'style' => 'success',
'content' => '<strong>*Test*</strong>',
'contentType' => 'text',
],
[
'style' => 'info',
'content' => '<strong>Test</strong>',
'contentType' => 'html',
],
[
'style' => 'danger',
'content' => '**Test**',
'contentType' => 'markdown',
],
],
],
],
);

$session = $this->getMinkSession();
$session->visit($this->getVuFindUrl());
$page = $session->getPage();
$this->waitForPageLoad($page);

$notice = $this->findCssAndGetText($page, '#content > .notices .alert-success');
$this->assertSame('<strong>*Test*</strong>', $notice);

$notice = $this->findCssAndGetText($page, '#content > .notices .alert-info strong');
$this->assertSame('Test', $notice);

$notice = $this->findCssAndGetText($page, '#content > .notices .alert-danger strong');
$this->assertSame('Test', $notice);
}

/**
* Test configured notices with configured class in style.
*
* @return void
*/
public function testConfiguredNoticesWithConfiguredClass(): void
{
$this->changeConfigs($this->getCacheClearPermissionConfig());
$this->clearCache('yaml');
$this->changeYamlConfigs(
[
'Notices' => [
Expand All @@ -179,7 +239,7 @@ public function testConfiguredNoticesWithConfiguredClass(): void
$page = $session->getPage();
$this->waitForPageLoad($page);
$this->unFindCss($page, '.notices .alert-success');
$notice1 = $this->findCssAndGetText($page, '#content > .notices .test-class');
$this->assertSame('Test Content', $notice1);
$notice = $this->findCssAndGetText($page, '#content > .notices .test-class');
$this->assertSame('Test Content', $notice);
}
}
Loading