Initial commit - Typo3 11.5.41
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers\Be;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
/**
|
||||
* Check if the checkbox should be active or not
|
||||
*/
|
||||
class IsCheckboxActiveViewHelper extends AbstractViewHelper
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
/**
|
||||
* Initialize arguments.
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('id', 'int', 'Category id', true);
|
||||
$this->registerArgument('categories', 'array', 'List of categories', false, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string
|
||||
{
|
||||
return (isset($this->arguments['categories']) && is_array($this->arguments['categories']) && in_array($this->arguments['id'], $this->arguments['categories'])) ? 'checked="checked"' : '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers\Category;
|
||||
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get usage count. This ViewHelper retrieves a simple count and does *not* take any additional constraints into account!
|
||||
* If you need additional constraints like startingpoint, archive, ... duplicate the ViewHelper and implement it on your own!
|
||||
*
|
||||
* Example usage
|
||||
* {n:category.count(categoryUid:category.item.uid) -> f:variable(name: 'categoryUsageCount')}
|
||||
* {categoryUsageCount}
|
||||
*/
|
||||
class CountViewHelper extends AbstractViewHelper implements ViewHelperInterface
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('categoryUid', 'int', 'Uid of the category', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return int
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
): int {
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tx_news_domain_model_news');
|
||||
|
||||
$categoryUid = $arguments['categoryUid'];
|
||||
$languageUid = GeneralUtility::makeInstance(Context::class)->getAspect('language')->getId();
|
||||
|
||||
$count = $queryBuilder
|
||||
->count('tx_news_domain_model_news.title')
|
||||
->from('tx_news_domain_model_news')
|
||||
->rightJoin(
|
||||
'tx_news_domain_model_news',
|
||||
'sys_category_record_mm',
|
||||
'sys_category_record_mm',
|
||||
$queryBuilder->expr()->eq('tx_news_domain_model_news.uid', $queryBuilder->quoteIdentifier('sys_category_record_mm.uid_foreign'))
|
||||
)
|
||||
->rightJoin(
|
||||
'sys_category_record_mm',
|
||||
'sys_category',
|
||||
'sys_category',
|
||||
$queryBuilder->expr()->eq('sys_category.uid', $queryBuilder->quoteIdentifier('sys_category_record_mm.uid_local'))
|
||||
)
|
||||
->where(
|
||||
$queryBuilder->expr()->andX(
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_category.uid',
|
||||
$queryBuilder->createNamedParameter($categoryUid, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_category_record_mm.tablenames',
|
||||
$queryBuilder->createNamedParameter('tx_news_domain_model_news', \PDO::PARAM_STR)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_category_record_mm.fieldname',
|
||||
$queryBuilder->createNamedParameter('categories', \PDO::PARAM_STR)
|
||||
),
|
||||
$queryBuilder->expr()->in(
|
||||
'tx_news_domain_model_news.sys_language_uid',
|
||||
$queryBuilder->createNamedParameter([-1, $languageUid], Connection::PARAM_INT_ARRAY)
|
||||
)
|
||||
)
|
||||
)
|
||||
->execute()
|
||||
->fetchColumn(0);
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers\Check;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use GeorgRinger\News\Seo\NewsAvailability;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
|
||||
|
||||
/**
|
||||
* Check if current news page is available
|
||||
*/
|
||||
class PageAvailableInLanguageViewHelper extends AbstractConditionViewHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* Initialize additional argument
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('language', 'int', 'Language ot check', true);
|
||||
parent::initializeArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|null $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null): bool
|
||||
{
|
||||
try {
|
||||
$newsAvailabilityChecker = GeneralUtility::makeInstance(NewsAvailability::class);
|
||||
return $newsAvailabilityChecker->check((int)$arguments['language']);
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
if (static::evaluateCondition($this->arguments)) {
|
||||
return $this->renderThenChild();
|
||||
}
|
||||
return $this->renderElseChild();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
use GeorgRinger\News\Domain\Model\News;
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* ViewHelper to exclude news items in other plugins
|
||||
*
|
||||
* # Example: Basic example
|
||||
*
|
||||
* <code>
|
||||
* <n:excludeDisplayedNews newsItem="{newsItem}" />
|
||||
* </code>
|
||||
* <output>
|
||||
* None
|
||||
* </output>
|
||||
*/
|
||||
class ExcludeDisplayedNewsViewHelper extends AbstractViewHelper implements ViewHelperInterface
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('newsItem', News::class, 'news item', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$newsItem = $arguments['newsItem'];
|
||||
$uid = $newsItem->getUid();
|
||||
|
||||
if (empty($GLOBALS['EXT']['news']['alreadyDisplayed'])) {
|
||||
$GLOBALS['EXT']['news']['alreadyDisplayed'] = [];
|
||||
}
|
||||
$GLOBALS['EXT']['news']['alreadyDisplayed'][$uid] = $uid;
|
||||
|
||||
// Add localized uid as well
|
||||
$originalUid = (int)$newsItem->_getProperty('_localizedUid');
|
||||
if ($originalUid > 0) {
|
||||
$GLOBALS['EXT']['news']['alreadyDisplayed'][$originalUid] = $originalUid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
|
||||
|
||||
/**
|
||||
* Class ExtensionLoadedViewHelper
|
||||
*/
|
||||
class ExtensionLoadedViewHelper extends AbstractConditionViewHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* Initialize additional argument
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('extensionKey', 'string', 'Extension which must be checked', true);
|
||||
parent::initializeArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|null $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null): bool
|
||||
{
|
||||
return ExtensionManagementUtility::isLoaded($arguments['extensionKey']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
if (static::evaluateCondition($this->arguments)) {
|
||||
return $this->renderThenChild();
|
||||
}
|
||||
return $this->renderElseChild();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers\Format;
|
||||
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
/**
|
||||
* ViewHelper to render children which don't print out any actual content
|
||||
*
|
||||
* # Example: Basic example
|
||||
* <code>
|
||||
* <n:format.nothing>
|
||||
* <n:titleTag>{newsItem.title}</n:titleTag>
|
||||
* Fobar
|
||||
* </n:format.nothing>
|
||||
* </code>
|
||||
* <output>
|
||||
* nothing
|
||||
* </output>
|
||||
*/
|
||||
class NothingViewHelper extends AbstractViewHelper
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
/**
|
||||
* Render children but do nothing else
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render(): void
|
||||
{
|
||||
$this->renderChildren();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* ViewHelper to render data in <head> section of website
|
||||
*
|
||||
* # Example: Basic example
|
||||
* <code>
|
||||
* <n:headerData>
|
||||
* <link rel="alternate"
|
||||
* type="application/rss+xml"
|
||||
* title="RSS 2.0"
|
||||
* href="{f:uri.page(pageType: settings.list.rss.channel.typeNum)}" />
|
||||
* </n:headerData>
|
||||
* </code>
|
||||
* <output>
|
||||
* Added to the header: <link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="uri to this page and type 9818" />
|
||||
* </output>
|
||||
*/
|
||||
class HeaderDataViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
|
||||
$pageRenderer->addHeaderData($renderChildrenClosure());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* ViewHelper to check if the current news item is rendered as single view on the same page
|
||||
*
|
||||
* # Example: Basic example
|
||||
* <code>
|
||||
* {n:ifIsActive(newsItem: newsItem, then: 'active', else: '')}
|
||||
* </code>
|
||||
* <output>
|
||||
* Renders the string "active" if the current news item is active
|
||||
* </output>
|
||||
*/
|
||||
class IfIsActiveViewHelper extends AbstractConditionViewHelper implements ViewHelperInterface
|
||||
{
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('newsItem', 'object', 'News item', false);
|
||||
parent::initializeArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|null $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null): bool
|
||||
{
|
||||
$vars = GeneralUtility::_GET('tx_news_pi1');
|
||||
return isset($vars['news']) && isset($arguments['newsItem']) && (int)$arguments['newsItem']->getUid() === (int)$vars['news'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
if (static::evaluateCondition($this->arguments)) {
|
||||
return $this->renderThenChild();
|
||||
}
|
||||
return $this->renderElseChild();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Page\AssetCollector;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class ImageSizeViewHelper
|
||||
*/
|
||||
class ImageSizeViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('property', 'string', 'either width or height', true);
|
||||
$this->registerArgument('image', 'string', 'generated image', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return int
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
): int {
|
||||
$value = 0;
|
||||
|
||||
$typo3VersionNumber = VersionNumberUtility::convertVersionNumberToInteger(
|
||||
VersionNumberUtility::getNumericTypo3Version()
|
||||
);
|
||||
|
||||
// If TYPO3 version is previous version 11
|
||||
if ($typo3VersionNumber < 11000000) {
|
||||
$usedImage = trim($arguments['image'], '/');
|
||||
} else {
|
||||
$usedImage = trim($arguments['image']);
|
||||
}
|
||||
|
||||
$assetCollector = GeneralUtility::makeInstance(AssetCollector::class);
|
||||
$imagesOnPage = $assetCollector->getMedia();
|
||||
|
||||
if (isset($imagesOnPage[$usedImage])) {
|
||||
switch ($arguments['property']) {
|
||||
case 'width':
|
||||
$value = $imagesOnPage[$usedImage][0];
|
||||
break;
|
||||
case 'height':
|
||||
$value = $imagesOnPage[$usedImage][1];
|
||||
break;
|
||||
case 'size':
|
||||
$file = Environment::getPublicPath() . '/' . $usedImage;
|
||||
if (is_file($file)) {
|
||||
$value = @filesize($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\Resource\FilePathSanitizer;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* ViewHelper to include a css/js file
|
||||
*
|
||||
* # Example: Basic example
|
||||
* <code>
|
||||
* <n:includeFile path="{settings.cssFile}" />
|
||||
* </code>
|
||||
* <output>
|
||||
* This will include the file provided by {settings} in the header
|
||||
* </output>
|
||||
*/
|
||||
class IncludeFileViewHelper extends AbstractViewHelper implements ViewHelperInterface
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('path', 'string', 'Path to the CSS/JS file which should be included', true);
|
||||
$this->registerArgument('compress', 'bool', 'Define if file should be compressed', false, false);
|
||||
$this->registerArgument('footer', 'bool', 'Define if JS file should be loaded in the footer', false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$path = $arguments['path'];
|
||||
$compress = (bool)$arguments['compress'];
|
||||
$footer = (bool)$arguments['footer'];
|
||||
|
||||
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
|
||||
if (TYPO3_MODE === 'FE') {
|
||||
$sanitizer = GeneralUtility::makeInstance(FilePathSanitizer::class);
|
||||
try {
|
||||
$path = $sanitizer->sanitize($path);
|
||||
// JS
|
||||
if (strtolower(substr($path, -3)) === '.js') {
|
||||
if ($footer) {
|
||||
$pageRenderer->addJsFooterFile($path, null, $compress, false, '', true);
|
||||
} else {
|
||||
$pageRenderer->addJsFile($path, null, $compress, false, '', true);
|
||||
}
|
||||
|
||||
// CSS
|
||||
} elseif (strtolower(substr($path, -4)) === '.css') {
|
||||
$pageRenderer->addCssFile($path, 'stylesheet', 'all', '', $compress, false, '', true);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// do nothing (todo handle properly?)
|
||||
}
|
||||
} else {
|
||||
// JS
|
||||
if (strtolower(substr($path, -3)) === '.js') {
|
||||
$pageRenderer->addJsFile($path, null, $compress, false, '', true);
|
||||
|
||||
// CSS
|
||||
} elseif (strtolower(substr($path, -4)) === '.css') {
|
||||
$pageRenderer->addCssFile($path, 'stylesheet', 'all', '', $compress, false, '', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers\Iterator;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\Variables\VariableProviderInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
|
||||
|
||||
/**
|
||||
* Creates chunks from an input Array/Traversable with option to allocate items to a fixed number of chunks
|
||||
*
|
||||
* thanks to Claus Due and the EXT:vhs where this has been copied from
|
||||
*/
|
||||
class ChunkViewHelper extends AbstractViewHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeChildren = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('subject', 'mixed', 'The subject Traversable/Array instance to shift');
|
||||
$this->registerArgument('count', 'integer', 'Number of items/chunk or if fixed then number of chunks', true);
|
||||
$this->registerArgument('as', 'string', 'Template variable name to assign; if not specified the ViewHelper returns the variable instead.');
|
||||
$this->registerArgument(
|
||||
'fixed',
|
||||
'boolean',
|
||||
'If true, creates $count chunks instead of $count values per chunk',
|
||||
false,
|
||||
false
|
||||
);
|
||||
$this->registerArgument(
|
||||
'preserveKeys',
|
||||
'boolean',
|
||||
'If set to true, the original array keys will be preserved',
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$count = (int)$arguments['count'];
|
||||
$fixed = (bool)($arguments['fixed'] ?? false);
|
||||
$preserveKeys = (bool)($arguments['preserveKeys'] ?? false);
|
||||
$subject = static::arrayFromArrayOrTraversableOrCSVStatic(
|
||||
empty($arguments['as']) ? ($arguments['subject'] ?? $renderChildrenClosure()) : $arguments['subject'],
|
||||
$preserveKeys
|
||||
);
|
||||
$output = [];
|
||||
if (0 >= $count) {
|
||||
return $output;
|
||||
}
|
||||
if ($fixed) {
|
||||
$subjectSize = count($subject);
|
||||
if (0 < $subjectSize) {
|
||||
$chunkSize = (int)ceil($subjectSize / $count);
|
||||
|
||||
$output = array_chunk($subject, $chunkSize, $preserveKeys);
|
||||
}
|
||||
// Fill the resulting array with empty items to get the desired element count
|
||||
$elementCount = count($output);
|
||||
if ($elementCount < $count) {
|
||||
$output += array_fill($elementCount, $count - $elementCount, null);
|
||||
}
|
||||
} else {
|
||||
$output = array_chunk($subject, $count, $preserveKeys);
|
||||
}
|
||||
|
||||
return static::renderChildrenWithVariableOrReturnInputStatic(
|
||||
$output,
|
||||
$arguments['as'],
|
||||
$renderingContext,
|
||||
$renderChildrenClosure
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $candidate
|
||||
* @param bool $useKeys
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected static function arrayFromArrayOrTraversableOrCSVStatic($candidate, $useKeys = true): array
|
||||
{
|
||||
if ($candidate instanceof \Traversable) {
|
||||
return iterator_to_array($candidate, $useKeys);
|
||||
}
|
||||
if ($candidate instanceof QueryResultInterface) {
|
||||
/** @var QueryResultInterface $candidate */
|
||||
return $candidate->toArray();
|
||||
}
|
||||
if (is_string($candidate)) {
|
||||
return GeneralUtility::trimExplode(',', $candidate, true);
|
||||
}
|
||||
if (is_array($candidate)) {
|
||||
return $candidate;
|
||||
}
|
||||
throw new Exception('Unsupported input type; cannot convert to array!', 1588049231);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $variable
|
||||
* @param string $as
|
||||
* @param \TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface $renderingContext
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function renderChildrenWithVariableOrReturnInputStatic(
|
||||
$variable,
|
||||
$as,
|
||||
RenderingContextInterface $renderingContext,
|
||||
\Closure $renderChildrenClosure
|
||||
) {
|
||||
if (true === empty($as)) {
|
||||
return $variable;
|
||||
}
|
||||
$variables = [$as => $variable];
|
||||
$content = static::renderChildrenWithVariablesStatic(
|
||||
$variables,
|
||||
$renderingContext->getVariableProvider(),
|
||||
$renderChildrenClosure
|
||||
);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders tag content of ViewHelper and inserts variables
|
||||
* in $variables into $variableContainer while keeping backups
|
||||
* of each existing variable, restoring it after rendering.
|
||||
* Returns the output of the renderChildren() method on $viewHelper.
|
||||
*
|
||||
* @param array $variables
|
||||
* @param VariableProviderInterface $templateVariableContainer
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function renderChildrenWithVariablesStatic(
|
||||
array $variables,
|
||||
$templateVariableContainer,
|
||||
$renderChildrenClosure
|
||||
) {
|
||||
$backups = static::backupVariables($variables, $templateVariableContainer);
|
||||
$content = $renderChildrenClosure();
|
||||
static::restoreVariables($variables, $backups, $templateVariableContainer);
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $variables
|
||||
* @param VariableProviderInterface $templateVariableContainer
|
||||
* @return array
|
||||
*/
|
||||
private static function backupVariables(array $variables, $templateVariableContainer): array
|
||||
{
|
||||
$backups = [];
|
||||
foreach ($variables as $variableName => $variableValue) {
|
||||
if ($templateVariableContainer->exists($variableName)) {
|
||||
$backups[$variableName] = $templateVariableContainer->get($variableName);
|
||||
$templateVariableContainer->remove($variableName);
|
||||
}
|
||||
$templateVariableContainer->add($variableName, $variableValue);
|
||||
}
|
||||
return $backups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $variables
|
||||
* @param array $backups
|
||||
* @param VariableProviderInterface $templateVariableContainer
|
||||
*/
|
||||
private static function restoreVariables(array $variables, array $backups, $templateVariableContainer): void
|
||||
{
|
||||
foreach ($variables as $variableName => $variableValue) {
|
||||
$templateVariableContainer->remove($variableName);
|
||||
if (true === isset($backups[$variableName])) {
|
||||
$templateVariableContainer->add($variableName, $variableValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
use GeorgRinger\News\Domain\Model\News;
|
||||
use GeorgRinger\News\Service\SettingsService;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
|
||||
|
||||
/**
|
||||
* ViewHelper to render links from news records to detail view or page
|
||||
*
|
||||
* # Example: Basic link
|
||||
* <code>
|
||||
* <n:link newsItem="{newsItem}" settings="{settings}">
|
||||
* {newsItem.title}
|
||||
* </n:link>
|
||||
* </code>
|
||||
* <output>
|
||||
* A link to the given news record using the news title as link text
|
||||
* </output>
|
||||
*
|
||||
* # Example: Set an additional attribute
|
||||
* # Description: Available: class, dir, id, lang, style, title, accesskey, tabindex, onclick
|
||||
* <code>
|
||||
* <n:link newsItem="{newsItem}" settings="{settings}" class="a-link-class">fo</n:link>
|
||||
* </code>
|
||||
* <output>
|
||||
* <a href="link" class="a-link-class">fo</n:link>
|
||||
* </output>
|
||||
*
|
||||
* # Example: Return the link only
|
||||
* <code>
|
||||
* <n:link newsItem="{newsItem}" settings="{settings}" uriOnly="1" />
|
||||
* </code>
|
||||
* <output>
|
||||
* The uri is returned
|
||||
* </output>
|
||||
*/
|
||||
class LinkViewHelper extends AbstractTagBasedViewHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tagName = 'a';
|
||||
|
||||
/**
|
||||
* @var \GeorgRinger\News\Service\SettingsService
|
||||
*/
|
||||
protected $pluginSettingsService;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $detailPidDeterminationCallbacks = [
|
||||
'flexform' => 'getDetailPidFromFlexform',
|
||||
'categories' => 'getDetailPidFromCategories',
|
||||
'default' => 'getDetailPidFromDefaultDetailPid',
|
||||
];
|
||||
|
||||
/** @var ContentObjectRenderer */
|
||||
protected $cObj;
|
||||
|
||||
/**
|
||||
* @param \GeorgRinger\News\Service\SettingsService $pluginSettingsService
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function injectSettingsService(SettingsService $pluginSettingsService): void
|
||||
{
|
||||
$this->pluginSettingsService = $pluginSettingsService;
|
||||
}
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerUniversalTagAttributes();
|
||||
$this->registerArgument('newsItem', News::class, 'news item', true);
|
||||
$this->registerArgument('settings', 'array', 'Settings', false, []);
|
||||
$this->registerArgument('uriOnly', 'bool', 'url only', false, false);
|
||||
$this->registerArgument('configuration', 'array', 'configuration', false, []);
|
||||
$this->registerArgument('content', 'string', 'content', false, '');
|
||||
$this->registerArgument('section', 'string', 'Anchor for links', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render link to news item or internal/external pages
|
||||
*
|
||||
* @return null|string link
|
||||
*/
|
||||
public function render(): ?string
|
||||
{
|
||||
/** @var News $newsItem */
|
||||
$newsItem = $this->arguments['newsItem'];
|
||||
$settings = $this->arguments['settings'] ?? [];
|
||||
$uriOnly = $this->arguments['uriOnly'] ?? false;
|
||||
$configuration = $this->arguments['configuration'] ?? [];
|
||||
$content = $this->arguments['content'] ?? '';
|
||||
|
||||
$tsSettings = (array)$this->pluginSettingsService->getSettings();
|
||||
ArrayUtility::mergeRecursiveWithOverrule($tsSettings, (array)$settings);
|
||||
// Options with stdWrap enabled won't override $tsSettings as intended here: override them explicit.
|
||||
if (isset($settings['useStdWrap']) && $settings['useStdWrap']) {
|
||||
foreach (GeneralUtility::trimExplode(',', $settings['useStdWrap'], true) as $stdWrapProperty) {
|
||||
if (is_array($tsSettings[$stdWrapProperty]) && array_key_exists($stdWrapProperty, $settings)) {
|
||||
$tsSettings[$stdWrapProperty] = $settings[$stdWrapProperty];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->init();
|
||||
$linkedContent = $this->renderChildren();
|
||||
|
||||
if ($newsItem === null) {
|
||||
return $linkedContent;
|
||||
}
|
||||
|
||||
$newsType = (int)$newsItem->getType();
|
||||
switch ($newsType) {
|
||||
// internal news
|
||||
case 1:
|
||||
$configuration['parameter'] = $newsItem->getInternalurl();
|
||||
break;
|
||||
// external news
|
||||
case 2:
|
||||
$configuration['parameter'] = $newsItem->getExternalurl();
|
||||
break;
|
||||
// normal news record
|
||||
default:
|
||||
$configuration = $this->getLinkToNewsItem($newsItem, $tsSettings, $configuration);
|
||||
}
|
||||
|
||||
$url = $this->cObj->typoLink_URL($configuration);
|
||||
|
||||
// link could not be generated
|
||||
if ($url === '' || $linkedContent === $url) {
|
||||
return $linkedContent;
|
||||
}
|
||||
|
||||
if ($this->hasArgument('section')) {
|
||||
$url .= '#' . $this->arguments['section'];
|
||||
}
|
||||
|
||||
if ($uriOnly) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
if (isset($tsSettings['link']['typesOpeningInNewWindow'])) {
|
||||
if (GeneralUtility::inList($tsSettings['link']['typesOpeningInNewWindow'], $newsType)) {
|
||||
$this->tag->addAttribute('target', '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->tag->hasAttribute('target')) {
|
||||
$target = $this->getTargetConfiguration($configuration);
|
||||
if (!empty($target)) {
|
||||
$this->tag->addAttribute('target', $target);
|
||||
}
|
||||
}
|
||||
|
||||
$this->tag->addAttribute('href', $url);
|
||||
|
||||
if (empty($content)) {
|
||||
$content = $linkedContent;
|
||||
}
|
||||
$this->tag->setContent($content);
|
||||
|
||||
return $this->tag->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the link configuration for the link to the news item
|
||||
*
|
||||
* @param News $newsItem
|
||||
* @param array $tsSettings
|
||||
* @param array $configuration
|
||||
* @return array
|
||||
*/
|
||||
protected function getLinkToNewsItem(
|
||||
News $newsItem,
|
||||
$tsSettings,
|
||||
array $configuration = []
|
||||
): array {
|
||||
if (!isset($configuration['parameter'])) {
|
||||
$detailPid = 0;
|
||||
// if TS is not set, prefer flexform setting
|
||||
if (!isset($tsSettings['detailPidDetermination'])) {
|
||||
$detailPidDeterminationMethods = ['flexform'];
|
||||
} else {
|
||||
$detailPidDeterminationMethods = GeneralUtility::trimExplode(
|
||||
',',
|
||||
$tsSettings['detailPidDetermination'],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($detailPidDeterminationMethods as $determinationMethod) {
|
||||
if ($callback = $this->detailPidDeterminationCallbacks[$determinationMethod]) {
|
||||
if ($detailPid = call_user_func([$this, $callback], $tsSettings, $newsItem)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$detailPid && isset($GLOBALS['TSFE'])) {
|
||||
$detailPid = $GLOBALS['TSFE']->id;
|
||||
}
|
||||
$configuration['parameter'] = $detailPid;
|
||||
}
|
||||
|
||||
$configuration['additionalParams'] = (isset($configuration['additionalParams']) ? $configuration['additionalParams'] : '') . '&tx_news_pi1[news]=' . $this->getNewsId($newsItem);
|
||||
$configuration['additionalParams'] .= '&tx_news_pi1[controller]=News&tx_news_pi1[action]=detail';
|
||||
|
||||
// Add date as human readable
|
||||
if (isset($tsSettings['link']['hrDate']) && $tsSettings['link']['hrDate'] == 1 || isset($tsSettings['link']['hrDate']['_typoScriptNodeValue']) && $tsSettings['link']['hrDate']['_typoScriptNodeValue'] == 1) {
|
||||
$dateTime = $newsItem->getDatetime();
|
||||
|
||||
if (!is_null($dateTime)) {
|
||||
if (!empty($tsSettings['link']['hrDate']['day'])) {
|
||||
$configuration['additionalParams'] .= '&tx_news_pi1[day]=' . $dateTime->format($tsSettings['link']['hrDate']['day']);
|
||||
}
|
||||
if (!empty($tsSettings['link']['hrDate']['month'])) {
|
||||
$configuration['additionalParams'] .= '&tx_news_pi1[month]=' . $dateTime->format($tsSettings['link']['hrDate']['month']);
|
||||
}
|
||||
if (!empty($tsSettings['link']['hrDate']['year'])) {
|
||||
$configuration['additionalParams'] .= '&tx_news_pi1[year]=' . $dateTime->format($tsSettings['link']['hrDate']['year']);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param News $newsItem
|
||||
* @return int
|
||||
*/
|
||||
protected function getNewsId(News $newsItem): int
|
||||
{
|
||||
$uid = $newsItem->getUid();
|
||||
// If a user is logged in and not in live workspace
|
||||
if (isset($GLOBALS['BE_USER']) && $GLOBALS['BE_USER']->workspace > 0) {
|
||||
$record = BackendUtility::getLiveVersionOfRecord(
|
||||
'tx_news_domain_model_news',
|
||||
$newsItem->getUid()
|
||||
);
|
||||
if ($record['uid']) {
|
||||
$uid = $record['uid'];
|
||||
}
|
||||
}
|
||||
|
||||
return $uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $configuration
|
||||
* @return string
|
||||
*/
|
||||
protected function getTargetConfiguration(array $configuration): string
|
||||
{
|
||||
$configuration['returnLast'] = 'target';
|
||||
|
||||
return $this->cObj->typoLink('dummy', $configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets detailPid from categories of the given news item. First will be return.
|
||||
*
|
||||
* @param array $settings
|
||||
* @param News $newsItem
|
||||
* @return int
|
||||
*/
|
||||
protected function getDetailPidFromCategories($settings, $newsItem): int
|
||||
{
|
||||
$detailPid = 0;
|
||||
if ($newsItem->getCategories()) {
|
||||
foreach ($newsItem->getCategories() as $category) {
|
||||
if ($detailPid = (int)$category->getSinglePid()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $detailPid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets detailPid from defaultDetailPid setting
|
||||
*
|
||||
* @param array $settings
|
||||
* @param News $newsItem
|
||||
* @return int
|
||||
*/
|
||||
protected function getDetailPidFromDefaultDetailPid($settings, $newsItem): int
|
||||
{
|
||||
return isset($settings['defaultDetailPid']) ? (int)$settings['defaultDetailPid'] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets detailPid from flexform of current plugin.
|
||||
*
|
||||
* @param array $settings
|
||||
* @param News $newsItem
|
||||
* @return int
|
||||
*/
|
||||
protected function getDetailPidFromFlexform($settings, $newsItem): int
|
||||
{
|
||||
return isset($settings['detailPid']) ? (int)$settings['detailPid'] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize properties
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init(): void
|
||||
{
|
||||
$this->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* ViewHelper to render meta tags
|
||||
*
|
||||
* # Example: Basic Example: News title as og:title meta tag
|
||||
* <code>
|
||||
* <n:metaTag property="og:title" content="{newsItem.title}" />
|
||||
* </code>
|
||||
* <output>
|
||||
* <meta property="og:title" content="TYPO3 is awesome" />
|
||||
* </output>
|
||||
*
|
||||
* # Example: Force the attribute "name"
|
||||
* <code>
|
||||
* <n:metaTag name="keywords" content="{newsItem.keywords}" />
|
||||
* </code>
|
||||
* <output>
|
||||
* <meta name="keywords" content="news 1, news 2" />
|
||||
* </output>
|
||||
*/
|
||||
class MetaTagViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Arguments initialization
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('property', 'string', 'Property of meta tag', false, '', false);
|
||||
$this->registerArgument('name', 'string', 'Content of meta tag using the name attribute', false, '', false);
|
||||
$this->registerArgument('content', 'string', 'Content of meta tag', true, null, false);
|
||||
$this->registerArgument('useCurrentDomain', 'boolean', 'Use current domain', false, false);
|
||||
$this->registerArgument('forceAbsoluteUrl', 'boolean', 'Force absolut domain', false, false);
|
||||
}
|
||||
|
||||
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
|
||||
{
|
||||
// Skip if current record is part of tt_content CType shortcut
|
||||
if (!empty($GLOBALS['TSFE']->recordRegister)
|
||||
&& is_array($GLOBALS['TSFE']->recordRegister)
|
||||
&& strpos(array_keys($GLOBALS['TSFE']->recordRegister)[0], 'tt_content:') !== false
|
||||
&& !empty($GLOBALS['TSFE']->currentRecord)
|
||||
&& strpos($GLOBALS['TSFE']->currentRecord, 'tx_news_domain_model_news:') !== false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$useCurrentDomain = $arguments['useCurrentDomain'];
|
||||
$forceAbsoluteUrl = $arguments['forceAbsoluteUrl'];
|
||||
$content = (string)$arguments['content'];
|
||||
|
||||
// set current domain
|
||||
if ($useCurrentDomain) {
|
||||
$content = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
|
||||
}
|
||||
|
||||
// prepend current domain
|
||||
if ($forceAbsoluteUrl) {
|
||||
$parsedPath = parse_url($content);
|
||||
if (is_array($parsedPath) && !isset($parsedPath['host'])) {
|
||||
$content =
|
||||
rtrim(GeneralUtility::getIndpEnv('TYPO3_SITE_URL'), '/')
|
||||
. '/'
|
||||
. ltrim($content, '/');
|
||||
}
|
||||
}
|
||||
|
||||
if ($content !== '') {
|
||||
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
|
||||
if ($arguments['property']) {
|
||||
$pageRenderer->setMetaTag('property', $arguments['property'], $content);
|
||||
} elseif ($arguments['name']) {
|
||||
$pageRenderer->setMetaTag('name', $arguments['name'], $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers\MultiCategoryLink;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* ViewHelper to get additional params including add/remove categories from list
|
||||
*
|
||||
* # Example: Basic Example
|
||||
* # Description: Render the content of the VH as page title
|
||||
* <code>
|
||||
* <f:link.page title="{category.item.title}" pageUid="{settings.listPid}"
|
||||
* additionalParams="{n:multiCategoryLink.arguments(
|
||||
* mode:'add',
|
||||
* item:category.item.uid,
|
||||
* list:overwriteDemand.categories)}">link
|
||||
* </f:link.page>
|
||||
* </code>
|
||||
* <output>
|
||||
* <title>TYPO3 is awesome</title>
|
||||
* </output>
|
||||
*/
|
||||
class ArgumentsViewHelper extends AbstractViewHelper implements ViewHelperInterface
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('mode', 'string', 'Mode, either "add" or "remove"', true);
|
||||
$this->registerArgument('list', 'string', 'Category list', false, '');
|
||||
$this->registerArgument('item', 'int', 'Category id', true);
|
||||
$this->registerArgument('additionalParams', 'array', 'Additional params', false, []);
|
||||
parent::initializeArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
): array {
|
||||
if ($arguments['mode'] !== 'add' && $arguments['mode'] !== 'remove') {
|
||||
throw new Exception('Mode must be either "add" or "remove', 1522293549);
|
||||
}
|
||||
|
||||
$allArguments = (array)$arguments['additionalParams'];
|
||||
$categoryId = $arguments['item'];
|
||||
|
||||
$categoryList = $arguments['list'];
|
||||
if ($arguments['mode'] === 'add') {
|
||||
if (!GeneralUtility::inList($categoryList, $categoryId)) {
|
||||
$categoryList .= ',' . $categoryId;
|
||||
}
|
||||
} else {
|
||||
$categoryList = GeneralUtility::rmFromList($categoryId, $categoryList);
|
||||
}
|
||||
|
||||
if (!empty($categoryList)) {
|
||||
$categoryList = trim($categoryList, ',');
|
||||
$categoryArray = [
|
||||
'tx_news_pi1' => [
|
||||
'overwriteDemand' => [
|
||||
'categories' => $categoryList
|
||||
]
|
||||
]
|
||||
];
|
||||
ArrayUtility::mergeRecursiveWithOverrule($allArguments, $categoryArray);
|
||||
}
|
||||
|
||||
return $allArguments;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers\MultiCategoryLink;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* ViewHelper to check if th
|
||||
*
|
||||
* # Example: Basic example
|
||||
* <code>
|
||||
* <n:multiCategoryLink.isCategoryActive list="{overwriteDemand.categories}" item="{category.uid}">
|
||||
* do stuff
|
||||
* </n:multiCategoryLink.isCategoryActive>
|
||||
* </code>
|
||||
* <output>
|
||||
* "du stuff" will be shown if the category is currently in demand
|
||||
* </output>
|
||||
*/
|
||||
class IsCategoryActiveViewHelper extends AbstractConditionViewHelper implements ViewHelperInterface
|
||||
{
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('list', 'string', 'List of news', false, '');
|
||||
$this->registerArgument('item', 'int', 'Category id', true);
|
||||
parent::initializeArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|null $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null): bool
|
||||
{
|
||||
if (empty($arguments['list'])) {
|
||||
return false;
|
||||
}
|
||||
return GeneralUtility::inList($arguments['list'], $arguments['item']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
if (static::evaluateCondition($this->arguments)) {
|
||||
return $this->renderThenChild();
|
||||
}
|
||||
return $this->renderElseChild();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
use GeorgRinger\News\Domain\Model\News;
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
/**
|
||||
* Paginate the bodytext which is very useful for longer texts or to increase
|
||||
* traffic.
|
||||
*
|
||||
* Example
|
||||
* ----------
|
||||
* <n:paginateBodytext object="{newsItem}"
|
||||
* as="bodytext" currentPage="{currentPage}">
|
||||
* <div class="articleBodyText">
|
||||
* <f:format.html>{bodytext}</f:format.html>
|
||||
* </div>
|
||||
* <f:if condition="{pagination.numberOfPages} > 1">
|
||||
* <div class="articlePagination">
|
||||
* <span>Seite</span>
|
||||
* <ul>
|
||||
* <f:for each="{pagination.pages}" as="page">
|
||||
* <f:if condition="{page.isCurrent}">
|
||||
* <f:then>
|
||||
* <li class="current">
|
||||
* {page.number}
|
||||
* </li>
|
||||
* </f:then>
|
||||
* <f:else>
|
||||
* <li>
|
||||
* <f:if condition="{page.number} == 1">
|
||||
* <f:then>
|
||||
* <f:link.action action="detail" arguments="{news: newsItem}">
|
||||
* {page.number}
|
||||
* </f:link.action>
|
||||
* </f:then>
|
||||
* <f:else>
|
||||
* <f:link.action action="detail" arguments="{news: newsItem, currentPage: page.number}">
|
||||
* {page.number}
|
||||
* </f:link.action>
|
||||
* </f:else>
|
||||
* </f:if>
|
||||
* </li>
|
||||
* </f:else>
|
||||
* </f:if>
|
||||
* </f:for>
|
||||
* </ul>
|
||||
* </div>
|
||||
* </f:if>
|
||||
* </n:paginateBodytext>
|
||||
*/
|
||||
class PaginateBodytextViewHelper extends AbstractViewHelper
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('object', News::class, 'news item', true);
|
||||
$this->registerArgument('as', 'string', 'as', true);
|
||||
$this->registerArgument('currentPage', 'int', 'current page', true);
|
||||
$this->registerArgument('token', 'string', 'token', '###more###');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render everything
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string
|
||||
{
|
||||
$as = $this->arguments['as'];
|
||||
$currentPage = $this->arguments['currentPage'];
|
||||
|
||||
$parts = GeneralUtility::trimExplode($this->arguments['token'], $this->arguments['object']->getBodytext(), true);
|
||||
$numberOfPages = count($parts);
|
||||
|
||||
if ($numberOfPages === 1) {
|
||||
$result = $parts[0];
|
||||
} else {
|
||||
$currentPage = (int)$currentPage;
|
||||
if ($currentPage < 1) {
|
||||
$currentPage = 1;
|
||||
} elseif ($currentPage > $numberOfPages) {
|
||||
$currentPage = $numberOfPages;
|
||||
}
|
||||
|
||||
$tagsToOpen = [];
|
||||
$tagsToClose = [];
|
||||
|
||||
for ($j = 0; $j < $currentPage; $j++) {
|
||||
$chunk = $parts[$j];
|
||||
|
||||
while (($chunk = mb_strstr($chunk, '<'))) {
|
||||
$tag = $this->extractTag($chunk);
|
||||
$tagStrLen = mb_strlen($tag);
|
||||
|
||||
if ($this->isOpeningTag($tag)) {
|
||||
if ($j < $currentPage - 1) {
|
||||
$tagsToOpen[] = $tag;
|
||||
}
|
||||
$tagsToClose[] = $tag;
|
||||
} elseif ($this->isClosingTag($tag)) {
|
||||
if ($j < $currentPage - 1) {
|
||||
array_pop($tagsToOpen);
|
||||
} elseif (mb_strpos($parts[$j], $chunk) === 0) {
|
||||
$parts[$j] = mb_substr($parts[$j], $tagStrLen);
|
||||
array_pop($tagsToOpen);
|
||||
}
|
||||
array_pop($tagsToClose);
|
||||
}
|
||||
|
||||
$chunk = mb_substr($chunk, $tagStrLen);
|
||||
}
|
||||
}
|
||||
|
||||
$result = implode('', $tagsToOpen) . $parts[$currentPage - 1];
|
||||
|
||||
while ($tag = array_pop($tagsToClose)) {
|
||||
$result .= $this->getClosingTagByOpeningTag($tag);
|
||||
}
|
||||
}
|
||||
|
||||
$pages = [];
|
||||
for ($i = 1; $i <= $numberOfPages; $i++) {
|
||||
$pages[] = ['number' => $i, 'isCurrent' => ($i === $currentPage)];
|
||||
}
|
||||
|
||||
$pagination = [
|
||||
'pages' => $pages,
|
||||
'numberOfPages' => $numberOfPages,
|
||||
'current' => $currentPage
|
||||
];
|
||||
|
||||
if ($currentPage < $numberOfPages) {
|
||||
$pagination['nextPage'] = $currentPage + 1;
|
||||
}
|
||||
if ($currentPage > 1) {
|
||||
$pagination['previousPage'] = $currentPage - 1;
|
||||
}
|
||||
|
||||
$this->templateVariableContainer->add($as, $result);
|
||||
$this->templateVariableContainer->add('pagination', $pagination);
|
||||
|
||||
return $this->renderChildren();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the first html tag for a given html string
|
||||
*
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
protected function extractTag($html): string
|
||||
{
|
||||
$tag = '';
|
||||
$length = mb_strlen($html);
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$char = mb_substr($html, $i, 1);
|
||||
$tag .= $char;
|
||||
if ($char === '>') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given tag is self closing
|
||||
*
|
||||
* @param string $tag
|
||||
* @return bool
|
||||
*/
|
||||
protected function isSelfClosingTag($tag): bool
|
||||
{
|
||||
return mb_substr($tag, -2) === '/>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given tag is closing tag
|
||||
*
|
||||
* @param string $tag
|
||||
* @return bool
|
||||
*/
|
||||
protected function isClosingTag($tag): bool
|
||||
{
|
||||
return mb_substr($tag, 0, 2) === '</';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given Tag is a an opening tag
|
||||
*
|
||||
* @param string $tag
|
||||
* @return bool
|
||||
*/
|
||||
protected function isOpeningTag($tag): bool
|
||||
{
|
||||
return !($this->isSelfClosingTag($tag) || $this->isClosingTag($tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a closing tag from a given opening tag
|
||||
*
|
||||
* @param string $openingTag
|
||||
* @return string
|
||||
*/
|
||||
protected function getClosingTagByOpeningTag($openingTag): string
|
||||
{
|
||||
if (!$tag = mb_strstr(mb_substr($openingTag, 1), ' ', true)) {
|
||||
$tag = mb_strstr(mb_substr($openingTag, 1), '>', true);
|
||||
}
|
||||
|
||||
return '</' . $tag . '>';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
class RemoveMediaTagsViewHelper extends AbstractViewHelper
|
||||
{
|
||||
protected $escapingInterceptorEnabled = false;
|
||||
|
||||
protected $escapeOutput = false;
|
||||
|
||||
protected $escapeChildren = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $tags = ['[media]'];
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$content = $this->renderChildren();
|
||||
return str_replace($this->tags, '', $content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use GeorgRinger\News\Domain\Model\News;
|
||||
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Rendering\RendererRegistry;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
use TYPO3\CMS\Extbase\Service\ImageService;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
class RenderMediaViewHelper extends AbstractViewHelper
|
||||
{
|
||||
protected $escapeOutput = false;
|
||||
|
||||
protected $escapingInterceptorEnabled = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $mediaTag = '/\\[media\\]/';
|
||||
|
||||
protected $replaceMediaTag = '/(?:<p>\s*)?\\[media\\](?:\s*<\/p>)?/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $imgClass = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $videoClass = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $audioClass = '';
|
||||
|
||||
/**
|
||||
* Initialize all arguments. You need to override this method and call
|
||||
* $this->registerArgument(...) inside this method, to register all your arguments.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('news', 'object', 'the news post', true);
|
||||
$this->registerArgument('imgClass', 'string', 'add css class to images');
|
||||
$this->registerArgument('videoClass', 'string', 'wrap videos in a div with this class');
|
||||
$this->registerArgument('audioClass', 'string', 'wrap audio files in a div with this class');
|
||||
$this->registerArgument('fileIndex', 'int', 'index of image to start with', false, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Core\Resource\FileInterface $image
|
||||
* @return string
|
||||
*/
|
||||
private function renderImage(\TYPO3\CMS\Core\Resource\FileInterface $image): string
|
||||
{
|
||||
if ($this->objectManager === null) {
|
||||
$this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
}
|
||||
$imageService = $this->objectManager->get(ImageService::class);
|
||||
|
||||
$cropString = '';
|
||||
if ($image->hasProperty('crop')) {
|
||||
$cropString = $image->getProperty('crop');
|
||||
}
|
||||
$cropVariantCollection = CropVariantCollection::create((string)$cropString);
|
||||
$cropVariant = $this->arguments['cropVariant'] ?: 'default';
|
||||
$cropArea = $cropVariantCollection->getCropArea($cropVariant);
|
||||
$processingInstructions = [
|
||||
'width' => null,
|
||||
'height' => null,
|
||||
'crop' => $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image)
|
||||
];
|
||||
|
||||
$processedImage = $imageService->applyProcessingInstructions($image, $processingInstructions);
|
||||
$imageUri = $imageService->getImageUri($processedImage);
|
||||
|
||||
$alt = trim($image->getProperty('alternative'));
|
||||
$title = trim($image->getProperty('title'));
|
||||
$description = trim($image->getProperty('description'));
|
||||
|
||||
$imageAttributes = [
|
||||
'src' => $imageUri,
|
||||
'alt' => $alt ?: ($title ?: ''),
|
||||
'title' => $title
|
||||
];
|
||||
|
||||
if (!empty($this->imgClass)) {
|
||||
$imageAttributes['class'] = $this->imgClass;
|
||||
}
|
||||
|
||||
$imageAttributes = array_reduce(
|
||||
array_keys($imageAttributes),
|
||||
function ($carry, $key) use ($imageAttributes) {
|
||||
return $carry . ' ' . $key . '="' . htmlspecialchars($imageAttributes[$key]) . '"';
|
||||
},
|
||||
''
|
||||
);
|
||||
|
||||
if (!empty($description)) {
|
||||
$description = '<figcaption>' . htmlspecialchars($description) . '</figcaption>';
|
||||
}
|
||||
|
||||
return '<figure>' . '<img ' . $imageAttributes . ' />' . $description . '</figure>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the [media] tags with the output of the according media render output
|
||||
*
|
||||
* @param string $content
|
||||
* @param array $files
|
||||
* @return string
|
||||
*/
|
||||
private function renderMedia($content, array $files): string
|
||||
{
|
||||
$fileIndex = $this->arguments['fileIndex'];
|
||||
preg_match_all($this->mediaTag, $content, $matches);
|
||||
foreach ($matches[0] as $_) {
|
||||
/** @var \GeorgRinger\News\Domain\Model\FileReference $file */
|
||||
$file = null;
|
||||
/** @var \TYPO3\CMS\Core\Resource\FileReference $media */
|
||||
$media = null;
|
||||
|
||||
// check if a file is present for current media tag
|
||||
if (count($files) <= $fileIndex) {
|
||||
break;
|
||||
}
|
||||
|
||||
$file = $files[$fileIndex++];
|
||||
if ($file === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
$media = $file->getOriginalResource();
|
||||
$fileRenderer = RendererRegistry::getInstance()->getRenderer($media);
|
||||
|
||||
// if a renderer is configured for the file type use this renderer
|
||||
if ($fileRenderer !== null) {
|
||||
$media_tag = $fileRenderer->render($media, 0, 0);
|
||||
|
||||
// check if media tag needs to be wrapped in div, depends on type of media file
|
||||
$wrapClass= '';
|
||||
if ($media->getType() === File::FILETYPE_VIDEO) {
|
||||
$wrapClass = $this->videoClass;
|
||||
} elseif ($media->getType() === File::FILETYPE_AUDIO) {
|
||||
$wrapClass = $this->audioClass;
|
||||
}
|
||||
|
||||
if (!empty($wrapClass)) {
|
||||
$media_tag = '<div class="' . $wrapClass . '">' . $media_tag . '</div>';
|
||||
}
|
||||
}
|
||||
// fallback to image rendering
|
||||
else {
|
||||
$media_tag = $this->renderImage($media);
|
||||
}
|
||||
|
||||
// replace one tag in content with render output
|
||||
$content = preg_replace($this->replaceMediaTag, $media_tag, $content, 1);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string
|
||||
{
|
||||
/** @var News $news */
|
||||
$news = $this->arguments['news'];
|
||||
|
||||
$this->imgClass = htmlspecialchars($this->arguments['imgClass']);
|
||||
$this->videoClass = htmlspecialchars($this->arguments['videoClass']);
|
||||
$this->audioClass = htmlspecialchars($this->arguments['audioClass']);
|
||||
|
||||
$mediaFiles = (array)$news->getMediaNonPreviews();
|
||||
|
||||
$content = $this->renderChildren();
|
||||
$content = $this->renderMedia($content, $mediaFiles);
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
use GeorgRinger\News\Domain\Model\News;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
|
||||
use TYPO3\CMS\Core\Context\LanguageAspect;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ViewHelper for a **simple** prev/next link.
|
||||
* Only the pid is taken into account, nothing else!
|
||||
*
|
||||
* # Example: Basic example
|
||||
* <code>
|
||||
*
|
||||
* <n:simplePrevNext pidList="{newsItem.pid}" news="{newsItem}" as="paginated" sortField="datetime">
|
||||
* <f:if condition="{paginated}">
|
||||
* <ul class="prev-next">
|
||||
* <f:if condition="{paginated.prev}">
|
||||
* <li class="previous">
|
||||
* <n:link newsItem="{paginated.prev}" settings="{settings}">
|
||||
* {paginated.prev.title}
|
||||
* </n:link>
|
||||
* </li>
|
||||
* </f:if>
|
||||
* <f:if condition="{paginated.next}">
|
||||
* <li class="next">
|
||||
* <n:link newsItem="{paginated.next}" settings="{settings}" class="next">
|
||||
* {paginated.next.title}
|
||||
* </n:link>
|
||||
* </li>
|
||||
* </f:if>
|
||||
* </ul>
|
||||
* </f:if>
|
||||
* </n:simplePrevNext>
|
||||
*
|
||||
* The attributes includeExternalType & includeInternalType allow to include internal and
|
||||
* external news types.
|
||||
*
|
||||
* </code>
|
||||
* <output>
|
||||
* Menu with 2 li items with the link to the previous and next news item.
|
||||
* </output>
|
||||
*/
|
||||
class SimplePrevNextViewHelper extends AbstractViewHelper
|
||||
{
|
||||
|
||||
/* @var $dataMapper \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper */
|
||||
protected $dataMapper;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
/**
|
||||
* Inject the DataMapper
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper $dataMapper
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function injectDataMapper(DataMapper $dataMapper): void
|
||||
{
|
||||
$this->dataMapper = $dataMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize arguments.
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('news', News::class, 'news item', true);
|
||||
$this->registerArgument('pidList', 'string', 'pid list', false, '');
|
||||
$this->registerArgument('sortField', 'string', 'sort field', false, 'datetime');
|
||||
$this->registerArgument('as', 'string', 'as', true);
|
||||
$this->registerArgument('includeInternalType', 'boolean', 'Include internal news types', false, false);
|
||||
$this->registerArgument('includeExternalType', 'bool', 'Include external news types', false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string
|
||||
{
|
||||
$neighbours = $this->getNeighbours($this->arguments['news'], $this->arguments['pidList'], $this->arguments['sortField']);
|
||||
$as = $this->arguments['as'];
|
||||
|
||||
$mapped = $this->mapResultToObjects($neighbours);
|
||||
|
||||
$this->templateVariableContainer->add($as, $mapped);
|
||||
$output = $this->renderChildren();
|
||||
$this->templateVariableContainer->remove($as);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the array from DB to an understandable output
|
||||
*
|
||||
* @param array $result
|
||||
* @return array
|
||||
*/
|
||||
protected function mapResultToObjects(array $result): array
|
||||
{
|
||||
$out = [];
|
||||
foreach ($result as $_id => $single) {
|
||||
$out[$_id] = $this->getObject($single['uid']);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the news object from the given id
|
||||
*
|
||||
* @param int $id
|
||||
* @return mixed|null
|
||||
* @throws AspectNotFoundException
|
||||
*/
|
||||
protected function getObject($id)
|
||||
{
|
||||
$record = null;
|
||||
|
||||
$rawRecord = $this->getRawRecord($id);
|
||||
|
||||
/** @var LanguageAspect $languageAspect */
|
||||
$languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
|
||||
|
||||
if (isset($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE']) && $languageAspect->getContentId() > 0) {
|
||||
$overlay = $GLOBALS['TSFE']->sys_page->getRecordOverlay(
|
||||
'tx_news_domain_model_news',
|
||||
$rawRecord,
|
||||
$languageAspect->getContentId(),
|
||||
$languageAspect->getLegacyOverlayType()
|
||||
);
|
||||
if (!is_null($overlay)) {
|
||||
$rawRecord = $overlay;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($rawRecord)) {
|
||||
$records = $this->dataMapper->map(News::class, [$rawRecord]);
|
||||
$record = array_shift($records);
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param News $news
|
||||
* @param string $pidList
|
||||
* @param string $sortField
|
||||
* @return array
|
||||
*/
|
||||
protected function getNeighbours(News $news, string $pidList, string $sortField): array
|
||||
{
|
||||
$data = [];
|
||||
$pidList = empty($pidList) ? (string)$news->getPid() : $pidList;
|
||||
|
||||
$connection = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getConnectionForTable('tx_news_domain_model_news');
|
||||
|
||||
foreach (['prev', 'next'] as $label) {
|
||||
$queryBuilder = $connection->createQueryBuilder();
|
||||
|
||||
$extraWhere = [
|
||||
$queryBuilder->expr()->neq('uid', $queryBuilder->createNamedParameter($news->getUid(), \PDO::PARAM_INT))
|
||||
];
|
||||
if ((bool)($this->arguments['includeInternalType'] ?? false) === false) {
|
||||
$extraWhere[] = $queryBuilder->expr()->neq('type', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT));
|
||||
}
|
||||
if ((bool)($this->arguments['includeExternalType'] ?? false) === false) {
|
||||
$extraWhere[] = $queryBuilder->expr()->neq('type', $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT));
|
||||
}
|
||||
|
||||
$getter = 'get' . ucfirst($sortField) . '';
|
||||
if ($news->$getter() instanceof \DateTime) {
|
||||
if ($label === 'prev') {
|
||||
$extraWhere[] = $queryBuilder->expr()->lt($sortField, $queryBuilder->createNamedParameter($news->$getter()->getTimestamp(), \PDO::PARAM_INT));
|
||||
} else {
|
||||
$extraWhere[] = $queryBuilder->expr()->gt($sortField, $queryBuilder->createNamedParameter($news->$getter()->getTimestamp(), \PDO::PARAM_INT));
|
||||
}
|
||||
} else {
|
||||
if ($label === 'prev') {
|
||||
$extraWhere[] = $queryBuilder->expr()->lt($sortField, $queryBuilder->createNamedParameter($news->$getter(), \PDO::PARAM_STR));
|
||||
} else {
|
||||
$extraWhere[] = $queryBuilder->expr()->gt($sortField, $queryBuilder->createNamedParameter($news->$getter(), \PDO::PARAM_STR));
|
||||
}
|
||||
}
|
||||
|
||||
$row = $queryBuilder
|
||||
->select('*')
|
||||
->from('tx_news_domain_model_news')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)),
|
||||
$queryBuilder->expr()->in('pid', $queryBuilder->createNamedParameter(explode(',', $pidList), Connection::PARAM_INT_ARRAY))
|
||||
)
|
||||
->andWhere(...$extraWhere)
|
||||
->setMaxResults(1)
|
||||
->orderBy($sortField, ($label === 'prev' ? 'desc' : 'asc'))
|
||||
->execute()->fetch();
|
||||
if (is_array($row)) {
|
||||
$data[$label] = $row;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
protected function getQueryBuilder(): QueryBuilder
|
||||
{
|
||||
return GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tx_news_domain_model_news');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
protected function getRawRecord(int $id): ?array
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilder();
|
||||
$rawRecord = $queryBuilder
|
||||
->select('*')
|
||||
->from('tx_news_domain_model_news')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT))
|
||||
)
|
||||
->setMaxResults(1)
|
||||
->execute()->fetch();
|
||||
return $rawRecord;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers\Tag;
|
||||
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get usage count
|
||||
*
|
||||
* Example usage
|
||||
* {n:tag.count(tagUid:tag.uid) -> f:variable(name: 'tagUsageCount')}
|
||||
* {tagUsageCount}
|
||||
*/
|
||||
class CountViewHelper extends AbstractViewHelper implements ViewHelperInterface
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('tagUid', 'int', 'Uid of the tag', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return int
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
): int {
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tx_news_domain_model_news');
|
||||
|
||||
$count = $queryBuilder
|
||||
->count('tx_news_domain_model_news.title')
|
||||
->from('tx_news_domain_model_news')
|
||||
->rightJoin(
|
||||
'tx_news_domain_model_news',
|
||||
'tx_news_domain_model_news_tag_mm',
|
||||
'tx_news_domain_model_news_tag_mm',
|
||||
$queryBuilder->expr()->eq('tx_news_domain_model_news.uid', $queryBuilder->quoteIdentifier('tx_news_domain_model_news_tag_mm.uid_local'))
|
||||
)
|
||||
->rightJoin(
|
||||
'tx_news_domain_model_news_tag_mm',
|
||||
'tx_news_domain_model_tag',
|
||||
'tx_news_domain_model_tag',
|
||||
$queryBuilder->expr()->eq('tx_news_domain_model_tag.uid', $queryBuilder->quoteIdentifier('tx_news_domain_model_news_tag_mm.uid_foreign'))
|
||||
)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('tx_news_domain_model_tag.uid', $queryBuilder->createNamedParameter($arguments['tagUid'], \PDO::PARAM_INT))
|
||||
)
|
||||
->execute()
|
||||
->fetchColumn(0);
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* ViewHelper to get the target out of the typolink
|
||||
*
|
||||
* # Example: Basic Example
|
||||
* # Description: {relatedLink.uri} is defined as "123 _blank"
|
||||
* <code>
|
||||
* <f:link.typolink parameter="{relatedLink.uri}" target="{n:targetLink(link:relatedLink.uri)}">Link</f:link.typolink>
|
||||
* </code>
|
||||
* <output>
|
||||
* A link to the page with uid 123 and target set to "_blank"
|
||||
* </output>
|
||||
*/
|
||||
class TargetLinkViewHelper extends AbstractViewHelper implements ViewHelperInterface
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initialize arguments.
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('link', 'string', 'Link', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct target of a typolink
|
||||
*
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return mixed
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$params = explode(' ', $arguments['link']);
|
||||
|
||||
// The target is on the 2nd place and must start with a '_'
|
||||
if (count($params) >= 2 && substr($params[1], 0, 1) === '_') {
|
||||
return $params[1];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace GeorgRinger\News\ViewHelpers;
|
||||
|
||||
/**
|
||||
* This file is part of the "news" Extension for TYPO3 CMS.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use GeorgRinger\News\Seo\NewsTitleProvider;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface;
|
||||
|
||||
/**
|
||||
* ViewHelper to render the page title
|
||||
*
|
||||
* # Example: Basic Example
|
||||
* # Description: Render the content of the VH as page title
|
||||
* <code>
|
||||
* <n:titleTag>{newsItem.title}</n:titleTag>
|
||||
* </code>
|
||||
* <output>
|
||||
* <title>TYPO3 is awesome</title>
|
||||
* </output>
|
||||
*/
|
||||
class TitleTagViewHelper extends AbstractViewHelper implements ViewHelperInterface
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
): void {
|
||||
// Skip if current record is part of tt_content CType shortcut
|
||||
if (!empty($GLOBALS['TSFE']->recordRegister)
|
||||
&& is_array($GLOBALS['TSFE']->recordRegister)
|
||||
&& strpos(array_keys($GLOBALS['TSFE']->recordRegister)[0], 'tt_content:') !== false
|
||||
&& !empty($GLOBALS['TSFE']->currentRecord)
|
||||
&& strpos($GLOBALS['TSFE']->currentRecord, 'tx_news_domain_model_news:') !== false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = trim($renderChildrenClosure());
|
||||
if (!empty($content)) {
|
||||
GeneralUtility::makeInstance(NewsTitleProvider::class)->setTitle($content);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user