[!!!][TASK] Migrate cshmanual to Extbase & Fluid 26/34226/15
authorGeorg Ringer <georg.ringer@gmail.com>
Sat, 15 Nov 2014 20:21:32 +0000 (21:21 +0100)
committerFrank Nägler <frank.naegler@typo3.org>
Fri, 7 Aug 2015 13:34:05 +0000 (15:34 +0200)
Use a proper code base for the system extension "cshmanual".

Resolves: #63000
Releases: master
Change-Id: I0981c94dca0bec1d3603fd27b9aa56860788f1a3
Reviewed-on: http://review.typo3.org/34226
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Frank Nägler <frank.naegler@typo3.org>
Tested-by: Frank Nägler <frank.naegler@typo3.org>
18 files changed:
typo3/sysext/backend/Classes/Controller/BackendLayoutWizardController.php
typo3/sysext/backend/Classes/Template/DocumentTemplate.php
typo3/sysext/backend/Resources/Public/JavaScript/ContextHelp.js
typo3/sysext/core/Documentation/Changelog/master/Breaking-63000-MigrateCshmanualToExtbase.rst [new file with mode: 0644]
typo3/sysext/cshmanual/Classes/Controller/HelpController.php [new file with mode: 0644]
typo3/sysext/cshmanual/Classes/Controller/HelpModuleController.php [deleted file]
typo3/sysext/cshmanual/Classes/Domain/Repository/TableManualRepository.php [new file with mode: 0644]
typo3/sysext/cshmanual/Classes/Service/AccessService.php [new file with mode: 0644]
typo3/sysext/cshmanual/Classes/ViewHelpers/FormatViewHelper.php [new file with mode: 0644]
typo3/sysext/cshmanual/Modules/CshManual/index.php [deleted file]
typo3/sysext/cshmanual/Resources/Private/Layouts/Default.html [new file with mode: 0644]
typo3/sysext/cshmanual/Resources/Private/Partials/Manual.html [new file with mode: 0644]
typo3/sysext/cshmanual/Resources/Private/Partials/TableOfContents.html [new file with mode: 0644]
typo3/sysext/cshmanual/Resources/Private/Templates/Help/All.html [new file with mode: 0644]
typo3/sysext/cshmanual/Resources/Private/Templates/Help/Detail.html [new file with mode: 0644]
typo3/sysext/cshmanual/Resources/Private/Templates/Help/Index.html [new file with mode: 0644]
typo3/sysext/cshmanual/Resources/Private/Templates/cshmanual.html [deleted file]
typo3/sysext/cshmanual/ext_tables.php

