WIP Migrate product detail page

This commit is contained in:
Björn Fromme
2021-07-27 14:06:12 +02:00
committed by Björn Fromme
parent e10d60b893
commit 5a63f88153
37 changed files with 1410 additions and 470 deletions
+51 -35
View File
@@ -395,9 +395,9 @@
}
},
"@babel/plugin-proposal-async-generator-functions": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.5.tgz",
"integrity": "sha512-tbD/CG3l43FIXxmu4a7RBe4zH7MLJ+S/lFowPFO7HetS2hyOZ/0nnnznegDuzFzfkyQYTxqdTH/hKmuBngaDAA==",
"version": "7.14.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz",
"integrity": "sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.14.5",
@@ -487,16 +487,24 @@
}
},
"@babel/plugin-proposal-object-rest-spread": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.5.tgz",
"integrity": "sha512-VzMyY6PWNPPT3pxc5hi9LloKNr4SSrVCg7Yr6aZpW4Ym07r7KqSU/QXYwjXLVxqwSv0t/XSXkFoKBPUkZ8vb2A==",
"version": "7.14.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz",
"integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==",
"dev": true,
"requires": {
"@babel/compat-data": "^7.14.5",
"@babel/compat-data": "^7.14.7",
"@babel/helper-compilation-targets": "^7.14.5",
"@babel/helper-plugin-utils": "^7.14.5",
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
"@babel/plugin-transform-parameters": "^7.14.5"
},
"dependencies": {
"@babel/compat-data": {
"version": "7.14.7",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
"integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==",
"dev": true
}
}
},
"@babel/plugin-proposal-optional-catch-binding": {
@@ -741,9 +749,9 @@
}
},
"@babel/plugin-transform-destructuring": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.5.tgz",
"integrity": "sha512-wU9tYisEbRMxqDezKUqC9GleLycCRoUsai9ddlsq54r8QRLaeEhc+d+9DqCG+kV9W2GgQjTZESPTpn5bAFMDww==",
"version": "7.14.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz",
"integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.14.5"
@@ -862,9 +870,9 @@
}
},
"@babel/plugin-transform-named-capturing-groups-regex": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.5.tgz",
"integrity": "sha512-+Xe5+6MWFo311U8SchgeX5c1+lJM+eZDBZgD+tvXu9VVQPXwwVzeManMMjYX6xw2HczngfOSZjoFYKwdeB/Jvw==",
"version": "7.14.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz",
"integrity": "sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==",
"dev": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.14.5"
@@ -991,17 +999,17 @@
}
},
"@babel/preset-env": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.5.tgz",
"integrity": "sha512-ci6TsS0bjrdPpWGnQ+m4f+JSSzDKlckqKIJJt9UZ/+g7Zz9k0N8lYU8IeLg/01o2h8LyNZDMLGgRLDTxpudLsA==",
"version": "7.14.7",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.7.tgz",
"integrity": "sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA==",
"dev": true,
"requires": {
"@babel/compat-data": "^7.14.5",
"@babel/compat-data": "^7.14.7",
"@babel/helper-compilation-targets": "^7.14.5",
"@babel/helper-plugin-utils": "^7.14.5",
"@babel/helper-validator-option": "^7.14.5",
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5",
"@babel/plugin-proposal-async-generator-functions": "^7.14.5",
"@babel/plugin-proposal-async-generator-functions": "^7.14.7",
"@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/plugin-proposal-class-static-block": "^7.14.5",
"@babel/plugin-proposal-dynamic-import": "^7.14.5",
@@ -1010,7 +1018,7 @@
"@babel/plugin-proposal-logical-assignment-operators": "^7.14.5",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
"@babel/plugin-proposal-numeric-separator": "^7.14.5",
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
"@babel/plugin-proposal-object-rest-spread": "^7.14.7",
"@babel/plugin-proposal-optional-catch-binding": "^7.14.5",
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
"@babel/plugin-proposal-private-methods": "^7.14.5",
@@ -1036,7 +1044,7 @@
"@babel/plugin-transform-block-scoping": "^7.14.5",
"@babel/plugin-transform-classes": "^7.14.5",
"@babel/plugin-transform-computed-properties": "^7.14.5",
"@babel/plugin-transform-destructuring": "^7.14.5",
"@babel/plugin-transform-destructuring": "^7.14.7",
"@babel/plugin-transform-dotall-regex": "^7.14.5",
"@babel/plugin-transform-duplicate-keys": "^7.14.5",
"@babel/plugin-transform-exponentiation-operator": "^7.14.5",
@@ -1048,7 +1056,7 @@
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
"@babel/plugin-transform-modules-systemjs": "^7.14.5",
"@babel/plugin-transform-modules-umd": "^7.14.5",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.5",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.7",
"@babel/plugin-transform-new-target": "^7.14.5",
"@babel/plugin-transform-object-super": "^7.14.5",
"@babel/plugin-transform-parameters": "^7.14.5",
@@ -1056,7 +1064,7 @@
"@babel/plugin-transform-regenerator": "^7.14.5",
"@babel/plugin-transform-reserved-words": "^7.14.5",
"@babel/plugin-transform-shorthand-properties": "^7.14.5",
"@babel/plugin-transform-spread": "^7.14.5",
"@babel/plugin-transform-spread": "^7.14.6",
"@babel/plugin-transform-sticky-regex": "^7.14.5",
"@babel/plugin-transform-template-literals": "^7.14.5",
"@babel/plugin-transform-typeof-symbol": "^7.14.5",
@@ -1067,8 +1075,16 @@
"babel-plugin-polyfill-corejs2": "^0.2.2",
"babel-plugin-polyfill-corejs3": "^0.2.2",
"babel-plugin-polyfill-regenerator": "^0.2.2",
"core-js-compat": "^3.14.0",
"core-js-compat": "^3.15.0",
"semver": "^6.3.0"
},
"dependencies": {
"@babel/compat-data": {
"version": "7.14.7",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
"integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==",
"dev": true
}
}
},
"@babel/preset-modules": {
@@ -1797,9 +1813,9 @@
"dev": true
},
"alpinejs": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.1.1.tgz",
"integrity": "sha512-svEX82laPua+oqbYlUgX1H7Q+R0GD0V7fOnjZocPBqABmpQGkofPtPV9dGFkgZy7G6q60KFSzkiSwKMw33EFYw==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.2.1.tgz",
"integrity": "sha512-MYYGUmVHNWN27TvgAtUCYXZlfsXoVCrLQT3a0Ak6CQKqf1TCHfQKxmhzJWscW5kPcLlOK2aYmWbV2H+XyfN2FQ==",
"requires": {
"@vue/reactivity": "^3.0.2"
}
@@ -2707,15 +2723,15 @@
"integrity": "sha512-v8JWLJcI7Zs9NWrs8hiVldVtm3EBF70TJI231vxn6YToBGj0c9dvdnYwltydkAnrbBMOM/qX1xLFrnTfm5wTag=="
},
"core-js": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.15.0.tgz",
"integrity": "sha512-GUbtPllXMYRzIgHNZ4dTYTcUemls2cni83Q4Q/TrFONHfhcg9oEGOtaGHfb0cpzec60P96UKPvMkjX1jET8rUw==",
"version": "3.15.2",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.15.2.tgz",
"integrity": "sha512-tKs41J7NJVuaya8DxIOCnl8QuPHx5/ZVbFo1oKgVl1qHFBBrDctzQGtuLjPpRdNTWmKPH6oEvgN/MUID+l485Q==",
"dev": true
},
"core-js-compat": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.0.tgz",
"integrity": "sha512-8X6lWsG+s7IfOKzV93a7fRYfWRZobOfjw5V5rrq43Vh/W+V6qYxl7Akalsvgab4PFT/4L/pjQbdBUEM36NXKrw==",
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.1.tgz",
"integrity": "sha512-xGhzYMX6y7oEGQGAJmP2TmtBLvR4nZmRGEcFa3ubHOq5YEp51gGN9AovVa0AoujGZIq+Wm6dISiYyGNfdflYww==",
"dev": true,
"requires": {
"browserslist": "^4.16.6",
@@ -7922,9 +7938,9 @@
}
},
"vue-router": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.1.tgz",
"integrity": "sha512-RRQNLT8Mzr8z7eL4p7BtKvRaTSGdCbTy2+Mm5HTJvLGYSSeG9gDzNasJPP/yOYKLy+/cLG/ftrqq5fvkFwBJEw=="
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.2.tgz",
"integrity": "sha512-807gn82hTnjCYGrnF3eNmIw/dk7/GE4B5h69BlyCK9KHASwSloD1Sjcn06zg9fVG4fYH2DrsNBZkpLtb25WtaQ=="
},
"vue-scrollto": {
"version": "2.20.0",
+5 -5
View File
@@ -10,7 +10,7 @@
},
"dependencies": {
"@splidejs/splide": "^2.4.21",
"alpinejs": "^3.1.1",
"alpinejs": "^3.2.1",
"axios": "^0.21.1",
"axios-auth-refresh": "^1.0.7",
"bootstrap-sass": "^3.4.1",
@@ -29,19 +29,19 @@
"slick-carousel": "^1.8.1",
"sticky-js": "^1.3.0",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vue-router": "^3.5.2",
"vue-scrollto": "^2.20.0",
"vue-session": "^1.0.0",
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
"@babel/plugin-proposal-object-rest-spread": "^7.14.7",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.14.5",
"@babel/preset-env": "^7.14.7",
"@symfony/webpack-encore": "^1.5.0",
"@tailwindcss/custom-forms": "^0.2.1",
"autoprefixer": "^9.4.6",
"core-js": "^3.15.0",
"core-js": "^3.15.2",
"file-loader": "^6.2.0",
"node-sass": "^4.14.1",
"postcss": "^8.3.5",
@@ -115,15 +115,6 @@ class AjaxDateController extends ActionController
*/
public function datesAction(Product $product, Hotel $hotel = null, $paCode = null, $dateFrom = null, $dateTo = null)
{
if ($hotel === null) {
return json_encode([
'dates' => [],
'bookable' => false,
'altProductLink' => null,
'altLabel' => null,
]);
}
$forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true);
$filterSettings = $this->filterService->getDefaultFilterSettings(
$forcedConceptUids,
@@ -157,12 +148,17 @@ class AjaxDateController extends ActionController
'template' => $this->settings['bpnBookingUrlTemplateCode'],
'paCode' => $paCode,
]);
$hasSurchargeOrDiscount = $this->dateService->checkSurcharcheOrDiscount($datesTable);
return json_encode([
'dates' => $datesTable,
'bookable' => $product->getBookable(),
'hotelName' => $hotel->getName(),
'altProductLink' => $altProductLink,
'altLabel' => $altLabel,
]);
'hasSurcharge' => $hasSurchargeOrDiscount['surcharge'],
'hasDiscount' => $hasSurchargeOrDiscount['discount'],
], JSON_THROW_ON_ERROR);
}
}
@@ -111,12 +111,16 @@ class AjaxTableController extends ActionController
'template' => $this->settings['bpnBookingUrlTemplateCode'],
'paCode' => $paCode,
]);
$dateStart = $date ? $date->getDateStart()->format('d.m.Y') : '';
$dateEnd = $date ? $date->getDateEnd()->format('d.m.Y') : '';
$dateRange = sprintf('%s - %s', $dateStart, $dateEnd);
return json_encode([
'dateStart' => $date ? $date->getDateStart()->format('Y-m-d') : '',
'dateEnd' => $date ? $date->getDateEnd()->format('Y-m-d') : '',
'servicesIncluded' => $date ? $date->getServicesIncluded() : '',
'priceTable' => $priceTable,
]);
'dateRange' => $dateRange,
'servicesIncluded' => $date ? $date->getServicesIncluded() : [],
'prices' => $priceTable,
], JSON_THROW_ON_ERROR);
}
/**
@@ -159,6 +159,26 @@ class ProductController extends ActionController
$backlinkUrl = GeneralUtility::_GET('ref');
$backLinkLabel = strpos($backlinkUrl, 'suche') !== -1 ? 'zurück zum Suchergebnis' : 'zurück';
// Generate dates uri
$datesArguments = [
'dateFrom' => $dateFrom,
'dateTo' => $dateTo,
'product' => $product,
'hotel' => $hotel
];
$datesUri = $this->uriBuilder
->reset()
->setCreateAbsoluteUri(true)
->setTargetPageType(1702)
->setTargetPageUid(855)
->uriFor(
'dates',
$datesArguments,
'AjaxDate',
'EpProducts',
'ajax'
);
$this->view->assignMultiple([
'hotel' => $hotel,
'product' => $product,
@@ -168,7 +188,8 @@ class ProductController extends ActionController
'dateFrom' => $dateFrom,
'dateTo' => $dateTo,
'referringUrl' => $backlinkUrl,
'backlinkLabel' => $backLinkLabel
'backlinkLabel' => $backLinkLabel,
'datesUri' => $datesUri,
]);
}
@@ -158,7 +158,7 @@ class DateService implements SingletonInterface
$filterSettings
);
return $this->preprocessDateTable([
return $this->preprocessDatesTable([
'dateTableData' => $dateTableData,
'template' => $template,
'paCode' => $paCode,
@@ -322,6 +322,7 @@ class DateService implements SingletonInterface
'roomBusProId' => $row['roomBusProId'],
'bookingUrl' => $bookingUrl,
'isHideBookingButton' => $isHideBookingButton,
'showBookingButton' => !$isHideBookingButton,
];
}
@@ -332,7 +333,7 @@ class DateService implements SingletonInterface
* @param array $options
* @return array
*/
public function preprocessDateTable(array $options)
public function preprocessDatesTable(array $options)
{
$resolver = new OptionsResolver();
$resolver->setDefined(['paCode', 'isDayTrip', 'isHideBookingButton', 'nonBookableDateUids']);
@@ -370,8 +371,8 @@ class DateService implements SingletonInterface
'dateEnd' => $dateEnd->format('d.m.y'),
'dateMinPrice' => $row['dateMinPrice'],
'datePseudoPrice' => $row['datePseudoPrice'],
'dateBusPrice' => $row['dateBusPrice'],
'dateDiscount' => $row['dateDiscount'],
'dateBusPrice' => $row['dateBusPrice'] ?? 0,
'dateDiscount' => $row['dateDiscount'] ?? 0,
'dateNights' => $row['dateNights'],
'dateBusIncluded' => (bool) $row['dateBusIncluded'],
'dateSkipassIncluded' => (bool) $row['dateSkipassIncluded'],
@@ -379,8 +380,10 @@ class DateService implements SingletonInterface
'dateServicesGeneral' => unserialize($row['dateServicesGeneral'], ['allowed_classes' => false]),
'season' => $row['season'],
'available' => $row['available'],
'unavailable' => $row['available'] === 0,
'bookingUrl' => $bookingUrl,
'isHideBookingButton' => $isHideBookingButton,
'showBookingButton' => !$isHideBookingButton,
];
}
@@ -486,4 +489,22 @@ class DateService implements SingletonInterface
return $priceTable;
}
public function checkSurcharcheOrDiscount(array $datesTableData)
{
$data = [
'surcharge' => false,
'discount' => false,
];
foreach ($datesTableData as $row) {
if ($row['dateBusPrice'] && $row['dateBusPrice'] > 0) {
$data['surcharge'] = true;
}
if ($row['dateDiscount'] && $row['dateDiscount'] < 0) {
$data['discount'] = true;
}
}
return $data;
}
}
@@ -119,7 +119,7 @@ lib.stdheader.3.headerClass >
@import "EXT:ep_theme/Configuration/TypoScript/Page/Export.typoscript"
config {
compressJs = 1
compressJs = 0
compressCss = 1
typolinkCheckRootline = 1
typolinkEnableLinksAcrossDomains = 1
@@ -22,11 +22,13 @@ import collapse from './components/collapse'
import fbpixel from './components/fbpixel'
import ajaxContent from './components/ajax-content'
import faq from './components/faq'
import osmMap from './components/osm-map'
import productDetail from './components/product-detail'
// Executed on document ready
document.addEventListener('DOMContentLoaded', () => {
const appConfig = parseAppConfig()
const storedWatchlist = JSON.parse(sessionStorage.getItem('myep-watchlist'))
const storedWatchlist = JSON.parse(sessionStorage.getItem('myep-watchlist')) || []
appendPaCode(appConfig)
initSliders()
Alpine.store('appconfig', appConfig)
@@ -34,7 +36,7 @@ document.addEventListener('DOMContentLoaded', () => {
searchBox: false,
mobileNav: false,
})
Alpine.store('watchlist', storedWatchlist ? storedWatchlist : [])
Alpine.store('watchlist', storedWatchlist)
Alpine.data('scrollTop', scrollTop)
Alpine.data('sticky', sticky)
Alpine.data('watchlistToggle', watchlistToggle)
@@ -43,6 +45,8 @@ document.addEventListener('DOMContentLoaded', () => {
Alpine.data('fbpixel', fbpixel)
Alpine.data('ajaxContent', ajaxContent)
Alpine.data('faq', faq)
Alpine.data('osmMap', osmMap)
Alpine.data('productDetail', productDetail)
Alpine.start()
Glightbox({
@@ -62,7 +66,6 @@ import 'dayjs/locale/de'
global.$ = global.jQuery = $;
require('bootstrap-sass/assets/javascripts/bootstrap/alert')
require('bootstrap-sass/assets/javascripts/bootstrap/dropdown')
require('bootstrap-sass/assets/javascripts/bootstrap/modal')
require('bootstrap-sass/assets/javascripts/bootstrap/transition')
@@ -70,7 +73,7 @@ require('bootstrap-sass/assets/javascripts/bootstrap/transition')
// Import components
import SearchBar from './components/SearchBar.vue'
import SearchBox from './components/SearchBox.vue'
import ProductDetail from './components/ProductDetail.vue'
//import ProductDetail from './components/ProductDetail.vue'
import Calendar from './components/Calendar.vue'
import EventPricetable from './components/EventPriceTable.vue'
import ContactForm from './components/ContactForm.vue'
@@ -83,33 +86,32 @@ Vue.filter('date', (value) => {
});
// Store
import store from './store';
// import store from './store';
//Initialize vue app
new Vue({
el: '#app',
store,
components: {
SearchBar,
SearchBox,
SearchResult: () => import('./components/SearchResult.vue'),
ProductDetail,
OsmMap: () => import('./components/OsmMap.vue'),
Calendar,
EventPricetable,
ContactForm,
Watchlist,
HotelList,
MyEp: () => import('./myep/App.vue'),
GroupsPriceCalculator: () => import('./components/GroupsPriceCalculator.vue'),
},
data () {
return {
maxWindowWidth: 991,
mobileMode: false,
}
},
created () {
this.$store.dispatch('init');
},
});
// Initialize vue app
// new Vue({
// el: '#app',
// store,
// components: {
// SearchBar,
// //SearchBox,
// //SearchResult: () => import('./components/SearchResult.vue'),
// //ProductDetail,
// //Calendar,
// //EventPricetable,
// //ContactForm,
// //Watchlist,
// //HotelList,
// //MyEp: () => import('./myep/App.vue'),
// //GroupsPriceCalculator: () => import('./components/GroupsPriceCalculator.vue'),
// },
// data () {
// return {
// maxWindowWidth: 991,
// mobileMode: false,
// }
// },
// created () {
// this.$store.dispatch('init');
// },
// });
@@ -16,7 +16,7 @@
</div>
</div>
<div ref="table">
<div class="ajax-content-wrapper" x-data="ajaxContent" :data-uri="uri">
<div class="ajax-content-wrapper" x-data="ajaxContent(uri)">
<div class="ajax-content" x-ref="container"></div>
<div x-ref="trigger">
<img :src="loaderUri" alt="Loading" title="Loading">
@@ -1,90 +0,0 @@
<template>
<div class="osm-map" ref="container"></div>
</template>
<script>
import L from 'leaflet';
export default {
props: {
lat: {
type: String,
default: null
},
lng: {
type: String,
default: null
},
zoom: {
type: Number,
default: 17
},
markers: {
type: Array,
default: null
},
externalLink: {
type: String,
default: null
}
},
data () {
return {
map: null
}
},
methods: {
initMap () {
this.map = L.map(this.$refs.container, {
scrollWheelZoom: false
});
this.map.setZoom(this.zoom);
if (this.lat && this.lng) {
const position = L.latLng(this.lat, this.lng);
const marker = L.marker(position);
if (this.externalLink) {
marker.on('click', () => {
window.open(this.externalLink, '_blank');
});
} else {
marker.on('click', () => {
window.open('https://www.google.com/maps/search/?api=1&zoom=15&query=' + this.lat + ',' + this.lng, '_blank');
});
}
marker.addTo(this.map);
this.map.setView(position);
} else if (this.markers.length) {
const bounds = L.latLngBounds();
for (let item of this.markers) {
const position = L.latLng(item.lat, item.lng);
const marker = L.marker(position);
if (item.externalLink) {
marker.on('click', () => {
window.open(item.externalLink, '_blank');
});
} else {
const popupContent = '<div><strong>' + item.name + '</strong><br>' + item.teaser +
'<br><a href="' + item.uri + '">zu den Details</a></div>';
marker.bindPopup(popupContent);
}
marker.addTo(this.map);
bounds.extend(position);
}
this.map.fitBounds(bounds);
}
L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(this.map);
}
},
mounted () {
this.initMap()
}
}
</script>
<style>
.leaflet-top, .leaflet-bottom {
z-index: 490 !important;
}
</style>
@@ -61,7 +61,7 @@
</a>
</div>
</div>
<a href="#" x-data="watchlistToggle" x-bind="trigger" :data-uid="item.key">
<a href="#" x-data="watchlistToggle(item.key))" x-bind="trigger">
<span data-microtip-position="top" x-bind:aria-label="label" role="tooltip">
<i class="fa fa-plus-circle" x-bind:class="icon"></i>
</span>
@@ -1,18 +1,20 @@
import axios from 'axios'
import { debounce } from './throttle-debounce'
export default () => ({
uri: '',
export default uri => ({
uri,
loaded: false,
loading: false,
init() {
this.uri = this.$el.dataset.uri
window.addEventListener('scroll', debounce(() => {
this.load()
}, 250))
},
load() {
if (true === this.loaded || false === this.inViewport()) {
if (true === this.loaded) {
return
}
if (false === this.inViewport()) {
return
}
this.loading = true
@@ -1,5 +1,5 @@
export default () => {
const configElement = document.getElementById('appconfig');
const configElement = document.getElementById('appconfig')
if (null === configElement) {
return {}
}
@@ -1,25 +1,21 @@
import { debounce } from './throttle-debounce'
export default () => ({
collapsed: false,
export default (isCollapsed = true, until = null, from = null) => ({
collapsed: isCollapsed,
collapsedUntil: until,
collapsedFrom: from,
init() {
const initialState = this.$el.dataset.collapsed
if (initialState !== undefined) {
this.collapsed = true
}
this.checkBreakpoints()
window.addEventListener('resize', debounce(() => {
this.checkBreakpoints()
}, 250))
},
checkBreakpoints() {
const until = this.$el.dataset.collapseUntil
if (until !== undefined) {
this.collapsed = window.innerWidth < parseInt(until)
if (null !== this.collapsedUntil) {
this.collapsed = window.innerWidth < parseInt(this.collapsedUntil)
}
const from = this.$el.dataset.collapseFrom
if (from !== undefined) {
this.collapsed = window.innerWidth > parseInt(from)
if (null !== this.collapsedFrom) {
this.collapsed = window.innerWidth > parseInt(this.collapsedFrom)
}
},
trigger: {
@@ -1,6 +1,5 @@
export default () => ({
export default props => ({
init() {
const props = JSON.parse(this.$el.dataset.fbpixelProps)
fbq('track', 'ViewContent', props)
}
})
@@ -0,0 +1,52 @@
import L from 'leaflet';
export default () => ({
init() {
this.lat = this.$el.dataset.lat
this.lng = this.$el.dataset.lng
this.zoom = this.$el.dataset.zoom || 12
this.externalLink = this.$el.dataset.link
this.markers = this.$el.dataset.markers ? JSON.parse(this.$el.dataset.markers) : []
this.map = L.map(this.$el, {
scrollWheelZoom: false
});
this.map.setZoom(this.zoom);
if (this.lat && this.lng) {
const position = L.latLng(this.lat, this.lng);
const marker = L.marker(position);
if (this.externalLink) {
marker.on('click', () => {
window.open(this.externalLink, '_blank')
});
} else {
marker.on('click', () => {
window.open('https://www.google.com/maps/search/?api=1&zoom=15&query=' + this.lat + ',' + this.lng, '_blank')
});
}
marker.addTo(this.map);
this.map.setView(position);
} else if (this.markers.length) {
const bounds = L.latLngBounds();
for (let item of this.markers) {
const position = L.latLng(item.lat, item.lng);
const marker = L.marker(position);
if (item.externalLink) {
marker.on('click', () => {
window.open(item.externalLink, '_blank');
});
} else {
const popupContent = '<div><strong>' + item.name + '</strong><br>' + item.teaser +
'<br><a href="' + item.uri + '">zu den Details</a></div>';
marker.bindPopup(popupContent);
}
marker.addTo(this.map);
bounds.extend(position);
}
this.map.fitBounds(bounds);
}
L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(this.map);
}
})
@@ -0,0 +1,85 @@
import axios from 'axios'
export default uris => ({
uris,
show: 'dates',
tableMode: 'dates',
datesRows: [],
pricesRows: [],
servicesIncluded: [],
dateRange: '',
available: false,
singleDate: false,
bookable: true,
hasSurcharge: false,
hasDiscount: false,
altLabel: null,
altProductLink: null,
loading: false,
addBus: false,
discountBus: false,
showAll: false,
init() {
this.loadDates()
},
loadDates() {
this.loading = true
axios({
url: this.uris.dates,
}).then(response => {
const json = response.data
if (json.dates.length === 1) {
this.singleDate = true
const dateUid = json.dates[0].dateUid
this.loadPrices(dateUid)
} else {
this.singleDate = false
this.datesRows = json.dates
this.bookable = json.bookable
this.altLabel = json.altLabel
this.altProductLink = json.altProductLink
this.hasSurcharge = json.hasSurcharge
this.hasDiscount = json.hasDiscount
this.available = json.dates.length > 0
this.tableMode = 'dates'
}
}).catch(() => {
}).finally(() => {
this.loading = false
})
},
loadPrices(dateUid) {
this.loading = true
const data = new FormData()
data.set('tx_epproducts_ajax[date]', dateUid)
data.set('tx_epproducts_ajax[paCode]', this.$store.appconfig.paCode)
axios({
url: this.uris.pricetable,
method: 'POST',
data
}).then(response => {
const json = response.data
this.pricesRows = json.prices
this.servicesIncluded = json.servicesIncluded
this.dateRange = json.dateRange
this.tableMode = 'prices'
}).catch(() => {
}).finally(() => {
this.loading = false
})
},
calculatePrice(minPrice, busPrice, discount) {
if (this.addBus) {
return minPrice + busPrice
} else if (this.discountBus) {
return minPrice + discount
}
return minPrice
},
showBusIcon(busPrice, busIncluded) {
return (
busPrice && this.addBus ||
busIncluded && !this.discountBus
)
},
})
@@ -1,12 +1,9 @@
import { debounce } from './throttle-debounce'
export default () => ({
export default offset => ({
offset,
sticky: false,
offset: 0,
init() {
if (this.$el.dataset.offset) {
this.offset = this.$el.dataset.offset
}
window.addEventListener('scroll', debounce(() => {
this.sticky = window.scrollY > this.offset
}, 250))
@@ -1,5 +1,5 @@
export default () => ({
uid: null,
export default uid => ({
uid,
trigger: {
['@click.prevent']() {
const watchlistIndex = this.$store.watchlist.indexOf(this.uid)
@@ -11,9 +11,6 @@ export default () => ({
sessionStorage.setItem('myep-watchlist', JSON.stringify(this.$store.watchlist))
}
},
init() {
this.uid = this.$el.dataset.uid
},
onList() {
return -1 !== this.$store.watchlist.indexOf(this.uid)
},
@@ -12,7 +12,7 @@
</f:if>
<div class="panel-group">
<f:for each="{faqs}" as="faq" iteration="iteration">
<div class="panel panel-default" x-data="collapse" data-collapsed>
<div class="panel panel-default" x-data="collapse">
<a class="headline headline--4" role="button" href="#" x-bind="trigger">
{faq.question}
</a>
@@ -117,7 +117,7 @@
</f:else>
</f:if>
</div>
<a href="#" class="teaserbox-watchlist" x-data="watchlistToggle" x-bind="trigger" :data-uid="item.key">
<a href="#" class="teaserbox-watchlist" x-data="watchlistToggle(item.key)" x-bind="trigger">
<span data-microtip-position="top" x-bind:aria-label="label" role="tooltip">
<i class="fa fa-plus-circle" x-bind:class="icon"></i>
</span>
@@ -115,7 +115,7 @@
</a>
</div>
</div>
<a href="#" x-data="watchlistToggle" x-bind="trigger" data-uid="{item.key}">
<a href="#" x-data="watchlistToggle({item.key})" x-bind="trigger">
<span data-microtip-position="top" x-bind="label" role="tooltip">
<i class="fa fa-plus-circle" x-bind="icon"></i>
</span>
@@ -92,7 +92,7 @@
</a>
</div>
</div>
<a href="#" class="teaserbox-watchlist" x-data="watchlistToggle" x-bind="trigger" :data-uid="item.key">
<a href="#" class="teaserbox-watchlist" x-data="watchlistToggle('{hotel.uid}:{product.uid}')" x-bind="trigger">
<span data-microtip-position="top" x-bind:aria-label="label" role="tooltip">
<i class="fa fa-plus-circle" x-bind:class="icon"></i>
</span>
@@ -9,7 +9,7 @@
Bereich wechseln <i class="area-nav__trigger-icon fa fa-lg fa-caret-down"></i>
</a>
<nav role="navigation">
<ul class="area-nav__list" x-bind:class="open ? 'open' : ''" x-show="open" x-transition x-cloak>
<ul class="area-nav__list" x-bind:class="open && 'open'" x-show="open" x-transition x-cloak>
<v:menu levels="1" useShortcutUid="1" pageUid="{settings.topNavPid}">
<f:for each="{menu}" as="menuitem">
<li class="area-nav__list-item">
@@ -0,0 +1,173 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers"
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers">
<f:layout name="Default"/>
<f:section name="Main">
<f:variable name="rowCount" value="{rows -> f:count()}"/>
<f:if condition="{rowCount} > 0">
<div class="dates-table-wrapper" x-data="datesTable">
<f:if condition="{showHeader}">
<f:if condition="{bookable}">
<f:then>
<div class="ep-headbar">Buchungsoptionen{f:if(condition: hotelName, then: ' {hotelName}')}</div>
</f:then>
<f:else>
<div class="ep-headbar">Termine &amp; Leistungen</div>
</f:else>
</f:if>
</f:if>
<f:if condition="{hasSourcharge} || {hasDiscount}">
<div class="dates-table__pricetoggle">
<f:if condition="{hasSurcharge}">
<a href="#" x-on:click.prevent="addBus = !addBus" x-show="addBus">
<i class="fa fa-arrow-circle-right"></i> Preise für Eigenanreise anzeigen
</a>
<a href="#" x-on:click.prevent="addBus = !addBus" x-show="! addBus">
<i class="fa fa-arrow-circle-right"></i> Preise für Busanreise anzeigen
</a>
</f:if>
<f:if condition="{hasDiscount}">
<a href="#" x-on:click.prevent="discountBus = !discountBus" x-show="discountBus">
<i class="fa fa-arrow-circle-right"></i> Preise für Busanreise anzeigen
</a>
<a href="#" x-on:click.prevent="discountBus = !discountBus" x-show="! discountBus">
<i class="fa fa-arrow-circle-right"></i> Preise für Eigenanreise anzeigen
</a>
</f:if>
</div>
</f:if>
<div class="table-responsive">
<table class="table table-striped dates-table">
<thead>
<tr>
<th>Termin</th>
<th>
<span data-microtip-position="bottom" aria-label="Nächte" role="tooltip">
<i class="fa fa-bed"></i>
</span>
</th>
<th>Preis ab</th>
<th>inkl.</th>
<th class="hidden-xs"></th>
</tr>
</thead>
<tbody>
<f:for each="{rows}" as="row" iteration="iteration">
<tr{f:if(condition: '{iteration.index} > 4', then: ' x-bind:class="{ \'hidden\': !showAll }"')}>
<td class="dates-table__cell dates-table__cell--date">
<f:if condition="{bookable} && {row.available} && {row.showBookingButton}">
<f:then>
<button class="dates-table__date"
x-on:click.prevent="loadPrices({row.dateUid})">
{row.dateStart} - {row.dateEnd}
</button>
<div class="hidden-md hidden-lg dates-table__links">
<button x-on:click.prevent="loadPrices({row.dateUid})" class="button button--small">
Details
</button>
<a href="{row.bookingUrl}" target="_blank" class="button button--small button--action">
Buchen
</a>
</div>
</f:then>
<f:else>
{row.dateStart} - {row.dateEnd}
</f:else>
</f:if>
</td>
<td class="dates-table__cell dates-table__cell--nights">
{row.dateNights}
</td>
<td class="dates-table__cell dates-table__cell--price">
<f:if condition="{row.datePseudoPrice}">
<span class="dates-table__pseudo-price">
{row.datePseudoPrice} €
</span>
</f:if>
<strong x-text="calculatePrice({row.dateMinPrice}, {row.dateBusPrice}, {row.dateDiscount}) + '€'"></strong>
</td>
<td class="dates-table__cell dates-table__cell--icons">
<div class="icon-wrapper hidden-xs hidden-sm">
<span x-show="showBusIcon({row.dateBusPrice}, {row.dateBusIncluded})" data-microtip-position="top" aria-label="Busfahrt inklusive" role="tooltip">
<i class="fa fa-bus"></i>
</span>
<span x-show="{row.dateSkipassIncluded}" data-microtip-position="top" aria-label="{f:if(condition: '{row.season} =="s"', then: 'Bergbahnticket inklusive', else: 'Skipass inklusive')}" role="tooltip">
<i class="fa fa-tag"></i>
</div>
</div>
<button type="button" class="button button--light button--small hidden-xs"
data-toggle="modal"
data-microtip-position="top" aria-label="Alle Inklusivleistungen anzeigen" role="tooltip">Leistungen</button>
<a href="#" data-toggle="modal"
class="hidden-sm hidden-md hidden-lg"><i class="fa fa-info-circle"></i></a>
</td>
<td class="dates-table__cell dates-table__cell--buttons hidden-xs">
<f:if condition="{row.available} || {row.isHideBookingButton}">
<button class="button button--small" x-on:click="loadPrices({row.dateUid})">
Details
</button>
</f:if>
<f:if condition="{row.available} && {row.showBookingButton}">
<f:link.typolink parameter="{row.bookingUrl}" target="_blank" class="button button--small button--action">
Buchen
</f:link.typolink>
</f:if>
<f:if condition="{row.isHideBookingButton}">
<f:link.typolink parameter="{travelAlertUrl}" class="button button--small button--mute">
Reisen-Alert
</f:link.typolink>
</f:if>
<f:if condition="{row.unavailable} && {row.showBookingButton}">
<span class="label label-default">ausgebucht</span>
</f:if>
</td>
</tr>
</f:for>
</tbody>
</table>
</div>
<f:if condition="{rowCount} > 5 || {altProductLink}">
<div class="row dates-table__links">
<div class="col-xs-12 col-md-6">
<f:if condition="{rows -> f:count()} > 5">
<a href="#" x-on:click.prevent="showAll = !showAll">
<i class="fa" x-bind:class="[{ 'fa-minus-circle': showAll }, { 'fa-plus-circle': !showAll }]"></i>
<template v-show="showAll">Weniger Termine anzeigen</template>
<template v-show="!showAll">Alle Termine anzeigen</template>
</a>
</f:if>
</div>
<f:if condition="{altProductLink}">
<div class="col-xs-12 col-md-6">
<f:link.typolink parameter="{altProductLink}" class="dates-table__altlink">
<i class="fa fa-arrow-circle-right"></i> {altLabel}
</f:link.typolink>
</div>
</f:if>
</div>
</f:if>
<!-- ToDo: Implement modals -->
<template v-for="(row, index) of datesRows">
<div class="modal fade" :id="'dateservices' + index" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
<h5 class="modal-title">Inklusivleistungen</h5>
</div>
<div class="modal-body">
<div class="table-responsive">
<services-included :services="row.dateServicesIncluded" class="services"></services-included>
</div>
</div>
</div>
</div>
</div>
</template>
</div>
</f:if>
</f:section>
</html>
@@ -0,0 +1,146 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers"
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers">
<f:layout name="Default"/>
<f:section name="Main">
<div class="price-table-wrapper" x-data="datesTable">
<div class="row ep-headbar">
<div class="col-xs-6">Buchungsoptionen</div>
<div class="col-xs-6 text-right">{dateStart} - {dateEnd}</div>
</div>
<f:if condition="{hasSurcharge} || {hasDiscount}">
<div class="dates-table__pricetoggle">
<f:if condition="{hasSurcharge}">
<a href="#" x-on:click.prevent="addBus = !addBus" x-show="addBus">
<i class="fa fa-car"></i> Preise für Eigenanreise anzeigen
</a>
<a href="#" x-on:click.prevent="addBus = !addBus" x-show="! addBus">
<i class="fa fa-bus"></i> Preise für Busanreise anzeigen
</a>
</f:if>
<f:if condition="{hasDiscount}">
<a href="#" @click.prevent="discountBus = !discountBus" x-show="discountBus">
<i class="fa fa-bus"></i> Preise für Busanreise anzeigen
</a>
<a href="#" @click.prevent="discountBus = !discountBus" x-show="! discountBus">
<i class="fa fa-car"></i> Preise für Eigenanreise anzeigen
</a>
</f:if>
</div>
</f:if>
<div class="table-responsive">
<table class="table table-striped pricetable">
<thead>
<tr>
<th>Zimmertyp</th>
<th>Preis</th>
<th>inkl.</th>
<th></th>
<th class="hidden-xs hidden-md"></th>
</tr>
</thead>
<tbody>
<f:for each="{rows}" as="row" iteration="iteration">
<tr>
<td style="white-space: normal">
<f:if condition="{row.showBookingButton} && {row.roomAvailable}">
<f:then>
<a class="pricetable__room-label" href="{row.bookingUrl}" target="_blank">{row.roomName}</a>
<div class="hidden-lg">
<a class="button button--small button--action" href="{row.bookingUrl}" target="_blank">Jetzt buchen</a>
</div>
</f:then>
<f:else>
{row.roomName}
</f:else>
</f:if>
<f:if condition="{row.roomAvailable}">
<f:else>
<div class="hidden-lg">
<span class="label label-default">ausgebucht</span>
</div>
</f:else>
</f:if>
</td>
<td style="white-space: nowrap{f:if(condition: '{row.roomAvailable} && {row.showBookingButton}', else: ' line-through')}"
x-text="calculatePrice({row.roomPrice}, {row.roomBusPrice}, {row.roomDiscount}) + '€'"></td>
<td>
<span x-show="showBusIcon({row.roomBusPrice}, {row.roomBusIncluded})" data-microtip-position="top" aria-label="Busfahrt inklusive" role="tooltip">
<i class="fa fa-bus"></i>
</span>
<f:if condition="{row.dateSkipassIncluded}">
<span data-microtip-position="top" aria-label="{f:if(condition: '{row.season} == \'s\'', then: 'Bergbahnticket inklusive', else: 'Skipass inklusive')}" role="tooltip">
<i class="fa fa-tag"></i>
</span>
</f:if>
</td>
<td>
<f:if condition="{row.roomAvailable} && {row.roomOptionalServices -> f:count()} > 0">
<button class="button button--light button--small hidden-xs"
data-toggle="modal" data-target="'#optservices' + index"
data-microtip-position="top" aria-label="Alle Zusatzleistungen anzeigen" role="tooltip">Optionen</button>
<a href="#" class="hidden-sm hidden-md hidden-lg"
data-toggle="modal" data-target="'#optservices' + index"><i class="fa fa-info-circle"></i></a>
</f:if>
<!-- ToDo: Implement modals -->
<div class="modal fade" id="'optservices' + index" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
<h5 class="modal-title">Optionale Zusatzleistungen</h5>
</div>
<div class="modal-body">
<div class="table-responsive">
<services-optional services="row.roomOptionalServices" class="services"></services-optional>
</div>
</div>
</div>
</div>
</div>
</td>
<td class="hidden-xs hidden-md">
<f:if condition="{row.roomAvailable} && {row.showBookingButton}">
<a class="button button--small button--action"
href="{row.bookingUrl}" target="_blank">Buchen</a>
</f:if>
<f:if condition="{row.isHideBookingButton}">
<a class="button button--small button--mute" v-if="row.isHideBookingButton"
href="{travelAlertUrl}">Reisen-Alert</a>
</f:if>
<f:if condition="{row.roomAvailable} || {row.isHideBookingButton}">
<f:else>
<span class="label label-default">ausgebucht</span>
</f:else>
</f:if>
</td>
</tr>
</f:for>
</tbody>
</table>
</div>
<f:if condition="{rows -> f:count()} > 1">
<p>
<button class="button button--small" x-on:click.prevent="tableMode = 'dates'">
<i class="fa fa-undo"></i> zurück zur Terminübersicht
</button>
</p>
</f:if>
<div class="row">
<div class="col-md-12">
<div class="ep-headbar">Inklusivleistungen</div>
<div class="ep-box">
<ul class="list-unstyled">
<f:for each="{servicesIncluded}" as="service">
<li><span class="glyphicon glyphicon-ok" aria-hidden="true"></span> {service}</li>
</f:for>
</ul>
</div>
</div>
</div>
</div>
</f:section>
</html>
@@ -14,7 +14,11 @@
<f:variable name="longitude" value="{region.0.data.longitude}"/>
</f:if>
<div class="row">
<osm-map lat="{latitude}" lng="{longitude}" :zoom="17"></osm-map>
<div class="osm-map"
x-data="osmMap"
data-lat="{latitude}"
data-lng="{longitude}"
data-zoom="17"></div>
</div>
</f:section>
@@ -39,8 +39,12 @@
<div class="ep-sidebar ep-snow">
<p><strong>Lage</strong></p>
<div>
<osm-map lat="{hotel.latitude}" lng="{hotel.longitude}" :zoom="12"
external-link="{f:uri.typolink(parameter: hotel.externalLink)}"></osm-map>
<div class="osm-map"
x-data="osmMap"
data-lat="{hotel.latitude}"
data-lng="{hotel.longitude}"
data-zoom="12"
data-link="{f:uri.typolink(parameter: hotel.externalLink)}"></div>
</div>
</div>
</div>
@@ -24,8 +24,7 @@
<div class="col-xs-12">
<h2>Buchungsoptionen</h2>
<div class="ajax-content-wrapper"
x-data="ajaxContent"
data-uri="{ep:uri.ajax(action: 'pricetableHtml', controller: 'AjaxTable', pageUid: settings.defaultAjaxUid, arguments: '{product: product, hotel: hotel}', format: 'html')}">
x-data="ajaxContent('{ep:uri.ajax(action: 'pricetableHtml', controller: 'AjaxTable', pageUid: settings.defaultAjaxUid, arguments: '{product: product, hotel: hotel}', format: 'html')}')">
<div class="ajax-content" x-ref="container"></div>
<div x-ref="trigger">
<img src="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif')}" alt="Loading" title="Loading">
@@ -7,8 +7,8 @@
<f:section name="Main">
<ep:container data="{data}">
<div class="osm-map"
data-controller="osm-map"
data-osm-map-markers-value='{markerData -> f:format.raw()}'></div>
x-data="osmMap"
data-markers='{markerData -> f:format.raw()}'></div>
</ep:container>
</f:section>
@@ -7,263 +7,470 @@
<f:layout name="Default"/>
<f:section name="Main">
<product-detail
:uris='{
<article>
<f:render partial="Product/HeaderDetail" arguments="{_all}"/>
<div class="container" id="detail" x-data='productDetail({
dates: "<f:format.raw>{ep:uri.ajax(action: 'dates', controller: 'AjaxDate', arguments: '{product: product, hotel: hotel}', format: 'json', pageUid: settings.defaultAjaxUid)}</f:format.raw>",
contingents: "<f:format.raw>{ep:uri.ajax(action: 'list', controller: 'AjaxContingent', format: 'json', pageUid: settings.defaultAjaxUid)}</f:format.raw>",
rooms: "<f:format.raw>{ep:uri.ajax(action: 'rooms', controller: 'AjaxContingent', format: 'json', pageUid: settings.defaultAjaxUid)}</f:format.raw>",
pricetable: "<f:format.raw>{ep:uri.ajax(action: 'pricetable', controller: 'AjaxTable', arguments: '{product: product, hotel: hotel}', format: 'json', pageUid: settings.defaultAjaxUid)}</f:format.raw>"
}'
argument-prefix='<ep:argumentPrefix pluginName="Ajax" />'
:hotel-first="{f:if(condition: settings.hotelOnTop, then: 'true', else: 'false')}"
:bus-pro-id="{product.busProId -> f:format.raw()}"
name-internal="{product.nameInternal -> f:format.raw()}"
:daytrip="{product.daytrip -> v:variable.convert(type: 'int')}"
date-from="{dateFrom}"
date-to="{dateTo}"
inline-template>
<article>
<f:render partial="Product/HeaderDetail" arguments="{_all}"/>
<div class="container" id="detail">
<div class="product-detail-wrapper">
<div class="row">
<div class="col-md-12">
<f:render partial="Header/Header" arguments="{layout: 8, subheader: '{product.region.name} / {product.name}', header: product.headline}"/>
</div>
pricetable: "<f:format.raw>{ep:uri.ajax(action: 'pricetable', controller: 'AjaxTable', arguments: '{product: product, hotel: hotel}', format: 'html', pageUid: settings.defaultAjaxUid)}</f:format.raw>",
travelAlert: "<f:format.raw>{f:uri.typolink(parameter: settings.travelAlertPageUid)}</f:format.raw>"
})'>
<div class="product-detail-wrapper">
<div class="row">
<div class="col-md-12">
<f:render partial="Header/Header" arguments="{layout: 8, subheader: '{product.region.name} / {product.name}', header: product.headline}"/>
</div>
<div class="row">
<div class="col-md-4 col-md-push-8">
<div class="row">
<div class="col-xs-12">
<f:if condition="{settings.hotelOnTop}">
<f:then>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'hotel'}"
@click.prevent="showHtml('hotel')">Unterkunft</button>
</f:then>
<f:else>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'dates'}"
@click.prevent="loadDatesView()">Termine/Preise</button>
</f:else>
</f:if>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-md-12">
<f:if condition="{settings.hotelOnTop}">
<f:then>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'dates'}"
@click.prevent="loadDatesView()">Termine/Preise</button>
</f:then>
<f:else>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'hotel'}"
@click.prevent="showHtml('hotel')">Unterkunft</button>
</f:else>
</f:if>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'region'}"
@click.prevent="showHtml('region')">Gebiet</button>
</div>
<div class="col-xs-6 col-md-12">
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'city'}"
@click.prevent="showHtml('city')">Ort</button>
<f:if condition="{product.journey}">
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'journey'}"
@click.prevent="showHtml('journey')">Anreise</button>
</f:if>
<f:if condition="{product.faqs}">
<button class="button button--light button--sidebar"
@click.prevent="scrollTo('#faq')">FAQ</button>
</f:if>
</div>
<div class="col-xs-12">
<p>
<a href="#" x-data="watchlistToggle" x-bind="trigger" data-uid="{hotel.uid}:{product.uid}">
<span data-microtip-position="top" x-bind:aria-label="label" role="tooltip">
<i class="fa" x-bind:class="icon"></i>
</span>
<span x-text="label"></span>
</a>
</p>
<p>
<a href="{f:uri.typolink(parameter: settings.coronaUpdatesPageUid)}"
class="block w-full py-2 border-2 border-red-500 rounded text-red-500 text-center uppercase hover:bg-red-500 hover:text-white transition-colors duration-200 ease-in-out"
title="Corona Updates">
Corona Updates
</a>
</p>
</div>
</div>
<div class="hidden-xs">
<f:render section="Calendar" arguments="{_all}"/>
<f:render partial="Facts" arguments="{facts: product.facts}"/>
<f:if condition="{product.video}">
<div class="video">
<iframe class="video__frame" width="560" height="315" frameborder="0" allowfullscreen
src="{ep:uri.video(value: product.video)}"></iframe>
</div>
</f:if>
<div class="ep-sidebar ep-snow">
<p><strong>Lage</strong></p>
<div>
<osm-map lat="{hotel.latitude}" lng="{hotel.longitude}" :zoom="12"
external-link="{f:uri.typolink(parameter: hotel.externalLink)}"></osm-map>
</div>
</div>
<f:render partial="Region/Webcam" arguments="{region: product.region}"/>
<f:render partial="RegionMaps" arguments="{region: product.region}"/>
<f:render partial="RegionAward" arguments="{region: product.region}"/>
<f:if condition="{product.banner}">
<div class="ep-sidebar ep-snow">
<f:link.typolink parameter="{product.banner.originalResource.link}"
title="{product.banner.title}">
<f:image src="{product.banner.uid}" treatIdAsReference="1"
class="scale" alt="{product.banner.alternative}"/>
</f:link.typolink>
</div>
</f:if>
<f:render partial="Rating" arguments="{product: product, targetPageUid: settings.ratingPageUid, label: settings.ratingWidgetLabel}"/>
<f:render partial="Snowreport" arguments="{snowreport: product.region.snowreport}"/>
<f:render partial="Officetip" arguments="{officetip: product.officetip}"/>
<f:if condition="{settings.hideTeamer}">
<f:else>
<f:render partial="Teamer" arguments="{teamer: hotel.teamer}"/>
</f:else>
</f:if>
</div>
</div>
<div id="main" class="col-md-8 col-md-pull-4">
<!-- Dates -->
<div v-cloak v-show="!loading && datesShow">
<f:if condition="{isProductWithExcludedConcept}">
<f:if condition="{product.region.season} == 'w'">
<div class="alert alert-info">
<p><strong>Gruppenrabatt bis zu 100€ möglich</strong></p>
<p>Für Gruppen bis 15 Personen könnt ihr <f:link.typolink parameter="31">hier direkt buchen</f:link.typolink>.
Für Gruppen ab 16 Personen erstellen wir euch ein konkretes Angebot zu günstigen
Gruppenkonditionen zu dieser Reise. Anfrage via Tel. 0221 - 272 276 18 oder mit einer
<f:link.typolink parameter="{settings.defaultContactFormPageUid}">Kurzanfrage</f:link.typolink>!</p>
</div>
</f:if>
</f:if>
<f:if condition="{product.daytrip}">
</div>
<div class="row">
<div class="col-md-4 col-md-push-8">
<div class="row">
<div class="col-xs-12">
<f:if condition="{settings.hotelOnTop}">
<f:then>
<date-select
hotel-name="{hotel.name}"
:hotel-uid="{hotel.uid}"
:product-uid="{product.uid}"
:contingent-endpoint-uri="uris.contingents"
:rooms-endpoint-uri="uris.rooms"
:argument-prefix="argumentPrefix"
loader-uri="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif')}"
></date-select>
<button class="button button--light button--sidebar"
x-bind:class="{ 'button--active': show === 'hotel'}"
x-on:click.prevent="show = 'hotel'">Unterkunft</button>
</f:then>
<f:else>
<template v-if="available">
<dates-table :dates-rows="datesRows"
:alt-product-link="altProductLink"
:alt-label="altLabel"
hotel-name="{hotel.name}"
:bookable="bookable"
travel-alert-url="{f:uri.typolink(parameter: settings.travelAlertPageUid)}"
></dates-table>
</template>
<f:if condition="{isProductWithNoInfoConcept}">
<f:else>
<template v-else>
<f:render partial="NotBookable" arguments="{_all}"/>
</template>
</f:else>
</f:if>
<button class="button button--light button--sidebar"
x-bind:class="{ 'button--active': show === 'dates'}"
x-on:click.prevent="show = 'dates'">Termine/Preise</button>
</f:else>
</f:if>
<f:render partial="Product/Details" arguments="{_all}"/>
</div>
<!-- /Dates -->
<!-- Prices -->
<div v-cloak v-show="!loading && priceTableShow">
<price-table :price-table-rows="priceTableRows"
:services-included="servicesIncluded"
:date-label="dateLabel"
:single-date="singleDate"
travel-alert-url="{f:uri.typolink(parameter: settings.travelAlertPageUid)}"
></price-table>
<f:alias map="{currentPageUid: 1}">
<f:render partial="Product/Details" arguments="{_all}"/>
</f:alias>
</div>
<!-- /Prices -->
<!-- Hotel -->
<div v-show="detailShow && activeSection === 'hotel'">
<f:render partial="Hotel/Details" arguments="{hotel: hotel, bars: 1, showNonBookableHint: 0}"/>
</div>
<!-- /Hotel -->
<!-- City -->
<div v-show="detailShow && activeSection === 'city'">
<f:render partial="City/Details" arguments="{city: product.city, bars: 1}"/>
</div>
<!-- /City -->
<!-- Region -->
<div v-show="detailShow && activeSection === 'region'">
<f:render partial="Region/Details" arguments="{region: product.region, bars: 1}"/>
</div>
<!-- /Region -->
<!-- Journey -->
<div v-show="detailShow && activeSection === 'journey'">
<f:render partial="Journey/Details" arguments="{journey: product.journey, bars: 1}"/>
</div>
<!-- /Journey -->
<!-- Loader -->
<div v-show="loading" class="loader"><p>Loading... <f:image src="EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif" alt="Loading"/></p></div>
<!-- /Loader -->
<div class="hidden-md hidden-lg">
<f:render section="Calendar" arguments="{_all}"/>
<f:render partial="Facts" arguments="{facts: product.facts}"/>
<f:if condition="{product.video}">
<div class="video">
<iframe class="video__frame" width="560" height="315" frameborder="0" allowfullscreen
src="{ep:uri.video(value: product.video)}"></iframe>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-md-12">
<f:if condition="{settings.hotelOnTop}">
<f:then>
<button class="button button--light button--sidebar"
x-bind:class="{ 'button--active': show === 'dates'}"
x-on:click.prevent="show = 'dates'">Termine/Preise</button>
</f:then>
<f:else>
<button class="button button--light button--sidebar"
x-bind:class="{ 'button--active': show === 'hotel'}"
x-on:click.prevent="show = 'hotel'">Unterkunft</button>
</f:else>
</f:if>
<div class="ep-sidebar ep-snow">
<p><strong>Lage</strong></p>
<div>
<osm-map lat="{hotel.latitude}" lng="{hotel.longitude}" :zoom="12"
external-link="{f:uri.typolink(parameter: hotel.externalLink)}"></osm-map>
</div>
<button class="button button--light button--sidebar"
x-bind:class="{ 'button--active': show === 'region'}"
x-on:click.prevent="show = 'region'">Gebiet</button>
</div>
<div class="col-xs-6 col-md-12">
<button class="button button--light button--sidebar"
x-bind:class="{ 'button--active': show === 'city'}"
x-on:click.prevent="show = 'city'">Ort</button>
<f:if condition="{product.journey}">
<button class="button button--light button--sidebar"
x-bind:class="{ 'button--active': show === 'journey'}"
x-on:click.prevent="show = 'journey'">Anreise</button>
</f:if>
<f:if condition="{product.faqs}">
<button class="button button--light button--sidebar"
x-on:click.prevent="scrollTo('#faq')">FAQ</button>
</f:if>
</div>
<div class="col-xs-12">
<p>
<a href="#" x-data="watchlistToggle('{hotel.uid}:{product.uid}')" x-bind="trigger">
<span data-microtip-position="top" x-bind:aria-label="label" role="tooltip">
<i class="fa" x-bind:class="icon"></i>
</span>
<span x-text="label"></span>
</a>
</p>
<p>
<a href="{f:uri.typolink(parameter: settings.coronaUpdatesPageUid)}"
class="block w-full py-2 border-2 border-red-500 rounded text-red-500 text-center uppercase hover:bg-red-500 hover:text-white transition-colors duration-200 ease-in-out"
title="Corona Updates">
Corona Updates
</a>
</p>
</div>
</div>
<div class="hidden-xs">
<f:render section="Calendar" arguments="{_all}"/>
<f:render partial="Facts" arguments="{facts: product.facts}"/>
<f:if condition="{product.video}">
<div class="video">
<iframe class="video__frame" width="560" height="315" allowfullscreen
src="{ep:uri.video(value: product.video)}"></iframe>
</div>
<f:render partial="Region/Webcam" arguments="{region: product.region}"/>
<f:render partial="RegionMaps" arguments="{region: product.region}"/>
<f:render partial="RegionAward" arguments="{region: product.region}"/>
<f:if condition="{product.banner}">
<div class="ep-sidebar ep-snow">
<f:link.typolink parameter="{product.banner.originalResource.link}"
title="{product.banner.title}">
<f:image src="{product.banner.uid}" treatIdAsReference="1"
class="scale" alt="{product.banner.alternative}"/>
</f:link.typolink>
</f:if>
<div class="ep-sidebar ep-snow">
<p><strong>Lage</strong></p>
<div>
<div class="osm-map"
x-data="osmMap"
data-lat="{hotel.latitude}"
data-lng="{hotel.longitude}"
data-link="{f:uri.typolink(parameter: hotel.externalLink)}"></div>
</div>
</div>
<f:render partial="Region/Webcam" arguments="{region: product.region}"/>
<f:render partial="RegionMaps" arguments="{region: product.region}"/>
<f:render partial="RegionAward" arguments="{region: product.region}"/>
<f:if condition="{product.banner}">
<div class="ep-sidebar ep-snow">
<f:link.typolink parameter="{product.banner.originalResource.link}"
title="{product.banner.title}">
<f:image src="{product.banner.uid}" treatIdAsReference="1"
class="scale" alt="{product.banner.alternative}"/>
</f:link.typolink>
</div>
</f:if>
<f:render partial="Rating" arguments="{product: product, targetPageUid: settings.ratingPageUid, label: settings.ratingWidgetLabel}"/>
<f:render partial="Snowreport" arguments="{snowreport: product.region.snowreport}"/>
<f:render partial="Officetip" arguments="{officetip: product.officetip}"/>
<f:if condition="{settings.hideTeamer}">
<f:else>
<f:render partial="Teamer" arguments="{teamer: hotel.teamer}"/>
</f:else>
</f:if>
</div>
</div>
<div id="main" class="col-md-8 col-md-pull-4">
<!-- Loader -->
<div x-show="loading" class="flex space-x-2 mb-8">
<f:image class="block w-4 h-4" src="EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif" alt="Loading"/>
<span>Loading...</span>
</div>
<!-- /Loader -->
<!-- Dates -->
<div x-show="show === 'dates' && !loading" x-transition.opacity>
<f:if condition="{isProductWithExcludedConcept}">
<f:if condition="{product.region.season} == 'w'">
<div class="alert alert-info">
<p><strong>Gruppenrabatt bis zu 100€ möglich</strong></p>
<p>Für Gruppen bis 15 Personen könnt ihr <f:link.typolink parameter="31">hier direkt buchen</f:link.typolink>.
Für Gruppen ab 16 Personen erstellen wir euch ein konkretes Angebot zu günstigen
Gruppenkonditionen zu dieser Reise. Anfrage via Tel. 0221 - 272 276 18 oder mit einer
<f:link.typolink parameter="{settings.defaultContactFormPageUid}">Kurzanfrage</f:link.typolink>!</p>
</div>
</f:if>
<f:render partial="Rating" arguments="{product: product, targetPageUid: settings.ratingPageUid, label: settings.ratingWidgetLabel}"/>
<f:render partial="Snowreport" arguments="{snowreport: product.region.snowreport}"/>
<f:render partial="Officetip" arguments="{officetip: product.officetip}"/>
<f:render partial="Teamer" arguments="{teamer: hotel.teamer}"/>
</f:if>
<f:if condition="{product.daytrip}">
<f:then>
<f:comment><!--
<date-select
hotel-name="{hotel.name}"
:hotel-uid="{hotel.uid}"
:product-uid="{product.uid}"
:contingent-endpoint-uri="uris.contingents"
:rooms-endpoint-uri="uris.rooms"
:argument-prefix="argumentPrefix"
loader-uri="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif')}"
></date-select>
--></f:comment>
</f:then>
<f:else>
<div x-show="tableMode === 'dates'">
<f:render section="DatesTable" arguments="{_all}"/>
</div>
<div x-show="tableMode === 'prices'">
<f:render section="PriceTable" arguments="{_all}"/>
</div>
<f:if condition="{isProductWithNoInfoConcept}">
<template x-if="!available">
<f:render partial="NotBookable" arguments="{_all}"/>
</template>
</f:if>
</f:else>
</f:if>
</div>
<!-- /Dates -->
<div x-show="show === 'dates' || show === 'prices'">
<f:render partial="Product/Details" arguments="{_all}"/>
</div>
<!-- Hotel -->
<div x-show="show === 'hotel'" x-transition.opacity>
<f:render partial="Hotel/Details" arguments="{hotel: hotel, bars: 1, showNonBookableHint: 0}"/>
</div>
<!-- /Hotel -->
<!-- City -->
<div x-show="show === 'city'" x-transition.opacity>
<f:render partial="City/Details" arguments="{city: product.city, bars: 1}"/>
</div>
<!-- /City -->
<!-- Region -->
<div x-show="show === 'region'" x-transition.opacity>
<f:render partial="Region/Details" arguments="{region: product.region, bars: 1}"/>
</div>
<!-- /Region -->
<!-- Journey -->
<div x-show="show === 'journey'" x-transition.opacity>
<f:render partial="Journey/Details" arguments="{journey: product.journey, bars: 1}"/>
</div>
<!-- /Journey -->
<div class="hidden-md hidden-lg">
<f:render section="Calendar" arguments="{_all}"/>
<f:render partial="Facts" arguments="{facts: product.facts}"/>
<f:if condition="{product.video}">
<div class="video">
<iframe class="video__frame" width="560" height="315" allowfullscreen
src="{ep:uri.video(value: product.video)}"></iframe>
</div>
</f:if>
<div class="ep-sidebar ep-snow">
<p><strong>Lage</strong></p>
<div>
<div class="osm-map"
x-data="osmMap"
data-lat="{hotel.latitude}"
data-lng="{hotel.longitude}"
data-link="{f:uri.typolink(parameter: hotel.externalLink)}"></div>
</div>
</div>
<f:render partial="Region/Webcam" arguments="{region: product.region}"/>
<f:render partial="RegionMaps" arguments="{region: product.region}"/>
<f:render partial="RegionAward" arguments="{region: product.region}"/>
<f:if condition="{product.banner}">
<div class="ep-sidebar ep-snow">
<f:link.typolink parameter="{product.banner.originalResource.link}"
title="{product.banner.title}">
<f:image src="{product.banner.uid}" treatIdAsReference="1"
class="scale" alt="{product.banner.alternative}"/>
</f:link.typolink>
</div>
</f:if>
<f:render partial="Rating" arguments="{product: product, targetPageUid: settings.ratingPageUid, label: settings.ratingWidgetLabel}"/>
<f:render partial="Snowreport" arguments="{snowreport: product.region.snowreport}"/>
<f:render partial="Officetip" arguments="{officetip: product.officetip}"/>
<f:render partial="Teamer" arguments="{teamer: hotel.teamer}"/>
</div>
</div>
</div>
</div>
</article>
</product-detail>
<div x-data="fbpixel" data-fbpixel-props='{ "content_ids": [ {product.busProId -> f:format.raw()} ], "content_name": "{product.nameInternal -> f:format.raw()}", "content_type": "product" }'></div>
</div>
</article>
<div x-data x-init='fbq("track", "ViewContent", { "content_ids": [ {product.busProId -> f:format.raw()} ], "content_name": "{product.nameInternal -> f:format.raw()}", "content_type": "product" })'></div>
<f:render partial="Faq" arguments="{faqs: product.faqs, settings: settings}"/>
</f:section>
<f:section name="DatesTable">
<div class="dates-table-wrapper">
<div x-show="bookable" class="ep-headbar">Buchungsoptionen {hotel.name}</div>
<div x-show="!bookable" class="ep-headbar">Termine &amp; Leistungen</div>
<f:render section="PriceToggle"/>
<div class="table-responsive">
<table class="table table-striped dates-table">
<thead>
<tr>
<th>Termin</th>
<th>
<span data-microtip-position="bottom" aria-label="Nächte" role="tooltip">
<i class="fa fa-bed"></i>
</span>
</th>
<th>Preis ab</th>
<th>inkl.</th>
<th class="hidden-xs"></th>
</tr>
</thead>
<tbody>
<template x-for="(row, index) in datesRows" x-bind:key="row.dateUid">
<tr x-bind:class="{ 'hidden': index > 4 && !showAll }">
<td class="dates-table__cell dates-table__cell--date">
<template x-if="bookable && row.available && !row.isHideBookingButton">
<a class="dates-table__date" href="#"
x-on:click.prevent="loadPrices(row.dateUid)"
x-text="row.dateStart + ' - ' + row.dateEnd"></a>
<div class="hidden-md hidden-lg dates-table__links">
<button x-on:click.prevent="loadPrices(row.dateUid)" class="button button--small">
Details
</button>
<a x-bind:href="row.bookingUrl" target="_blank" class="button button--small button--action">
Buchen
</a>
</div>
</template>
<template x-if="!bookable || !row.available || row.isHideBookingButton">
<span x-text="row.dateStart + ' - ' + row.dateEnd"></span>
</template>
</td>
<td class="dates-table__cell dates-table__cell--nights" x-text="row.dateNights"></td>
<td class="dates-table__cell dates-table__cell--price">
<span class="dates-table__pseudo-price" x-show="row.datePseudoPrice" x-text="row.datePseudoPrice + ' €'"></span>
<strong x-text="calculatePrice(row.dateMinPrice, row.dateBusPrice, row.dateDiscount) + ' €'"></strong>
</td>
<td class="dates-table__cell dates-table__cell--icons">
<span class="icon-wrapper hidden-xs hidden-sm">
<span x-show="showBusIcon(row.dateBusPrice, row.dateBusIncluded)" data-microtip-position="top" aria-label="Busfahrt inklusive" role="tooltip">
<i class="fa fa-bus"></i>
</span>
<span x-show="row.dateSkipassIncluded" data-microtip-position="top" x-bind:aria-label="row.season === 's' ? 'Bergbahnticket inklusive' : 'Skipass inklusive'" role="tooltip">
<i class="fa fa-tag"></i>
</span>
</span>
<button type="button" class="button button--light button--small hidden-xs"
data-toggle="modal" data-target="'#dateservices' + index"
data-microtip-position="top" aria-label="Alle Inklusivleistungen anzeigen" role="tooltip">Leistungen</button>
<a href="#" data-toggle="modal" data-target="'#dateservices' + index"
class="hidden-sm hidden-md hidden-lg"><i class="fa fa-info-circle"></i></a>
</td>
<td class="dates-table__cell dates-table__cell--buttons hidden-xs">
<button x-show="row.available || row.isHideBookingButton" class="button button--small" x-on:click="loadPrices(row.dateUid)">Details</button>
<a x-show="row.available && !row.isHideBookingButton" x-bind:href="row.bookingUrl" target="_blank" class="button button--small button--action">Buchen</a>
<a x-show="row.isHideBookingButton" x-bind:href="uris.travelAlertUrl" class="button button--small button--mute">Reisen-Alert</a>
<span x-show="!row.available && !row.isHideBookingButton" class="label label-default">ausgebucht</span>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<template x-if="datesRows.length > 5 || altProductLink">
<div class="row dates-table__links">
<div class="col-xs-12 col-md-6">
<a x-show="datesRows.length > 5" href="#" x-on:click.prevent="showAll = !showAll">
<i class="fa" x-bind:class="{ 'fa-minus-circle': showAll , 'fa-plus-circle': !showAll }"></i>
<span x-text="showAll ? 'Weniger Termine anzeigen' : 'Alle Termine anzeigen'"></span>
</a>
</div>
<template x-if="altProductLink">
<div class="col-xs-12 col-md-6">
<a x-bind:href="altProductLink" x-bind:title="altLabel" class="dates-table__altlink">
<i class="fa fa-arrow-circle-right"></i> <span x-text="altLabel"></span>
</a>
</div>
</template>
</div>
</template>
</div>
</f:section>
<f:section name="PriceTable">
<div class="price-table-wrapper">
<div class="row ep-headbar">
<div class="col-xs-6">Buchungsoptionen</div>
<div class="col-xs-6 text-right" x-text="dateRange"></div>
</div>
<f:render section="PriceToggle"/>
<div class="table-responsive">
<table class="table table-striped pricetable">
<thead>
<tr>
<th>Zimmertyp</th>
<th>Preis</th>
<th>inkl.</th>
<th></th>
<th class="hidden-xs hidden-md"></th>
</tr>
</thead>
<tbody>
<template x-for="(row, index) in pricesRows" x-bind:key="row.roomBusProId">
<tr>
<td style="white-space: normal">
<span x-show="row.isHideBookingButton || !row.roomAvailable" x-text="row.roomName"></span>
<a x-show="!row.isHideBookingButton && row.roomAvailable" class="pricetable__room-label"
x-bind:href="row.bookingUrl" target="_blank" x-text="row.roomName"></a>
<div class="hidden-lg" x-show="!row.isHideBookingButton && row.roomAvailable">
<a class="button button--small button--action"
x-bind:href="row.bookingUrl" target="_blank">Jetzt buchen</a>
</div>
<div class="hidden-lg" x-show="!row.roomAvailable">
<span class="label label-default">ausgebucht</span>
</div>
</td>
<td style="white-space: nowrap" x-bind:style="{textDecoration: !row.roomAvailable && !row.isHideBookingButton ? 'line-through' : ''}"
x-text="calculatePrice(row.roomPrice, row.roomBusPrice, row.roomDiscount) + ' €'"></td>
<td>
<span x-show="showBusIcon(row.roomBusPrice, row.dateBusIncluded)" data-microtip-position="top" aria-label="Busfahrt inklusive" role="tooltip">
<i class="fa fa-bus"></i>
</span>
<span x-show="row.dateSkipassIncluded" data-microtip-position="top" x-bind:aria-label="row.season === 's' ? 'Bergbahnticket inklusive' : 'Skipass inklusive'" role="tooltip">
<i class="fa fa-tag"></i>
</span>
</td>
<td>
<button x-show="hasOptionalServices(row) && row.roomAvailable"
class="button button--light button--small hidden-xs"
data-toggle="modal" data-target="'#optservices' + index"
data-microtip-position="top" aria-label="Alle Zusatzleistungen anzeigen" role="tooltip">Optionen</button>
<a href="#" x-show="hasOptionalServices(row) && row.roomAvailable" class="hidden-sm hidden-md hidden-lg"
data-toggle="modal" data-target="'#optservices' + index"><i class="fa fa-info-circle"></i></a>
<div class="modal fade" :id="'optservices' + index" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
<h5 class="modal-title">Optionale Zusatzleistungen</h5>
</div>
<div class="modal-body">
<div class="table-responsive">
<services-optional :services="row.roomOptionalServices" class="services"></services-optional>
</div>
</div>
</div>
</div>
</div>
</td>
<td class="hidden-xs hidden-md">
<a class="button button--small button--action" x-show="row.roomAvailable && !row.isHideBookingButton"
x-bind:href="row.bookingUrl" target="_blank">Buchen</a>
<a class="button button--small button--mute" x-show="row.isHideBookingButton"
x-bind:href="uris.travelAlertUrl">Reisen-Alert</a>
<span x-show="!row.roomAvailable && !row.isHideBookingButton" class="label label-default">ausgebucht</span>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<template x-if="!singleDate">
<p>
<button class="button button--small" x-on:click.prevent="tableMode = 'dates'">
<i class="fa fa-undo"></i> zurück zur Terminübersicht
</button>
</p>
</template>
<div class="row">
<div class="col-md-12">
<div class="ep-headbar">Inklusivleistungen</div>
<div class="ep-box">
<ul class="list-unstyled">
<template x-for="service in servicesIncluded">
<li>
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <span x-text="service"></span>
</li>
</template>
</ul>
</div>
</div>
</div>
</div>
</f:section>
<f:section name="PriceToggle">
<div class="dates-table__pricetoggle" x-show="hasSurcharge || hasDiscount">
<template x-if="hasSurcharge">
<a href="#" x-on:click.prevent="addBus = !addBus">
<span x-show="addBus">
<i class="fa fa-arrow-circle-right"></i> Preise für Eigenanreise anzeigen
</span>
<span x-show="! addBus">
<i class="fa fa-arrow-circle-right"></i> Preise für Busanreise anzeigen
</span>
</a>
</template>
<template x-if="hasDiscount">
<a href="#" x-on:click.prevent="discountBus = !discountBus">
<span x-show="discountBus">
<i class="fa fa-arrow-circle-right"></i> Preise für Busanreise anzeigen
</span>
<span x-show="!discountBus">
<i class="fa fa-arrow-circle-right"></i> Preise für Eigenanreise anzeigen
</span>
</a>
</template>
</div>
</f:section>
<f:section name="Calendar">
<f:if condition="{product.calendarHotel}">
<f:if condition="{hotel.groupsPriceConfigs}">
@@ -275,6 +482,7 @@
</f:if>
<div class="ep-sidebar ep-facts">
<p><strong>Belegungskalender</strong></p>
<f:comment><!--
<calendar
uri="{ep:uri.ajax(action: 'range', controller: 'AjaxCalendar', extensionName: 'epproducts', pageUid: settings.defaultAjaxUid, arguments: '{hotel: product.calendarHotel}', format: 'html')}"
loader-uri="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif')}"
@@ -285,6 +493,7 @@
:step="1"
argument-prefix="{ep:argumentPrefix(pluginName: 'ajax', extensionName: 'epproducts')}"
></calendar>
--></f:comment>
</div>
<f:if condition="{hotel.groupsPriceConfigs}">
<f:else>
@@ -0,0 +1,305 @@
<html data-namespace-typo3-fluid="true" lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers"
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers"
xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers">
<f:layout name="Default"/>
<f:section name="Main">
<product-detail
:uris='{
dates: "<f:format.raw>{ep:uri.ajax(action: 'dates', controller: 'AjaxDate', arguments: '{product: product, hotel: hotel}', format: 'json', pageUid: settings.defaultAjaxUid)}</f:format.raw>",
contingents: "<f:format.raw>{ep:uri.ajax(action: 'list', controller: 'AjaxContingent', format: 'json', pageUid: settings.defaultAjaxUid)}</f:format.raw>",
rooms: "<f:format.raw>{ep:uri.ajax(action: 'rooms', controller: 'AjaxContingent', format: 'json', pageUid: settings.defaultAjaxUid)}</f:format.raw>",
pricetable: "<f:format.raw>{ep:uri.ajax(action: 'pricetable', controller: 'AjaxTable', arguments: '{product: product, hotel: hotel}', format: 'json', pageUid: settings.defaultAjaxUid)}</f:format.raw>"
}'
argument-prefix='<ep:argumentPrefix pluginName="Ajax" />'
:hotel-first="{f:if(condition: settings.hotelOnTop, then: 'true', else: 'false')}"
:bus-pro-id="{product.busProId -> f:format.raw()}"
name-internal="{product.nameInternal -> f:format.raw()}"
:daytrip="{product.daytrip -> v:variable.convert(type: 'int')}"
date-from="{dateFrom}"
date-to="{dateTo}"
inline-template>
<article>
<f:render partial="Product/HeaderDetail" arguments="{_all}"/>
<div class="container" id="detail">
<div class="product-detail-wrapper">
<div class="row">
<div class="col-md-12">
<f:render partial="Header/Header" arguments="{layout: 8, subheader: '{product.region.name} / {product.name}', header: product.headline}"/>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-push-8">
<div class="row">
<div class="col-xs-12">
<f:if condition="{settings.hotelOnTop}">
<f:then>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'hotel'}"
@click.prevent="showHtml('hotel')">Unterkunft</button>
</f:then>
<f:else>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'dates'}"
@click.prevent="loadDatesView()">Termine/Preise</button>
</f:else>
</f:if>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-md-12">
<f:if condition="{settings.hotelOnTop}">
<f:then>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'dates'}"
@click.prevent="loadDatesView()">Termine/Preise</button>
</f:then>
<f:else>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'hotel'}"
@click.prevent="showHtml('hotel')">Unterkunft</button>
</f:else>
</f:if>
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'region'}"
@click.prevent="showHtml('region')">Gebiet</button>
</div>
<div class="col-xs-6 col-md-12">
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'city'}"
@click.prevent="showHtml('city')">Ort</button>
<f:if condition="{product.journey}">
<button class="button button--light button--sidebar"
:class="{ 'button--active': activeSection === 'journey'}"
@click.prevent="showHtml('journey')">Anreise</button>
</f:if>
<f:if condition="{product.faqs}">
<button class="button button--light button--sidebar"
@click.prevent="scrollTo('#faq')">FAQ</button>
</f:if>
</div>
<div class="col-xs-12">
<p>
<a href="#" x-data="watchlistToggle" x-bind="trigger" data-uid="{hotel.uid}:{product.uid}">
<span data-microtip-position="top" x-bind:aria-label="label" role="tooltip">
<i class="fa" x-bind:class="icon"></i>
</span>
<span x-text="label"></span>
</a>
</p>
<p>
<a href="{f:uri.typolink(parameter: settings.coronaUpdatesPageUid)}"
class="block w-full py-2 border-2 border-red-500 rounded text-red-500 text-center uppercase hover:bg-red-500 hover:text-white transition-colors duration-200 ease-in-out"
title="Corona Updates">
Corona Updates
</a>
</p>
</div>
</div>
<div class="hidden-xs">
<f:render section="Calendar" arguments="{_all}"/>
<f:render partial="Facts" arguments="{facts: product.facts}"/>
<f:if condition="{product.video}">
<div class="video">
<iframe class="video__frame" width="560" height="315" frameborder="0" allowfullscreen
src="{ep:uri.video(value: product.video)}"></iframe>
</div>
</f:if>
<div class="ep-sidebar ep-snow">
<p><strong>Lage</strong></p>
<div>
<div class="osm-map"
x-data="osmMap"
data-lat="{hotel.latitude}"
data-lng="{hotel.longitude}"
data-link="{f:uri.typolink(parameter: hotel.externalLink)}"></div>
</div>
</div>
<f:render partial="Region/Webcam" arguments="{region: product.region}"/>
<f:render partial="RegionMaps" arguments="{region: product.region}"/>
<f:render partial="RegionAward" arguments="{region: product.region}"/>
<f:if condition="{product.banner}">
<div class="ep-sidebar ep-snow">
<f:link.typolink parameter="{product.banner.originalResource.link}"
title="{product.banner.title}">
<f:image src="{product.banner.uid}" treatIdAsReference="1"
class="scale" alt="{product.banner.alternative}"/>
</f:link.typolink>
</div>
</f:if>
<f:render partial="Rating" arguments="{product: product, targetPageUid: settings.ratingPageUid, label: settings.ratingWidgetLabel}"/>
<f:render partial="Snowreport" arguments="{snowreport: product.region.snowreport}"/>
<f:render partial="Officetip" arguments="{officetip: product.officetip}"/>
<f:if condition="{settings.hideTeamer}">
<f:else>
<f:render partial="Teamer" arguments="{teamer: hotel.teamer}"/>
</f:else>
</f:if>
</div>
</div>
<div id="main" class="col-md-8 col-md-pull-4">
<!-- Dates -->
<div v-cloak v-show="!loading && datesShow">
<f:if condition="{isProductWithExcludedConcept}">
<f:if condition="{product.region.season} == 'w'">
<div class="alert alert-info">
<p><strong>Gruppenrabatt bis zu 100€ möglich</strong></p>
<p>Für Gruppen bis 15 Personen könnt ihr <f:link.typolink parameter="31">hier direkt buchen</f:link.typolink>.
Für Gruppen ab 16 Personen erstellen wir euch ein konkretes Angebot zu günstigen
Gruppenkonditionen zu dieser Reise. Anfrage via Tel. 0221 - 272 276 18 oder mit einer
<f:link.typolink parameter="{settings.defaultContactFormPageUid}">Kurzanfrage</f:link.typolink>!</p>
</div>
</f:if>
</f:if>
<f:if condition="{product.daytrip}">
<f:then>
<date-select
hotel-name="{hotel.name}"
:hotel-uid="{hotel.uid}"
:product-uid="{product.uid}"
:contingent-endpoint-uri="uris.contingents"
:rooms-endpoint-uri="uris.rooms"
:argument-prefix="argumentPrefix"
loader-uri="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif')}"
></date-select>
</f:then>
<f:else>
<template v-if="available">
<dates-table :dates-rows="datesRows"
:alt-product-link="altProductLink"
:alt-label="altLabel"
hotel-name="{hotel.name}"
:bookable="bookable"
travel-alert-url="{f:uri.typolink(parameter: settings.travelAlertPageUid)}"
></dates-table>
</template>
<f:if condition="{isProductWithNoInfoConcept}">
<f:else>
<template v-else>
<f:render partial="NotBookable" arguments="{_all}"/>
</template>
</f:else>
</f:if>
</f:else>
</f:if>
<f:render partial="Product/Details" arguments="{_all}"/>
</div>
<!-- /Dates -->
<!-- Prices -->
<div v-cloak v-show="!loading && priceTableShow">
<price-table :price-table-rows="priceTableRows"
:services-included="servicesIncluded"
:date-label="dateLabel"
:single-date="singleDate"
travel-alert-url="{f:uri.typolink(parameter: settings.travelAlertPageUid)}"
></price-table>
<f:alias map="{currentPageUid: 1}">
<f:render partial="Product/Details" arguments="{_all}"/>
</f:alias>
</div>
<!-- /Prices -->
<!-- Hotel -->
<div v-show="detailShow && activeSection === 'hotel'">
<f:render partial="Hotel/Details" arguments="{hotel: hotel, bars: 1, showNonBookableHint: 0}"/>
</div>
<!-- /Hotel -->
<!-- City -->
<div v-show="detailShow && activeSection === 'city'">
<f:render partial="City/Details" arguments="{city: product.city, bars: 1}"/>
</div>
<!-- /City -->
<!-- Region -->
<div v-show="detailShow && activeSection === 'region'">
<f:render partial="Region/Details" arguments="{region: product.region, bars: 1}"/>
</div>
<!-- /Region -->
<!-- Journey -->
<div v-show="detailShow && activeSection === 'journey'">
<f:render partial="Journey/Details" arguments="{journey: product.journey, bars: 1}"/>
</div>
<!-- /Journey -->
<!-- Loader -->
<div v-show="loading" class="loader"><p>Loading... <f:image src="EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif" alt="Loading"/></p></div>
<!-- /Loader -->
<div class="hidden-md hidden-lg">
<f:render section="Calendar" arguments="{_all}"/>
<f:render partial="Facts" arguments="{facts: product.facts}"/>
<f:if condition="{product.video}">
<div class="video">
<iframe class="video__frame" width="560" height="315" frameborder="0" allowfullscreen
src="{ep:uri.video(value: product.video)}"></iframe>
</div>
</f:if>
<div class="ep-sidebar ep-snow">
<p><strong>Lage</strong></p>
<div>
<div class="osm-map"
x-data="osmMap"
data-lat="{hotel.latitude}"
data-lng="{hotel.longitude}"
data-link="{f:uri.typolink(parameter: hotel.externalLink)}"></div>
</div>
</div>
<f:render partial="Region/Webcam" arguments="{region: product.region}"/>
<f:render partial="RegionMaps" arguments="{region: product.region}"/>
<f:render partial="RegionAward" arguments="{region: product.region}"/>
<f:if condition="{product.banner}">
<div class="ep-sidebar ep-snow">
<f:link.typolink parameter="{product.banner.originalResource.link}"
title="{product.banner.title}">
<f:image src="{product.banner.uid}" treatIdAsReference="1"
class="scale" alt="{product.banner.alternative}"/>
</f:link.typolink>
</div>
</f:if>
<f:render partial="Rating" arguments="{product: product, targetPageUid: settings.ratingPageUid, label: settings.ratingWidgetLabel}"/>
<f:render partial="Snowreport" arguments="{snowreport: product.region.snowreport}"/>
<f:render partial="Officetip" arguments="{officetip: product.officetip}"/>
<f:render partial="Teamer" arguments="{teamer: hotel.teamer}"/>
</div>
</div>
</div>
</div>
</div>
</article>
</product-detail>
<div x-data="fbpixel('{ "content_ids": [ {product.busProId -> f:format.raw()} ], "content_name": "{product.nameInternal -> f:format.raw()}", "content_type": "product" }')"></div>
<f:render partial="Faq" arguments="{faqs: product.faqs, settings: settings}"/>
</f:section>
<f:section name="Calendar">
<f:if condition="{product.calendarHotel}">
<f:if condition="{hotel.groupsPriceConfigs}">
<a class="button button--full"
data-glightbox
href="{f:uri.action(action: 'index', controller: 'GroupsPrice', arguments: '{hotel: hotel}', pageUid: settings.groupsPricePopupPageUid)}">
Preisberechnung
</a>
</f:if>
<div class="ep-sidebar ep-facts">
<p><strong>Belegungskalender</strong></p>
<calendar
uri="{ep:uri.ajax(action: 'range', controller: 'AjaxCalendar', extensionName: 'epproducts', pageUid: settings.defaultAjaxUid, arguments: '{hotel: product.calendarHotel}', format: 'html')}"
loader-uri="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif')}"
hotel-uid="{product.calendarHotel.uid}"
hotel-name="{product.calendarHotel.name}"
:months="1"
:show-header="false"
:step="1"
argument-prefix="{ep:argumentPrefix(pluginName: 'ajax', extensionName: 'epproducts')}"
></calendar>
</div>
<f:if condition="{hotel.groupsPriceConfigs}">
<f:else>
<f:link.typolink class="button button--full" parameter="{settings.groupsContactFormPageUid}" additionalParams="&ref={currentPageUid}">
Direkt zum Anfrageformular
</f:link.typolink>
</f:else>
</f:if>
</f:if>
</f:section>
</html>
@@ -47,7 +47,7 @@
</div>
</div>
</div>
<div x-data="fbpixel" data-fbpixel-props='{ "content_ids": [ {region.uid -> f:format.raw()} ], "content_name": "{region.nameInternal -> f:format.raw()}", "content_type": "product" }'></div>
<div x-data="fbpixel('{ "content_ids": [ {region.uid -> f:format.raw()} ], "content_name": "{region.nameInternal -> f:format.raw()}", "content_type": "product" }')"></div>
</f:section>
</html>
@@ -43,7 +43,7 @@
</f:section>
<f:section name="CollapsibleSimple">
<div class="panel panel-default" x-data="collapse" data-collapsed>
<div class="panel panel-default" x-data="collapse">
<div class="panel-heading">
<h4 class="panel-title">
<a role="button" href="#" x-bind="trigger">
@@ -77,7 +77,7 @@
</f:section>
<f:section name="CollapsibleHotel">
<div class="panel panel-default" x-data="collapse" data-collapsed>
<div class="panel panel-default" x-data="collapse">
<div class="panel-heading">
<h4 class="panel-title">
<a role="button" href="#" data-bind="trigger">
@@ -237,7 +237,7 @@
</f:section>
<f:section name="CollapsibleCity">
<div class="panel panel-default" x-data="collapse" data-collapsed>
<div class="panel panel-default" x-data="collapse">
<div class="panel-heading">
<h4 class="panel-title">
<a role="button" href="#" x-bind="trigger">
@@ -271,7 +271,7 @@
</f:section>
<f:section name="CollapsibleRegion">
<div class="panel panel-default" x-data="collapse" data-collapsed>
<div class="panel panel-default" x-data="collapse">
<div class="panel-heading">
<h4 class="panel-title">
<a role="button" href="#" x-bind="trigger">
@@ -333,7 +333,7 @@
</f:section>
<f:section name="CollapsibleImages">
<div class="panel panel-default" x-data="collapse" data-collapsed>
<div class="panel panel-default" x-data="collapse">
<div class="panel-heading">
<h4 class="panel-title">
<a role="button" href="#" x-bind="trigger">
@@ -14,7 +14,7 @@
:initial-filter-options='{filterOptions -> f:format.json() -> f:format.raw()}'
:date-presets='{settings.datePickerPresets -> f:format.json() -> f:format.raw()}'
inline-template>
<div class="container searchbar{f:if(condition: fixed, then: ' affix')}"{f:if(condition: fixed, else: ' x-data="sticky" data-offset="650" x-bind:class="sticky ? \'affix\': \'\'"')}>
<div class="container searchbar{f:if(condition: fixed, then: ' affix')}"{f:if(condition: fixed, else: ' x-data="sticky(650)" x-bind:class="sticky ? \'affix\': \'\'"')}>
<div class="container">
<f:form action="processSearch" controller="Search" method="post" name="searchParams"
object="{searchParams}" pluginName="searchresult" extensionName="epproducts"
@@ -5,6 +5,8 @@
<f:layout name="Default"/>
<f:section name="Main">
</f:section>
<f:section name="Main__">
<div id="searchbox" class="searchbox hidden-lg" x-data x-show="$store.show.searchBox" x-transition x-cloak>
<search-box
options-uri='<ep:uri.ajax controller="AjaxSearchbar" action="options" pageUid="{settings.defaultAjaxUid}" />'
@@ -21,7 +21,7 @@
</div>
<div class="container">
<div class="row">
<div class="col-md-3" x-data="collapse" data-collapse-until="991">
<div class="col-md-3" x-data="collapse(false, 991)">
<p class="lg:hidden">
<button class="button button--full button--small" role="button" x-bind="trigger">
<i class="fa fa-toggle-on"></i> Filter ein-/ausblenden