Changes for page Solr Search
Last modified by teamwire004 on 2026/03/03 08:31
From version 6.1
edited by teamwire004
on 2026/03/03 08:31
on 2026/03/03 08:31
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/17.10.3]
To version 4.1
edited by teamwire005
on 2025/01/07 08:42
on 2025/01/07 08:42
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-search-solr-ui/16.10.2]
Summary
-
Page properties (1 modified, 0 added, 0 removed)
-
Objects (2 modified, 0 added, 0 removed)
Details
- Page properties
-
- Author
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki.teamwire00 41 +XWiki.teamwire005
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -1,7 +1,11 @@ 1 1 require(['jquery', 'xwiki-events-bridge'], function($) { 2 2 var enhanceSearchResultHighlights = function() { 3 - consthighlights = $(this).removeClass('hidden').prev('.search-result-highlights').addClass('preview');3 + var highlights = $(this).removeClass('hidden').parent().prev('.search-result-highlights').addClass('preview'); 4 4 5 + // Workaround for IE8 which doesn't support :first-of-type CSS selector. 6 + highlights.find('.search-result-highlight').first().addClass('first').parent('dd').addClass('first') 7 + .prev('dt').addClass('first'); 8 + 5 5 $(this).one('click', function(event) { 6 6 event.preventDefault(); 7 7 $(event.target).remove(); ... ... @@ -11,19 +11,19 @@ 11 11 12 12 var collapseAllFacets = function(event) { 13 13 event.preventDefault(); 14 - $(event.target).closest('.search-facets').find('.search-facet .search-facet-body').collapse('hide');18 + $(event.target).closest('.search-facets').find('.search-facet').removeClass('expanded'); 15 15 $(event.target).hide().parent().children('.search-facets-action-expandAll').show(); 16 16 }; 17 17 18 18 var expandAllFacets = function(event) { 19 19 event.preventDefault(); 20 - $(event.target).closest('.search-facets').find('.search-facet .search-facet-body').collapse('show');24 + $(event.target).closest('.search-facets').find('.search-facet').addClass('expanded'); 21 21 $(event.target).hide().parent().children('.search-facets-action-collapseAll').show(); 22 22 }; 23 23 24 24 var updateExpandCollapseAllFacetsState = function(facetsContainer) { 25 - letfacetCount = facetsContainer.find('.search-facet').length;26 - letexpandedFacetCount = facetsContainer.find('.search-facet-body.collapse.in').length;29 + var facetCount = facetsContainer.find('.search-facet').length; 30 + var expandedFacetCount = facetsContainer.find('.search-facet.expanded').length; 27 27 if (expandedFacetCount > facetCount / 2) { 28 28 facetsContainer.find('.search-facets-action-collapseAll').show() 29 29 .parent().children('.search-facets-action-expandAll').hide(); ... ... @@ -33,16 +33,10 @@ 33 33 } 34 34 }; 35 35 36 - var addFacetValueCheckbox = function() { 40 + var addFacetValueCheckbox = function(index) { 37 37 // Create an id unique to the facet value. 38 38 let facetContainer = $(this).parents('.search-facet').first(); 39 - // We need the ids of the target facet elements to stay stable through the change, in order to refocus the item 40 - // that was clicked and triggered the change. 41 - // We use the JQuery index, so that id indexes are reset across facetContainers. 42 - // This allows for stable indexes: when reloading the facets after changing the filter for the target facet X, 43 - // the ids of all the checkbox for the target facet X will keep the same index. 44 - // This property is lost if multiple facets are changed in the query at once. 45 - $(this).attr('id', facetContainer.attr('data-name') + '-' + facetContainer.find('a.itemName').index($(this))); 43 + $(this).attr('id', facetContainer.attr('data-name') + '-' + index.toString()); 46 46 // Initialize the checkbox. 47 47 let checkBox = $(document.createElement('input')).attr('type', 'checkbox'); 48 48 checkBox.attr('aria-labelledby', $(this).attr('id')); ... ... @@ -70,7 +70,8 @@ 70 70 updateExpandCollapseAllFacetsState(facetsContainer); 71 71 72 72 // Expand/Collapse toggle for each facet. 73 - facetsContainer.find('.search-facet-body').on('hidden.bs.collapse shown.bs.collapse', function(event) { 71 + facetsContainer.find('.facet-toggler').on('click', function(event) { 72 + $(event.target).parents('.search-facet').toggleClass('expanded'); 74 74 updateExpandCollapseAllFacetsState(facetsContainer); 75 75 }); 76 76 ... ... @@ -84,15 +84,10 @@ 84 84 var queryIndex = url.indexOf('?'); 85 85 return queryIndex < 0 ? '' : url.substr(queryIndex + 1); 86 86 }; 87 - 88 - let removeQueryString = function(url) { 89 - let queryIndex = url.indexOf('?'); 90 - return queryIndex < 0 ? url : url.substring(0, queryIndex); 91 - }; 92 92 93 93 var getSearchUIState = function() { 94 94 var expandedFacets = []; 95 - $('.search-facet :has(btn.facet-toggle:not(.collapsed))').each(function() {89 + $('.search-facet.expanded').each(function() { 96 96 expandedFacets.push($(this).attr('data-name')); 97 97 }); 98 98 return { ... ... @@ -103,7 +103,7 @@ 103 103 var setSearchUIState = function(state) { 104 104 state = state || {}; 105 105 var expandedFacets = state.expandedFacets || []; 106 - $('.search-facet :has(btn.facet-toggle.collapsed)').each(function() {100 + $('.search-facet').not('.expanded').each(function() { 107 107 if (expandedFacets.indexOf($(this).attr('data-name')) >= 0) { 108 108 $(this).addClass('expanded'); 109 109 } ... ... @@ -118,9 +118,7 @@ 118 118 119 119 var searchRequest = null; 120 120 121 - // changeTargetSelector is the CSS selector of the facet anchor that initiated this reload. ' 122 - // We expect the focus to go back to this place once the UI is reloaded. 123 - var pushSearchUIState = function(viewURL, changeTargetSelector) { 115 + var pushSearchUIState = function(viewURL) { 124 124 // If there is a request in progress, abort it to prevent its callback from being called. 125 125 searchRequest && searchRequest.abort(); 126 126 $('.search-ui').attr('aria-busy', true); ... ... @@ -133,7 +133,6 @@ 133 133 window.history.replaceState && window.history.replaceState(state, document.title); 134 134 // Make sure the browser address bar reflects the new state (and thus the new state can be bookmarked). 135 135 window.history.pushState && window.history.pushState(state, document.title, viewURL); 136 - document.querySelector(changeTargetSelector)?.focus(); 137 137 }); 138 138 }; 139 139 ... ... @@ -140,12 +140,12 @@ 140 140 var reloadSearchUI = function(event) { 141 141 event.preventDefault(); 142 142 var anchor = $(event.target).closest('a'); 143 - anchor.length && anchor.first().trigger('xwiki:search:update', anchor.attr('href'));134 + anchor.length && $(document).trigger('xwiki:search:update', anchor.attr('href')); 144 144 }; 145 145 146 146 // Others (e.g. a custom facet) can trigger a search UI update by firing this event. 147 147 $(document).on('xwiki:search:update', function(event, viewURL) { 148 - pushSearchUIState(viewURL , `[data-facetvalue='${CSS.escape(event.target.dataset.facetvalue)}']`);139 + pushSearchUIState(viewURL); 149 149 }); 150 150 151 151 $(window).on('popstate', function(event) { ... ... @@ -185,41 +185,10 @@ 185 185 }); 186 186 187 187 var enhanceSearchUI = function() { 188 - // Enhance search options 189 - document.querySelectorAll('input.options-item').forEach(function (option){ 190 - option.addEventListener('change', function() { 191 - let queryFieldName = this.getAttribute('data-query-name'); 192 - let queryField = document.querySelector('input[name="' + queryFieldName + '"]'); 193 - queryField.value = this.checked ? 'true' : 'false'; 194 - // We want to build the URL the same way it's done in the velocimacro #extendQueryString 195 - // We retrieve the search parameters of the latest request 196 - let params = new URLSearchParams(window.location.search); 197 - let formParams = new URLSearchParams(new FormData(this.form)); 198 - // We replace the existing parameters with their value from the form 199 - for (let param of formParams.keys()) { 200 - if (params.has(param)) params.delete(param); 201 - for (let paramValue of formParams.getAll(param)) { 202 - params.append(param,paramValue); 203 - } 204 - } 205 - pushSearchUIState(window.location.pathname + '?' + params.toString(), 206 - 'input[data-query-name="' + queryFieldName + '"]'); 207 - }); 208 - }); 209 - // Enhance search result sorting 210 - document.querySelectorAll('.search-results-sort select#sort-by-input, ' + 211 - '.search-results-sort input#sort-order-input').forEach(function (sortInput){ 212 - sortInput.addEventListener('change', function() { 213 - let baseURL = removeQueryString(this.form.getAttribute('action')); 214 - pushSearchUIState(baseURL + "?" + 215 - new URLSearchParams(new FormData(this.form)).toString(), 216 - 'input[data-query-name="' + this.getAttribute('name') + '"]'); 217 - }); 218 - }); 219 - 220 220 $('.search-result-highlightAll').each(enhanceSearchResultHighlights); 221 221 $('.search-facets').each(enhanceSearchFacets); 222 222 $([ 182 + '.search-results-sort a.sort-item', 223 223 '.search-options a.options-item', 224 224 '.pagination a', 225 225 '.controlPagination a',
- XWiki.StyleSheetExtension[0]
-
- Code
-
... ... @@ -1,7 +1,7 @@ 1 1 #template('colorThemeInit.vm') 2 2 3 3 /* Hide the 'Created by', 'Modified by' and 'Tags' document sections. */ 4 -.xdocLastModification, #xdocFooter { 4 +.xdocLastModification, .skin-colibri #document-info, #xdocFooter { 5 5 display: none; 6 6 } 7 7 #document-title > h1 { ... ... @@ -9,99 +9,86 @@ 9 9 margin-bottom: 0; 10 10 } 11 11 12 -/** 13 - * Layout for the search bar 14 - */ 15 -.search-bar { 16 - margin: .5em 0; 17 -} 18 - 19 -@media (min-width: 768px) { 20 - .search-bar { 21 - max-width: 50%; 22 - } 23 -} 24 - 25 25 /** 26 - * Layout for searchcontrols (sort + options)13 + * Search form 27 27 */ 28 28 29 -.search-results-controls { 30 - display: flex; 31 - flex-wrap: wrap; 32 - gap: 1em; 33 - 34 - & label { 35 - /* Reset the styles of the labels. */ 36 - margin: 0; 37 - font-weight: unset; 38 - } 16 +.skin-colibri .search-form { 17 + /* There is no space after the title in Colibri. */ 18 + margin-top: 1.5em; 39 39 } 40 40 41 -.search-results-sort, 42 -.search-options, .search-options > ul, .search-options > ul > li, 43 -.search-options > ul > li > label { 44 - display: flex; 45 - gap: .4em; 46 - align-items: center; 21 +.skin-colibri .search-form input[type="search"] { 22 + /* Colibri doesn't have the grid system. */ 23 + width: 50%; 47 47 } 48 48 49 49 /** 50 50 * Sort 51 51 */ 52 -/* This select should be especially lightweight on the UI. We're removing the default border and shadow. */ 53 -#sort-by-input { 54 - cursor: pointer; 55 55 56 - &:hover, &:focus { 57 - cursor: pointer; 58 - } 59 -} 60 - 61 -/* This checkbox input should be styled as a switch between ascending and descending states. */ 62 -.search-results-sort #sort-order-input { 63 - /* Hide the default checkbox. We rely on the style of the icon in its label to make it work. */ 64 - appearance: none; 30 +ul.search-results-sort { 31 + color: $theme.textSecondaryColor; 32 + font-size: .9em; 33 + padding: 5px 0 2px 0; 65 65 margin: 0; 66 66 } 67 - 68 -#sort-by-input, .search-results-sort label:has(>#sort-order-input) { 69 - /* We want most of the styles from "form-control", but not the shadow that comes from bootstrap. */ 70 - box-shadow: none; 71 - & :hover,& :focus,& :focus-within { 72 - border-color: var(--input-border-focus); 73 - } 36 +.search-results-sort li { 37 + display: inline; 38 + list-style-type: none; 39 + padding-left: 1.5em; 74 74 } 75 - 76 -/* Flip the second icon so that it's the arrow going up and down. */ 77 -.search-results-sort label #sort-order-input + * + * { 78 - transform: scaleY(-1); 41 +.search-results-sort li:first-of-type { 42 + padding: 0; 79 79 } 80 - 81 -/* When the box is checked, we want to hide the first icon. 82 -When the box is not checked, we want to hide the second icon. */ 83 -.search-results-sort label #sort-order-input:checked + *, 84 -.search-results-sort label #sort-order-input:not(:checked) + * + * { 85 - display: none; 44 +a.sort-item { 45 + color: inherit; 46 + text-decoration: none; 86 86 } 48 +a.sort-item:hover { 49 + color: $theme.linkColor; 50 + text-decoration: underline; 51 +} 52 +a.sort-item.active, a.sort-item.active:hover { 53 + font-weight: bold; 54 + color: $theme.textColor; 55 + text-decoration: none; 56 +} 57 +.sort-item-order { 58 + margin-left: .3em; 59 +} 87 87 88 88 /** 89 89 * Options 90 90 */ 91 91 92 -.search-options ul { 65 +ul.search-options { 66 + color: $theme.textSecondaryColor; 67 + font-size: .9em; 68 + padding: 5px 0 2px 0; 93 93 margin: 0; 70 +} 71 +.search-options li { 72 + display: inline; 73 + list-style-type: none; 74 + padding-left: 1.5em; 75 +} 76 +.search-options li:first-of-type { 94 94 padding: 0; 95 - 96 - & input[type="checkbox"] { 97 - position: unset; 98 - margin: 0; 99 - } 100 - 101 - & label { 102 - margin-right: 1em; 103 - } 104 104 } 79 +a.options-item { 80 + color: inherit; 81 + text-decoration: none; 82 +} 83 +a.options-item:hover { 84 + color: $theme.linkColor; 85 + text-decoration: underline; 86 +} 87 +a.options-item.active, a.options-item.active:hover{ 88 + font-weight: bold; 89 + color: $theme.textColor; 90 + text-decoration: none; 91 +} 105 105 106 106 /** 107 107 * Search Results ... ... @@ -111,6 +111,12 @@ 111 111 margin-top: 1em; 112 112 } 113 113 101 +/* Colibri skin doesn't have the grid system. */ 102 +.skin-colibri .search-results-left { 103 + margin: 0.5em 20em 0.5em 0; 104 + padding: 0.5em 0.5em 0.5em 0; 105 +} 106 + 114 114 .search-results { 115 115 padding: .3em 0 .8em 0; 116 116 } ... ... @@ -174,8 +174,6 @@ 174 174 175 175 dl.search-result-highlights > dt { 176 176 margin-top: .3em; 177 - color: var(--text-muted); 178 - font-weight: var(--font-weight-semibold); 179 179 } 180 180 181 181 blockquote.search-result-highlight { ... ... @@ -196,6 +196,11 @@ 196 196 font-weight: bold; 197 197 } 198 198 190 +dl.search-result-highlights > dt { 191 + color: $theme.textSecondaryColor; 192 + font-weight: normal; 193 +} 194 + 199 199 dl.search-result-highlights.preview dt, 200 200 dl.search-result-highlights.preview dd > * { 201 201 display: none; ... ... @@ -202,10 +202,17 @@ 202 202 } 203 203 204 204 dl.search-result-highlights.preview dt:first-of-type, 205 -dl.search-result-highlights.preview dd:first-of-type blockquote:first-of-type { 201 +dl.search-result-highlights.preview dd:first-of-type blockquote:first-of-type, 202 +/* Workaround for IE8 which doesn't support :first-of-type CSS selector. */ 203 +dl.search-result-highlights.preview dt.first, 204 +dl.search-result-highlights.preview dd.first blockquote.first { 206 206 display: block; 207 207 } 208 208 208 +a.search-result-highlightAll:after { 209 + content: ' \bb'; 210 +} 211 + 209 209 .search-result-debug { 210 210 white-space: pre; 211 211 } ... ... @@ -214,25 +214,40 @@ 214 214 * Facets 215 215 */ 216 216 217 -.search-facets-header{ 218 - border-bottom: 1px solid var(--xwiki-border-color); 220 +.search-facets { 221 + background-color: $theme.backgroundSecondaryColor; 222 + box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); 223 + /* Leave space for the bottom shadow. */ 224 + margin-bottom: 1em; 225 + border-radius: 7px; 219 219 } 227 +/* Colibri skin doesn't have the grid system. */ 228 +.skin-colibri .search-facets { 229 + float: right; 230 + max-width: 19.5em; 231 + width: 19.5em; 232 +} 220 220 221 -.search-facets-header strong { 222 - font-size: 1.25em; 234 +.search-facets-header, 235 +.search-facets-actions, 236 +.search-facet { 237 + border-bottom: 1px solid $theme.borderColor; 238 + border-top: 1px solid $theme.pageContentBackgroundColor; 239 + position: relative; 223 223 } 224 224 225 225 .search-facets-header, 226 226 .search-facets-actions { 227 - padding: .5em 0;244 + padding: 0.5em 1em; 228 228 } 229 - 230 230 .search-facet { 231 - padding: .2em 0; 232 - display: flex; 233 - flex-direction: column; 247 + padding: 0.5em .8em; 234 234 } 235 235 250 +.search-facets-header { 251 + border-top: none; 252 +} 253 + 236 236 .search-facets-header > p, 237 237 .search-facets-actions > p { 238 238 /* The wiki syntax generates paragraphs which have bottom margin. */ ... ... @@ -243,6 +243,16 @@ 243 243 font-size: .8em; 244 244 } 245 245 264 +.search-facets-actions a { 265 + color: $theme.textSecondaryColor; 266 + text-decoration: none; 267 +} 268 + 269 +.search-facets-actions a:hover { 270 + color: $theme.linkColor; 271 + text-decoration: underline; 272 +} 273 + 246 246 .search-facets-action-collapseAll, 247 247 .search-facets-action-expandAll { 248 248 float: right; ... ... @@ -254,28 +254,33 @@ 254 254 margin: 0; 255 255 } 256 256 257 -.search-facet-header, .search-facet-body { 258 - padding-left: .5em; 259 - border: 1px solid var(--xwiki-border-color); 260 - border-radius: var(--border-radius-small); 285 +.search-facet:last-of-type { 286 + border-bottom: none; 261 261 } 262 262 263 263 .search-facet-header { 264 - background-color: var(--xwiki-background-secondary-color); 265 -} 266 - 267 -.search-facet-header label { 268 268 color: $theme.titleColor; 269 269 cursor: pointer; 292 + line-height: 1.4em; 293 + margin: 0 .2em; 270 270 display: flex; 271 271 justify-content: space-between; 272 - align-items:center;296 + position: relative; 273 273 } 274 274 299 +.search-facet:last-of-type .search-facet-header:after { 300 + border: medium none; 301 +} 302 + 303 +.search-facet.expanded:last-of-type .search-facet-header:after { 304 + border-bottom: 1px dotted $theme.pageContentBackgroundColor; 305 + border-top: 1px dotted $theme.borderColor; 306 +} 307 + 275 275 .search-facet-body { 276 - border-top-width:0;277 - border-top-left-radius:0;278 - border-top-right-radius:0;309 + overflow: hidden; /* required for effect */ 310 + display: none; 311 + margin-top: .5em; 279 279 } 280 280 281 281 .search-facet-body ul, ... ... @@ -286,46 +286,37 @@ 286 286 .search-facet-body li { 287 287 display: flex; 288 288 flex-wrap: wrap; 289 - padding: . 3em .5em;322 + padding: .1em .2em; 290 290 } 291 291 292 -.search-facet .search-facet-header .facet-toggle, button.facet-value-toggle {325 +.search-facet .search-facet-header .facet-toggler, button.facet-value-toggler { 293 293 background: transparent; 294 294 transition: background-color .2s ease-in-out; 295 295 } 296 296 297 -.search-facet .search-facet-header .facet-toggle:active, button.facet-value-toggle:active { 330 +.search-facet .search-facet-header .facet-toggler:active, button.facet-value-toggler:active { 298 298 box-shadow: unset; 299 299 } 300 300 301 -.search-facet .search-facet-header .facet-toggle .collapsed> span, button.facet-value-toggle > span,302 -.search-facet .search-facet-header .facet-toggle .collapsed> img, button.facet-value-toggle > img {334 +.search-facet .search-facet-header .facet-toggler > span, button.facet-value-toggler > span, 335 +.search-facet .search-facet-header .facet-toggler > img, button.facet-value-toggler > img { 303 303 transform: rotate(90deg); 304 304 } 305 305 306 -.search-facet .search-facet-header .facet-toggle > span, .expanded > button.facet-value-toggle > span, 307 -.search-facet .search-facet-header .facet-toggle > img, .expanded > button.facet-value-toggle > img { 339 +.search-facet.expanded .search-facet-header .facet-toggler > span, .expanded > button.facet-value-toggler > span, 340 +.search-facet.expanded .search-facet-header .facet-toggler > img, .expanded > button.facet-value-toggler > img { 308 308 transform: rotate(0deg); 309 309 } 310 310 311 -@media (prefers-reduced-motion : no-preference) {312 - .search-facet .search-facet-header .facet-toggle > span, button.facet-value-toggle > span, 313 - .search-facet .search-facet-header .facet-toggle > img, button.facet-value-toggle > img { 344 +@media not (prefers-reduced-motion) { 345 + .search-facet .search-facet-header .facet-toggler > span, button.facet-value-toggler > span, 346 + .search-facet .search-facet-header .facet-toggler > img, button.facet-value-toggler > img { 314 314 transition: transform 0.2s ease; 315 315 } 316 316 } 317 317 318 -.search-facet:has(.search-facet-body.collapse.in), 319 -.search-facet:has(.search-facet-body.collapsing) { 320 - & .search-facet-header { 321 - border-bottom-width: 0; 322 - border-bottom-left-radius: 0; 323 - border-bottom-right-radius: 0; 324 - 325 - & label { 326 - font-weight: var(--font-weight-semibold); 327 - } 328 - } 351 +.search-facet.expanded .search-facet-body { 352 + display: block; 329 329 } 330 330 331 331 .search-facet-body ul, .search-facet-body ul.users { ... ... @@ -336,6 +336,10 @@ 336 336 margin: .5em 0; 337 337 } 338 338 363 +.search-facet-body li:hover { 364 + background-color: $theme.highlightColor; 365 +} 366 + 339 339 .search-facet-body input[type="checkbox"] { 340 340 margin: .2em 0; 341 341 } ... ... @@ -360,8 +360,7 @@ 360 360 } 361 361 362 362 .search-facet-body .itemName, 363 -.search-facet-body .itemNameempty, 364 -.search-facet-body .facet-value-toggle, 391 +.search-facet-body .facet-value-toggler, 365 365 .search-facet-body .more { 366 366 /* Remove link styling */ 367 367 color: $theme.textColor; ... ... @@ -379,11 +379,8 @@ 379 379 } 380 380 381 381 .search-facet-body .itemCount { 382 - padding: .1em .5em;409 + padding: .1em 0; 383 383 margin-left: auto; 384 - background-color: var(--nav-link-hover-bg); 385 - /* We want those item count blocks to be pill shaped. */ 386 - border-radius: 1em / 50%; 387 387 } 388 388 389 389 @media (max-width: 768px) { ... ... @@ -403,6 +403,17 @@ 403 403 } 404 404 405 405 /** 430 + * Fix the breadcrumb in Colibri skin. 431 + */ 432 +.skin-colibri .breadcrumb > li { 433 + display: inline; 434 +} 435 +.skin-colibri .breadcrumb > li + li:before { 436 + color: $theme.textSecondaryColor; 437 + content: ' \00BB '; 438 +} 439 + 440 +/** 406 406 * Miscellaneous 407 407 */ 408 408 ... ... @@ -411,3 +411,13 @@ 411 411 padding-left: 0; 412 412 } 413 413 449 +.paginationFilter .resultsNo, 450 +.paginationFilter .controlPagination, 451 +.paginationFilter .pagination { 452 + line-height: 22px; 453 +} 454 + 455 +.iconRSS { 456 + background: url("$xwiki.getSkinFile('icons/silk/feed.png')") no-repeat scroll 0 0 transparent; 457 + padding-left: 20px; 458 +}