Änderungen von Dokument Solr Search Macros

Zuletzt geändert von Daniel Herrmann am 2026/02/04 20:23

Von Version Icon 2.1 Icon
bearbeitet von Daniel Herrmann
am 2025/09/20 09:53
Änderungskommentar: Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/17.7.0]
Auf Version Icon 5.1
bearbeitet von Daniel Herrmann
am 2026/02/04 20:23
Änderungskommentar: Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/17.10.3]

Zusammenfassung

Details

Icon Seiteneigenschaften
Inhalt
... ... @@ -4,13 +4,11 @@
4 4  #set ($rangePattern = $regextool.compile('^[\[{](.+) TO (.+)[\]}]$'))
5 5  #set ($wildcardPattern = $regextool.compile('^\(.*\*.*\)$'))
6 6  
7 -#macro (displaySearchForm)
7 +#macro (_displaySearchFormBegin)
8 8   #set($void = $services.progress.startStep('#displaySearchForm'))
9 9   {{html clean="false"}}
10 - <form class="search-form row" action="$doc.getURL()" role="search">
10 + <form class="search-form" action="$doc.getURL()" role="search">
11 11   <div class="hidden">
12 - <input type="hidden" name="sort" value="$!escapetool.xml($sort)"/>
13 - <input type="hidden" name="sortOrder" value="$!escapetool.xml($sortOrder)"/>
14 14   <input type="hidden" name="highlight" value="$highlightEnabled"/>
15 15   <input type="hidden" name="facet" value="$facetEnabled"/>
16 16   ## The parameter used to determine if the request has been redirected with default search filters.
... ... @@ -27,26 +27,36 @@
27 27   #end
28 28   #end
29 29   </div>
30 - <div class="col-xs-12 col-sm-6">
28 + <div class="search-bar">
31 31   <div class="input-group">
30 + <input id="search-page-bar-input" type="search" name="text" class="form-control"
31 + title="$escapetool.xml($services.localization.render('search.page.bar.query.title'))"
32 + placeholder="$escapetool.xml($services.localization.render('search.page.bar.query.title'))"
33 + value="$escapetool.xml($text)"/>
32 32   <label class='sr-only' for='search-page-bar-input'>
33 - $services.localization.render('search.page.bar.query.title')
35 + $escapetool.xml($services.localization.render('search.page.bar.query.title'))
34 34   </label>
35 - <input id='search-page-bar-input' type='search' name='text' class='form-control withTip useTitleAsTip'
36 - title="$services.localization.render('search.page.bar.query.title')" value="$escapetool.xml($text)"/>
37 37   <span class="input-group-btn">
38 38   <button type="submit" class="btn btn-primary">
39 39   $services.icon.renderHTML('search')
40 - <span class="sr-only">$services.localization.render('search.page.bar.submit')</span>
40 + <span>$escapetool.xml($services.localization.render('search.page.bar.submit'))</span>
41 41   </button>
42 42   </span>
43 43   </div>
44 44   </div>
45 - </form>
46 46   {{/html}}
47 47   #set($void = $services.progress.endStep())
48 48  #end
49 49  
49 +## We make sure the html block in this macro is not considered as inline to avoid generating extra `p` tags.
50 +#macro (_displaySearchFormEnd)
51 +
52 + {{html clean="false"}}
53 + </form>
54 + {{/html}}
55 +
56 +#end
57 +
50 50  #macro (displaySearchDebugInfo)
51 51   (% class="search-debug" %)(((
52 52   === Debug Information ===
... ... @@ -111,12 +111,12 @@
111 111   #end
112 112   #extendQueryString($url $resetParameters)
113 113   [[{{translation key="solr.facets.resetAll"}}>>path:$url
114 - ||class="search-facets-action-reset"]]## Continue in the same paragraph.
122 + ||class="search-facets-action-reset force-no-underline"]]## Continue in the same paragraph.
115 115   {{html clean="false"}}
116 - <a href="#" class="search-facets-action-collapseAll hidden">
124 + <a href="#" class="search-facets-action-collapseAll hidden force-no-underline">
117 117   $escapetool.xml($services.localization.render('solr.facets.collapseAll'))
118 118   </a>
119 - <a href="#" class="search-facets-action-expandAll hidden">
127 + <a href="#" class="search-facets-action-expandAll hidden force-no-underline">
120 120   $escapetool.xml($services.localization.render('solr.facets.expandAll'))
121 121   </a>
122 122   <span class="clearfloats"></span>
... ... @@ -148,9 +148,10 @@
148 148   ## Show active facets (that have selected values or that have an explicit limit on the number of values, i.e.
149 149   ## pagination) as expanded. Collapse the rest, otherwise you have to scroll to see all the available facets.
150 150   #set ($facetValuesLimit = $request.getParameter("l_$facetField.name"))
151 - <div class="search-facet#if ($facetRequestValues || $facetValuesLimit) expanded#end" data-name="$facetField.name">
152 - #displaySearchFacetHeader($facetField)
153 - #displaySearchFacetBody($facetField)
159 + <div class="search-facet" data-name="$facetField.name">
160 + #set ($expanded = ($facetRequestValues || $facetValuesLimit))
161 + #displaySearchFacetHeader($facetField $expanded)
162 + #displaySearchFacetBody($facetField $expanded)
154 154   </div>
155 155   #end
156 156  #end
... ... @@ -167,7 +167,7 @@
167 167   #setVariable("$property" $classDocument.xWikiClass.get($classPropertyReference.name))
168 168  #end
169 169  
170 -#macro (displaySearchFacetHeader $facetField)
179 +#macro (displaySearchFacetHeader $facetField $expanded)
171 171   #set ($facetPrettyNameKey = "solr.field.$facetField.name")
172 172   #if ($services.localization.get($facetPrettyNameKey))
173 173   #set ($facetPrettyName = $services.localization.render($facetPrettyNameKey))
... ... @@ -182,17 +182,21 @@
182 182   #set ($facetPrettyName = $facetField.name)
183 183   #end
184 184   <div class="search-facet-header">
185 - <span id="$escapetool.xml($facetField.name)-toggler-hint">$escapetool.xml($facetPrettyName)</span>
186 - <button class="btn btn-xs facet-toggler"
187 - aria-controls="$escapetool.xml($facetField.name)-dropdown"
188 - aria-labelledby="$escapetool.xml($facetField.name)-toggler-hint">
194 + <label>$escapetool.xml($facetPrettyName)
195 + <button class="btn btn-xs facet-toggle#if(!$expanded) collapsed#end"
196 + type="button"
197 + data-toggle="collapse"
198 + data-target="#$escapetool.xml($facetField.name)-dropdown"
199 + aria-expanded="$expanded"
200 + aria-controls="$escapetool.xml($facetField.name)-dropdown">
189 189   $services.icon.renderHTML('caret-down')
190 190   </button>
203 + </label>
191 191   </div>
192 192  #end
193 193  
194 -#macro (displaySearchFacetBody $facetField)
195 - <div id="$escapetool.xml($facetField.name)-dropdown" class="search-facet-body">
207 +#macro (displaySearchFacetBody $facetField $expanded)
208 + <div id="$escapetool.xml($facetField.name)-dropdown" class="search-facet-body collapse#if($expanded) in#end">
196 196   #set ($facetDisplayer = $solrConfig.facetDisplayers.get($facetField.name))
197 197   #if (!$facetDisplayer && $facetField.name.startsWith('property.'))
198 198   ## Choose a facet displayer based on the property type.
... ... @@ -245,7 +245,7 @@
245 245   #displaySearchFacetValue($facetValue $customQueryStringParameters $customValueDisplayer false)
246 246  #end
247 247  
248 -#macro (displaySearchFacetValue $facetValue $customQueryStringParameters $customValueDisplayer $displayToggler)
261 +#macro (displaySearchFacetValue $facetValue $customQueryStringParameters $customValueDisplayer $displayToggle)
249 249   #set ($selectedValues = [])
250 250   #if ($facetRequestValues)
251 251   #set ($discard = $selectedValues.addAll($facetRequestValues.subList(0, $facetRequestValues.size())))
... ... @@ -260,7 +260,8 @@
260 260   #set ($discard = $queryStringParameters.putAll($customQueryStringParameters))
261 261   #end
262 262   #extendQueryString($url $queryStringParameters)
263 - <a href="$url" class="itemName#if ($selected) selected#end#if ($facetValue.name == '') empty#end">
276 + <a href="$url" class="itemName#if ($selected) selected#end#if ($facetValue.name == '') empty#end"
277 + #if ($facetValue.name != '')data-facetvalue="$escapetool.xml($facetValue.name)"#end>
264 264   #if ($facetValue.name == '')
265 265   #set ($facetPrettyValueKey = "solr.field.${facetField.name}.emptyValue")
266 266   #if (!$services.localization.get($facetPrettyValueKey))
... ... @@ -277,8 +277,8 @@
277 277   #end
278 278   </a>
279 279   <div class="itemCount">$facetValue.count</div>
280 - #if ($displayToggler)
281 - <button class="btn btn-xs facet-value-toggler">
294 + #if ($displayToggle)
295 + <button class="btn btn-xs facet-value-toggle">
282 282   <span class='sr-only'>$escapetool.xml($facetPrettyValue)</span>
283 283   $services.icon.renderHTML('caret-down')
284 284   </button>
... ... @@ -305,7 +305,7 @@
305 305   #end
306 306  #end
307 307  
308 -#macro (displaySearchResultsSort)
322 +#macro (_displaySearchResultsControls)
309 309   #set ($defaultSortOrder = $solrConfig.sortFields.get($type))
310 310   #if (!$defaultSortOrder)
311 311   #set ($defaultSortOrder = {'score': 'desc'})
... ... @@ -314,28 +314,63 @@
314 314   'asc': $services.icon.render('caret-up'),
315 315   'desc': $services.icon.render('caret-down')
316 316   })
317 - (% class="search-options" %)
318 - * {{translation key="solr.options"/}}
319 - #if($highlightEnabled)#extendQueryString($url {'highlight': [false]})#else#extendQueryString($url {'highlight': [true]})#end
320 - * [[{{translation key="solr.options.highlight"/}}>>path:${url}||class="options-item#if($highlightEnabled) active#end" title="$services.localization.render('solr.options.highlight.title')"]]
321 - #if($facetEnabled)#extendQueryString($url {'facet': [false]})#else#extendQueryString($url {'facet': [true]})#end
322 - * [[{{translation key="solr.options.facet"/}}>>path:${url}||class="options-item#if($facetEnabled) active#end" title="$services.localization.render('solr.options.facet.title')"]]
331 + (% class='search-results-controls' %)
332 + (((
323 323  
324 - (% class="search-results-sort" %)
325 - * {{translation key="solr.sortBy"/}}
326 - #foreach ($entry in $defaultSortOrder.entrySet())
327 - #set ($class = 'sort-item')
328 - #set ($sortOrderIndicator = $NULL)
329 - #set ($targetSortOrder = $entry.value)
330 - #if ($sort == $entry.key)
331 - #set ($class = "$class active")
332 - #set ($sortOrderHint = $services.localization.render("solr.sortOrder.$sortOrder"))
333 - #set ($sortOrderIndicator = "(% class=""sort-item-order"" title=""$sortOrderHint"" %)$sortOrderSymbol.get($sortOrder)(%%)")
334 - #set ($targetSortOrder = "#if ($sortOrder == 'asc')desc#{else}asc#end")
335 - #end
336 - #extendQueryString($url {'sort': [$entry.key], 'sortOrder': [$targetSortOrder]})
337 - * [[{{translation key="solr.sortBy.$entry.key"/}}$!sortOrderIndicator>>path:${url}||class="$class"]]
338 - #end
334 + {{html clean="false"}}
335 + <div class="search-results-sort">
336 + <label for="sort-by-input" class="sr-only">$escapetool.xml($services.localization.render('search.solr.sortBy.hint'))</label>##
337 + <select id="sort-by-input" name="sort">
338 + #foreach ($entry in $defaultSortOrder.entrySet())
339 + <option class="sort-item" value="$entry.key" #if($sort == $entry.key)selected='selected'#end>
340 + #set ($sortOptionNameList = $entry.key.split('_'))
341 + #set ($camelCasedSortOptionName = $sortOptionNameList.get(0))
342 + #foreach ($namePart in $sortOptionNameList.subList(1, $sortOptionNameList.size()))
343 + #set ($camelCasedSortOptionName = "${camelCasedSortOptionName}$stringtool.capitalize($namePart)")
344 + #end
345 + $escapetool.xml($services.localization.render("search.solr.sortBy.field.$camelCasedSortOptionName"))
346 + </option>
347 + #end
348 + </select>##
349 + <label class="form-control" title="$escapetool.xml($services.localization.render("search.solr.sortOrder.$sortOrder"))">##
350 + <input id="sort-order-input" type="checkbox" name="sortOrder" value="asc" #if ("$!sortOrder" == 'asc')checked="checked"#end/>##
351 + $services.icon.renderHTML('sort-descending')##
352 + $services.icon.renderHTML('sort-ascending')##
353 + <span class="sr-only">$escapetool.xml($services.localization.render("search.solr.sortOrder.$sortOrder"))</span>##
354 + </label>##
355 + </div>
356 + <div class="search-options">
357 + <ul>##
358 + <li>##
359 + <label>##
360 + <input id="option-highlight-input" type="checkbox" class="options-item" value="true"
361 + data-query-name="highlight"
362 + aria-describedby="option-highlight-description"
363 + title="$escapetool.xml($services.localization.render('solr.options.highlight.title'))"
364 + #if($highlightEnabled)checked#end/>##
365 + $escapetool.xml($services.localization.render('search.solr.options.showHighlight'))##
366 + </label>##
367 + <span id="option-highlight-description" class="sr-only">
368 + $escapetool.xml($services.localization.render('solr.options.highlight.title'))
369 + </span>##
370 + </li>##
371 + <li>##
372 + <label>##
373 + <input id="option-facet-input" type="checkbox" class="options-item" value="true" data-query-name="facet"
374 + aria-describedby="option-facet-description"
375 + title="$escapetool.xml($services.localization.render('solr.options.facet.title'))"
376 + #if($facetEnabled)checked#end/>##
377 + $escapetool.xml($services.localization.render('search.solr.options.showFacet'))
378 + </label>##
379 + <span id="option-facet-description" class="sr-only">
380 + $escapetool.xml($services.localization.render('solr.options.facet.title'))
381 + </span>##
382 + </li>##
383 + </ul>##
384 + </div>
385 + {{/html}}
386 +
387 + )))
339 339  #end
340 340  
341 341  #macro (extendQueryString $url $extraParameters)
... ... @@ -380,7 +380,8 @@
380 380   ## Add the parameters required to output the RSS feed instead of the search UI.
381 381   #set ($discard = $parameters.put('outputSyntax', 'plain'))
382 382   #set ($discard = $parameters.put('media', 'rss'))
383 - <a href="$doc.getURL('get', $escapetool.url($parameters))" class="hasIcon iconRSS">
432 + <a href="$doc.getURL('get', $escapetool.url($parameters))">
433 + $services.icon.renderHTML('rss')
384 384   $services.localization.render('search.rss', ["[$escapetool.xml($text)]"])
385 385   </a>
386 386   {{/html}}
... ... @@ -412,7 +412,7 @@
412 412   #displaySearchResultLocation()
413 413   <div class="search-result-author">
414 414   $services.localization.render('core.footer.modification', [
415 - "#displayUserProfileLink($searchResult.author $searchResult.author_display)",
465 + "#displayUser($searchResult.author {'useInlineHTML': true})",
416 416   $xwiki.formatDate($searchResult.date)
417 417   ])
418 418   </div>
... ... @@ -434,7 +434,7 @@
434 434   </h2>
435 435   #displaySearchResultLocation($searchResult)
436 436   <div class="search-result-uploader">
437 - #set ($uploader = "#displayUserProfileLink($searchResult.attauthor.get(0) $searchResult.attauthor_display.get(0))")
487 + #set ($uploader = "#displayUser($searchResult.attauthor.get(0) {'useInlineHTML': true})")
438 438   #set ($uploadDate = $xwiki.formatDate($searchResult.attdate.get(0)))
439 439   #set ($fileSize = "#dynamicsize($searchResult.attsize.get(0))")
440 440   $services.localization.render('solr.result.uploadedBy', [$uploader, $uploadDate, $fileSize])
... ... @@ -485,15 +485,6 @@
485 485   </div>
486 486  #end
487 487  
488 -#macro (displayUserProfileLink $userReference $userName)
489 -#if ($userReference)
490 -## We could test if the specified user exists but we want to speed up the search.
491 -<a href="$xwiki.getURL($userReference)">$escapetool.xml($userName)</a>##
492 -#else
493 -$services.localization.render('core.users.unknownUser')##
494 -#end
495 -#end
496 -
497 497  #macro (displaySearchResultHighlighting $searchResult)
498 498   #getSearchResultHighlighting($searchResult $highlighting)
499 499   #if ($highlighting.size() > 0)
... ... @@ -517,12 +517,10 @@
517 517   #end
518 518   </dl>
519 519   #if ($highlighting.size() > 1)
520 - ## We wrap the link in a DIV because otherwise the HTML cleaning generates a paragraph.
521 - <div>
522 - <a href="#" class="search-result-highlightAll hidden">
523 - $escapetool.xml($services.localization.render('solr.result.highlightAll'))
524 - </a>
525 - </div>
561 + <button class="search-result-highlightAll btn btn-xs btn-default hidden">
562 + $escapetool.xml($services.localization.render('solr.result.highlightAll'))
563 + $services.icon.renderHTML('right')
564 + </button>
526 526   #end
527 527   #end
528 528  #end
... ... @@ -594,9 +594,10 @@
594 594   ## Set query parameters.
595 595   #set ($discard = $query.setLimit($rows))
596 596   #set ($discard = $query.setOffset($start))
636 + #set ($discard = $query.addFilter('searchExclusions/solr'))
597 597   #set ($discard = $query.bindValue('sort', "${sort} ${sortOrder}"))
598 598   #set ($discard = $query.bindValue('tie', $solrConfig.tieBreaker))
599 - #set ($discard = $query.bindValue('mm', $solrConfig.minShouldMatch))
639 + #set ($discard = $query.bindValue('mm', $solrConfig.minShouldMatch))
600 600   #setQueryFields($query)
601 601   #setPhraseFields($query)
602 602   #setFacetFields($query)
... ... @@ -809,6 +809,8 @@
809 809   #if ("$!sort" == '')
810 810   #set ($sort = 'score')
811 811   #end
852 + ## If at any point this default behavior is changed, be extra careful with "#sort-order-input" initialization.
853 + ## We assume here that empty values are mapped to "desc" (meaning that we use "asc" as the checkbox value).
812 812   #set ($sortOrder = $request.sortOrder)
813 813   #if ("$!sortOrder" == '')
814 814   #set ($sortOrder = 'desc')
... ... @@ -850,12 +850,15 @@
850 850   {{/html}}
851 851  
852 852   #end
853 - #displaySearchForm()
895 + #_displaySearchFormBegin()
854 854   #if ($text != '')
855 855   #getSearchResults()
898 + #_displaySearchResultsControls()
899 + #_displaySearchFormEnd()
856 856   #if ($debug)
857 857   #displaySearchDebugInfo()
858 858   #end
903 +
859 859   (% class="search-results-container row" %)(((
860 860   #if ($facetEnabled)
861 861   (% class="col-xs-12 col-sm-4 col-sm-push-8 col-md-3 col-md-push-9" %)(((
... ... @@ -864,11 +864,11 @@
864 864   #end
865 865   (% class="search-results-left col-xs-12#if ($facetEnabled) col-sm-8 col-sm-pull-4 col-md-9 col-md-pull-3#end" %)
866 866   (((
867 - #displaySearchResultsSort()
868 -
869 869   #displaySearchResults()
870 870   )))
871 871   )))
915 + #else
916 + #_displaySearchFormEnd()
872 872   #end
873 873   )))
874 874   #set($void = $services.progress.popLevel())

