diff --git a/public_html/media/css/tag-list.css b/public_html/media/css/tag-list.css
index 0c098614..6c60f95a 100644
--- a/public_html/media/css/tag-list.css
+++ b/public_html/media/css/tag-list.css
@@ -47,3 +47,19 @@ form h1 {
.frequency8 { color: #be4343; }
.frequency9 { color: #b83333; }
.frequency10 { color: #b22222; }
+
+nav.sort-styles ul {
+ list-style-type: none;
+ margin: 0 0 2.5em 0;
+ text-align: center;
+ padding: 0;
+}
+nav.sort-styles li {
+ display: inline-block;
+ font-size: 105%;
+ margin: 0 1em;
+ padding-bottom: 0.2em;
+}
+nav.sort-styles li.active {
+ border-bottom: 3px solid firebrick;
+}
diff --git a/public_html/media/css/user-list.css b/public_html/media/css/user-list.css
index 90ee904f..7680a836 100644
--- a/public_html/media/css/user-list.css
+++ b/public_html/media/css/user-list.css
@@ -24,7 +24,7 @@
nav.sort-styles ul {
list-style-type: none;
- margin: 0 0 1em 0;
+ margin: 0 0 2.5em 0;
text-align: center;
padding: 0;
}
diff --git a/public_html/media/js/core.js b/public_html/media/js/core.js
index 021aee2a..8cf9452f 100644
--- a/public_html/media/js/core.js
+++ b/public_html/media/js/core.js
@@ -178,9 +178,9 @@ $(function()
{
var term = extractLast(request.term);
if (term != '')
- $.get(searchInput.attr('data-autocomplete-url') + '?json', {filter: term}, function(data)
+ $.get(searchInput.attr('data-autocomplete-url') + '?json', {filter: term + ' order:popularity,desc'}, function(data)
{
- response($.map(data.tags, function(tag) { return { label: tag.name, value: tag.name }; }));
+ response($.map(data.tags, function(tag) { return { label: tag.name + ' (' + tag.count + ')', value: tag.name }; }));
});
},
focus: function()
diff --git a/public_html/media/js/post-view.js b/public_html/media/js/post-view.js
index 579508e5..5559ee24 100644
--- a/public_html/media/js/post-view.js
+++ b/public_html/media/js/post-view.js
@@ -10,7 +10,7 @@ function onDomUpdate()
aDom.addClass('inactive');
var tags = [];
- $.getJSON('/tags?json', function(data)
+ $.getJSON('/tags?json', {filter: 'order:popularity,desc'}, function(data)
{
aDom.removeClass('inactive');
var formDom = $('form.edit-post');
diff --git a/public_html/media/js/upload.js b/public_html/media/js/upload.js
index 92176dda..1b521034 100644
--- a/public_html/media/js/upload.js
+++ b/public_html/media/js/upload.js
@@ -11,7 +11,7 @@ $(function()
});
var tags = [];
- $.getJSON('/tags?json', function(data)
+ $.getJSON('/tags?json', {filter: 'order:popularity,desc'}, function(data)
{
tags = data['tags'];
});
diff --git a/src/Controllers/TagController.php b/src/Controllers/TagController.php
index 40290ee7..dd17ca4e 100644
--- a/src/Controllers/TagController.php
+++ b/src/Controllers/TagController.php
@@ -3,8 +3,10 @@ class TagController
{
/**
* @route /tags
+ * @route /tags/{filter}
+ * @validate filter [a-zA-Z\32:,_-]+
*/
- public function listAction()
+ public function listAction($filter = null)
{
$this->context->stylesheets []= 'tag-list.css';
$this->context->stylesheets []= 'tabs.css';
@@ -12,9 +14,10 @@ class TagController
$this->context->viewName = 'tag-list-wrapper';
PrivilegesHelper::confirmWithException(Privilege::ListTags);
- $suppliedFilter = InputHelper::get('filter');
+ $suppliedFilter = $filter ?: InputHelper::get('filter') ?: 'order:alpha,asc';
$tags = Model_Tag::getEntitiesRows($suppliedFilter, null, null);
+ $this->context->filter = $suppliedFilter;
$this->context->transport->tags = $tags;
if ($this->context->json)
@@ -22,20 +25,11 @@ class TagController
$this->context->transport->tags = array_values(array_map(function($tag) {
return ['name' => $tag['name'], 'count' => $tag['post_count']];
}, $this->context->transport->tags));
- usort($this->context->transport->tags, function($a, $b) {
- return $a['count'] > $b['count'] ? -1 : 1;
- });
- }
- else
- {
- uasort($this->context->transport->tags, function($a, $b) {
- return strnatcasecmp($a['name'], $b['name']);
- });
}
}
/**
- * @route /tags/merge
+ * @route /tag/merge
*/
public function mergeAction()
{
@@ -77,7 +71,7 @@ class TagController
}
/**
- * @route /tags/rename
+ * @route /tag/rename
*/
public function renameAction()
{
diff --git a/src/Models/Model_Tag_QueryBuilder.php b/src/Models/Model_Tag_QueryBuilder.php
index 89474792..490496b9 100644
--- a/src/Models/Model_Tag_QueryBuilder.php
+++ b/src/Models/Model_Tag_QueryBuilder.php
@@ -17,21 +17,71 @@ class model_Tag_QueryBuilder implements AbstractQueryBuilder
foreach ($allowedSafety as $s)
$dbQuery->put($s);
+ $orderToken = null;
+
if ($query !== null)
{
- $limitQuery = true;
- if (strlen($query) >= 3)
- $query = '%' . $query;
- $query .= '%';
- $dbQuery
- ->and('LOWER(tag.name)')
- ->like('LOWER(?)')
- ->put($query);
+ $tokens = preg_split('/\s+/', $query);
+ foreach ($tokens as $token)
+ {
+ if (strpos($token, ':') !== false)
+ {
+ list ($key, $value) = explode(':', $token);
+
+ if ($key == 'order')
+ $orderToken = $value;
+ else
+ throw new SimpleException('Unknown key: ' . $key);
+ }
+ else
+ {
+ $limitQuery = true;
+ if (strlen($token) >= 3)
+ $token = '%' . $token;
+ $token .= '%';
+ $dbQuery
+ ->and('LOWER(tag.name)')
+ ->like('LOWER(?)')
+ ->put($token);
+ }
+ }
}
$dbQuery->groupBy('tag.id');
+ if ($orderToken)
+ self::order($dbQuery,$orderToken);
+
if ($limitQuery)
$dbQuery->limit(15);
}
+
+ private static function order($dbQuery, $value)
+ {
+ if (strpos($value, ',') !== false)
+ {
+ list ($orderColumn, $orderDir) = explode(',', $value);
+ }
+ else
+ {
+ $orderColumn = $value;
+ $orderDir = 'asc';
+ }
+
+ switch ($orderColumn)
+ {
+ case 'popularity':
+ $dbQuery->orderBy('post_count');
+ break;
+
+ case 'alpha':
+ $dbQuery->orderBy('name');
+ break;
+ }
+
+ if ($orderDir == 'asc')
+ $dbQuery->asc();
+ else
+ $dbQuery->desc();
+ }
}
diff --git a/src/Views/tag-list.phtml b/src/Views/tag-list.phtml
index ba130621..3e0d479f 100644
--- a/src/Views/tag-list.phtml
+++ b/src/Views/tag-list.phtml
@@ -1,3 +1,30 @@
+
+
context->transport->tags)); ?>