Modifications pour le document Solr Search Macros

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

Depuis la version 2.1
modifié par Florent Charton
sur 2024/08/08 18:44
Commentaire de modification : Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/15.10.11]
À la version 5.1
modifié par Florent Charton
sur 2026/03/13 11:04
Commentaire de modification : Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/17.10.4]

Résumé

Détails

Propriétés de la Page
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,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)
... ... @@ -798,10 +798,7 @@
798 798   #end
799 799   ##
800 800   ## Pagination
801 - #set ($rows = $numbertool.toNumber($request.rows).intValue())
802 - #if ("$!rows" == '')
803 - #set ($rows = 10)
804 - #end
841 + #getAndValidateQueryLimitFromRequest('rows', 10, $rows)
805 805   #set ($start = $numbertool.toNumber($request.firstIndex).intValue())
806 806   #if ("$!start" == '')
807 807   #set ($start = 0)
... ... @@ -812,6 +812,8 @@
812 812   #if ("$!sort" == '')
813 813   #set ($sort = 'score')
814 814   #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).
815 815   #set ($sortOrder = $request.sortOrder)
816 816   #if ("$!sortOrder" == '')
817 817   #set ($sortOrder = 'desc')
... ... @@ -853,12 +853,15 @@
853 853   {{/html}}
854 854  
855 855   #end
856 - #displaySearchForm()
895 + #_displaySearchFormBegin()
857 857   #if ($text != '')
858 858   #getSearchResults()
898 + #_displaySearchResultsControls()
899 + #_displaySearchFormEnd()
859 859   #if ($debug)
860 860   #displaySearchDebugInfo()
861 861   #end
903 +
862 862   (% class="search-results-container row" %)(((
863 863   #if ($facetEnabled)
864 864   (% class="col-xs-12 col-sm-4 col-sm-push-8 col-md-3 col-md-push-9" %)(((
... ... @@ -867,11 +867,11 @@
867 867   #end
868 868   (% class="search-results-left col-xs-12#if ($facetEnabled) col-sm-8 col-sm-pull-4 col-md-9 col-md-pull-3#end" %)
869 869   (((
870 - #displaySearchResultsSort()
871 -
872 872   #displaySearchResults()
873 873   )))
874 874   )))
915 + #else
916 + #_displaySearchFormEnd()
875 875   #end
876 876   )))
877 877   #set($void = $services.progress.popLevel())