1 Commits

3 changed files with 42 additions and 6 deletions

View File

@@ -112,9 +112,16 @@ class OrganonSortHelper extends Base
} }
/** /**
* Number-aware title sort (strnatcasecmp, so "Task 2" precedes "Task 10"), then write positions. * Title sort, then write positions. Mirrors the native reorder scope (all tasks in the
* Mirrors the native reorder scope (all tasks in the column+swimlane, no status filter). Core's * column+swimlane, no status filter). Core's TaskReorderModel::reorderTasks is protected, so the
* TaskReorderModel::reorderTasks is protected, so the 3-line position write is replicated here. * 3-line position write is replicated here.
*
* Each title is reduced to a comparison slug -- lowercased, accent-stripped, spaces -> dashes --
* then compared with strnatcasecmp. The dash is deliberate: strnatcasecmp SKIPS whitespace, so a
* plain space would make "Luiz Eduardo" sort after "Luiza..." (it would compare "LuizEduardo" vs
* "Luiza..."); a dash is not whitespace, so the separator is honoured, while strnatcasecmp still
* groups digit runs ("Task 2" < "Task 10"). The result is case-insensitive, accent-insensitive,
* whitespace-correct and number-aware.
*/ */
private function reorderByTitle($project_id, $swimlane_id, $column_id, $direction) private function reorderByTitle($project_id, $swimlane_id, $column_id, $direction)
{ {
@@ -125,8 +132,13 @@ class OrganonSortHelper extends Base
->eq('column_id', $column_id) ->eq('column_id', $column_id)
->findAll(); ->findAll();
foreach ($rows as &$row) {
$row['sortkey'] = str_replace(' ', '-', $this->stripAccents(mb_strtolower((string) $row['title'], 'UTF-8')));
}
unset($row);
usort($rows, function ($a, $b) use ($direction) { usort($rows, function ($a, $b) use ($direction) {
$cmp = strnatcasecmp((string) $a['title'], (string) $b['title']); $cmp = strnatcasecmp($a['sortkey'], $b['sortkey']);
return $direction === 'desc' ? -$cmp : $cmp; return $direction === 'desc' ? -$cmp : $cmp;
}); });
@@ -137,4 +149,28 @@ class OrganonSortHelper extends Base
$position++; $position++;
} }
} }
/**
* Flatten a string for sorting: strip accents to their base letter so accented names sort by that
* base (Avila near A, not after Z). Uses ext-intl Normalizer when available (deterministic and
* locale-independent), falling back to iconv //TRANSLIT (locale-dependent), then the raw string
* (still sorts, just accent-naive). Case is already lowered by the caller.
*
* @param string $s
* @return string
*/
private function stripAccents($s)
{
if (class_exists('Normalizer')) {
$decomposed = \Normalizer::normalize($s, \Normalizer::FORM_D);
if ($decomposed !== false) {
return preg_replace('/\p{Mn}/u', '', $decomposed);
}
}
$translit = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s);
return $translit !== false ? $translit : $s;
}
} }

View File

@@ -162,7 +162,7 @@ class Plugin extends Base
public function getPluginVersion() public function getPluginVersion()
{ {
return '1.9.0'; return '1.9.1';
} }
public function getPluginHomepage() public function getPluginHomepage()

View File

@@ -1 +1 @@
OrganonTweaks v1.9.0 OrganonTweaks v1.9.1