Skip to content

Commit 2b35f84

Browse files
committed
Add Any and No value filter
1 parent f79cec7 commit 2b35f84

6 files changed

Lines changed: 81 additions & 11 deletions

File tree

i18n/en.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,8 @@
3434
"wikibase-faceted-search-facet-show-less": "Show less",
3535

3636
"wikibase-faceted-search-facet-range-min": "Minimum",
37-
"wikibase-faceted-search-facet-range-max": "Maximum"
37+
"wikibase-faceted-search-facet-range-max": "Maximum",
38+
39+
"wikibase-faceted-search-facet-any-value": "Any value",
40+
"wikibase-faceted-search-facet-no-value": "No value"
3841
}

i18n/qqq.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,7 @@
2626
"wikibase-faceted-search-facet-show-more": "Label used for the Show more button in the facet",
2727
"wikibase-faceted-search-facet-show-less": "Label used for the Show less button in the facet",
2828
"wikibase-faceted-search-facet-range-min": "Minimum data value label displayed on range facet",
29-
"wikibase-faceted-search-facet-range-max": "Maximum data value label displayed on range facet"
29+
"wikibase-faceted-search-facet-range-max": "Maximum data value label displayed on range facet",
30+
"wikibase-faceted-search-facet-any-value": "Label used for the any value checkbox in the facet",
31+
"wikibase-faceted-search-facet-no-value": "Label used for the no value checkbox in the facet"
3032
}

resources/ext.wikibase.facetedsearch.js

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
const HAS_ANY_VALUE = '__anyvalue__';
2+
const HAS_NO_VALUE = '__novalue__';
3+
14
let specialSearchInput;
25

