protected function treeView()
	{
		$table = $this->strTable;
		$treeClass = 'tl_tree';

		if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6)
		{
			$table = $this->ptable;
			$treeClass = 'tl_tree_xtnd';

			System::loadLanguageFile($table);
			$this->loadDataContainer($table);
		}

		/** @var Session $objSession */
		$objSession = System::getContainer()->get('session');

		/** @var AttributeBagInterface $objSessionBag */
		$objSessionBag = $objSession->getBag('contao_backend');

		$session = $objSessionBag->all();

		// Toggle the nodes
		if (Input::get('ptg') == 'all')
		{
			$node = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $this->strTable.'_'.$table.'_tree' : $this->strTable.'_tree';

			// Expand tree
			if (empty($session[$node]) || !\is_array($session[$node]) || current($session[$node]) != 1)
			{
				$session[$node] = array();
				$objNodes = $this->Database->execute("SELECT DISTINCT pid FROM " . $table . " WHERE pid>0");

				while ($objNodes->next())
				{
					$session[$node][$objNodes->pid] = 1;
				}
			}

			// Collapse tree
			else
			{
				$session[$node] = array();
			}

			$objSessionBag->replace($session);
			$this->redirect(preg_replace('/(&(amp;)?|\?)ptg=[^& ]*/i', '', Environment::get('request')));
		}

		// Return if a mandatory field (id, pid, sorting) is missing
		if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && (!$this->Database->fieldExists('id', $table) || !$this->Database->fieldExists('pid', $table) || !$this->Database->fieldExists('sorting', $table)))
		{
			return '
<p class="tl_empty">Table "'.$table.'" can not be shown as tree, because the "id", "pid" or "sorting" field is missing!</p>';
		}

		// Return if there is no parent table
		if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6 && !\strlen($this->ptable))
		{
			return '
<p class="tl_empty">Table "'.$table.'" can not be shown as extended tree, because there is no parent table!</p>';
		}

		$blnClipboard = false;
		$arrClipboard = $objSession->get('CLIPBOARD');

		// Check the clipboard
		if (!empty($arrClipboard[$this->strTable]))
		{
			$blnClipboard = true;
			$arrClipboard = $arrClipboard[$this->strTable];
		}

		if (isset($GLOBALS['TL_DCA'][$table]['config']['label']))
		{
			$label = $GLOBALS['TL_DCA'][$table]['config']['label'];
		}
		elseif (($do = Input::get('do')) && isset($GLOBALS['TL_LANG']['MOD'][$do]))
		{
			$label = $GLOBALS['TL_LANG']['MOD'][$do][0];
		}
		else
		{
			$label = $GLOBALS['TL_LANG']['MOD']['page'][0];
		}

		$icon = $GLOBALS['TL_DCA'][$table]['list']['sorting']['icon'] ?: 'pagemounts.svg';
		$label = Image::getHtml($icon).' <label>'.$label.'</label>';

		// Begin buttons container
		$return = Message::generate() . '
