Commit 886626f3 authored by Markus Klein's avatar Markus Klein Committed by Benni Mack
Browse files

[!!!][FEATURE] ElementBrowser refactoring, LinkBrowser API - Part 1

This change refactors the ElementBrowser and splits it into
multiple dedicated classes for each mode.

The former modes for file, folder and record selection are now
placed in dedicated *Browser classes.
The former mode "wizard", which defines its actual functionality
via the "act" variable, is a separate controller now, which
provides the API to be exensible.

The integration of the various trees and lists is solved by
a dedicated LinkParameterProviderInterface. Any class can
provides link parameters now by implementing this interface.

Other than that:
 * Lots of unused code is removed
 * All JS is moved into requireJS modules
 * Tree code is simplified by properly using constructors

Part 2 will:
 * add Breaking and Feature documentation
 * finalize RTE re-integration
 * finally delete unused classes

Resolves: #66369
Releases: master
Change-Id: I0a28663ce4c91c2405abc9e2a13063699c6bb231
Reviewed-on: http://review.typo3.org/42951


Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 671d0b70
......@@ -1275,7 +1275,7 @@ class EditDocumentController {
if ($this->returnUrl === 'sysext/backend/Resources/Private/Templates/Close.html') {
return '';
}
$aOnClick = 'vHWin=window.open(' . GeneralUtility::quoteJSvalue(GeneralUtility::linkThisScript(array('returnUrl' => 'sysext/backend/Resources/Private/Templates/Close.html'))) . ',' . GeneralUtility::quoteJSvalue(md5($this->R_URI)) . ',\'width=670,height=500,status=0,menubar=0,scrollbars=1,resizable=1\');vHWin.focus();return false;';
$aOnClick = 'var vHWin=window.open(' . GeneralUtility::quoteJSvalue(GeneralUtility::linkThisScript(array('returnUrl' => 'sysext/backend/Resources/Private/Templates/Close.html'))) . ',' . GeneralUtility::quoteJSvalue(md5($this->R_URI)) . ',\'width=670,height=500,status=0,menubar=0,scrollbars=1,resizable=1\');vHWin.focus();return false;';
return '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.openInNewWindow', TRUE) . '">' . $this->iconFactory->getIcon('actions-window-open', Icon::SIZE_SMALL)->render() . '</a>';
}
......
......@@ -23,7 +23,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Filelist\FileListFolderTree;
use TYPO3\CMS\Backend\Template\DocumentTemplate;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Recordlist\Browser\ElementBrowser;
use TYPO3\CMS\Recordlist\Tree\View\DummyLinkParameterProvider;
/**
* Main script class for rendering of the folder tree
......@@ -113,10 +113,13 @@ class FileSystemNavigationFrameController {
$this->foldertree->thisScript = $this->scopeData['script'];
$this->foldertree->ext_noTempRecyclerDirs = $this->scopeData['ext_noTempRecyclerDirs'];
if ($this->foldertree instanceof ElementBrowserFolderTreeView) {
$browser = GeneralUtility::makeInstance(ElementBrowser::class);
$browser->mode = $this->scopeData['browser']['mode'];
$browser->act = $this->scopeData['browser']['act'];
$this->foldertree->setElementBrowser($browser);
// create a fake provider to pass link data along properly
$linkParamProvider = GeneralUtility::makeInstance(DummyLinkParameterProvider::class,
$this->scopeData['browser']['mode'],
$this->scopeData['browser']['act'],
$this->scopeData['script']
);
$this->foldertree->setLinkParameterProvider($linkParamProvider);
}
} else {
$this->foldertree = GeneralUtility::makeInstance(FileListFolderTree::class);
......
......@@ -295,7 +295,7 @@ abstract class AbstractFormElement extends AbstractNode {
'this.blur();' .
$onlyIfSelectedJS .
'vHWin=window.open(' . GeneralUtility::quoteJSvalue($url) . '+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' .
'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,200' .
'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,300' .
')' .
'+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName) . '),' .
GeneralUtility::quoteJSvalue('popUp' . $md5ID) . ',' .
......@@ -340,7 +340,7 @@ abstract class AbstractFormElement extends AbstractNode {
$aOnClick =
'this.blur();' .
'vHWin=window.open('. GeneralUtility::quoteJSvalue($url) . '+\'&P[currentValue]=\'+TBE_EDITOR.rawurlencode(' .
'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,200' .
'document.editform[' . GeneralUtility::quoteJSvalue($itemName) . '].value,300' .
')' .
'+\'&P[currentSelectedValues]=\'+TBE_EDITOR.curSelected(' . GeneralUtility::quoteJSvalue($itemName) . '),' .
GeneralUtility::quoteJSvalue('popUp' . $md5ID) . ',' .
......
......@@ -14,7 +14,11 @@ namespace TYPO3\CMS\Backend\RecordList;
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider;
use TYPO3\CMS\Backend\Routing\Router;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Database\DatabaseConnection;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
......@@ -31,6 +35,11 @@ use TYPO3\CMS\Lang\LanguageService;
*/
abstract class AbstractRecordList {
/**
* @var int
*/
protected $id = 0;
/**
* default Max items shown
*
......@@ -153,7 +162,7 @@ abstract class AbstractRecordList {
public $languageIconTitles = array();
/**
* @var \TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider
* @var TranslationConfigurationProvider
*/
public $translateTools;
......@@ -165,16 +174,22 @@ abstract class AbstractRecordList {
$this->fixedL = $GLOBALS['BE_USER']->uc['titleLen'];
}
$this->getTranslateTools();
$this->determineScriptUrl();
}
/**
* Sets the script url depending on being a module or script request
*/
protected function determineScriptUrl() {
if ($moduleName = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('M')) {
$this->thisScript = \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleUrl($moduleName);
if ($routePath = GeneralUtility::_GP('route')) {
$router = GeneralUtility::makeInstance(Router::class);
$route = $router->match($routePath);
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
$this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier'));
} elseif ($moduleName = GeneralUtility::_GP('M')) {
$this->thisScript = BackendUtility::getModuleUrl($moduleName);
} else {
$this->thisScript = \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('SCRIPT_NAME');
$this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME');
}
}
......@@ -193,12 +208,12 @@ abstract class AbstractRecordList {
* @param string $icon Is the <img>+<a> of the record. If not supplied the first 'join'-icon will be a 'line' instead
* @param array $data Is the dataarray, record with the fields. Notice: These fields are (currently) NOT htmlspecialchar'ed before being wrapped in <td>-tags
* @param string $rowParams Is insert in the <tr>-tags. Must carry a ' ' as first character
* @param int OBSOLETE - NOT USED ANYMORE. $lMargin is the leftMargin (int)
* @param string $altLine Is the HTML <img>-tag for an alternative 'gfx/ol/line.gif'-icon (used in the top)
* @param string $_ OBSOLETE - NOT USED ANYMORE. $lMargin is the leftMargin (int)
* @param string $_ OBSOLETE - NOT USED ANYMORE. Is the HTML <img>-tag for an alternative 'gfx/ol/line.gif'-icon (used in the top)
* @param string $colType Defines the tag being used for the columns. Default is td.
* @return string HTML content for the table row
*/
public function addElement($h, $icon, $data, $rowParams = '', $lMargin = '', $altLine = '', $colType = 'td') {
public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_ = '', $colType = 'td') {
$colType = ($colType === 'th') ? 'th' : 'td';
$noWrap = $this->no_noWrap ? '' : ' nowrap="nowrap"';
// Start up:
......@@ -397,7 +412,7 @@ abstract class AbstractRecordList {
*/
public function initializeLanguages() {
// Look up page overlays:
$this->pageOverlays = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'pages_language_overlay', 'pid=' . (int)$this->id . BackendUtility::deleteClause('pages_language_overlay') . BackendUtility::versioningPlaceholderClause('pages_language_overlay'), '', '', '', 'sys_language_uid');
$this->pageOverlays = $this->getDatabaseConnection()->exec_SELECTgetRows('*', 'pages_language_overlay', 'pid=' . (int)$this->id . BackendUtility::deleteClause('pages_language_overlay') . BackendUtility::versioningPlaceholderClause('pages_language_overlay'), '', '', '', 'sys_language_uid');
$this->languageIconTitles = $this->getTranslateTools()->getSystemLanguages($this->id);
}
......@@ -426,11 +441,11 @@ abstract class AbstractRecordList {
/**
* Gets an instance of TranslationConfigurationProvider
*
* @return \TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider
* @return TranslationConfigurationProvider
*/
protected function getTranslateTools() {
if (!isset($this->translateTools)) {
$this->translateTools = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider::class);
$this->translateTools = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
}
return $this->translateTools;
}
......@@ -466,4 +481,13 @@ abstract class AbstractRecordList {
return $GLOBALS['LANG'];
}
/**
* Returns the database connection
*
* @return DatabaseConnection
*/
protected function getDatabaseConnection() {
return $GLOBALS['TYPO3_DB'];
}
}
......@@ -17,13 +17,10 @@ namespace TYPO3\CMS\Backend\RecordList;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Recordlist\Browser\ElementBrowser;
use TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList;
/**
* Displays the page/file tree for browsing database records or files.
* Used from TCEFORMS an other elements
* In other words: This is the ELEMENT BROWSER!
* Displays the page tree for browsing database records.
*/
class ElementBrowserRecordList extends DatabaseRecordList {
......@@ -41,57 +38,6 @@ class ElementBrowserRecordList extends DatabaseRecordList {
*/
protected $relatingField;
/**
* Back-reference to ElementBrowser class
*
* @var ElementBrowser
*/
protected $elementBrowser;
/**
* Initializes the script path
*/
public function __construct() {
parent::__construct();
$this->determineScriptUrl();
}
/**
* @param ElementBrowser $elementBrowser
* @return void
*/
public function setElementBrowser(ElementBrowser $elementBrowser) {
$this->elementBrowser = $elementBrowser;
}
/**
* Creates the URL for links
*
* @param mixed $altId If not blank string, this is used instead of $this->id as the id value.
* @param string $table If this is "-1" then $this->table is used, otherwise the value of the input variable.
* @param string $exclList Commalist of fields NOT to pass as parameters (currently "sortField" and "sortRev")
* @return string Query-string for URL
*/
public function listURL($altId = '', $table = '-1', $exclList = '') {
return $this->getThisScript() . 'id=' . ($altId !== '' ? $altId : $this->id)
. '&table=' . rawurlencode((int)$table === -1 ? $this->table : $table)
. ($this->thumbs ? '&imagemode=' . $this->thumbs : '')
. ($this->searchString ? '&search_field=' . rawurlencode($this->searchString) : '')
. ($this->searchLevels ? '&search_levels=' . rawurlencode($this->searchLevels) : '')
. ((!$exclList || !GeneralUtility::inList($exclList, 'sortField')) && $this->sortField ? '&sortField=' . rawurlencode($this->sortField) : '')
. ((!$exclList || !GeneralUtility::inList($exclList, 'sortRev')) && $this->sortRev ? '&sortRev=' . rawurlencode($this->sortRev) : '')
. $this->ext_addP();
}
/**
* Returns additional, local GET parameters to include in the links of the record list.
*
* @return string
*/
public function ext_addP() {
return '&act=' . $this->elementBrowser->act . '&mode=' . $this->elementBrowser->mode . '&expandPage=' . $this->elementBrowser->expandPage . '&bparams=' . rawurlencode($this->elementBrowser->bparams);
}
/**
* Returns the title (based on $code) of a record (from table $table) with the proper link around (that is for "pages"-records a link to the level of that record...)
*
......@@ -109,11 +55,15 @@ class ElementBrowserRecordList extends DatabaseRecordList {
}
$title = BackendUtility::getRecordTitle($table, $row, FALSE, TRUE);
$ficon = $this->iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render();
$aOnClick = 'return insertElement(' . GeneralUtility::quoteJSvalue($table) . ', ' . GeneralUtility::quoteJSvalue($row['uid']) . ', \'db\', ' . GeneralUtility::quoteJSvalue($title) . ', \'\', \'\', ' . GeneralUtility::quoteJSvalue($ficon) . ');';
$ATag = '<a href="#" onclick="' . $aOnClick . '" title="' . $this->getLanguageService()->getLL('addToList', TRUE) . '">';
$ATag_alt = substr($ATag, 0, -4) . ',\'\',1);">';
$ATag = '<a href="#" data-close="0" title="' . $this->getLanguageService()->getLL('addToList', TRUE) . '">';
$ATag_alt = '<a href="#" data-close="1" title="' . $this->getLanguageService()->getLL('addToList', TRUE) . '">';
$ATag_e = '</a>';
return $ATag . $this->iconFactory->getIcon('actions-edit-add', Icon::SIZE_SMALL)->render() . $ATag_e . $ATag_alt . $code . $ATag_e;
$out = '<span data-uid="' . htmlspecialchars($row['uid']) . '" data-table="' . htmlspecialchars($table) . '" data-title="' . htmlspecialchars($title) . '" data-icon="' . htmlspecialchars($ficon) . '">';
$out .= $ATag . $this->iconFactory->getIcon('actions-edit-add', Icon::SIZE_SMALL)->render() . $ATag_e . $ATag_alt . $code . $ATag_e;
$out .= '</span>';
return $out;
}
/**
......
......@@ -14,10 +14,15 @@ namespace TYPO3\CMS\Backend\Tree\View;
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Backend\Routing\Router;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Database\DatabaseConnection;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Lang\LanguageService;
/**
* Base class for creating a browsable array/page/folder tree in HTML
......@@ -262,14 +267,26 @@ abstract class AbstractTreeView {
*/
public $recs = array();
/**
* Constructor
*/
public function __construct() {
$this->determineScriptUrl();
}
/**
* Sets the script url depending on being a module or script request
*/
protected function determineScriptUrl() {
if ($moduleName = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('M')) {
$this->thisScript = \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleUrl($moduleName);
if ($routePath = GeneralUtility::_GP('route')) {
$router = GeneralUtility::makeInstance(Router::class);
$route = $router->match($routePath);
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
$this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier'));
} elseif ($moduleName = GeneralUtility::_GP('M')) {
$this->thisScript = BackendUtility::getModuleUrl($moduleName);
} else {
$this->thisScript = \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('SCRIPT_NAME');
$this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME');
}
}
......@@ -283,8 +300,8 @@ abstract class AbstractTreeView {
/**
* Initialize the tree class. Needs to be overwritten
*
* @param string Record WHERE clause
* @param string Record ORDER BY field
* @param string $clause Record WHERE clause
* @param string $orderByFields Record ORDER BY field
* @return void
*/
public function init($clause = '', $orderByFields = '') {
......@@ -315,7 +332,7 @@ abstract class AbstractTreeView {
* @param bool $noCheck If set, the fieldname will be set no matter what. Otherwise the field name must either be found as key in $GLOBALS['TCA'][$table]['columns'] or in the list ->defaultList
* @return void
*/
public function addField($field, $noCheck = 0) {
public function addField($field, $noCheck = FALSE) {
if ($noCheck || is_array($GLOBALS['TCA'][$this->table]['columns'][$field]) || GeneralUtility::inList($this->defaultList, $field)) {
$this->fieldArray[] = $field;
}
......@@ -369,7 +386,7 @@ abstract class AbstractTreeView {
$firstHtml .= $this->getIcon($rootRec);
} else {
// Artificial record for the tree root, id=0
$rootRec = $this->getRootRecord($uid);
$rootRec = $this->getRootRecord();
$firstHtml .= $this->getRootIcon($rootRec);
}
if (is_array($rootRec)) {
......@@ -395,7 +412,7 @@ abstract class AbstractTreeView {
/**
* Compiles the HTML code for displaying the structure found inside the ->tree array
*
* @param array $treeArr "tree-array" - if blank string, the internal ->tree array is used.
* @param array|string $treeArr "tree-array" - if blank string, the internal ->tree array is used.
* @return string The HTML code for the tree
*/
public function printTree($treeArr = '') {
......@@ -647,7 +664,7 @@ abstract class AbstractTreeView {
*/
public function getTitleStr($row, $titleLen = 30) {
$title = htmlspecialchars(GeneralUtility::fixed_lgd_cs($row['title'], $titleLen));
$title = trim($row['title']) === '' ? '<em>[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.no_title', TRUE) . ']</em>' : $title;
$title = trim($row['title']) === '' ? '<em>[' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.no_title', TRUE) . ']</em>' : $title;
return $title;
}
......@@ -693,11 +710,10 @@ abstract class AbstractTreeView {
* @param int $uid item id for which to select subitems (parent id)
* @param int $depth Max depth (recursivity limit)
* @param string $depthData HTML-code prefix for recursive calls.
* @param string $blankLineCode ? (internal)
* @param string $subCSSclass CSS class to use for <td> sub-elements
* @return int The count of items on the level
*/
public function getTree($uid, $depth = 999, $depthData = '', $blankLineCode = '', $subCSSclass = '') {
public function getTree($uid, $depth = 999, $depthData = '') {
// Buffer for id hierarchy is reset:
$this->buffer_idH = array();
// Init vars
......@@ -709,9 +725,9 @@ abstract class AbstractTreeView {
$crazyRecursionLimiter = 999;
$idH = array();
// Traverse the records:
while ($crazyRecursionLimiter > 0 && ($row = $this->getDataNext($res, ''))) {
while ($crazyRecursionLimiter > 0 && ($row = $this->getDataNext($res))) {
$pageUid = ($this->table === 'pages') ? $row['uid'] : $row['pid'];
if (!$GLOBALS['BE_USER']->isInWebMount($pageUid)) {
if (!$this->getBackendUser()->isInWebMount($pageUid)) {
// Current record is not within web mount => skip it
continue;
}
......@@ -791,17 +807,18 @@ abstract class AbstractTreeView {
$res = $this->getDataInit($uid);
return $this->getDataCount($res);
} else {
return $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $this->table, $this->parentField . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($uid, $this->table) . BackendUtility::deleteClause($this->table) . BackendUtility::versioningPlaceholderClause($this->table) . $this->clause);
$db = $this->getDatabaseConnection();
$where = $this->parentField . '=' . $db->fullQuoteStr($uid, $this->table) . BackendUtility::deleteClause($this->table) . BackendUtility::versioningPlaceholderClause($this->table) . $this->clause;
return $db->exec_SELECTcountRows('uid', $this->table, $where);
}
}
/**
* Returns root record for uid (<=0)
*
* @param int $uid uid, <= 0 (normally, this does not matter)
* @return array Array with title/uid keys with values of $this->title/0 (zero)
*/
public function getRootRecord($uid) {
public function getRootRecord() {
return array('title' => $this->title, 'uid' => 0);
}
......@@ -827,11 +844,11 @@ abstract class AbstractTreeView {
* For arrays: This will return key to the ->dataLookup array
*
* @param int $parentId parent item id
* @param string $subCSSclass Class for sub-elements.
*
* @return mixed Data handle (Tables: An sql-resource, arrays: A parentId integer. -1 is returned if there were NO subLevel.)
* @access private
*/
public function getDataInit($parentId, $subCSSclass = '') {
public function getDataInit($parentId) {
if (is_array($this->data)) {
if (!is_array($this->dataLookup[$parentId][$this->subLevelID])) {
$parentId = -1;
......@@ -840,7 +857,9 @@ abstract class AbstractTreeView {
}
return $parentId;
} else {
return $GLOBALS['TYPO3_DB']->exec_SELECTquery(implode(',', $this->fieldArray), $this->table, $this->parentField . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($parentId, $this->table) . BackendUtility::deleteClause($this->table) . BackendUtility::versioningPlaceholderClause($this->table) . $this->clause, '', $this->orderByFields);
$db = $this->getDatabaseConnection();
$where = $this->parentField . '=' . $db->fullQuoteStr($parentId, $this->table) . BackendUtility::deleteClause($this->table) . BackendUtility::versioningPlaceholderClause($this->table) . $this->clause;
return $db->exec_SELECTquery(implode(',', $this->fieldArray), $this->table, $where, '', $this->orderByFields);
}
}
......@@ -856,7 +875,7 @@ abstract class AbstractTreeView {
if (is_array($this->data)) {
return count($this->dataLookup[$res][$this->subLevelID]);
} else {
return $GLOBALS['TYPO3_DB']->sql_num_rows($res);
return $this->getDatabaseConnection()->sql_num_rows($res);
}
}
......@@ -864,12 +883,12 @@ abstract class AbstractTreeView {
* Getting the tree data: next entry
*
* @param mixed $res Data handle
* @param string $subCSSclass CSS class for sub elements (workspace related)
*
* @return array item data array OR FALSE if end of elements.
* @access private
* @see getDataInit()
*/
public function getDataNext(&$res, $subCSSclass = '') {
public function getDataNext(&$res) {
if (is_array($this->data)) {
if ($res < 0) {
$row = FALSE;
......@@ -878,7 +897,7 @@ abstract class AbstractTreeView {
}
return $row;
} else {
while ($row = @$GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
while ($row = @$this->getDatabaseConnection()->sql_fetch_assoc($res)) {
BackendUtility::workspaceOL($this->table, $row, $this->BE_USER->workspace, TRUE);
if (is_array($row)) {
break;
......@@ -897,7 +916,7 @@ abstract class AbstractTreeView {
*/
public function getDataFree(&$res) {
if (!is_array($this->data)) {
$GLOBALS['TYPO3_DB']->sql_free_result($res);
$this->getDatabaseConnection()->sql_free_result($res);
}
}
......@@ -943,4 +962,25 @@ abstract class AbstractTreeView {
$this->dataLookup = &$treeLookupArr;
}
/**
* @return LanguageService
*/
protected function getLanguageService() {
return $GLOBALS['LANG'];
}
/**
* @return BackendUserAuthentication
*/
protected function getBackendUser() {
return $GLOBALS['BE_USER'];
}
/**
* @return DatabaseConnection
*/
protected function getDatabaseConnection() {
return $GLOBALS['TYPO3_DB'];
}
}
......@@ -13,9 +13,10 @@ namespace TYPO3\CMS\Backend\Tree\View;
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Recordlist\Browser\ElementBrowser;
use TYPO3\CMS\Recordlist\Tree\View\LinkParameterProviderInterface;
/**
* Base extension class which generates the folder tree.
......@@ -35,24 +36,18 @@ class ElementBrowserFolderTreeView extends FolderTreeView {
/**
* Back-reference to ElementBrowser class
*
* @var ElementBrowser
*/
protected $elementBrowser;
/**
* Initializes the script path
* @var LinkParameterProviderInterface
*/
public function __construct() {
$this->determineScriptUrl();
parent::__construct();
}
protected $linkParameterProvider;
/**
* @param ElementBrowser $elementBrowser
* @param LinkParameterProviderInterface $linkParameterProvider
*
* @return void
*/
public function setElementBrowser(ElementBrowser $elementBrowser) {
$this->elementBrowser = $elementBrowser;
public function setLinkParameterProvider(LinkParameterProviderInterface $linkParameterProvider) {
$this->linkParameterProvider = $linkParameterProvider;
$this->thisScript = $linkParameterProvider->getScriptUrl();
}
/**
......@@ -64,8 +59,8 @@ class ElementBrowserFolderTreeView extends FolderTreeView {
*/
public function wrapTitle($title, Folder $folderObject) {
if ($this->ext_isLinkable($folderObject)) {
$aOnClick = 'return jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript() . 'act=' . $this->elementBrowser->act . '&mode=' . $this->elementBrowser->mode . '&expandFolder=' . rawurlencode($folderObject->getCombinedIdentifier())) . ');';
return '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $title . '</a>';
$parameters = GeneralUtility::implodeArrayForUrl('', $this->linkParameterProvider->getUrlParameters(['identifier' => $folderObject->getCombinedIdentifier()]));
return '<a href="#" onclick="return jumpToUrl(' . htmlspecialchars(GeneralUtility::quoteJSvalue($this->getThisScript() . ltrim($parameters, '&'))) . ');">' . $title . '</a>';
} else {
return '<span class="text-muted">' . $title . '</span>';
}
......@@ -78,11 +73,20 @@ class ElementBrowserFolderTreeView extends FolderTreeView {
* @return bool TRUE is returned if the path is found in the web-part of the server and is NOT a recycler or temp folder AND if ->ext_noTempRecyclerDirs is not set.
*/
public function ext_isLinkable(Folder $folderObject) {
if ($this->ext_noTempRecyclerDirs && (substr($folderObject->getIdentifier(), -7) === '_temp_/' || substr($folderObject->getIdentifier(), -11) === '_recycler_/')) {
return FALSE;
} else {
return TRUE;
$identifier = $folderObject->getIdentifier();
return !$this->ext_noTempRecyclerDirs || substr($identifier, -7) !== '_temp_/' && substr($identifier, -11) !== '_recycler_/';
}
/**
* @param string $cmd
* @param bool $isOpen
* @return string
*/
protected function renderPMIconAndLink($cmd, $isOpen) {
if (get_class($this) === __CLASS__) {
return $this->PMiconATagWrap('', $cmd, !$isOpen);
}
return parent::renderPMIconAndLink($cmd, $isOpen);
}
/**
......@@ -96,12 +100,11 @@ class ElementBrowserFolderTreeView extends FolderTreeView {
* @access private
*/
public function PM_ATagWrap($icon, $cmd, $bMark = '', $isOpen = FALSE) {
$name = $anchor = '';
if ($bMark) {
$anchor = '#' . $bMark;
$name = ' name="' . $bMark . '"';
}
$aOnClick = 'return jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript() . 'PM=' . $cmd) . ',' . GeneralUtility::quoteJSvalue($anchor) . ');';