Modifications pour le document Solr Search Macros

Modifié par Florent Charton le 2026/03/13 11:04

Depuis la version 1.1
modifié par superadmin
sur 2022/06/20 08:49
Commentaire de modification : Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/13.10.6]
À la version 4.1
modifié par Florent Charton
sur 2026/01/13 15:01
Commentaire de modification : Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/17.10.2]

Résumé

Détails

Propriétés de la Page
Auteur du document
... ... @@ -1,1 +1,1 @@
1 -XWiki.superadmin
1 +xwiki:XWiki.fcharton
Contenu
... ... @@ -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,23 +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">
32 - <input type="search" name="text" class="form-control withTip useTitleAsTip"
33 - title="$services.localization.render('search.page.bar.query.title')" value="$escapetool.xml($text)"/>
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 + <label class='sr-only' for='search-page-bar-input'>
35 + $escapetool.xml($services.localization.render('search.page.bar.query.title'))
36 + </label>
34 34   <span class="input-group-btn">
35 35   <button type="submit" class="btn btn-primary">
36 36   $services.icon.renderHTML('search')
37 - <span class="sr-only">$services.localization.render('search.page.bar.submit')</span>
40 + <span>$escapetool.xml($services.localization.render('search.page.bar.submit'))</span>
38 38   </button>
39 39   </span>
40 40   </div>
41 41   </div>
42 - </form>
43 43   {{/html}}
44 44   #set($void = $services.progress.endStep())
45 45  #end
46 46  
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 +
47 47  #macro (displaySearchDebugInfo)
48 48   (% class="search-debug" %)(((
49 49   === Debug Information ===
... ... @@ -108,12 +108,12 @@
108 108   #end
109 109   #extendQueryString($url $resetParameters)
110 110   [[{{translation key="solr.facets.resetAll"}}>>path:$url
111 - ||class="search-facets-action-reset"]]## Continue in the same paragraph.
122 + ||class="search-facets-action-reset force-no-underline"]]## Continue in the same paragraph.
112 112   {{html clean="false"}}
113 - <a href="#" class="search-facets-action-collapseAll hidden">
124 + <a href="#" class="search-facets-action-collapseAll hidden force-no-underline">
114 114   $escapetool.xml($services.localization.render('solr.facets.collapseAll'))
115 115   </a>
116 - <a href="#" class="search-facets-action-expandAll hidden">
127 + <a href="#" class="search-facets-action-expandAll hidden force-no-underline">
117 117   $escapetool.xml($services.localization.render('solr.facets.expandAll'))
118 118   </a>
119 119   <span class="clearfloats"></span>
... ... @@ -178,11 +178,18 @@
178 178   #else
179 179   #set ($facetPrettyName = $facetField.name)
180 180   #end
181 - <div class="search-facet-header">$escapetool.xml($facetPrettyName)</div>
192 + <div class="search-facet-header">
193 + <label>$escapetool.xml($facetPrettyName)
194 + <button class="btn btn-xs facet-toggle"
195 + aria-controls="$escapetool.xml($facetField.name)-dropdown">
196 + $services.icon.renderHTML('caret-down')
197 + </button>
198 + </label>
199 + </div>
182 182  #end
183 183  
184 184  #macro (displaySearchFacetBody $facetField)
185 - <div class="search-facet-body">
203 + <div id="$escapetool.xml($facetField.name)-dropdown" class="search-facet-body">
186 186   #set ($facetDisplayer = $solrConfig.facetDisplayers.get($facetField.name))
187 187   #if (!$facetDisplayer && $facetField.name.startsWith('property.'))
188 188   ## Choose a facet displayer based on the property type.
... ... @@ -232,6 +232,10 @@
232 232  #end
233 233  
234 234  #macro (displaySearchFacetValue $facetValue $customQueryStringParameters $customValueDisplayer)
253 + #displaySearchFacetValue($facetValue $customQueryStringParameters $customValueDisplayer false)
254 +#end
255 +
256 +#macro (displaySearchFacetValue $facetValue $customQueryStringParameters $customValueDisplayer $displayToggle)
235 235   #set ($selectedValues = [])
236 236   #if ($facetRequestValues)
237 237   #set ($discard = $selectedValues.addAll($facetRequestValues.subList(0, $facetRequestValues.size())))
... ... @@ -246,8 +246,8 @@
246 246   #set ($discard = $queryStringParameters.putAll($customQueryStringParameters))
247 247   #end
248 248   #extendQueryString($url $queryStringParameters)
249 - <div class="itemCount">$facetValue.count</div>
250 - <a href="$url" class="itemName#if ($selected) selected#end#if ($facetValue.name == '') empty#end">
271 + <a href="$url" class="itemName#if ($selected) selected#end#if ($facetValue.name == '') empty#end"
272 + #if ($facetValue.name != '')data-facetvalue="$escapetool.xml($facetValue.name)"#end>
251 251   #if ($facetValue.name == '')
252 252   #set ($facetPrettyValueKey = "solr.field.${facetField.name}.emptyValue")
253 253   #if (!$services.localization.get($facetPrettyValueKey))
... ... @@ -263,7 +263,13 @@
263 263   $escapetool.xml($facetPrettyValue)
264 264   #end
265 265   </a>
266 - <div class="clearfloats"></div>
288 + <div class="itemCount">$facetValue.count</div>
289 + #if ($displayToggle)
290 + <button class="btn btn-xs facet-value-toggle">
291 + <span class='sr-only'>$escapetool.xml($facetPrettyValue)</span>
292 + $services.icon.renderHTML('caret-down')
293 + </button>
294 + #end
267 267  #end
268 268  
269 269  #**
... ... @@ -286,7 +286,7 @@
286 286   #end
287 287  #end
288 288  
289 -#macro (displaySearchResultsSort)
317 +#macro (_displaySearchResultsControls)
290 290   #set ($defaultSortOrder = $solrConfig.sortFields.get($type))
291 291   #if (!$defaultSortOrder)
292 292   #set ($defaultSortOrder = {'score': 'desc'})
... ... @@ -295,28 +295,63 @@
295 295   'asc': $services.icon.render('caret-up'),
296 296   'desc': $services.icon.render('caret-down')
297 297   })
298 - (% class="search-options" %)
299 - * {{translation key="solr.options"/}}
300 - #if($highlightEnabled)#extendQueryString($url {'highlight': [false]})#else#extendQueryString($url {'highlight': [true]})#end
301 - * [[{{translation key="solr.options.highlight"/}}>>path:${url}||class="options-item#if($highlightEnabled) active#end" title="$services.localization.render('solr.options.highlight.title')"]]
302 - #if($facetEnabled)#extendQueryString($url {'facet': [false]})#else#extendQueryString($url {'facet': [true]})#end
303 - * [[{{translation key="solr.options.facet"/}}>>path:${url}||class="options-item#if($facetEnabled) active#end" title="$services.localization.render('solr.options.facet.title')"]]
326 + (% class='search-results-controls' %)
327 + (((
304 304  
305 - (% class="search-results-sort" %)
306 - * {{translation key="solr.sortBy"/}}
307 - #foreach ($entry in $defaultSortOrder.entrySet())
308 - #set ($class = 'sort-item')
309 - #set ($sortOrderIndicator = $NULL)
310 - #set ($targetSortOrder = $entry.value)
311 - #if ($sort == $entry.key)
312 - #set ($class = "$class active")
313 - #set ($sortOrderHint = $services.localization.render("solr.sortOrder.$sortOrder"))
314 - #set ($sortOrderIndicator = "(% class=""sort-item-order"" title=""$sortOrderHint"" %)$sortOrderSymbol.get($sortOrder)(%%)")
315 - #set ($targetSortOrder = "#if ($sortOrder == 'asc')desc#{else}asc#end")
316 - #end
317 - #extendQueryString($url {'sort': [$entry.key], 'sortOrder': [$targetSortOrder]})
318 - * [[{{translation key="solr.sortBy.$entry.key"/}}$!sortOrderIndicator>>path:${url}||class="$class"]]
319 - #end
329 + {{html clean="false"}}
330 + <div class="search-results-sort">
331 + <label for="sort-by-input" class="sr-only">$escapetool.xml($services.localization.render('search.solr.sortBy.hint'))</label>##
332 + <select id="sort-by-input" name="sort">
333 + #foreach ($entry in $defaultSortOrder.entrySet())
334 + <option class="sort-item" value="$entry.key" #if($sort == $entry.key)selected='selected'#end>
335 + #set ($sortOptionNameList = $entry.key.split('_'))
336 + #set ($camelCasedSortOptionName = $sortOptionNameList.get(0))
337 + #foreach ($namePart in $sortOptionNameList.subList(1, $sortOptionNameList.size()))
338 + #set ($camelCasedSortOptionName = "${camelCasedSortOptionName}$stringtool.capitalize($namePart)")
339 + #end
340 + $escapetool.xml($services.localization.render("search.solr.sortBy.field.$camelCasedSortOptionName"))
341 + </option>
342 + #end
343 + </select>##
344 + <label class="form-control" title="$escapetool.xml($services.localization.render("search.solr.sortOrder.$sortOrder"))">##
345 + <input id="sort-order-input" type="checkbox" name="sortOrder" value="asc" #if ("$!sortOrder" == 'asc')checked="checked"#end/>##
346 + $services.icon.renderHTML('sort-descending')##
347 + $services.icon.renderHTML('sort-ascending')##
348 + <span class="sr-only">$escapetool.xml($services.localization.render("search.solr.sortOrder.$sortOrder"))</span>##
349 + </label>##
350 + </div>
351 + <div class="search-options">
352 + <ul>##
353 + <li>##
354 + <label>##
355 + <input id="option-highlight-input" type="checkbox" class="options-item" value="true"
356 + data-query-name="highlight"
357 + aria-describedby="option-highlight-description"
358 + title="$escapetool.xml($services.localization.render('solr.options.highlight.title'))"
359 + #if($highlightEnabled)checked#end/>##
360 + $escapetool.xml($services.localization.render('search.solr.options.showHighlight'))##
361 + </label>##
362 + <span id="option-highlight-description" class="sr-only">
363 + $escapetool.xml($services.localization.render('solr.options.highlight.title'))
364 + </span>##
365 + </li>##
366 + <li>##
367 + <label>##
368 + <input id="option-facet-input" type="checkbox" class="options-item" value="true" data-query-name="facet"
369 + aria-describedby="option-facet-description"
370 + title="$escapetool.xml($services.localization.render('solr.options.facet.title'))"
371 + #if($facetEnabled)checked#end/>##
372 + $escapetool.xml($services.localization.render('search.solr.options.showFacet'))
373 + </label>##
374 + <span id="option-facet-description" class="sr-only">
375 + $escapetool.xml($services.localization.render('solr.options.facet.title'))
376 + </span>##
377 + </li>##
378 + </ul>##
379 + </div>
380 + {{/html}}
381 +
382 + )))
320 320  #end
321 321  
322 322  #macro (extendQueryString $url $extraParameters)
... ... @@ -361,7 +361,8 @@
361 361   ## Add the parameters required to output the RSS feed instead of the search UI.
362 362   #set ($discard = $parameters.put('outputSyntax', 'plain'))
363 363   #set ($discard = $parameters.put('media', 'rss'))
364 - <a href="$doc.getURL('get', $escapetool.url($parameters))" class="hasIcon iconRSS">
427 + <a href="$doc.getURL('get', $escapetool.url($parameters))">
428 + $services.icon.renderHTML('rss')
365 365   $services.localization.render('search.rss', ["[$escapetool.xml($text)]"])
366 366   </a>
367 367   {{/html}}
... ... @@ -393,7 +393,7 @@
393 393   #displaySearchResultLocation()
394 394   <div class="search-result-author">
395 395   $services.localization.render('core.footer.modification', [
396 - "#displayUserProfileLink($searchResult.author $searchResult.author_display)",
460 + "#displayUser($searchResult.author {'useInlineHTML': true})",
397 397   $xwiki.formatDate($searchResult.date)
398 398   ])
399 399   </div>
... ... @@ -415,7 +415,7 @@
415 415   </h2>
416 416   #displaySearchResultLocation($searchResult)
417 417   <div class="search-result-uploader">
418 - #set ($uploader = "#displayUserProfileLink($searchResult.attauthor.get(0) $searchResult.attauthor_display.get(0))")
482 + #set ($uploader = "#displayUser($searchResult.attauthor.get(0) {'useInlineHTML': true})")
419 419   #set ($uploadDate = $xwiki.formatDate($searchResult.attdate.get(0)))
420 420   #set ($fileSize = "#dynamicsize($searchResult.attsize.get(0))")
421 421   $services.localization.render('solr.result.uploadedBy', [$uploader, $uploadDate, $fileSize])
... ... @@ -466,15 +466,6 @@
466 466   </div>
467 467  #end
468 468  
469 -#macro (displayUserProfileLink $userReference $userName)
470 -#if ($userReference)
471 -## We could test if the specified user exists but we want to speed up the search.
472 -<a href="$xwiki.getURL($userReference)">$escapetool.xml($userName)</a>##
473 -#else
474 -$services.localization.render('core.users.unknownUser')##
475 -#end
476 -#end
477 -
478 478  #macro (displaySearchResultHighlighting $searchResult)
479 479   #getSearchResultHighlighting($searchResult $highlighting)
480 480   #if ($highlighting.size() > 0)
... ... @@ -498,12 +498,10 @@
498 498   #end
499 499   </dl>
500 500   #if ($highlighting.size() > 1)
501 - ## We wrap the link in a DIV because otherwise the HTML cleaning generates a paragraph.
502 - <div>
503 - <a href="#" class="search-result-highlightAll hidden">
504 - $escapetool.xml($services.localization.render('solr.result.highlightAll'))
505 - </a>
506 - </div>
556 + <button class="search-result-highlightAll btn btn-xs btn-default hidden">
557 + $escapetool.xml($services.localization.render('solr.result.highlightAll'))
558 + $services.icon.renderHTML('right')
559 + </button>
507 507   #end
508 508   #end
509 509  #end
... ... @@ -575,9 +575,10 @@
575 575   ## Set query parameters.
576 576   #set ($discard = $query.setLimit($rows))
577 577   #set ($discard = $query.setOffset($start))
631 + #set ($discard = $query.addFilter('searchExclusions/solr'))
578 578   #set ($discard = $query.bindValue('sort', "${sort} ${sortOrder}"))
579 579   #set ($discard = $query.bindValue('tie', $solrConfig.tieBreaker))
580 - #set ($discard = $query.bindValue('mm', $solrConfig.minShouldMatch))
634 + #set ($discard = $query.bindValue('mm', $solrConfig.minShouldMatch))
581 581   #setQueryFields($query)
582 582   #setPhraseFields($query)
583 583   #setFacetFields($query)
... ... @@ -779,10 +779,7 @@
779 779   #end
780 780   ##
781 781   ## Pagination
782 - #set ($rows = $numbertool.toNumber($request.rows).intValue())
783 - #if ("$!rows" == '')
784 - #set ($rows = 10)
785 - #end
836 + #getAndValidateQueryLimitFromRequest('rows', 10, $rows)
786 786   #set ($start = $numbertool.toNumber($request.firstIndex).intValue())
787 787   #if ("$!start" == '')
788 788   #set ($start = 0)
... ... @@ -793,6 +793,8 @@
793 793   #if ("$!sort" == '')
794 794   #set ($sort = 'score')
795 795   #end
847 + ## If at any point this default behavior is changed, be extra careful with "#sort-order-input" initialization.
848 + ## We assume here that empty values are mapped to "desc" (meaning that we use "asc" as the checkbox value).
796 796   #set ($sortOrder = $request.sortOrder)
797 797   #if ("$!sortOrder" == '')
798 798   #set ($sortOrder = 'desc')
... ... @@ -834,12 +834,15 @@
834 834   {{/html}}
835 835  
836 836   #end
837 - #displaySearchForm()
890 + #_displaySearchFormBegin()
838 838   #if ($text != '')
839 839   #getSearchResults()
893 + #_displaySearchResultsControls()
894 + #_displaySearchFormEnd()
840 840   #if ($debug)
841 841   #displaySearchDebugInfo()
842 842   #end
898 +
843 843   (% class="search-results-container row" %)(((
844 844   #if ($facetEnabled)
845 845   (% class="col-xs-12 col-sm-4 col-sm-push-8 col-md-3 col-md-push-9" %)(((
... ... @@ -848,11 +848,11 @@
848 848   #end
849 849   (% class="search-results-left col-xs-12#if ($facetEnabled) col-sm-8 col-sm-pull-4 col-md-9 col-md-pull-3#end" %)
850 850   (((
851 - #displaySearchResultsSort()
852 -
853 853   #displaySearchResults()
854 854   )))
855 855   )))
910 + #else
911 + #_displaySearchFormEnd()
856 856   #end
857 857   )))
858 858   #set($void = $services.progress.popLevel())
... ... @@ -894,8 +894,7 @@
894 894   ##
895 895   ## Output the feed.
896 896   ##
897 - #set ($discard = $response.setContentType('application/rss+xml'))
898 - $xwiki.feed.getFeedOutput($feed, 'rss_2.0')
953 + #rawResponse($xwiki.feed.getFeedOutput($feed, 'rss_2.0'), 'application/rss+xml')
899 899  #end
900 900  
901 901  #macro (handleSolrSearchRequest)