<div id="tl_buttons">'.((Input::get('act') == 'select') ? '
<a href="'.$this->getReferer(true).'" class="header_back" title="'.StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a> ' : (isset($GLOBALS['TL_DCA'][$this->strTable]['config']['backlink']) ? '
<a href="contao/main.php?'.$GLOBALS['TL_DCA'][$this->strTable]['config']['backlink'].'" class="header_back" title="'.StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a> ' : '')) . ((Input::get('act') != 'select' && !$blnClipboard && !$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable']) ? '
<a href="'.$this->addToUrl('act=paste&amp;mode=create').'" class="header_new" title="'.StringUtil::specialchars($GLOBALS['TL_LANG'][$this->strTable]['new'][1]).'" accesskey="n" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG'][$this->strTable]['new'][0].'</a> ' : '') . ($blnClipboard ? '
<a href="'.$this->addToUrl('clipboard=1').'" class="header_clipboard" title="'.StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['clearClipboard']).'" accesskey="x">'.$GLOBALS['TL_LANG']['MSC']['clearClipboard'].'</a> ' : $this->generateGlobalButtons()) . '
</div>';

		$tree = '';
		$blnHasSorting = $this->Database->fieldExists('sorting', $table);
		$arrFound = array();

		if (!empty($this->procedure))
		{
			$fld = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? 'pid' : 'id';

			if ($fld == 'id')
			{
				$objRoot = $this->Database->prepare("SELECT id FROM " . $this->strTable . " WHERE " . implode(' AND ', $this->procedure) . ($blnHasSorting ? " ORDER BY sorting" : ""))
										  ->execute($this->values);
			}
			elseif ($blnHasSorting)
			{
				$objRoot = $this->Database->prepare("SELECT pid, (SELECT sorting FROM " . $table . " WHERE " . $this->strTable . ".pid=" . $table . ".id) AS psort FROM " . $this->strTable . " WHERE " . implode(' AND ', $this->procedure) . " GROUP BY pid" . ($blnHasSorting ? " ORDER BY psort" : ""))
										  ->execute($this->values);
			}
			else
			{
				$objRoot = $this->Database->prepare("SELECT pid FROM " . $this->strTable . " WHERE " . implode(' AND ', $this->procedure) . " GROUP BY pid")
										  ->execute($this->values);
			}

			if ($objRoot->numRows < 1)
			{
				$this->root = array();
			}
			else
			{
				// Respect existing limitations (root IDs)
				if (!empty($this->root))
				{
					$arrRoot = array();

					while ($objRoot->next())
					{
						if (\count(array_intersect($this->root, $this->Database->getParentRecords($objRoot->$fld, $table))) > 0)
						{
							$arrRoot[] = $objRoot->$fld;
						}
					}

					$arrFound = $arrRoot;
					$this->root = $this->eliminateNestedPages($arrFound, $table, $blnHasSorting);
				}
				else
				{
					$arrFound = $objRoot->fetchEach($fld);
					$this->root = $this->eliminateNestedPages($arrFound, $table, $blnHasSorting);
				}
			}
		}

		// Call a recursive function that builds the tree
		if (\is_array($this->root))
		{
			for ($i=0, $c=\count($this->root); $i<$c; $i++)
			{
				$tree .= $this->generateTree($table, $this->root[$i], array('p'=>$this->root[($i-1)], 'n'=>$this->root[($i+1)]), $blnHasSorting, -20, ($blnClipboard ? $arrClipboard : false), ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && $blnClipboard && $this->root[$i] == $arrClipboard['id']), false, false, $arrFound);
			}
		}

		// Return if there are no records
		if ($tree == '' && Input::get('act') != 'paste')
		{
			return $return . '
<p class="tl_empty">'.$GLOBALS['TL_LANG']['MSC']['noResult'].'</p>';
		}

		$return .= ((Input::get('act') == 'select') ? '
<form action="'.ampersand(Environment::get('request'), true).'" id="tl_select" class="tl_form'.((Input::get('act') == 'select') ? ' unselectable' : '').'" method="post" novalidate>
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="tl_select">
<input type="hidden" name="REQUEST_TOKEN" value="'.REQUEST_TOKEN.'">' : '').($blnClipboard ? '
<div id="paste_hint">
  <p>'.$GLOBALS['TL_LANG']['MSC']['selectNewPosition'].'</p>
</div>' : '').'
<div class="tl_listing_container tree_view" id="tl_listing">'.($GLOBALS['TL_DCA'][$table]['list']['sorting']['breadcrumb'] ?? '').((Input::get('act') == 'select' || ($this->strPickerFieldType == 'checkbox')) ? '
<div class="tl_select_trigger">
<label for="tl_select_trigger" class="tl_select_label">'.$GLOBALS['TL_LANG']['MSC']['selectAll'].'</label> <input type="checkbox" id="tl_select_trigger" onclick="Backend.toggleCheckboxes(this)" class="tl_tree_checkbox">
</div>' : '').'
<ul class="tl_listing '.$treeClass.($this->strPickerFieldType ? ' picker unselectable' : '').'">
  <li class="tl_folder_top cf"><div class="tl_left">'.$label.'</div> <div class="tl_right">';

		$_buttons = '&nbsp;';

		// Show paste button only if there are no root records specified
		if (Input::get('act') != 'select' && $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && $blnClipboard && ((empty($GLOBALS['TL_DCA'][$table]['list']['sorting']['root']) && $GLOBALS['TL_DCA'][$table]['list']['sorting']['root'] !== false) || $GLOBALS['TL_DCA'][$table]['list']['sorting']['rootPaste']))
		{
			// Call paste_button_callback (&$dc, $row, $table, $cr, $childs, $previous, $next)
			if (\is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']))
			{
				$strClass = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback'][0];
				$strMethod = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback'][1];

				$this->import($strClass);
				$_buttons = $this->$strClass->$strMethod($this, array('id'=>0), $table, false, $arrClipboard);
			}
			elseif (\is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']))
			{
				$_buttons = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']($this, array('id'=>0), $table, false, $arrClipboard);
			}
			else
			{
				$imagePasteInto = Image::getHtml('pasteinto.svg', $GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][0]);
				$_buttons = '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid=0'.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][0]).'" onclick="Backend.getScrollOffset()">'.$imagePasteInto.'</a> ';
			}
		}

		// End table
		$return .= $_buttons . '</div></li>'.$tree.'
