first commit

This commit is contained in:
salam committed 2026-10-19 08:18:39 +02:00
commit 1218dd1517
12716 files changed
+989233

No files matched your search

@@ -0,0 +1,143 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components;
/*
* 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!
*/
/**
* Control used by various components
*/
class AbstractControl
{
/**
* HTML tag attribute for class
*
* @var string
*/
protected $classes = '';
/**
* HTML tag attribute for title
*
* @var string
*/
protected $title = '';
/**
* HTML tag attributes for data-*
* Use key => value pairs
*
* @var array
*/
protected $dataAttributes = [];
/**
* HTML tag attribute onClick
* Outdated, use sparingly
*
* @var string
*/
protected $onClick = '';
/**
* Get classes
*
* @return string
*/
public function getClasses()
{
return $this->classes;
}
/**
* Get Title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Get Data attributes
*
* @return array
*/
public function getDataAttributes()
{
return $this->dataAttributes;
}
/**
* Get Onclick Attribute
*
* @return string
*/
public function getOnClick()
{
return $this->onClick;
}
/**
* Set classes
*
* @param string $classes HTML class attribute to set
*
* @return $this
*/
public function setClasses($classes)
{
$this->classes = $classes;
return $this;
}
/**
* Set title attribute
*
* @param string $title HTML title attribute to set
*
* @return $this
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Set Data attributes
*
* @param array $dataAttributes HTML data attributes to set
*
* @return $this
*/
public function setDataAttributes(array $dataAttributes)
{
$this->dataAttributes = $dataAttributes;
return $this;
}
/**
* Set OnClick
*
* @param string $onClick HTML onClick attribute to set
*
* @return $this
*/
public function setOnClick($onClick)
{
$this->onClick = $onClick;
return $this;
}
}
@@ -0,0 +1,177 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components;
/*
* 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\Template\Components\Buttons\Action\HelpButton;
use TYPO3\CMS\Backend\Template\Components\Buttons\Action\ShortcutButton;
use TYPO3\CMS\Backend\Template\Components\Buttons\ButtonInterface;
use TYPO3\CMS\Backend\Template\Components\Buttons\FullyRenderedButton;
use TYPO3\CMS\Backend\Template\Components\Buttons\InputButton;
use TYPO3\CMS\Backend\Template\Components\Buttons\LinkButton;
use TYPO3\CMS\Backend\Template\Components\Buttons\PositionInterface;
use TYPO3\CMS\Backend\Template\Components\Buttons\SplitButton;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Bar holding the buttons
*/
class ButtonBar
{
/**
* Identifier for the left button bar
*/
const BUTTON_POSITION_LEFT = 'left';
/**
* Identifier for the right button bar
*/
const BUTTON_POSITION_RIGHT = 'right';
/**
* Internal array of all registered buttons
*
* @var array
*/
protected $buttons = [];
/**
* Add button
*
* @param ButtonInterface $button The Button Object to add
* @param string $buttonPosition Position of the button (left/right)
* @param int $buttonGroup Buttongroup of the button
*
* @throws \InvalidArgumentException In case a button is not valid
*
* @return $this
*/
public function addButton(
ButtonInterface $button,
$buttonPosition = self::BUTTON_POSITION_LEFT,
$buttonGroup = 1
) {
if (!$button->isValid()) {
throw new \InvalidArgumentException('Button "' . $button->getType() . '" is not valid', 1441706370);
}
// Determine the default button position
if ($button instanceof PositionInterface) {
$buttonPosition = $button->getPosition();
$buttonGroup = $button->getGroup();
}
// We make the button immutable here
$this->buttons[$buttonPosition][$buttonGroup][] = clone $button;
return $this;
}
/**
* Creates a new button of the given type
*
* @param string $button ButtonClass to invoke. Must implement ButtonInterface
*
* @throws \InvalidArgumentException In case a ButtonClass does not implement
* ButtonInterface
*
* @return ButtonInterface
*/
public function makeButton($button)
{
if (!in_array(ButtonInterface::class, class_implements($button), true)) {
throw new \InvalidArgumentException('A Button must implement ButtonInterface', 1441706378);
}
return GeneralUtility::makeInstance($button);
}
/**
* Creates a new InputButton
*
* @return InputButton
*/
public function makeInputButton()
{
return GeneralUtility::makeInstance(InputButton::class);
}
/**
* Creates a new SplitButton
*
* @return SplitButton
*/
public function makeSplitButton()
{
return GeneralUtility::makeInstance(SplitButton::class);
}
/**
* Creates a new LinkButton
*
* @return LinkButton
*/
public function makeLinkButton()
{
return GeneralUtility::makeInstance(LinkButton::class);
}
/**
* Creates a new FullyRenderedButton
*
* @return FullyRenderedButton
*/
public function makeFullyRenderedButton()
{
return GeneralUtility::makeInstance(FullyRenderedButton::class);
}
/**
* Creates a new ShortcutButton
*
* @return ShortcutButton
*/
public function makeShortcutButton()
{
return GeneralUtility::makeInstance(ShortcutButton::class);
}
/**
* Creates a new HelpButton
*
* @return HelpButton
*/
public function makeHelpButton()
{
return GeneralUtility::makeInstance(HelpButton::class);
}
/**
* Returns an associative array of all buttons in the form of
* ButtonPosition > ButtonGroup > Button
*
* @return array
*/
public function getButtons()
{
// here we need to call the sorting methods and stuff.
foreach ($this->buttons as $position => $_) {
ksort($this->buttons[$position]);
}
// Hook for manipulating the docHeaderButtons
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Backend\Template\Components\ButtonBar']['getButtonsHook'] ?? [] as $funcRef) {
$params = [
'buttons' => $this->buttons
];
$this->buttons = GeneralUtility::callUserFunction($funcRef, $params, $this);
}
return $this->buttons;
}
}
@@ -0,0 +1,156 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons;
/*
* 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\Template\Components\AbstractControl;
use TYPO3\CMS\Core\Imaging\Icon;
/**
* AbstractButton
*/
class AbstractButton extends AbstractControl implements ButtonInterface
{
/**
* Icon object
*
* @var Icon
*/
protected $icon;
/**
* Defines whether to show the title as a label within the button
*
* @var bool
*/
protected $showLabelText = false;
/**
* Disabled state of the button
*
* @var bool
*/
protected $disabled = false;
/**
* Show Label text
*
* @return bool
*/
public function getShowLabelText()
{
return $this->showLabelText;
}
/**
* Show Label text
*
* @param bool $showLabelText
*
* @return $this
*/
public function setShowLabelText($showLabelText)
{
$this->showLabelText = $showLabelText;
return $this;
}
/**
* Get icon
*
* @return Icon
*/
public function getIcon()
{
return $this->icon;
}
/**
* Get type
*
* @return string
*/
public function getType()
{
return static::class;
}
/**
* Set icon
*
* @param Icon $icon Icon object for the button
*
* @return $this
*/
public function setIcon(Icon $icon)
{
$this->icon = $icon;
return $this;
}
/**
* Check if button is disabled
*
* @return bool
*/
public function isDisabled(): bool
{
return $this->disabled;
}
/**
* Set if button needs to be disabled
*
* @param bool $disabled
* @return AbstractButton
*/
public function setDisabled(bool $disabled): AbstractButton
{
$this->disabled = $disabled;
return $this;
}
/**
* Implementation from ButtonInterface
* This object is an abstract, so no implementation is necessary
*
* @return bool
*/
public function isValid()
{
return false;
}
/**
* Implementation from ButtonInterface
* This object is an abstract, so no implementation is necessary
*
* @return string
*/
public function __toString()
{
return '';
}
/**
* Implementation from ButtonInterface
* This object is an abstract, so no implementation is necessary
*
* @return string
*/
public function render()
{
return '';
}
}
@@ -0,0 +1,156 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons\Action;
/*
* 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\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\Template\Components\Buttons\ButtonInterface;
use TYPO3\CMS\Backend\Template\Components\Buttons\PositionInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
/**
* HelpButton
*
* Renders a help button in the DocHeader which will be rendered
* to the right position using button group "99".
*
* EXAMPLE USAGE TO ADD A HELP BUTTON:
*
* $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
* $myButton = $buttonBar->makeHelpButton()
* ->setModuleName('xMOD_csh_corebe')
* ->setFieldName('list_module');
* $buttonBar->addButton($myButton);
*/
class HelpButton implements ButtonInterface, PositionInterface
{
/**
* @var string
*/
protected $moduleName;
/**
* @var string
*/
protected $fieldName = '';
/**
* Gets the name of the module.
*
* @return string
*/
public function getModuleName()
{
return $this->moduleName;
}
/**
* Sets the name of the module.
*
* @param string $moduleName
* @return HelpButton
*/
public function setModuleName($moduleName)
{
$this->moduleName = $moduleName;
return $this;
}
/**
* Gets the name of the field.
*
* @return string
*/
public function getFieldName()
{
return $this->fieldName;
}
/**
* Sets the name of the field.
*
* @param string $fieldName
* @return HelpButton
*/
public function setFieldName($fieldName)
{
$this->fieldName = $fieldName;
return $this;
}
/**
* Gets the button position.
*
* @return string
*/
public function getPosition()
{
return ButtonBar::BUTTON_POSITION_RIGHT;
}
/**
* Gets the button group.
*
* @return int
*/
public function getGroup()
{
return 99;
}
/**
* Gets the type of the button
*
* @return string
*/
public function getType()
{
return static::class;
}
/**
* Determines whether the button shall be rendered.
* Depends on the defined module and field name.
*
* @return bool
*/
public function isValid()
{
return !empty($this->moduleName);
}
/**
* Renders the button
*
* @return string
*/
public function __toString()
{
return $this->render();
}
/**
* Renders the button
*
* @return string
*/
public function render()
{
$helpMarkup = BackendUtility::cshItem($this->moduleName, $this->fieldName);
if ($helpMarkup === '') {
return '';
}
return '<span class="btn btn-sm btn-default">' . $helpMarkup . '</span>';
}
}
@@ -0,0 +1,265 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons\Action;
/*
* 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\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\Template\Components\Buttons\ButtonInterface;
use TYPO3\CMS\Backend\Template\Components\Buttons\PositionInterface;
use TYPO3\CMS\Backend\Template\ModuleTemplate;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext;
/**
* ShortcutButton
*
* Renders a shortcut button in the DocHeader which will be rendered
* to the right position using button group "91".
*
* EXAMPLE USAGE TO ADD A SHORTCUT BUTTON:
*
* $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
* $myButton = $buttonBar->makeShortcutButton()
* ->setModuleName('my_info');
* $buttonBar->addButton($myButton);
*/
class ShortcutButton implements ButtonInterface, PositionInterface
{
/**
* @var string
*/
protected $moduleName;
/**
* @var string
*/
protected $displayName;
/**
* @var array
*/
protected $setVariables = [];
/**
* @var array
*/
protected $getVariables = [];
/**
* @var ControllerContext
*/
protected $controllerContext;
/**
* Gets the name of the module.
*
* @return string
*/
public function getModuleName()
{
return $this->moduleName;
}
/**
* Sets the name of the module.
*
* @param string $moduleName
* @return ShortcutButton
*/
public function setModuleName($moduleName)
{
$this->moduleName = $moduleName;
return $this;
}
/**
* Gets the display name of the module.
*
* @return string
*/
public function getDisplayName()
{
return $this->displayName;
}
/**
* Sets the display name of the module.
*
* @param string $displayName
* @return ShortcutButton
*/
public function setDisplayName($displayName)
{
$this->displayName = $displayName;
return $this;
}
/**
* Gets the SET variables.
*
* @return array
*/
public function getSetVariables()
{
return $this->setVariables;
}
/**
* Sets the SET variables.
*
* @param array $setVariables
* @return ShortcutButton
*/
public function setSetVariables(array $setVariables)
{
$this->setVariables = $setVariables;
return $this;
}
/**
* Gets the GET variables.
*
* @return array
*/
public function getGetVariables()
{
return $this->getVariables;
}
/**
* Sets the GET variables.
*
* @param array $getVariables
* @return ShortcutButton
*/
public function setGetVariables(array $getVariables)
{
$this->getVariables = $getVariables;
return $this;
}
/**
* Gets the button position.
*
* @return string
*/
public function getPosition()
{
return ButtonBar::BUTTON_POSITION_RIGHT;
}
/**
* Gets the button group.
*
* @return int
*/
public function getGroup()
{
return 91;
}
/**
* Gets the type of the button
*
* @return string
*/
public function getType()
{
return static::class;
}
/**
* Determines whether the button shall be rendered.
* Depends on the backend user permission to create
* shortcuts and the defined module name.
*
* @return bool
*/
public function isValid()
{
$this->preProcess();
return
!empty($this->moduleName)
;
}
/**
* Renders the button
*
* @return string
*/
public function __toString()
{
return $this->render();
}
/**
* Renders the button
*
* @return string
*/
public function render()
{
if ($this->getBackendUser()->mayMakeShortcut()) {
/** @var ModuleTemplate $moduleTemplate */
$moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
$shortcutMarkup = $moduleTemplate->makeShortcutIcon(
implode(',', $this->getVariables),
implode(',', $this->setVariables),
$this->moduleName,
'',
$this->displayName
);
} else {
$shortcutMarkup = '';
}
return $shortcutMarkup;
}
/**
* Pre-processes class member values.
*/
protected function preProcess()
{
$emptyGetVariables = (count($this->getVariables) === 0);
// Set default GET parameters
if ($emptyGetVariables) {
$this->getVariables = ['id', 'route'];
}
// Automatically determine module name in Extbase context
if ($this->controllerContext !== null) {
$currentRequest = $this->controllerContext->getRequest();
$extensionName = $currentRequest->getControllerExtensionName();
$this->moduleName = $currentRequest->getPluginName();
// Extend default GET parameters
if ($emptyGetVariables) {
$modulePrefix = strtolower('tx_' . $extensionName . '_' . $this->moduleName);
$this->getVariables[] = $modulePrefix;
}
}
}
/**
* @return BackendUserAuthentication
*/
protected function getBackendUser()
{
return $GLOBALS['BE_USER'];
}
}
@@ -0,0 +1,49 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons;
/*
* 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!
*/
/**
* Interface for buttons
*/
interface ButtonInterface
{
/**
* Validates all set parameters of a button.
*
* @return bool
*/
public function isValid();
/**
* Returns the fully qualified class name of the button as a string
*
* @return string
*/
public function getType();
/**
* RenderMethod of a button if accessed as string from fluid
*
* @return string
*/
public function __toString();
/**
* Renders the markup for the button
*
* @return string
*/
public function render();
}
@@ -0,0 +1,111 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons;
/*
* 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!
*/
/**
* FullyRenderedButton
*
* This button type is an intermediate solution for buttons that are rendered
* by methods from TYPO3 itself, like the CSH buttons or Bookmark buttons.
*
* There should be no need to use them, so do yourself a favour and don't.
*
* EXAMPLE USAGE TO ADD A BUTTON TO THE FIRST BUTTON GROUP IN THE LEFT BAR:
*
* $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
* $myButton = $buttonBar->makeFullyRenderedButton()
* ->setHtmlSource('<span class="i-should-not-be-using-this>Foo</span>');
* $buttonBar->addButton($myButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
*/
class FullyRenderedButton implements ButtonInterface
{
/**
* The full HTML source of the rendered button.
* This source will be passed through to the frontend as is,
* so keep htmlspecialchars() in mind
*
* @var string
*/
protected $htmlSource = '';
/**
* Gets the HTML Source of the button
*
* @return string
*/
public function getHtmlSource()
{
return $this->htmlSource;
}
/**
* Sets the HTML Source of the button and returns itself
*
* @param string $htmlSource HTML sourcecode of the button
*
* @return FullyRenderedButton
*/
public function setHtmlSource($htmlSource)
{
$this->htmlSource = $htmlSource;
return $this;
}
/**
* Gets the type of the button
*
* @return string
*/
public function getType()
{
return static::class;
}
/**
* Validator for a FullyRenderedButton
*
* @return bool
*/
public function isValid()
{
if (
trim($this->getHtmlSource()) !== ''
&& $this->getType() === self::class
) {
return true;
}
return false;
}
/**
* Renders the button
*
* @return string
*/
public function __toString()
{
return $this->render();
}
/**
* Renders the button
*
* @return string
*/
public function render()
{
return '<span class="btn btn-sm btn-default">' . $this->getHtmlSource() . '</span>';
}
}
@@ -0,0 +1,187 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons;
/*
* 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!
*/
/**
* InputButton
*
* This button type renders a HTML tag <button> and takes the HTML attributes
* name and value as additional attributes to those defined in AbstractButton.
*
* Since we no longer want to have any <input type="submit" /> in the TYPO3 core
* you should use this button type to send forms
*
* EXAMPLE USAGE TO ADD A BUTTON TO THE FIRST BUTTON GROUP IN THE LEFT BAR:
*
* $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
* $saveButton = $buttonBar->makeInputButton()
* ->setName('save')
* ->setValue('1')
* ->setIcon($this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL))
* ->setTitle('Save');
* $buttonBar->addButton($saveButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
*/
class InputButton extends AbstractButton
{
/**
* Name Attribute of the button
*
* @var string
*/
protected $name = '';
/**
* Value attribute of the button
*
* @var string
*/
protected $value = '';
/**
* ID of the referenced <form> tag
*
* @var string
*/
protected $form = '';
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set name
*
* @param string $name Name attribute
*
* @return InputButton
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get value
*
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* Set value
*
* @param string $value Value attribute
*
* @return InputButton
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @return string
*/
public function getForm()
{
return $this->form;
}
/**
* @param string $form
*
* @return InputButton
*/
public function setForm($form)
{
$this->form = $form;
return $this;
}
/**
* Validates the current button
*
* @return bool
*/
public function isValid()
{
if (
trim($this->getName()) !== ''
&& trim($this->getValue()) !== ''
&& trim($this->getTitle()) !== ''
&& $this->getType() === self::class
&& $this->getIcon() !== null
) {
return true;
}
return false;
}
/**
* Renders the markup of the button
*
* @return string
*/
public function render()
{
$attributes = [
'name' => $this->getName(),
'class' => 'btn btn-default btn-sm ' . $this->getClasses(),
'value' => $this->getValue(),
'title' => $this->getTitle(),
'form' => trim($this->getForm())
];
if ($this->isDisabled()) {
$attributes['disabled'] = 'disabled';
}
$labelText = '';
if ($this->showLabelText) {
$labelText = ' ' . $this->title;
}
foreach ($this->dataAttributes as $attributeName => $attributeValue) {
$attributes['data-' . $attributeName] = $attributeValue;
}
$attributesString = '';
foreach ($attributes as $key => $value) {
if ($value !== '') {
$attributesString .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"';
}
}
return '<button' . $attributesString . '>'
. $this->getIcon()->render() . htmlspecialchars($labelText)
. '</button>';
}
/**
* Magic method so Fluid can access a button via {button}
*
* @return string
*/
public function __toString()
{
return $this->render();
}
}
@@ -0,0 +1,126 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons;
/*
* 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!
*/
/**
* LinkButton
*
* This button type renders a regular anchor tag with TYPO3s way to render a
* button control.
*
* EXAMPLE USAGE TO ADD A BUTTON TO THE FIRST BUTTON GROUP IN THE LEFT BAR:
*
* $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
* $saveButton = $buttonBar->makeLinkButton()
* ->setHref('#')
* ->setDataAttributes([
* 'foo' => 'bar'
* ])
* ->setIcon($this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL))
* ->setTitle('Save');
* $buttonBar->addButton($saveButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
*/
class LinkButton extends AbstractButton
{
/**
* HREF attribute of the link
*
* @var string
*/
protected $href = '';
/**
* Get href
*
* @return string
*/
public function getHref()
{
return $this->href;
}
/**
* Set href
*
* @param string $href HREF attribute
*
* @return LinkButton
*/
public function setHref($href)
{
$this->href = $href;
return $this;
}
/**
* Validates the current button
*
* @return bool
*/
public function isValid()
{
if (
trim($this->getHref()) !== ''
&& trim($this->getTitle()) !== ''
&& $this->getType() === self::class
&& $this->getIcon() !== null
) {
return true;
}
return false;
}
/**
* Renders the markup for the button
*
* @return string
*/
public function render()
{
$attributes = [
'href' => $this->getHref(),
'class' => 'btn btn-default btn-sm ' . $this->getClasses(),
'title' => $this->getTitle()
];
$labelText = '';
if ($this->showLabelText) {
$labelText = ' ' . $this->title;
}
foreach ($this->dataAttributes as $attributeName => $attributeValue) {
$attributes['data-' . $attributeName] = $attributeValue;
}
if ($this->onClick !== '') {
$attributes['onclick'] = $this->onClick;
}
$attributesString = '';
foreach ($attributes as $key => $value) {
$attributesString .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"';
}
return '<a ' . $attributesString . '>'
. $this->getIcon()->render() . htmlspecialchars($labelText)
. '</a>';
}
/**
* Magic method so Fluid can access a button via {button}
*
* @return string
*/
public function __toString()
{
return $this->render();
}
}
@@ -0,0 +1,35 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons;
/*
* 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!
*/
/**
* Interface for buttons
*/
interface PositionInterface
{
/**
* Gets the button position.
*
* @return string
*/
public function getPosition();
/**
* Gets the button group.
*
* @return int
*/
public function getGroup();
}
@@ -0,0 +1,217 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Buttons;
/*
* 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!
*/
/**
* SplitButton
*
* This button type renders a bootstrap split button.
* It takes multiple button objects as parameters
*
* EXAMPLE USAGE TO ADD A SPLIT BUTTON TO THE FIRST BUTTON GROUP IN THE LEFT BAR:
*
* $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
*
* $saveButton = $buttonBar->makeInputButton()
* ->setName('save')
* ->setValue('1')
* ->setIcon($this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL))
* ->setTitle('Save');
*
* $saveAndCloseButton = $buttonBar->makeInputButton()
* ->setName('save_and_close')
* ->setValue('1')
* ->setTitle('Save and close')
* ->setIcon($this->iconFactory->getIcon('actions-document-save-close', Icon::SIZE_SMALL));
*
* $saveAndShowPageButton = $buttonBar->makeInputButton()
* ->setName('save_and_show')
* ->setValue('1')
* ->setTitle('Save and show')
* ->setIcon($this->iconFactory->getIcon('actions-document-save-view', Icon::SIZE_SMALL));
*
* $splitButtonElement = $buttonBar->makeSplitButton()
* ->addItem($saveButton, TRUE)
* ->addItem($saveAndCloseButton)
* ->addItem($saveAndShowPageButton);
*/
class SplitButton extends AbstractButton
{
/**
* Internal var that determines whether the split button has received any primary
* actions yet
*
* @var bool
*/
protected $containsPrimaryAction = false;
/**
* Internal array of items in the split button
*
* @var array
*/
protected $items = [];
/**
* Adds an instance of any button to the split button
*
* @param AbstractButton $item ButtonObject to add
* @param bool $primaryAction Is the button the primary action?
*
* @throws \InvalidArgumentException In case a button is not valid
*
* @return $this
*/
public function addItem(AbstractButton $item, $primaryAction = false)
{
if (!$item->isValid()) {
throw new \InvalidArgumentException(
'Only valid items may be assigned to a split Button. "' .
$item->getType() .
'" did not pass validation',
1441706330
);
}
if ($primaryAction && $this->containsPrimaryAction) {
throw new \InvalidArgumentException('A splitButton may only contain one primary action', 1441706340);
}
if ($primaryAction) {
$this->containsPrimaryAction = true;
$this->items['primary'] = clone $item;
} else {
$this->items['options'][] = clone $item;
}
return $this;
}
/**
* Returns the current button
*
* @return array
*/
public function getButton()
{
if (!isset($this->items['primary']) && isset($this->items['options'])) {
$primaryAction = array_shift($this->items['options']);
$this->items['primary'] = $primaryAction;
}
return $this->items;
}
/**
* Validates the current button
*
*
* @return bool
*/
public function isValid()
{
$subject = $this->getButton();
return isset($subject['primary'])
&& ($subject['primary'] instanceof AbstractButton)
&& isset($subject['options']);
}
/**
* Renders the HTML markup of the button
*
* @return string
*/
public function render()
{
$items = $this->getButton();
$attributes = [
'type' => 'submit',
'class' => 'btn btn-sm btn-default ' . $items['primary']->getClasses(),
];
if (method_exists($items['primary'], 'getName')) {
$attributes['name'] = $items['primary']->getName();
}
if (method_exists($items['primary'], 'getValue')) {
$attributes['value'] = $items['primary']->getValue();
}
if (!empty($items['primary']->getOnClick())) {
$attributes['onclick'] = $items['primary']->getOnClick();
}
if (method_exists($items['primary'], 'getForm') && !empty($items['primary']->getForm())) {
$attributes['form'] = $items['primary']->getForm();
}
$attributesString = '';
foreach ($attributes as $key => $value) {
$attributesString .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"';
}
$content = '
<div class="btn-group t3js-splitbutton">
<button' . $attributesString . '>
' . $items['primary']->getIcon()->render('inline') . '
' . htmlspecialchars($items['primary']->getTitle()) . '
</button>
<button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">';
/** @var AbstractButton $option */
foreach ($items['options'] as $option) {
if ($option instanceof InputButton) {
// if the option is an InputButton we have to create a custom rendering
$optionAttributes = [
'href' => '#',
'data-name' => $option->getName(),
'data-value' => $option->getValue(),
'data-form' => $option->getForm()
];
if (!empty($option->getClasses())) {
$optionAttributes['class'] = $option->getClasses();
}
if (!empty($option->getOnClick())) {
$optionAttributes['onclick'] = $option->getOnClick();
}
$optionAttributesString = '';
foreach ($optionAttributes as $key => $value) {
$optionAttributesString .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"';
}
$html = '<a' . $optionAttributesString . '>' . $option->getIcon()->render('inline') . ' '
. htmlspecialchars($option->getTitle()) . '</a>';
} else {
// for any other kind of button we simply use what comes along (e.g. LinkButton)
$html = $option->render();
}
$content .= '
<li>
' . $html . '
</li>
';
}
$content .= '
</ul>
</div>
';
return $content;
}
/**
* Magic method so Fluid can access a button via {button}
*
* @return string
*/
public function __toString()
{
return $this->render();
}
}
@@ -0,0 +1,130 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components;
/*
* 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\Core\Utility\GeneralUtility;
/**
* DocHeader component class
*/
class DocHeaderComponent
{
/**
* MenuRegistry Object
*
* @var MenuRegistry
*/
protected $menuRegistry;
/**
* Meta information
*
* @var MetaInformation
*/
protected $metaInformation;
/**
* Registry Container for Buttons
*
* @var ButtonBar
*/
protected $buttonBar;
/**
* @var bool
*/
protected $enabled = true;
/**
* Sets up buttonBar and MenuRegistry
*/
public function __construct()
{
$this->buttonBar = GeneralUtility::makeInstance(ButtonBar::class);
$this->menuRegistry = GeneralUtility::makeInstance(MenuRegistry::class);
$this->metaInformation = GeneralUtility::makeInstance(MetaInformation::class);
}
/**
* Set page information
*
* @param array $metaInformation Record array
*/
public function setMetaInformation(array $metaInformation)
{
$this->metaInformation->setRecordArray($metaInformation);
}
/**
* Get moduleMenuRegistry
*
* @return MenuRegistry
*/
public function getMenuRegistry()
{
return $this->menuRegistry;
}
/**
* Get ButtonBar
*
* @return ButtonBar
*/
public function getButtonBar()
{
return $this->buttonBar;
}
/**
* Determines whether this components is enabled.
*
* @return bool
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* Sets the enabled property to TRUE.
*/
public function enable()
{
$this->enabled = true;
}
/**
* Sets the enabled property to FALSE (disabled).
*/
public function disable()
{
$this->enabled = false;
}
/**
* Returns the abstract content of the docHeader as an array
*
* @return array
*/
public function docHeaderContent()
{
return [
'enabled' => $this->isEnabled(),
'buttons' => $this->buttonBar->getButtons(),
'menus' => $this->menuRegistry->getMenus(),
'metaInformation' => $this->metaInformation
];
}
}
@@ -0,0 +1,152 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Menu;
/*
* 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\Core\Utility\GeneralUtility;
/**
* Menu
*/
class Menu
{
/**
* Menu Identifier
*
* @var string
*/
protected $identifier = '';
/**
* Label of the Menu (useful for Selectbox menus)
*
* @var string
*/
protected $label = '';
/**
* Container for menuitems
*
* @var array
*/
protected $menuItems = [];
/**
* Get the label
*
* @return string
*/
public function getLabel()
{
return $this->label;
}
/**
* Set label
*
* @param string $label LabelText for the menu (accepts LLL syntax)
*
* @return Menu
*/
public function setLabel($label)
{
$this->label = $label;
return $this;
}
/**
* Set identifier
*
* @param string $identifier Menu Identifier
*
* @return Menu
*/
public function setIdentifier($identifier)
{
$this->identifier = $identifier;
return $this;
}
/**
* Adds a new menuItem
*
* @param MenuItem $menuItem The menuItem to add to the menu
*
* @throws \InvalidArgumentException In case a menuItem is not valid
*/
public function addMenuItem(MenuItem $menuItem)
{
if (!$menuItem->isValid($menuItem)) {
throw new \InvalidArgumentException('MenuItem "' . $menuItem->getTitle() . '" is not valid', 1442236317);
}
// @todo implement sorting of menu items
// @todo maybe even things like spacers/sections?
$this->menuItems[] = clone $menuItem;
}
/**
* Get menu items
*
* @return array
*/
public function getMenuItems()
{
return $this->menuItems;
}
/**
* Get identifier
*
* @return string
*/
public function getIdentifier()
{
return $this->identifier;
}
/**
* Get identifier for data attribute
*
* @return string
*/
public function getDataIdentifier(): string
{
$dataMenuIdentifier = GeneralUtility::camelCaseToLowerCaseUnderscored($this->identifier);
$dataMenuIdentifier = str_replace('_', '-', $dataMenuIdentifier);
return $dataMenuIdentifier;
}
/**
* MenuItem Factory Method
*
* @return MenuItem
*/
public function makeMenuItem()
{
$menuItem = GeneralUtility::makeInstance(MenuItem::class);
return $menuItem;
}
/**
* Validation function
*
* @param Menu $menu The menu to validate
*
* @return bool
*/
public function isValid(Menu $menu)
{
return trim($menu->getIdentifier()) !== '';
}
}
@@ -0,0 +1,101 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components\Menu;
/*
* 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\Template\Components\AbstractControl;
/**
* MenuItem
*/
class MenuItem extends AbstractControl
{
/**
* Sets the href of the menuItem
*
* @var string
*/
protected $href = '';
/**
* Sets the active state of the menuItem
*
* @var bool
*/
protected $active = false;
/**
* Set href
*
* @param string $href Href of the MenuItem
*
* @return MenuItem
*/
public function setHref($href)
{
$this->href = $href;
return $this;
}
/**
* Set active
*
* @param bool $active Defines whether a menuItem is active
*
* @return MenuItem
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get href
*
* @return string
*/
public function getHref()
{
return $this->href;
}
/**
* Check if is active
*
* @return bool
*/
public function isActive()
{
return $this->active;
}
/**
* Validation
*
* @param MenuItem $menuItem The menuItem to validate
*
* @return bool
*/
public function isValid(MenuItem $menuItem)
{
if (
$menuItem->getHref() !== ''
&& $menuItem->getTitle() !== ''
) {
return true;
}
return false;
}
}
@@ -0,0 +1,79 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components;
/*
* 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\Template\Components\Menu\Menu;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* MenuRegistry
*/
class MenuRegistry
{
/**
* Internal array that stores all registered menus
*
* @var array
*/
protected $menus = [];
/**
* Adds a menu to the registry
*
* @param Menu $menu Menu object to add to the menuRegistry
*
* @throws \InvalidArgumentException In case a menu is not valid
*/
public function addMenu(Menu $menu)
{
if (!$menu->isValid($menu)) {
throw new \InvalidArgumentException('Menu "' . $menu->getIdentifier() . '" is not valid', 1442236362);
}
$this->menus[$menu->getIdentifier()] = clone $menu;
}
/**
* Returns all menus in an abstract array
*
* @return array
*/
public function getMenus()
{
// @todo do we want to provide a hook here?
/**
* For Code Completion
*
* @var int $key
* @var Menu $menu
*/
foreach ($this->menus as $key => $menu) {
if (empty($menu->getMenuItems())) {
unset($this->menus[$key]);
}
}
return $this->menus;
}
/**
* MenuFactory method
*
* @return Menu
*/
public function makeMenu()
{
$menu = GeneralUtility::makeInstance(Menu::class);
return $menu;
}
}
@@ -0,0 +1,264 @@
<?php
namespace TYPO3\CMS\Backend\Template\Components;
/*
* 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\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
use TYPO3\CMS\Core\Resource\FolderInterface;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* MetaInformation
*/
class MetaInformation
{
/**
* The recordArray.
* Typically this is a page record
*
* @var array
*/
protected $recordArray = [];
/**
* Set the RecordArray
*
* @param array $recordArray RecordArray
*/
public function setRecordArray(array $recordArray)
{
$this->recordArray = $recordArray;
}
/**
* Generate the page path for docHeader
*
* @return string The page path
*/
public function getPath()
{
$pageRecord = $this->recordArray;
$title = '';
// Is this a real page
if (is_array($pageRecord) && !empty($pageRecord['uid'])) {
$title = substr($pageRecord['_thePathFull'], 0, -1);
// Remove current page title
$pos = strrpos($title, $pageRecord['title']);
if ($pos !== false) {
$title = substr($title, 0, $pos);
}
} elseif (!empty($pageRecord['combined_identifier'])) {
try {
$resourceObject = ResourceFactory::getInstance()->getObjectFromCombinedIdentifier($pageRecord['combined_identifier']);
$title = $resourceObject->getStorage()->getName() . ':';
$title .= $resourceObject->getParentFolder()->getReadablePath();
} catch (ResourceDoesNotExistException $e) {
} catch (InsufficientFolderAccessPermissionsException $e) {
}
}
// Setting the path of the page
// crop the title to title limit (or 50, if not defined)
$beUser = $this->getBackendUser();
$cropLength = empty($beUser->uc['titleLen']) ? 50 : $beUser->uc['titleLen'];
$croppedTitle = GeneralUtility::fixed_lgd_cs($title, -$cropLength);
if ($croppedTitle !== $title) {
$pagePath = '<abbr title="' . htmlspecialchars($title) . '">' . htmlspecialchars($croppedTitle) . '</abbr>';
} else {
$pagePath = htmlspecialchars($title);
}
return $pagePath;
}
/**
* Setting page icon with context menu + uid for docheader
*
* @return string Record info
*/
public function getRecordInformation()
{
$recordInformations = $this->getRecordInformations();
if (!empty($recordInformations)) {
$recordInformation = $recordInformations['icon'] .
' <strong>' . htmlspecialchars($recordInformations['title']) . ($recordInformations['uid'] !== '' ? '&nbsp;[' . $recordInformations['uid'] . ']' : '') . '</strong>' .
(!empty($recordInformations['additionalInfo']) ? ' ' . htmlspecialchars($recordInformations['additionalInfo']) : '');
} else {
$recordInformation = '';
}
return $recordInformation;
}
/**
* Setting page icon
*
* @return string Record icon
*/
public function getRecordInformationIcon()
{
$recordInformations = $this->getRecordInformations();
if (!empty($recordInformations)) {
$recordInformationIcon = $recordInformations['icon'];
} else {
$recordInformationIcon = null;
}
return $recordInformationIcon;
}
/**
* Setting page title
*
* @return string Record title, already htmlspecialchar()'ed
*/
public function getRecordInformationTitle()
{
$recordInformations = $this->getRecordInformations();
if (!empty($recordInformations)) {
$title = $recordInformations['title'];
} else {
$title = '';
}
// crop the title to title limit (or 50, if not defined)
$beUser = $this->getBackendUser();
$cropLength = empty($beUser->uc['titleLen']) ? 50 : $beUser->uc['titleLen'];
return htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, $cropLength));
}
/**
* Setting page uid
*
* @return int|null Record uid
*/
public function getRecordInformationUid()
{
$recordInformations = $this->getRecordInformations();
if (!empty($recordInformations)) {
$recordInformationUid = $recordInformations['uid'];
} else {
$recordInformationUid = null;
}
return $recordInformationUid;
}
/**
* Returns record additional information
*
* @return string Record additional information
*/
public function getRecordInformationAdditionalInfo(): string
{
$recordInformations = $this->getRecordInformations();
return $recordInformations['additionalInfo'] ?? '';
}
/**
* Setting page array
*
* @return array Record info
*/
protected function getRecordInformations()
{
$pageRecord = $this->recordArray;
if (empty($pageRecord)) {
return [];
}
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
$uid = '';
$title = '';
$additionalInfo = (!empty($pageRecord['_additional_info']) ? $pageRecord['_additional_info'] : '');
// Add icon with context menu, etc:
// If there IS a real page
if (is_array($pageRecord) && !empty($pageRecord['uid'])) {
$toolTip = BackendUtility::getRecordToolTip($pageRecord, 'pages');
$iconImg = '<span ' . $toolTip . '>' . $iconFactory->getIconForRecord('pages', $pageRecord, Icon::SIZE_SMALL)->render() . '</span>';
// Make Icon:
$theIcon = BackendUtility::wrapClickMenuOnIcon($iconImg, 'pages', $pageRecord['uid']);
$uid = $pageRecord['uid'];
$title = BackendUtility::getRecordTitle('pages', $pageRecord);
} elseif (is_array($pageRecord) && !empty($pageRecord['combined_identifier'])) {
// If the module is about a FAL resource
try {
$resourceObject = ResourceFactory::getInstance()->getObjectFromCombinedIdentifier($pageRecord['combined_identifier']);
$fileMountTitle = $resourceObject->getStorage()->getFileMounts()[$resourceObject->getIdentifier()]['title'] ?? '';
$title = $fileMountTitle ?: $resourceObject->getName();
// If this is a folder but not in within file mount boundaries this is the root folder
if ($resourceObject instanceof FolderInterface && !$resourceObject->getStorage()->isWithinFileMountBoundaries($resourceObject)) {
$iconImg = '<span title="' . htmlspecialchars($title) . '">' . $iconFactory->getIconForResource(
$resourceObject,
Icon::SIZE_SMALL,
null,
['mount-root' => true]
)->render() . '</span>';
} else {
$iconImg = '<span title="' . htmlspecialchars($title) . '">' . $iconFactory->getIconForResource(
$resourceObject,
Icon::SIZE_SMALL
)->render() . '</span>';
}
$tableName = ($resourceObject->getIdentifier() === $resourceObject->getStorage()->getRootLevelFolder()->getIdentifier())
? 'sys_filemounts' : 'sys_file';
$theIcon = BackendUtility::wrapClickMenuOnIcon($iconImg, $tableName, $pageRecord['combined_identifier']);
} catch (ResourceDoesNotExistException $e) {
$theIcon = '';
}
} else {
// On root-level of page tree
// Make Icon
$iconImg = '<span title="' .
htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) .
'">' .
$iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render() . '</span>';
if ($this->getBackendUser()->isAdmin()) {
$theIcon = BackendUtility::wrapClickMenuOnIcon($iconImg, 'pages');
} else {
$theIcon = $iconImg;
}
$uid = '0';
$title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
}
// returns array for icon, title, uid and additional info
return [
'uid' => $uid,
'icon' => $theIcon,
'title' => $title,
'additionalInfo' => $additionalInfo
];
}
/**
* Get LanguageService Object
*
* @return LanguageService
*/
protected function getLanguageService()
{
return $GLOBALS['LANG'];
}
/**
* Get the Backend User Object
*
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
*/
protected function getBackendUser()
{
return $GLOBALS['BE_USER'];
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,760 @@
<?php
namespace TYPO3\CMS\Backend\Template;
/*
* 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\Backend\Shortcut\ShortcutRepository;
use TYPO3\CMS\Backend\Template\Components\DocHeaderComponent;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Messaging\AbstractMessage;
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\HttpUtility;
use TYPO3\CMS\Fluid\View\Exception\InvalidTemplateResourceException;
use TYPO3\CMS\Fluid\View\StandaloneView;
/**
* A class taking care of the "outer" HTML of a module, especially
* the doc header and other related parts.
*
* @internal This API is not yet carved in stone and may be adapted later.
*/
class ModuleTemplate
{
/**
* Error Icon Constant
*
* @internal
*/
const STATUS_ICON_ERROR = 3;
/**
* Warning Icon Constant
*
* @internal
*/
const STATUS_ICON_WARNING = 2;
/**
* Notification Icon Constant
*
* @internal
*/
const STATUS_ICON_NOTIFICATION = 1;
/**
* OK Icon Constant
*
* @internal
*/
const STATUS_ICON_OK = -1;
/**
* DocHeaderComponent
*
* @var DocHeaderComponent
*/
protected $docHeaderComponent;
/**
* Javascript Code Array
* Used for inline JS
*
* @var array
*/
protected $javascriptCodeArray = [];
/**
* Expose the pageRenderer
*
* @var PageRenderer
*/
protected $pageRenderer;
/**
* @var bool
*/
protected $uiBlock = false;
/**
* TemplateRootPath
*
* @var string[]
*/
protected $templateRootPaths = ['EXT:backend/Resources/Private/Templates'];
/**
* PartialRootPath
*
* @var string[]
*/
protected $partialRootPaths = ['EXT:backend/Resources/Private/Partials'];
/**
* LayoutRootPath
*
* @var string[]
*/
protected $layoutRootPaths = ['EXT:backend/Resources/Private/Layouts'];
/**
* Template name
*
* @var string
*/
protected $templateFile = 'Module.html';
/**
* Fluid Standalone View
*
* @var StandaloneView
*/
protected $view;
/**
* Content String
*
* @var string
*/
protected $content = '';
/**
* IconFactory Member
*
* @var IconFactory
*/
protected $iconFactory;
/**
* Module ID
*
* @var string
*/
protected $moduleId = '';
/**
* Module Name
*
* @var string
*/
protected $moduleName = '';
/**
* Title Tag
*
* @var string
*/
protected $title = '';
/**
* Body Tag
*
* @var string
*/
protected $bodyTag = '<body>';
/**
* Flash message queue
*
* @var \TYPO3\CMS\Core\Messaging\FlashMessageQueue
*/
protected $flashMessageQueue;
/**
* Returns the current body tag
*
* @return string
*/
public function getBodyTag()
{
return $this->bodyTag;
}
/**
* Sets the body tag
*
* @param string $bodyTag
* @return self
*/
public function setBodyTag($bodyTag): self
{
$this->bodyTag = $bodyTag;
return $this;
}
/**
* Gets the standalone view.
*
* @return StandaloneView
*/
public function getView()
{
return $this->view;
}
/**
* Set content
*
* @param string $content Content of the module
* @return self
*/
public function setContent($content): self
{
$this->view->assign('content', $content);
return $this;
}
/**
* Set title tag
*
* @param string $title
* @return self
*/
public function setTitle($title): self
{
$this->title = $title;
return $this;
}
/**
* Returns the IconFactory
*
* @return IconFactory
*/
public function getIconFactory()
{
return $this->iconFactory;
}
/**
* Class constructor
* Sets up view and property objects
*
* @throws InvalidTemplateResourceException In case a template is invalid
*/
public function __construct()
{
$this->view = GeneralUtility::makeInstance(StandaloneView::class);
$this->view->setPartialRootPaths($this->partialRootPaths);
$this->view->setTemplateRootPaths($this->templateRootPaths);
$this->view->setLayoutRootPaths($this->layoutRootPaths);
$this->view->setTemplate($this->templateFile);
$this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
$this->docHeaderComponent = GeneralUtility::makeInstance(DocHeaderComponent::class);
$this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
}
/**
* Loads all necessary Javascript Files
*/
protected function loadJavaScripts()
{
$this->pageRenderer->loadRequireJsModule('bootstrap');
if (TYPO3_MODE === 'BE' && $this->getBackendUserAuthentication() && !empty($this->getBackendUserAuthentication()->user)) {
$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextHelp');
$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DocumentHeader');
$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/SplitButtons');
}
}
/**
* Loads all necessary stylesheets
*/
protected function loadStylesheets()
{
if (!empty($GLOBALS['TBE_STYLES']['stylesheet'])) {
$this->pageRenderer->addCssFile($GLOBALS['TBE_STYLES']['stylesheet']);
}
if (!empty($GLOBALS['TBE_STYLES']['stylesheet2'])) {
$this->pageRenderer->addCssFile($GLOBALS['TBE_STYLES']['stylesheet2']);
}
}
/**
* Sets mandatory parameters for the view (pageRenderer)
*/
protected function setupPage()
{
// Yes, hardcoded on purpose
$this->pageRenderer->setXmlPrologAndDocType('<!DOCTYPE html>');
$this->pageRenderer->setCharSet('utf-8');
$this->pageRenderer->setLanguage($GLOBALS['LANG']->lang);
$this->pageRenderer->setMetaTag('name', 'viewport', 'width=device-width, initial-scale=1');
}
/**
* Wrapper function for adding JS inline blocks
*/
protected function setJavaScriptCodeArray()
{
foreach ($this->javascriptCodeArray as $name => $code) {
$this->pageRenderer->addJsInlineCode($name, $code, false);
}
}
/**
* Adds JS inline blocks of code to the internal registry
*
* @param string $name Javascript code block name
* @param string $code Inline Javascript
* @return self
*/
public function addJavaScriptCode($name = '', $code = ''): self
{
$this->javascriptCodeArray[$name] = $code;
return $this;
}
/**
* Get the DocHeader
*
* @return DocHeaderComponent
*/
public function getDocHeaderComponent()
{
return $this->docHeaderComponent;
}
/**
* Returns the fully rendered view
*
* @return string
*/
public function renderContent()
{
$this->setupPage();
$this->pageRenderer->setTitle($this->title);
$this->loadJavaScripts();
$this->setJavaScriptCodeArray();
$this->loadStylesheets();
$this->view->assign('docHeader', $this->docHeaderComponent->docHeaderContent());
if ($this->moduleId) {
$this->view->assign('moduleId', $this->moduleId);
}
if ($this->moduleName) {
$this->view->assign('moduleName', $this->moduleName);
}
$this->view->assign('uiBlock', $this->uiBlock);
$this->view->assign('flashMessageQueueIdentifier', $this->getFlashMessageQueue()->getIdentifier());
$renderedPage = $this->pageRenderer->render(PageRenderer::PART_HEADER);
$renderedPage .= $this->bodyTag;
$renderedPage .= $this->view->render();
$this->pageRenderer->addJsFooterInlineCode('updateSignals', BackendUtility::getUpdateSignalCode());
$renderedPage .= $this->pageRenderer->render(PageRenderer::PART_FOOTER);
return $renderedPage;
}
/**
* Get PageRenderer
*
* @return PageRenderer
*/
public function getPageRenderer()
{
return $this->pageRenderer;
}
/**
* Set form tag
*
* @param string $formTag Form tag to add
* @return self
*/
public function setForm($formTag = ''): self
{
$this->view->assign('formTag', $formTag);
return $this;
}
/**
* Sets the ModuleId
*
* @param string $moduleId ID of the module
* @return self
*/
public function setModuleId($moduleId): self
{
$this->moduleId = $moduleId;
$this->registerModuleMenu($moduleId);
return $this;
}
/**
* Sets the ModuleName
*
* @param string $moduleName Name of the module
* @return self
*/
public function setModuleName($moduleName): self
{
$this->moduleName = $moduleName;
return $this;
}
/**
* Generates the Menu for things like Web->Info
*
* @param $moduleMenuIdentifier
* @return self
*/
public function registerModuleMenu($moduleMenuIdentifier): self
{
if (isset($GLOBALS['TBE_MODULES_EXT'][$moduleMenuIdentifier])) {
$menuEntries =
$GLOBALS['TBE_MODULES_EXT'][$moduleMenuIdentifier]['MOD_MENU']['function'];
$menu = $this->getDocHeaderComponent()->getMenuRegistry()->makeMenu()->setIdentifier('MOD_FUNC');
foreach ($menuEntries as $menuEntry) {
$menuItem = $menu->makeMenuItem()
->setTitle($menuEntry['title'])
->setHref('#');
$menu->addMenuItem($menuItem);
}
$this->docHeaderComponent->getMenuRegistry()->addMenu($menu);
}
return $this;
}
/**
* Creates a tab menu where the tabs or collapsible are rendered with bootstrap markup
*
* @param array $menuItems Tab elements, each element is an array with "label" and "content"
* @param string $domId DOM id attribute, will be appended with an iteration number per tab.
* @param int $defaultTabIndex Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1
* (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing
* will result in no default tab open.
* @param bool $collapsible If set, the tabs are rendered as headers instead over each sheet. Effectively this means
* there is no tab menu, but rather a foldout/fold-in menu.
* @param bool $wrapContent If set, the content is wrapped in div structure which provides a padding and border
* style. Set this FALSE to get unstyled content pane with fullsize content area.
* @param bool $storeLastActiveTab If set, the last open tab is stored in local storage and will be re-open again.
* If you don't need this feature, e.g. for wizards like import/export you can
* disable this behaviour.
* @return string
*/
public function getDynamicTabMenu(array $menuItems, $domId, $defaultTabIndex = 1, $collapsible = false, $wrapContent = true, $storeLastActiveTab = true)
{
$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tabs');
$templatePath = ExtensionManagementUtility::extPath('backend')
. 'Resources/Private/Templates/DocumentTemplate/';
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setTemplatePathAndFilename($templatePath . ($collapsible ? 'Collapse.html' : 'Tabs.html'));
$view->setPartialRootPaths([$templatePath . 'Partials']);
$view->assignMultiple([
'id' => 'DTM-' . GeneralUtility::shortMD5($domId),
'items' => $menuItems,
'defaultTabIndex' => $defaultTabIndex,
'wrapContent' => $wrapContent,
'storeLastActiveTab' => $storeLastActiveTab,
]);
return $view->render();
}
/*******************************************
* THE FOLLOWING METHODS ARE SUBJECT TO BE DEPRECATED / DROPPED!
*
* These methods have been copied over from DocumentTemplate and enables
* core modules to drop the dependency to DocumentTemplate altogether without
* rewriting these modules now.
* The methods below are marked as internal and will be removed
* one-by-one with further refactoring of modules.
*
* Do not use these methods within own extensions if possible or
* be prepared to change this later again.
*******************************************/
/**
* Includes a javascript library that exists in the core /typo3/ directory
*
* @param string $lib Library name. Call it with the full path like
* "sysext/core/Resources/Public/JavaScript/QueryGenerator.js" to load it
*
* @internal
* @return self
* @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0, use PageRenderer directly.
* @see \TYPO3\CMS\Core\Page\PageRenderer::addJsFile
*/
public function loadJavascriptLib($lib): self
{
trigger_error('ModuleTemplate->loadJavascriptLib() should not be used any longer, as this method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
$this->pageRenderer->addJsFile($lib);
return $this;
}
/**
* Returns a linked shortcut-icon which will call the shortcut frame and set a
* shortcut there back to the calling page/module
*
* @param string $gvList Is the list of GET variables to store (if any)
* @param string $setList Is the list of SET[] variables to store
* (if any) - SET[] variables a stored in $GLOBALS["SOBE"]->MOD_SETTINGS
* for backend modules
* @param string $modName Module name string
* @param string|int $motherModName Is used to enter the "parent module
* name" if the module is a submodule under eg. Web>* or File>*. You
* can also set this value to 1 in which case the currentLoadedModule
* is sent to the shortcut script (so - not a fixed value!) - that is used
* in file_edit and wizard_rte modules where those are really running as
* a part of another module.
* @param string $displayName When given this name is used instead of the
* module name.
* @param string $classes Additional CSS classes for the link around the icon
*
* @return string HTML content
* @todo Make this thing return a button object
* @internal
*/
public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '', $displayName = '', $classes = 'btn btn-default btn-sm')
{
$gvList = 'route,id,' . $gvList;
$storeUrl = $this->makeShortcutUrl($gvList, $setList);
$pathInfo = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
// Fallback for alt_mod. We still pass in the old xMOD... stuff,
// but TBE_MODULES only knows about "record_edit".
// We still need to pass the xMOD name to createShortcut below,
// since this is used for icons.
$moduleName = $modName === 'xMOD_alt_doc.php' ? 'record_edit' : $modName;
// Add the module identifier automatically if typo3/index.php is used:
// @todo: routing
if (GeneralUtility::_GET('route') !== null) {
$storeUrl = '&route=' . $moduleName . $storeUrl;
}
if ((int)$motherModName === 1) {
$motherModule = 'top.currentModuleLoaded';
} elseif ($motherModName) {
$motherModule = GeneralUtility::quoteJSvalue($motherModName);
} else {
$motherModule = '\'\'';
}
$confirmationText = GeneralUtility::quoteJSvalue(
$this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.makeBookmark')
);
$shortcutUrl = $pathInfo['path'] . '?' . $storeUrl;
$shortcutRepository = GeneralUtility::makeInstance(ShortcutRepository::class);
$shortcutExist = $shortcutRepository->shortcutExists($shortcutUrl);
if ($shortcutExist) {
return '<a class="active ' . htmlspecialchars($classes) . '" title="">' .
$this->iconFactory->getIcon('actions-system-shortcut-active', Icon::SIZE_SMALL)->render() . '</a>';
}
$url = GeneralUtility::quoteJSvalue(rawurlencode($shortcutUrl));
$onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility::quoteJSvalue(rawurlencode($modName)) .
', ' . $url . ', ' . $confirmationText . ', ' . $motherModule . ', this, ' . GeneralUtility::quoteJSvalue($displayName) . ');return false;';
return '<a href="#" class="' . htmlspecialchars($classes) . '" onclick="' . htmlspecialchars($onClick) . '" title="' .
htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.makeBookmark')) . '">' .
$this->iconFactory->getIcon('actions-system-shortcut-new', Icon::SIZE_SMALL)->render() . '</a>';
}
/**
* MAKE url for storing
* Internal func
*
* @param string $gvList Is the list of GET variables to store (if any)
* @param string $setList Is the list of SET[] variables to store (if any)
* - SET[] variables a stored in $GLOBALS["SOBE"]->MOD_SETTINGS for backend
* modules
*
* @return string GET-parameters for the shortcut-url only(!). String starts with '&'
* @internal
*/
public function makeShortcutUrl($gvList, $setList)
{
$getParams = GeneralUtility::_GET();
$storeArray = array_merge(
GeneralUtility::compileSelectedGetVarsFromArray($gvList, $getParams),
['SET' => GeneralUtility::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS)]
);
return HttpUtility::buildQueryString($storeArray, '&');
}
/**
* Returns the BE USER Object
*
* @return BackendUserAuthentication
*/
protected function getBackendUserAuthentication()
{
return $GLOBALS['BE_USER'];
}
/**
* Returns the LanguageService
*
* @return LanguageService
*/
protected function getLanguageService()
{
return $GLOBALS['LANG'];
}
/**
* Returns an image-tag with an 18x16 icon of the following types:
*
* $type:
* -1:» OK icon (Check-mark)
* 1:» Notice (Speach-bubble)
* 2:» Warning (Yellow triangle)
* 3:» Fatal error (Red stop sign)
*
* @param int $type See description
*
* @return string HTML image tag (if applicable)
* @internal
* @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0
*/
public function icons($type)
{
trigger_error('ModuleTemplate->icons() should not be used any longer, as this will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
$icon = '';
switch ($type) {
case self::STATUS_ICON_ERROR:
$icon = 'status-dialog-error';
break;
case self::STATUS_ICON_WARNING:
$icon = 'status-dialog-warning';
break;
case self::STATUS_ICON_NOTIFICATION:
$icon = 'status-dialog-notification';
break;
case self::STATUS_ICON_OK:
$icon = 'status-dialog-ok';
break;
default:
// Do nothing
}
if ($icon != '') {
return $this->iconFactory->getIcon($icon, Icon::SIZE_SMALL)->render();
}
return '';
}
/**
* Returns JavaScript variables setting the returnUrl and thisScript location for use by JavaScript on the page.
* Used in fx. db_list.php (Web>List)
*
* @param string $thisLocation URL to "this location" / current script
* @return string Urls are returned as JavaScript variables T3_RETURN_URL and T3_THIS_LOCATION
* @see typo3/db_list.php
* @internal
*/
public function redirectUrls($thisLocation = '')
{
$thisLocation = $thisLocation ? $thisLocation : GeneralUtility::linkThisScript([
'CB' => '',
'SET' => '',
'cmd' => '',
'popViewId' => ''
]);
$out = '
var T3_RETURN_URL = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode(GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'))))) . ';
var T3_THIS_LOCATION = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode($thisLocation))) . '
';
return $out;
}
/**
* Returns the header-bar in the top of most backend modules
* Closes section if open.
*
* @param string $text The text string for the header
* @return string HTML content
* @internal
*/
public function header($text)
{
return '
<!-- MAIN Header in page top -->
<h1 class="t3js-title-inlineedit">' . htmlspecialchars($text) . '</h1>
';
}
/**
* Creates a Message object and adds it to the FlashMessageQueue.
*
* @param string $messageBody The message
* @param string $messageTitle Optional message title
* @param int $severity Optional severity, must be one of \TYPO3\CMS\Core\Messaging\FlashMessage constants
* @param bool $storeInSession Optional, defines whether the message should be stored in the session (default)
* @throws \InvalidArgumentException if the message body is no string
* @return self
*/
public function addFlashMessage($messageBody, $messageTitle = '', $severity = AbstractMessage::OK, $storeInSession = true): self
{
if (!is_string($messageBody)) {
throw new \InvalidArgumentException('The message body must be of type string, "' . gettype($messageBody) . '" given.', 1446483133);
}
/* @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */
$flashMessage = GeneralUtility::makeInstance(
\TYPO3\CMS\Core\Messaging\FlashMessage::class,
$messageBody,
$messageTitle,
$severity,
$storeInSession
);
$this->getFlashMessageQueue()->enqueue($flashMessage);
return $this;
}
/**
* @param \TYPO3\CMS\Core\Messaging\FlashMessageQueue $flashMessageQueue
* @return self
*/
public function setFlashMessageQueue($flashMessageQueue): self
{
$this->flashMessageQueue = $flashMessageQueue;
return $this;
}
/**
* @return \TYPO3\CMS\Core\Messaging\FlashMessageQueue
*/
protected function getFlashMessageQueue()
{
if (!isset($this->flashMessageQueue)) {
/** @var FlashMessageService $service */
$service = GeneralUtility::makeInstance(FlashMessageService::class);
$this->flashMessageQueue = $service->getMessageQueueByIdentifier();
}
return $this->flashMessageQueue;
}
/**
* @return bool
*/
public function isUiBlock(): bool
{
return $this->uiBlock;
}
/**
* @param bool $uiBlock
* @return self
*/
public function setUiBlock(bool $uiBlock): self
{
$this->uiBlock = $uiBlock;
return $this;
}
}