36
/**
@@ -52,9 +55,9 @@ function onFacetsInput( event ) {
5255

5356
// TODO: Clean up the facet type detection logic after MVP or when we have more facet types
5457
if ( target.classList.contains( 'wikibase-faceted-search__facet-item-checkbox' ) ) {
55-
onListFacetInput( facet, propertyId );
56-
} else if ( target.classList.contains( 'wikibase-faceted-search__facet-toggle-button' ) ) {
5758
onListFacetInput( facet, propertyId, target.value );
59+
} else if ( target.classList.contains( 'wikibase-faceted-search__facet-toggle-button' ) ) {
60+
onToggleInput( facet, propertyId, target.value );
5861
} else if ( target.classList.contains( 'wikibase-faceted-search__facet-item-input' ) ) {
5962
onRangeFacetInput( facet, propertyId );
6063
}
@@ -81,9 +84,28 @@ function onInstancesClick( event, instanceId ) {
8184
*
8285
* @param {HTMLDivElement} facet
8386
* @param {string} propertyId
84-
* @param {?string} mode
87+
* @param {string} value
8588
*/
86-
function onListFacetInput( facet, propertyId, mode ) {
89+
function onListFacetInput( facet, propertyId, value ) {
90+
let selectedValues = getListFacetSelectedValues( facet );
91+
if ( value === HAS_ANY_VALUE || value === HAS_NO_VALUE ) {
92+
selectedValues = selectedValues.indexOf( value ) !== -1 ? [ value ] : [];
93+
} else {
94+
selectedValues = selectedValues.filter( ( v ) => v !== HAS_ANY_VALUE && v !== HAS_NO_VALUE );
95+
}
96+
97+
const newQueries = getListFacetQuerySegments( selectedValues, propertyId, getListFacetQueryMode( facet ) );
98+
submitSearchForm( buildQueryString( specialSearchInput.value, newQueries, propertyId ) );
99+
}
100+
101+
/**
102+
* Handles the input event for the toggle button.
103+
*
104+
* @param {HTMLDivElement} facet
105+
* @param {string} propertyId
106+
* @param {string} mode
107+
*/
108+
function onToggleInput( facet, propertyId, mode ) {
87109
const selectedValues = getListFacetSelectedValues( facet );
88110
mode = mode || getListFacetQueryMode( facet );
89111
const newQueries = getListFacetQuerySegments( selectedValues, propertyId, mode );
@@ -192,6 +214,15 @@ function getListFacetSelectedValues( facet ) {
192214
* @return {string[]}
193215
*/
194216
function getListFacetQuerySegments( selectedValues, propertyId, mode ) {
217+
if ( selectedValues.length === 1 ) {
218+
if ( selectedValues[ 0 ] === HAS_ANY_VALUE ) {
219+
return [ `haswbfacet:${ propertyId }` ];
220+
}
221+
if ( selectedValues[ 0 ] === HAS_NO_VALUE ) {
222+
return [ `-haswbfacet:${ propertyId }` ];
223+
}
224+
}
225+
195226
const segments = [];
196227
if ( mode === 'AND' ) {
197228
if ( selectedValues.length === 0 ) {
@@ -255,7 +286,7 @@ function buildQueryString( oldQuery, newQueries, propertyId ) {
255286
function getFilteredQueries( query, propertyId ) {
256287
const propertyIdPattern = propertyId || 'P\\d+';
257288
return query.split( /\s+/ ).filter(
258-
( item ) => !( new RegExp( `^(haswbfacet|\\-haswbfacet):${ propertyIdPattern }(=|>=|<=)` ) ).test( item )
289+
( item ) => !( new RegExp( `^(haswbfacet|\\-haswbfacet):${ propertyIdPattern }(=|>=|<=)?\\b` ) ).test( item )
259290
);
260291
}
261292

src/Persistence/ElasticValueCounter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function countValues( PropertyConstraints $constraints ): ValueCounts {
5959
}
6060

6161
private function getFilteredQuery( PropertyConstraints $constraints ): AbstractQuery {
62-
if ( $constraints->getOrSelectedValues() !== [] ) {
62+
if ( $constraints->hasNoValue() || $constraints->getOrSelectedValues() !== [] ) {
6363
return $this->queryFilter->removeFacet( $this->currentQuery, $constraints->propertyId );
6464
}
6565
return $this->currentQuery;

src/Presentation/ListFacetHtmlBuilder.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class ListFacetHtmlBuilder implements FacetHtmlBuilder {
2020
private const CONFIG_KEY_DEFAULT_COMBINE_WITH = 'defaultCombineWith';
2121
private const CONFIG_VALUE_COMBINE_WITH_AND = 'AND';
2222
private const CONFIG_VALUE_COMBINE_WITH_OR = 'OR';
23+
private const CONFIG_KEY_SHOW_ANY_FILTER = 'showAnyFilter';
24+
private const CONFIG_KEY_SHOW_NONE_FILTER = 'showNoneFilter';
2325

2426
private const COMBINE_WITH_AND_BY_DEFAULT = true; // Maybe this gets turned into (constructor-injected) config
2527

@@ -32,7 +34,7 @@ public function __construct(
3234

3335
public function buildHtml( FacetConfig $config, PropertyConstraints $state ): string {
3436
$valueCounts = $this->getValuesAndCounts( $state );
35-
if ( count( $valueCounts ) === 0 ) {
37+
if ( count( $valueCounts ) === 0 && !$state->hasAnyValue() && !$state->hasNoValue() ) {
3638
return '';
3739
}
3840

@@ -50,6 +52,8 @@ public function buildViewModel( FacetConfig $config, PropertyConstraints $state,
5052

5153
return [
5254
'toggle' => $this->buildToggleViewModel( $combineWithAnd, $this->hasCombineWithChoice( $config ) ),
55+
'any-value-checkbox' => $this->buildAnyValueCheckboxViewModel( $config, $state->hasAnyValue() ),
56+
'no-value-checkbox' => $this->buildNoValueCheckboxViewModel( $config, $state->hasNoValue() ),
5357
'checkboxes' => $this->buildCheckboxesViewModel( $config, $state, $valueCounts ),
5458
'msg-show-more' => wfMessage( 'wikibase-faceted-search-facet-show-more' )->text(),
5559
'msg-show-less' => wfMessage( 'wikibase-faceted-search-facet-show-less' )->text()
@@ -146,6 +150,34 @@ private function buildCheckboxViewModel( FacetConfig $config, ValueCount $valueC
146150
];
147151
}
148152

153+
private function buildAnyValueCheckboxViewModel( FacetConfig $config, bool $isSelected ): array {
154+
if ( ( $config->typeSpecificConfig[self::CONFIG_KEY_SHOW_ANY_FILTER] ?? false ) !== true ) {
155+
return [];
156+
}
157+
158+
return [
159+
'formattedValue' => wfMessage( 'wikibase-faceted-search-facet-any-value' )->text(),
160+
'count' => '',
161+
'checked' => $isSelected,
162+
'value' => '__anyvalue__',
163+
'id' => $config->propertyId->getSerialization() . "-any-value",
164+
];
165+
}
166+
167+
private function buildNoValueCheckboxViewModel( FacetConfig $config, bool $isSelected ): array {
168+
if ( ( $config->typeSpecificConfig[self::CONFIG_KEY_SHOW_NONE_FILTER] ?? false ) !== true ) {
169+
return [];
170+
}
171+
172+
return [
173+
'formattedValue' => wfMessage( 'wikibase-faceted-search-facet-no-value' )->text(),
174+
'count' => '',
175+
'checked' => $isSelected,
176+
'value' => '__novalue__',
177+
'id' => $config->propertyId->getSerialization() . "-no-value",
178+
];
179+
}
180+
149181
/**
150182
* @return ValueCount[]
151183
*/

templates/ListFacet.mustache

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{{#toggle}}
22
<div class="wikibase-faceted-search__facet-toggle">
33
{{#and}}
4-
<button
4+
<button
55
class="wikibase-faceted-search__facet-toggle-button cdx-button {{#selected}}cdx-button--action-progressive cdx-button--weight-primary{{/selected}}"
66
value="{{value}}"
77
{{#disabled}}disabled{{/disabled}}
@@ -22,6 +22,8 @@
2222
{{/toggle}}
2323
{{#checkboxes}}
2424
<div class="wikibase-faceted-search__facet-items">
25+
{{#any-value-checkbox}}{{>FacetItemCheckbox}}{{/any-value-checkbox}}
26+
{{#no-value-checkbox}}{{>FacetItemCheckbox}}{{/no-value-checkbox}}
2527
{{#visible}}{{>FacetItemCheckbox}}{{/visible}}
2628
</div>
2729
{{#showMore}}
@@ -35,4 +37,4 @@
3537
</div>
3638
</details>
3739
{{/showMore}}
38-
{{/checkboxes}}
40+
{{/checkboxes}}

0 commit comments

Comments
 (0)