You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

476 line
16 KiB

  1. const $ = global.$;
  2. // Plain InfiniteScroll without jquery plugin to avoid overhead
  3. // If needed plase see https://v3.infinite-scroll.com/extras.html
  4. // $(elem).infiniteScroll does not work
  5. // For API Reference See Vanila js Section of docs
  6. const InfiniteScroll = require('infinite-scroll');
  7. import {EtrackerUtils} from "./EtrackerUtils";
  8. export class SearchUtils {
  9. static loadResults() {
  10. this.shouldPreloadSearchEnteries = false;
  11. this.initEventsScrollPreservance();
  12. this.initialSearchRequest();
  13. }
  14. static initialSearchRequest(){
  15. const query = $('#query').val();
  16. const querySource = $('#querySource').val();
  17. const infiniteScrollInstance = InfiniteScroll.data(".search-results #dummy-wrapper");
  18. $(".results-wrapper").detach();
  19. $(".search-hits").empty();
  20. if(infiniteScrollInstance instanceof InfiniteScroll){
  21. infiniteScrollInstance.destroy();
  22. }
  23. // ETracker-Event asynchron absetzen:
  24. if (query.length > 0) {
  25. const searchCategory = $("#query").data('search-category'), hasCategory = typeof searchCategory !== "undefined";
  26. if (!window.isPbe) {
  27. window.setTimeout(EtrackerUtils.fireETrackerEvent, 250,
  28. (hasCategory ? searchCategory : 'Kombi-Suche'), query,
  29. 'Suche', '');
  30. }
  31. }
  32. $('#infscr-initial-loading').show();
  33. const ajaxUrl = $('.search-results').data("initialsearch-url")
  34. + "?preSearch=oidSearch&querySource=" + encodeURIComponent(querySource) + "&query="
  35. + encodeURIComponent(query) + SearchUtils.getQueryParameter();
  36. const resultWrapper = $("#dummy-wrapper");
  37. $.ajax({
  38. url: ajaxUrl,
  39. success: function (result) {
  40. $(resultWrapper).append(result);
  41. // oidSearch redirect:
  42. var rUrl = $("#oidmatch").data("redirect-url");
  43. if (rUrl !== undefined && rUrl.trim().length > 0) {
  44. location.href = rUrl;
  45. } else {
  46. SearchUtils.initInfiniteScroll();
  47. SearchUtils.initFeedbackToggle();
  48. SearchUtils.fillSearchCategoryAddition(query);
  49. $('#infscr-initial-loading').hide();
  50. }
  51. }
  52. });
  53. if (window.OMQHelp && query.length >0) {
  54. if (window.history.replaceState) {
  55. const cleanUrl = window.location.origin + window.location.pathname;
  56. window.history.replaceState(null, '', cleanUrl);
  57. }
  58. const omqAccount = $("#omq-help-container").data('omq-help-account');
  59. window.OMQHelp.update({
  60. query: query,
  61. account: omqAccount
  62. });
  63. }
  64. }
  65. /**
  66. * Dient zum Ein/Ausblenden der Feedback Funktion von Einschub-Suchen.
  67. * (insbesondere dem Wegweiser)
  68. */
  69. static initFeedbackToggle() {
  70. $('#feedbackToggle').click(function () {
  71. var feedbackBlock = $('#feedbackBlock');
  72. if (feedbackBlock.is(':hidden')) {
  73. $.ajax({
  74. url: $(this).data("feedback-url"),
  75. success: function (result) {
  76. // TODO: Feedback form prüfen
  77. $(feedbackBlock).append($(result));
  78. console.log($(result).find("#feedbackBlock"));
  79. $(this).show('slow');
  80. SearchUtils.initFeedback();
  81. }
  82. });
  83. } else {
  84. feedbackBlock.hide('slow');
  85. }
  86. return false;
  87. });
  88. }
  89. /**
  90. * Feedback Formular für Einschub-Suchen.
  91. */
  92. static initFeedback() {
  93. $('#feedbackBlock').find('form').submit(
  94. function () {
  95. $
  96. .post($('#feedbackToggle').data('feedback-url'), $(
  97. '#feedbackBlock').find('form').serialize(),
  98. function (msg) {
  99. $('#feedbackBlock').html(msg);
  100. if ($('#feedbackBlock').find('form')
  101. .size() > 0) {
  102. SearchUtils.initFeedback();
  103. } else {
  104. $('#feedbackToggle').hide();
  105. }
  106. });
  107. return false;
  108. });
  109. }
  110. static fillSearchCategoryAddition(queryP) {
  111. const buttonWrapper = $('#searchcategoryaddition');
  112. const firstWrapper = $('.results-wrapper').first();
  113. const btnAll = $('<a class="btn btn-small" />');
  114. const isZeroResults = $('.search-results .results-wrapper').length === 0;
  115. const isKombiWrapper = $('.search-results').hasClass("kombi-wrapper");
  116. const searchCategoryAdditionLink = buttonWrapper.attr('data-searchcategoryaddition-link');
  117. // const searchCategoryAdditionTitle = buttonWrapper.attr('data-searchcategoryaddition-title');
  118. const defaultSearchText = "Allgemeine Suche";
  119. buttonWrapper.children().remove();
  120. buttonWrapper.append(btnAll);
  121. // btnAll.text(searchCategoryAdditionTitle);
  122. btnAll.attr('href', searchCategoryAdditionLink + "?query=" + encodeURIComponent(queryP));
  123. if (isKombiWrapper && !isZeroResults) {
  124. const defaultSearchTextAll = "Alle&nbsp;";
  125. const ephasizedText = $('<strong/>').text(`${firstWrapper.attr('data-totalresults')} Treffer`);
  126. btnAll.addClass('active').html(defaultSearchTextAll).append(ephasizedText);
  127. $('.results-wrapper').not('.no-border').each(function () {
  128. const rw = $(this);
  129. const btn = $('<a />').addClass('btn btn-small primary-light').attr('href', rw.attr('data-searchcategoryaddition-link')).appendTo(buttonWrapper);
  130. let txt = rw.attr('data-searchcategoryaddition-title');
  131. if (rw.attr('data-result-count') !== undefined) {
  132. txt = txt + ' (' + rw.attr('data-result-count') + ')';
  133. }
  134. btn.text(txt);
  135. })
  136. } else if(!isKombiWrapper){
  137. buttonWrapper.insertAfter('.search-filter-form');
  138. btnAll.text(defaultSearchText);
  139. btnAll.addClass("primary-light");
  140. btnAll.attr('href', buttonWrapper.attr('data-searchcategoryaddition-link') + "?query=" + encodeURIComponent(queryP));
  141. } else {
  142. buttonWrapper.children().remove();
  143. }
  144. }
  145. /**
  146. * Berechnet die Url-Parameter für die Suchfilter.
  147. */
  148. static getQueryParameter() {
  149. var queryFields = $('#ev-search-filter-form').find('[data-queryparam]');
  150. var queryParams = "";
  151. if (queryFields.length) {
  152. var input = queryFields.filter('input[type!="checkbox"]');
  153. if (input.length) {
  154. queryParams = queryParams + "&" + $.param(input);
  155. }
  156. var select = queryFields.filter('select');
  157. if (select.length) {
  158. queryParams = queryParams + "&" + $.param(select);
  159. }
  160. var check = queryFields.filter('input[type="checkbox"]:checked');
  161. if (check.length) {
  162. queryParams = queryParams + "&" + $.param(check);
  163. }
  164. }
  165. return queryParams;
  166. }
  167. /**
  168. * Berechnet die Url-Parameter für die Seitenpaginierung.
  169. */
  170. static getPagingParameter() {
  171. var params = "";
  172. var resultWrapper = $('.results-wrapper');
  173. if (resultWrapper.length) {
  174. var total = resultWrapper.data("totalresults");
  175. var itemsPerPage = resultWrapper.data("resultsperpage");
  176. var numPages = resultWrapper.data("numpages");
  177. var pointerWithName = resultWrapper[resultWrapper.length -1].dataset.pointermap;
  178. var currentPageWithName = resultWrapper[resultWrapper.length -1].dataset.currentpagemap;
  179. if (!(total === undefined)) {
  180. params = params + "&totalResults=" + total;
  181. }
  182. if (!(itemsPerPage === undefined)) {
  183. params = params + "&resultsPerPage=" + itemsPerPage;
  184. }
  185. if (!(numPages === undefined)) {
  186. params = params + "&numPages=" + numPages;
  187. }
  188. if (!(pointerWithName === undefined)) {
  189. params = params + "&pointerMap=" + encodeURIComponent(pointerWithName);
  190. }
  191. if (!(currentPageWithName === undefined)) {
  192. params = params + "&currentPageMap=" + encodeURIComponent(currentPageWithName);
  193. }
  194. }
  195. return params;
  196. }
  197. static initEventsScrollPreservance(){
  198. $(document).on("click", "#search-results .results-wrapper .event-component",function(event){
  199. const originalHistoryState = history.state ||{};
  200. originalHistoryState.lastScrollPosition = $(window).scrollTop();
  201. history.replaceState(originalHistoryState, document.title);
  202. });
  203. }
  204. static scrollToLastViewedEvent(){
  205. if(history.state && history.state.lastScrollPosition){
  206. requestAnimationFrame(()=>{
  207. $('html, body').animate(
  208. {
  209. scrollTop : history.state.lastScrollPosition
  210. }, 500);
  211. });
  212. }
  213. }
  214. static updateSearchHistoryState(lastScrolledPage){
  215. try{
  216. const originalHistoryState = {};
  217. originalHistoryState.lastScrolledSearchPage = lastScrolledPage;
  218. history.replaceState(originalHistoryState, document.title);
  219. } catch(e) {
  220. console.warn("Could not update history state", e);
  221. }
  222. }
  223. /**
  224. * Initialisiert das Endlosscrolling für Trefferlisten.
  225. */
  226. static initInfiniteScroll() {
  227. ihk.resources = ihk.resources || {loadSpinner: ""};
  228. const $infiniteScrollContainer = $('.search-results #dummy-wrapper');
  229. if ($infiniteScrollContainer.length > 0) {
  230. const $pagingNav = $('.paging-nav');
  231. $pagingNav.hide();
  232. SearchUtils.updateSearchResultsMessage();
  233. SearchUtils.highlightSearchTerm();
  234. const infiniteScrollObj = new InfiniteScroll($infiniteScrollContainer[0],{
  235. onInit: function(){
  236. if(history.state && history.state.lastScrolledSearchPage ){
  237. const lastScrolledPageFromHistory = history.state.lastScrolledSearchPage;
  238. // load the last scrolled page after leaving the page and returning
  239. if((lastScrolledPageFromHistory > 1) && (lastScrolledPageFromHistory >= this.pageIndex)){
  240. SearchUtils.shouldPreloadSearchEnteries = true;
  241. requestAnimationFrame(()=>{
  242. this.loadNextPage().then(function (loaded) {
  243. let { response, body, items } = loaded;
  244. console.log( response );
  245. console.log( body );
  246. console.log( items );
  247. /** const resultWrapper = $('.results-wrapper');
  248. resultWrapper.data("pointermap", "{antrago=6, sweap=4}");
  249. resultWrapper.data("currentpagemap", "{antrago=2, sweap=1}");
  250. console.log(resultWrapper);**/
  251. });
  252. });
  253. }
  254. }
  255. },
  256. path: function () {
  257. // Load the second page because we do presearch
  258. const index = this.pageIndex + 1;
  259. const resultWrapper = $('.results-wrapper');
  260. if (resultWrapper.length) {
  261. const numPages = resultWrapper
  262. .data("numpages");
  263. if ((numPages === undefined)
  264. || (index <= numPages)) {
  265. return $('.search-results')
  266. .data(
  267. "infinitescroll-normal-return-url")
  268. + "?query="
  269. + encodeURIComponent($(
  270. '#query').val())
  271. + "&currentPage="
  272. + index
  273. + SearchUtils.getQueryParameter()
  274. + SearchUtils.getPagingParameter();
  275. }
  276. }
  277. return "";// damit nicht stumpf wiederholt
  278. // das letzte Ergebnis
  279. // angehangen wird!
  280. },
  281. append: ".results-wrapper",
  282. responseBody: "html",
  283. history: false,
  284. // debug: true -> for developement
  285. });
  286. infiniteScrollObj.on( 'append', function( response, path, items ) {
  287. if($(items).is(".results-wrapper")){
  288. const pageIndex = this.pageIndex;
  289. if(SearchUtils.shouldPreloadSearchEnteries){
  290. if(history.state && history.state.lastScrolledSearchPage > pageIndex){
  291. this.loadNextPage();
  292. } else {
  293. SearchUtils.shouldPreloadSearchEnteries = false;
  294. SearchUtils.scrollToLastViewedEvent();
  295. }
  296. }else {
  297. SearchUtils.updateSearchHistoryState(pageIndex);
  298. SearchUtils.highlightSearchTerm();
  299. }
  300. }else {
  301. // Destroy falls keine results mehr
  302. infiniteScrollObj.destroy();
  303. }
  304. });
  305. }
  306. }
  307. /**
  308. * Markiert nach erfolgter Suche den Suchbegriff innerhalb der Trefferliste.
  309. */
  310. static highlightSearchTerm() {
  311. var $searchResults = $('.search-results .results-wrapper .result'), $searchField = $('#query');
  312. // highlight search term
  313. if ($searchResults.length > 0 && $searchField.length > 0) {
  314. var searchTerm = $searchField.val();
  315. if (typeof searchTerm !== 'undefined') {
  316. if ($searchResults.highlight) {
  317. $searchResults.highlight(searchTerm);
  318. }
  319. }
  320. }
  321. }
  322. /**
  323. * Liefert nach erfolgter Suche die korrekte Anzahl Treffer. und erzeugt
  324. * gegebenfalls für Etracker einen 0-Treffer Event.
  325. */
  326. static updateSearchResultsMessage() {
  327. var searchHits = $('.search-hits');
  328. var resultWrapper = $('.results-wrapper');
  329. var resultVal = 0;
  330. if (typeof resultWrapper.val() !== "undefined") {
  331. resultVal = resultWrapper.data("totalresults");
  332. }
  333. // IHK-2681: 0-Treffer-Suche
  334. if (resultVal === 0) {
  335. var searchCategoryE = $("#query").data('search-category'), hasCategoryE = typeof searchCategoryE !== "undefined";
  336. var queryE = $('#query').val();
  337. var actionE = '0-Treffer-Suche';
  338. var querySource = $('#querySource').val();
  339. if ('autocomplete' === querySource) {
  340. actionE = '0-Treffer-Vorschlag';
  341. $('#querySource').val('manual');
  342. }
  343. if (!window.isPbe) {
  344. //todo: etracker
  345. window.setTimeout(EtrackerUtils.fireETrackerEvent, 250,
  346. (hasCategoryE ? searchCategoryE : 'Kombi-Suche'),
  347. queryE, actionE, '');
  348. }
  349. }
  350. searchHits.text(resultVal + " Treffer");
  351. }
  352. static getAllUrlParams(url) {
  353. // get query string from url (optional) or window
  354. var queryString = url ? url.split('?')[1] : window.location.search.slice(1);
  355. // we'll store the parameters here
  356. var obj = {};
  357. // if query string exists
  358. if (queryString) {
  359. // stuff after # is not part of query string, so get rid of it
  360. queryString = queryString.split('#')[0];
  361. // split our query string into its component parts
  362. var arr = queryString.split('&');
  363. for (var i=0; i<arr.length; i++) {
  364. // separate the keys and the values
  365. var a = arr[i].split('=');
  366. // in case params look like: list[]=thing1&list[]=thing2
  367. var paramNum = undefined;
  368. var paramName = a[0].replace(/\[\d*\]/, function(v) {
  369. paramNum = v.slice(1,-1);
  370. return '';
  371. });
  372. // set parameter value (use 'true' if empty)
  373. var paramValue = typeof(a[1])==='undefined' ? true : a[1];
  374. // if parameter name already exists
  375. if (obj[paramName]) {
  376. // convert value to array (if still string)
  377. if (typeof obj[paramName] === 'string') {
  378. obj[paramName] = [obj[paramName]];
  379. }
  380. // if no array index number specified...
  381. if (typeof paramNum === 'undefined') {
  382. // put the value on the end of the array
  383. obj[paramName].push(paramValue);
  384. }
  385. // if array index number specified...
  386. else {
  387. // put the value at that index number
  388. obj[paramName][paramNum] = paramValue;
  389. }
  390. }
  391. // if param name doesn't exist yet, set it
  392. else {
  393. obj[paramName] = paramValue;
  394. }
  395. }
  396. }
  397. return obj;
  398. }
  399. }
  400. $(document).ready(function () {
  401. // Submit-Event abfangen und stattdessen den Ajax-Call ausführen:
  402. $("#search-form").bind("submit", function () {
  403. SearchUtils.loadResults();
  404. SearchUtils.updateSearchHistoryState(1);
  405. });
  406. // Click-Event abfangen und stattdessen den Ajax-Call ausführen:
  407. $("#search-submit, #search-submit-button").click(function () {
  408. SearchUtils.loadResults();
  409. SearchUtils.updateSearchHistoryState(1);
  410. });
  411. if ($('#query').val() != null) {
  412. SearchUtils.loadResults();
  413. }
  414. });