From 93556a0bc4195bed7ae869a4cd7b89c9bc9478e4 Mon Sep 17 00:00:00 2001
From: Kevin Ditscheid <kevin.ditscheid@sgalinski.de>
Date: Mon, 17 Dec 2018 17:23:14 +0100
Subject: [PATCH] [BUGFIX] Update ViewHelpers and deprecated calls

---
 Classes/Controller/BackendController.php      |  14 +-
 Classes/Utility/BackendNewsUtility.php        |   4 +-
 .../ViewHelpers/Backend/ControlViewHelper.php |  30 +++--
 .../Backend/EditOnClickViewHelper.php         |  23 +++-
 .../ViewHelpers/Backend/IconViewHelper.php    |  23 +++-
 .../Backend/NewsItemTagsViewHelper.php        |  19 ++-
 .../Backend/RecordIconViewHelper.php          |  21 ++-
 .../Backend/TranslationLinksViewHelper.php    |  24 +++-
 .../Backend/Widget/PaginateViewHelper.php     |  35 +++--
 .../ViewHelpers/GetReadingTimeViewHelper.php  |  15 ++-
 Configuration/TypoScript/Frontend/setup.txt   |   6 +-
 Resources/Private/Layouts/Backend.html        |   9 +-
 .../Private/Partials/Backend/SelectPage.html  |   6 +-
 Resources/Public/JavaScript/Backend.js        | 123 ++++++++++++++++++
 .../{Scripts => JavaScript}/CategoryFilter.js |   0
 .../Public/{Scripts => JavaScript}/Likes.js   |   0
 .../{Scripts => JavaScript}/ScrollBrowser.js  |   0
 .../Public/{Scripts => JavaScript}/Tabs.js    |   0
 Resources/Public/Scripts/Backend.js           | 101 --------------
 composer.json                                 |   2 +-
 ext_emconf.php                                |   2 +-
 ext_localconf.php                             |   2 +-
 22 files changed, 286 insertions(+), 173 deletions(-)
 create mode 100644 Resources/Public/JavaScript/Backend.js
 rename Resources/Public/{Scripts => JavaScript}/CategoryFilter.js (100%)
 rename Resources/Public/{Scripts => JavaScript}/Likes.js (100%)
 rename Resources/Public/{Scripts => JavaScript}/ScrollBrowser.js (100%)
 rename Resources/Public/{Scripts => JavaScript}/Tabs.js (100%)
 delete mode 100644 Resources/Public/Scripts/Backend.js

