mirror of
https://github.com/caddyserver/caddy.git
synced 2025-02-24 00:38:53 +01:00
Add new browse sort - namedirfirst (#1551)
* Revert "browse: sort listing by dir first (#1527)"
commit 4e1229e7c9
.
* Add new browse sort order namedirfirst. Make namedirfirst default sort
This commit is contained in:
parent
ce47cf51be
commit
464ade1da7
4 changed files with 66 additions and 27 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -16,6 +16,4 @@ Caddyfile
|
||||||
|
|
||||||
og_static/
|
og_static/
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
caddyhttp/browse/temp*
|
|
|
@ -21,9 +21,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sortByName = "name"
|
sortByName = "name"
|
||||||
sortBySize = "size"
|
sortByNameDirFirst = "namedirfirst"
|
||||||
sortByTime = "time"
|
sortBySize = "size"
|
||||||
|
sortByTime = "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Browse is an http.Handler that can show a file listing when
|
// Browse is an http.Handler that can show a file listing when
|
||||||
|
@ -128,6 +129,7 @@ func (fi FileInfo) HumanModTime(format string) string {
|
||||||
|
|
||||||
// Implement sorting for Listing
|
// Implement sorting for Listing
|
||||||
type byName Listing
|
type byName Listing
|
||||||
|
type byNameDirFirst Listing
|
||||||
type bySize Listing
|
type bySize Listing
|
||||||
type byTime Listing
|
type byTime Listing
|
||||||
|
|
||||||
|
@ -137,6 +139,15 @@ func (l byName) Swap(i, j int) { l.Items[i], l.Items[j] = l.Items[j], l.Items[i]
|
||||||
|
|
||||||
// Treat upper and lower case equally
|
// Treat upper and lower case equally
|
||||||
func (l byName) Less(i, j int) bool {
|
func (l byName) Less(i, j int) bool {
|
||||||
|
return strings.ToLower(l.Items[i].Name) < strings.ToLower(l.Items[j].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// By Name Dir First
|
||||||
|
func (l byNameDirFirst) Len() int { return len(l.Items) }
|
||||||
|
func (l byNameDirFirst) Swap(i, j int) { l.Items[i], l.Items[j] = l.Items[j], l.Items[i] }
|
||||||
|
|
||||||
|
// Treat upper and lower case equally
|
||||||
|
func (l byNameDirFirst) Less(i, j int) bool {
|
||||||
|
|
||||||
// if both are dir or file sort normally
|
// if both are dir or file sort normally
|
||||||
if l.Items[i].IsDir == l.Items[j].IsDir {
|
if l.Items[i].IsDir == l.Items[j].IsDir {
|
||||||
|
@ -176,6 +187,8 @@ func (l Listing) applySort() {
|
||||||
switch l.Sort {
|
switch l.Sort {
|
||||||
case sortByName:
|
case sortByName:
|
||||||
sort.Sort(sort.Reverse(byName(l)))
|
sort.Sort(sort.Reverse(byName(l)))
|
||||||
|
case sortByNameDirFirst:
|
||||||
|
sort.Sort(sort.Reverse(byNameDirFirst(l)))
|
||||||
case sortBySize:
|
case sortBySize:
|
||||||
sort.Sort(sort.Reverse(bySize(l)))
|
sort.Sort(sort.Reverse(bySize(l)))
|
||||||
case sortByTime:
|
case sortByTime:
|
||||||
|
@ -188,6 +201,8 @@ func (l Listing) applySort() {
|
||||||
switch l.Sort {
|
switch l.Sort {
|
||||||
case sortByName:
|
case sortByName:
|
||||||
sort.Sort(byName(l))
|
sort.Sort(byName(l))
|
||||||
|
case sortByNameDirFirst:
|
||||||
|
sort.Sort(byNameDirFirst(l))
|
||||||
case sortBySize:
|
case sortBySize:
|
||||||
sort.Sort(bySize(l))
|
sort.Sort(bySize(l))
|
||||||
case sortByTime:
|
case sortByTime:
|
||||||
|
@ -345,11 +360,11 @@ func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope st
|
||||||
// If the query 'sort' or 'order' is empty, use defaults or any values previously saved in Cookies
|
// If the query 'sort' or 'order' is empty, use defaults or any values previously saved in Cookies
|
||||||
switch sort {
|
switch sort {
|
||||||
case "":
|
case "":
|
||||||
sort = sortByName
|
sort = sortByNameDirFirst
|
||||||
if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil {
|
if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil {
|
||||||
sort = sortCookie.Value
|
sort = sortCookie.Value
|
||||||
}
|
}
|
||||||
case sortByName, sortBySize, sortByTime:
|
case sortByName, sortByNameDirFirst, sortBySize, sortByTime:
|
||||||
http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil})
|
http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,13 @@ func TestSort(t *testing.T) {
|
||||||
t.Errorf("The listing isn't time sorted: %v", listing.Items)
|
t.Errorf("The listing isn't time sorted: %v", listing.Items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sort by name dir first
|
||||||
|
listing.Sort = "namedirfirst"
|
||||||
|
listing.applySort()
|
||||||
|
if !sort.IsSorted(byNameDirFirst(listing)) {
|
||||||
|
t.Errorf("The listing isn't namedirfirst sorted: %v", listing.Items)
|
||||||
|
}
|
||||||
|
|
||||||
// reverse by name
|
// reverse by name
|
||||||
listing.Sort = "name"
|
listing.Sort = "name"
|
||||||
listing.Order = "desc"
|
listing.Order = "desc"
|
||||||
|
@ -93,6 +100,14 @@ func TestSort(t *testing.T) {
|
||||||
if !isReversed(byTime(listing)) {
|
if !isReversed(byTime(listing)) {
|
||||||
t.Errorf("The listing isn't reversed by time: %v", listing.Items)
|
t.Errorf("The listing isn't reversed by time: %v", listing.Items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reverse by name dir first
|
||||||
|
listing.Sort = "namedirfirst"
|
||||||
|
listing.Order = "desc"
|
||||||
|
listing.applySort()
|
||||||
|
if !isReversed(byNameDirFirst(listing)) {
|
||||||
|
t.Errorf("The listing isn't reversed by namedirfirst: %v", listing.Items)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBrowseHTTPMethods(t *testing.T) {
|
func TestBrowseHTTPMethods(t *testing.T) {
|
||||||
|
@ -257,6 +272,9 @@ func TestBrowseJson(t *testing.T) {
|
||||||
Mode: f.Mode(),
|
Mode: f.Mode(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that sort=name returns correct listing.
|
||||||
|
|
||||||
listing := Listing{Items: fileinfos} // this listing will be used for validation inside the tests
|
listing := Listing{Items: fileinfos} // this listing will be used for validation inside the tests
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -269,33 +287,33 @@ func TestBrowseJson(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
//test case 1: testing for default sort and order and without the limit parameter, default sort is by name and the default order is ascending
|
//test case 1: testing for default sort and order and without the limit parameter, default sort is by name and the default order is ascending
|
||||||
//without the limit query entire listing will be produced
|
//without the limit query entire listing will be produced
|
||||||
{"/", "", "", -1, false, listing.Items},
|
{"/?sort=name", "", "", -1, false, listing.Items},
|
||||||
//test case 2: limit is set to 1, orderBy and sortBy is default
|
//test case 2: limit is set to 1, orderBy and sortBy is default
|
||||||
{"/?limit=1", "", "", 1, false, listing.Items[:1]},
|
{"/?limit=1&sort=name", "", "", 1, false, listing.Items[:1]},
|
||||||
//test case 3 : if the listing request is bigger than total size of listing then it should return everything
|
//test case 3 : if the listing request is bigger than total size of listing then it should return everything
|
||||||
{"/?limit=100000000", "", "", 100000000, false, listing.Items},
|
{"/?limit=100000000&sort=name", "", "", 100000000, false, listing.Items},
|
||||||
//test case 4 : testing for negative limit
|
//test case 4 : testing for negative limit
|
||||||
{"/?limit=-1", "", "", -1, false, listing.Items},
|
{"/?limit=-1&sort=name", "", "", -1, false, listing.Items},
|
||||||
//test case 5 : testing with limit set to -1 and order set to descending
|
//test case 5 : testing with limit set to -1 and order set to descending
|
||||||
{"/?limit=-1&order=desc", "", "desc", -1, false, listing.Items},
|
{"/?limit=-1&order=desc&sort=name", "", "desc", -1, false, listing.Items},
|
||||||
//test case 6 : testing with limit set to 2 and order set to descending
|
//test case 6 : testing with limit set to 2 and order set to descending
|
||||||
{"/?limit=2&order=desc", "", "desc", 2, false, listing.Items},
|
{"/?limit=2&order=desc&sort=name", "", "desc", 2, false, listing.Items},
|
||||||
//test case 7 : testing with limit set to 3 and order set to descending
|
//test case 7 : testing with limit set to 3 and order set to descending
|
||||||
{"/?limit=3&order=desc", "", "desc", 3, false, listing.Items},
|
{"/?limit=3&order=desc&sort=name", "", "desc", 3, false, listing.Items},
|
||||||
//test case 8 : testing with limit set to 3 and order set to ascending
|
//test case 8 : testing with limit set to 3 and order set to ascending
|
||||||
{"/?limit=3&order=asc", "", "asc", 3, false, listing.Items},
|
{"/?limit=3&order=asc&sort=name", "", "asc", 3, false, listing.Items},
|
||||||
//test case 9 : testing with limit set to 1111111 and order set to ascending
|
//test case 9 : testing with limit set to 1111111 and order set to ascending
|
||||||
{"/?limit=1111111&order=asc", "", "asc", 1111111, false, listing.Items},
|
{"/?limit=1111111&order=asc&sort=name", "", "asc", 1111111, false, listing.Items},
|
||||||
//test case 10 : testing with limit set to default and order set to ascending and sorting by size
|
//test case 10 : testing with limit set to default and order set to ascending and sorting by size
|
||||||
{"/?order=asc&sort=size", "size", "asc", -1, false, listing.Items},
|
{"/?order=asc&sort=size&sort=name", "size", "asc", -1, false, listing.Items},
|
||||||
//test case 11 : testing with limit set to default and order set to ascending and sorting by last modified
|
//test case 11 : testing with limit set to default and order set to ascending and sorting by last modified
|
||||||
{"/?order=asc&sort=time", "time", "asc", -1, false, listing.Items},
|
{"/?order=asc&sort=time&sort=name", "time", "asc", -1, false, listing.Items},
|
||||||
//test case 12 : testing with limit set to 1 and order set to ascending and sorting by last modified
|
//test case 12 : testing with limit set to 1 and order set to ascending and sorting by last modified
|
||||||
{"/?order=asc&sort=time&limit=1", "time", "asc", 1, false, listing.Items},
|
{"/?order=asc&sort=time&limit=1&sort=name", "time", "asc", 1, false, listing.Items},
|
||||||
//test case 13 : testing with limit set to -100 and order set to ascending and sorting by last modified
|
//test case 13 : testing with limit set to -100 and order set to ascending and sorting by last modified
|
||||||
{"/?order=asc&sort=time&limit=-100", "time", "asc", -100, false, listing.Items},
|
{"/?order=asc&sort=time&limit=-100&sort=name", "time", "asc", -100, false, listing.Items},
|
||||||
//test case 14 : testing with limit set to -100 and order set to ascending and sorting by size
|
//test case 14 : testing with limit set to -100 and order set to ascending and sorting by size
|
||||||
{"/?order=asc&sort=size&limit=-100", "size", "asc", -100, false, listing.Items},
|
{"/?order=asc&sort=size&limit=-100&sort=name", "size", "asc", -100, false, listing.Items},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
|
|
|
@ -342,12 +342,20 @@ footer {
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
{{- if and (eq .Sort "name") (ne .Order "desc")}}
|
{{- if and (eq .Sort "namedirfirst") (ne .Order "desc")}}
|
||||||
<a href="?sort=name&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a>
|
<a href="?sort=namedirfirst&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a>
|
||||||
{{- else if and (eq .Sort "name") (ne .Order "asc")}}
|
{{- else if and (eq .Sort "namedirfirst") (ne .Order "asc")}}
|
||||||
<a href="?sort=name&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a>
|
<a href="?sort=namedirfirst&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a>
|
||||||
{{- else}}
|
{{- else}}
|
||||||
<a href="?sort=name&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name</a>
|
<a href="?sort=namedirfirst&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name</a>
|
||||||
|
{{- end}}
|
||||||
|
|
|
||||||
|
{{- if and (eq .Sort "name") (ne .Order "desc")}}
|
||||||
|
<a href="?sort=name&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">(a-z) <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a>
|
||||||
|
{{- else if and (eq .Sort "name") (ne .Order "asc")}}
|
||||||
|
<a href="?sort=name&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">(a-z) <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a>
|
||||||
|
{{- else}}
|
||||||
|
<a href="?sort=name&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">(a-z)</a>
|
||||||
{{- end}}
|
{{- end}}
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
|
|
Loading…
Reference in a new issue