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

465 行
15 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 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&nbsp;";
  114. const ephasizedText = $('<strong/>').text(`${firstWrapper.attr('data-totalresults')} Treffer`);
  115. btnAll.addClass('active').html(defaultSearchTextAll).append(ephasizedText);
  116. $('.results-wrapper').not('.no-border').each(function () {
  117. const rw = $(this);
  118. const btn = $('<a />').addClass('btn btn-small primary-light').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.addClass("primary-light");
  129. btnAll.attr('href', buttonWrapper.attr('data-searchcategoryaddition-link') + "?query=" + encodeURIComponent(queryP));
  130. } else {
  131. buttonWrapper.children().remove();
  132. }
  133. }
  134. /**
  135. * Berechnet die Url-Parameter für die Suchfilter.
  136. */
  137. static getQueryParameter() {
  138. var queryFields = $('#ev-search-filter-form').find('[data-queryparam]');
  139. var queryParams = "";
  140. if (queryFields.length) {
  141. var input = queryFields.filter('input[type!="checkbox"]');
  142. if (input.length) {
  143. queryParams = queryParams + "&" + $.param(input);
  144. }
  145. var select = queryFields.filter('select');
  146. if (select.length) {
  147. queryParams = queryParams + "&" + $.param(select);
  148. }
  149. var check = queryFields.filter('input[type="checkbox"]:checked');
  150. if (check.length) {
  151. queryParams = queryParams + "&" + $.param(check);
  152. }
  153. }
  154. return queryParams;
  155. }
  156. /**
  157. * Berechnet die Url-Parameter für die Seitenpaginierung.
  158. */
  159. static getPagingParameter() {
  160. var params = "";
  161. var resultWrapper = $('.results-wrapper');
  162. if (resultWrapper.length) {
  163. var total = resultWrapper.data("totalresults");
  164. var itemsPerPage = resultWrapper.data("resultsperpage");
  165. var numPages = resultWrapper.data("numpages");
  166. var pointerWithName = resultWrapper[resultWrapper.length -1].dataset.pointermap;
  167. var currentPageWithName = resultWrapper[resultWrapper.length -1].dataset.currentpagemap;
  168. if (!(total === undefined)) {
  169. params = params + "&totalResults=" + total;
  170. }
  171. if (!(itemsPerPage === undefined)) {
  172. params = params + "&resultsPerPage=" + itemsPerPage;
  173. }
  174. if (!(numPages === undefined)) {
  175. params = params + "&numPages=" + numPages;
  176. }
  177. if (!(pointerWithName === undefined)) {
  178. params = params + "&pointerMap=" + encodeURIComponent(pointerWithName);
  179. }
  180. if (!(currentPageWithName === undefined)) {
  181. params = params + "&currentPageMap=" + encodeURIComponent(currentPageWithName);
  182. }
  183. }
  184. return params;
  185. }
  186. static initEventsScrollPreservance(){
  187. $(document).on("click", "#search-results .results-wrapper .event-component",function(event){
  188. const originalHistoryState = history.state ||{};
  189. originalHistoryState.lastScrollPosition = $(window).scrollTop();
  190. history.replaceState(originalHistoryState, document.title);
  191. });
  192. }
  193. static scrollToLastViewedEvent(){
  194. if(history.state && history.state.lastScrollPosition){
  195. requestAnimationFrame(()=>{
  196. $('html, body').animate(
  197. {
  198. scrollTop : history.state.lastScrollPosition
  199. }, 500);
  200. });
  201. }
  202. }
  203. static updateSearchHistoryState(lastScrolledPage){
  204. try{
  205. const originalHistoryState = {};
  206. originalHistoryState.lastScrolledSearchPage = lastScrolledPage;
  207. history.replaceState(originalHistoryState, document.title);
  208. } catch(e) {
  209. console.warn("Could not update history state", e);
  210. }
  211. }
  212. /**
  213. * Initialisiert das Endlosscrolling für Trefferlisten.
  214. */
  215. static initInfiniteScroll() {
  216. ihk.resources = ihk.resources || {loadSpinner: ""};
  217. const $infiniteScrollContainer = $('.search-results #dummy-wrapper');
  218. if ($infiniteScrollContainer.length > 0) {
  219. const $pagingNav = $('.paging-nav');
  220. $pagingNav.hide();
  221. SearchUtils.updateSearchResultsMessage();
  222. SearchUtils.highlightSearchTerm();
  223. const infiniteScrollObj = new InfiniteScroll($infiniteScrollContainer[0],{
  224. onInit: function(){
  225. if(history.state && history.state.lastScrolledSearchPage ){
  226. const lastScrolledPageFromHistory = history.state.lastScrolledSearchPage;
  227. // load the last scrolled page after leaving the page and returning
  228. if((lastScrolledPageFromHistory > 1) && (lastScrolledPageFromHistory >= this.pageIndex)){
  229. SearchUtils.shouldPreloadSearchEnteries = true;
  230. requestAnimationFrame(()=>{
  231. this.loadNextPage().then(function (loaded) {
  232. let { response, body, items } = loaded;
  233. console.log( response );
  234. console.log( body );
  235. console.log( items );
  236. /** const resultWrapper = $('.results-wrapper');
  237. resultWrapper.data("pointermap", "{antrago=6, sweap=4}");
  238. resultWrapper.data("currentpagemap", "{antrago=2, sweap=1}");
  239. console.log(resultWrapper);**/
  240. });
  241. });
  242. }
  243. }
  244. },
  245. path: function () {
  246. // Load the second page because we do presearch
  247. const index = this.pageIndex + 1;
  248. const resultWrapper = $('.results-wrapper');
  249. if (resultWrapper.length) {
  250. const numPages = resultWrapper
  251. .data("numpages");
  252. if ((numPages === undefined)
  253. || (index <= numPages)) {
  254. return $('.search-results')
  255. .data(
  256. "infinitescroll-normal-return-url")
  257. + "?query="
  258. + encodeURIComponent($(
  259. '#query').val())
  260. + "&currentPage="
  261. + index
  262. + SearchUtils.getQueryParameter()
  263. + SearchUtils.getPagingParameter();
  264. }
  265. }
  266. return "";// damit nicht stumpf wiederholt
  267. // das letzte Ergebnis
  268. // angehangen wird!
  269. },
  270. append: ".results-wrapper",
  271. responseBody: "html",
  272. history: false,
  273. // debug: true -> for developement
  274. });
  275. infiniteScrollObj.on( 'append', function( response, path, items ) {
  276. if($(items).is(".results-wrapper")){
  277. const pageIndex = this.pageIndex;
  278. if(SearchUtils.shouldPreloadSearchEnteries){
  279. if(history.state && history.state.lastScrolledSearchPage > pageIndex){
  280. this.loadNextPage();
  281. } else {
  282. SearchUtils.shouldPreloadSearchEnteries = false;
  283. SearchUtils.scrollToLastViewedEvent();
  284. }
  285. }else {
  286. SearchUtils.updateSearchHistoryState(pageIndex);
  287. SearchUtils.highlightSearchTerm();
  288. }
  289. }else {
  290. // Destroy falls keine results mehr
  291. infiniteScrollObj.destroy();
  292. }
  293. });
  294. }
  295. }
  296. /**
  297. * Markiert nach erfolgter Suche den Suchbegriff innerhalb der Trefferliste.
  298. */
  299. static highlightSearchTerm() {
  300. var $searchResults = $('.search-results .results-wrapper .result'), $searchField = $('#query');
  301. // highlight search term
  302. if ($searchResults.length > 0 && $searchField.length > 0) {
  303. var searchTerm = $searchField.val();
  304. if (typeof searchTerm !== 'undefined') {
  305. if ($searchResults.highlight) {
  306. $searchResults.highlight(searchTerm);
  307. }
  308. }
  309. }
  310. }
  311. /**
  312. * Liefert nach erfolgter Suche die korrekte Anzahl Treffer. und erzeugt
  313. * gegebenfalls für Etracker einen 0-Treffer Event.
  314. */
  315. static updateSearchResultsMessage() {
  316. var searchHits = $('.search-hits');
  317. var resultWrapper = $('.results-wrapper');
  318. var resultVal = 0;
  319. if (typeof resultWrapper.val() !== "undefined") {
  320. resultVal = resultWrapper.data("totalresults");
  321. }
  322. // IHK-2681: 0-Treffer-Suche
  323. if (resultVal === 0) {
  324. var searchCategoryE = $("#query").data('search-category'), hasCategoryE = typeof searchCategoryE !== "undefined";
  325. var queryE = $('#query').val();
  326. var actionE = '0-Treffer-Suche';
  327. var querySource = $('#querySource').val();
  328. if ('autocomplete' === querySource) {
  329. actionE = '0-Treffer-Vorschlag';
  330. $('#querySource').val('manual');
  331. }
  332. if (!window.isPbe) {
  333. //todo: etracker
  334. window.setTimeout(EtrackerUtils.fireETrackerEvent, 250,
  335. (hasCategoryE ? searchCategoryE : 'Kombi-Suche'),
  336. queryE, actionE, '');
  337. }
  338. }
  339. searchHits.text(resultVal + " Treffer");
  340. }
  341. static getAllUrlParams(url) {
  342. // get query string from url (optional) or window
  343. var queryString = url ? url.split('?')[1] : window.location.search.slice(1);
  344. // we'll store the parameters here
  345. var obj = {};
  346. // if query string exists
  347. if (queryString) {
  348. // stuff after # is not part of query string, so get rid of it
  349. queryString = queryString.split('#')[0];
  350. // split our query string into its component parts
  351. var arr = queryString.split('&');
  352. for (var i=0; i<arr.length; i++) {
  353. // separate the keys and the values
  354. var a = arr[i].split('=');
  355. // in case params look like: list[]=thing1&list[]=thing2
  356. var paramNum = undefined;
  357. var paramName = a[0].replace(/\[\d*\]/, function(v) {
  358. paramNum = v.slice(1,-1);
  359. return '';
  360. });
  361. // set parameter value (use 'true' if empty)
  362. var paramValue = typeof(a[1])==='undefined' ? true : a[1];
  363. // if parameter name already exists
  364. if (obj[paramName]) {
  365. // convert value to array (if still string)
  366. if (typeof obj[paramName] === 'string') {
  367. obj[paramName] = [obj[paramName]];
  368. }
  369. // if no array index number specified...
  370. if (typeof paramNum === 'undefined') {
  371. // put the value on the end of the array
  372. obj[paramName].push(paramValue);
  373. }
  374. // if array index number specified...
  375. else {
  376. // put the value at that index number
  377. obj[paramName][paramNum] = paramValue;
  378. }
  379. }
  380. // if param name doesn't exist yet, set it
  381. else {
  382. obj[paramName] = paramValue;
  383. }
  384. }
  385. }
  386. return obj;
  387. }
  388. }
  389. $(document).ready(function () {
  390. // Submit-Event abfangen und stattdessen den Ajax-Call ausführen:
  391. $("#search-form").bind("submit", function () {
  392. SearchUtils.loadResults();
  393. SearchUtils.updateSearchHistoryState(1);
  394. });
  395. // Click-Event abfangen und stattdessen den Ajax-Call ausführen:
  396. $("#search-submit, #search-submit-button").click(function () {
  397. SearchUtils.loadResults();
  398. SearchUtils.updateSearchHistoryState(1);
  399. });
  400. if ($('#query').val() != null) {
  401. SearchUtils.loadResults();
  402. }
  403. });