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
Generated
+91 -76
View File
@@ -1693,16 +1693,16 @@
},
{
"name": "symfony/console",
"version": "v2.8.43",
"version": "v2.8.44",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "42a0adc7dd656ca2e360285eb6d822df9ce0b160"
"reference": "0c1fcbb9afb5cff992c982ff99c0434f0146dcfc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/42a0adc7dd656ca2e360285eb6d822df9ce0b160",
"reference": "42a0adc7dd656ca2e360285eb6d822df9ce0b160",
"url": "https://api.github.com/repos/symfony/console/zipball/0c1fcbb9afb5cff992c982ff99c0434f0146dcfc",
"reference": "0c1fcbb9afb5cff992c982ff99c0434f0146dcfc",
"shasum": ""
},
"require": {
@@ -1750,20 +1750,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2018-07-09T12:58:09+00:00"
"time": "2018-07-26T11:13:39+00:00"
},
{
"name": "symfony/debug",
"version": "v2.8.43",
"version": "v2.8.44",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "a26ddce7fe4e884097d72435653bc7e703411f26"
"reference": "d985c8546da49c4727e27dae82bcf783ee2c5af0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/a26ddce7fe4e884097d72435653bc7e703411f26",
"reference": "a26ddce7fe4e884097d72435653bc7e703411f26",
"url": "https://api.github.com/repos/symfony/debug/zipball/d985c8546da49c4727e27dae82bcf783ee2c5af0",
"reference": "d985c8546da49c4727e27dae82bcf783ee2c5af0",
"shasum": ""
},
"require": {
@@ -1807,20 +1807,20 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2018-06-22T15:01:26+00:00"
"time": "2018-07-26T11:13:39+00:00"
},
{
"name": "symfony/finder",
"version": "v2.8.43",
"version": "v2.8.44",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "995cd7c28a0778cece02e2133b4d813dc509dfc3"
"reference": "f0de0b51913eb2caab7dfed6413b87e14fca780e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/995cd7c28a0778cece02e2133b4d813dc509dfc3",
"reference": "995cd7c28a0778cece02e2133b4d813dc509dfc3",
"url": "https://api.github.com/repos/symfony/finder/zipball/f0de0b51913eb2caab7dfed6413b87e14fca780e",
"reference": "f0de0b51913eb2caab7dfed6413b87e14fca780e",
"shasum": ""
},
"require": {
@@ -1856,20 +1856,20 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2018-06-19T11:07:17+00:00"
"time": "2018-07-26T11:13:39+00:00"
},
{
"name": "symfony/inflector",
"version": "v3.4.13",
"version": "v3.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/inflector.git",
"reference": "bc27e8f793a571313132923b5ad10fdf2843e26c"
"reference": "129ac0c59e516f5fe210efe51a44f79ab9925c16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/inflector/zipball/bc27e8f793a571313132923b5ad10fdf2843e26c",
"reference": "bc27e8f793a571313132923b5ad10fdf2843e26c",
"url": "https://api.github.com/repos/symfony/inflector/zipball/129ac0c59e516f5fe210efe51a44f79ab9925c16",
"reference": "129ac0c59e516f5fe210efe51a44f79ab9925c16",
"shasum": ""
},
"require": {
@@ -1914,7 +1914,7 @@
"symfony",
"words"
],
"time": "2018-05-01T22:53:27+00:00"
"time": "2018-07-26T08:45:46+00:00"
},
{
"name": "symfony/options-resolver",
@@ -1972,25 +1972,28 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.8.0",
"version": "v1.9.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae"
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae",
"reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
"dev-master": "1.9-dev"
}
},
"autoload": {
@@ -2023,20 +2026,20 @@
"polyfill",
"portable"
],
"time": "2018-04-30T19:57:29+00:00"
"time": "2018-08-06T14:22:27+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.8.0",
"version": "v1.9.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "3296adf6a6454a050679cde90f95350ad604b171"
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171",
"reference": "3296adf6a6454a050679cde90f95350ad604b171",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8",
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8",
"shasum": ""
},
"require": {
@@ -2048,7 +2051,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
"dev-master": "1.9-dev"
}
},
"autoload": {
@@ -2082,30 +2085,30 @@
"portable",
"shim"
],
"time": "2018-04-26T10:06:28+00:00"
"time": "2018-08-06T14:22:27+00:00"
},
{
"name": "symfony/polyfill-php70",
"version": "v1.8.0",
"version": "v1.9.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php70.git",
"reference": "77454693d8f10dd23bb24955cffd2d82db1007a6"
"reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/77454693d8f10dd23bb24955cffd2d82db1007a6",
"reference": "77454693d8f10dd23bb24955cffd2d82db1007a6",
"url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/1e24b0c4a56d55aaf368763a06c6d1c7d3194934",
"reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934",
"shasum": ""
},
"require": {
"paragonie/random_compat": "~1.0|~2.0",
"paragonie/random_compat": "~1.0|~2.0|~9.99",
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
"dev-master": "1.9-dev"
}
},
"autoload": {
@@ -2141,20 +2144,20 @@
"portable",
"shim"
],
"time": "2018-04-26T10:06:28+00:00"
"time": "2018-08-06T14:22:27+00:00"
},
{
"name": "symfony/process",
"version": "v3.4.13",
"version": "v3.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "f741672edfcfe3a2ea77569d419006f23281d909"
"reference": "0414db29bd770ec5a4152683e655f55efd4fa60f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/f741672edfcfe3a2ea77569d419006f23281d909",
"reference": "f741672edfcfe3a2ea77569d419006f23281d909",
"url": "https://api.github.com/repos/symfony/process/zipball/0414db29bd770ec5a4152683e655f55efd4fa60f",
"reference": "0414db29bd770ec5a4152683e655f55efd4fa60f",
"shasum": ""
},
"require": {
@@ -2190,20 +2193,20 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2018-07-09T09:01:07+00:00"
"time": "2018-07-26T11:19:56+00:00"
},
{
"name": "symfony/property-access",
"version": "v3.4.13",
"version": "v3.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/property-access.git",
"reference": "a6e8c778b220dfd5cd5f5dcb09f87ee232dd608a"
"reference": "28d3129c330f73d47fafa8239a2fa6ccd44136a6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/property-access/zipball/a6e8c778b220dfd5cd5f5dcb09f87ee232dd608a",
"reference": "a6e8c778b220dfd5cd5f5dcb09f87ee232dd608a",
"url": "https://api.github.com/repos/symfony/property-access/zipball/28d3129c330f73d47fafa8239a2fa6ccd44136a6",
"reference": "28d3129c330f73d47fafa8239a2fa6ccd44136a6",
"shasum": ""
},
"require": {
@@ -2258,7 +2261,7 @@
"property path",
"reflection"
],
"time": "2018-01-03T07:37:34+00:00"
"time": "2018-07-26T09:06:28+00:00"
},
{
"name": "symfony/serializer",
@@ -2418,6 +2421,7 @@
}
],
"description": "This extension integrates the grid layout concept also to regular content elements - the grid elements.\r\nIt offers a lot of new features like advanced drag & drop or real references, that improve the usability of the page and list module to speed up the daily work with the backend.",
"homepage": "https://extensions.typo3.org/extension/gridelements/",
"time": "2017-12-23T18:15:17+00:00"
},
{
@@ -2451,28 +2455,29 @@
}
],
"description": "Compress/minify your HTML output",
"homepage": "https://extensions.typo3.org/extension/html_compress/",
"time": "2016-12-26T10:19:02+00:00"
},
{
"name": "typo3-ter/imageoptimizer",
"version": "1.0.4",
"version": "1.1.2",
"dist": {
"type": "zip",
"url": "https://extensions.typo3.org/extension/download/imageoptimizer/1.0.4/zip/",
"url": "https://extensions.typo3.org/extension/download/imageoptimizer/1.1.2/zip/",
"reference": null,
"shasum": null
},
"require": {
"typo3/cms-core": ">= 6.2.0, <= 8.9.99"
"typo3/cms-core": ">= 7.6.0, <= 8.7.99"
},
"replace": {
"imageoptimizer": "self.version"
},
"type": "typo3-cms-extension",
"autoload": {
"classmap": [
"Classes/"
]
"psr-4": {
"Lemming\\Imageoptimizer\\": "Classes/"
}
},
"authors": [
{
@@ -2483,7 +2488,9 @@
}
],
"description": "Optimize uploaded/processed images with binaries of your choice",
"time": "2017-03-11T11:37:47+00:00"
"homepage": "https://extensions.typo3.org/extension/imageoptimizer/",
"abandoned": "christophlehmann/imageoptimizer",
"time": "2018-08-20T23:03:56+00:00"
},
{
"name": "typo3-ter/loginlimit",
@@ -2515,6 +2522,7 @@
}
],
"description": "Protect backend and/or frontend login against brute-force attacks.",
"homepage": "https://extensions.typo3.org/extension/loginlimit/",
"time": "2017-09-23T10:40:00+00:00"
},
{
@@ -2551,6 +2559,7 @@
}
],
"description": "Media management system for TYPO3 CMS.",
"homepage": "https://extensions.typo3.org/extension/media/",
"time": "2017-11-02T13:08:04+00:00"
},
{
@@ -2584,6 +2593,7 @@
}
],
"description": "Search Engine Optimization (SEO), Indexed Google-Sitemap (TXT- and XML-Sitemap) for all Extensions (pibase, extbase), Metatags, Canonical-URL, Pagetitle manipulations, Crawler verification, Piwik and Google Analytics support and some more... multi-language- and multi-tree-support",
"homepage": "https://extensions.typo3.org/extension/metaseo/",
"time": "2017-06-11T18:32:55+00:00"
},
{
@@ -2623,6 +2633,7 @@
}
],
"description": "Simply manage (permanent 301) redirects in the list view. The extension supports multidomain sites, count the redirect usage and shows the last referer. UPDATE! imports the records from realurl.",
"homepage": "https://extensions.typo3.org/extension/ods_redirects/",
"time": "2017-05-22T22:07:45+00:00"
},
{
@@ -2656,6 +2667,7 @@
}
],
"description": "Provides API for Backend modules to get a proper path to the Frontend page (simulateStatic/RealURL/CoolURI-like)",
"homepage": "https://extensions.typo3.org/extension/pagepath/",
"time": "2017-02-15T15:40:25+00:00"
},
{
@@ -2692,6 +2704,7 @@
"username": "plusb"
}
],
"homepage": "https://extensions.typo3.org/extension/pb_social/",
"time": "2018-02-14T11:05:37+00:00"
},
{
@@ -2725,14 +2738,15 @@
}
],
"description": "Optimization of the final page: reformatting the (x)html output, removal of new lines, and quotes. Move development repository to https://github.com/lochmueller/sourceopt",
"homepage": "https://extensions.typo3.org/extension/sourceopt/",
"time": "2017-06-15T17:25:53+00:00"
},
{
"name": "typo3-ter/vidi",
"version": "2.6.0",
"version": "2.7.0",
"dist": {
"type": "zip",
"url": "https://extensions.typo3.org/extension/download/vidi/2.6.0/zip/",
"url": "https://extensions.typo3.org/extension/download/vidi/2.7.0/zip/",
"reference": null,
"shasum": null
},
@@ -2757,7 +2771,8 @@
}
],
"description": "Generic listing of records with versatile ways of interacting with the data, e.g. advanced filter, inline editing, mass editing, ... Veni, vidi, vici!",
"time": "2017-11-02T13:05:47+00:00"
"homepage": "https://extensions.typo3.org/extension/vidi/",
"time": "2018-08-03T10:50:35+00:00"
},
{
"name": "typo3/class-alias-loader",
@@ -4439,16 +4454,16 @@
},
{
"name": "symfony/cache",
"version": "v3.4.13",
"version": "v3.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "ae6a68d17e5e2c41e9cca278add1feda0473bcfe"
"reference": "337408485de75c884e6ab1b2e8f055d31a7aa7b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/ae6a68d17e5e2c41e9cca278add1feda0473bcfe",
"reference": "ae6a68d17e5e2c41e9cca278add1feda0473bcfe",
"url": "https://api.github.com/repos/symfony/cache/zipball/337408485de75c884e6ab1b2e8f055d31a7aa7b6",
"reference": "337408485de75c884e6ab1b2e8f055d31a7aa7b6",
"shasum": ""
},
"require": {
@@ -4505,20 +4520,20 @@
"caching",
"psr6"
],
"time": "2018-07-01T06:47:44+00:00"
"time": "2018-07-26T11:19:56+00:00"
},
{
"name": "symfony/expression-language",
"version": "v3.4.13",
"version": "v3.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/expression-language.git",
"reference": "555bf77002c6319eaf6311be7d6213dc3668e641"
"reference": "d60e37ab9838338d959f2cc177a66cf498293788"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/expression-language/zipball/555bf77002c6319eaf6311be7d6213dc3668e641",
"reference": "555bf77002c6319eaf6311be7d6213dc3668e641",
"url": "https://api.github.com/repos/symfony/expression-language/zipball/d60e37ab9838338d959f2cc177a66cf498293788",
"reference": "d60e37ab9838338d959f2cc177a66cf498293788",
"shasum": ""
},
"require": {
@@ -4555,20 +4570,20 @@
],
"description": "Symfony ExpressionLanguage Component",
"homepage": "https://symfony.com",
"time": "2018-06-21T11:10:19+00:00"
"time": "2018-07-26T09:06:28+00:00"
},
{
"name": "symfony/polyfill-apcu",
"version": "v1.8.0",
"version": "v1.9.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-apcu.git",
"reference": "9b83bd010112ec196410849e840d9b9fefcb15ad"
"reference": "19e1b73bf255265ad0b568f81766ae2a3266d8d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/9b83bd010112ec196410849e840d9b9fefcb15ad",
"reference": "9b83bd010112ec196410849e840d9b9fefcb15ad",
"url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/19e1b73bf255265ad0b568f81766ae2a3266d8d2",
"reference": "19e1b73bf255265ad0b568f81766ae2a3266d8d2",
"shasum": ""
},
"require": {
@@ -4577,7 +4592,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
"dev-master": "1.9-dev"
}
},
"autoload": {
@@ -4611,11 +4626,11 @@
"portable",
"shim"
],
"time": "2018-04-26T10:06:28+00:00"
"time": "2018-08-06T14:22:27+00:00"
},
{
"name": "symfony/yaml",
"version": "v3.3.17",
"version": "v3.3.18",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
@@ -65,26 +65,6 @@ class AjaxFilterpanelController extends ActionController
$this->processFilterSettingsArgument($forcedConceptUid);
}
/**
* @param FilterSettings $filterSettings
*
* @return string
*/
public function optionsAction(FilterSettings $filterSettings = null)
{
if ($filterSettings === null) {
$forcedConceptUid = (int) $this->settings['forcedConceptUid'];
$filterSettings = $this->filterService->getDefaultFilterSettings($forcedConceptUid);
}
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids']);
$filterOptions = $this->filterService->getFilterOptions($filterSettings, $excludedConceptUids);
if ($filterOptions === null) {
$filterSettings = $this->filterService->getDefaultFilterSettings();
$filterOptions = $this->filterService->getFilterOptions($filterSettings, $excludedConceptUids);
}
return json_encode($filterOptions);
}
/**
* @param FilterSettings $filterSettings
* @param string $search
@@ -29,7 +29,8 @@ namespace EP\EpProducts\Controller;
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Service\FilterService;
use EP\EpProducts\Service\SearchService;
use EP\EpProducts\Service\SearchResultUrlService;
use EP\EpProducts\Service\SearchResultService;
use EP\EpProducts\Traits\RequestArgumentTypeConversionTrait;
use EP\EpProducts\Utility\DateUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -46,19 +47,32 @@ class AjaxSearchController extends ActionController
protected $filterService;
/**
* @var SearchService
* @var SearchResultService
*/
protected $searchService;
protected $searchResultService;
/**
* @var SearchResultUrlService
*/
protected $searchResultUrlService;
/**
* @param FilterService $filterService
* @param SearchService $searchService
* @param SearchResultService $searchResultService
* @param SearchResultUrlService $searchResultUrlService
*/
public function __construct(FilterService $filterService, SearchService $searchService)
public function __construct
(
FilterService $filterService,
SearchResultService $searchResultService,
SearchResultUrlService $searchResultUrlService
)
{
parent::__construct();
$this->filterService = $filterService;
$this->searchService = $searchService;
$this->searchResultService = $searchResultService;
$this->searchResultUrlService = $searchResultUrlService;
}
public function initializeAction()
@@ -76,30 +90,35 @@ class AjaxSearchController extends ActionController
public function searchresultAction(FilterSettings $filterSettings = null, $referringPageUid = null)
{
$dateSelected = false;
$organic = true;
if ($filterSettings === null) {
$forcedConceptUid = (int) $this->settings['forcedConceptUid'];
$filterSettings = $this->filterService->getDefaultFilterSettings($forcedConceptUid);
} else if ($filterSettings->getDateFrom() !== null || $filterSettings->getDateTo() !== null) {
} elseif ($filterSettings->getDateFrom() !== null || $filterSettings->getDateTo() !== null) {
$dateSelected = true;
}
$organic = true;
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids']);
$searchResult = $this->searchService->getSearchResult($filterSettings, $excludedConceptUids);
$filterOptions = $this->filterService->getFilterOptions($filterSettings, $excludedConceptUids);
if ($filterOptions === null) {
$filterSettings = $this->filterService->getDefaultFilterSettings();
$filterOptions = $this->filterService->getFilterOptions($filterSettings, $excludedConceptUids);
}
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
if ($searchResult->getTotal() === 0) {
$filterSettings = $this->filterService->getDefaultFilterSettings();
$searchResult = $this->searchService->getSearchResult($filterSettings, $excludedConceptUids);
$searchResult = $this->searchResultService->getResult($filterSettings, $excludedConceptUids);
$organic = false;
}
$this->view->assignMultiple([
'searchResult' => $searchResult,
'detailPageUid' => $this->settings['defaultDetailPageUid'],
$options = [
'defaultDetailPageUid' => $this->settings['defaultDetailPageUid'],
'referringPageUid' => $referringPageUid,
'filterSettings' => $filterSettings,
'dateSelected' => $dateSelected,
'organic' => $organic,
]);
];
$this->searchResultUrlService->process($searchResult, $options);
return json_encode([
'html' => $this->view->render(),
'data' => $searchResult->getData(),
'filterOptions' => $filterOptions,
'meta' => [
'organic' => $organic,
'total' => $searchResult->getTotal(),
@@ -57,7 +57,7 @@ class HotelController extends ActionController
/**
* @var ProductService
*/
private $productService;
protected $productService;
/**
* @param HotelService $hotelService
@@ -0,0 +1,67 @@
<?php
namespace EP\EpProducts\Service;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Extbase\Service\ImageService;
class FlagIconService implements SingletonInterface
{
const FLAGICON_PATH = 'EXT:ep_theme/Resources/Public/images/%s.png';
/**
* @var ImageService
*/
protected $imageService;
/**
* @var array
*/
protected static $cache = [];
/**
* @param ImageService $imageService
*/
public function __construct(ImageService $imageService)
{
$this->imageService = $imageService;
}
/**
* @param string $code
* @return string
*/
public function getImage($code)
{
if (!isset(self::$cache[$code])) {
$src = sprintf(self::FLAGICON_PATH, strtolower($code));
$image = $this->imageService->getImage($src, null, false);
self::$cache[$code] = $this->imageService->getImageUri($image, true);
}
return self::$cache[$code];
}
}
@@ -0,0 +1,63 @@
<?php
namespace EP\EpProducts\Service;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Traits\ImageServiceTrait;
use TYPO3\CMS\Core\SingletonInterface;
class HotelImageService implements SingletonInterface
{
use ImageServiceTrait;
/**
* @var string
*/
protected $table = 'tx_epproducts_domain_model_hotel';
/**
* @var string
*/
protected $field = 'teaser_images';
/**
* @var array
*/
protected $imageSizes = [
's' => [
'width' => '220',
'height' => '130c-100',
],
'm' => [
'width' => '260',
'height' => '200c-100',
],
'l' => [
'width' => '280',
'height' => '220c-100',
]
];
}
@@ -39,19 +39,32 @@ class HotelService implements SingletonInterface
* @var \EP\EpProducts\Domain\Repository\HotelRepository
*/
protected $hotelRepository;
/**
* @var ImageService
* @var HotelImageService
*/
protected $imageService;
protected $hotelImageService;
/**
* @var FlagIconService
*/
protected $flagIconService;
/**
* @param HotelRepository $hotelRepository
* @param ImageService $imageService
* @param HotelImageService $hotelImageService
* @param FlagIconService $flagIconService
*/
public function __construct(HotelRepository $hotelRepository, ImageService $imageService)
public function __construct
(
HotelRepository $hotelRepository,
HotelImageService $hotelImageService,
FlagIconService $flagIconService
)
{
$this->hotelRepository = $hotelRepository;
$this->imageService = $imageService;
$this->hotelImageService = $hotelImageService;
$this->flagIconService = $flagIconService;
}
/**
@@ -94,10 +107,11 @@ class HotelService implements SingletonInterface
'name' => $hotelData['hotelName'],
'teaser' => $hotelData['hotelTeaser'],
'category' => $hotelCategory,
'images' => $this->imageService->getHotelImages($hotelUid),
'images' => $this->hotelImageService->getImages($hotelUid),
'country' => [
'name' => $hotelData['country'],
'code' => $hotelData['countryCode']
'code' => $hotelData['countryCode'],
'flag' => $this->flagIconService->getImage($hotelData['countryCode']),
],
'region' => [
'name' => $hotelData['regionName'],
@@ -153,10 +167,11 @@ class HotelService implements SingletonInterface
'name' => $row['hotelName'],
'teaser' => $row['hotelTeaser'],
'category' => $hotelCategory,
'images' => $this->imageService->getHotelImages($hotelUid),
'images' => $this->hotelImageService->getImages($hotelUid),
'country' => [
'name' => $row['country'],
'code' => $row['countryCode']
'code' => $row['countryCode'],
'flag' => $this->flagIconService->getImage($row['countryCode']),
],
'region' => [
'name' => $row['regionName'],
@@ -207,7 +222,7 @@ class HotelService implements SingletonInterface
'name' => $row['hotelName'],
'teaser' => $row['hotelTeaser'],
'category' => $hotelCategory,
'images' => $this->imageService->getHotelImages($row['hotelUid']),
'images' => $this->hotelImageService->getImages($row['hotelUid']),
'fact' => $row['hotelFact'],
],
'available' => 0,
@@ -1,89 +0,0 @@
<?php
namespace EP\EpProducts\Service;
/***************************************************************
*
* Copyright notice
*
* (c) 2016 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Core\SingletonInterface;
class ImageService implements SingletonInterface
{
/**
* @var \TYPO3\CMS\Core\Resource\FileRepository
*/
protected $fileRepository;
/**
* @param FileRepository $fileRepository
*/
public function __construct(FileRepository $fileRepository)
{
$this->fileRepository = $fileRepository;
}
/**
* @var array
*/
static protected $cache = [
'imagesProduct' => [],
'imagesHotel' => [],
];
/**
* @param int $productUid
* @return array
*/
public function getProductImages($productUid)
{
if (!isset(self::$cache['imagesProduct'][$productUid])) {
self::$cache['imagesProduct'][$productUid] = $this->fileRepository->findByRelation(
'tx_epproducts_domain_model_product',
'teaser_images',
$productUid
);
}
return self::$cache['imagesProduct'][$productUid];
}
/**
* @param int $hotelUid
* @return array
*/
public function getHotelImages($hotelUid)
{
if (!isset(self::$cache['imagesHotel'][$hotelUid])) {
self::$cache['imagesHotel'][$hotelUid] = $this->fileRepository->findByRelation(
'tx_epproducts_domain_model_hotel',
'teaser_images',
$hotelUid
);
}
return self::$cache['imagesHotel'][$hotelUid];
}
}
@@ -0,0 +1,71 @@
<?php
namespace EP\EpProducts\Service;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Traits\ImageServiceTrait;
use TYPO3\CMS\Core\SingletonInterface;
class ProductImageService implements SingletonInterface
{
use ImageServiceTrait;
/**
* @var string
*/
protected $table = 'tx_epproducts_domain_model_product';
/**
* @var string
*/
protected $field = 'teaser_images';
/**
* @var array
*/
protected $imageSizes = [
'xs' => [
'width' => '320',
'height' => '160c-100',
],
's' => [
'width' => '350',
'height' => '175c-100',
],
'm' => [
'width' => '360',
'height' => '200c-100',
],
'l' => [
'width' => '370',
'height' => '220c-100',
],
'xl' => [
'width' => '500',
'height' => '250c-100',
],
];
}
@@ -46,24 +46,40 @@ class ProductService implements SingletonInterface
protected $hotelRepository;
/**
* @var ImageService
* @var ProductImageService
*/
protected $imageService;
protected $productImageService;
/**
* @var HotelImageService
*/
protected $hotelImageService;
/**
* @var FlagIconService
*/
protected $flagIconService;
/**
* @param ProductRepository $productRepository
* @param HotelRepository $hotelRepository
* @param ImageService $imageService
* @param HotelImageService $hotelImageService
* @param ProductImageService $productImageService
* @param FlagIconService $flagIconService
*/
public function __construct(
ProductRepository $productRepository,
HotelRepository $hotelRepository,
ImageService $imageService
HotelImageService $hotelImageService,
ProductImageService $productImageService,
FlagIconService $flagIconService
)
{
$this->productRepository = $productRepository;
$this->hotelRepository = $hotelRepository;
$this->imageService = $imageService;
$this->productImageService = $productImageService;
$this->hotelImageService = $hotelImageService;
$this->flagIconService = $flagIconService;
}
/**
@@ -185,7 +201,7 @@ class ProductService implements SingletonInterface
'fact' => $teaserData['productFact'],
'feature' => $teaserData['productFeature'],
'teaser' => $teaserData['productTeaser'],
'images' => $this->imageService->getProductImages($teaserData['productUid']),
'images' => $this->productImageService->getImages($teaserData['productUid']),
],
'concept' => [
'name' => $teaserData['conceptName'],
@@ -196,11 +212,12 @@ class ProductService implements SingletonInterface
'category' => $hotelCategory,
'fact' => $teaserData['hotelFact'],
'uid' => $teaserData['hotelUid'],
'images' => $this->imageService->getHotelImages($teaserData['hotelUid']),
'images' => $this->hotelImageService->getImages($teaserData['hotelUid']),
],
'country' => [
'name' => $teaserData['countryName'],
'code' => $teaserData['countryCode'],
'flag' => $this->flagIconService->getImage($teaserData['countryCode']),
],
'region' => [
'name' => $teaserData['regionName'],
@@ -32,7 +32,7 @@ use EP\EpProducts\Domain\Model\SearchResult;
use EP\EpProducts\Domain\Repository\ProductRepository;
use TYPO3\CMS\Core\SingletonInterface;
class SearchService implements SingletonInterface
class SearchResultService implements SingletonInterface
{
/**
* @var ProductRepository
@@ -40,18 +40,30 @@ class SearchService implements SingletonInterface
protected $productRepository;
/**
* @var ImageService
* @var HotelImageService
*/
protected $imageService;
protected $hotelImageService;
/**
* @var FlagIconService
*/
protected $flagIconService;
/**
* @param ProductRepository $productRepository
* @param ImageService $imageService
* @param HotelImageService $hotelImageService
* @param FlagIconService $flagIconService
*/
public function __construct(ProductRepository $productRepository, ImageService $imageService)
public function __construct
(
ProductRepository $productRepository,
HotelImageService $hotelImageService,
FlagIconService $flagIconService
)
{
$this->productRepository = $productRepository;
$this->imageService = $imageService;
$this->hotelImageService = $hotelImageService;
$this->flagIconService = $flagIconService;
}
/**
@@ -60,10 +72,10 @@ class SearchService implements SingletonInterface
*
* @return SearchResult
*/
public function getSearchResult(FilterSettings $filterSettings, $excludedConceptUids = [])
public function getResult(FilterSettings $filterSettings, $excludedConceptUids = [])
{
$searchResultData = $this->productRepository->getSearchResult($filterSettings, $excludedConceptUids);
return $this->preprocessSearchresult($searchResultData);
return $this->preprocess($searchResultData);
}
/**
@@ -71,7 +83,7 @@ class SearchService implements SingletonInterface
*
* @return SearchResult
*/
public function preprocessSearchresult(array $searchResultData)
public function preprocess(array $searchResultData)
{
$data = [];
$total = 0;
@@ -100,9 +112,11 @@ class SearchService implements SingletonInterface
if (!array_key_exists($key, $items)) {
$items[$key] = [
'key' => $key,
'minDateStart' => null,
'maxDateEnd' => null,
'minPrice' => null,
'detailPageUri' => null,
'earlybird' => $row['earlybird'],
'lowContingent' => $row['lowContingent'],
'servicesIncluded' => unserialize($row['servicesIncluded']),
@@ -110,13 +124,14 @@ class SearchService implements SingletonInterface
'uid' => $row['hotelUid'],
'name' => $row['hotelName'],
'teaser' => $row['hotelTeaser'],
'images' => $this->imageService->getHotelImages($row['hotelUid']),
'images' => $this->hotelImageService->getImages($row['hotelUid']),
'fact' => $row['hotelFact'],
'category' => $hotelCategory,
],
'country' => [
'code' => $row['countryCode'],
'name' => $row['countryName'],
'flag' => $this->flagIconService->getImage($row['countryCode']),
],
'region' => [
'name' => $row['regionName'],
@@ -148,8 +163,8 @@ class SearchService implements SingletonInterface
$item['dates'][] = $row['dateStart'];
}
$dateStart = new \DateTime($row['dateStart']);
$dateEnd = new \DateTime($row['dateEnd']);
$dateStart = $row['dateStart'];
$dateEnd = $row['dateEnd'];
if ($item['minDateStart'] === null
|| $item['minDateStart'] > $dateStart) {
@@ -178,5 +193,4 @@ class SearchService implements SingletonInterface
return new SearchResult($data, $total);
}
}
}
@@ -0,0 +1,93 @@
<?php
namespace EP\EpProducts\Service;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use EP\EpProducts\Domain\Model\FilterSettings;
use EP\EpProducts\Domain\Model\SearchResult;
use Symfony\Component\OptionsResolver\OptionsResolver;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
class SearchResultUrlService implements SingletonInterface
{
/**
* @var UriBuilder
*/
protected $uriBuilder;
/**
* @param UriBuilder $uriBuilder
*/
public function __construct(UriBuilder $uriBuilder)
{
$this->uriBuilder = $uriBuilder;
}
/**
* @param SearchResult $searchResult
* @param array $options
*/
public function process(SearchResult $searchResult, array $options)
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setRequired([ 'defaultDetailPageUid', 'referringPageUid', 'filterSettings' ]);
$optionsResolver->setAllowedTypes('filterSettings', FilterSettings::class);
$resolvedOptions = $optionsResolver->resolve($options);
/** @var FilterSettings $filterSettings */
$filterSettings = $resolvedOptions['filterSettings'];
$encodedFilterSettings = FilterSettingsEncoder::encode($filterSettings);
$defaultDetailPageUid = $resolvedOptions['defaultDetailPageUid'];
$referringPageUid = $resolvedOptions['referringPageUid'];
$data = $searchResult->getData();
foreach ($data as $conceptUid => $conceptData)
{
foreach ($conceptData['items'] as $key => $item)
{
$detailPageUid = $item['product']['detailPage'] ?: $defaultDetailPageUid;
$arguments = [
'product' => $item['product']['uid'],
'hotel' => $item['hotel']['uid'],
'referringPageUid' => $referringPageUid,
'filterSettings' => $encodedFilterSettings,
];
$uri = $this
->uriBuilder
->reset()
->setTargetPageUid($detailPageUid)
->setCreateAbsoluteUri(true)
->uriFor('detail', $arguments, 'Product', 'epproducts', 'product_detail')
;
$data[$conceptUid]['items'][$key]['detailPageUri'] = $uri;
}
}
$searchResult->setData($data);
}
}
@@ -0,0 +1,105 @@
<?php
namespace EP\EpProducts\Traits;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Extbase\Service\ImageService;
trait ImageServiceTrait
{
/**
* @var array
*/
protected static $cache = [];
/**
* @var \TYPO3\CMS\Core\Resource\FileRepository
*/
protected $fileRepository;
/**
* @var ImageService
*/
protected $imageService;
/**
* @param FileRepository $fileRepository
* @param ImageService $imageService
*/
public function __construct(FileRepository $fileRepository, ImageService $imageService)
{
$this->fileRepository = $fileRepository;
$this->imageService = $imageService;
}
/**
* @param int $uid
* @return array
*/
public function getImages($uid)
{
if (!isset(self::$cache[$uid])) {
$original = $this->fileRepository->findByRelation(
$this->table,
$this->field,
$uid
);
$resized = $this->generateResizedImages($original);
self::$cache[$uid] = [
'original' => $original,
'resized' => $resized,
];
}
return self::$cache[$uid];
}
/**
* @param array $images
* @return array
*/
protected function generateResizedImages($images)
{
$resized = [];
foreach ($this->imageSizes as $version => $instructions)
{
foreach ($images as $image)
{
$intructions['crop'] = $image->getProperty('crop');
$processedImage = $this->imageService->applyProcessingInstructions($image, $instructions);
$resized[$version][] = [
'url' => $this->imageService->getImageUri($processedImage, true),
'alt' => $image->getProperty('alternative'),
'title' => $image->getProperty('title'),
];
}
}
return $resized;
}
}
@@ -108,8 +108,7 @@ tx_epproducts_ajax_json {
2 = reset
}
AjaxFilterpanel {
1 = options
2 = autocomplete
1 = autocomplete
}
AjaxContent {
1 = country
@@ -314,7 +314,7 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\T
[
'AjaxSearch' => 'searchresult',
'AjaxDate' => 'dates',
'AjaxFilterpanel' => 'options,autocomplete',
'AjaxFilterpanel' => 'autocomplete',
'AjaxSearchbar' => 'options,reset',
'AjaxContent' => 'country,region,city,hotel,product,journey,webcam',
'AjaxTable' => 'pricetable,pricetableHtml,eventPricetable',
@@ -323,7 +323,7 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\EP\EpProducts\T
[
'AjaxSearch' => 'searchresult',
'AjaxDate' => 'dates',
'AjaxFilterpanel' => 'options,autocomplete',
'AjaxFilterpanel' => 'autocomplete',
'AjaxSearchbar' => 'options,reset',
'AjaxContent' => 'webcam',
'AjaxTable' => 'pricetable,pricetableHtml,eventPricetable',
@@ -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>