Änderungen von Dokument Solr Search Macros

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

Von 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]
Auf Version Icon 3.1 Icon
bearbeitet von Daniel Herrmann
am 2025/11/08 02:44
Änderungskommentar: Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/17.9.0]

Zusammenfassung

Details

Icon Seiteneigenschaften
Inhalt
... ... @@ -4,11 +4,13 @@
4 4  #set ($rangePattern = $regextool.compile('^[\[{](.+) TO (.+)[\]}]$'))
5 5  #set ($wildcardPattern = $regextool.compile('^\(.*\*.*\)$'))
6 6  
7 -#macro (_displaySearchFormBegin)
7 +#macro (displaySearchForm)
8 8   #set($void = $services.progress.startStep('#displaySearchForm'))
9 9   {{html clean="false"}}
10 - <form class="search-form" action="$doc.getURL()" role="search">
10 + <form class="search-form row" 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)"/>
12 12   <input type="hidden" name="highlight" value="$highlightEnabled"/>
13 13   <input type="hidden" name="facet" value="$facetEnabled"/>
14 14   ## The parameter used to determine if the request has been redirected with default search filters.
... ... @@ -25,36 +25,26 @@
25 25   #end
26 26   #end
27 27   </div>
28 - <div class="search-bar">
30 + <div class="col-xs-12 col-sm-6">
29 29   <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)"/>
34 34   <label class='sr-only' for='search-page-bar-input'>
35 - $escapetool.xml($services.localization.render('search.page.bar.query.title'))
33 + $services.localization.render('search.page.bar.query.title')
36 36   </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>$escapetool.xml($services.localization.render('search.page.bar.submit'))</span>
40 + <span class="sr-only">$services.localization.render('search.page.bar.submit')</span>
41 41   </button>
42 42   </span>
43 43   </div>
44 44   </div>
45 + </form>
45 45   {{/html}}
46 46   #set($void = $services.progress.endStep())
47 47  #end
48 48  
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 -
58 58  #macro (displaySearchDebugInfo)
59 59   (% class="search-debug" %)(((
60 60   === Debug Information ===
... ... @@ -119,12 +119,12 @@
119 119   #end
120 120   #extendQueryString($url $resetParameters)
121 121   [[{{translation key="solr.facets.resetAll"}}>>path:$url
122 - ||class="search-facets-action-reset force-no-underline"]]## Continue in the same paragraph.
114 + ||class="search-facets-action-reset"]]## Continue in the same paragraph.
123 123   {{html clean="false"}}
124 - <a href="#" class="search-facets-action-collapseAll hidden force-no-underline">
116 + <a href="#" class="search-facets-action-collapseAll hidden">
125 125   $escapetool.xml($services.localization.render('solr.facets.collapseAll'))
126 126   </a>
127 - <a href="#" class="search-facets-action-expandAll hidden force-no-underline">
119 + <a href="#" class="search-facets-action-expandAll hidden">
128 128   $escapetool.xml($services.localization.render('solr.facets.expandAll'))
129 129   </a>
130 130   <span class="clearfloats"></span>
... ... @@ -156,10 +156,9 @@
156 156   ## Show active facets (that have selected values or that have an explicit limit on the number of values, i.e.
157 157   ## pagination) as expanded. Collapse the rest, otherwise you have to scroll to see all the available facets.
158 158   #set ($facetValuesLimit = $request.getParameter("l_$facetField.name"))
159 - <div class="search-facet" data-name="$facetField.name">
160 - #set ($expanded = ($facetRequestValues || $facetValuesLimit))
161 - #displaySearchFacetHeader($facetField $expanded)
162 - #displaySearchFacetBody($facetField $expanded)
151 + <div class="search-facet#if ($facetRequestValues || $facetValuesLimit) expanded#end" data-name="$facetField.name">
152 + #displaySearchFacetHeader($facetField)
153 + #displaySearchFacetBody($facetField)
163 163   </div>
164 164   #end
165 165  #end
... ... @@ -176,7 +176,7 @@
176 176   #setVariable("$property" $classDocument.xWikiClass.get($classPropertyReference.name))
177 177  #end
178 178  
179 -#macro (displaySearchFacetHeader $facetField $expanded)
170 +#macro (displaySearchFacetHeader $facetField)
180 180   #set ($facetPrettyNameKey = "solr.field.$facetField.name")
181 181   #if ($services.localization.get($facetPrettyNameKey))
182 182   #set ($facetPrettyName = $services.localization.render($facetPrettyNameKey))
... ... @@ -191,21 +191,17 @@
191 191   #set ($facetPrettyName = $facetField.name)
192 192   #end
193 193   <div class="search-facet-header">
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">
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">
201 201   $services.icon.renderHTML('caret-down')
202 202   </button>
203 - </label>
204 204   </div>
205 205  #end
206 206  
207 -#macro (displaySearchFacetBody $facetField $expanded)
208 - <div id="$escapetool.xml($facetField.name)-dropdown" class="search-facet-body collapse#if($expanded) in#end">
194 +#macro (displaySearchFacetBody $facetField)
195 + <div id="$escapetool.xml($facetField.name)-dropdown" class="search-facet-body">
209 209   #set ($facetDisplayer = $solrConfig.facetDisplayers.get($facetField.name))
210 210   #if (!$facetDisplayer && $facetField.name.startsWith('property.'))
211 211   ## Choose a facet displayer based on the property type.
... ... @@ -258,7 +258,7 @@
258 258   #displaySearchFacetValue($facetValue $customQueryStringParameters $customValueDisplayer false)
259 259  #end
260 260  
261 -#macro (displaySearchFacetValue $facetValue $customQueryStringParameters $customValueDisplayer $displayToggle)
248 +#macro (displaySearchFacetValue $facetValue $customQueryStringParameters $customValueDisplayer $displayToggler)
262 262   #set ($selectedValues = [])
263 263   #if ($facetRequestValues)
264 264   #set ($discard = $selectedValues.addAll($facetRequestValues.subList(0, $facetRequestValues.size())))
... ... @@ -273,8 +273,7 @@
273 273   #set ($discard = $queryStringParameters.putAll($customQueryStringParameters))
274 274   #end
275 275   #extendQueryString($url $queryStringParameters)
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>
263 + <a href="$url" class="itemName#if ($selected) selected#end#if ($facetValue.name == '') empty#end">
278 278   #if ($facetValue.name == '')
279 279   #set ($facetPrettyValueKey = "solr.field.${facetField.name}.emptyValue")
280 280   #if (!$services.localization.get($facetPrettyValueKey))
... ... @@ -291,8 +291,8 @@
291 291   #end
292 292   </a>
293 293   <div class="itemCount">$facetValue.count</div>
294 - #if ($displayToggle)
295 - <button class="btn btn-xs facet-value-toggle">
280 + #if ($displayToggler)
281 + <button class="btn btn-xs facet-value-toggler">
296 296   <span class='sr-only'>$escapetool.xml($facetPrettyValue)</span>
297 297   $services.icon.renderHTML('caret-down')
298 298   </button>
... ... @@ -319,7 +319,7 @@
319 319   #end
320 320  #end
321 321  
322 -#macro (_displaySearchResultsControls)
308 +#macro (displaySearchResultsSort)
323 323   #set ($defaultSortOrder = $solrConfig.sortFields.get($type))
324 324   #if (!$defaultSortOrder)
325 325   #set ($defaultSortOrder = {'score': 'desc'})
... ... @@ -328,63 +328,28 @@
328 328   'asc': $services.icon.render('caret-up'),
329 329   'desc': $services.icon.render('caret-down')
330 330   })
331 - (% class='search-results-controls' %)
332 - (((
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')"]]
333 333  
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 - )))
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
388 388  #end
389 389  
390 390  #macro (extendQueryString $url $extraParameters)
... ... @@ -429,8 +429,7 @@
429 429   ## Add the parameters required to output the RSS feed instead of the search UI.
430 430   #set ($discard = $parameters.put('outputSyntax', 'plain'))
431 431   #set ($discard = $parameters.put('media', 'rss'))
432 - <a href="$doc.getURL('get', $escapetool.url($parameters))">
433 - $services.icon.renderHTML('rss')
383 + <a href="$doc.getURL('get', $escapetool.url($parameters))" class="hasIcon iconRSS">
434 434   $services.localization.render('search.rss', ["[$escapetool.xml($text)]"])
435 435   </a>
436 436   {{/html}}
... ... @@ -462,7 +462,7 @@
462 462   #displaySearchResultLocation()
463 463   <div class="search-result-author">
464 464   $services.localization.render('core.footer.modification', [
465 - "#displayUser($searchResult.author {'useInlineHTML': true})",
415 + "#displayUserProfileLink($searchResult.author $searchResult.author_display)",
466 466   $xwiki.formatDate($searchResult.date)
467 467   ])
468 468   </div>
... ... @@ -484,7 +484,7 @@
484 484   </h2>
485 485   #displaySearchResultLocation($searchResult)
486 486   <div class="search-result-uploader">
487 - #set ($uploader = "#displayUser($searchResult.attauthor.get(0) {'useInlineHTML': true})")
437 + #set ($uploader = "#displayUserProfileLink($searchResult.attauthor.get(0) $searchResult.attauthor_display.get(0))")
488 488   #set ($uploadDate = $xwiki.formatDate($searchResult.attdate.get(0)))
489 489   #set ($fileSize = "#dynamicsize($searchResult.attsize.get(0))")
490 490   $services.localization.render('solr.result.uploadedBy', [$uploader, $uploadDate, $fileSize])
... ... @@ -535,6 +535,15 @@
535 535   </div>
536 536  #end
537 537  
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 +
538 538  #macro (displaySearchResultHighlighting $searchResult)
539 539   #getSearchResultHighlighting($searchResult $highlighting)
540 540   #if ($highlighting.size() > 0)
... ... @@ -558,10 +558,12 @@
558 558   #end
559 559   </dl>
560 560   #if ($highlighting.size() > 1)
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>
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>
565 565   #end
566 566   #end
567 567  #end
... ... @@ -849,8 +849,6 @@
849 849   #if ("$!sort" == '')
850 850   #set ($sort = 'score')
851 851   #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).
854 854   #set ($sortOrder = $request.sortOrder)
855 855   #if ("$!sortOrder" == '')
856 856   #set ($sortOrder = 'desc')
... ... @@ -892,15 +892,12 @@
892 892   {{/html}}
893 893  
894 894   #end
895 - #_displaySearchFormBegin()
854 + #displaySearchForm()
896 896   #if ($text != '')
897 897   #getSearchResults()
898 - #_displaySearchResultsControls()
899 - #_displaySearchFormEnd()
900 900   #if ($debug)
901 901   #displaySearchDebugInfo()
902 902   #end
903 -
904 904   (% class="search-results-container row" %)(((
905 905   #if ($facetEnabled)
906 906   (% class="col-xs-12 col-sm-4 col-sm-push-8 col-md-3 col-md-push-9" %)(((
... ... @@ -909,11 +909,11 @@
909 909   #end
910 910   (% class="search-results-left col-xs-12#if ($facetEnabled) col-sm-8 col-sm-pull-4 col-md-9 col-md-pull-3#end" %)
911 911   (((
868 + #displaySearchResultsSort()
869 +
912 912   #displaySearchResults()
913 913   )))
914 914   )))
915 - #else
916 - #_displaySearchFormEnd()
917 917   #end
918 918   )))
919 919   #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.