@@ -659,20 +659,29 @@ function extractNormalizedFacetValues(results, attribute) {
659
659
}
660
660
661
661
/**
662
- * Sort nodes of a hierarchical facet results
662
+ * Sort nodes of a hierarchical or disjunctive facet results
663
663
* @private
664
- * @param {HierarchicalFacet } node node to upon which we want to apply the sort
664
+ * @param {function } sortFn
665
+ * @param {HierarchicalFacet|Array } node node upon which we want to apply the sort
666
+ * @param {string[] } names attribute names
667
+ * @param {number } [level=0] current index in the names array
665
668
*/
666
- function recSort ( sortFn , node ) {
669
+ function recSort ( sortFn , node , names , level ) {
670
+ level = level || 0 ;
671
+
672
+ if ( Array . isArray ( node ) ) {
673
+ return sortFn ( node , names [ level ] ) ;
674
+ }
675
+
667
676
if ( ! node . data || node . data . length === 0 ) {
668
677
return node ;
669
678
}
670
679
671
680
var children = node . data . map ( function ( childNode ) {
672
- return recSort ( sortFn , childNode ) ;
681
+ return recSort ( sortFn , childNode , names , level + 1 ) ;
673
682
} ) ;
674
- var sortedChildren = sortFn ( children ) ;
675
- var newNode = merge ( { } , node , { data : sortedChildren } ) ;
683
+ var sortedChildren = sortFn ( children , names [ level ] ) ;
684
+ var newNode = defaultsPure ( { data : sortedChildren } , node ) ;
676
685
return newNode ;
677
686
}
678
687
@@ -682,6 +691,70 @@ function vanillaSortFn(order, data) {
682
691
return data . sort ( order ) ;
683
692
}
684
693
694
+ /**
695
+ * @typedef FacetOrdering
696
+ * @type {Object }
697
+ * @property {string[] } [order]
698
+ * @property {'count' | 'alpha' | 'hidden' } [sortRemainingBy]
699
+ */
700
+
701
+ /**
702
+ * Sorts facet arrays via their facet ordering
703
+ * @param {Array } facetValues the values
704
+ * @param {FacetOrdering } facetOrdering the ordering
705
+ * @returns {Array }
706
+ */
707
+ function sortViaFacetOrdering ( facetValues , facetOrdering ) {
708
+ var orderedFacets = [ ] ;
709
+ var remainingFacets = [ ] ;
710
+
711
+ var order = facetOrdering . order || [ ] ;
712
+ /**
713
+ * an object with the keys being the values in order, the values their index:
714
+ * ['one', 'two'] -> { one: 0, two: 1 }
715
+ */
716
+ var reverseOrder = order . reduce ( function ( acc , name , i ) {
717
+ acc [ name ] = i ;
718
+ return acc ;
719
+ } , { } ) ;
720
+
721
+ facetValues . forEach ( function ( item ) {
722
+ if ( reverseOrder [ item . name ] !== undefined ) {
723
+ orderedFacets [ reverseOrder [ item . name ] ] = item ;
724
+ } else {
725
+ remainingFacets . push ( item ) ;
726
+ }
727
+ } ) ;
728
+
729
+ var sortRemainingBy = facetOrdering . sortRemainingBy ;
730
+ var ordering ;
731
+ if ( sortRemainingBy === 'hidden' ) {
732
+ return orderedFacets ;
733
+ } else if ( sortRemainingBy === 'alpha' ) {
734
+ ordering = [ [ 'name' ] , [ 'asc' ] ] ;
735
+ } else {
736
+ ordering = [ [ 'count' ] , [ 'desc' ] ] ;
737
+ }
738
+
739
+ return orderedFacets . concat (
740
+ orderBy ( remainingFacets , ordering [ 0 ] , ordering [ 1 ] )
741
+ ) ;
742
+ }
743
+
744
+ /**
745
+ * @param {SearchResults } results the search results class
746
+ * @param {string } attribute the attribute to retrieve ordering of
747
+ * @returns {FacetOrdering= }
748
+ */
749
+ function getFacetOrdering ( results , attribute ) {
750
+ return (
751
+ results . renderingContent &&
752
+ results . renderingContent . facetOrdering &&
753
+ results . renderingContent . facetOrdering . values &&
754
+ results . renderingContent . facetOrdering . values [ attribute ]
755
+ ) ;
756
+ }
757
+
685
758
/**
686
759
* Get a the list of values for a given facet attribute. Those values are sorted
687
760
* refinement first, descending count (bigger value on top), and name ascending
@@ -694,6 +767,9 @@ function vanillaSortFn(order, data) {
694
767
* might not be respected if you have facet values that are already refined.
695
768
* @param {string } attribute attribute name
696
769
* @param {object } opts configuration options.
770
+ * @param {boolean } [opts.facetOrdering]
771
+ * Force the use of facetOrdering from the result if a sortBy is present. If
772
+ * sortBy isn't present, facetOrdering will be used automatically.
697
773
* @param {Array.<string> | function } opts.sortBy
698
774
* When using strings, it consists of
699
775
* the name of the [FacetValue](#SearchResults.FacetValue) or the
@@ -733,30 +809,41 @@ SearchResults.prototype.getFacetValues = function(attribute, opts) {
733
809
return undefined ;
734
810
}
735
811
736
- var options = defaultsPure ( { } , opts , { sortBy : SearchResults . DEFAULT_SORT } ) ;
812
+ var options = defaultsPure ( { } , opts , {
813
+ sortBy : SearchResults . DEFAULT_SORT ,
814
+ // if no sortBy is given, attempt to sort based on facetOrdering
815
+ // if it is given, we still allow to sort via facet ordering first
816
+ facetOrdering : ! ( opts && opts . sortBy )
817
+ } ) ;
737
818
738
- if ( Array . isArray ( options . sortBy ) ) {
739
- var order = formatSort ( options . sortBy , SearchResults . DEFAULT_SORT ) ;
740
- if ( Array . isArray ( facetValues ) ) {
741
- return orderBy ( facetValues , order [ 0 ] , order [ 1 ] ) ;
742
- }
743
- // If facetValues is not an array, it's an object thus a hierarchical facet object
744
- return recSort ( function ( hierarchicalFacetValues ) {
745
- return orderBy ( hierarchicalFacetValues , order [ 0 ] , order [ 1 ] ) ;
746
- } , facetValues ) ;
747
- } else if ( typeof options . sortBy === 'function' ) {
748
- if ( Array . isArray ( facetValues ) ) {
749
- return facetValues . sort ( options . sortBy ) ;
819
+ var results = this ;
820
+ var attributes ;
821
+ if ( Array . isArray ( facetValues ) ) {
822
+ attributes = [ attribute ] ;
823
+ } else {
824
+ var config = results . _state . getHierarchicalFacetByName ( facetValues . name ) ;
825
+ attributes = config . attributes ;
826
+ }
827
+
828
+ return recSort ( function ( data , facetName ) {
829
+ if ( options . facetOrdering ) {
830
+ var facetOrdering = getFacetOrdering ( results , facetName ) ;
831
+ if ( Boolean ( facetOrdering ) ) {
832
+ return sortViaFacetOrdering ( data , facetOrdering ) ;
833
+ }
750
834
}
751
- // If facetValues is not an array, it's an object thus a hierarchical facet object
752
- return recSort ( function ( data ) {
835
+
836
+ if ( Array . isArray ( options . sortBy ) ) {
837
+ var order = formatSort ( options . sortBy , SearchResults . DEFAULT_SORT ) ;
838
+ return orderBy ( data , order [ 0 ] , order [ 1 ] ) ;
839
+ } else if ( typeof options . sortBy === 'function' ) {
753
840
return vanillaSortFn ( options . sortBy , data ) ;
754
- } , facetValues ) ;
755
- }
756
- throw new Error (
757
- 'options.sortBy is optional but if defined it must be ' +
758
- 'either an array of string (predicates) or a sorting function'
759
- ) ;
841
+ }
842
+ throw new Error (
843
+ 'options.sortBy is optional but if defined it must be ' +
844
+ 'either an array of string (predicates) or a sorting function'
845
+ ) ;
846
+ } , facetValues , attributes ) ;
760
847
} ;
761
848
762
849
/**
0 commit comments