VITEC headless: ContentElementResolver, Product fields (videofile, showdatapath)
- New Classes/Service/ContentElementResolver.php: parses TYPO3 typolink
(t3://record?identifier=tt_content&uid=N, t3://page?uid=P#N, plain numeric)
to a normalised tt_content envelope ({id,type,colPos,sorting,appearance,
data}), recursively resolving any nested VITEC list-plugin children.
- ProductListJsonRenderer / ProductShowJsonRenderer: contentelement and
contentelementcta now emit the resolved object instead of the raw
typolink string (breaking change at those two keys).
- Product model: new field videofile (FAL, single video upload in tab
Images and Videos, mp4/webm/ogv/mov/m4v); new bool field showdatapath
(toggle at end of General tab, controls the "Datapath is now Vitec"
graphic in the frontend). ext_tables.sql, TCA, model property +
getter/setter, and both renderers updated accordingly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0
packages/vitec/Classes/DataProcessing/ContainerChildrenProcessor.php
Executable file → Normal file
@@ -215,6 +215,22 @@ class Product extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
|
||||
/**
|
||||
* Uploaded / locally selected video file (FAL)
|
||||
*
|
||||
* @var \TYPO3\CMS\Extbase\Domain\Model\FileReference|null
|
||||
*/
|
||||
protected $videofile;
|
||||
|
||||
|
||||
/**
|
||||
* Show the "Datapath is now Vitec" graphic in the frontend
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $showdatapath = false;
|
||||
|
||||
protected $contentelement;
|
||||
|
||||
/**
|
||||
@@ -865,6 +881,50 @@ class Product extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the uploaded video file
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Domain\Model\FileReference|null
|
||||
*/
|
||||
public function getVideofile(): ?\TYPO3\CMS\Extbase\Domain\Model\FileReference
|
||||
{
|
||||
return $this->videofile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uploaded video file
|
||||
*
|
||||
* @param \TYPO3\CMS\Extbase\Domain\Model\FileReference|null $videofile
|
||||
* @return void
|
||||
*/
|
||||
public function setVideofile(?\TYPO3\CMS\Extbase\Domain\Model\FileReference $videofile): void
|
||||
{
|
||||
$this->videofile = $videofile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the showdatapath flag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getShowdatapath(): bool
|
||||
{
|
||||
return (bool)$this->showdatapath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the showdatapath flag
|
||||
*
|
||||
* @param bool $showdatapath
|
||||
* @return void
|
||||
*/
|
||||
public function setShowdatapath(bool $showdatapath): void
|
||||
{
|
||||
$this->showdatapath = $showdatapath;
|
||||
}
|
||||
|
||||
public function getContentelement(): string
|
||||
{
|
||||
return $this->contentelement;
|
||||
@@ -919,4 +979,4 @@ class Product extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
0
packages/vitec/Classes/EventListener/ShowFrontendLayoutBanner.php
Executable file → Normal file
0
packages/vitec/Classes/Hook/SyncBackendLayoutHook.php
Executable file → Normal file
254
packages/vitec/Classes/Service/ContentElementResolver.php
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evomedien\Vitec\Service;
|
||||
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Evomedien\Vitec\UserFunc\ProductListJsonRenderer;
|
||||
use Evomedien\Vitec\UserFunc\ProductShowJsonRenderer;
|
||||
use Evomedien\Vitec\UserFunc\UsecaseListJsonRenderer;
|
||||
use Evomedien\Vitec\UserFunc\UsecaseShowJsonRenderer;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Resolves a TYPO3 typolink string (as stored by `inputLink` fields like
|
||||
* Product.contentelement / Product.contentelementcta) to the JSON
|
||||
* representation of the referenced tt_content element.
|
||||
*
|
||||
* Mirrors the shape produced by
|
||||
* {@see \Evomedien\Vitec\DataProcessing\ContainerChildrenProcessor}:
|
||||
* { id, type, colPos, sorting, appearance, data }
|
||||
*
|
||||
* Nested VITEC list-plugins are resolved through their `renderForRecord()`
|
||||
* just like container children, so a referenced productlist / productshow /
|
||||
* usecaselist / usecaseshow appears with its full headless JSON in `data`.
|
||||
*
|
||||
* Exception-safe: every public entry point returns `null` on any failure
|
||||
* so the surrounding JSON output stays clean.
|
||||
*/
|
||||
final class ContentElementResolver
|
||||
{
|
||||
/** Fields that go to the envelope (not to `data`). */
|
||||
private const ENVELOPE = [
|
||||
'uid', 'CType', 'colPos', 'sorting',
|
||||
'layout', 'frame_class', 'space_before_class', 'space_after_class',
|
||||
];
|
||||
|
||||
/** Technical / system / TCA-default fields — never sent to frontend. */
|
||||
private const SYSTEM_FIELDS = [
|
||||
'pid', 'sys_language_uid', 'l18n_parent', 'l18n_diffsource',
|
||||
'l10n_source', 'l10n_state', 'l10n_parent',
|
||||
't3_origuid', 'tx_impexp_origuid',
|
||||
'tx_container_parent',
|
||||
'tstamp', 'crdate', 'cruser_id',
|
||||
'hidden', 'deleted', 'starttime', 'endtime', 'fe_group',
|
||||
't3ver_oid', 't3ver_wsid', 't3ver_state', 't3ver_stage',
|
||||
't3ver_id', 't3ver_label', 't3ver_count', 't3ver_tstamp',
|
||||
'editlock', 'sorting_foreign', 'rowDescription',
|
||||
'spaceBefore', 'spaceAfter',
|
||||
'imagecols', 'sectionIndex', 'linkToTop', 'recursive', 'date',
|
||||
'bullets_type', 'cols',
|
||||
'table_delimiter', 'table_enclosure', 'table_header_position',
|
||||
'table_tfoot', 'table_caption',
|
||||
'filelink_size', 'filelink_sorting', 'filelink_sorting_direction',
|
||||
'uploads_description', 'uploads_type',
|
||||
];
|
||||
|
||||
private const KEEP_IF_ZERO = ['header_layout'];
|
||||
|
||||
private const PLUGIN_RENDERERS = [
|
||||
'vitec_productlist' => [ProductListJsonRenderer::class, 'products'],
|
||||
'vitec_productshow' => [ProductShowJsonRenderer::class, 'product'],
|
||||
'vitec_usecaselist' => [UsecaseListJsonRenderer::class, 'usecases'],
|
||||
'vitec_usecaseshow' => [UsecaseShowJsonRenderer::class, 'usecase'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Resolve a typolink string to a normalised tt_content JSON element.
|
||||
*
|
||||
* Accepted forms (all may include an optional anchor fragment):
|
||||
* - "t3://record?identifier=tt_content&uid=N"
|
||||
* - "t3://page?uid=PAGE#N" (link-popup: pick a CE on a page;
|
||||
* the fragment is the tt_content uid)
|
||||
* - "<numeric>" (legacy: bare tt_content uid)
|
||||
* - everything else → null (pure page links etc.)
|
||||
*
|
||||
* @return array<string,mixed>|null
|
||||
*/
|
||||
public static function resolveLink(?string $link): ?array
|
||||
{
|
||||
try {
|
||||
$link = trim((string)$link);
|
||||
if ($link === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$uid = self::extractTtContentUid($link);
|
||||
if ($uid <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tt_content');
|
||||
$row = $qb
|
||||
->select('*')
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$qb->expr()->eq('uid', $qb->createNamedParameter($uid, ParameterType::INTEGER)),
|
||||
$qb->expr()->eq('deleted', 0),
|
||||
$qb->expr()->eq('hidden', 0)
|
||||
)
|
||||
->executeQuery()
|
||||
->fetchAssociative();
|
||||
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::normaliseRecord($row);
|
||||
} catch (\Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise a tt_content DB row to the same envelope shape that
|
||||
* {@see \Evomedien\Vitec\DataProcessing\ContainerChildrenProcessor}
|
||||
* emits for container children. VITEC list-plugin children are
|
||||
* resolved to their headless JSON.
|
||||
*
|
||||
* @param array<string,mixed> $record
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function normaliseRecord(array $record): array
|
||||
{
|
||||
$data = [];
|
||||
foreach ($record as $field => $value) {
|
||||
if (in_array($field, self::ENVELOPE, true)) {
|
||||
continue;
|
||||
}
|
||||
if (in_array($field, self::SYSTEM_FIELDS, true)) {
|
||||
continue;
|
||||
}
|
||||
if (self::isEmpty($value) && !in_array($field, self::KEEP_IF_ZERO, true)) {
|
||||
continue;
|
||||
}
|
||||
$data[$field] = self::castValue($field, $value);
|
||||
}
|
||||
|
||||
self::resolvePluginData($record, $data);
|
||||
|
||||
return [
|
||||
'id' => (int)$record['uid'],
|
||||
'type' => (string)$record['CType'],
|
||||
'colPos' => (int)($record['colPos'] ?? 0),
|
||||
'sorting' => (int)($record['sorting'] ?? 0),
|
||||
'appearance' => [
|
||||
'layout' => (string)($record['layout'] ?? ''),
|
||||
'frameClass' => (string)($record['frame_class'] ?? 'default'),
|
||||
'spaceBefore' => (string)($record['space_before_class'] ?? ''),
|
||||
'spaceAfter' => (string)($record['space_after_class'] ?? ''),
|
||||
],
|
||||
'data' => (object)$data,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the tt_content uid from a typolink string.
|
||||
*
|
||||
* Handles four forms:
|
||||
* 1. plain numeric → tt_content uid
|
||||
* 2. t3://record?identifier=tt_content&uid=N → uid N
|
||||
* 3. t3://record?identifier=tt_content&uid=N#X → uid N (anchor ignored)
|
||||
* 4. t3://page?uid=PAGE#N → uid N from fragment
|
||||
* (link-popup picks a content element on a page; the fragment is
|
||||
* the tt_content uid, the query is the page uid)
|
||||
*/
|
||||
private static function extractTtContentUid(string $link): int
|
||||
{
|
||||
// Form 1: bare numeric uid
|
||||
if (ctype_digit($link)) {
|
||||
return (int)$link;
|
||||
}
|
||||
|
||||
$parts = parse_url($link);
|
||||
if (!is_array($parts)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Forms 2 & 3: t3://record?identifier=tt_content&uid=N
|
||||
if (str_starts_with($link, 't3://record') && !empty($parts['query'])) {
|
||||
$params = [];
|
||||
parse_str((string)$parts['query'], $params);
|
||||
$identifier = (string)($params['identifier'] ?? '');
|
||||
$uid = (int)($params['uid'] ?? 0);
|
||||
if ($identifier === 'tt_content' && $uid > 0) {
|
||||
return $uid;
|
||||
}
|
||||
}
|
||||
|
||||
// Form 4: t3://page?uid=PAGE#N → tt_content uid lives in the fragment
|
||||
if (str_starts_with($link, 't3://page')) {
|
||||
$fragment = (string)($parts['fragment'] ?? '');
|
||||
if (ctype_digit($fragment)) {
|
||||
return (int)$fragment;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the record is a VITEC list-plugin, run its renderer for THIS row
|
||||
* and inject the decoded result under its key. Drops raw pi_flexform.
|
||||
*
|
||||
* @param array<string,mixed> $record
|
||||
* @param array<string,mixed> $data
|
||||
*/
|
||||
private static function resolvePluginData(array $record, array &$data): void
|
||||
{
|
||||
$listType = (string)($record['list_type'] ?? '');
|
||||
if ($listType === '' || !isset(self::PLUGIN_RENDERERS[$listType])) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
[$rendererClass, $jsonKey] = self::PLUGIN_RENDERERS[$listType];
|
||||
$renderer = GeneralUtility::makeInstance($rendererClass);
|
||||
|
||||
if (!method_exists($renderer, 'renderForRecord')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$json = $renderer->renderForRecord($record);
|
||||
if ($json === '' || $json === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$decoded = json_decode($json, true);
|
||||
if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data[$jsonKey] = $decoded;
|
||||
unset($data['pi_flexform']);
|
||||
} catch (\Throwable $e) {
|
||||
// leave raw data on failure
|
||||
}
|
||||
}
|
||||
|
||||
private static function isEmpty(mixed $value): bool
|
||||
{
|
||||
return $value === null || $value === '' || $value === 0 || $value === '0';
|
||||
}
|
||||
|
||||
private static function castValue(string $field, mixed $value): mixed
|
||||
{
|
||||
if (in_array($field, ['header_layout'], true)) {
|
||||
return (int)$value;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -155,8 +155,8 @@ class ProductListJsonRenderer
|
||||
'description' => (string)($product['description'] ?? ''),
|
||||
'highlights' => (string)($product['highlights'] ?? ''),
|
||||
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
|
||||
'contentelement' => (string)($product['contentelement'] ?? ''),
|
||||
'contentelementcta' => (string)($product['contentelementcta'] ?? ''),
|
||||
'contentelement' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelement'] ?? '')),
|
||||
'contentelementcta' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelementcta'] ?? '')),
|
||||
|
||||
'hideonapp' => (bool)($product['hideonapp'] ?? false),
|
||||
'hideonwebsite' => (bool)($product['hideonwebsite'] ?? false),
|
||||
@@ -166,6 +166,7 @@ class ProductListJsonRenderer
|
||||
'legacy' => (bool)($product['legacy'] ?? false),
|
||||
'supportproduct' => (bool)($product['supportproduct'] ?? false),
|
||||
'subproduct' => (bool)($product['subproduct'] ?? false),
|
||||
'showdatapath' => (bool)($product['showdatapath'] ?? false),
|
||||
|
||||
'link' => '/product/' . (string)($product['slug'] ?? ''),
|
||||
|
||||
@@ -173,6 +174,7 @@ class ProductListJsonRenderer
|
||||
'images' => $this->getProductImages($uid),
|
||||
'downloads' => $this->getProductDownloads($uid),
|
||||
'ogimage' => $this->getProductOgImage($uid),
|
||||
'videofile' => $this->getProductVideoFile($uid),
|
||||
'relatedprodukt' => $this->getRelatedProducts($uid),
|
||||
];
|
||||
}
|
||||
@@ -310,6 +312,49 @@ class ProductListJsonRenderer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve the uploaded video file (single FAL reference, fieldname=videofile).
|
||||
*
|
||||
* @return array<string,mixed>|null
|
||||
*/
|
||||
protected function getProductVideoFile(int $productUid): ?array
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||
->getQueryBuilderForTable('sys_file_reference');
|
||||
|
||||
$row = $queryBuilder
|
||||
->select('fr.uid', 'fr.title', 'fr.description', 'f.uid as file_uid', 'f.identifier', 'f.name', 'f.size', 'f.extension', 'f.mime_type')
|
||||
->from('sys_file_reference', 'fr')
|
||||
->join('fr', 'sys_file', 'f', 'fr.uid_local = f.uid')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('fr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', \Doctrine\DBAL\ParameterType::STRING)),
|
||||
$queryBuilder->expr()->eq('fr.fieldname', $queryBuilder->createNamedParameter('videofile', \Doctrine\DBAL\ParameterType::STRING)),
|
||||
$queryBuilder->expr()->eq('fr.uid_foreign', $queryBuilder->createNamedParameter($productUid, \Doctrine\DBAL\ParameterType::INTEGER)),
|
||||
$queryBuilder->expr()->eq('fr.deleted', 0),
|
||||
$queryBuilder->expr()->eq('fr.hidden', 0),
|
||||
$queryBuilder->expr()->eq('f.missing', 0)
|
||||
)
|
||||
->orderBy('fr.sorting_foreign', 'ASC')
|
||||
->setMaxResults(1)
|
||||
->executeQuery()
|
||||
->fetchAssociative();
|
||||
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'uid' => (int)$row['file_uid'],
|
||||
'name' => (string)($row['name'] ?? ''),
|
||||
'url' => '/fileadmin' . ($row['identifier'] ?? ''),
|
||||
'size' => (int)($row['size'] ?? 0),
|
||||
'extension' => (string)($row['extension'] ?? ''),
|
||||
'mimeType' => (string)($row['mime_type'] ?? ''),
|
||||
'title' => (string)($row['title'] ?? ''),
|
||||
'description' => (string)($row['description'] ?? ''),
|
||||
];
|
||||
}
|
||||
protected function getProductCategories(int $productUid): array
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||
|
||||
@@ -169,8 +169,8 @@ class ProductShowJsonRenderer
|
||||
'description' => (string)($product['description'] ?? ''),
|
||||
'highlights' => (string)($product['highlights'] ?? ''),
|
||||
'shortcutpid' => (string)($product['shortcutpid'] ?? ''),
|
||||
'contentelement' => (string)($product['contentelement'] ?? ''),
|
||||
'contentelementcta' => (string)($product['contentelementcta'] ?? ''),
|
||||
'contentelement' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelement'] ?? '')),
|
||||
'contentelementcta' => \Evomedien\Vitec\Service\ContentElementResolver::resolveLink((string)($product['contentelementcta'] ?? '')),
|
||||
|
||||
'hideonapp' => (bool)($product['hideonapp'] ?? false),
|
||||
'hideonwebsite' => (bool)($product['hideonwebsite'] ?? false),
|
||||
@@ -180,6 +180,7 @@ class ProductShowJsonRenderer
|
||||
'legacy' => (bool)($product['legacy'] ?? false),
|
||||
'supportproduct' => (bool)($product['supportproduct'] ?? false),
|
||||
'subproduct' => (bool)($product['subproduct'] ?? false),
|
||||
'showdatapath' => (bool)($product['showdatapath'] ?? false),
|
||||
|
||||
'link' => '/product/' . (string)($product['slug'] ?? ''),
|
||||
|
||||
@@ -187,6 +188,7 @@ class ProductShowJsonRenderer
|
||||
'images' => $this->getProductImages($uid),
|
||||
'downloads' => $this->getProductDownloads($uid),
|
||||
'ogimage' => $this->getProductOgImage($uid),
|
||||
'videofile' => $this->getProductVideoFile($uid),
|
||||
'relatedprodukt' => $this->getRelatedProducts($uid),
|
||||
];
|
||||
}
|
||||
@@ -317,6 +319,49 @@ class ProductShowJsonRenderer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve the uploaded video file (single FAL reference, fieldname=videofile).
|
||||
*
|
||||
* @return array<string,mixed>|null
|
||||
*/
|
||||
protected function getProductVideoFile(int $productUid): ?array
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||
->getQueryBuilderForTable('sys_file_reference');
|
||||
|
||||
$row = $queryBuilder
|
||||
->select('fr.uid', 'fr.title', 'fr.description', 'f.uid as file_uid', 'f.identifier', 'f.name', 'f.size', 'f.extension', 'f.mime_type')
|
||||
->from('sys_file_reference', 'fr')
|
||||
->join('fr', 'sys_file', 'f', 'fr.uid_local = f.uid')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('fr.tablenames', $queryBuilder->createNamedParameter('tx_vitec_domain_model_product', \Doctrine\DBAL\ParameterType::STRING)),
|
||||
$queryBuilder->expr()->eq('fr.fieldname', $queryBuilder->createNamedParameter('videofile', \Doctrine\DBAL\ParameterType::STRING)),
|
||||
$queryBuilder->expr()->eq('fr.uid_foreign', $queryBuilder->createNamedParameter($productUid, \Doctrine\DBAL\ParameterType::INTEGER)),
|
||||
$queryBuilder->expr()->eq('fr.deleted', 0),
|
||||
$queryBuilder->expr()->eq('fr.hidden', 0),
|
||||
$queryBuilder->expr()->eq('f.missing', 0)
|
||||
)
|
||||
->orderBy('fr.sorting_foreign', 'ASC')
|
||||
->setMaxResults(1)
|
||||
->executeQuery()
|
||||
->fetchAssociative();
|
||||
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'uid' => (int)$row['file_uid'],
|
||||
'name' => (string)($row['name'] ?? ''),
|
||||
'url' => '/fileadmin' . ($row['identifier'] ?? ''),
|
||||
'size' => (int)($row['size'] ?? 0),
|
||||
'extension' => (string)($row['extension'] ?? ''),
|
||||
'mimeType' => (string)($row['mime_type'] ?? ''),
|
||||
'title' => (string)($row['title'] ?? ''),
|
||||
'description' => (string)($row['description'] ?? ''),
|
||||
];
|
||||
}
|
||||
protected function getProductCategories(int $productUid): array
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
|
||||
0
packages/vitec/Classes/UserFunc/UsecaseListJsonRenderer.php
Executable file → Normal file
0
packages/vitec/Classes/UserFunc/UsecaseShowJsonRenderer.php
Executable file → Normal file
0
packages/vitec/Classes/View/BackendLayoutDataProvider.php
Executable file → Normal file
0
packages/vitec/Classes/View/VitecBackendLayoutView.php
Executable file → Normal file
0
packages/vitec/Configuration/FlexForms/Container.xml
Executable file → Normal file
0
packages/vitec/Configuration/Icons.php
Executable file → Normal file
0
packages/vitec/Configuration/TCA/Overrides/pages.php
Executable file → Normal file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_25_25_25_25.php
Executable file → Normal file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_33_33_33.php
Executable file → Normal file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_33_66.php
Executable file → Normal file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_50_50.php
Executable file → Normal file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_cols_66_33.php
Executable file → Normal file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_container.php
Executable file → Normal file
0
packages/vitec/Configuration/TCA/Overrides/tt_content_vitec_shared.php
Executable file → Normal file
@@ -23,9 +23,9 @@ return [
|
||||
],
|
||||
],
|
||||
'types' => [
|
||||
'1' => ['showitem' => 'title, subtitle, slug, teaser, description, applications, highlights, contentelement, contentelementcta, downloads,
|
||||
'1' => ['showitem' => 'title, subtitle, slug, teaser, description, applications, highlights, contentelement, contentelementcta, downloads, showdatapath,
|
||||
--div--;SEO, seotitle, urltitle, seometa, keywords, structureddata,
|
||||
--div--;Images and Videos, productimage, ogimage, video,
|
||||
--div--;Images and Videos, productimage, ogimage, video, videofile,
|
||||
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories, categories,
|
||||
--div--;Visibility, hideonapp, hideonwebsite, hideondatasheets, hideonproducts, shortcut, shortcutpid,
|
||||
--div--;Misc, legacy, supportproduct, subproduct, relatedprodukt,
|
||||
@@ -496,6 +496,52 @@ return [
|
||||
],
|
||||
],
|
||||
|
||||
'videofile' => [
|
||||
'exclude' => true,
|
||||
'label' => 'Video File (Upload or Local)',
|
||||
'config' => [
|
||||
'type' => 'inline',
|
||||
'foreign_table' => 'sys_file_reference',
|
||||
'foreign_field' => 'uid_foreign',
|
||||
'foreign_sortby' => 'sorting_foreign',
|
||||
'foreign_table_field' => 'tablenames',
|
||||
'foreign_match_fields' => [
|
||||
'fieldname' => 'videofile',
|
||||
],
|
||||
'appearance' => [
|
||||
'collapseAll' => true,
|
||||
'levelLinksPosition' => 'top',
|
||||
'showSynchronizationLink' => true,
|
||||
'showPossibleLocalizationRecords' => true,
|
||||
'showAllLocalizationLink' => true,
|
||||
],
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true,
|
||||
],
|
||||
'filter' => [
|
||||
[
|
||||
'userFunc' => \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter::class . '->filterInlineChildren',
|
||||
'parameters' => [
|
||||
'allowedFileExtensions' => 'mp4,webm,ogv,mov,m4v',
|
||||
],
|
||||
],
|
||||
],
|
||||
'maxitems' => 1,
|
||||
'minitems' => 0,
|
||||
],
|
||||
],
|
||||
|
||||
'showdatapath' => [
|
||||
'exclude' => true,
|
||||
'label' => "Show 'Datapath is now Vitec' graphic",
|
||||
'description' => "Toggle the 'Datapath is now Vitec' graphic on this product in the frontend.",
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
'renderType' => 'checkboxToggle',
|
||||
'default' => 0,
|
||||
],
|
||||
],
|
||||
|
||||
'contentelement' => [
|
||||
'exclude' => true,
|
||||
'label' => 'Select Content Element for Key Features Section',
|
||||
@@ -538,4 +584,4 @@ return [
|
||||
|
||||
/* ----------------------------------------------------- */
|
||||
],
|
||||
];
|
||||
];
|
||||
|
||||
0
packages/vitec/Configuration/TypoScript/Headless/vitec_containers.typoscript
Executable file → Normal file
0
packages/vitec/Configuration/TypoScript/Headless/vitec_menus.typoscript
Executable file → Normal file
0
packages/vitec/Resources/Private/Language/locallang_containers.xlf
Executable file → Normal file
0
packages/vitec/Resources/Private/Language/locallang_pages.xlf
Executable file → Normal file
0
packages/vitec/Resources/Public/Icons/vitec-cols-25-25-25-25.svg
Executable file → Normal file
|
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
0
packages/vitec/Resources/Public/Icons/vitec-cols-33-33-33.svg
Executable file → Normal file
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 278 B |
0
packages/vitec/Resources/Public/Icons/vitec-cols-33-66.svg
Executable file → Normal file
|
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
0
packages/vitec/Resources/Public/Icons/vitec-cols-50-50.svg
Executable file → Normal file
|
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 203 B |
0
packages/vitec/Resources/Public/Icons/vitec-cols-66-33.svg
Executable file → Normal file
|
Before Width: | Height: | Size: 202 B After Width: | Height: | Size: 202 B |
0
packages/vitec/Resources/Public/Icons/vitec-container.svg
Executable file → Normal file
|
Before Width: | Height: | Size: 447 B After Width: | Height: | Size: 447 B |
0
packages/vitec/ext_localconf.php
Executable file → Normal file
@@ -51,6 +51,8 @@ CREATE TABLE tx_vitec_domain_model_product (
|
||||
productlayout int(11) DEFAULT '0' NOT NULL,
|
||||
contentelement varchar(255) DEFAULT '' NOT NULL,
|
||||
contentelementcta varchar(255) DEFAULT '' NOT NULL,
|
||||
videofile int(11) unsigned DEFAULT '0' NOT NULL,
|
||||
showdatapath smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||
KEY parent (pid)
|
||||
);
|
||||
CREATE TABLE tx_vitec_domain_model_download (
|
||||
@@ -168,4 +170,4 @@ ADD type VARCHAR(255) DEFAULT '' NOT NULL;
|
||||
|
||||
CREATE TABLE tt_content (
|
||||
tx_vitec_bg_variant VARCHAR(20) DEFAULT 'none' NOT NULL
|
||||
);
|
||||
);
|
||||
|
||||