diff --git a/docs/twig-templates.md b/docs/twig-templates.md new file mode 100644 index 000000000..d8a636dfc --- /dev/null +++ b/docs/twig-templates.md @@ -0,0 +1,134 @@ +# Twig-Templates in MetaModels + +Ab MetaModels 2.5 kann jedes MetaModels-Template zusätzlich als **Twig-Template** angeboten +werden. Existiert für ein Template eine Twig-Variante, hat sie **Vorrang** vor dem klassischen +`.html5`-PHP-Template – analog zu Contao Core. Fehlt die Twig-Variante, wird unverändert das +`.html5` gerendert (voller Rückwärtskompatibilitäts-Fallback). + +## Funktionsweise + +`MetaModels\Render\Template::parse()` fragt vor dem Einbinden des Legacy-`.html5` den +`MetaModels\Render\TwigTemplateSurrogate` ab. Dieser prüft im gemanagten Contao-Twig-Loader +(`contao.twig.filesystem_loader`), ob ein passendes Twig-Template existiert, und rendert es via +`twig`. Der Twig-Context wird über Contaos `ContextFactory::fromData()` aus den Template-Daten +gebaut – dieselben Variablen wie im `.html5` stehen zur Verfügung. + +Das entspricht 1:1 Contaos eigenem Surrogat-Mechanismus +(`\Contao\Template::renderTwigSurrogateIfExists()`). + +### Namensschema + +Aus dem Legacy-Namen wird der Twig-Identifier gebildet: + +``` +@Contao/metamodels//.html.twig +``` + +* **Gruppe** kommt aus dem Render-Kontext: `attribute`, `filter` oder `item`. +* **Leaf** ist der Template-Name ohne das konventionelle Legacy-Präfix. + +| Legacy `.html5` | Gruppe | Twig-Identifier | +|------------------------|-------------|-------------------------------------| +| `mm_attr_text` | `attribute` | `metamodels/attribute/text` | +| `mm_filter_default` | `filter` | `metamodels/filter/default` | +| `mm_filteritem_...` | `filter` | `metamodels/filter/...` | +| `mm_default` | `item` | `metamodels/item/default` | + +Für eigene Templates gilt dieselbe Regel: `mm_attr_text_fancy` wird zu +`metamodels/attribute/text_fancy` — das Präfix entfällt, der Rest wird zum Leaf. + +### Textformat + +Neben der sichtbaren Ausgabe (`html5`) kann auch das Format `text` (Suchindex, Sortierung, +Gruppen-Header) auf Twig laufen. Die Templates dafür tragen ein zusätzliches `.text` im +Namen: + +| Legacy | Twig-Datei | Twig-Identifier | +|-------------------|---------------------------|----------------------------------| +| `mm_attr_text.html5` | `attribute/text.html.twig` | `metamodels/attribute/text` | +| `mm_attr_text.text` | `attribute/text.text.html.twig` | `metamodels/attribute/text.text` | + +Die doppelte Endung ist **kein Schönheitsfehler, sondern zwingend**. Contao bildet den +Identifier, indem es das abschließende `.html.twig` bzw. `.twig` abschneidet, und verbietet +gemischte Typen unter einem Identifier. Ein `text.text.twig` neben `text.html.twig` hätte +also denselben Identifier `…/text`, aber einen anderen Typ — der `ContaoFilesystemLoader` +bricht dann den Aufbau der **gesamten** Hierarchie mit einer `OutOfBoundsException` ab: + +``` +The "metamodels/item/prerendered" template has incompatible types, +got "html.twig/html5" in "…/prerendered.html.twig" and "text.twig" in "…/prerendered.text.twig". +``` + +Das legt Backend **und** Frontend komplett lahm, nicht nur das betroffene Template. Mit +`.text.html.twig` bleibt die echte Endung `html.twig`, und die Textvariante bekommt den +eigenen Identifier `…/text.text`. Dieselbe Benennung nutzt bereits +`email_metamodels_notelist.text.html.twig` im Paket `notelist`. + +Ein projekteigenes `templates/mm_attr_text.text` behält weiterhin Vorrang vor dem +mitgelieferten Twig-Template — genauso wie im Format `html5`. + +### Frontend und Backend + +Der Vorrang gilt in **beiden** Scopes. Die Backend-Listen rendern Attribute ebenfalls mit +`html5` (siehe `ItemRendererListener`), daher wirken Attribut-Twig-Templates auch dort. +**Standardtemplates müssen deshalb backend-tauglich bleiben** (schlanke `div`/`span`-Wrapper, +wie die bisherigen `.html5`). Für abweichende Backend-Darstellung empfiehlt sich ein eigenes +Render-Setting mit eigener Template-Auswahl. + +## Twig-Templates in einem Paket bereitstellen + +Der Contao-Twig-Loader behandelt den Legacy-Ordner `Resources/contao/templates` **flach** +(Unterordner werden verworfen, der Identifier wäre nur der Dateiname). Damit die +`metamodels//`-Struktur erhalten bleibt, müssen die Templates – genau wie in +Contaos eigenen Bundles – unter einem **Namespace-Root** liegen: ein Ordner `twig/` mit einer +leeren Marker-Datei **`.twig-root`**. + +``` +src/CoreBundle/Resources/contao/templates/ +└── twig/ + ├── .twig-root (leere Marker-Datei, einmal pro Paket) + └── metamodels/ + ├── attribute/ + │ └── text.html.twig + ├── filter/ + │ └── default.html.twig + └── item/ + └── default.html.twig +``` + +(In Paketen mit moderner Struktur entsprechend unter `contao/templates/twig/…`.) + +Es ist **kein PHP-Code** nötig – die Dateien werden vom Loader automatisch unter `@Contao` +erfasst. + +## Template Studio, Themes und Overrides + +Weil die Templates im gemanagten `@Contao`-Namespace liegen (Untergruppe `metamodels/`), sind +sie ohne Zusatzaufwand: + +* im **Template Studio** sichtbar und editierbar, +* über **Theme-Ordner** und das globale Projekt-`templates/`-Verzeichnis überschreibbar. + +Ein höher priorisiertes `.html5` in der gemanagten Hierarchie (z. B. ein Projekt-Override am +neuen Pfad `templates/metamodels//.html5`) behält gegenüber einem Paket-Twig-Template +den Vorrang – ebenfalls wie in Contao. + +### Legacy-Flach-Override (Übergangslösung, remove in 3.0) + +Zusätzlich behält ein Override am **flachen** Legacy-Namen im Projekt-`templates/`-Ordner (oder in +einem Theme-Ordner) – z. B. `templates/metamodel_prerendered.html5` – weiterhin Vorrang vor einem +Paket-Twig-Template. `Template::hasLegacyTemplateOverride()` erkennt solche Overrides (Pfad unterhalb +`%kernel.project_dir%/templates`, per DI injiziert) und überspringt dann den Twig-Surrogaten. So +funktionieren bestehende Anpassungen nach dem Upgrade unverändert weiter. + +**Diese Rücksichtnahme ist bewusst als `@deprecated` markiert und entfällt in 3.0** gemeinsam mit den +`.html5`-Templates – Overrides sollten nach `templates/metamodels//…` umgezogen werden. + +## Rollout-Stand + +* **MetaModels Core:** Mechanismus implementiert (`Template`, `TemplateFactory`, + `TwigTemplateSurrogate`, DI) inkl. Legacy-Flach-Override-Vorrang (Übergangslösung). Als erste + Core-Twig-Templates ausgeliefert: `item/prerendered`, `item/unrendered`, `item/prerendered_debug` + sowie `filter/default`, `filter/checkbox`, `filter/radiobuttons`, `filter/linklist`, + `filter/datepicker`. `FrontendFilter` rendert die Filter-Widgets über die MetaModels-Engine. +* **Attribute-Templates:** werden schrittweise paketweise als Twig-Varianten nachgezogen. diff --git a/src/Attribute/Base.php b/src/Attribute/Base.php index 1323b29cd..935368fb5 100644 --- a/src/Attribute/Base.php +++ b/src/Attribute/Base.php @@ -639,7 +639,7 @@ public function parseValue($arrRowData, $strOutputFormat = 'text', $objSettings if ($objSettings && ($strTemplate = (string) $objSettings->get('template'))) { $templateFactory = System::getContainer()->get('metamodels.template_factory'); assert($templateFactory instanceof TemplateFactory); - $objTemplate = $templateFactory->createTemplate($strTemplate); + $objTemplate = $templateFactory->createTemplate($strTemplate, 'attribute'); $this->prepareTemplate($objTemplate, $arrRowData, $objSettings); @@ -657,7 +657,8 @@ public function parseValue($arrRowData, $strOutputFormat = 'text', $objSettings // FIXME: this throws when no parent has been set - need to catch! $objSettingsFallback = $this->getDefaultRenderSettings()->setParent($objSettings->getParent()); - $objTemplate = $templateFactory->createTemplate((string) $objSettingsFallback->get('template')); + $objTemplate = + $templateFactory->createTemplate((string) $objSettingsFallback->get('template'), 'attribute'); $this->prepareTemplate($objTemplate, $arrRowData, $objSettingsFallback); $arrResult['text'] = $objTemplate->parse('text', true); diff --git a/src/CoreBundle/Contao/Hooks/LoadDataContainer.php b/src/CoreBundle/Contao/Hooks/LoadDataContainer.php index 8e9d60a60..671523c94 100644 --- a/src/CoreBundle/Contao/Hooks/LoadDataContainer.php +++ b/src/CoreBundle/Contao/Hooks/LoadDataContainer.php @@ -194,7 +194,7 @@ private function handleNonMetaModelTable(string $tableName): void $parentDCA['list']['operations'][$operationName] = [ 'href' => 'table=' . $metaModelTable, 'icon' => $this->iconBuilder->getBackendIcon($inputScreen['meta']['backendicon']), - 'attributes' => 'onclick="Backend.getScrollOffset()"', + 'attributes' => 'data-action="contao--scroll-offset#store"', ]; // Is the destination table a metamodel with variants? diff --git a/src/CoreBundle/Controller/ListControllerTrait.php b/src/CoreBundle/Controller/ListControllerTrait.php index 9c7af525d..61eece917 100644 --- a/src/CoreBundle/Controller/ListControllerTrait.php +++ b/src/CoreBundle/Controller/ListControllerTrait.php @@ -45,6 +45,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\RouterInterface; use Symfony\Contracts\Translation\TranslatorInterface; +use Twig\Markup; /** * Helper trait for lists (CE and MOD). @@ -410,8 +411,9 @@ private function renderBackendWildcard(string $href, string $name, Model $model) /** @psalm-suppress UndefinedMagicPropertyFetch */ $headline = StringUtil::deserialize($model->headline); + // Mark the info text as safe HTML so the (auto-escaping) Twig be_wildcard template does not escape it. /** @psalm-suppress UndefinedMagicPropertyAssignment */ - $template->wildcard = $this->getWildcardInfoText($model, $href, $name); + $template->wildcard = new Markup($this->getWildcardInfoText($model, $href, $name), 'UTF-8'); /** @psalm-suppress UndefinedMagicPropertyAssignment */ $template->title = (\is_array($headline) ? $headline['value'] : $headline); /** @psalm-suppress UndefinedMagicPropertyAssignment */ diff --git a/src/CoreBundle/EventListener/DcGeneral/DefinitionBuilder/CommandBuilder.php b/src/CoreBundle/EventListener/DcGeneral/DefinitionBuilder/CommandBuilder.php index 7f8b714e7..08ba019aa 100644 --- a/src/CoreBundle/EventListener/DcGeneral/DefinitionBuilder/CommandBuilder.php +++ b/src/CoreBundle/EventListener/DcGeneral/DefinitionBuilder/CommandBuilder.php @@ -205,7 +205,7 @@ private function parseModelOperations(Contao2BackendViewDefinitionInterface $vie assert($this->container instanceof IMetaModelDataDefinition); $collection = $view->getModelCommands(); - $scrOffsetAttributes = ['attributes' => 'onclick="Backend.getScrollOffset();"']; + $scrOffsetAttributes = ['attributes' => 'data-action="contao--scroll-offset#store"']; $this->createCommand($collection, 'edit', ['act' => 'edit'], 'edit.svg'); $this->createCommand($collection, 'copy', ['act' => 'copy'], 'copy.svg', $scrOffsetAttributes); $this->createCommand($collection, 'cut', ['act' => 'cut'], 'cut.svg', $scrOffsetAttributes); @@ -216,7 +216,8 @@ private function parseModelOperations(Contao2BackendViewDefinitionInterface $vie 'delete.svg', [ 'attributes' => - 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'data-action="contao--scroll-offset#store"' + . ' onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ] ); $this->createCommand($collection, 'show', ['act' => 'show'], 'show.svg'); diff --git a/src/CoreBundle/Resources/config/services.yml b/src/CoreBundle/Resources/config/services.yml index 89f6770f1..f8a0f2d39 100644 --- a/src/CoreBundle/Resources/config/services.yml +++ b/src/CoreBundle/Resources/config/services.yml @@ -80,11 +80,20 @@ services: - "%kernel.project_dir%" - "@translator" + metamodels.render.twig_surrogate: + class: MetaModels\Render\TwigTemplateSurrogate + arguments: + - "@twig" + - "@contao.twig.filesystem_loader" + - "@contao.twig.interop.context_factory" + metamodels.template_factory: class: MetaModels\Render\TemplateFactory arguments: - "@=service('contao.framework').getAdapter('Contao\\\\TemplateLoader')" - "@cca.dc-general.scope-matcher" + - "@metamodels.render.twig_surrogate" + - "%kernel.project_dir%" public: true metamodels.contao_input: @@ -136,6 +145,7 @@ services: - '@database_connection' - '@MetaModels\Filter\FilterUrlBuilder' - '@translator' + - '@metamodels.template_factory' public: true metamodels.controller.abstract.add_all: diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel.php index fcf98fa2f..fee56c0e7 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel.php @@ -320,7 +320,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ], ], 'operations' => [ @@ -341,7 +341,7 @@ 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_attribute.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_attribute.php index 263813175..c9993520d 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_attribute.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_attribute.php @@ -181,7 +181,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ] ], 'operations' => [ @@ -196,14 +196,14 @@ 'description' => 'cut.description', 'href' => 'act=cut', 'icon' => 'cut.svg', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ], 'delete' => [ 'label' => 'delete.label', 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_dca.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_dca.php index 4992b0fab..4dd316367 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_dca.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_dca.php @@ -138,7 +138,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ], ], 'operations' => [ @@ -159,7 +159,7 @@ 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_dca_sortgroup.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_dca_sortgroup.php index b2041b22b..137ed8edc 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_dca_sortgroup.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_dca_sortgroup.php @@ -111,7 +111,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ], ], 'operations' => [ @@ -132,7 +132,7 @@ 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_dcasetting.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_dcasetting.php index 62854fe21..137832744 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_dcasetting.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_dcasetting.php @@ -145,14 +145,14 @@ 'label' => 'addall.label', 'description' => 'addall.description', 'class' => 'header_add_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ], 'all' => [ 'label' => 'all.label', 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ], ], 'operations' => [ @@ -173,7 +173,7 @@ 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_dcasetting_condition.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_dcasetting_condition.php index 5fb0d7a20..8eea2d146 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_dcasetting_condition.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_dcasetting_condition.php @@ -159,7 +159,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ] ], 'operations' => [ @@ -185,14 +185,14 @@ 'label' => 'cut.label', 'description' => 'cut.description', 'icon' => 'cut.svg', - 'attributes' => 'onclick="Backend.getScrollOffset()"', + 'attributes' => 'data-action="contao--scroll-offset#store"', ], 'delete' => [ 'label' => 'delete.label', 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_filter.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_filter.php index 9161a567b..ec78dab81 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_filter.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_filter.php @@ -120,7 +120,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ] ], 'operations' => [ @@ -135,7 +135,7 @@ 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_filtersetting.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_filtersetting.php index 9f19b2001..b44517812 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_filtersetting.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_filtersetting.php @@ -158,7 +158,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ] ], 'operations' => [ @@ -184,14 +184,14 @@ 'label' => 'cut.label', 'description' => 'cut.description', 'icon' => 'cut.svg', - 'attributes' => 'onclick="Backend.getScrollOffset()"', + 'attributes' => 'data-action="contao--scroll-offset#store"', ], 'delete' => [ 'label' => 'delete.label', 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_rendersetting.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_rendersetting.php index 9318176f1..14a1c512d 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_rendersetting.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_rendersetting.php @@ -128,14 +128,14 @@ 'label' => 'addall.label', 'description' => 'addall.description', 'class' => 'header_add_all rendersetting_add_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ], 'all' => [ 'label' => 'all.label', 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ] ], 'operations' => [ @@ -155,7 +155,7 @@ 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_rendersettings.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_rendersettings.php index 814fd3a52..d12a6fc60 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_rendersettings.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_rendersettings.php @@ -129,7 +129,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ] ], 'operations' => [ @@ -150,7 +150,7 @@ 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/dca/tl_metamodel_searchable_pages.php b/src/CoreBundle/Resources/contao/dca/tl_metamodel_searchable_pages.php index 926107077..1a4597bfe 100644 --- a/src/CoreBundle/Resources/contao/dca/tl_metamodel_searchable_pages.php +++ b/src/CoreBundle/Resources/contao/dca/tl_metamodel_searchable_pages.php @@ -91,7 +91,7 @@ 'description' => 'all.description', 'href' => 'act=select', 'class' => 'header_edit_all', - 'attributes' => 'onclick="Backend.getScrollOffset();"' + 'attributes' => 'data-action="contao--scroll-offset#store"' ], ], 'operations' => [ @@ -112,7 +112,7 @@ 'description' => 'delete.description', 'href' => 'act=delete', 'icon' => 'delete.svg', - 'attributes' => 'onclick="if (!confirm(this.dataset.msgConfirm)) return false; Backend.getScrollOffset();"', + 'attributes' => 'data-action="contao--scroll-offset#store" onclick="if (!confirm(this.dataset.msgConfirm)) return false;"', ], 'show' => [ 'label' => 'show.label', diff --git a/src/CoreBundle/Resources/contao/templates/be_ace_mm.html5 b/src/CoreBundle/Resources/contao/templates/be_ace_mm.html5 index 3adec21a3..039258cc6 100644 --- a/src/CoreBundle/Resources/contao/templates/be_ace_mm.html5 +++ b/src/CoreBundle/Resources/contao/templates/be_ace_mm.html5 @@ -8,72 +8,99 @@ if ($GLOBALS['TL_CONFIG']['useCE']): ?> diff --git a/src/CoreBundle/Resources/contao/templates/ce_metamodel_list.html.twig b/src/CoreBundle/Resources/contao/templates/ce_metamodel_list.html.twig new file mode 100644 index 000000000..3b7ee82dd --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/ce_metamodel_list.html.twig @@ -0,0 +1,5 @@ +{% extends searchable|default(false) ? '@Contao/block_searchable.html.twig' : '@Contao/block_unsearchable.html.twig' %} +{% block content %} +{{ items|raw }} +{{ pagination|raw }} +{% endblock %} diff --git a/src/CoreBundle/Resources/contao/templates/mm_actionbutton.html.twig b/src/CoreBundle/Resources/contao/templates/mm_actionbutton.html.twig new file mode 100644 index 000000000..88411e519 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/mm_actionbutton.html.twig @@ -0,0 +1 @@ +{% if action.html|default('') %}{{ action.html|raw }}{% else %}{{ action.label|raw }}{% endif %} diff --git a/src/CoreBundle/Resources/contao/templates/mm_clearall_default.html.twig b/src/CoreBundle/Resources/contao/templates/mm_clearall_default.html.twig new file mode 100644 index 000000000..5e6c6620c --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/mm_clearall_default.html.twig @@ -0,0 +1,6 @@ + + + diff --git a/src/CoreBundle/Resources/contao/templates/mm_filter_default.html.twig b/src/CoreBundle/Resources/contao/templates/mm_filter_default.html.twig new file mode 100644 index 000000000..0aac1fbd1 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/mm_filter_default.html.twig @@ -0,0 +1,23 @@ + +
+ {% if headline|default('') %} + <{{ hl }}>{{ headline|raw }} + {% endif %} + + + +
+ {% for filter in filters|default([]) %} +
+ {{ filter.value|raw }} +
+ {% endfor %} + {% if submit|default('') %} +
+ +
+ {% endif %} +
+ +
+ diff --git a/src/CoreBundle/Resources/contao/templates/mm_pagination.html.twig b/src/CoreBundle/Resources/contao/templates/mm_pagination.html.twig new file mode 100644 index 000000000..ff9b489ae --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/mm_pagination.html.twig @@ -0,0 +1,27 @@ +{% set fragment = paginationFragment|default('') ? '#' ~ paginationFragment : '' %} + + + diff --git a/src/CoreBundle/Resources/contao/templates/twig/.twig-root b/src/CoreBundle/Resources/contao/templates/twig/.twig-root new file mode 100644 index 000000000..e69de29bb diff --git a/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/checkbox.html.twig b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/checkbox.html.twig new file mode 100644 index 000000000..55d0afb37 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/checkbox.html.twig @@ -0,0 +1,16 @@ +{% extends "@Contao/metamodels/filter/default.html.twig" %} +{% block formlabel %} + {% if not hide_label|default(false) %} + {{ legend|default('')|raw }} + {% endif %} +{% endblock %} +{% block formfield %} + {% if options|default([]) is iterable and options|length %} +
+ {% for option in options %} + {% set cls = (loop.first ? 'first ' : '') ~ (loop.last ? 'last ' : '') ~ (loop.index0 % 2 == 1 ? 'even' : 'odd') ~ (option.class|default('') ? ' ' ~ option.class : '') %} + + {% endfor %} +
+ {% endif %} +{% endblock %} diff --git a/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/datepicker.html.twig b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/datepicker.html.twig new file mode 100644 index 000000000..bd06caa19 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/datepicker.html.twig @@ -0,0 +1,22 @@ +{% extends "@Contao/metamodels/filter/default.html.twig" %} +{% block formlabel %} + {% if not hide_label|default(false) %} + {{ label|default('')|raw }} + {% endif %} +{% endblock %} +{% block formfield %} + {% set minKey = raw.optionsMin.key|default(null) %} + {% set maxKey = raw.optionsMax.key|default(null) %} + {% set dateMin = minKey is not null ? minKey|date('Y-m-d') : '' %} + {% set dateMax = maxKey is not null ? maxKey|date('Y-m-d') : '' %} + {% set placeholderMin = raw.optionsMin.value|default('') %} + {% set placeholderMax = raw.optionsMax.value|default('') %} + {% set values = raw.value|default([]) %} + {% if raw.eval.fromField|default(false) %} + + {% endif %} + {% set toIndex = (raw.eval.size|default(0) == 2) ? 1 : 0 %} + {% if raw.eval.toField|default(false) %} + + {% endif %} +{% endblock %} diff --git a/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/default.html.twig b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/default.html.twig new file mode 100644 index 000000000..810d281d0 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/default.html.twig @@ -0,0 +1,17 @@ +{# + MetaModels default filter widget - Twig version of mm_filteritem_default.html5. +#} +{% block error %} + {% for error in errors|default([]) %} +

{{ error }}

+ {% endfor %} +{% endblock %} + +{% block formlabel %} + {% if not hide_label|default(false) %} + {{ label|default('')|raw }} + {% endif %} +{% endblock %} +{% block formfield %} + {{ formfield|default('')|raw }} +{% endblock %} diff --git a/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/linklist.html.twig b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/linklist.html.twig new file mode 100644 index 000000000..d562eee8a --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/linklist.html.twig @@ -0,0 +1,21 @@ +{% extends "@Contao/metamodels/filter/default.html.twig" %} +{% block formlabel %} + {% if not hide_label|default(false) %} + {{ label|default('')|raw }} + {% endif %} +{% endblock %} +{% block formfield %} + {% if options|default([]) is iterable and options|length %} + {% set urlFragment = urlfragment|default('') ? '#' ~ urlfragment : '' %} +
    + {% for option in options %} + {% set cls = (loop.first ? 'first ' : '') ~ (loop.last ? 'last ' : '') ~ (loop.index0 % 2 == 1 ? 'even' : 'odd') ~ (option.class|default('') ? ' ' ~ option.class : '') %} +
  • + {{ option.value|raw }} +
  • + {% endfor %} +
+ {% endif %} +{% endblock %} diff --git a/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/radiobuttons.html.twig b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/radiobuttons.html.twig new file mode 100644 index 000000000..448412660 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/twig/metamodels/filter/radiobuttons.html.twig @@ -0,0 +1,16 @@ +{% extends "@Contao/metamodels/filter/default.html.twig" %} +{% block formlabel %} + {% if not hide_label|default(false) %} + {{ legend|default('')|raw }} + {% endif %} +{% endblock %} +{% block formfield %} + {% if options|default([]) is iterable and options|length %} +
+ {% for option in options %} + {% set cls = (loop.first ? 'first ' : '') ~ (loop.last ? 'last ' : '') ~ (loop.index0 % 2 == 1 ? 'even' : 'odd') ~ (option.class|default('') ? ' ' ~ option.class : '') %} + + {% endfor %} +
+ {% endif %} +{% endblock %} diff --git a/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/prerendered.html.twig b/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/prerendered.html.twig new file mode 100644 index 000000000..c44a55ef6 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/prerendered.html.twig @@ -0,0 +1,37 @@ +{# + MetaModels prerendered item list - Twig version of metamodel_prerendered.html5. +#} +{% if data|default([])|length %} +
+ {% for item in data %} + {% block item %} + {% set html5vals = item.html5|default({}) %} + {% set textvals = item.text|default({}) %} +
+ {% for field, name in item.attributes %} + {% set value = html5vals[field] is defined ? html5vals[field] : (textvals[field] is defined ? textvals[field] : null) %} + {% if value is not null %} +
+ {% if not view.get('hideLabels') %} +
{{ 'field_label'|trans({'%field_label%': name}, 'metamodels_list') }}
+ {% endif %} +
{{ value|raw }}
+
+ {% endif %} + {% endfor %} + {% block actions %} +
+ {% for action in item.actions %} + {{ include('@Contao/mm_actionbutton.html.twig', {action: action}) }} + {% endfor %} +
+ {% endblock %} +
+ {% endblock %} + {% endfor %} +
+{% else %} + {% block noItem %} +

{{ noItemsMsg|default('')|raw }}

+ {% endblock %} +{% endif %} diff --git a/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/prerendered_debug.html.twig b/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/prerendered_debug.html.twig new file mode 100644 index 000000000..2215a7d90 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/prerendered_debug.html.twig @@ -0,0 +1,15 @@ +{# + MetaModels prerendered debug list - Twig version of metamodel_prerendered_debug.html5. +#} +{% if app.debug %} + {{ dump(data) }} +{% endif %} +{% if data|default([])|length %} + {% for item in data %} + {# Include here your output, e.g. item.html5['attribute_name'] or item.text['attribute_name']. #} + {% endfor %} +{% else %} + {% block noItem %} +

{{ noItemsMsg|default('')|raw }}

+ {% endblock %} +{% endif %} diff --git a/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/unrendered.html.twig b/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/unrendered.html.twig new file mode 100644 index 000000000..66565df21 --- /dev/null +++ b/src/CoreBundle/Resources/contao/templates/twig/metamodels/item/unrendered.html.twig @@ -0,0 +1,37 @@ +{# + MetaModels unrendered item list - Twig version of metamodel_unrendered.html5. +#} +{% if items.getCount() %} +
+ {% for item in items.parseAll('html5', view) %} + {% block item %} + {% set html5vals = item.html5|default({}) %} + {% set textvals = item.text|default({}) %} +
+ {% for field, attr in items.getItem().getMetaModel().getAttributes() %} + {% set value = html5vals[field] is defined ? html5vals[field] : (textvals[field] is defined ? textvals[field] : null) %} + {% if value is not null %} +
+ {% if not view.get('hideLabels') %} +
{{ 'field_label'|trans({'%field_label%': attr.getName()}, 'metamodels_list') }}
+ {% endif %} +
{{ value|raw }}
+
+ {% endif %} + {% endfor %} + {% block actions %} +
+ {% for action in item.actions %} + {{ include('@Contao/mm_actionbutton.html.twig', {action: action}) }} + {% endfor %} +
+ {% endblock %} +
+ {% endblock %} + {% endfor %} +
+{% else %} + {% block noItem %} +

{{ noItemsMsg|default('')|raw }}

+ {% endblock %} +{% endif %} diff --git a/src/CoreBundle/Resources/views/Backend/add-all.html.twig b/src/CoreBundle/Resources/views/Backend/add-all.html.twig index 90d58ab58..8aeda91de 100644 --- a/src/CoreBundle/Resources/views/Backend/add-all.html.twig +++ b/src/CoreBundle/Resources/views/Backend/add-all.html.twig @@ -15,13 +15,13 @@ {{ backBt }}
-
+