index d80b18b..364f800 100644 (file)
@@ -83,7 +83,12 @@ class BackendLayoutWizardController {
                $pageRenderer->loadExtJS();
                $pageRenderer->addJsFile(ExtensionManagementUtility::extRelPath('backend') . 'Resources/Public/JavaScript/grideditor.js');
                $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
-               $pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', BackendUtility::getModuleUrl('help_cshmanual'));
+               $pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', BackendUtility::getModuleUrl('help_CshmanualCshmanual', array(
+                       'tx_cshmanual_help_cshmanualcshmanual' => array(
+                               'controller' => 'Help',
+                               'action' => 'detail'
+                       )
+               )));
                $pageRenderer->addJsInlineCode('storeData', '
                        function storeData(data) {
                                if (parent.opener && parent.opener.document && parent.opener.document.' . $this->formName . ' && parent.opener.document.' . $this->formName . '[' . GeneralUtility::quoteJSvalue($this->fieldName) . ']) {
index 33770f9..9b24869 100644 (file)
@@ -1509,7 +1509,12 @@ function jumpToUrl(URL) {
         */
        protected function loadCshJavascript() {
                $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextHelp');
-               $this->pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', BackendUtility::getModuleUrl('help_cshmanual'));
+               $this->pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', BackendUtility::getModuleUrl('help_CshmanualCshmanual', array(
+                       'tx_cshmanual_help_cshmanualcshmanual' => array(
+                               'controller' => 'Help',
+                               'action' => 'detail'
+                       )
+               )));
        }
 
        /**
index 9ff4caf..531641c 100644 (file)
@@ -94,11 +94,12 @@ define('TYPO3/CMS/Backend/ContextHelp', ['jquery', 'TYPO3/CMS/Backend/Popover',
         * @param {object} $trigger
         */
        ContextHelp.showHelpPopup = function($trigger) {
-               var identifier = $trigger.data('table') + '.' + $trigger.data('field'),
-                       configuration = top.TYPO3.configuration.ContextHelpWindows || top.TYPO3.configuration.PopupWindow;
+               var configuration = top.TYPO3.configuration.ContextHelpWindows || top.TYPO3.configuration.PopupWindow;
                try {
                        var cshWindow = window.open(
-                               ContextHelp.helpModuleUrl + '&tfID=' + identifier,
+                               ContextHelp.helpModuleUrl +
+                                       '&tx_cshmanual_help_cshmanualcshmanual[table]=' + $trigger.data('table') +
+                                       '&tx_cshmanual_help_cshmanualcshmanual[field]=' + $trigger.data('field'),
                                'ContextHelpWindow',
                                'height=' + configuration.height + ',width=' + configuration.width + ',status=0,menubar=0,scrollbars=1'
                        );
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-63000-MigrateCshmanualToExtbase.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-63000-MigrateCshmanualToExtbase.rst
new file mode 100644 (file)
index 0000000..368e492
--- /dev/null
@@ -0,0 +1,26 @@
+===================================================
+Breaking: #63000 - Migrate EXT:cshmanual to Extbase
+===================================================
+
+Description
+===========
+
+The extension "cshmanual" has been migrated to a newer code base by using Extbase and Fluid.
+
+
+Impact
+======
+
+Any call to the previous public methods of the old controller HelpModuleController will fail as the code base changed.
+
+
+Affected installations
+======================
+
+Any installation using an extension which calls the previously available methods directly.
+
+
+Migration
+=========
+
+Use the Extbase controller or Repository class.
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Classes/Controller/HelpController.php b/typo3/sysext/cshmanual/Classes/Controller/HelpController.php
new file mode 100644 (file)
index 0000000..94ae307
--- /dev/null
@@ -0,0 +1,118 @@
+<?php
+namespace TYPO3\CMS\Cshmanual\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Cshmanual\Domain\Repository\TableManualRepository;
+use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+
+/**
+ * Main help module controller
+ */
+class HelpController extends ActionController {
+
+       /**
+        * Section identifiers
+        */
+       const FULL = 0;
+       const TOC_ONLY = 1;
+
+       /**
+        * @var TableManualRepository
+        */
+       protected $tableManualRepository;
+
+       /**
+        * Initialize the controller
+        *
+        * @return void
+        */
+       public function initializeAction() {
+               $this->tableManualRepository = GeneralUtility::makeInstance(TableManualRepository::class);
+       }
+
+       /**
+        * Initialize the view
+        *
+        * @param \TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view The view
+        * @return void
+        */
+       public function initializeView(\TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view) {
+               $view->assign('copyright', BackendUtility::TYPO3_copyRightNotice());
+       }
+
+       /**
+        * Show table of contents
+        *
+        * @return void
+        */
+       public function indexAction() {
+               $this->view->assign('toc', $this->tableManualRepository->getSections(self::TOC_ONLY));
+       }
+
+       /**
+        * Show the table of contents and all manuals
+        *
+        * @return void
+        */
+       public function allAction() {
+               $this->view->assign('all', $this->tableManualRepository->getSections(self::FULL));
+       }
+
+       /**
+        * Show a single manual
+        *
+        * @param string $table
+        * @param string $field
+        * @return void
+        */
+       public function detailAction($table = '', $field = '*') {
+               if (empty($table)) {
+                       $this->forward('index');
+               }
+
+               $mainKey = $table;
+               $identifierParts = GeneralUtility::trimExplode('.', $field);
+               // The field is the second one
+               if (count($identifierParts) > 1) {
+                       array_shift($field);
+                       // There's at least one extra part
+                       $extraIdentifierInformation = array();
+                       $extraIdentifierInformation[] = array_shift($identifierParts);
+                       // If the ds_pointerField contains a comma, it means the choice of FlexForm DS
+                       // is determined by 2 parameters. In this case we have an extra identifier part
+                       if (strpos($GLOBALS['TCA'][$table]['columns'][$field]['config']['ds_pointerField'], ',') !== FALSE) {
+                               $extraIdentifierInformation[] = array_shift($identifierParts);
+                       }
+                       // The remaining parts make up the FlexForm field name itself (reassembled with dots)
+                       $flexFormField = implode('.', $identifierParts);
+                       // Assemble a different main key and switch field to use FlexForm field name
+                       $mainKey .= '.' . $field;
+                       foreach ($extraIdentifierInformation as $extraKey) {
+                               $mainKey .= '.' . $extraKey;
+                       }
+                       $field = $flexFormField;
+               }
+
+               $this->view->assignMultiple(array(
+                       'table' => $table,
+                       'key' => $mainKey,
+                       'field' => $field,
+                       'manuals' => $field === '*' ? $this->tableManualRepository->getTableManual($mainKey) : array($this->tableManualRepository->getSingleManual($mainKey, $field)),
+               ));
+       }
+
+}
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Classes/Controller/HelpModuleController.php b/typo3/sysext/cshmanual/Classes/Controller/HelpModuleController.php
deleted file mode 100644 (file)
index a18dcb9..0000000
+++ /dev/null
@@ -1,594 +0,0 @@
-<?php
-namespace TYPO3\CMS\Cshmanual\Controller;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * Script Class for rendering the Context Sensitive Help documents,
- * either the single display in the small pop-up window or the full-table view in the larger window.
- */
-class HelpModuleController {
-
-       /**
-        * @var string
-        */
-       public $allowedHTML = '<strong><em><b><i>';
-
-       /**
-        * For these vars, see init()
-        * If set access to fields and tables is checked. Should be done for TRUE database tables.
-        *
-        * @var bool
-        */
-       public $limitAccess;
-
-       /**
-        * The "table" key
-        *
-        * @var string
-        */
-       public $table;
-
-       /**
-        * The "field" key
-        *
-        * @var string
-        */
-       public $field;
-
-       /**
-        * Key used to point to the right CSH resource
-        * In simple cases, is equal to $table
-        *
-        * @var string
-        */
-       protected $mainKey;
-
-       /**
-        * Internal, static: GPvar
-        * Table/Field id
-        *
-        * @var string
-        */
-       public $tfID;
-
-       /**
-        * Back (previous tfID)
-        *
-        * @var string
-        */
-       public $back;
-
-       /**
-        * If set, then in TOC mode the FULL manual will be printed as well!
-        *
-        * @var bool
-        */
-       public $renderALL;
-
-       /**
-        * Content accumulation
-        *
-        * @var string
-        */
-       public $content;
-
-       /**
-        * URL to help module
-        *
-        * @var string
-        */
-       protected $moduleUrl;
-
-       /**
-        * Initialize the class for various input etc.
-        *
-        * @return void
-        */
-       public function init() {
-               $this->moduleUrl = BackendUtility::getModuleUrl('help_cshmanual');
-               // Setting GPvars:
-               $this->tfID = GeneralUtility::_GP('tfID');
-               // Sanitizes the tfID using whitelisting.
-               if (!preg_match('/^[a-zA-Z0-9_\\-\\.\\*]*$/', $this->tfID)) {
-                       $this->tfID = '';
-               }
-               $this->back = GeneralUtility::_GP('back');
-               $this->renderALL = GeneralUtility::_GP('renderALL');
-               // Set internal table/field to the parts of "tfID" incoming var.
-               $identifierParts = explode('.', $this->tfID);
-               // The table is the first item
-               $this->table = array_shift($identifierParts);
-               $this->mainKey = $this->table;
-               // The field is the second one
-               $this->field = array_shift($identifierParts);
-               // There may be extra parts for FlexForms
-               if (!empty($identifierParts)) {
-                       // There's at least one extra part
-                       $extraIdentifierInformation = array();
-                       $extraIdentifierInformation[] = array_shift($identifierParts);
-                       // If the ds_pointerField contains a comma, it means the choice of FlexForm DS
-                       // is determined by 2 parameters. In this case we have an extra identifier part
-                       if (strpos($GLOBALS['TCA'][$this->table]['columns'][$this->field]['config']['ds_pointerField'], ',') !== FALSE) {
-                               $extraIdentifierInformation[] = array_shift($identifierParts);
-                       }
-                       // The remaining parts make up the FlexForm field name itself
-                       // (reassembled with dots)
-                       $flexFormField = implode('.', $identifierParts);
-                       // Assemble a different main key and switch field to use FlexForm field name
-                       $this->mainKey .= '.' . $this->field;
-                       foreach ($extraIdentifierInformation as $extraKey) {
-                               $this->mainKey .= '.' . $extraKey;
-                       }
-                       $this->field = $flexFormField;
-               }
-               // limitAccess is checked if the $this->table really IS a table (and if the user is NOT a translator who should see all!)
-               $showAllToUser = BackendUtility::isModuleSetInTBE_MODULES('txllxmltranslateM1') && $GLOBALS['BE_USER']->check('modules', 'txllxmltranslateM1');
-               $this->limitAccess = isset($GLOBALS['TCA'][$this->table]) ? !$showAllToUser : FALSE;
-               $this->getLanguageService()->includeLLFile('EXT:lang/locallang_view_help.xlf');
-       }
-
-       /**
-        * Main function, rendering the display
-        *
-        * @return void
-        */
-       public function main() {
-               if ($this->field == '*') {
-                       // If ALL fields is supposed to be shown:
-                       $this->content .= $this->render_Table($this->mainKey);
-               } elseif ($this->tfID) {
-                       // ... otherwise show only single field:
-                       $this->content .= $this->render_Single($this->mainKey, $this->field);
-               } else {
-                       // Render Table Of Contents if nothing else:
-                       $this->content .= $this->render_TOC();
-               }
-
-               $this->doc = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
-               $this->doc->setModuleTemplate('EXT:cshmanual/Resources/Private/Templates/cshmanual.html');
-
-               $markers = array('CONTENT' => $this->content);
-
-               $this->content = $this->doc->moduleBody(array(), array(), $markers);
-               $this->content = $this->doc->render($this->getLanguageService()->getLL('title'), $this->content);
-       }
-
-       /**
-        * Outputting the accumulated content to screen
-        *
-        * @return void
-        */
-       public function printContent() {
-               echo $this->content;
-       }
-
-       /************************************
-        * Rendering main modes
-        ************************************/
-
-       /**
-        * Creates Table Of Contents and possibly "Full Manual" mode if selected.
-        *
-        * @return string HTML content
-        */
-       public function render_TOC() {
-               // Initialize:
-               $CSHkeys = array_flip(array_keys($GLOBALS['TCA_DESCR']));
-               $TCAkeys = array_keys($GLOBALS['TCA']);
-               $outputSections = array();
-               $tocArray = array();
-               // TYPO3 Core Features:
-               $this->getLanguageService()->loadSingleTableDescription('xMOD_csh_corebe');
-               $this->render_TOC_el('xMOD_csh_corebe', 'core', $outputSections, $tocArray, $CSHkeys);
-               // Backend Modules:
-               $loadModules = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Module\ModuleLoader::class);
-               $loadModules->load($GLOBALS['TBE_MODULES']);
-               foreach ($loadModules->modules as $mainMod => $info) {
-                       $cshKey = '_MOD_' . $mainMod;
-                       if ($CSHkeys[$cshKey]) {
-                               $this->getLanguageService()->loadSingleTableDescription($cshKey);
-                               $this->render_TOC_el($cshKey, 'modules', $outputSections, $tocArray, $CSHkeys);
-                       }
-                       if (is_array($info['sub'])) {
-                               foreach ($info['sub'] as $subMod => $subInfo) {
-                                       $cshKey = '_MOD_' . $mainMod . '_' . $subMod;
-                                       if ($CSHkeys[$cshKey]) {
-                                               $this->getLanguageService()->loadSingleTableDescription($cshKey);
-                                               $this->render_TOC_el($cshKey, 'modules', $outputSections, $tocArray, $CSHkeys);
-                                       }
-                               }
-                       }
-               }
-               // Database Tables:
-               foreach ($TCAkeys as $table) {
-                       // Load descriptions for table $table
-                       $this->getLanguageService()->loadSingleTableDescription($table);
-                       if (is_array($GLOBALS['TCA_DESCR'][$table]['columns']) && $GLOBALS['BE_USER']->check('tables_select', $table)) {
-                               $this->render_TOC_el($table, 'tables', $outputSections, $tocArray, $CSHkeys);
-                       }
-               }
-               // Extensions
-               foreach ($CSHkeys as $cshKey => $value) {
-                       if (GeneralUtility::isFirstPartOfStr($cshKey, 'xEXT_') && !isset($GLOBALS['TCA'][$cshKey])) {
-                               $this->getLanguageService()->loadSingleTableDescription($cshKey);
-                               $this->render_TOC_el($cshKey, 'extensions', $outputSections, $tocArray, $CSHkeys);
-                       }
-               }
-               // Other:
-               foreach ($CSHkeys as $cshKey => $value) {
-                       if (!GeneralUtility::isFirstPartOfStr($cshKey, '_MOD_') && !isset($GLOBALS['TCA'][$cshKey])) {
-                               $this->getLanguageService()->loadSingleTableDescription($cshKey);
-                               $this->render_TOC_el($cshKey, 'other', $outputSections, $tocArray, $CSHkeys);
-                       }
-               }
-
-               // COMPILE output:
-               $output = '';
-               $output .= '<h1>' . $this->getLanguageService()->getLL('manual_title', TRUE) . '</h1>';
-               $output .= '<p class="lead">' . $this->getLanguageService()->getLL('description', TRUE) . '</p>';
-
-               $output .= '<h2>' . $this->getLanguageService()->getLL('TOC', TRUE) . '</h2>' . $this->render_TOC_makeTocList($tocArray);
-               if (!$this->renderALL) {
-                       $output .= '
-                               <br/>
-                               <p class="c-nav"><a href="' . htmlspecialchars($this->moduleUrl) . '&amp;renderALL=1">' . $this->getLanguageService()->getLL('full_manual', TRUE) . '</a></p>';
-               }
-               if ($this->renderALL) {
-                       $output .= '
-
-                               <h2>' . $this->getLanguageService()->getLL('full_manual_chapters', TRUE) . '</h2>' . implode('
-
-
-                               <!-- NEW SECTION: -->
-                               ', $outputSections);
-               }
-               $output .= '<hr /><p class="manual-title">' . BackendUtility::TYPO3_copyRightNotice() . '</p>';
-               return $output;
-       }
-
-       /**
-        * Creates a TOC list element and renders corresponding HELP content if "renderALL" mode is set.
-        *
-        * @param string $table CSH key / Table name
-        * @param string $tocCat TOC category keyword: "core", "modules", "tables", "other
-        * @param array $outputSections Array for accumulation of rendered HELP Content (in "renderALL" mode). Passed by reference!
-        * @param array $tocArray TOC array; Here TOC index elements are created. Passed by reference!
-        * @param array $CSHkeys CSH keys array. Every item rendered will be unset in this array so finally we can see what CSH keys are not processed yet. Passed by reference!
-        * @return void
-        */
-       public function render_TOC_el($table, $tocCat, &$outputSections, &$tocArray, &$CSHkeys) {
-               // Render full manual right here!
-               if ($this->renderALL) {
-                       $outputSections[$table] = $this->render_Table($table);
-                       if ($outputSections[$table]) {
-                               $outputSections[$table] = '
-
-               <!-- New CSHkey/Table: ' . $table . ' -->
-               <p class="c-nav"><a name="ANCHOR_' . $table . '" href="#">' . $this->getLanguageService()->getLL('to_top', TRUE) . '</a></p>
-               <h2>' . $this->getTableFieldLabel($table) . '</h2>
-
-               ' . $outputSections[$table];
-                               $tocArray[$tocCat][$table] = '<a href="#ANCHOR_' . $table . '">' . $this->getTableFieldLabel($table) . '</a>';
-                       } else {
-                               unset($outputSections[$table]);
-                       }
-               } else {
-                       // Only TOC:
-                       $tocArray[$tocCat][$table] = '<p><a href="' . htmlspecialchars($this->moduleUrl) . '&amp;tfID=' . rawurlencode(($table . '.*')) . '">' . $this->getTableFieldLabel($table) . '</a></p>';
-               }
-               // Unset CSH key:
-               unset($CSHkeys[$table]);
-       }
-
-       /**
-        * Renders the TOC index as a HTML bullet list from TOC array
-        *
-        * @param array $tocArray ToC Array.
-        * @return string HTML bullet list for index.
-        */
-       public function render_TOC_makeTocList($tocArray) {
-               // The Various manual sections:
-               $keys = explode(',', 'core,modules,tables,extensions,other');
-               // Create TOC bullet list:
-               $output = '';
-               foreach ($keys as $tocKey) {
-                       if (is_array($tocArray[$tocKey])) {
-                               $output .= '
-                                       <li>' . $this->getLanguageService()->getLL(('TOC_' . $tocKey), TRUE) . '
-                                               <ul>
-                                                       <li>' . implode('</li>
-                                                       <li>', $tocArray[$tocKey]) . '</li>
-                                               </ul>
-                                       </li>';
-                       }
-               }
-               // Compile TOC:
-               $output = '
-
-                       <!-- TOC: -->
-                       <div class="c-toc">
-                               <ul>
-                               ' . $output . '
-                               </ul>
-                       </div>';
-               return $output;
-       }
-
-       /**
-        * Render CSH for a full cshKey/table
-        *
-        * @param string $key Full CSH key (may be different from table name)
-        * @param string $table CSH key / table name
-        * @return string HTML output
-        */
-       public function render_Table($key, $table = NULL) {
-               $output = '';
-               // Take default key if not explicitly specified
-               if ($table === NULL) {
-                       $table = $key;
-               }
-               // Load descriptions for table $table
-               $this->getLanguageService()->loadSingleTableDescription($key);
-               if (is_array($GLOBALS['TCA_DESCR'][$key]['columns']) && (!$this->limitAccess || $GLOBALS['BE_USER']->check('tables_select', $table))) {
-                       // Initialize variables:
-                       $parts = array();
-                       // Reserved for header of table
-                       $parts[0] = '';
-                       // Traverse table columns as listed in TCA_DESCR
-                       foreach ($GLOBALS['TCA_DESCR'][$key]['columns'] as $field => $_) {
-                               $fieldValue = isset($GLOBALS['TCA'][$key]) && (string)$field !== '' ? $GLOBALS['TCA'][$key]['columns'][$field] : array();
-                               if (is_array($fieldValue) && (!$this->limitAccess || !$fieldValue['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $field))) {
-                                       if (!$field) {
-                                               // Header
-                                               $parts[0] = $this->printItem($key, '', 1);
-                                       } else {
-                                               // Field
-                                               $parts[] = $this->printItem($key, $field, 1);
-                                       }
-                               }
-                       }
-                       if (!$parts[0]) {
-                               unset($parts[0]);
-                       }
-                       $output .= implode('<br />', $parts);
-               }
-               // TOC link:
-               if (!$this->renderALL) {
-                       $tocLink = '<p class="c-nav"><a href="' . htmlspecialchars($this->moduleUrl) . '">' . $this->getLanguageService()->getLL('goToToc', TRUE) . '</a></p>';
-                       $output = $tocLink . '
-                               <br/>' . $output . '
-                               <br />' . $tocLink;
-               }
-               return $output;
-       }
-
-       /**
-        * Renders CSH for a single field.
-        *
-        * @param string $key CSH key / table name
-        * @param string $field Sub key / field name
-        * @return string HTML output
-        */
-       public function render_Single($key, $field) {
-               $output = '';
-               // Load the description field
-               $this->getLanguageService()->loadSingleTableDescription($key);
-               // Render single item
-               $output .= $this->printItem($key, $field);
-               // Link to Full table description and TOC:
-               $getLLKey = $this->limitAccess ? 'fullDescription' : 'fullDescription_module';
-               $output .= '<br />
-                       <p class="c-nav"><a href="' . htmlspecialchars($this->moduleUrl) . '&amp;tfID=' . rawurlencode(($key . '.*')) . '">' . $this->getLanguageService()->getLL($getLLKey, TRUE) . '</a></p>
-                       <p class="c-nav"><a href="' . htmlspecialchars($this->moduleUrl) . '">' . $this->getLanguageService()->getLL('goToToc', TRUE) . '</a></p>';
-               return $output;
-       }
-
-       /************************************
-        * Rendering CSH items
-        ************************************/
-
-       /**
-        * Make seeAlso links from $value
-        *
-        * @param string $value See-also input codes
-        * @param string $anchorTable If $anchorTable is set to a tablename, then references to this table will be made as anchors, not URLs.
-        * @return string See-also links HTML
-        */
-       public function make_seeAlso($value, $anchorTable = '') {
-               // Split references by comma or linebreak
-               $items = preg_split('/[,' . LF . ']/', $value);
-               $lines = array();
-               foreach ($items as $val) {
-                       $val = trim($val);
-                       if ($val) {
-                               $iP = explode(':', $val);
-                               $iPUrl = GeneralUtility::trimExplode('|', $val);
-                               // URL reference:
-                               if (substr($iPUrl[1], 0, 4) == 'http') {
-                                       $lines[] = '<a href="' . htmlspecialchars($iPUrl[1]) . '" target="_blank"><em>' . htmlspecialchars($iPUrl[0]) . '</em></a>';
-                               } elseif (substr($iPUrl[1], 0, 5) == 'FILE:') {
-                                       $fileName = GeneralUtility::getFileAbsFileName(substr($iPUrl[1], 5), 1, 1);
-                                       if ($fileName && @is_file($fileName)) {
-                                               $fileName = '../' . \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($fileName);
-                                               $lines[] = '<a href="' . htmlspecialchars($fileName) . '" target="_blank"><em>' . htmlspecialchars($iPUrl[0]) . '</em></a>';
-                                       }
-                               } else {
-                                       // "table" reference
-                                       if (!isset($GLOBALS['TCA'][$iP[0]]) || (!$iP[1] || is_array($GLOBALS['TCA'][$iP[0]]['columns'][$iP[1]])) && (!$this->limitAccess || $GLOBALS['BE_USER']->check('tables_select', $iP[0]) && (!$iP[1] || !$GLOBALS['TCA'][$iP[0]]['columns'][$iP[1]]['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $iP[0] . ':' . $iP[1])))) {
-                                               // Checking read access:
-                                               if (isset($GLOBALS['TCA_DESCR'][$iP[0]])) {
-                                                       // Make see-also link:
-                                                       $href = $this->renderALL || $anchorTable && $iP[0] == $anchorTable ? '#' . rawurlencode(implode('.', $iP)) : $this->moduleUrl . '&tfID=' . rawurlencode(implode('.', $iP)) . '&back=' . $this->tfID;
-                                                       $label = $this->getTableFieldLabel($iP[0], $iP[1], ' / ');
-                                                       $lines[] = '<a href="' . htmlspecialchars($href) . '">' . htmlspecialchars($label) . '</a>';
-                                               }
-                                       }
-                               }
-                       }
-               }
-               return implode('<br />', $lines);
-       }
-
-       /**
-        * Will return an image tag with description in italics.
-        *
-        * @param string $images Image file reference (list of)
-        * @param string $descr Description string (divided for each image by line break)
-        * @return string Image HTML codes
-        */
-       public function printImage($images, $descr) {
-               $code = '';
-               // Splitting:
-               $imgArray = GeneralUtility::trimExplode(',', $images, TRUE);
-               if (!empty($imgArray)) {
-                       $descrArray = explode(LF, $descr, count($imgArray));
-                       foreach ($imgArray as $k => $image) {
-                               $descr = $descrArray[$k];
-                               $absImagePath = GeneralUtility::getFileAbsFileName($image, 1, 1);
-                               if ($absImagePath && @is_file($absImagePath)) {
-                                       $imgFile = \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($absImagePath);
-                                       $imgInfo = @getimagesize($absImagePath);
-                                       if (is_array($imgInfo)) {
-                                               $imgFile = '../' . $imgFile;
-                                               $code .= '<br /><img src="' . $imgFile . '" ' . $imgInfo[3] . ' class="c-inlineimg img-responsive" alt="" /><br />
-                                               ';
-                                               $code .= '<p><em>' . htmlspecialchars($descr) . '</em></p>
-                                               ';
-                                       } else {
-                                               $code .= '<div style="background-color: red; border: 1px solid black; color: white;">NOT AN IMAGE: ' . $imgFile . '</div>';
-                                       }
-                               } else {
-                                       $code .= '<div style="background-color: red; border: 1px solid black; color: white;">IMAGE FILE NOT FOUND: ' . $image . '</div>';
-                               }
-                       }
-               }
-               return $code;
-       }
-
-       /**
-        * Returns header HTML content
-        *
-        * @param string $str Header text
-        * @param int $type Header type (1, 0)
-        * @return string The HTML for the header.
-        */
-       public function headerLine($str, $type = 0) {
-               switch ($type) {
-                       case 1:
-                               $str = '<h2>' . htmlspecialchars($str) . '</h2>
-                                       ';
-                               break;
-                       case 0:
-                               $str = '<h3>' . htmlspecialchars($str) . '</h3>
-                                       ';
-                               break;
-               }
-               return $str;
-       }
-
-       /**
-        * Returns prepared content
-        *
-        * @param string $str Content to format.
-        * @return string Formatted content.
-        */
-       public function prepareContent($str) {
-               return '<p>' . nl2br(trim(strip_tags($str, $this->allowedHTML))) . '</p>
-               ';
-       }
-
-       /**
-        * Prints a single $table/$field information piece
-        * If $anchors is set, then seeAlso references to the same table will be page-anchors, not links.
-        *
-        * @param string $key CSH key / table name
-        * @param string $field Sub key / field name
-        * @param bool $anchors If anchors is to be shown.
-        * @return string HTML content
-        */
-       public function printItem($key, $field, $anchors = FALSE) {
-               $out = '';
-               if ($key && (!$field || is_array($GLOBALS['TCA_DESCR'][$key]['columns'][$field]))) {
-                       // Make seeAlso references.
-                       $seeAlsoRes = $this->make_seeAlso($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['seeAlso'], $anchors ? $key : '');
-                       // Making item:
-                       $out = '<a name="' . $key . '.' . $field . '"></a>' . $this->headerLine($this->getTableFieldLabel($key, $field), 1) . $this->prepareContent($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['description']) . ($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['details'] ? $this->headerLine(($this->getLanguageService()->getLL('details') . ':')) . $this->prepareContent($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['details']) : '') . ($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['syntax'] ? $this->headerLine(($this->getLanguageService()->getLL('syntax') . ':')) . $this->prepareContent($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['syntax']) : '') . ($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['image'] ? $this->printImage($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['image'], $GLOBALS['TCA_DESCR'][$key]['columns'][$field]['image_descr']) : '') . ($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['seeAlso'] && $seeAlsoRes ? $this->headerLine(($this->getLanguageService()->getLL('seeAlso') . ':')) . '<p>' . $seeAlsoRes . '</p>' : '') . ($this->back ? '<br /><p><a href="' . htmlspecialchars($this->moduleUrl . '&tfID=' . rawurlencode($this->back)) . '" class="typo3-goBack">' . htmlspecialchars($this->getLanguageService()->getLL('goBack')) . '</a></p>' : '') . '<br />';
-               }
-               return $out;
-       }
-
-       /**
-        * Returns labels for a given field in a given structure
-        *
-        * @param string $key CSH key / table name
-        * @param string $field Sub key / field name
-        * @return array Table and field labels in a numeric array
-        */
-       public function getTableFieldNames($key, $field) {
-               $this->getLanguageService()->loadSingleTableDescription($key);
-               // Define the label for the key
-               $keyName = $key;
-               if (is_array($GLOBALS['TCA_DESCR'][$key]['columns']['']) && isset($GLOBALS['TCA_DESCR'][$key]['columns']['']['alttitle'])) {
-                       // If there's an alternative title, use it
-                       $keyName = $GLOBALS['TCA_DESCR'][$key]['columns']['']['alttitle'];
-               } elseif (isset($GLOBALS['TCA'][$key])) {
-                       // Otherwise, if it's a table, use its title
-                       $keyName = $GLOBALS['TCA'][$key]['ctrl']['title'];
-               } else {
-                       // If no title was found, make sure to remove any "_MOD_"
-                       $keyName = preg_replace('/^_MOD_/', '', $key);
-               }
-               // Define the label for the field
-               $fieldName = $field;
-               if (is_array($GLOBALS['TCA_DESCR'][$key]['columns'][$field]) && isset($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['alttitle'])) {
-                       // If there's an alternative title, use it
-                       $fieldName = $GLOBALS['TCA_DESCR'][$key]['columns'][$field]['alttitle'];
-               } elseif (isset($GLOBALS['TCA'][$key]) && isset($GLOBALS['TCA'][$key]['columns'][$field])) {
-                       // Otherwise, if it's a table, use its title
-                       $fieldName = $GLOBALS['TCA'][$key]['columns'][$field]['label'];
-               }
-               return array($keyName, $fieldName);
-       }
-
-       /**
-        * Returns composite label for table/field
-        *
-        * @param string $key CSH key / table name
-        * @param string $field Sub key / field name
-        * @param string $mergeToken Token to merge the two strings with
-        * @return string Labels joined with merge token
-        * @see getTableFieldNames()
-        */
-       public function getTableFieldLabel($key, $field = '', $mergeToken = ': ') {
-               // Get table / field parts:
-               list($tableName, $fieldName) = $this->getTableFieldNames($key, $field);
-               // Create label:
-               $labelString = $this->getLanguageService()->sL($tableName) . ($field ? $mergeToken . rtrim(trim($this->getLanguageService()->sL($fieldName)), ':') : '');
-               return $labelString;
-       }
-
-       /**
-        * Returns LanguageService
-        *
-        * @return \TYPO3\CMS\Lang\LanguageService
-        */
-       protected function getLanguageService() {
-               return $GLOBALS['LANG'];
-       }
-
-}
diff --git a/typo3/sysext/cshmanual/Classes/Domain/Repository/TableManualRepository.php b/typo3/sysext/cshmanual/Classes/Domain/Repository/TableManualRepository.php
new file mode 100644 (file)
index 0000000..9028036
--- /dev/null
@@ -0,0 +1,405 @@
+<?php
+namespace TYPO3\CMS\Cshmanual\Domain\Repository;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
+
+/**
+ * Tabble manual repository
+ */
+class TableManualRepository {
+
+       /**
+        * @var \TYPO3\CMS\Cshmanual\Service\AccessService
+        */
+       protected $accessService;
+
+       /**
+        * Constructor
+        */
+       public function __construct() {
+               $this->accessService = GeneralUtility::makeInstance(\TYPO3\CMS\Cshmanual\Service\AccessService::class);
+       }
+
+       /**
+        * Get the manual of the given table
+        *
+        * @param string $table
+        * @return array the manual for a TCA table, see getItem() for details
+        */
+       public function getTableManual($table) {
+               $parts = array();
+
+               // Load descriptions for table $table
+               $this->getLanguageService()->loadSingleTableDescription($table);
+               if (is_array($GLOBALS['TCA_DESCR'][$table]['columns']) && ($this->accessService->checkAccess('tables_select', $table))) {
+                       // Reserved for header of table
+                       $parts[0] = '';
+                       // Traverse table columns as listed in TCA_DESCR
+                       foreach ($GLOBALS['TCA_DESCR'][$table]['columns'] as $field => $_) {
+                               if (!$this->isExcludableField($table, $field) || $this->accessService->checkAccess('non_exclude_fields', $table . ':' . $field)) {
+                                       if (!$field) {
+                                               // Header
+                                               $parts[0] = $this->getItem($table, '', TRUE);
+                                       } else {
+                                               // Field
+                                               $parts[] = $this->getItem($table, $field, TRUE);
+                                       }
+                               }
+                       }
+                       if (!$parts[0]) {
+                               unset($parts[0]);
+                       }
+               }
+               return $parts;
+       }
+
+       /**
+        * Get a single manual
+        *
+        * @param string $table table name
+        * @param string $field field name
+        * @return array
+        */
+       public function getSingleManual($table, $field) {
+               $this->getLanguageService()->loadSingleTableDescription($table);
+               return $this->getItem($table, $field);
+       }
+
+       /**
+        * Get TOC sections
+        *
+        * @param string $mode
+        * @return array
+        */
+       public function getSections($mode) {
+               // Initialize
+               $cshKeys = array_flip(array_keys($GLOBALS['TCA_DESCR']));
+               $tcaKeys = array_keys($GLOBALS['TCA']);
+               $outputSections = array();
+               $tocArray = array();
+               // TYPO3 Core Features
+               $lang = $this->getLanguageService();
+               $lang->loadSingleTableDescription('xMOD_csh_corebe');
+               $this->renderTableOfContentItem($mode, 'xMOD_csh_corebe', 'core', $outputSections, $tocArray, $cshKeys);
+               // Backend Modules
+               $loadModules = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Module\ModuleLoader::class);
+               $loadModules->load($GLOBALS['TBE_MODULES']);
+               foreach ($loadModules->modules as $mainMod => $info) {
+                       $cshKey = '_MOD_' . $mainMod;
+                       if ($cshKeys[$cshKey]) {
+                               $lang->loadSingleTableDescription($cshKey);
+                               $this->renderTableOfContentItem($mode, $cshKey, 'modules', $outputSections, $tocArray, $cshKeys);
+                       }
+                       if (is_array($info['sub'])) {
+                               foreach ($info['sub'] as $subMod => $subInfo) {
+                                       $cshKey = '_MOD_' . $mainMod . '_' . $subMod;
+                                       if ($cshKeys[$cshKey]) {
+                                               $lang->loadSingleTableDescription($cshKey);
+                                               $this->renderTableOfContentItem($mode, $cshKey, 'modules', $outputSections, $tocArray, $cshKeys);
+                                       }
+                               }
+                       }
+               }
+               // Database Tables
+               foreach ($tcaKeys as $table) {
+                       // Load descriptions for table $table
+                       $lang->loadSingleTableDescription($table);
+                       if (is_array($GLOBALS['TCA_DESCR'][$table]['columns']) && $this->accessService->checkAccess('tables_select', $table)) {
+                               $this->renderTableOfContentItem($mode, $table, 'tables', $outputSections, $tocArray, $cshKeys);
+                       }
+               }
+               foreach ($cshKeys as $cshKey => $value) {
+                       // Extensions
+                       if (GeneralUtility::isFirstPartOfStr($cshKey, 'xEXT_') && !isset($GLOBALS['TCA'][$cshKey])) {
+                               $lang->loadSingleTableDescription($cshKey);
+                               $this->renderTableOfContentItem($mode, $cshKey, 'extensions', $outputSections, $tocArray, $cshKeys);
+                       }
+                       // Other
+                       if (!GeneralUtility::isFirstPartOfStr($cshKey, '_MOD_') && !isset($GLOBALS['TCA'][$cshKey])) {
+                               $lang->loadSingleTableDescription($cshKey);
+                               $this->renderTableOfContentItem($mode, $cshKey, 'other', $outputSections, $tocArray, $cshKeys);
+                       }
+               }
+
+               if ($mode === \TYPO3\CMS\Cshmanual\Controller\HelpController::TOC_ONLY) {
+                       return $tocArray;
+               }
+
+               return array(
+                       'toc' => $tocArray,
+                       'content' => $outputSections
+               );
+       }
+
+       /**
+        * Creates a TOC list element and renders corresponding HELP content if "renderALL" mode is set.
+        *
+        * @param int $mode Mode
+        * @param string $table CSH key / Table name
+        * @param string $tocCat TOC category keyword: "core", "modules", "tables", "other
+        * @param array $outputSections Array for accumulation of rendered HELP Content (in "renderALL" mode). Passed by reference!
+        * @param array $tocArray TOC array; Here TOC index elements are created. Passed by reference!
+        * @param array $CSHkeys CSH keys array. Every item rendered will be unset in this array so finally we can see what CSH keys are not processed yet. Passed by reference!
+        * @return void
+        */
+       protected function renderTableOfContentItem($mode, $table, $tocCat, &$outputSections, &$tocArray, &$CSHkeys) {
+               $tocArray[$tocCat][$table] = $this->getTableFieldLabel($table);
+               if (!$mode) {
+                       // Render full manual right here!
+                       $outputSections[$table]['content'] = $this->getTableManual($table);
+                       if (!$outputSections[$table]) {
+                               unset($outputSections[$table]);
+                       }
+               }
+
+               // Unset CSH key
+               unset($CSHkeys[$table]);
+       }
+
+       /**
+        * Returns composite label for table/field
+        *
+        * @param string $key CSH key / table name
+        * @param string $field Sub key / field name
+        * @param string $mergeToken Token to merge the two strings with
+        * @return string Labels joined with merge token
+        * @see getTableFieldNames()
+        */
+       protected function getTableFieldLabel($key, $field = '', $mergeToken = ': ') {
+               // Get table / field parts
+               list($tableName, $fieldName) = $this->getTableFieldNames($key, $field);
+               // Create label
+               return $this->getLanguageService()->sL($tableName) . ($field ? $mergeToken . rtrim(trim($this->getLanguageService()->sL($fieldName)), ':') : '');
+       }
+
+       /**
+        * Returns labels for a given field in a given structure
+        *
+        * @param string $key CSH key / table name
+        * @param string $field Sub key / field name
+        * @return array Table and field labels in a numeric array
+        */
+       protected function getTableFieldNames($key, $field) {
+               $this->getLanguageService()->loadSingleTableDescription($key);
+               // Define the label for the key
+               $keyName = $key;
+               if (!empty($GLOBALS['TCA_DESCR'][$key]['columns']['']['alttitle'])) {
+                       // If there's an alternative title, use it
+                       $keyName = $GLOBALS['TCA_DESCR'][$key]['columns']['']['alttitle'];
+               } elseif (isset($GLOBALS['TCA'][$key])) {
+                       // Otherwise, if it's a table, use its title
+                       $keyName = $GLOBALS['TCA'][$key]['ctrl']['title'];
+               } else {
+                       // If no title was found, make sure to remove any "_MOD_"
+                       $keyName = preg_replace('/^_MOD_/', '', $key);
+               }
+               // Define the label for the field
+               $fieldName = $field;
+               if (!empty($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['alttitle'])) {
+                       // If there's an alternative title, use it
+                       $fieldName = $GLOBALS['TCA_DESCR'][$key]['columns'][$field]['alttitle'];
+               } elseif (!empty($GLOBALS['TCA'][$key]['columns'][$field])) {
+                       // Otherwise, if it's a table, use its title
+                       $fieldName = $GLOBALS['TCA'][$key]['columns'][$field]['label'];
+               }
+               return array($keyName, $fieldName);
+       }
+
+       /**
+        * Gets a single $table/$field information piece
+        * If $anchors is set, then seeAlso references to the same table will be page-anchors, not links.
+        *
+        * @param string $table CSH key / table name
+        * @param string $field Sub key / field name
+        * @param bool $anchors If anchors is to be shown.
+        * @return array with the information
+        */
+       protected function getItem($table, $field, $anchors = FALSE) {
+               if (!empty($table)) {
+                       $field = !empty($field) ? $field : '';
+                       $setup = $GLOBALS['TCA_DESCR'][$table]['columns'][$field];
+                       return array(
+                               'table' => $table,
+                               'field' => $field,
+                               'configuration' => $setup,
+                               'headerLine' => $this->getTableFieldLabel($table, $field),
+                               'content' => !empty($setup['description']) ? $setup['description'] : '',
+                               'images' => !empty($setup['image']) ? $this->getImages($setup['image'], $setup['image_descr']) : array(),
+                               'seeAlso' => !empty($setup['seeAlso']) ? $this->getSeeAlsoLinks($setup['seeAlso'], $anchors ? $table : '') : '',
+                       );
+               }
+               return array();
+       }
+
+       /**
+        * Get see-also links
+        *
+        * @param string $value See-also input codes
+        * @param string $anchorTable If $anchorTable is set to a tablename, then references to this table will be made as anchors, not URLs.
+        * @return array See-also links
+        */
+       protected function getSeeAlsoLinks($value, $anchorTable = '') {
+               // Split references by comma or linebreak
+               $items = preg_split('/[,' . LF . ']/', $value);
+               $lines = array();
+               foreach ($items as $itemValue) {
+                       $itemValue = trim($itemValue);
+                       if ($itemValue) {
+                               $reference = GeneralUtility::trimExplode(':', $itemValue);
+                               $referenceUrl = GeneralUtility::trimExplode('|', $itemValue);
+                               if (substr($referenceUrl[1], 0, 4) === 'http') {
+                                       // URL reference
+                                       $lines[] = array(
+                                               'url' => $referenceUrl[1],
+                                               'title' => $referenceUrl[0],
+                                               'target' => '_blank'
+                                       );
+                               } elseif (substr($referenceUrl[1], 0, 5) === 'FILE:') {
+                                       // File reference
+                                       $fileName = GeneralUtility::getFileAbsFileName(substr($referenceUrl[1], 5), 1, 1);
+                                       if ($fileName && @is_file($fileName)) {
+                                               $fileName = '../' . PathUtility::stripPathSitePrefix($fileName);
+                                               $lines[] = array(
+                                                       'url' => $fileName,
+                                                       'title' => $referenceUrl[0],
+                                                       'target' => '_blank'
+                                               );
+                                       }
+                               } else {
+                                       // Table reference
+                                       $table = !empty($reference[0]) ? $reference[0] : '';
+                                       $field = !empty($reference[1]) ? $reference[1] : '';
+                                       $accessAllowed = TRUE;
+                                       // Check if table exists and current user can access it
+                                       if (!empty($table)) {
+                                               $accessAllowed = !$this->getTableSetup($table) || $this->accessService->checkAccess('tables_select', $table);
+                                       }
+                                       // Check if field exists and is excludable or user can access it
+                                       if ($accessAllowed && !empty($field)) {
+                                               $accessAllowed = !$this->isExcludableField($table, $field) || $this->accessService->checkAccess('non_exclude_fields', $table . ':' . $field);
+                                       }
+                                       // Check read access
+                                       if ($accessAllowed && isset($GLOBALS['TCA_DESCR'][$table])) {
+                                               // Make see-also link
+                                               $label = $this->getTableFieldLabel($table, $field, ' / ');
+                                               if ($anchorTable && $table === $anchorTable) {
+                                                       $lines[] = array(
+                                                               'url' => '#' . rawurlencode(implode('.', $reference)),
+                                                               'title' => $label,
+                                                       );
+                                               } else {
+                                                       $lines[] = array(
+                                                               'internal' => TRUE,
+                                                               'arguments' => array(
+                                                                       'table' => $table,
+                                                                       'field' => $field
+                                                               ),
+                                                               'title' => $label
+                                                       );
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return $lines;
+       }
+
+       /**
+        * Check if given table / field is excludable
+        *
+        * @param string $table The table
+        * @param string $field The field
+        * @return bool TRUE if given field is excludable
+        */
+       protected function isExcludableField($table, $field) {
+               $fieldSetup = $this->getFieldSetup($table, $field);
+               if (!empty($fieldSetup)) {
+                       return !empty($fieldSetup['exclude']);
+               }
+               return FALSE;
+       }
+
+       /**
+        * Returns an array of images with description
+        *
+        * @param string $images Image file reference (list of)
+        * @param string $descriptions Description string (divided for each image by line break)
+        * @return array
+        */
+       protected function getImages($images, $descriptions) {
+               $imageData = array();
+               // Splitting
+               $imgArray = GeneralUtility::trimExplode(',', $images, TRUE);
+               if (!empty($imgArray)) {
+                       $descrArray = explode(LF, $descriptions, count($imgArray));
+                       foreach ($imgArray as $k => $image) {
+                               $descriptions = $descrArray[$k];
+                               $absImagePath = GeneralUtility::getFileAbsFileName($image, TRUE, TRUE);
+                               if ($absImagePath && @is_file($absImagePath)) {
+                                       $imgFile = PathUtility::stripPathSitePrefix($absImagePath);
+                                       $imgInfo = @getimagesize($absImagePath);
+                                       if (is_array($imgInfo)) {
+                                               $imageData[] = array(
+                                                       'image' => $imgFile,
+                                                       'description' => $descriptions
+                                               );
+                                       }
+                               }
+                       }
+               }
+               return $imageData;
+       }
+
+       /**
+        * Returns the setup for given table
+        *
+        * @param string $table The table
+        * @return array The table setup
+        */
+       protected function getTableSetup($table) {
+               if (!empty($table) && !empty($GLOBALS['TCA'][$table])) {
+                       return $GLOBALS['TCA'][$table];
+               }
+               return array();
+       }
+
+       /**
+        * Returns the setup for given table / field
+        *
+        * @param string $table The table
+        * @param string $field The field
+        * @param bool $allowEmptyField Allow empty field
+        * @return array The field setup
+        */
+       protected function getFieldSetup($table, $field, $allowEmptyField = FALSE) {
+               $tableSetup = $this->getTableSetup($table);
+               if (!empty($tableSetup) && (!empty($field) || $allowEmptyField) && !empty($tableSetup['columns'][$field])) {
+                       return $tableSetup['columns'][$field];
+               }
+               return array();
+       }
+
+       /**
+        * Returns LanguageService
+        *
+        * @return \TYPO3\CMS\Lang\LanguageService
+        */
+       protected function getLanguageService() {
+               return $GLOBALS['LANG'];
+       }
+}
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Classes/Service/AccessService.php b/typo3/sysext/cshmanual/Classes/Service/AccessService.php
new file mode 100644 (file)
index 0000000..a57f56a
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+namespace TYPO3\CMS\Cshmanual\Service;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Access service
+ */
+class AccessService {
+
+       /**
+        * Check if current backend user has access to given identifier
+        *
+        * @param string $type The type
+        * @param string $identifier The search string in access list
+        * @return bool TRUE if the user has access
+        */
+       public function checkAccess($type, $identifier) {
+               if (!empty($type) && !empty($identifier)) {
+                       return $this->getBackendUser()->check($type, $identifier);
+               }
+               return FALSE;
+       }
+
+       /**
+        * Returns the current BE user.
+        *
+        * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+        */
+       protected function getBackendUser() {
+               return $GLOBALS['BE_USER'];
+       }
+}
+
diff --git a/typo3/sysext/cshmanual/Classes/ViewHelpers/FormatViewHelper.php b/typo3/sysext/cshmanual/Classes/ViewHelpers/FormatViewHelper.php
new file mode 100644 (file)
index 0000000..dbabfa3
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+namespace TYPO3\CMS\Cshmanual\ViewHelpers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
+
+/**
+ * Format the given content
+ *
+ * @internal
+ */
+class FormatViewHelper extends AbstractViewHelper implements CompilableInterface {
+
+       /**
+        * Disable the escaping interceptor
+        *
+        * @var bool
+        */
+       protected $escapingInterceptorEnabled = FALSE;
+
+       /**
+        * Format the content
+        *
+        * @param string $content
+        * @return string
+        */
+       public function render($content = '') {
+               return self::renderStatic(
+                       array(
+                               'content' => $content,
+                       ),
+                       $this->buildRenderChildrenClosure(),
+                       $this->renderingContext
+               );
+       }
+
+       /**
+        * @param array $arguments
+        * @param callable $renderChildrenClosure
+        * @param RenderingContextInterface $renderingContext
+        *
+        * @return string
+        */
+       static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
+               if (empty($content)) {
+                       $content = $renderChildrenClosure();
+               }
+               return nl2br(trim(strip_tags($content, '<strong><em><b><i>')));
+       }
+
+}
diff --git a/typo3/sysext/cshmanual/Modules/CshManual/index.php b/typo3/sysext/cshmanual/Modules/CshManual/index.php
deleted file mode 100644 (file)
index 2a90f47..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-$GLOBALS['SOBE'] = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Cshmanual\Controller\HelpModuleController::class);
-$GLOBALS['SOBE']->init();
-$GLOBALS['SOBE']->main();
-$GLOBALS['SOBE']->printContent();
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Resources/Private/Layouts/Default.html b/typo3/sysext/cshmanual/Resources/Private/Layouts/Default.html
new file mode 100644 (file)
index 0000000..adef4b2
--- /dev/null
@@ -0,0 +1,31 @@
+<f:be.container>
+       <div class="typo3-fullDoc">
+               <div id="typo3-docheader">
+                       <div class="typo3-docheader-functions">
+                               <div class="left">
+                                       <f:be.buttons.csh />
+                               </div>
+                               <div class="right">
+                               </div>
+                       </div>
+                       <div class="typo3-docheader-buttons">
+                               <div class="left">
+                                       <f:render section="docheader" />
+                               </div>
+                               <div class="right">
+                                       <f:be.buttons.shortcut />
+                               </div>
+                       </div>
+               </div>
+               <div id="typo3-docbody">
+                       <div id="typo3-inner-docbody">
+                               <f:render section="content" />
+
+                               <hr />
+                               <p>
+                                       <f:format.raw>{copyright}</f:format.raw>
+                               </p>
+                       </div>
+               </div>
+       </div>
+</f:be.container>
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Resources/Private/Partials/Manual.html b/typo3/sysext/cshmanual/Resources/Private/Partials/Manual.html
new file mode 100644 (file)
index 0000000..b4791ea
--- /dev/null
@@ -0,0 +1,53 @@
+{namespace csh=TYPO3\CMS\Cshmanual\ViewHelpers}
+<a id="{manual.table}{f:if(condition:manual.field,then:'.{manual.field}')}"></a>
+
+<h2>{manual.headerLine}</h2>
+
+<p>{manual.content}</p>
+
+<f:if condition="{manual.configuration.details}">
+       <h3>
+               <f:translate key="LLL:EXT:lang/locallang_view_help.xlf:details" />
+       </h3>
+       <csh:format>{manual.configuration.details}</csh:format>
+</f:if>
+
+<f:if condition="{manual.configuration.syntax}">
+       <h3>
+               <f:translate key="LLL:EXT:lang/locallang_view_help.xlf:syntax" />
+       </h3>
+       {manual.configuration.syntax}
+</f:if>
+
+<f:if condition="{manual.images}">
+       <f:for each="{manual.images}" as="image">
+               <div>
+                       <img src="../{image.image}" />
+                       <f:if condition="{image.description}">
+                               <p>{image.description}</p>
+                       </f:if>
+               </div>
+       </f:for>
+       {manual.configuration.syntax}
+</f:if>
+
+<f:if condition="{manual.seeAlso}">
+       <h3>
+               <f:translate key="LLL:EXT:lang/locallang_view_help.xlf:seeAlso" />
+       </h3>
+       <ul>
+               <f:for each="{manual.seeAlso}" as="link">
+                       <li>
+                               <f:if condition="{link.internal}">
+                                       <f:then>
+                                               <f:link.action action="detail" arguments="{link.arguments}">{link.title}</f:link.action>
+                                       </f:then>
+                                       <f:else>
+                                               <a href="{link.url}" target="{link.target}">{link.title}</a>
+                                       </f:else>
+                               </f:if>
+
+                       </li>
+               </f:for>
+       </ul>
+</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Resources/Private/Partials/TableOfContents.html b/typo3/sysext/cshmanual/Resources/Private/Partials/TableOfContents.html
new file mode 100644 (file)
index 0000000..01da11e
--- /dev/null
@@ -0,0 +1,35 @@
+<h1>
+       <f:translate key="LLL:EXT:lang/locallang_view_help.xlf:manual_title" />
+</h1>
+<p class="lead">
+       <f:translate key="LLL:EXT:lang/locallang_view_help.xlf:description" />
+</p>
+
+<h2>
+       <f:translate key="LLL:EXT:lang/locallang_view_help.xlf:TOC" />
+</h2>
+
+<f:if condition="{toc}">
+       <ul>
+               <f:for each="{toc}" as="modules" key="type">
+                       <li>
+                               <f:translate key="LLL:EXT:lang/locallang_view_help.xlf:TOC_{type}" default="{type}" />
+
+                               <ul>
+                                       <f:for each="{modules}" as="title" key="module">
+                                               <li>
+                                                       <f:if condition="{all}">
+                                                               <f:then>
+                                                                       <a href="#{module}">{module}</a>
+                                                               </f:then>
+                                                               <f:else>
+                                                                       <f:link.action action="detail" arguments="{table:module,field:'*'}">{title}</f:link.action>
+                                                               </f:else>
+                                                       </f:if>
+                                               </li>
+                                       </f:for>
+                               </ul>
+                       </li>
+               </f:for>
+       </ul>
+</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Resources/Private/Templates/Help/All.html b/typo3/sysext/cshmanual/Resources/Private/Templates/Help/All.html
new file mode 100644 (file)
index 0000000..b06a701
--- /dev/null
@@ -0,0 +1,15 @@
+<f:layout name="Default" />
+
+<f:section name="docheader">
+       <f:be.buttons.icon uri="{f:uri.action(action:'index')}" icon="actions-view-go-up" />
+</f:section>
+
+<f:section name="content">
+       <f:render partial="TableOfContents" arguments="{toc:all.toc,all:1}" />
+
+       <f:for each="{all.content}" as="sections">
+               <f:for each="{sections.content}" as="item">
+                       <f:render partial="Manual" arguments="{manual:item}" />
+               </f:for>
+       </f:for>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Resources/Private/Templates/Help/Detail.html b/typo3/sysext/cshmanual/Resources/Private/Templates/Help/Detail.html
new file mode 100644 (file)
index 0000000..d91dece
--- /dev/null
@@ -0,0 +1,12 @@
+{namespace csh=TYPO3\CMS\Cshmanual\ViewHelpers}
+<f:layout name="Default" />
+
+<f:section name="docheader">
+       <f:be.buttons.icon uri="{f:uri.action(action:'index')}" icon="actions-view-go-up" />
+</f:section>
+
+<f:section name="content">
+       <f:for each="{manuals}" as="manual">
+               <f:render partial="Manual" arguments="{manual:manual}" />
+       </f:for>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Resources/Private/Templates/Help/Index.html b/typo3/sysext/cshmanual/Resources/Private/Templates/Help/Index.html
new file mode 100644 (file)
index 0000000..4a22e04
--- /dev/null
@@ -0,0 +1,13 @@
+<f:layout name="Default" />
+
+<f:section name="docheader">
+
+</f:section>
+<f:section name="content">
+
+       <f:render partial="TableOfContents" arguments="{toc:toc,all:0}" />
+
+       <f:link.action action="all">
+               <f:translate key="LLL:EXT:lang/locallang_view_help.xlf:full_manual" />
+       </f:link.action>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/cshmanual/Resources/Private/Templates/cshmanual.html b/typo3/sysext/cshmanual/Resources/Private/Templates/cshmanual.html
deleted file mode 100644 (file)
index 7c88a68..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- ###FULLDOC### begin -->
-<div class="typo3-fullDoc">
-       <div id="typo3-docheader">
-               <div class="typo3-docheader-functions">
-                       <div class="left"></div>
-                       <div class="right"></div>
-               </div>
-               <div class="typo3-docheader-buttons">
-                       <div class="left">###BUTTONLIST_LEFT###</div>
-                       <div class="right">###BUTTONLIST_RIGHT###</div>
-               </div>
-       </div>
-
-       <div id="typo3-docbody">
-               <div id="typo3-inner-docbody">
-                       <div class="typo3-view-help">
-                               ###CONTENT###
-                       </div>
-               </div>
-       </div>
-</div>
-<!-- ###FULLDOC### end -->
-
-<!-- Grouping the icons on top -->
-
-<!-- ###BUTTON_GROUP_WRAP### -->
-<div class="buttongroup">###BUTTONS###</div>
-<!-- ###BUTTON_GROUP_WRAP### -->
index 0256cba..ecdc52e 100644 (file)
@@ -2,21 +2,18 @@
 defined('TYPO3_MODE') or die();
 
 if (TYPO3_MODE === 'BE') {
-       \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addModule(
+       \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
+               'TYPO3.CMS.Cshmanual',
                'help',
                'cshmanual',
                'top',
-               'EXT:cshmanual/Modules/CshManual/',
                array(
-                       'script' => '_DISPATCH',
-                       'access' => 'user,group',
-                       'name' => 'help_cshmanual',
-                       'labels' => array(
-                               'tabs_images' => array(
-                                       'tab' => 'EXT:cshmanual/Resources/Public/Icons/module-cshmanual.svg',
-                               ),
-                               'll_ref' => 'LLL:EXT:lang/locallang_mod_help_cshmanual.xlf',
-                       ),
+                       'Help' => 'index,all,detail',
+               ),
+               array(
+                       'access' => 'user',
+                       'icon' => 'EXT:cshmanual/Resources/Public/Icons/module-cshmanual.svg',
+                       'labels' => 'LLL:EXT:lang/locallang_mod_help_cshmanual.xlf',
                )
        );
-}
+}
\ No newline at end of file