</ul>'.($this->strPickerFieldType == 'radio' ? '
<div class="tl_radio_reset">
<label for="tl_radio_reset" class="tl_radio_label">'.$GLOBALS['TL_LANG']['MSC']['resetSelected'].'</label> <input type="radio" name="picker" id="tl_radio_reset" value="" class="tl_tree_radio">
</div>' : '').'
</div>';

		// Close the form
		if (Input::get('act') == 'select')
		{
			// Submit buttons
			$arrButtons = array();

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
			{
				$arrButtons['edit'] = '<button type="submit" name="edit" id="edit" class="tl_submit" accesskey="s">'.$GLOBALS['TL_LANG']['MSC']['editSelected'].'</button>';
			}

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notDeletable'])
			{
				$arrButtons['delete'] = '<button type="submit" name="delete" id="delete" class="tl_submit" accesskey="d" onclick="return confirm(\''.$GLOBALS['TL_LANG']['MSC']['delAllConfirm'].'\')">'.$GLOBALS['TL_LANG']['MSC']['deleteSelected'].'</button>';
			}

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable'])
			{
				$arrButtons['copy'] = '<button type="submit" name="copy" id="copy" class="tl_submit" accesskey="c">'.$GLOBALS['TL_LANG']['MSC']['copySelected'].'</button>';
			}

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notSortable'])
			{
				$arrButtons['cut'] = '<button type="submit" name="cut" id="cut" class="tl_submit" accesskey="x">'.$GLOBALS['TL_LANG']['MSC']['moveSelected'].'</button>';
			}

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
			{
				$arrButtons['override'] = '<button type="submit" name="override" id="override" class="tl_submit" accesskey="v">'.$GLOBALS['TL_LANG']['MSC']['overrideSelected'].'</button>';
			}

			// Call the buttons_callback (see #4691)
			if (\is_array($GLOBALS['TL_DCA'][$this->strTable]['select']['buttons_callback']))
			{
				foreach ($GLOBALS['TL_DCA'][$this->strTable]['select']['buttons_callback'] as $callback)
				{
					if (\is_array($callback))
					{
						$this->import($callback[0]);
						$arrButtons = $this->{$callback[0]}->{$callback[1]}($arrButtons, $this);
					}
					elseif (\is_callable($callback))
					{
						$arrButtons = $callback($arrButtons, $this);
					}
				}
			}

			if (\count($arrButtons) < 3)
			{
				$strButtons = implode(' ', $arrButtons);
			}
			else
			{
				$strButtons = array_shift($arrButtons) . ' ';
				$strButtons .= '<div class="split-button">';
				$strButtons .= array_shift($arrButtons) . '<button type="button" id="sbtog">' . Image::getHtml('navcol.svg') . '</button> <ul class="invisible">';

				foreach ($arrButtons as $strButton)
				{
					$strButtons .= '<li>' . $strButton . '</li>';
				}

				$strButtons .= '</ul></div>';
			}

			$return .= '
</div>
<div class="tl_formbody_submit" style="text-align:right">
<div class="tl_submit_container">
  ' . $strButtons . '
</div>
</div>
</form>';
		}

		return $return;
	}
protected function treeView()
	{
		$table = $this->strTable;
		$treeClass = 'tl_tree';

		if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6)
		{
			$table = $this->ptable;
			$treeClass = 'tl_tree_xtnd';

			System::loadLanguageFile($table);
			$this->loadDataContainer($table);
		}

		
		$objSession = System::getContainer()->get('session');

		
		$objSessionBag = $objSession->getBag('contao_backend');

		$session = $objSessionBag->all();

		
		if (Input::get('ptg') == 'all')
		{
			$node = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? $this->strTable.'_'.$table.'_tree' : $this->strTable.'_tree';

			
			if (empty($session[$node]) || !\is_array($session[$node]) || current($session[$node]) != 1)
			{
				$session[$node] = array();
				$objNodes = $this->Database->execute("SELECT DISTINCT pid FROM " . $table . " WHERE pid>0");

				while ($objNodes->next())
				{
					$session[$node][$objNodes->pid] = 1;
				}
			}

			
			else
			{
				$session[$node] = array();
			}

			$objSessionBag->replace($session);
			$this->redirect(preg_replace('/(&(amp;)?|\?)ptg=[^& ]*/i', '', Environment::get('request')));
		}

		
		if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && (!$this->Database->fieldExists('id', $table) || !$this->Database->fieldExists('pid', $table) || !$this->Database->fieldExists('sorting', $table)))
		{
			return '
<p class="tl_empty">Table "'.$table.'" can not be shown as tree, because the "id", "pid" or "sorting" field is missing!</p>';
		}

		
		if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6 && !\strlen($this->ptable))
		{
			return '
<p class="tl_empty">Table "'.$table.'" can not be shown as extended tree, because there is no parent table!</p>';
		}

		$blnClipboard = false;
		$arrClipboard = $objSession->get('CLIPBOARD');

		
		if (!empty($arrClipboard[$this->strTable]))
		{
			$blnClipboard = true;
			$arrClipboard = $arrClipboard[$this->strTable];
		}

		if (isset($GLOBALS['TL_DCA'][$table]['config']['label']))
		{
			$label = $GLOBALS['TL_DCA'][$table]['config']['label'];
		}
		elseif (($do = Input::get('do')) && isset($GLOBALS['TL_LANG']['MOD'][$do]))
		{
			$label = $GLOBALS['TL_LANG']['MOD'][$do][0];
		}
		else
		{
			$label = $GLOBALS['TL_LANG']['MOD']['page'][0];
		}

		$icon = $GLOBALS['TL_DCA'][$table]['list']['sorting']['icon'] ?: 'pagemounts.svg';
		$label = Image::getHtml($icon).' <label>'.$label.'</label>';

		
		$return = Message::generate() . '