diff --git a/Classes/Controller/BackendController.php b/Classes/Controller/BackendController.php
index 2ce6d9d..ed2080d 100644
--- a/Classes/Controller/BackendController.php
+++ b/Classes/Controller/BackendController.php
@@ -121,11 +121,7 @@ class BackendController extends ActionController {
 	 * @api
 	 */
 	protected function initializeView(ViewInterface $view) {
-		if (VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version) >= 8000000) {
-			$GLOBALS['LANG']->includeLLFile('EXT:lang/Resources/Private/Language/locallang_mod_web_list.xlf');
-		} else {
-			$GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_mod_web_list.xlf');
-		}
+		$GLOBALS['LANG']->includeLLFile('EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf');
 		// create doc header component
 		$this->pageUid = (int) GeneralUtility::_GP('id');
 		/** @var BackendUserAuthentication $backendUser */
@@ -226,8 +222,12 @@ class BackendController extends ActionController {
 		// Refresh
 		$refreshButton = $buttonBar->makeLinkButton()
 			->setHref(GeneralUtility::getIndpEnv('REQUEST_URI'))
-			->setTitle(LocalizationUtility::translate('LLL:EXT:lang/locallang_core.xlf:labels.reload', ''))
-			->setIcon($iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL));
+			->setTitle(
+				LocalizationUtility::translate(
+					'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'
+				)
+			)
+			->setIcon($iconFactory->getIcon('actions-edit-undo', Icon::SIZE_SMALL));
 		$buttonBar->addButton($refreshButton, ButtonBar::BUTTON_POSITION_RIGHT);
 
 		// shortcut button
diff --git a/Classes/Utility/BackendNewsUtility.php b/Classes/Utility/BackendNewsUtility.php
index 8b677e5..a7cd4c2 100644
--- a/Classes/Utility/BackendNewsUtility.php
+++ b/Classes/Utility/BackendNewsUtility.php
@@ -84,7 +84,9 @@ class BackendNewsUtility {
 	public static function getAlternativePageOptions(): array {
 		$options = [];
 		/** @var array $rootOptionRows */
-		$rootOptionRows = self::getRecordsByField('pages', 'is_siteroot', 1, '', '', 'sorting');
+		$rootOptionRows = self::getRecordsByField(
+			'pages', 'is_siteroot', 1, ' AND sys_language_uid IN (0,-1)', '', 'sorting'
+		);
 		if ($rootOptionRows) {
 			foreach ($rootOptionRows as $row) {
 				$pageInfo = BackendUtility::readPageAccess($row['uid'], $GLOBALS['BE_USER']->getPagePermsClause(1));
diff --git a/Classes/ViewHelpers/Backend/ControlViewHelper.php b/Classes/ViewHelpers/Backend/ControlViewHelper.php
index d25c74a..c6a3fad 100644
--- a/Classes/ViewHelpers/Backend/ControlViewHelper.php
+++ b/Classes/ViewHelpers/Backend/ControlViewHelper.php
@@ -30,7 +30,6 @@ use SGalinski\SgNews\Service\LicensingService;
 use SGalinski\SgNews\ViewHelpers\AbstractViewHelper;
 use TYPO3\CMS\Backend\Clipboard\Clipboard;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -41,24 +40,35 @@ use TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList;
  * Class ControlViewHelper
  **/
 class ControlViewHelper extends AbstractViewHelper {
+
+	/**
+	 * Initialize the ViewHelper arguments
+	 */
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerArgument('table', 'string', 'The table to control', TRUE);
+		$this->registerArgument('row', 'mixed', 'The row of the record', TRUE);
+		$this->registerArgument('sortingData', 'array', 'The sorting data', FALSE, []);
+		$this->registerArgument('clipboard', 'bool', 'Use the clipboard', FALSE, FALSE);
+	}
+
 	/**
 	 * Renders the control buttons for the specified record
 	 *
-	 * @param string $table
-	 * @param mixed $row
-	 * @param array $sortingData
-	 * @param boolean $clipboard
 	 * @return string
 	 * @throws \InvalidArgumentException
 	 * @throws \UnexpectedValueException
 	 */
-	public function render($table, $row, array $sortingData = [], $clipboard = FALSE): string {
+	public function render(): string {
+		$table = $this->arguments['table'];
+		$row = $this->arguments['row'];
+		$sortingData = $this->arguments['sortingData'];
+		$clipboard = $this->arguments['clipboard'];
 		if (!is_array($row)) {
 			$row = BackendUtility::getRecord($table, $row->getUid());
 		}
-		/** @var DatabaseRecordList $databaseRecordList */
+
 		$databaseRecordList = GeneralUtility::makeInstance(DatabaseRecordList::class);
-		/** @var BackendUserAuthentication $backendUser */
 		$backendUser = $GLOBALS['BE_USER'];
 		$pageInfo = BackendUtility::readPageAccess($row['pid'], $backendUser->getPagePermsClause(1));
 		$databaseRecordList->calcPerms = $GLOBALS['BE_USER']->calcPerms($pageInfo);
@@ -66,6 +76,7 @@ class ControlViewHelper extends AbstractViewHelper {
 		if ($table === 'pages') {
 			$databaseRecordList->searchLevels = 1;
 		}
+
 		$out = $databaseRecordList->makeControl($table, $row);
 		if ($clipboard) {
 			$databaseRecordList->MOD_SETTINGS['clipBoard'] = TRUE;
@@ -74,6 +85,7 @@ class ControlViewHelper extends AbstractViewHelper {
 			$GLOBALS['SOBE'] = $databaseRecordList;
 			$out .= $databaseRecordList->makeClip($table, $row);
 		}
+
 		if ($table === 'pages' && LicensingService::checkKey()) {
 			$rootline = BackendUtility::BEgetRootLine($row['uid'], '', TRUE);
 			ksort($rootline);
@@ -82,7 +94,6 @@ class ControlViewHelper extends AbstractViewHelper {
 				$path .= '/p' . dechex($page['uid']);
 			}
 
-			/** @var IconFactory $iconFactory */
 			$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
 			$buttonLabel = LocalizationUtility::translate('backend.button.editPageContent', 'SgNews');
 			$onclick = 'return sgNewsGoToPageModule(' . $row['uid'] . ', \'' . $path . '\');';
@@ -92,6 +103,7 @@ class ControlViewHelper extends AbstractViewHelper {
 			$link = sprintf($link, $icon . ' ' . $buttonLabel);
 			$out .= sprintf($wrap, $link);
 		}
+
 		return $out;
 	}
 }
diff --git a/Classes/ViewHelpers/Backend/EditOnClickViewHelper.php b/Classes/ViewHelpers/Backend/EditOnClickViewHelper.php
index 9a643a8..a44a01b 100644
--- a/Classes/ViewHelpers/Backend/EditOnClickViewHelper.php
+++ b/Classes/ViewHelpers/Backend/EditOnClickViewHelper.php
@@ -34,21 +34,34 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
  * Class EditOnClickViewHelper
  **/
 class EditOnClickViewHelper extends AbstractViewHelper {
+
+	/**
+	 * Register the ViewHelper arguments
+	 */
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerArgument('table', 'string', 'The table for the clickenlarge link', TRUE);
+		$this->registerArgument('uid', 'int', 'The uid of the record to clickenlarge', TRUE);
+		$this->registerArgument('new', 'bool', 'Open a new record in the popup', FALSE, FALSE);
+		$this->registerArgument('type', 'string', 'The type of the news', FALSE, '');
+	}
+
 	/**
 	 * Renders the onclick script for editing a record
 	 *
-	 * @param string $table
-	 * @param int $uid
-	 * @param boolean $new
-	 * @param string $type
 	 * @return string
 	 */
-	public function render($table, $uid, $new = FALSE, $type = ''): string {
+	public function render(): string {
+		$table = $this->arguments['table'];
+		$uid = $this->arguments['uid'];
+		$new = $this->arguments['news'];
+		$type = $this->arguments['type'];
 		$additionalParameters = '';
 		if ($new && $table === 'pages' && in_array($type, ['news', 'category'], TRUE)) {
 			$additionalParameters = '&overrideVals[pages][doktype]=' .
 				($type === 'news' ? BackendNewsUtility::NEWS_DOKTYPE : BackendNewsUtility::CATEGORY_DOKTYPE);
 		}
+
 		return BackendUtility::editOnClick(
 			'&edit[' . $table . '][' . $uid . ']=' . ($new ? 'new' : 'edit') . $additionalParameters, '', -1
 		);
diff --git a/Classes/ViewHelpers/Backend/IconViewHelper.php b/Classes/ViewHelpers/Backend/IconViewHelper.php
index ec51011..5788ca4 100644
--- a/Classes/ViewHelpers/Backend/IconViewHelper.php
+++ b/Classes/ViewHelpers/Backend/IconViewHelper.php
@@ -35,19 +35,28 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * Class IconViewHelper
  **/
 class IconViewHelper extends AbstractViewHelper {
+
+	/**
+	 * Initialize the ViewHelper arguments
+	 */
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerArgument('id', 'string', 'The id of the record', TRUE);
+		$this->registerArgument('size', 'string', 'The size of the icon', FALSE, '');
+		$this->registerArgument('overlayId', 'string', 'The overlay of the icon', FALSE);
+	}
+
 	/**
 	 * Renders the icon for the specified identifier
 	 * with the requested size option and overlay.
 	 *
-	 * @param string $id
-	 * @param string $size
-	 * @param string $overlayId
 	 * @return string
 	 * @throws \InvalidArgumentException
 	 */
-	public function render($id, $size = '', $overlayId = NULL): string {
-		$id = trim($id);
-		$size = trim($size);
+	public function render(): string {
+		$id = trim($this->arguments['id']);
+		$size = trim($this->arguments['size']);
+		$overlayId = $this->arguments['overlayId'];
 		switch ($size) {
 			case 'small' :
 				$size = Icon::SIZE_SMALL;
@@ -59,7 +68,7 @@ class IconViewHelper extends AbstractViewHelper {
 				$size = Icon::SIZE_DEFAULT;
 				break;
 		}
-		/** @var IconFactory $iconFactory */
+
 		$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
 		return $iconFactory->getIcon($id, $size, $overlayId)->render();
 	}
diff --git a/Classes/ViewHelpers/Backend/NewsItemTagsViewHelper.php b/Classes/ViewHelpers/Backend/NewsItemTagsViewHelper.php
index 95bb308..ebaa298 100644
--- a/Classes/ViewHelpers/Backend/NewsItemTagsViewHelper.php
+++ b/Classes/ViewHelpers/Backend/NewsItemTagsViewHelper.php
@@ -33,23 +33,32 @@ use SGalinski\SgNews\ViewHelpers\AbstractViewHelper;
  * Class EditOnClickViewHelper
  **/
 class NewsItemTagsViewHelper extends AbstractViewHelper {
+
+	/**
+	 * Initialize the ViewHelper arguments
+	 */
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerArgument('uid', 'int', 'The uid of the news', FALSE, 0);
+		$this->registerArgument('languageUid', 'int', 'The language uid', FALSE, 0);
+	}
+
 	/**
 	 * Renders the tags for the specified news uid
 	 *
-	 * @param int $uid
-	 * @param int $languageUid
 	 * @return string
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 * @throws \InvalidArgumentException
 	 */
-	public function render($uid = 0, $languageUid = 0): string {
+	public function render(): string {
 		$out = '';
-		$uid = (int) $uid;
-		$languageUid = (int) $languageUid;
+		$uid = $this->arguments['uid'];
+		$languageUid = $this->arguments['languageUid'];
 		if ($uid) {
 			$tags = BackendNewsUtility::getTagsForNewsItem($uid, $languageUid);
 			$out = implode(', ', $tags);
 		}
+
 		return $out;
 	}
 }
diff --git a/Classes/ViewHelpers/Backend/RecordIconViewHelper.php b/Classes/ViewHelpers/Backend/RecordIconViewHelper.php
index 222e757..20f18b7 100644
--- a/Classes/ViewHelpers/Backend/RecordIconViewHelper.php
+++ b/Classes/ViewHelpers/Backend/RecordIconViewHelper.php
@@ -36,17 +36,27 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * Class IconViewHelper
  **/
 class RecordIconViewHelper extends AbstractViewHelper {
+
+	/**
+	 * Initialize the ViewHelper arguments
+	 */
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerArgument('table', 'string', 'The table of the record', TRUE);
+		$this->registerArgument('row', 'array', 'The row of the record icon', TRUE);
+		$this->registerArgument('clickMenu', 'bool', 'Render the click menu', FALSE, TRUE);
+	}
+
 	/**
 	 * Renders the icon for the specified record
 	 *
-	 * @param string $table
-	 * @param mixed $row
-	 * @param boolean $clickMenu
 	 * @return string
 	 * @throws \InvalidArgumentException
 	 */
-	public function render($table, $row, $clickMenu = TRUE): string {
-		/** @var IconFactory $iconFactory */
+	public function render(): string {
+		$table = $this->arguments['table'];
+		$row = $this->arguments['row'];
+		$clickMenu = $this->arguments['clickMenu'];
 		$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
 		$toolTip = BackendUtility::getRecordToolTip($row, $table);
 		$iconImg = '<span ' . $toolTip . '>'
@@ -55,6 +65,7 @@ class RecordIconViewHelper extends AbstractViewHelper {
 		if ($clickMenu) {
 			return BackendUtility::wrapClickMenuOnIcon($iconImg, $table, $row['uid']);
 		}
+
 		return $iconImg;
 	}
 }
diff --git a/Classes/ViewHelpers/Backend/TranslationLinksViewHelper.php b/Classes/ViewHelpers/Backend/TranslationLinksViewHelper.php
index c9a4664..df34c49 100644
--- a/Classes/ViewHelpers/Backend/TranslationLinksViewHelper.php
+++ b/Classes/ViewHelpers/Backend/TranslationLinksViewHelper.php
@@ -40,16 +40,27 @@ use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
  * Class EditOnClickViewHelper
  **/
 class TranslationLinksViewHelper extends AbstractViewHelper {
+
+	/**
+	 * Register the ViewHelp0er arguments
+	 */
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerArgument('uid', 'int', 'The uid of the record', TRUE);
+		$this->registerArgument('table', 'string', 'The table of the record', TRUE);
+		$this->registerArgument('pageUid', 'int', 'The uid of the page', FALSE, 0);
+	}
+
 	/**
 	 * Renders the translation links for the specified record
 	 *
-	 * @param int $pageUid
-	 * @param string $table
-	 * @param int $uid
 	 * @return string
 	 * @throws \InvalidArgumentException
 	 */
-	public function render($pageUid = 0, $table, $uid): string {
+	public function render(): string {
+		$uid = $this->arguments['uid'];
+		$table = $this->arguments['table'];
+		$pageUid = $this->arguments['pageUid'];
 		$out = '';
 		if (!LicensingService::checkKey()) {
 			return $out;
@@ -62,7 +73,6 @@ class TranslationLinksViewHelper extends AbstractViewHelper {
 		$pageUid = (int) $pageUid;
 		$row = BackendUtility::getRecord($table, $uid);
 		if ($row) {
-			/** @var IconFactory $iconFactory */
 			$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
 			$lanuageField = $GLOBALS['TCA'][$table]['ctrl']['languageField'];
 			$currentLanguageUid = $table === 'pages' ? 0 : $row[$lanuageField];
@@ -115,7 +125,9 @@ class TranslationLinksViewHelper extends AbstractViewHelper {
 					}
 					$out .= ' <a href="#" onclick="' . $onClick . '" title="' . $language['title'] . ' [' . $newLabel . ']" >' .
 						$iconFactory->getIcon(
-							$language['flag'], Icon::SIZE_SMALL, 'overlay-new',
+							$language['flag'],
+							Icon::SIZE_SMALL,
+							'overlay-new',
 							IconState::cast(IconState::STATE_DISABLED)
 						)->render() .
 						'</a>';
diff --git a/Classes/ViewHelpers/Backend/Widget/PaginateViewHelper.php b/Classes/ViewHelpers/Backend/Widget/PaginateViewHelper.php
index b3dd0b0..644806b 100644
--- a/Classes/ViewHelpers/Backend/Widget/PaginateViewHelper.php
+++ b/Classes/ViewHelpers/Backend/Widget/PaginateViewHelper.php
@@ -33,7 +33,7 @@ use TYPO3\CMS\Fluid\Core\Widget\AbstractWidgetViewHelper;
  */
 class PaginateViewHelper extends AbstractWidgetViewHelper {
 	/**
-	 * @var \SGalinski\SgNews\ViewHelpers\Backend\Widget\Controller\PaginateController
+	 * @var PaginateController
 	 */
 	protected $controller;
 
@@ -42,25 +42,38 @@ class PaginateViewHelper extends AbstractWidgetViewHelper {
 	 *
 	 * @param PaginateController $controller
 	 */
-	public function injectPaginateController(
-		PaginateController $controller
-	) {
+	public function injectPaginateController(PaginateController $controller) {
 		$this->controller = $controller;
 	}
 
+	/**
+	 * Initialize the ViewHelper arguments
+	 */
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerArgument('objects', 'mixed', 'The objects to paginate', TRUE);
+		$this->registerArgument('as', 'string', 'The name of the variable inside the pagination', TRUE);
+		$this->registerArgument(
+			'configuration',
+			'array',
+			'The configuration of the pagination',
+			FALSE,
+			[
+				'itemsPerPage' => 10,
+				'insertAbove' => FALSE,
+				'insertBelow' => TRUE,
+				'recordsLabel' => ''
+			]
+		);
+	}
+
 	/**
 	 * Renders the paginator
 	 *
-	 * @param mixed $objects
-	 * @param string $as
-	 * @param array $configuration
 	 * @return string
 	 * @throws \TYPO3\CMS\Fluid\Core\Widget\Exception\MissingControllerException
 	 */
-	public function render(
-		$objects, $as,
-		array $configuration = ['itemsPerPage' => 10, 'insertAbove' => FALSE, 'insertBelow' => TRUE, 'recordsLabel' => '']
-	): string {
+	public function render(): string {
 		return $this->initiateSubRequest();
 	}
 }
diff --git a/Classes/ViewHelpers/GetReadingTimeViewHelper.php b/Classes/ViewHelpers/GetReadingTimeViewHelper.php
index 69d48c2..eb60192 100644
--- a/Classes/ViewHelpers/GetReadingTimeViewHelper.php
+++ b/Classes/ViewHelpers/GetReadingTimeViewHelper.php
@@ -26,7 +26,7 @@ namespace SGalinski\SgNews\ViewHelpers;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
-use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 
 /**
  * View helper that returns the estimates reading time of a given content
@@ -36,13 +36,22 @@ use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
  * <sg:getReadingTime content="" />
  */
 class GetReadingTimeViewHelper extends AbstractViewHelper {
+
+	/**
+	 * Register the ViewHelper arguments
+	 */
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerArgument('content', 'string', 'The content to read', TRUE);
+	}
+
 	/**
 	 * Returns the estimated reading time of the given content
 	 *
-	 * @param string $content
 	 * @return string
 	 */
-	public function render($content): string {
+	public function render(): string {
+		$content = $this->arguments['content'];
 		$word = str_word_count(strip_tags($content));
 		$minutes = floor($word / 200);
 		$seconds = floor($word % 200 / (200 / 60));
diff --git a/Configuration/TypoScript/Frontend/setup.txt b/Configuration/TypoScript/Frontend/setup.txt
index 9ec4f5e..6c371b2 100644
--- a/Configuration/TypoScript/Frontend/setup.txt
+++ b/Configuration/TypoScript/Frontend/setup.txt
@@ -1,8 +1,8 @@
 # include the endless scrolling javascript code
 page.includeJSFooterlibs {
-	sg_news_scrollbrowser = EXT:sg_news/Resources/Public/Scripts/ScrollBrowser.js
-	sg_news_tabs = EXT:sg_news/Resources/Public/Scripts/Tabs.js
-	sg_news_likes = EXT:sg_news/Resources/Public/Scripts/Likes.js
+	sg_news_scrollbrowser = EXT:sg_news/Resources/Public/JavaScript/ScrollBrowser.js
+	sg_news_tabs = EXT:sg_news/Resources/Public/JavaScript/Tabs.js
+	sg_news_likes = EXT:sg_news/Resources/Public/JavaScript/Likes.js
 }
 
 # news feed as own page type
diff --git a/Resources/Private/Layouts/Backend.html b/Resources/Private/Layouts/Backend.html
index 8d09914..a97ecad 100644
--- a/Resources/Private/Layouts/Backend.html
+++ b/Resources/Private/Layouts/Backend.html
@@ -1,12 +1,13 @@
 {namespace core = TYPO3\CMS\Core\ViewHelpers}
 {namespace sg=SGalinski\SgNews\ViewHelpers}
 
-<f:be.container enableClickMenu="FALSE" loadExtJs="FALSE"
+<f:be.container
 	includeRequireJsModules="{
 		0: 'TYPO3/CMS/Backend/AjaxDataHandler',
-		1:  '{f:if(condition: \'{typo3Version} < 8000000 \', then: \'TYPO3/CMS/Backend/ClickMenu\', else: \'TYPO3/CMS/Backend/ContextMenu\')}',
+		1: 'TYPO3/CMS/Backend/ContextMenu',
 		2: 'TYPO3/CMS/Backend/Tooltip',
-		2: 'TYPO3/CMS/Recordlist/Tooltip'}"
+		3: 'TYPO3/CMS/Recordlist/Tooltip',
+		4: 'TYPO3/CMS/SgNews/Backend'}"
 	includeJsFiles="{0: '{f:uri.resource(path: \'Scripts/Backend.js\')}'}">
 	<div class="module" data-module-id="" data-module-name="">
 		<div class="module-docheader t3js-module-docheader">
@@ -21,7 +22,7 @@
 					</f:for>
 				</div>
 				<div class="module-docheader-bar-column-right">
-					<span class="typo3-docheader-pagePath"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw></span>
+					<span class="typo3-docheader-pagePath"><f:translate key="LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw></span>
 					<f:format.raw>{docHeader.metaInformation.recordInformation}</f:format.raw>
 				</div>
 			</div>
diff --git a/Resources/Private/Partials/Backend/SelectPage.html b/Resources/Private/Partials/Backend/SelectPage.html
index 7957f43..5779b08 100644
--- a/Resources/Private/Partials/Backend/SelectPage.html
+++ b/Resources/Private/Partials/Backend/SelectPage.html
@@ -17,9 +17,9 @@
 					<f:for each="{pages}" as="page">
 						<tr data-uid="{page.uid}">
 							<td nowrap="nowrap" class="col-title">
-								<a href="#" onclick="sgNewsGoToPage({page.uid}, '{page.path}'); return false;">
+								<f:link.action action="index" additionalParams="{id: page.uid, returnUrl: returnUrl}">
 									<sg:backend.recordIcon table="pages" row="{page}" clickMenu="0" /> {page._thePathFull}
-								</a>
+								</f:link.action>
 							</td>
 						</tr>
 					</f:for>
@@ -27,4 +27,4 @@
 			</table>
 		</div>
 	</div>
-</f:if>
\ No newline at end of file
+</f:if>
diff --git a/Resources/Public/JavaScript/Backend.js b/Resources/Public/JavaScript/Backend.js
new file mode 100644
index 0000000..512a775
--- /dev/null
+++ b/Resources/Public/JavaScript/Backend.js
@@ -0,0 +1,123 @@
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) sgalinski Internet Services (https://www.sgalinski.de)
+ *
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+define(['jquery'], function($) {
+	'use strict';
+	var SgNewsModule = {
+		init: function() {
+			$.get(TYPO3.settings.ajaxUrls['sg_news::ajaxPing']);
+			$('#filter-reset-btn').on('click', function(event) {
+				event.preventDefault();
+				this.form.reset();
+				$(this).closest('form').find('select').val('');
+				$('#filter-search').val('');
+				this.form.submit();
+			});
+		},
+		// functions for backend docheader functionality
+		jumpExt: function(URL, anchor) {
+			var anc = anchor ? anchor : "";
+			window.location.href = URL + (T3_THIS_LOCATION ? "&returnUrl=" + T3_THIS_LOCATION : "") + anc;
+			return false;
+		},
+		jumpSelf: function(URL) {
+			window.location.href = URL + (T3_RETURN_URL ? "&returnUrl=" + T3_RETURN_URL : "");
+			return false;
+		},
+		jumpToUrl: function(URL) {
+			window.location.href = URL;
+			return false;
+		},
+		setHighlight: function(id) {
+			top.fsMod.recentIds["web"] = id;
+			top.fsMod.navFrameHighlightedID["web"] = "pages" + id + "_" + top.fsMod.currentBank;    // For highlighting
+			if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
+				top.content.nav_frame.refresh_nav();
+			}
+		},
+		/**
+		 * Switches to the spefied page in the BE
+		 *
+		 * @param {number} uid
+		 * @param {string} path
+		 */
+		sgNewsGoToPage: function(uid, path, selectOnly) {
+			parent.fsMod.recentIds['web'] = uid;
+			if (typeof selectOnly === 'undefined') {
+				selectOnly = false;
+			}
+			selectOnly = Boolean(selectOnly);
+			if (top.nav) {
+				if (selectOnly) {
+					top.nav.invokePageId(uid, SgNewsModule.gotToPageCallbackNoFollow);
+				} else {
+					top.nav.invokePageId(uid, SgNewsModule.gotToPageCallback);
+				}
+			} else {
+				var tree = top.Ext.getCmp('typo3-pagetree');
+				if (tree) {
+					tree.activeTree.selectPath(path);
+				}
+				if (selectOnly) {
+					return;
+				}
+				var separator = '?';
+				if (top.currentSubScript.indexOf('?') !== -1) {
+					separator = '&';
+				}
+				top.TYPO3.Backend.ContentContainer.setUrl(
+					top.currentSubScript + separator + 'id=' + uid
+				);
+			}
+		},
+		/**
+		 * Callback for page selection in the pagetree without follow
+		 */
+		gotToPageCallbackNoFollow: function(path) {
+			var callback = top.Ext.createDelegate(top.nav.mainTree.selectPath, top.nav.mainTree);
+			callback.apply(this, arguments);
+		},
+		/**
+		 * Callback for page selection in the pagetree
+		 */
+		gotToPageCallback: function(path) {
+			var callback = top.Ext.createDelegate(top.nav.mainTree.selectPath, top.nav.mainTree);
+			callback.apply(this, arguments);
+			var node = top.nav.getSelected();
+			if (node) {
+				top.TYPO3.Components.PageTree.Actions.singleClick(node, top.TYPO3.Components.PageTree.Tree);
+			}
+		},
+		sgNewsGoToPageModule: function(uid, path) {
+			SgNewsModule.sgNewsGoToPage(uid, path, true);
+			parent.TYPO3.ModuleMenu.App.showModule('web_layout');
+			return false;
+		}
+	};
+
+	TYPO3.SgNewsModule = SgNewsModule;
+
+	SgNewsModule.init();
+	return SgNewsModule;
+});
diff --git a/Resources/Public/Scripts/CategoryFilter.js b/Resources/Public/JavaScript/CategoryFilter.js
similarity index 100%
rename from Resources/Public/Scripts/CategoryFilter.js
rename to Resources/Public/JavaScript/CategoryFilter.js
diff --git a/Resources/Public/Scripts/Likes.js b/Resources/Public/JavaScript/Likes.js
similarity index 100%
rename from Resources/Public/Scripts/Likes.js
rename to Resources/Public/JavaScript/Likes.js
diff --git a/Resources/Public/Scripts/ScrollBrowser.js b/Resources/Public/JavaScript/ScrollBrowser.js
similarity index 100%
rename from Resources/Public/Scripts/ScrollBrowser.js
rename to Resources/Public/JavaScript/ScrollBrowser.js
diff --git a/Resources/Public/Scripts/Tabs.js b/Resources/Public/JavaScript/Tabs.js
similarity index 100%
rename from Resources/Public/Scripts/Tabs.js
rename to Resources/Public/JavaScript/Tabs.js
diff --git a/Resources/Public/Scripts/Backend.js b/Resources/Public/Scripts/Backend.js
deleted file mode 100644
index 7a32bfb..0000000
--- a/Resources/Public/Scripts/Backend.js
+++ /dev/null
@@ -1,101 +0,0 @@
-(function($) {
-	$(document).ready(function() {
-		$.get(TYPO3.settings.ajaxUrls['sg_news::ajaxPing']);
-		$('#filter-reset-btn').on('click', function(event) {
-			event.preventDefault();
-			this.form.reset();
-			$(this).closest('form').find('select').val('');
-			$('#filter-search').val('');
-			this.form.submit();
-		});
-	});
-})(TYPO3.jQuery);
-
-// functions for backend docheader functionality
-function jumpExt(URL, anchor) {    //
-	var anc = anchor ? anchor : "";
-	window.location.href = URL + (T3_THIS_LOCATION ? "&returnUrl=" + T3_THIS_LOCATION : "") + anc;
-	return false;
-}
-
-function jumpSelf(URL) {    //
-	window.location.href = URL + (T3_RETURN_URL ? "&returnUrl=" + T3_RETURN_URL : "");
-	return false;
-}
-
-function jumpToUrl(URL) {
-	window.location.href = URL;
-	return false;
-}
-
-function setHighlight(id) {    //
-	top.fsMod.recentIds["web"] = id;
-	top.fsMod.navFrameHighlightedID["web"] = "pages" + id + "_" + top.fsMod.currentBank;    // For highlighting
-	if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
-		top.content.nav_frame.refresh_nav();
-	}
-}
-
-/**
- * Switches to the spefied page in the BE
- *
- * @param {number} uid
- * @param {string} path
- */
-function sgNewsGoToPage(uid, path, selectOnly) {
-	parent.fsMod.recentIds['web'] = uid;
-	if(typeof selectOnly === 'undefined') {
-		selectOnly = false;
-	}
-	selectOnly = Boolean(selectOnly);
-	if (top.nav) {
-		if (selectOnly) {
-			top.nav.invokePageId(uid, gotToPageCallbackNoFollow);
-		} else {
-			top.nav.invokePageId(uid, gotToPageCallback);
-		}
-	} else {
-		var tree = top.Ext.getCmp('typo3-pagetree');
-		if (tree) {
-			tree.activeTree.selectPath(path);
-		}
-		if (selectOnly) {
-			return;
-		}
-		var separator = '?';
-		if (top.currentSubScript.indexOf('?') !== -1) {
-			separator = '&';
-		}
-		top.TYPO3.Backend.ContentContainer.setUrl(
-			top.currentSubScript + separator + 'id=' + uid
-		);
-	}
-}
-
-
-/**
- * Callback for page selection in the pagetree without follow
- */
-function gotToPageCallbackNoFollow(path){
-	var callback = top.Ext.createDelegate(top.nav.mainTree.selectPath, top.nav.mainTree);
-	callback.apply(this, arguments);
-}
-
-
-/**
- * Callback for page selection in the pagetree
- */
-function gotToPageCallback(path){
-	var callback = top.Ext.createDelegate(top.nav.mainTree.selectPath, top.nav.mainTree);
-	callback.apply(this, arguments);
-	var node = top.nav.getSelected();
-	if (node) {
-		top.TYPO3.Components.PageTree.Actions.singleClick(node, top.TYPO3.Components.PageTree.Tree);
-	}
-}
-
-function sgNewsGoToPageModule(uid, path) {
-	sgNewsGoToPage(uid, path, true);
-	parent.TYPO3.ModuleMenu.App.showModule('web_layout');
-	return false;
-}
diff --git a/composer.json b/composer.json
index 147d7cb..d4ea7a2 100644
--- a/composer.json
+++ b/composer.json
@@ -24,7 +24,7 @@
 		}
 	],
 	"require": {
-		"typo3/cms-core": "^7.6.0 || ^8.7.0 || ^9.5.1",
+		"typo3/cms-core": "^8.7.0 || ^9.5.1",
 		"stefanfroemken/repair_translation": "^1.0"
 	},
 	"require-dev": {
diff --git a/ext_emconf.php b/ext_emconf.php
index 6264a43..2968cc2 100644
--- a/ext_emconf.php
+++ b/ext_emconf.php
@@ -22,7 +22,7 @@ $EM_CONF[$_EXTKEY] = [
 	'version' => '5.7.1',
 	'constraints' => [
 		'depends' => [
-			'typo3' => '7.6.0-9.5.99',
+			'typo3' => '8.7.0-9.5.99',
 			'php' => '7.0.0-7.3.99',
 		],
 		'conflicts' => [],
diff --git a/ext_localconf.php b/ext_localconf.php
index df06519..5ff9bb5 100644
--- a/ext_localconf.php
+++ b/ext_localconf.php
@@ -72,7 +72,7 @@ if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('sg_ajax')) {
 
 // hook registration
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] =
-	'EXT:sg_news/Classes/TCA/TcaProvider.php:SGalinski\SgNews\TCA\TcaProvider';
+	'SGalinski\SgNews\TCA\TcaProvider';
 
 // Xclasses
 $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects']['TYPO3\CMS\Core\Page\PageRenderer'] =
-- 
GitLab