Community

https://wiki.makerspace-darmstadt.de/bin/download/Panels/MKSP%20Slack/Slack_MKSP.png

Wir benutzen Slack, um miteinander zu kommunizieren. Melde Dich an und werde Teil unserer Maker-Community!

Zum Slack Workspace

Frage? FAQ!

Du hast eine Frage, die sich nicht direkt im Wiki findet?

Natürlich kannst Du die Frage jederzeit gerne in der Slack Community stellen. Bevor Du das machst, schau doch bitte einmal auf unserer Homepage bei den Häufig gestellten Fragen vorbei. Wir versuchen diese Fragen stets aktuell zu halten, eventuell hilft Dir das ja schon weiter.

Offene Werkstatt

Ohne Anmeldung einfach vorbei kommen. Am besten bringst Du direkt den ausgefüllten Haftungsauschluss mit.

Jeden Donnerstag ab 19 Uhr

Während der offenen Werkstatt kannst Du einfach vorbei kommen und an Deinem Projekt arbeiten. Bitte beachte aber, dass zur Verwendung der Maschinen eine Einweisung erforderlich ist, die Du gegebenfalls vorher absolvieren musst. Wenn ein Mitglied mit entsprechender Einweisung vor Ort ist und Zeit hat, helfen wir natürlich gerne aus. Dies können wir aber nicht garantieren, da Rundgänge Priorität haben.

Sprich Dich idealerweise schon vor der offenen Werkstatt mit einem Mitglied in unserem Slack ab. So kannst Du sicherstellen, dass Du auf jeden Fall arbeiten kannst.

Übrigens: Du kannst Dich mit einem Mitglied gerne auch außerhalb der offenen Werkstattzeiten zum Arbeiten verabreden!

Führungen und Rundgänge

Im Rahmen der offenen Werkstatt bieten wir euch auch gerne einen Rundgang durch unsere Werkstatt. Hier könnt ihr den Verein und unser Konzept kennenlernen sowie die Maschinen und Möglichkeiten der Werkstatt gezeigt bekommen.

Jeden Donnerstag wird eine Führung angeboten:

  • Um 19:15 Uhr (bitte um 19:00 Uhr da sein)

Der Rundgang dauert ca. 45 Minuten und ihr habt natürlich auch die Möglichkeit, eure Fragen loszuwerden.

Bitte beachtet folgendes: Die Werkstatt beinhaltet gefährliche Maschinen. Bringt daher bitte nach Möglichkeit den ausgefüllten und unterschrieben Haftungsauschluss schon mit. Dieser kann aber auch vor Ort ausgefüllt werden, das verzögert allerdings die Abläufe.