Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "lexical" and "natural" sort strategies for notation codes #1205

Merged
merged 8 commits into from
Sep 16, 2021
2 changes: 1 addition & 1 deletion model/Concept.php
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ public function getProperties()
if ($superprop) {
$superprop = EasyRdf\RdfNamespace::shorten($superprop) ? EasyRdf\RdfNamespace::shorten($superprop) : $superprop;
}
$sort_by_notation = $this->vocab->getConfig()->sortByNotation();
$sort_by_notation = $this->vocab->getConfig()->getSortByNotation();
$propobj = new ConceptProperty($prop, $proplabel, $prophelp, $superprop, $sort_by_notation);

if ($propobj->getLabel() !== null) {
Expand Down
8 changes: 6 additions & 2 deletions model/ConceptProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,12 @@ private function sortValues()
return -1;
}
else {
// assume that notations are unique
return strnatcasecmp($anot, $bnot);
// assume that notations are unique, choose strategy
if ($this->sort_by_notation == "decimal") {
return strcoll($anot, $bnot);
} else { // natural
return strnatcasecmp($anot, $bnot);
}
}
});
}
Expand Down
7 changes: 1 addition & 6 deletions model/ConceptPropertyValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,7 @@ public function __construct($model, $vocab, $resource, $prop, $clang = '')

public function __toString()
{
$label = is_string($this->getLabel()) ? $this->getLabel() : $this->getLabel()->getValue();
if ($this->vocab->getConfig()->sortByNotation()) {
$label = ltrim($this->getNotation() . ' ') . $label;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the notation here doesn't seem to have any effect on the sort order so I just removed it.

}

return $label;
return is_string($this->getLabel()) ? $this->getLabel() : $this->getLabel()->getValue();
}

public function getLang()
Expand Down
17 changes: 13 additions & 4 deletions model/VocabularyConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,21 @@ public function getTitle($lang = null)
}

/**
* Returns a boolean value set in the config.ttl config.
* @return boolean
* Returns the sorting strategy for notation codes set in the config.ttl
* config: either "decimal" (default), "natural", or null if
* sorting by notations is disabled.
* @return string|bool
*/
public function sortByNotation()
public function getSortByNotation(): ?string
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed the method for better consistency with other getters, and redefined its return value.

{
return $this->getBoolean('skosmos:sortByNotation');
$value = $this->getLiteral('skosmos:sortByNotation');
if ($value == "decimal" || $value == "natural") {
return $value;
}
// not a special value - interpret as boolean instead
$bvalue = $this->getBoolean('skosmos:sortByNotation');
// default sorting strategy is "decimal"
return $bvalue ? "decimal" : null;
}

/**
Expand Down
16 changes: 10 additions & 6 deletions resource/js/hierarchy.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,17 +508,21 @@ function getTreeConfiguration() {
var bNode = this.get_node(b);

// sort on notation if requested, and notations exist
if (window.showNotation) {
if (window.sortByNotation) {
var aNotation = aNode.original.notation;
var bNotation = bNode.original.notation;

if (aNotation) {
if (bNotation) {
if (aNotation < bNotation) {
return -1;
}
else if (aNotation > bNotation) {
return 1;
if (window.sortByNotation == "decimal") {
if (aNotation < bNotation) {
return -1;
}
else if (aNotation > bNotation) {
return 1;
}
} else { // natural
return naturalCompare(aNotation, bNotation);
}
}
else return -1;
Expand Down
11 changes: 9 additions & 2 deletions resource/js/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,14 @@ function countAndSetOffset() {
}
}

// return -1 if the value is negative, 1 otherwise
// used to coerce sort values so they are compatible with the jsTree sort plugin
function negVsPos(val) {
return (val < 0) ? -1 : 1;
}

// Natural sort from: http://stackoverflow.com/a/15479354/3894569
// adapted to return only -1 or 1 using negVsPos function above
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the documentation of the jsTree sort plugin, it expects that the return value of the sort function is either -1 or 1 (anything other than -1 will be interpreted as 1, AFAICT). To make sure that the return values meet those expectations, I added a coercing function.

function naturalCompare(a, b) {
var ax = [], bx = [];

Expand All @@ -337,10 +344,10 @@ function naturalCompare(a, b) {
var an = ax.shift();
var bn = bx.shift();
var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1], lang);
if(nn) return nn;
if(nn) return negVsPos(nn);
}

return ax.length - bx.length;
return negVsPos(ax.length - bx.length);
}

function makeCallbacks(data, pageType) {
Expand Down
35 changes: 33 additions & 2 deletions tests/VocabularyConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -318,12 +318,43 @@ public function testShowChangeListDefaultValue() {
}

/**
* @covers VocabularyConfig::sortByNotation
* @covers VocabularyConfig::getSortByNotation
* @covers VocabularyConfig::getLiteral
* @covers VocabularyConfig::getBoolean
*/
public function testShowSortByNotationDefaultValue() {
$vocab = $this->model->getVocabulary('test');
$this->assertEquals(false, $vocab->getConfig()->sortByNotation());
$this->assertNull($vocab->getConfig()->getSortByNotation());
}