<div id="tl_buttons">'.((Input::get('act') == 'select') ? '
<a href="'.$this->getReferer(true).'" class="header_back" title="'.StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a> ' : (isset($GLOBALS['TL_DCA'][$this->strTable]['config']['backlink']) ? '
<a href="contao/main.php?'.$GLOBALS['TL_DCA'][$this->strTable]['config']['backlink'].'" class="header_back" title="'.StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a> ' : '')) . ((Input::get('act') != 'select' && !$blnClipboard && !$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable']) ? '
<a href="'.$this->addToUrl('act=paste&amp;mode=create').'" class="header_new" title="'.StringUtil::specialchars($GLOBALS['TL_LANG'][$this->strTable]['new'][1]).'" accesskey="n" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG'][$this->strTable]['new'][0].'</a> ' : '') . ($blnClipboard ? '
<a href="'.$this->addToUrl('clipboard=1').'" class="header_clipboard" title="'.StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['clearClipboard']).'" accesskey="x">'.$GLOBALS['TL_LANG']['MSC']['clearClipboard'].'</a> ' : $this->generateGlobalButtons()) . '
</div>';

		$tree = '';
		$blnHasSorting = $this->Database->fieldExists('sorting', $table);
		$arrFound = array();

		if (!empty($this->procedure))
		{
			$fld = ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6) ? 'pid' : 'id';

			if ($fld == 'id')
			{
				$objRoot = $this->Database->prepare("SELECT id FROM " . $this->strTable . " WHERE " . implode(' AND ', $this->procedure) . ($blnHasSorting ? " ORDER BY sorting" : ""))
										  ->execute($this->values);
			}
			elseif ($blnHasSorting)
			{
				$objRoot = $this->Database->prepare("SELECT pid, (SELECT sorting FROM " . $table . " WHERE " . $this->strTable . ".pid=" . $table . ".id) AS psort FROM " . $this->strTable . " WHERE " . implode(' AND ', $this->procedure) . " GROUP BY pid" . ($blnHasSorting ? " ORDER BY psort" : ""))
										  ->execute($this->values);
			}
			else
			{
				$objRoot = $this->Database->prepare("SELECT pid FROM " . $this->strTable . " WHERE " . implode(' AND ', $this->procedure) . " GROUP BY pid")
										  ->execute($this->values);
			}

			if ($objRoot->numRows < 1)
			{
				$this->root = array();
			}
			else
			{
				
				if (!empty($this->root))
				{
					$arrRoot = array();

					while ($objRoot->next())
					{
						if (\count(array_intersect($this->root, $this->Database->getParentRecords($objRoot->$fld, $table))) > 0)
						{
							$arrRoot[] = $objRoot->$fld;
						}
					}

					$arrFound = $arrRoot;
					$this->root = $this->eliminateNestedPages($arrFound, $table, $blnHasSorting);
				}
				else
				{
					$arrFound = $objRoot->fetchEach($fld);
					$this->root = $this->eliminateNestedPages($arrFound, $table, $blnHasSorting);
				}
			}
		}

		
		if (\is_array($this->root))
		{
			for ($i=0, $c=\count($this->root); $i<$c; $i++)
			{
				$tree .= $this->generateTree($table, $this->root[$i], array('p'=>$this->root[($i-1)], 'n'=>$this->root[($i+1)]), $blnHasSorting, -20, ($blnClipboard ? $arrClipboard : false), ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && $blnClipboard && $this->root[$i] == $arrClipboard['id']), false, false, $arrFound);
			}
		}

		
		if ($tree == '' && Input::get('act') != 'paste')
		{
			return $return . '
<p class="tl_empty">'.$GLOBALS['TL_LANG']['MSC']['noResult'].'</p>';
		}

		$return .= ((Input::get('act') == 'select') ? '
<form action="'.ampersand(Environment::get('request'), true).'" id="tl_select" class="tl_form'.((Input::get('act') == 'select') ? ' unselectable' : '').'" method="post" novalidate>
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="tl_select">
<input type="hidden" name="REQUEST_TOKEN" value="'.REQUEST_TOKEN.'">' : '').($blnClipboard ? '
<div id="paste_hint">
  <p>'.$GLOBALS['TL_LANG']['MSC']['selectNewPosition'].'</p>
</div>' : '').'
<div class="tl_listing_container tree_view" id="tl_listing">'.($GLOBALS['TL_DCA'][$table]['list']['sorting']['breadcrumb'] ?? '').((Input::get('act') == 'select' || ($this->strPickerFieldType == 'checkbox')) ? '
<div class="tl_select_trigger">
<label for="tl_select_trigger" class="tl_select_label">'.$GLOBALS['TL_LANG']['MSC']['selectAll'].'</label> <input type="checkbox" id="tl_select_trigger" onclick="Backend.toggleCheckboxes(this)" class="tl_tree_checkbox">
</div>' : '').'
<ul class="tl_listing '.$treeClass.($this->strPickerFieldType ? ' picker unselectable' : '').'">
  <li class="tl_folder_top cf"><div class="tl_left">'.$label.'</div> <div class="tl_right">';

		$_buttons = '&nbsp;';

		
		if (Input::get('act') != 'select' && $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 5 && $blnClipboard && ((empty($GLOBALS['TL_DCA'][$table]['list']['sorting']['root']) && $GLOBALS['TL_DCA'][$table]['list']['sorting']['root'] !== false) || $GLOBALS['TL_DCA'][$table]['list']['sorting']['rootPaste']))
		{
			
			if (\is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']))
			{
				$strClass = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback'][0];
				$strMethod = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback'][1];

				$this->import($strClass);
				$_buttons = $this->$strClass->$strMethod($this, array('id'=>0), $table, false, $arrClipboard);
			}
			elseif (\is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']))
			{
				$_buttons = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['paste_button_callback']($this, array('id'=>0), $table, false, $arrClipboard);
			}
			else
			{
				$imagePasteInto = Image::getHtml('pasteinto.svg', $GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][0]);
				$_buttons = '<a href="'.$this->addToUrl('act='.$arrClipboard['mode'].'&amp;mode=2&amp;pid=0'.(!\is_array($arrClipboard['id']) ? '&amp;id='.$arrClipboard['id'] : '')).'" title="'.StringUtil::specialchars($GLOBALS['TL_LANG'][$this->strTable]['pasteinto'][0]).'" onclick="Backend.getScrollOffset()">'.$imagePasteInto.'</a> ';
			}
		}

		
		$return .= $_buttons . '</div></li>'.$tree.'
</ul>'.($this->strPickerFieldType == 'radio' ? '
<div class="tl_radio_reset">
<label for="tl_radio_reset" class="tl_radio_label">'.$GLOBALS['TL_LANG']['MSC']['resetSelected'].'</label> <input type="radio" name="picker" id="tl_radio_reset" value="" class="tl_tree_radio">
</div>' : '').'
</div>';

		
		if (Input::get('act') == 'select')
		{
			
			$arrButtons = array();

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
			{
				$arrButtons['edit'] = '<button type="submit" name="edit" id="edit" class="tl_submit" accesskey="s">'.$GLOBALS['TL_LANG']['MSC']['editSelected'].'</button>';
			}

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notDeletable'])
			{
				$arrButtons['delete'] = '<button type="submit" name="delete" id="delete" class="tl_submit" accesskey="d" onclick="return confirm(\''.$GLOBALS['TL_LANG']['MSC']['delAllConfirm'].'\')">'.$GLOBALS['TL_LANG']['MSC']['deleteSelected'].'</button>';
			}

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable'])
			{
				$arrButtons['copy'] = '<button type="submit" name="copy" id="copy" class="tl_submit" accesskey="c">'.$GLOBALS['TL_LANG']['MSC']['copySelected'].'</button>';
			}

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notSortable'])
			{
				$arrButtons['cut'] = '<button type="submit" name="cut" id="cut" class="tl_submit" accesskey="x">'.$GLOBALS['TL_LANG']['MSC']['moveSelected'].'</button>';
			}

			if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable'])
			{
				$arrButtons['override'] = '<button type="submit" name="override" id="override" class="tl_submit" accesskey="v">'.$GLOBALS['TL_LANG']['MSC']['overrideSelected'].'</button>';
			}

			
			if (\is_array($GLOBALS['TL_DCA'][$this->strTable]['select']['buttons_callback']))
			{
				foreach ($GLOBALS['TL_DCA'][$this->strTable]['select']['buttons_callback'] as $callback)
				{
					if (\is_array($callback))
					{
						$this->import($callback[0]);
						$arrButtons = $this->{$callback[0]}->{$callback[1]}($arrButtons, $this);
					}
					elseif (\is_callable($callback))
					{
						$arrButtons = $callback($arrButtons, $this);
					}
				}
			}

			if (\count($arrButtons) < 3)
			{
				$strButtons = implode(' ', $arrButtons);
			}
			else
			{
				$strButtons = array_shift($arrButtons) . ' ';
				$strButtons .= '<div class="split-button">';
				$strButtons .= array_shift($arrButtons) . '<button type="button" id="sbtog">' . Image::getHtml('navcol.svg') . '</button> <ul class="invisible">';

				foreach ($arrButtons as $strButton)
				{
					$strButtons .= '<li>' . $strButton . '</li>';
				}

				$strButtons .= '</ul></div>';
			}

			$return .= '
</div>
<div class="tl_formbody_submit" style="text-align:right">
<div class="tl_submit_container">
  ' . $strButtons . '
</div>
</div>
</form>';
		}

		return $return;
	}
protected function treeView ( ) { $ table = $ this -> strTable ; $ treeClass = 'tl_tree' ; if ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 6 ) { $ table = $ this -> ptable ; $ treeClass = 'tl_tree_xtnd' ; System :: loadLanguageFile ( $ table ) ; $ this -> loadDataContainer ( $ table ) ; } /** @var Session $objSession */ $ objSession = System :: getContainer ( ) -> get ( 'session' ) ; /** @var AttributeBagInterface $objSessionBag */ $ objSessionBag = $ objSession -> getBag ( 'contao_backend' ) ; $ session = $ objSessionBag -> all ( ) ; // Toggle the nodes if ( Input :: get ( 'ptg' ) == 'all' ) { $ node = ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 6 ) ? $ this -> strTable . '_' . $ table . '_tree' : $ this -> strTable . '_tree' ; // Expand tree if ( empty ( $ session [ $ node ] ) || ! \ is_array ( $ session [ $ node ] ) || current ( $ session [ $ node ] ) != 1 ) { $ session [ $ node ] = array ( ) ; $ objNodes = $ this -> Database -> execute ( "SELECT DISTINCT pid FROM " . $ table . " WHERE pid>0" ) ; while ( $ objNodes -> next ( ) ) { $ session [ $ node ] [ $ objNodes -> pid ] = 1 ; } } // Collapse tree else { $ session [ $ node ] = array ( ) ; } $ objSessionBag -> replace ( $ session ) ; $ this -> redirect ( preg_replace ( '/(&(amp;)?|\?)ptg=[^& ]*/i' , '' , Environment :: get ( 'request' ) ) ) ; } // Return if a mandatory field (id, pid, sorting) is missing if ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 5 && ( ! $ this -> Database -> fieldExists ( 'id' , $ table ) || ! $ this -> Database -> fieldExists ( 'pid' , $ table ) || ! $ this -> Database -> fieldExists ( 'sorting' , $ table ) ) ) { return '
<p class="tl_empty">Table "' . $ table . '" can not be shown as tree, because the "id", "pid" or "sorting" field is missing!</p>' ; } // Return if there is no parent table if ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 6 && ! \ strlen ( $ this -> ptable ) ) { return '
<p class="tl_empty">Table "' . $ table . '" can not be shown as extended tree, because there is no parent table!</p>' ; } $ blnClipboard = false ; $ arrClipboard = $ objSession -> get ( 'CLIPBOARD' ) ; // Check the clipboard if ( ! empty ( $ arrClipboard [ $ this -> strTable ] ) ) { $ blnClipboard = true ; $ arrClipboard = $ arrClipboard [ $ this -> strTable ] ; } if ( isset ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'config' ] [ 'label' ] ) ) { $ label = $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'config' ] [ 'label' ] ; } elseif ( ( $ do = Input :: get ( 'do' ) ) && isset ( $ GLOBALS [ 'TL_LANG' ] [ 'MOD' ] [ $ do ] ) ) { $ label = $ GLOBALS [ 'TL_LANG' ] [ 'MOD' ] [ $ do ] [ 0 ] ; } else { $ label = $ GLOBALS [ 'TL_LANG' ] [ 'MOD' ] [ 'page' ] [ 0 ] ; } $ icon = $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'sorting' ] [ 'icon' ] ? : 'pagemounts.svg' ; $ label = Image :: getHtml ( $ icon ) . ' <label>' . $ label . '</label>' ; // Begin buttons container $ return = Message :: generate ( ) . '
<div id="tl_buttons">' . ( ( Input :: get ( 'act' ) == 'select' ) ? '
<a href="' . $ this -> getReferer ( true ) . '" class="header_back" title="' . StringUtil :: specialchars ( $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'backBTTitle' ] ) . '" accesskey="b" onclick="Backend.getScrollOffset()">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'backBT' ] . '</a> ' : ( isset ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'backlink' ] ) ? '
<a href="contao/main.php?' . $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'backlink' ] . '" class="header_back" title="' . StringUtil :: specialchars ( $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'backBTTitle' ] ) . '" accesskey="b" onclick="Backend.getScrollOffset()">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'backBT' ] . '</a> ' : '' ) ) . ( ( Input :: get ( 'act' ) != 'select' && ! $ blnClipboard && ! $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'closed' ] && ! $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'notCreatable' ] ) ? '
<a href="' . $ this -> addToUrl ( 'act=paste&amp;mode=create' ) . '" class="header_new" title="' . StringUtil :: specialchars ( $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'new' ] [ 1 ] ) . '" accesskey="n" onclick="Backend.getScrollOffset()">' . $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'new' ] [ 0 ] . '</a> ' : '' ) . ( $ blnClipboard ? '
<a href="' . $ this -> addToUrl ( 'clipboard=1' ) . '" class="header_clipboard" title="' . StringUtil :: specialchars ( $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'clearClipboard' ] ) . '" accesskey="x">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'clearClipboard' ] . '</a> ' : $ this -> generateGlobalButtons ( ) ) . '
</div>' ; $ tree = '' ; $ blnHasSorting = $ this -> Database -> fieldExists ( 'sorting' , $ table ) ; $ arrFound = array ( ) ; if ( ! empty ( $ this -> procedure ) ) { $ fld = ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 6 ) ? 'pid' : 'id' ; if ( $ fld == 'id' ) { $ objRoot = $ this -> Database -> prepare ( "SELECT id FROM " . $ this -> strTable . " WHERE " . implode ( ' AND ' , $ this -> procedure ) . ( $ blnHasSorting ? " ORDER BY sorting" : "" ) ) -> execute ( $ this -> values ) ; } elseif ( $ blnHasSorting ) { $ objRoot = $ this -> Database -> prepare ( "SELECT pid, (SELECT sorting FROM " . $ table . " WHERE " . $ this -> strTable . ".pid=" . $ table . ".id) AS psort FROM " . $ this -> strTable . " WHERE " . implode ( ' AND ' , $ this -> procedure ) . " GROUP BY pid" . ( $ blnHasSorting ? " ORDER BY psort" : "" ) ) -> execute ( $ this -> values ) ; } else { $ objRoot = $ this -> Database -> prepare ( "SELECT pid FROM " . $ this -> strTable . " WHERE " . implode ( ' AND ' , $ this -> procedure ) . " GROUP BY pid" ) -> execute ( $ this -> values ) ; } if ( $ objRoot -> numRows < 1 ) { $ this -> root = array ( ) ; } else { // Respect existing limitations (root IDs) if ( ! empty ( $ this -> root ) ) { $ arrRoot = array ( ) ; while ( $ objRoot -> next ( ) ) { if ( \ count ( array_intersect ( $ this -> root , $ this -> Database -> getParentRecords ( $ objRoot -> $ fld , $ table ) ) ) > 0 ) { $ arrRoot [ ] = $ objRoot -> $ fld ; } } $ arrFound = $ arrRoot ; $ this -> root = $ this -> eliminateNestedPages ( $ arrFound , $ table , $ blnHasSorting ) ; } else { $ arrFound = $ objRoot -> fetchEach ( $ fld ) ; $ this -> root = $ this -> eliminateNestedPages ( $ arrFound , $ table , $ blnHasSorting ) ; } } } // Call a recursive function that builds the tree if ( \ is_array ( $ this -> root ) ) { for ( $ i = 0 , $ c = \ count ( $ this -> root ) ; $ i < $ c ; $ i ++ ) { $ tree .= $ this -> generateTree ( $ table , $ this -> root [ $ i ] , array ( 'p' => $ this -> root [ ( $ i - 1 ) ] , 'n' => $ this -> root [ ( $ i + 1 ) ] ) , $ blnHasSorting , - 20 , ( $ blnClipboard ? $ arrClipboard : false ) , ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 5 && $ blnClipboard && $ this -> root [ $ i ] == $ arrClipboard [ 'id' ] ) , false , false , $ arrFound ) ; } } // Return if there are no records if ( $ tree == '' && Input :: get ( 'act' ) != 'paste' ) { return $ return . '
<p class="tl_empty">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'noResult' ] . '</p>' ; } $ return .= ( ( Input :: get ( 'act' ) == 'select' ) ? '
<form action="' . ampersand ( Environment :: get ( 'request' ) , true ) . '" id="tl_select" class="tl_form' . ( ( Input :: get ( 'act' ) == 'select' ) ? ' unselectable' : '' ) . '" method="post" novalidate>
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="tl_select">
<input type="hidden" name="REQUEST_TOKEN" value="' . REQUEST_TOKEN . '">' : '' ) . ( $ blnClipboard ? '
<div id="paste_hint">
  <p>' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'selectNewPosition' ] . '</p>
</div>' : '' ) . '
<div class="tl_listing_container tree_view" id="tl_listing">' . ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'sorting' ] [ 'breadcrumb' ] ?? '' ) . ( ( Input :: get ( 'act' ) == 'select' || ( $ this -> strPickerFieldType == 'checkbox' ) ) ? '
<div class="tl_select_trigger">
<label for="tl_select_trigger" class="tl_select_label">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'selectAll' ] . '</label> <input type="checkbox" id="tl_select_trigger" onclick="Backend.toggleCheckboxes(this)" class="tl_tree_checkbox">
</div>' : '' ) . '
<ul class="tl_listing ' . $ treeClass . ( $ this -> strPickerFieldType ? ' picker unselectable' : '' ) . '">
  <li class="tl_folder_top cf"><div class="tl_left">' . $ label . '</div> <div class="tl_right">' ; $ _buttons = '&nbsp;' ; // Show paste button only if there are no root records specified if ( Input :: get ( 'act' ) != 'select' && $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'mode' ] == 5 && $ blnClipboard && ( ( empty ( $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'sorting' ] [ 'root' ] ) && $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'sorting' ] [ 'root' ] !== false ) || $ GLOBALS [ 'TL_DCA' ] [ $ table ] [ 'list' ] [ 'sorting' ] [ 'rootPaste' ] ) ) { // Call paste_button_callback (&$dc, $row, $table, $cr, $childs, $previous, $next) if ( \ is_array ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] ) ) { $ strClass = $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] [ 0 ] ; $ strMethod = $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] [ 1 ] ; $ this -> import ( $ strClass ) ; $ _buttons = $ this -> $ strClass -> $ strMethod ( $ this , array ( 'id' => 0 ) , $ table , false , $ arrClipboard ) ; } elseif ( \ is_callable ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] ) ) { $ _buttons = $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'list' ] [ 'sorting' ] [ 'paste_button_callback' ] ( $ this , array ( 'id' => 0 ) , $ table , false , $ arrClipboard ) ; } else { $ imagePasteInto = Image :: getHtml ( 'pasteinto.svg' , $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'pasteinto' ] [ 0 ] ) ; $ _buttons = '<a href="' . $ this -> addToUrl ( 'act=' . $ arrClipboard [ 'mode' ] . '&amp;mode=2&amp;pid=0' . ( ! \ is_array ( $ arrClipboard [ 'id' ] ) ? '&amp;id=' . $ arrClipboard [ 'id' ] : '' ) ) . '" title="' . StringUtil :: specialchars ( $ GLOBALS [ 'TL_LANG' ] [ $ this -> strTable ] [ 'pasteinto' ] [ 0 ] ) . '" onclick="Backend.getScrollOffset()">' . $ imagePasteInto . '</a> ' ; } } // End table $ return .= $ _buttons . '</div></li>' . $ tree . '
