Skip to content

Instantly share code, notes, and snippets.

@vkemeter
Last active December 5, 2022 13:20
Show Gist options
  • Save vkemeter/92e0c11eba014399e68cbd1fa95f7738 to your computer and use it in GitHub Desktop.
Save vkemeter/92e0c11eba014399e68cbd1fa95f7738 to your computer and use it in GitHub Desktop.
Add Custom TCA Field (for Simple Informations in the Backend e.g.)
// 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');
});
});
<?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' ];
}
}
<?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'
);
<?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;
}
}
<?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