/**
* @covers VocabularyConfig::getSortByNotation
* @covers VocabularyConfig::getLiteral
* @covers VocabularyConfig::getBoolean
*/
public function testShowSortByNotationTrueIsDecimal() {
$vocab = $this->model->getVocabulary('test-notation-sort');
$this->assertEquals("decimal", $vocab->getConfig()->getSortByNotation());
}

/**
* @covers VocabularyConfig::getSortByNotation
* @covers VocabularyConfig::getLiteral
* @covers VocabularyConfig::getBoolean
*/
public function testShowSortByNotationDecimal() {
$vocab = $this->model->getVocabulary('test-qualified-notation');
$this->assertEquals("decimal", $vocab->getConfig()->getSortByNotation());
}

/**
* @covers VocabularyConfig::getSortByNotation
* @covers VocabularyConfig::getLiteral
* @covers VocabularyConfig::getBoolean
*/
public function testShowSortByNotationNatural() {
$vocab = $this->model->getVocabulary('testNotation');
$this->assertEquals("natural", $vocab->getConfig()->getSortByNotation());
}

/**
Expand Down
3 changes: 2 additions & 1 deletion tests/testconfig.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
void:uriSpace "http://www.skosmos.skos/test-qualified-notation/" ;
skosmos:defaultLanguage "en" ;
skosmos:groupClass skos:Collection ;
skosmos:sortByNotation "decimal" ;
skosmos:language "en" ;
skosmos:alphabeticalListQualifier skos:notation ;
skosmos:sparqlGraph <http://www.skosmos.skos/test-qualified-notation/> .
Expand Down Expand Up @@ -337,7 +338,7 @@
dc:subject :cat_general ;
void:uriSpace "http://www.skosmos.skos/notationFeatures/";
skosmos:language "fi";
skosmos:sortByNotation true ;
skosmos:sortByNotation "natural" ;
skosmos:searchByNotation true ;
skosmos:showNotation true ;
skosmos:useModifiedDate "true";
Expand Down
3 changes: 2 additions & 1 deletion view/scripts.twig
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ var prefLabels = [{"lang": "{{ search_results|first.label.lang }}","label": "{{
{% if request.vocab and request.vocab.uriSpace %}
var uriSpace = "{{ request.vocab.uriSpace }}";
{% endif %}
var showNotation = {% if request.vocab and request.vocab.config.showNotation == false %}false{% else %}true{% endif %};
{% if request.vocab %}
var showNotation = {% if request.vocab.config.showNotation %}true{% else %}false{% endif %};
var sortByNotation = {% if request.vocab.config.sortByNotation %}"{{ request.vocab.config.sortByNotation }}"{% else %}null{% endif %};
var languageOrder = [{% for lang in request.vocab.config.languageOrder(request.contentLang) %}"{{ lang }}"{% if not loop.last %},{% endif %}{% endfor %}];
var vocShortName = "{{ request.vocab.config.shortname }}";
{% endif %}
Expand Down