Render search result client side, loads of cleanups

This commit is contained in:
Björn Fromme
2018-08-21 19:22:05 +02:00
parent 6f50dcc612
commit 686f50fe11
32 changed files with 831 additions and 595 deletions
@@ -26,6 +26,7 @@
this.loading = false;
this.html = html;
$(this.$refs.trigger).remove();
EventBus.$emit('ajaxContentLoaded');
});
},
isInViewport ($triggerElement) {
@@ -42,11 +43,6 @@
}
}
},
watch: {
html () {
EventBus.$emit('ajaxContentLoaded');
}
},
mounted () {
const $triggerElement = $(this.$refs.trigger);
this.initContent($triggerElement);
@@ -14,7 +14,6 @@
import 'dayjs/locale/de'
export default {
template: '#productdetailtpl',
components: {
DatesTable,
PriceTable,
@@ -27,7 +26,6 @@
},
data () {
return {
lock: false,
datesRows: {},
altLabel: null,
altProductLink: null,
@@ -56,17 +54,13 @@
},
methods: {
loadDates () {
if (this.lock) {
return;
}
this.lock = true;
this.loading = true;
this.datesShow = true;
this.priceTableShow = false;
this.detailShow = false;
let query = {};
query[this.argumentPrefix + '[filterSettings]'] = this.filterSettings;
$.get(this.uris['dates'], query, (json) => {
$.post(this.uris['dates'], query, (json) => {
if (json.dates.length === 1) {
this.singleDate = true;
let dateRow = json.dates[0];
@@ -79,7 +73,7 @@
this.altProductLink = json.altProductLink;
this.loading = false;
}
this.lock = false;
EventBus.$emit('tableLoaded');
}, 'json');
},
@@ -102,6 +96,7 @@
this.dateEnd = dayjs(json.dateEnd).format('DD.MM.YYYY');
this.servicesIncluded = json.servicesIncluded;
this.loading = false;
EventBus.$emit('tableLoaded');
}, 'json');
},
loadPriceTableView (dateuid) {
@@ -120,6 +115,7 @@
if (scroll) {
this.scrollToMain();
}
EventBus.$emit('ajaxContentLoaded');
});
this.activeUri = uri;
},
@@ -127,23 +123,7 @@
EventBus.$emit('scrollTo', '#main');
}
},
watch: {
detailHtml () {
EventBus.$emit('ajaxContentLoaded');
},
datesRows () {
EventBus.$emit('tableLoaded');
},
priceTableRows () {
EventBus.$emit('tableLoaded');
}
},
created () {
EventBus.$on('dateRangeUpdate', (range) => {
this.filterSettings.dateFrom = (range.from !== null) ? dayjs(range.from).format('YYYY-MM-DD') : null;
this.filterSettings.dateTo = (range.to !== null) ? dayjs(range.to).format('YYYY-MM-DD') : null;
this.loadDates();
});
EventBus.$on('loadDatesTable', () => {
this.loadDatesView();
});
@@ -156,8 +136,7 @@
if (this.hotelFirst) {
this.loadHtml('hotel', false);
} else {
this.loadDates();
this.activeUri = 'dates';
this.loadDatesView();
}
});
}
@@ -1,5 +1,4 @@
<script>
import Vue from 'vue'
import $ from 'jquery'
import DaterangeSelect from './DaterangeSelect.vue'
import DestinationSelect from './DestinationSelect.vue'
@@ -13,9 +13,12 @@
import BoardTypesSelect from './BoardTypesSelect.vue'
import RoomTypesSelect from './RoomTypesSelect.vue'
import BusSelect from './BusSelect.vue'
import SearchResultItem from './SearchResultItem.vue'
import dayjs from 'dayjs'
import 'dayjs/locale/de'
import defaultFilterSettings from '../filtersettings'
export default {
components: {
DaterangeSelect,
@@ -28,15 +31,15 @@
HotelTypesSelect,
BoardTypesSelect,
RoomTypesSelect,
BusSelect
BusSelect,
SearchResultItem
},
data () {
return {
loading: false,
lock: false,
resultHtml: '',
resultData: {},
resultMeta: null,
filterCount: 0,
defaultFilterSettings: defaultFilterSettings,
filterSettings: this.initialFilterSettings,
filterOptions: this.initialFilterOptions
}
@@ -46,20 +49,16 @@
type: String,
required: true
},
optionsUri: {
type: String,
required: true
},
initialFilterSettings: {
type: Object,
default () {
return this.getDefaultFiltersettings();
return defaultFilterSettings;
}
},
initialFilterOptions: {
type: Object,
default () {
return this.getDefaultFiltersettings();
return defaultFilterSettings;
}
},
referringPageUid: {
@@ -100,6 +99,24 @@
info += 'ergab ' + this.resultMeta.total + ' Treffer';
}
return info;
},
filterCount () {
let count = 0;
if (this.filterSettings.destinationUid) count++;
if (this.filterSettings.destinationName) count++;
if (this.filterSettings.countryUids.length > 0) count++;
if (this.filterSettings.regionUids.length > 0) count++;
if (this.filterSettings.cityUids.length > 0) count++;
if (this.filterSettings.conceptUids.length > 0) count++;
if (this.filterSettings.hotelTypes.length > 0) count++;
if (this.filterSettings.boardTypes.length > 0) count++;
if (this.filterSettings.roomTypes.length > 0) count++;
if (this.filterSettings.dateFrom !== null) count++;
if (this.filterSettings.dateTo !== null) count++;
if (this.filterSettings.priceRange > 0) count++;
if (this.filterSettings.bus) count++;
if (this.filterSettings.pax > 2) count++;
return count;
}
},
methods: {
@@ -110,126 +127,37 @@
this.loading = true;
this.resultMeta = null;
$.post(this.resultsUri, query, (json) => {
this.resultHtml = json.html;
this.resultData = json.data;
this.filterOptions = json.filterOptions;
this.resultMeta = json.meta;
this.loading = false;
EventBus.$emit('ajaxContentLoaded');
});
},
applyFilterSettings () {
if (this.lock) {
return;
}
this.lock = true;
let query = {};
query[this.argumentPrefix + '[filterSettings]'] = this.filterSettings;
$.post(this.optionsUri, query, (json) => {
this.filterOptions = json;
this.lock = false;
this.updateFilterCount();
this.loadResults();
}, 'json');
},
cleanFilterSettings () {
this.filterSettings.productUid = 0;
this.filterSettings.hotelUid = 0;
this.filterSettings.destinationName = '';
this.filterSettings.destinationUid = 0;
this.filterSettings.destinationType = '';
this.origin = 'filter';
this.filterCount = 0;
},
resetFilterSettings () {
this.filterSettings = this.getDefaultFiltersettings();
this.applyFilterSettings();
this.updateFilterCount();
},
updateFilterCount () {
let count = 0;
if (this.filterSettings.destinationUid) {
count++;
}
if (this.filterSettings.destinationName) {
count++;
}
if (this.filterSettings.countryUids.length > 0) {
count++;
}
if (this.filterSettings.regionUids.length > 0) {
count++;
}
if (this.filterSettings.cityUids.length > 0) {
count++;
}
if (this.filterSettings.conceptUids.length > 0) {
count++;
}
if (this.filterSettings.hotelTypes.length > 0) {
count++;
}
if (this.filterSettings.boardTypes.length > 0) {
count++;
}
if (this.filterSettings.roomTypes.length > 0) {
count++;
}
if (this.filterSettings.dateFrom !== null) {
count++;
}
if (this.filterSettings.dateTo !== null) {
count++;
}
if (this.filterSettings.priceRange > 0) {
count++;
}
if (this.filterSettings.bus) {
count++;
}
if (this.filterSettings.pax > 2) {
count++;
}
this.filterCount = count;
},
getDefaultFiltersettings () {
return {
destinationName: '',
destinationUid: 0,
destinationType: '',
productUid: 0,
hotelUid: 0,
countryUids: [],
regionUids: [],
cityUids: [],
conceptUids: [],
dateFrom: null,
dateTo: null,
nights: 0,
pax: 1,
hotelTypes: [],
boardTypes: [],
roomTypes: [],
bus: false
};
this.filterSettings = this.defaultFilterSettings;
this.loadResults();
},
updateDestination (destination) {
this.filterSettings.destinationUid = destination.uid;
this.filterSettings.destinationType = destination.type;
this.filterSettings.destinationName = destination.name;
this.applyFilterSettings();
this.loadResults();
},
updateDestinations (destinations) {
this.filterSettings.countryUids = destinations.countryUids;
this.filterSettings.regionUids = destinations.regionUids;
this.applyFilterSettings();
this.loadResults();
},
updateConcepts (conceptUids) {
this.filterSettings.conceptUids = conceptUids;
this.applyFilterSettings();
this.loadResults();
},
updateDateRange (range) {
this.filterSettings.dateFrom = (range.from !== null) ? dayjs(range.from).format('YYYY-MM-DD') : null;
this.filterSettings.dateTo = (range.to !== null) ? dayjs(range.to).format('YYYY-MM-DD') : null;
this.applyFilterSettings();
this.loadResults();
},
updateDateSelectMobile () {
if (this.filterSettings.dateFrom === '') {
@@ -238,44 +166,36 @@
if (this.filterSettings.dateTo === '') {
this.filterSettings.dateTo = null;
}
this.applyFilterSettings();
this.loadResults();
},
updatePriceRange (range) {
this.filterSettings.priceRange = range;
this.applyFilterSettings();
this.loadResults();
},
updatePax (pax) {
this.filterSettings.pax = pax;
this.applyFilterSettings();
this.loadResults();
},
updateHotelTypes (hotelTypes) {
this.filterSettings.hotelTypes = hotelTypes;
this.applyFilterSettings();
this.loadResults();
},
updateBoardTypes (hotelTypes) {
this.filterSettings.boardTypes = hotelTypes;
this.applyFilterSettings();
this.loadResults();
},
updateRoomTypes (roomTypes) {
this.filterSettings.roomTypes = roomTypes;
this.applyFilterSettings();
this.loadResults();
},
updateBus (bus) {
this.filterSettings.bus = bus;
this.applyFilterSettings();
}
},
watch: {
loading (newValue, oldValue) {
if (newValue !== oldValue && newValue === false) {
EventBus.$emit('ajaxContentLoaded');
}
this.loadResults();
}
},
mounted () {
Vue.nextTick(() => {
this.loadResults();
this.updateFilterCount();
});
}
}
@@ -0,0 +1,116 @@
<template>
<div class="teaserbox teaserbox--landscape teaserbox--searchresult searchresult-item">
<div class="teaserbox__image">
<img class="teaserbox__flag" v-bind:src="item.country.flag" v-bind:alt="item.country.name"/>
<a v-bind:href="item.detailPageUri" rel="nofollow">
<picture class="searchresult-item__image">
<source media="(max-width: 768px)" v-bind:srcset="item.hotel.images.resized.s[0].url + ' 220w'"/>
<source media="(max-width: 1200px)" v-bind:srcset="item.hotel.images.resized.l[0].url + ' 280w'"/>
<source media="(min-width: 1201px)" v-bind:srcset="item.hotel.images.resized.m[0].url + ' 260w'"/>
<img class="scale" v-bind:src="item.hotel.images.resized.s[0].url"
v-bind:title="item.hotel.images.resized.s[0].title"
v-bind:alt="item.hotel.images.resized.s[0].alt">
</picture>
</a>
<div class="concept-badge" v-bind:id="section.concept.code"
v-bind:class=" 'concept-badge--' + section.concept.code">{{ section.concept.name }}</div>
</div>
<div class="teaserbox__main">
<div class="teaserbox__header">
<span class="searchresult-item__headline">
{{ item.region.name }}
<strong v-if="section.concept.code === 'evt'"><br>{{ item.product.name }}</strong>
</span>
<span class="searchresult-item__subline">{{ item.hotel.name }}</span>
<span class="searchresult-item__category" v-if="item.hotel.category">Kategorie {{ item.hotel.category }}</span>
</div>
<ul class="check-list searchresult-item__checklist">
<li v-if="item.hotel.fact">{{ item.hotel.fact }}</li>
<li v-if="item.product.fact">{{ item.product.fact }}</li>
<template v-if="item.region.feature">
<li>{{ item.region.feature }}</li>
</template>
<template v-else>
<li v-if="item.region.fact">{{ item.region.fact }}</li>
</template>
</ul>
<ul class="check-list check-list--inverted searchresult-item__featurelist">
<li>Skipass</li>
<li v-if="item.board">{{ item.board }}</li>
<li v-if="item.product.feature">{{ item.product.feature }}</li>
</ul>
</div>
<div class="teaserbox__aside">
<div class="teaserbox__aside__top">
<span class="searchresult-item__label">{{ item.dates.length > 1 ? 'Zeitraum' : 'Termin' }}</span>
<span class="searchresult-item__daterange">{{ dateRange }}</span>
<a v-bind:href="item.detailPageUri" rel="nofollow" v-if="item.dates.length">
<span class="searchresult-item__daterange">
<i class="fa fa-arrow-circle-right"></i> {{ item.dates.length }} Termin{{ item.dates.length > 1 ? 'e' : '' }}
</span>
</a>
<hr>
<span class="searchresult-item__label">{{ nightsOptions }}</span>
</div>
<div class="teaserbox__aside__bottom">
<span class="searchresult-item__price">ab {{ item.minPrice }} </span>
<a v-bind:href="item.detailPageUri" class="button button--full searchresult-item__button" rel="nofollow">
Details &amp; Buchen
</a>
</div>
</div>
</div>
</template>
<script>
import dayjs from 'dayjs'
import 'dayjs/locale/de'
export default {
props: {
item: {
type: Object,
required: true
},
section: {
type: Object,
required: true
}
},
computed: {
nightsOptions () {
const nights = this.item.nights;
if (nights === null) {
return '';
}
nights.sort();
const optionsCount = nights.length;
const lastOption = nights.pop();
let output = '';
if (optionsCount > 2) {
output += nights.join(',') + ' oder ' + lastOption;
} else if (optionsCount === 2) {
output += nights.shift() + ' oder ' + lastOption;
} else {
output = lastOption;
}
output += lastOption > 1 ? ' Nächte' : ' Nacht';
return output;
},
dateRange () {
const dateFrom = this.item.minDateStart;
const dateTo = this.item.maxDateEnd;
if (dateFrom === null && dateTo === null) {
return '';
}
if (dateFrom !== null && dateTo === null) {
return 'ab ' + dayjs(dateFrom).format('DD.MM.YYYY');
}
if (dateFrom === null && dateTo !== null) {
return '-' + dayjs(dateTo).format('DD.MM.YYYY');
}
return dayjs(dateFrom).format('DD.MM.YYYY') + '-' + dayjs(dateTo).format('DD.MM.YYYY');
}
}
}
</script>
@@ -0,0 +1,19 @@
export default {
destinationName: '',
destinationUid: 0,
destinationType: '',
productUid: 0,
hotelUid: 0,
countryUids: [],
regionUids: [],
cityUids: [],
conceptUids: [],
dateFrom: null,
dateTo: null,
nights: 0,
pax: 1,
hotelTypes: [],
boardTypes: [],
roomTypes: [],
bus: false
};
@@ -8,9 +8,9 @@
<f:link.page class="teaserbox teaserbox--hotel" pageUid="{hotel.detailPage}" title="{hotel.name}">
<div class="teaserbox__image">
<img class="teaserbox__flag"
src="{f:uri.image(src: '{ep:flagiconSource(countryCode: hotel.country.code)}')}"
src="{hotel.country.flag}"
alt="{country: hotel.country.name}"/>
<f:render partial="TeaserImage" arguments="{image: hotel.images.0}"/>
<f:render partial="TeaserImage" arguments="{image: hotel.images.original.0}"/>
</div>
<div class="teaserbox__main">
<span class="headline headline--3 headline--teaser">{hotel.name -> f:format.nl2br()}</span>
@@ -1,16 +1,14 @@
<html data-namespace-typo3-fluid="true" lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers"
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
<f:section name="Teaser">
<f:link.page class="teaserbox teaserbox--hotel" pageUid="{hotel.detailPage}" title="{hotel.name}">
<div class="teaserbox__image">
<img class="teaserbox__flag"
src="{f:uri.image(src: '{ep:flagiconSource(countryCode: hotel.country.code)}')}"
src="{hotel.country.flag}"
alt="{country: hotel.country.name}"/>
<f:render partial="TeaserImage" arguments="{image: hotel.images.0}"/>
<f:render partial="TeaserImage" arguments="{image: hotel.images.original.0}"/>
</div>
<div class="teaserbox__main">
<span class="headline headline--3 headline--teaser">{hotel.name -> f:format.nl2br()}</span>
@@ -1,16 +1,14 @@
<html data-namespace-typo3-fluid="true" lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers"
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
<f:section name="Teaser">
<f:link.page class="teaserbox teaserbox--hotel" pageUid="{hotel.detailPage}" title="{hotel.name}">
<div class="teaserbox__image">
<img class="teaserbox__flag"
src="{f:uri.image(src: '{ep:flagiconSource(countryCode: hotel.country.code)}')}"
src="{hotel.country.flag}"
alt="{hotel.country.name}"/>
<f:render partial="TeaserImage" arguments="{image: hotel.images.0}"/>
<f:render partial="TeaserImage" arguments="{image: hotel.images.original.0}"/>
</div>
<div class="teaserbox__main">
<span class="headline headline--3 headline--teaser">{hotel.name -> f:format.nl2br()}</span>
@@ -9,7 +9,7 @@
<div class="teaserbox teaserbox--landscape teaserbox--searchresult searchresult-item">
<div class="teaserbox__image">
<img class="teaserbox__flag"
src="{f:uri.image(src: '{ep:flagiconSource(countryCode: product.country.code)}')}"
src="{product.country.flag}"
alt="{product.country.name}"/>
<f:link.action
pageUid="{product.detailPage}"
@@ -28,10 +28,14 @@
</a>
<f:if condition="{data.tx_eptheme_hide_searchbar}">
<f:else>
<a v-on:click.prevent="toggleSearchbox()" class="search hidden-md hidden-lg" href="#" id="searchboxtoggle"><i class="fa fa-search" aria-hidden="true"></i></a>
<a v-on:click.prevent="toggleSearchbox()" class="search hidden-md hidden-lg" href="#" id="searchboxtoggle">
<i class="fa fa-search" aria-hidden="true"></i>
</a>
</f:else>
</f:if>
<a class="navbar-brand" href="{f:uri.page(pageUid: settings.defaultHomeUid)}" title=""><img class="logo" src="{f:uri.image(src: settings.logoImage)}" alt="{settings.defaultTitle}"></a>
<a class="navbar-brand" href="{f:uri.page(pageUid: settings.defaultHomeUid)}" title="">
<img class="logo" src="{f:uri.image(src: settings.logoImage)}" alt="{settings.defaultTitle}">
</a>
</div>
</f:section>
@@ -75,10 +79,14 @@
<li class="sectionhead">
<f:if condition="{subitem.doktype} == 3">
<f:then>
<a href="{subitem.url}" target="_blank" title="{subitem.linktext}">{f:if(condition: '{subitem.tx_eptheme_context_country_code}', then: '{f:image(src: \'{ep:flagiconSource(countryCode: subitem.tx_eptheme_context_country_code)}\', alt: subitem.tx_eptheme_context_country_code)}')}<span class="headline headline--4 headline--nav">{subitem.title}</span></a>
<a href="{subitem.url}" target="_blank" title="{subitem.linktext}">
{f:if(condition: '{subitem.tx_eptheme_context_country_code}', then: '{f:image(src: \'{ep:flagiconSource(countryCode: subitem.tx_eptheme_context_country_code)}\', alt: subitem.tx_eptheme_context_country_code)}')}<span class="headline headline--4 headline--nav">{subitem.title}</span>
</a>
</f:then>
<f:else>
<a href="{f:uri.page(pageUid: subitem.uid)}">{f:if(condition: '{subitem.tx_eptheme_context_country_code}', then: '{f:image(src: \'{ep:flagiconSource(countryCode: subitem.tx_eptheme_context_country_code)}\', alt: subitem.tx_eptheme_context_country_code)}')}<span class="headline headline--4 headline--nav">{subitem.title}</span></a>
<a href="{f:uri.page(pageUid: subitem.uid)}">
{f:if(condition: '{subitem.tx_eptheme_context_country_code}', then: '{f:image(src: \'{ep:flagiconSource(countryCode: subitem.tx_eptheme_context_country_code)}\', alt: subitem.tx_eptheme_context_country_code)}')}<span class="headline headline--4 headline--nav">{subitem.title}</span>
</a>
</f:else>
</f:if>
</li>
@@ -36,9 +36,9 @@
<div class="teaserbox__side teaserbox__side--front">
<div class="teaserbox__image">
<img class="teaserbox__flag"
src="{f:uri.image(src: '{ep:flagiconSource(countryCode: teaser.country.code)}')}"
src="{teaser.country.flag}"
alt="{teaser.country.name}"/>
<f:render partial="TeaserImage" arguments="{image: teaser.product.images.0}"/>
<f:render partial="TeaserImage" arguments="{image: teaser.product.images.original.0}"/>
</div>
<f:if condition="{teaser.concept.code}">
<div class="concept-badge concept-badge--{teaser.concept.code}">{teaser.concept.name}</div>
@@ -20,7 +20,7 @@
<div class="teaserbox teaserbox--landscape teaserbox--product col-xs-12">
<div class="teaserbox__image">
<img class="teaserbox__flag"
src="{f:uri.image(src: '{ep:flagiconSource(countryCode: teaser.country.code)}')}"
src="{teaser.country.flag}"
alt="{teaser.country.name}"/>
<a href="{uriLink}" title="{teaser.product.name}">
<f:render section="Image" arguments="{_all}"/>
@@ -100,10 +100,10 @@
<f:section name="Image">
<f:if condition="{teaser.hotelCount} > 1">
<f:then>
<f:render section="PictureTag" arguments="{image: teaser.product.images.0}"/>
<f:render section="PictureTag" arguments="{image: teaser.product.images.original.0}"/>
</f:then>
<f:else>
<f:render section="PictureTag" arguments="{image: teaser.hotel.images.0}"/>
<f:render section="PictureTag" arguments="{image: teaser.hotel.images.original.0}"/>
</f:else>
</f:if>
</f:section>
@@ -1,175 +0,0 @@
<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"
xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers">
<f:layout name="Default"/>
<f:section name="Main">
<a id="resulttop" class="anchor"></a>
<f:for each="{searchResult.data}" as="section">
<a id="concept-{section.concept.uid}" class="anchor"></a>
<h2 class="headline headline--secondary headline--underlined">{section.concept.name}</h2>
<div class="searchresult-section searchresult-section--{section.concept.code}">
<f:for each="{section.items}" as="item">
<f:render section="Hotel" arguments="{_all}"/>
</f:for>
</div>
</f:for>
</f:section>
<f:section name="Hotel">
<div class="teaserbox teaserbox--landscape teaserbox--searchresult searchresult-item">
<div class="teaserbox__image">
<img class="teaserbox__flag"
src="{f:uri.image(src: '{ep:flagiconSource(countryCode: item.country.code)}')}"
alt="{item.country.name}"/>
<f:link.action
pageUid="{item.product.detailPage}"
action="detail"
controller="Product"
arguments="{
product: item.product.uid,
hotel: item.hotel.uid,
referringPageUid: referringPageUid,
filterSettings: '{filterSettings -> ep:filterSettingsEncoder()}'
}"
additionalAttributes="{rel: 'nofollow'}"
>
<f:render section="Image" arguments="{_all}"/>
</f:link.action>
<f:if condition="{section.concept.code}">
<div class="concept-badge concept-badge--{section.concept.code}">{section.concept.name}</div>
</f:if>
</div>
<div class="teaserbox__main">
<div class="teaserbox__header">
<span class="searchresult-item__headline">
{item.region.name}<f:if condition="{section.concept.code} == 'evt'"><strong><br>{item.product.name}</strong></f:if>
</span>
<span class="searchresult-item__subline">{item.hotel.name}</span>
<f:if condition="{item.hotel.category}">
<span class="searchresult-item__category">Kategorie {item.hotel.category}</span>
</f:if>
</div>
<ul class="check-list searchresult-item__checklist">
<f:if condition="{item.hotel.fact}">
<li>{item.hotel.fact}</li>
</f:if>
<f:if condition="{item.product.fact}">
<li>{item.product.fact}</li>
</f:if>
<f:if condition="{item.region.feature}">
<f:then>
<li>{item.region.feature}</li>
</f:then>
<f:else>
<f:if condition="{item.region.fact}">
<li>{item.region.fact}</li>
</f:if>
</f:else>
</f:if>
</ul>
<ul class="check-list check-list--inverted searchresult-item__featurelist">
<li>Skipass</li>
<f:if condition="{item.board}">
<li>{item.board}</li>
</f:if>
<f:if condition="{item.product.feature}">
<li>{item.product.feature}</li>
</f:if>
</ul>
</div>
<div class="teaserbox__aside">
<div class="teaserbox__aside__top">
<span class="searchresult-item__label">{f:if(condition: '{item.dates -> f:count()} > 1', then: 'Zeitraum', else: 'Termin')}</span>
<span class="searchresult-item__daterange">{ep:dateRange(dateFrom: item.minDateStart, dateTo: item.maxDateEnd, includeLabel: 0)}</span>
<f:if condition="{item.dates -> f:count()} > 1">
<f:link.action
pageUid="{item.product.detailPage -> v:or(alternative: detailPageUid)}"
action="detail"
controller="Product"
arguments="{
product: item.product.uid,
hotel: item.hotel.uid,
referringPageUid: referringPageUid,
filterSettings: '{filterSettings -> ep:filterSettingsEncoder()}'
}"
additionalAttributes="{rel: 'nofollow'}"
>
<span class="searchresult-item__daterange">
<i class="fa fa-arrow-circle-right"></i> {item.dates -> f:count()} Termin{f:if(condition: '{item.dates -> f:count()} > 1', then: 'e')}
</span>
</f:link.action>
</f:if>
<hr>
<span class="searchresult-item__label">{ep:nightsOptions(options: item.nights)}</span>
</div>
<div class="teaserbox__aside__bottom">
<span class="searchresult-item__price">ab {item.minPrice} €</span>
<f:link.action
pageUid="{item.product.detailPage -> v:or(alternative: detailPageUid)}"
action="detail"
controller="Product"
arguments="{
product: item.product.uid,
hotel: item.hotel.uid,
referringPageUid: referringPageUid,
filterSettings: '{filterSettings -> ep:filterSettingsEncoder()}'
}"
additionalAttributes="{rel: 'nofollow'}"
class="button button--full searchresult-item__button"
>Details &amp; Buchen</f:link.action>
</div>
</div>
</div>
</f:section>
<f:section name="Image">
<f:if condition="{item.hotel.images}">
<f:then>
<f:alias map="{image: item.hotel.images.0}">
<picture class="searchresult-item__image">
<source media="(max-width: 768px)" srcset="{f:uri.image(
src: image.uid, treatIdAsReference: 1,
crop: image.crop, width: '220', height: '130c-100'
)} 220w"/>
<source media="(max-width: 1200px)" srcset="{f:uri.image(
src: image.uid, treatIdAsReference: 1,
crop: image.crop, width: '280', height: '220c-100'
)} 280w"/>
<source media="(min-width: 1201px)" srcset="{f:uri.image(
src: image.uid, treatIdAsReference: 1,
crop: image.crop, width: '260', height: '200c-100'
)} 260w"/>
<img class="scale" src="{f:uri.image(
src: image.uid, treatIdAsReference: 1,
crop: image.crop, width: '260', height: '200c-100'
)}" title="{image.title}" alt="{image.alternative}">
</picture>
</f:alias>
</f:then>
<f:else>
<picture class="searchresult-item__image">
<source media="(max-width: 768px)" srcset="{f:uri.image(
src: 'EXT:ep_theme/Resources/Public/images/header-winter.jpg',
width: '220', height: '130c-100'
)} 220w"/>
<source media="(max-width: 1200px)" srcset="{f:uri.image(
src: 'EXT:ep_theme/Resources/Public/images/header-winter.jpg',
width: '280', height: '220c-100'
)} 280w"/>
<source media="(min-width: 1201px)" srcset="{f:uri.image(
src: 'EXT:ep_theme/Resources/Public/images/header-winter.jpg',
width: '260', height: '200c-100'
)} 260w"/>
<img class="scale" src="{f:uri.image(
src: 'EXT:ep_theme/Resources/Public/images/header-winter.jpg',
width: '260', height: '200c-100'
)}" title="" alt="">
</picture>
</f:else>
</f:if>
</f:section>
</html>
@@ -9,6 +9,7 @@
<f:section name="Main">
<f:render partial="Product/HeaderDetail" arguments="{_all}"/>
<div class="container" id="detail">
<noscript><h1>{product.headline}</h1></noscript>
<product-detail
:filter-settings='<v:format.json.encode>{filterSettings}</v:format.json.encode>'
:uris='{
@@ -22,9 +23,7 @@
argument-prefix='<ep:argumentPrefix pluginName="Ajax" />'
:hotel-first="{f:if(condition: settings.hotelOnTop, then: 'true', else: 'false')}"
:fb-pixel-data="{ productUid: <f:format.raw>{product.uid}</f:format.raw>, nameInternal: '<f:format.raw>{product.nameInternal}</f:format.raw>' }"
></product-detail>
<noscript><h1>{product.headline}</h1></noscript>
<script type="text/x-template" id="productdetailtpl">
inline-template>
<div class="product-detail-wrapper">
<div class="row">
<div class="col-md-12">
@@ -191,7 +190,7 @@
</div>
<facebook-pixel :values="{ content_ids: [ fbPixelData.productUid ], content_name: fbPixelData.nameInternal, content_type: 'product' }"></facebook-pixel>
</div>
</script>
</product-detail>
</div>
<f:render partial="Faq" arguments="{faqs: product.faqs, settings: settings}"/>
</f:section>
@@ -1,6 +1,5 @@
<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"
xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers">
<f:layout name="Default"/>
@@ -9,7 +9,6 @@
<div id="search">
<search-result
results-uri="{ep:uri.ajax(action: 'searchresult', controller: 'AjaxSearch', format: 'json', noCacheHash: 1)}"
options-uri="{ep:uri.ajax(action: 'options', controller: 'AjaxFilterpanel', format: 'json', noCacheHash: 1)}"
:initial-filter-settings='<v:format.json.encode>{filterSettings}</v:format.json.encode>'
:initial-filter-options='<v:format.json.encode>{filterOptions}</v:format.json.encode>'
:referring-page-uid="{referringPageUid}"
@@ -282,7 +281,19 @@
</div>
<div class="col-md-9 ajaxtarget searchresult" v-cloak>
<div class="searchresult__info alert alert-info" v-html="resultInfo"></div>
<div class="searchresult__content" v-html="resultHtml"></div>
<div class="searchresult__content">
<template v-for="section in resultData">
<a v-bind:id="'concept-' + section.concept.uid" class="anchor"></a>
<h2 class="headline headline--secondary headline--underlined">{{ section.concept.name }}</h2>
<div class="searchresult-section" v-bind:class="'searchresult-section--' + section.concept.code">
<search-result-item
v-for="item in section.items"
v-bind:key="item.key"
v-bind:item="item"
v-bind:section="section"></search-result-item>
</div>
</template>
</div>
<div v-show="loading" class="loader">
<f:image src="EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif" alt="Loading"/>
</div>