WIP Migrate to stimulus.js and tailwind
This commit is contained in:
@@ -86,6 +86,15 @@ class AjaxSearchController extends ActionController
|
|||||||
->searchResultService
|
->searchResultService
|
||||||
->getResult($filterSettings, $excludedConceptUids);
|
->getResult($filterSettings, $excludedConceptUids);
|
||||||
|
|
||||||
|
// No results? First retry without date constraint if any
|
||||||
|
if ((!empty($filterSettings['dateFrom']) || !empty($filterSettings['dateTo'])) && 0 === $searchResult->getTotal()) {
|
||||||
|
$filterSettings['dateFrom'] = null;
|
||||||
|
$filterSettings['dateTo'] = null;
|
||||||
|
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
||||||
|
$organic = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Still no results? Remove all constraints and search again with defaults
|
||||||
if (0 === $searchResult->getTotal()) {
|
if (0 === $searchResult->getTotal()) {
|
||||||
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
|
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
|
||||||
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
||||||
|
|||||||
@@ -136,9 +136,20 @@ class SearchController extends ActionController
|
|||||||
$dateSelected = true;
|
$dateSelected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
$searchResult = $this
|
||||||
|
->searchResultService
|
||||||
|
->getResult($filterSettings, $excludedConceptUids);
|
||||||
|
|
||||||
if ($searchResult->getTotal() === 0) {
|
// No results? First retry without date constraint if any
|
||||||
|
if ((!empty($filterSettings['dateFrom']) || !empty($filterSettings['dateTo'])) && 0 === $searchResult->getTotal()) {
|
||||||
|
$filterSettings['dateFrom'] = null;
|
||||||
|
$filterSettings['dateTo'] = null;
|
||||||
|
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
||||||
|
$organic = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Still no results? Remove all constraints and search again with defaults
|
||||||
|
if (0 === $searchResult->getTotal()) {
|
||||||
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
|
$filterSettings = $this->filterService->getNormalizedFilterSettings([], $forcedConceptUids);
|
||||||
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
|
||||||
$organic = false;
|
$organic = false;
|
||||||
|
|||||||
+1
-3
@@ -33,7 +33,7 @@ use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
|
|||||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||||
|
|
||||||
class AjaxSearchbarController extends ActionController
|
class SearchbarController extends ActionController
|
||||||
{
|
{
|
||||||
|
|
||||||
use RequestArgumentTypeConversionTrait;
|
use RequestArgumentTypeConversionTrait;
|
||||||
@@ -66,7 +66,6 @@ class AjaxSearchbarController extends ActionController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $searchParams
|
* @param array $searchParams
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function indexAction(array $searchParams)
|
public function indexAction(array $searchParams)
|
||||||
{
|
{
|
||||||
@@ -83,7 +82,6 @@ class AjaxSearchbarController extends ActionController
|
|||||||
);
|
);
|
||||||
|
|
||||||
$this->view->assignMultiple([
|
$this->view->assignMultiple([
|
||||||
'filterSettings' => $filterSettings,
|
|
||||||
'filterOptions' => $filterOptions,
|
'filterOptions' => $filterOptions,
|
||||||
'searchParams' => $searchParams,
|
'searchParams' => $searchParams,
|
||||||
'fixed' => $fixed,
|
'fixed' => $fixed,
|
||||||
@@ -156,9 +156,6 @@ tx_epproducts_ajax_json {
|
|||||||
AjaxDate {
|
AjaxDate {
|
||||||
1 = dates
|
1 = dates
|
||||||
}
|
}
|
||||||
AjaxSearchbar {
|
|
||||||
1 = index
|
|
||||||
}
|
|
||||||
AjaxTable {
|
AjaxTable {
|
||||||
1 = datestable
|
1 = datestable
|
||||||
2 = pricetable
|
2 = pricetable
|
||||||
|
|||||||
@@ -25,12 +25,6 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\T
|
|||||||
'description' => 'Importiert Schneehöhen',
|
'description' => 'Importiert Schneehöhen',
|
||||||
];
|
];
|
||||||
|
|
||||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\Task\GroupsSwissTask::class] = [
|
|
||||||
'extension' => $_EXTKEY,
|
|
||||||
'title' => 'EP Groups Swiss Export',
|
|
||||||
'description' => 'Publiziert Verfügbarkeiten nach groups.swiss',
|
|
||||||
];
|
|
||||||
|
|
||||||
$GLOBALS['TYPO3_CONF_VARS']['LOG']['EP']['EpProducts']['Service']['GroupsSwissService']['writerConfiguration'] = [
|
$GLOBALS['TYPO3_CONF_VARS']['LOG']['EP']['EpProducts']['Service']['GroupsSwissService']['writerConfiguration'] = [
|
||||||
\TYPO3\CMS\Core\Log\LogLevel::INFO => [
|
\TYPO3\CMS\Core\Log\LogLevel::INFO => [
|
||||||
'TYPO3\\CMS\\Core\\Log\\Writer\\FileWriter' => [
|
'TYPO3\\CMS\\Core\\Log\\Writer\\FileWriter' => [
|
||||||
@@ -50,10 +44,10 @@ $iconRegistry->registerIcon(
|
|||||||
'EP.' . $_EXTKEY,
|
'EP.' . $_EXTKEY,
|
||||||
'searchbar',
|
'searchbar',
|
||||||
[
|
[
|
||||||
'Search' => 'searchbar',
|
'Searchbar' => 'index',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'Search' => '',
|
'Searchbar' => 'index',
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -371,7 +365,6 @@ $iconRegistry->registerIcon(
|
|||||||
[
|
[
|
||||||
'AjaxSearch' => 'searchresult',
|
'AjaxSearch' => 'searchresult',
|
||||||
'AjaxDate' => 'dates',
|
'AjaxDate' => 'dates',
|
||||||
'AjaxSearchbar' => 'index',
|
|
||||||
'AjaxContingent' => 'list,rooms',
|
'AjaxContingent' => 'list,rooms',
|
||||||
'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable',
|
'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable',
|
||||||
'AjaxCalendar' => 'range,contingents,availableRooms',
|
'AjaxCalendar' => 'range,contingents,availableRooms',
|
||||||
@@ -381,7 +374,6 @@ $iconRegistry->registerIcon(
|
|||||||
[
|
[
|
||||||
'AjaxSearch' => 'searchresult',
|
'AjaxSearch' => 'searchresult',
|
||||||
'AjaxDate' => 'dates',
|
'AjaxDate' => 'dates',
|
||||||
'AjaxSearchbar' => 'index',
|
|
||||||
'AjaxContingent' => 'list,rooms',
|
'AjaxContingent' => 'list,rooms',
|
||||||
// 'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable',
|
// 'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable',
|
||||||
'AjaxCalendar' => 'range,contingents,availableRooms',
|
'AjaxCalendar' => 'range,contingents,availableRooms',
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ lib.searchBar {
|
|||||||
extensionName = EpProducts
|
extensionName = EpProducts
|
||||||
pluginName = searchbar
|
pluginName = searchbar
|
||||||
vendorName = EP
|
vendorName = EP
|
||||||
controller = Search
|
controller = Searchbar
|
||||||
action = searchbar
|
action = index
|
||||||
switchableControllerActions {
|
switchableControllerActions {
|
||||||
Search {
|
Searchbar {
|
||||||
1 = searchbar
|
1 = index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
settings =< plugin.tx_epproducts.settings
|
settings =< plugin.tx_epproducts.settings
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,5 @@
|
|||||||
import { Controller } from 'stimulus'
|
import { Controller } from 'stimulus'
|
||||||
import { useWindowResize, useDebounce } from 'stimulus-use'
|
import { useWindowResize, useDebounce, useClickOutside } from 'stimulus-use'
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ export default class extends Controller {
|
|||||||
initialize() {
|
initialize() {
|
||||||
useWindowResize(this)
|
useWindowResize(this)
|
||||||
useDebounce(this)
|
useDebounce(this)
|
||||||
|
useClickOutside(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
|
|||||||
+36
-14
@@ -5,7 +5,11 @@ import { German } from 'flatpickr/dist/l10n/de'
|
|||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
|
|
||||||
static targets = [ 'field' ]
|
static targets = [
|
||||||
|
'field',
|
||||||
|
'dateFrom',
|
||||||
|
'dateTo',
|
||||||
|
]
|
||||||
|
|
||||||
static values = {
|
static values = {
|
||||||
minDate: String,
|
minDate: String,
|
||||||
@@ -23,13 +27,9 @@ export default class extends Controller {
|
|||||||
minDate: this.minDateValue,
|
minDate: this.minDateValue,
|
||||||
onChange: selectedDates => {
|
onChange: selectedDates => {
|
||||||
if (selectedDates.length === 2) {
|
if (selectedDates.length === 2) {
|
||||||
let dateFrom = flatpickr.formatDate(selectedDates[0], 'Y-m-d')
|
this.dateFromValue = flatpickr.formatDate(selectedDates[0], 'Y-m-d')
|
||||||
let dateTo = flatpickr.formatDate(selectedDates[1], 'Y-m-d')
|
this.dateToValue = flatpickr.formatDate(selectedDates[1], 'Y-m-d')
|
||||||
this.dispatch('range-select', {
|
this.update()
|
||||||
from: dateFrom,
|
|
||||||
to: dateTo,
|
|
||||||
label: `${dateFrom} - ${dateTo}`
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -46,20 +46,42 @@ export default class extends Controller {
|
|||||||
selectPreset(e) {
|
selectPreset(e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const preset = JSON.parse(e.currentTarget.dataset.preset)
|
const preset = JSON.parse(e.currentTarget.dataset.preset)
|
||||||
|
this.dateFromValue = preset.dateFrom
|
||||||
|
this.dateToValue = preset.dateTo
|
||||||
let dateFrom = new Date(preset.dateFrom)
|
let dateFrom = new Date(preset.dateFrom)
|
||||||
let dateTo = new Date(preset.dateTo)
|
let dateTo = new Date(preset.dateTo)
|
||||||
this.picker.setDate([ dateFrom, dateTo ])
|
this.picker.setDate([ dateFrom, dateTo ])
|
||||||
this.dispatch('range-select', {
|
this.update()
|
||||||
from: preset.dateFrom,
|
|
||||||
to: preset.dateTo,
|
|
||||||
label: `${flatpickr.formatDate(dateFrom, 'd.m.Y')} - ${flatpickr.formatDate(dateTo, 'd.m.Y')}`
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset(e) {
|
reset(e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.picker.clear()
|
this.picker.clear()
|
||||||
this.picker.jumpToDate()
|
this.picker.jumpToDate()
|
||||||
this.dispatch('range-select', { from: null, to: null, label: null })
|
this.dateFromValue = ''
|
||||||
|
this.dateToValue = ''
|
||||||
|
this.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
// Set values to form fields if applicable
|
||||||
|
if (this.hasDateFromTarget) {
|
||||||
|
this.dateFromTarget.value = this.dateFromValue
|
||||||
|
}
|
||||||
|
if (this.hasDateToTarget) {
|
||||||
|
this.dateToTarget.value = this.dateToValue
|
||||||
|
}
|
||||||
|
// Dispatch event with selected values and formatted range label
|
||||||
|
let label = ''
|
||||||
|
if (this.dateFromValue && this.dateToValue) {
|
||||||
|
let dateFrom = new Date(this.dateFromValue)
|
||||||
|
let dateTo = new Date(this.dateToValue)
|
||||||
|
label = `${flatpickr.formatDate(dateFrom, 'd.m.Y')}-${flatpickr.formatDate(dateTo, 'd.m.Y')}`
|
||||||
|
}
|
||||||
|
this.dispatch('range-select', {
|
||||||
|
from: this.dateFromValue,
|
||||||
|
to: this.dateToValue,
|
||||||
|
label
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-37
@@ -1,56 +1,60 @@
|
|||||||
import { Controller } from 'stimulus'
|
import { Controller } from 'stimulus'
|
||||||
import { useFetch } from '../mixins/use_fetch'
|
import { useDispatch } from 'stimulus-use'
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
|
|
||||||
static targets = [
|
static targets = [
|
||||||
'container',
|
|
||||||
'form',
|
|
||||||
'destinationUid',
|
|
||||||
'destinationType',
|
|
||||||
'dateFrom',
|
'dateFrom',
|
||||||
'dateTo',
|
'dateTo',
|
||||||
'nights',
|
'destinationUid',
|
||||||
|
'destinationType',
|
||||||
'pax',
|
'pax',
|
||||||
'priceRange',
|
'priceRange',
|
||||||
'dateRangeLabel'
|
'dateRangeLabel',
|
||||||
|
'paxLabel',
|
||||||
|
'destinationLabel',
|
||||||
|
'priceRangeLabel',
|
||||||
]
|
]
|
||||||
|
|
||||||
static values = {
|
|
||||||
uri: String,
|
|
||||||
loading: Boolean,
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
useFetch(this)
|
useDispatch(this)
|
||||||
}
|
|
||||||
|
|
||||||
connect() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
load() {
|
|
||||||
this.loadingValue = true
|
|
||||||
let data = new URLSearchParams()
|
|
||||||
data.set('tx_epproducts_ajax[searchParams]', JSON.stringify({
|
|
||||||
dateFrom: this.dateFromTarget.value,
|
|
||||||
dateTo: this.dateToTarget.value,
|
|
||||||
}))
|
|
||||||
fetch(this.uriValue, { method: 'POST', body: data })
|
|
||||||
.then(this.checkStatus)
|
|
||||||
.then(this.parseHTML)
|
|
||||||
.then(html => {
|
|
||||||
this.containerTarget.innerHTML = html
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loadingValue = false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setDateRange(e) {
|
setDateRange(e) {
|
||||||
|
this.dateRangeLabelTarget.value = e.detail.label
|
||||||
this.dateFromTarget.value = e.detail.from
|
this.dateFromTarget.value = e.detail.from
|
||||||
this.dateToTarget.value = e.detail.to
|
this.dateToTarget.value = e.detail.to
|
||||||
this.dateRangeLabelTarget.value = e.detail.label
|
this.dispatch('input')
|
||||||
this.load()
|
}
|
||||||
|
|
||||||
|
setPax(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
let pax = e.currentTarget.dataset.option
|
||||||
|
this.paxTarget.value = pax
|
||||||
|
this.paxLabelTarget.value = pax
|
||||||
|
this.dispatch('input')
|
||||||
|
}
|
||||||
|
|
||||||
|
setDestination(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.destinationUidTarget.value = e.currentTarget.dataset.optionUid
|
||||||
|
this.destinationTypeTarget.value = e.currentTarget.dataset.optionType
|
||||||
|
this.destinationLabelTarget.value = e.currentTarget.dataset.optionLabel
|
||||||
|
this.dispatch('input')
|
||||||
|
}
|
||||||
|
|
||||||
|
resetDestination(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.destinationUidTarget.value = ''
|
||||||
|
this.destinationTypeTarget.value = ''
|
||||||
|
this.destinationLabelTarget.value = ''
|
||||||
|
this.dispatch('input')
|
||||||
|
}
|
||||||
|
|
||||||
|
setPriceRange(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.priceRangeTarget.value = e.currentTarget.dataset.optionValue
|
||||||
|
this.priceRangeLabelTarget.value = e.currentTarget.dataset.labelValue
|
||||||
|
this.dispatch('input')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,212 +0,0 @@
|
|||||||
<html data-namespace-typo3-fluid="true" lang="en"
|
|
||||||
xmlns="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers"
|
|
||||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
|
||||||
|
|
||||||
<div class="searchbar {f:if(condition: fixed, then: ' sticky')}"
|
|
||||||
data-searchbar-target="container"
|
|
||||||
{f:if(condition: fixed, else: ' data-controller="sticky" data-sticky-offset-value="650" data-sticky-sticky-class="sticky"')}>
|
|
||||||
<f:form action="processSearch" controller="Search" method="post" name="searchParams"
|
|
||||||
object="{searchParams}" pluginName="searchresult" extensionName="epproducts"
|
|
||||||
pageUid="{settings.defaultSearchPageUid}" data="{'searchbar-target': 'form'}">
|
|
||||||
<f:form.hidden property="destinationUid" data="{'searchbar-target': 'destinationUid'}"/>
|
|
||||||
<f:form.hidden property="destinationType" data="{'searchbar-target': 'destinationType'}"/>
|
|
||||||
<f:form.hidden property="dateFrom" data="{'searchbar-target': 'dateFrom'}"/>
|
|
||||||
<f:form.hidden property="dateTo" data="{'searchbar-target': 'dateTo'}"/>
|
|
||||||
<f:form.hidden property="nights" data="{'searchbar-target': 'nights'}"/>
|
|
||||||
<f:form.hidden property="pax" data="{'searchbar-target': 'pax'}"/>
|
|
||||||
<f:form.hidden property="priceRange" data="{'searchbar-target': 'priceRange'}"/>
|
|
||||||
<div class="sticky:max-w-screen-xl sticky:mx-auto flex flex-col sticky:flex-row sticky:items-center">
|
|
||||||
<div class="flex items-start justify-between sticky:flex-1 pt-8 px-8 sticky:py-4 sticky:px-0">
|
|
||||||
<div class="flex-1"
|
|
||||||
data-controller="collapse"
|
|
||||||
data-collapse-collapsed-value="true">
|
|
||||||
<div class="relative border-b border-r border-white mr-8">
|
|
||||||
<input type="text"
|
|
||||||
data-action="click->collapse#toggle"
|
|
||||||
class="w-full bg-transparent border-0 ring-0 focus:ring-0 text-white uppercase px-2 py-1 cursor-pointer placeholder-white"
|
|
||||||
placeholder="Zeitraum"
|
|
||||||
data-searchbar-target="dateRangeLabel"/>
|
|
||||||
<svg class="w-6 h-6 text-white absolute right-0 top-0 mr-2 mt-1">
|
|
||||||
<use href="#icon-calendar"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="hidden absolute z-20 top-100 mt-2 left-0 bg-white p-4 shadow-md"
|
|
||||||
data-collapse-target="container"
|
|
||||||
data-controller="datepicker"
|
|
||||||
<f:if condition="{filterSettings.dateFrom} && {filterSettings.dateTo}">
|
|
||||||
data-datepicker-date-from-value="{filterSettings.dateFrom}"
|
|
||||||
data-datepicker-date-to-value="{filterSettings.dateTo}"
|
|
||||||
</f:if>
|
|
||||||
data-datepicker-min-date-value="{filterOptions.dateFrom}"
|
|
||||||
data-datepicker-max-date-value="{filterOptions.dateTo}">
|
|
||||||
<f:if condition="{settings.datePickerPresets}">
|
|
||||||
<div class="flex items-center justify-between pb-2">
|
|
||||||
<f:for each="{settings.datePickerPresets}" as="preset">
|
|
||||||
<button class="daterange__preset"
|
|
||||||
data-preset='{preset -> f:format.json()}'
|
|
||||||
data-action="datepicker#selectPreset">
|
|
||||||
<span>
|
|
||||||
{preset.label}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</f:for>
|
|
||||||
</div>
|
|
||||||
</f:if>
|
|
||||||
<input type="hidden"
|
|
||||||
data-datepicker-target="field">
|
|
||||||
<div class="flex items-center justify-between pt-2">
|
|
||||||
<button class="daterange__button focus:outline-none"
|
|
||||||
data-action="collapse#close">
|
|
||||||
schließen
|
|
||||||
</button>
|
|
||||||
<button class="daterange__button focus:outline-none"
|
|
||||||
data-action="datepicker#reset">
|
|
||||||
zurücksetzen
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-24"
|
|
||||||
data-controller="collapse"
|
|
||||||
data-collapse-collapsed-value="true">
|
|
||||||
<div class="relative border-b border-r border-white mr-8">
|
|
||||||
<input type="text"
|
|
||||||
data-action="click->collapse#toggle"
|
|
||||||
class="w-full bg-transparent border-0 ring-0 focus:ring-0 text-white uppercase px-2 py-1 cursor-pointer"/>
|
|
||||||
<svg class="w-6 h-6 text-white absolute right-0 top-0 mr-2 mt-1">
|
|
||||||
<use href="#icon-user-group"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="hidden absolute top-100 mt-2 left-0 bg-white p-4 shadow-md w-full h-48 overflow-y-scroll"
|
|
||||||
data-collapse-target="container">
|
|
||||||
<ul class="m-0 p-0">
|
|
||||||
<f:for each="{filterOptions.pax}" as="option">
|
|
||||||
<li>
|
|
||||||
<a href="#" data-option-value="{option}">
|
|
||||||
{option}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</f:for>
|
|
||||||
<li>
|
|
||||||
<a href="{f:uri.typolink(parameter: settings.groupsPageUid)}">
|
|
||||||
> 20
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-1"
|
|
||||||
data-controller="collapse"
|
|
||||||
data-collapse-collapsed-value="true">
|
|
||||||
<div class="relative border-b border-r border-white mr-8">
|
|
||||||
<input type="text"
|
|
||||||
data-action="click->collapse#toggle"
|
|
||||||
class="w-full bg-transparent border-0 ring-0 focus:ring-0 text-white uppercase px-2 py-1 cursor-pointer placeholder-white"
|
|
||||||
placeholder="Reiseziel"/>
|
|
||||||
<svg class="w-6 h-6 text-white absolute right-0 top-0 mr-2 mt-1 transform rotate-45">
|
|
||||||
<use href="#icon-airplane"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="hidden absolute top-100 left-0 bg-white p-4 shadow-md min-w-full h-48 overflow-y-scroll"
|
|
||||||
data-collapse-target="container">
|
|
||||||
<f:for each="{filterOptions.destinations}" as="destination">
|
|
||||||
<div class="flex items-start justify-between">
|
|
||||||
<div class="w-1/2">
|
|
||||||
<a href="#">
|
|
||||||
<svg class="block w-8 h-6">
|
|
||||||
<use href="#icon-flag-{destination.country.code -> f:format.case(mode: 'lower')}"/>
|
|
||||||
</svg>
|
|
||||||
<strong>
|
|
||||||
{destination.country.label}
|
|
||||||
</strong>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="w-1/2">
|
|
||||||
<ul class="plain-list mb-0">
|
|
||||||
<f:for each="{destination.regions}" as="region">
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
{region.label}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</f:for>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</f:for>
|
|
||||||
<div class="flex items-start justify-between">
|
|
||||||
<div class="w-1/2">
|
|
||||||
<strong>Konzept</strong>
|
|
||||||
</div>
|
|
||||||
<div class="w-1/2">
|
|
||||||
<ul class="plain-list mb-0">
|
|
||||||
<f:for each="{filterOptions.concepts}" as="concept">
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
{concept.name}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</f:for>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<f:if condition="{filterSettings.destinationUid} || {filterSettings.conceptUid}">
|
|
||||||
<button>
|
|
||||||
zurücksetzen
|
|
||||||
</button>
|
|
||||||
</f:if>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-32"
|
|
||||||
data-controller="collapse"
|
|
||||||
data-collapse-collapsed-value="true">
|
|
||||||
<div class="relative border-r border-b border-white">
|
|
||||||
<input type="text"
|
|
||||||
data-action="click->collapse#toggle"
|
|
||||||
class="w-full bg-transparent border-0 ring-0 focus:ring-0 text-white uppercase px-2 py-1 cursor-pointer placeholder-white"
|
|
||||||
placeholder="Preis"/>
|
|
||||||
<svg class="w-6 h-6 text-white absolute right-0 top-0 mr-2 mt-1">
|
|
||||||
<use href="#icon-euro"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="hidden absolute top-100 left-0 bg-white p-4 shadow-md w-full h-48 overflow-y-scroll"
|
|
||||||
data-collapse-target="container">
|
|
||||||
<ul class="m-0 p-0">
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
beliebig
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<f:for each="{filterOptions.priceRanges}" as="range" iteration="iteration">
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
{range.formatted}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</f:for>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="hidden sticky:block sticky:ml-4">
|
|
||||||
<svg class="w-8 h-8 text-white">
|
|
||||||
<use href="#icon-chevron-right"></use>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<div class="flex justify-end mt-4 sticky:hidden">
|
|
||||||
<button type="submit" class="w-1/3 text-white uppercase py-2">
|
|
||||||
Detailsuche
|
|
||||||
</button>
|
|
||||||
<button type="submit" class="w-1/3 text-white bg-ep-primary-light uppercase py-2">
|
|
||||||
Alle anzeigen
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</f:form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<html data-namespace-typo3-fluid="true" lang="en"
|
|
||||||
xmlns="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
|
||||||
|
|
||||||
<f:layout name="Default"/>
|
|
||||||
|
|
||||||
<f:section name="Main">
|
|
||||||
<f:render partial="Search/Bar" arguments="{_all}"/>
|
|
||||||
</f:section>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,15 +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">
|
|
||||||
|
|
||||||
<f:layout name="Default"/>
|
|
||||||
|
|
||||||
<f:section name="Main">
|
|
||||||
<div data-controller="searchbar"
|
|
||||||
data-action="datepicker:range-select->searchbar#setDateRange"
|
|
||||||
data-searchbar-uri-value="{ep:uri.ajax(controller: 'AjaxSearchbar', action: 'index', pageUid: settings.defaultAjaxUid, format: 'html')}">
|
|
||||||
<f:render partial="Search/Bar" arguments="{_all}"/>
|
|
||||||
</div>
|
|
||||||
</f:section>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
<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 data-controller="searchbar"
|
||||||
|
{f:if(condition: fixed, else: ' data-controller="sticky" data-sticky-offset-value="650" data-sticky-sticky-class="sticky"')}
|
||||||
|
data-action="datepicker:range-select->searchbar#setDateRange"
|
||||||
|
data-searchbar-uri-value="{ep:uri.ajax(controller: 'Searchbar', action: 'index', pageUid: settings.defaultAjaxUid, format: 'html')}">
|
||||||
|
<div class="searchbar {f:if(condition: fixed, then: ' sticky')}"
|
||||||
|
data-searchbar-target="container">
|
||||||
|
<f:form action="processSearch" controller="Search" method="post" name="searchParams"
|
||||||
|
object="{searchParams}" pluginName="searchresult" extensionName="epproducts"
|
||||||
|
pageUid="{settings.defaultSearchPageUid}" data="{'searchbar-target': 'form'}">
|
||||||
|
<f:form.hidden property="dateFrom" data="{'searchbar-target': 'dateFrom'}"/>
|
||||||
|
<f:form.hidden property="dateTo" data="{'searchbar-target': 'dateTo'}"/>
|
||||||
|
<f:form.hidden property="pax" data="{'searchbar-target': 'pax'}"/>
|
||||||
|
<f:form.hidden property="destinationUid" data="{'searchbar-target': 'destinationUid'}"/>
|
||||||
|
<f:form.hidden property="destinationType" data="{'searchbar-target': 'destinationType'}"/>
|
||||||
|
<f:form.hidden property="priceRange" data="{'searchbar-target': 'priceRange'}"/>
|
||||||
|
<div class="sticky:max-w-screen-xl sticky:mx-auto flex flex-col sticky:flex-row sticky:items-center">
|
||||||
|
<div class="flex items-start justify-between sticky:flex-1 pt-8 px-8 sticky:py-4 sticky:px-0">
|
||||||
|
<div class="flex-1"
|
||||||
|
data-controller="collapse datepicker"
|
||||||
|
<f:if condition="{searchParams.dateFrom} && {searchParams.dateTo}">
|
||||||
|
data-datepicker-date-from-value="{searchParams.dateFrom}"
|
||||||
|
data-datepicker-date-to-value="{searchParams.dateTo}"
|
||||||
|
</f:if>
|
||||||
|
data-datepicker-min-date-value="{f:format.date(date: 'now', format: 'Y-m-d')}"
|
||||||
|
data-action="collapse:click:outside->collapse#close searchbar:input@window->collapse#close"
|
||||||
|
data-collapse-collapsed-value="true">
|
||||||
|
<div class="relative border-b border-r border-white mr-8">
|
||||||
|
<input type="text"
|
||||||
|
data-action="click->collapse#toggle"
|
||||||
|
class="w-full bg-transparent border-0 ring-0 focus:ring-0 text-white uppercase px-2 py-1 cursor-pointer placeholder-white"
|
||||||
|
placeholder="Zeitraum"
|
||||||
|
<f:if condition="{searchParams.dateFrom} && {searchParams.dateTo}">
|
||||||
|
value="{ep:dateRange(dateFrom: searchParams.dateFrom, dateTo: searchParams.dateTo, includeLabel: 0)}"
|
||||||
|
</f:if>
|
||||||
|
data-searchbar-target="dateRangeLabel"/>
|
||||||
|
<svg class="w-6 h-6 text-white absolute right-0 top-0 mr-2 mt-1"
|
||||||
|
data-action="click->collapse#toggle">
|
||||||
|
<use href="#icon-calendar"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="hidden absolute z-20 top-100 mt-2 left-0 bg-white p-4 shadow-md"
|
||||||
|
data-collapse-target="container">
|
||||||
|
<f:if condition="{settings.datePickerPresets}">
|
||||||
|
<div class="flex items-center justify-between pb-2">
|
||||||
|
<f:for each="{settings.datePickerPresets}" as="preset">
|
||||||
|
<button class="daterange__preset"
|
||||||
|
data-preset='{preset -> f:format.json()}'
|
||||||
|
data-action="datepicker#selectPreset">
|
||||||
|
<span>
|
||||||
|
{preset.label}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</f:for>
|
||||||
|
</div>
|
||||||
|
</f:if>
|
||||||
|
<input type="hidden"
|
||||||
|
data-datepicker-target="field">
|
||||||
|
<div class="flex items-center justify-between pt-2">
|
||||||
|
<button class="daterange__button focus:outline-none"
|
||||||
|
data-action="collapse#close">
|
||||||
|
schließen
|
||||||
|
</button>
|
||||||
|
<button class="daterange__button focus:outline-none"
|
||||||
|
data-action="datepicker#reset">
|
||||||
|
zurücksetzen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-24"
|
||||||
|
data-controller="collapse"
|
||||||
|
data-action="collapse:click:outside->collapse#close searchbar:input@window->collapse#close"
|
||||||
|
data-collapse-collapsed-value="true">
|
||||||
|
<div class="relative border-b border-r border-white mr-8">
|
||||||
|
<input type="text"
|
||||||
|
data-action="click->collapse#toggle"
|
||||||
|
data-searchbar-target="paxLabel"
|
||||||
|
value="{searchParams.pax}"
|
||||||
|
class="w-full bg-transparent border-0 ring-0 focus:ring-0 text-white uppercase px-2 py-1 cursor-pointer"/>
|
||||||
|
<svg class="w-6 h-6 text-white absolute right-0 top-0 mr-2 mt-1">
|
||||||
|
<use href="#icon-user-group"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="hidden absolute top-100 mt-2 left-0 bg-white p-4 shadow-md w-full h-48 overflow-y-scroll"
|
||||||
|
data-collapse-target="container">
|
||||||
|
<ul class="m-0 p-0">
|
||||||
|
<f:for each="{filterOptions.pax}" as="option">
|
||||||
|
<li>
|
||||||
|
<button data-action="searchbar#setPax"
|
||||||
|
data-option="{option}">
|
||||||
|
{option}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</f:for>
|
||||||
|
<li>
|
||||||
|
<a href="{f:uri.typolink(parameter: settings.groupsPageUid)}">
|
||||||
|
> 20
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1"
|
||||||
|
data-controller="collapse"
|
||||||
|
data-action="collapse:click:outside->collapse#close searchbar:input@window->collapse#close"
|
||||||
|
data-collapse-collapsed-value="true">
|
||||||
|
<div class="relative border-b border-r border-white mr-8">
|
||||||
|
<input type="text"
|
||||||
|
data-action="click->collapse#toggle"
|
||||||
|
data-searchbar-target="destinationLabel"
|
||||||
|
class="w-full bg-transparent border-0 ring-0 focus:ring-0 text-white uppercase px-2 py-1 cursor-pointer placeholder-white"
|
||||||
|
placeholder="Reiseziel"/>
|
||||||
|
<svg class="w-6 h-6 text-white absolute right-0 top-0 mr-2 mt-1 transform rotate-45">
|
||||||
|
<use href="#icon-airplane"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="hidden absolute top-100 left-0 bg-white p-4 shadow-md min-w-full h-48 overflow-y-scroll"
|
||||||
|
data-collapse-target="container">
|
||||||
|
<f:for each="{filterOptions.destinations}" as="destination">
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
|
<div class="w-1/2">
|
||||||
|
<button data-action="searchbar#setDestination"
|
||||||
|
data-option-uid="{destination.country.uid}"
|
||||||
|
data-option-type="country"
|
||||||
|
data-option-label="{destination.country.label}">
|
||||||
|
<svg class="block w-8 h-6">
|
||||||
|
<use href="#icon-flag-{destination.country.code -> f:format.case(mode: 'lower')}"/>
|
||||||
|
</svg>
|
||||||
|
<strong>
|
||||||
|
{destination.country.label}
|
||||||
|
</strong>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2">
|
||||||
|
<ul class="plain-list mb-0">
|
||||||
|
<f:for each="{destination.regions}" as="region">
|
||||||
|
<li>
|
||||||
|
<button data-action="searchbar#setDestination"
|
||||||
|
data-option-uid="{region.uid}"
|
||||||
|
data-option-type="region"
|
||||||
|
data-option-label="{region.label}">
|
||||||
|
{region.label}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</f:for>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</f:for>
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
|
<div class="w-1/2">
|
||||||
|
<strong>Konzept</strong>
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2">
|
||||||
|
<ul class="plain-list mb-0">
|
||||||
|
<f:for each="{filterOptions.concepts}" as="concept">
|
||||||
|
<li>
|
||||||
|
<button data-action="searchbar#setDestination"
|
||||||
|
data-option-uid="{concept.uid}"
|
||||||
|
data-option-type="concept"
|
||||||
|
data-option-label="{concept.name}">
|
||||||
|
{concept.name}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</f:for>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button data-action="searchbar#resetDestination">
|
||||||
|
zurücksetzen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-32"
|
||||||
|
data-controller="collapse"
|
||||||
|
data-action="collapse:click:outside->collapse#close searchbar:input@window->collapse#close"
|
||||||
|
data-collapse-collapsed-value="true">
|
||||||
|
<div class="relative border-r border-b border-white">
|
||||||
|
<input type="text"
|
||||||
|
data-action="click->collapse#toggle"
|
||||||
|
data-searchbar-target="priceRangeLabel"
|
||||||
|
class="w-full bg-transparent border-0 ring-0 focus:ring-0 text-white uppercase px-2 py-1 cursor-pointer placeholder-white"
|
||||||
|
placeholder="Preis"/>
|
||||||
|
<svg class="w-6 h-6 text-white absolute right-0 top-0 mr-2 mt-1">
|
||||||
|
<use href="#icon-euro"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="hidden absolute top-100 left-0 bg-white p-4 shadow-md w-full h-48 overflow-y-scroll"
|
||||||
|
data-collapse-target="container">
|
||||||
|
<ul class="m-0 p-0">
|
||||||
|
<li>
|
||||||
|
<button data-action="searchbar#setPriceRange"
|
||||||
|
data-option-value=""
|
||||||
|
data-label-value="beliebig">
|
||||||
|
beliebig
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<f:for each="{filterOptions.priceRanges}" as="range" iteration="iteration">
|
||||||
|
<li>
|
||||||
|
<button data-action="searchbar#setPriceRange"
|
||||||
|
data-option-value="{range.uid}"
|
||||||
|
data-label-value="{range.formatted}">
|
||||||
|
{range.formatted}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</f:for>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="hidden sticky:block sticky:ml-4">
|
||||||
|
<svg class="w-8 h-8 text-white">
|
||||||
|
<use href="#icon-chevron-right"></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="flex justify-end mt-4 sticky:hidden">
|
||||||
|
<button type="submit" class="w-1/3 text-white uppercase py-2">
|
||||||
|
Detailsuche
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="w-1/3 text-white bg-ep-primary-light uppercase py-2">
|
||||||
|
Alle anzeigen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</f:form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</f:section>
|
||||||
|
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user