您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

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