</ul>' . ( $ this -> strPickerFieldType == 'radio' ? '
<div class="tl_radio_reset">
<label for="tl_radio_reset" class="tl_radio_label">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'resetSelected' ] . '</label> <input type="radio" name="picker" id="tl_radio_reset" value="" class="tl_tree_radio">
</div>' : '' ) . '
</div>' ; // Close the form if ( Input :: get ( 'act' ) == 'select' ) { // Submit buttons $ arrButtons = array ( ) ; if ( ! $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'notEditable' ] ) { $ arrButtons [ 'edit' ] = '<button type="submit" name="edit" id="edit" class="tl_submit" accesskey="s">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'editSelected' ] . '</button>' ; } if ( ! $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'notDeletable' ] ) { $ arrButtons [ 'delete' ] = '<button type="submit" name="delete" id="delete" class="tl_submit" accesskey="d" onclick="return confirm(\'' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'delAllConfirm' ] . '\')">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'deleteSelected' ] . '</button>' ; } if ( ! $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'notCopyable' ] ) { $ arrButtons [ 'copy' ] = '<button type="submit" name="copy" id="copy" class="tl_submit" accesskey="c">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'copySelected' ] . '</button>' ; } if ( ! $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'notSortable' ] ) { $ arrButtons [ 'cut' ] = '<button type="submit" name="cut" id="cut" class="tl_submit" accesskey="x">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'moveSelected' ] . '</button>' ; } if ( ! $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'config' ] [ 'notEditable' ] ) { $ arrButtons [ 'override' ] = '<button type="submit" name="override" id="override" class="tl_submit" accesskey="v">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'overrideSelected' ] . '</button>' ; } // Call the buttons_callback (see #4691) if ( \ is_array ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'select' ] [ 'buttons_callback' ] ) ) { foreach ( $ GLOBALS [ 'TL_DCA' ] [ $ this -> strTable ] [ 'select' ] [ 'buttons_callback' ] as $ callback ) { if ( \ is_array ( $ callback ) ) { $ this -> import ( $ callback [ 0 ] ) ; $ arrButtons = $ this -> { $ callback [ 0 ] } -> { $ callback [ 1 ] } ( $ arrButtons , $ this ) ; } elseif ( \ is_callable ( $ callback ) ) { $ arrButtons = $ callback ( $ arrButtons , $ this ) ; } } } if ( \ count ( $ arrButtons ) < 3 ) { $ strButtons = implode ( ' ' , $ arrButtons ) ; } else { $ strButtons = array_shift ( $ arrButtons ) . ' ' ; $ strButtons .= '<div class="split-button">' ; $ strButtons .= array_shift ( $ arrButtons ) . '<button type="button" id="sbtog">' . Image :: getHtml ( 'navcol.svg' ) . '</button> <ul class="invisible">' ; foreach ( $ arrButtons as $ strButton ) { $ strButtons .= '<li>' . $ strButton . '</li>' ; } $ strButtons .= '</ul></div>' ; } $ return .= '
</div>
<div class="tl_formbody_submit" style="text-align:right">
<div class="tl_submit_container">
  ' . $ strButtons . '
</div>
</div>
</form>' ; } return $ return ; }
List all records of the current table as tree and return them as HTML string

@return string
List all records of the current table as tree and return them as HTML string