Last active
December 5, 2022 13:20
-
-
Save vkemeter/92e0c11eba014399e68cbd1fa95f7738 to your computer and use it in GitHub Desktop.
Add Custom TCA Field (for Simple Informations in the Backend e.g.)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// location: EXT:theme/Resources/Public/JavaScript/Backend.js | |
// depending on https://gist.github.com/vkemeter/92e0c11eba014399e68cbd1fa95f7738#file-complexinformation-php-L56 | |
define([ | |
'jquery', | |
'TYPO3/CMS/Backend/Modal', | |
'TYPO3/CMS/Backend/ActionButton/ImmediateAction', | |
'TYPO3/CMS/Backend/Notification', | |
'TYPO3/CMS/Core/Event/RegularEvent' | |
], function ($, Modal, ImmediateAction, Notification, RegularEvent) { | |
$(() => { | |
function createModalContent(origin) { | |
const img = $('<img>') | |
.attr('src', $(origin).data('image')) | |
.addClass('js-image-position') | |
.css({ | |
'max-width': '100%', | |
'height': 'auto', | |
'position': 'relative' | |
}); | |
const wrapper = $('<span>') | |
.css({ | |
'display': 'inline-block', | |
'position': 'relative' | |
}) | |
.append(img); | |
return wrapper; | |
} | |
function createIndicatorElement({x, y}, color = 'white') { | |
return $('<span>').css({ | |
'position': 'absolute', | |
'left': x + '%', | |
'top': y + '%', | |
'width': '38px', | |
'height': '38px', | |
'margin': '-19px 0 0 -19px', | |
'pointer-events': 'none', | |
'z-index': '1' | |
}).prepend('<?xml version="1.0" encoding="utf-8"?>\n' + | |
'<svg width="38" height="38" viewBox="0 0 38 38" fill="none" id="InfoOverlayIcon" xmlns="http://www.w3.org/2000/svg">\n' + | |
' <circle opacity="0.5" cx="19" cy="19" r="19" fill="#424241"/>\n' + | |
' <circle cx="19" cy="19" r="17.5" stroke="'+ color +'" stroke-width="3"/>\n' + | |
' <line x1="19" y1="16" x2="19" y2="28" stroke="white" stroke-width="4" stroke-linecap="round"/>\n' + | |
' <circle cx="19" cy="10" r="2" fill="white"/>\n' + | |
'</svg>'); | |
} | |
function getModalConfiguration(origin) { | |
let positionIcon; | |
return { | |
type: Modal.types.default, | |
content: createModalContent(origin), | |
size: Modal.sizes.large, | |
title: TYPO3.lang["InfoBoxPosition.modal.title"] || 'Set Translation for Modal Header', | |
callback(modalElement) { | |
const initValue = $('input[data-uid="' + $(origin).data('uid') + '"]').val(); | |
const mutationObserver = new MutationObserver(mutation => { | |
if(mutation[0].target.style.display === 'none') { | |
positionIcon?.remove(); | |
mutationObserver.disconnect(); | |
} | |
}); | |
mutationObserver.observe(modalElement.get(0), { | |
attributes: true, | |
attributeFilter: ['style'] | |
}); | |
try { | |
const initData = JSON.parse(initValue); | |
positionIcon = createIndicatorElement(initData, 'red'); | |
$(modalElement).find('.modal-body > span').prepend(positionIcon); | |
} catch (err) { | |
console.log('No initial data found or data was corrupted', err); | |
} | |
modalElement.find('.js-image-position').on('click', (e) => { | |
const target = e.target; | |
const x = (e.clientX - $(target).offset().left) / $(target).width() * 100; | |
const y = (e.clientY - $(target).offset().top) / $(target).height() * 100; | |
const data = {x, y}; | |
positionIcon?.remove(); | |
positionIcon = createIndicatorElement(data, 'green'); | |
$(target).parent().prepend(positionIcon); | |
document.body.setAttribute('data-position', JSON.stringify(data)); | |
}) | |
}, | |
buttons: [ | |
{ | |
text: TYPO3.lang["InfoBoxPosition.modal.btn.save.position"] || 'Save Record', | |
name: 'save', | |
id: 'image-position-save', | |
icon: 'actions-document-save', | |
active: true, | |
btnClass: 'btn-primary', | |
dataAttributes: { | |
action: 'save' | |
}, | |
trigger() { | |
const positionValue = document.body.dataset.position; | |
if (positionValue) { | |
const {parentid, uid} = origin.dataset; | |
$(`input[data-parentid="${parentid}"][data-uid="${uid}"]`).val(positionValue); | |
} | |
document.body.removeAttribute('data-position'); | |
Modal.currentModal.trigger('modal-dismiss'); | |
positionIcon?.remove(); | |
const immediateActionCallback = new ImmediateAction(function () { | |
$('button[name="_savedok"]').trigger('click'); | |
}); | |
Notification.info( | |
TYPO3.lang["InfoBoxPosition.Notification.save.title"] || 'Save the Record to save the Position', | |
TYPO3.lang["InfoBoxPosition.Notification.save.text"] || 'Urna congue egestas ipsum laoreet gravida dis, turpis libero consequat elit et, eu sit ultricies imperdiet nullam.', | |
0, | |
[ | |
{ | |
label: TYPO3.lang["InfoBoxPosition.Notification.save.btn"] || 'Save Record', | |
action: immediateActionCallback | |
} | |
] | |
); | |
} | |
} | |
] | |
} | |
} | |
function getLayoverItemContainerId() { | |
const layoverItem = Object.keys(TYPO3.settings.FormEngineInline.config) | |
.find(key => key.endsWith('tx_theme_image_details_layover_item')); | |
const exteriorItem = Object.keys(TYPO3.settings.FormEngineInline.config) | |
.find(key => key.endsWith('tx_theme_exterior_infopoint_item')); | |
if (layoverItem) { | |
return layoverItem; | |
} | |
if (exteriorItem) { | |
return exteriorItem; | |
} | |
} | |
const layoverItemContainerId = getLayoverItemContainerId(); | |
if(!layoverItemContainerId) { | |
console.error('Could not find layover container id'); | |
return; | |
} | |
const layoverItemContainer = document.getElementById(layoverItemContainerId)?.querySelector('.panel-group'); | |
new RegularEvent('click', event => { | |
if (typeof event.path !== 'undefined') { | |
var target = event.path.find(el => el.classList.contains('js-open-lightbox')); | |
} else { | |
var target = $(event.target).parent()[0]; | |
} | |
if(target) { | |
event.preventDefault(); | |
const modalConfiguration = getModalConfiguration(target); | |
Modal.advanced(modalConfiguration); | |
} | |
}).delegateTo(layoverItemContainer, '.js-open-lightbox'); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Supseven\Theme\Form\Element; | |
use TYPO3\CMS\Backend\Form\AbstractNode; | |
use TYPO3\CMS\Backend\Form\NodeFactory; | |
use TYPO3\CMS\Core\Database\ConnectionPool; | |
use TYPO3\CMS\Core\Resource\FileRepository; | |
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; | |
use TYPO3\CMS\Core\Utility\GeneralUtility; | |
use TYPO3\CMS\Fluid\View\StandaloneView; | |
class ComplexInformation extends AbstractNode | |
{ | |
/** @var array */ | |
protected $data = []; | |
/** @var string */ | |
private $templateFile = 'ComplexInformation.html'; | |
public function __construct(NodeFactory $nodeFactory, array $data) | |
{ | |
$this->data = $data; | |
parent::__construct($nodeFactory, $data); | |
} | |
/** | |
* @return array | |
*/ | |
public function render(): array | |
{ | |
// use a html/fluid template instead html code | |
/** @var StandaloneView $view */ | |
$view = GeneralUtility::makeInstance(StandaloneView::class); | |
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:theme/Resources/Private/Templates/Backend/Nodes/' . $this->templateFile)); | |
$view->setPartialRootPaths([1627475531 => 'EXT:theme/Resources/Private/Partials/Backend/']); | |
$view->assignMultiple( | |
[ | |
'params' => $this->data['parameterArray'], | |
'data' => $this->getSomeDataFromSomewhere($this->data['databaseRow']['uid']) | |
] | |
); | |
$resultArray = $this->initializeResultArray(); | |
// neet some css? | |
$resultArray['stylesheetFiles'] = [ | |
ExtensionManagementUtility::extPath('theme') . 'Resources/Public/Css/Backend/InfoboxPosition.css', | |
]; | |
// need a requirejs module? | |
$resultArray['requireJsModules'] = [ | |
'TYPO3/CMS/Theme/Backend' | |
]; | |
// add your html template to the output | |
$resultArray['html'] = $view->render(); | |
return $resultArray; | |
} | |
private function getSomeDataFromSomewhere(int $uid): array | |
{ | |
return [ 'some' => 'stuff' ]; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
defined('TYPO3_MODE') || die('Access denied.'); | |
call_user_func( | |
function ($extKey) { | |
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1537950765] = [ | |
'nodeName' => 'simpleInformationBlock', | |
'priority' => 40, | |
'class' => \Supseven\Courses\Form\Element\SimpleInformationBlock::class, | |
]; | |
}, | |
'YourExtKey' | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types = 1); | |
namespace Supseven\Courses\Form\Element; | |
use TYPO3\CMS\Backend\Form\Element\AbstractFormElement; | |
class SimpleInformationBlock extends AbstractFormElement | |
{ | |
public function render() | |
{ | |
$result = $this->initializeResultArray(); | |
$result['html'] = '<div class="alert alert-info">'. $this->data['parameterArray']['fieldConf']['config']['parameters']['text'] .'</div>'; | |
return $result; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// your tca (override) file | |
$tca = [ | |
'columns' => [ | |
'simple_information_block' => [ | |
'label' => 'Information', | |
'config' => [ | |
'type' => 'user', | |
'renderType' => 'simpleInformationBlock', | |
'parameters' => [ | |
'text' => 'I am a Simple Information. Edit me in '. __FILE__, | |
], | |
], | |
], | |
], | |
]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment