pull/144/head
Henrique Dias 2016-12-30 16:22:26 +00:00
parent 4f063734c4
commit 997f42a531
8 changed files with 260 additions and 81 deletions

View File

@ -768,6 +768,69 @@ header #logout {
color: rgba(255, 255, 255, .5); color: rgba(255, 255, 255, .5);
} }
/* BREADCRUMB */
header>div:last-child>div:first-child>* {
display: inline-block;
vertical-align: middle;
}
header>div:last-child>div:first-child>i {
margin-right: .3em;
}
#breadcrumbs-button {
padding: .4em 0.3em;
border-radius: .1em;
cursor: pointer;
transition: .1s ease all;
}
#breadcrumbs-button.active,
#breadcrumbs-button:hover {
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: #fff;
}
#current-file {
line-height: 2.7em;
}
#breadcrumbs {
transition: .1s ease all;
padding: 0;
margin: 0;
list-style: none;
display: inline-flex;
flex-direction: column;
border-radius: 2px;
border-top-left-radius: 0;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: #fff;
position: absolute;
left: 0;
top: 2.3em;
min-width: 7em;
z-index: 999;
opacity: 0;
visibility: hidden;
color: #656565;
}
#breadcrumbs.active {
opacity: 1;
visibility: visible;
}
#breadcrumbs li {
line-height: 1.5em;
padding: .3em;
}
/* MORE STUFF */
header>div { header>div {
display: flex; display: flex;
width: 100%; width: 100%;
@ -775,7 +838,7 @@ header>div {
} }
header>div:first-child>div:nth-child(1) { header>div:first-child>div:nth-child(1) {
margin-right: 2em; margin-right: 1em;
font-weight: 500; font-weight: 500;
font-size: 1.5em; font-size: 1.5em;
line-height: 2; line-height: 2;
@ -802,10 +865,12 @@ header #file-only {
padding-right: .3em; padding-right: .3em;
margin-right: .3em; margin-right: .3em;
transition: .2s ease all; transition: .2s ease all;
visibility: visible;
} }
#file-only.disabled { #file-only.disabled {
opacity: 0; opacity: 0;
visibility: hidden;
} }
header p { header p {
@ -921,8 +986,8 @@ header .action span {
} }
.floating .action { .floating .action {
background-color: #68EFAD; background-color: #2196f3 !important;
color: #306e50; color: #fff;
box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12); box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12);
} }
@ -954,31 +1019,36 @@ header .action span {
/* LISTING */ /* LISTING */
#listing { #listing {
max-width: calc(100% - 1.2em);
width: 100%;
}
#listing h2 {
margin: 0 0 0 0.5em;
font-size: 1em;
color: rgba(0, 0, 0, 0.2);
font-weight: 500;
}
#listing.list h2 {
display: none;
}
#listing>div {
display: flex; display: flex;
padding: 0; padding: 0;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-start; justify-content: flex-start;
max-width: calc(100% - 2.2em); position: relative;
width: 100%;
} }
#listing.list { #listing.list {
flex-direction: column; flex-direction: column;
margin-top: -1em; margin-top: 2em;
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
} }
#listing.list .item {
width: 100%;
margin: 0;
border: 0;
box-shadow: none;
border-radius: 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
padding: 1em;
}
#listing .item { #listing .item {
margin: .5em; margin: .5em;
padding: 0.5em; padding: 0.5em;
@ -991,15 +1061,7 @@ header .action span {
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
color: #6f6f6f; color: #6f6f6f;
} transition: .1s ease all;
.item:hover {
box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24) !important;
}
.item[aria-selected=true] {
background: #2196f3 !important;
color: #fff !important;
} }
.item div:first-of-type { .item div:first-of-type {
@ -1028,6 +1090,56 @@ header .action span {
vertical-align: bottom; vertical-align: bottom;
} }
#listing .item.header {
display: none !important;
background-color: #ccc;
}
#listing.list .item.header {
display: flex !important;
background: #fafafa;
position: fixed;
width: 100%;
top: 8em;
left: 0;
z-index: 999;
}
#listing.list .item.header>div:first-child {
width: 0;
}
#listing.list .item.header>div:last-child {
/* width: 100%; */
}
#listing.list .item.header>div:last-child *:first-child {
margin-right: 3em;
}
#listing.list .item {
width: 100%;
margin: 0;
border: 0;
box-shadow: none;
border-radius: 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
padding: 1em;
}
#listing .item:hover {
box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24) !important;
}
#listing.list .item:hover {
box-shadow: none !important;
}
#listing .item[aria-selected=true] {
background: #2196f3 !important;
color: #fff !important;
}
#listing.list .item div:first-of-type { #listing.list .item div:first-of-type {
width: 3em; width: 3em;
} }
@ -1038,6 +1150,21 @@ header .action span {
#listing.list .item div:last-of-type { #listing.list .item div:last-of-type {
width: calc(100% - 3em); width: calc(100% - 3em);
display: flex;
align-items: center;
}
#listing .item div:last-of-type * {
text-overflow: ellipsis;
overflow: hidden;
}
#listing.list .item div:last-of-type span {
width: 50%;
}
#listing.list .item div:last-of-type p:first-of-type {
width: 25%;
} }

View File

@ -185,7 +185,7 @@ function resetSearchText() {
let box = document.querySelector('#search > div div'); let box = document.querySelector('#search > div div');
if (user.AllowCommands) { if (user.AllowCommands) {
box.innerHTML = `Search or use one of your supported commands: ${user.Commands.join(", ")} `; box.innerHTML = `Search or use one of your supported commands: ${user.Commands.join(", ")}.`;
} else { } else {
box.innerHTML = "Type and press enter to search."; box.innerHTML = "Type and press enter to search.";
} }
@ -323,6 +323,11 @@ document.addEventListener("DOMContentLoaded", function(event) {
if (user.AllowEdit) { if (user.AllowEdit) {
buttons.delete.addEventListener("click", deleteEvent); buttons.delete.addEventListener("click", deleteEvent);
} }
document.getElementById("breadcrumbs-button").addEventListener("click", event => {
event.currentTarget.classList.toggle("active");
document.getElementById("breadcrumbs").classList.toggle("active");
});
setupSearch(); setupSearch();
return false; return false;

View File

@ -41,13 +41,12 @@ var renameEvent = function(event) {
let keyDownEvent = (event) => { let keyDownEvent = (event) => {
if (event.keyCode == 13) { if (event.keyCode == 13) {
let newName = span.innerHTML, let newName = span.innerHTML,
newLink = removeLastDirectoryPartOf(toWebDavURL(link)) + newName, newLink = removeLastDirectoryPartOf(toWebDavURL(link)) + "/" + newName,
html = document.getElementById('rename').changeToLoading(), html = document.getElementById('rename').changeToLoading(),
request = new XMLHttpRequest(); request = new XMLHttpRequest();
request.open('MOVE', toWebDavURL(link)); request.open('MOVE', toWebDavURL(link));
request.setRequestHeader('Destination', newLink); request.setRequestHeader('Destination', newLink);
request.setRequestHeader('Content-type', 'text/plain; charset=utf-8');
request.send(); request.send();
request.onreadystatechange = function() { request.onreadystatechange = function() {
// TODO: redirect if it's moved to another folder // TODO: redirect if it's moved to another folder

View File

@ -33,7 +33,7 @@
<div> <div>
<div><p>File Manager</p></div> <div><p>File Manager</p></div>
<div id="search"> <div id="search">
<i class="material-icons" title="Storage">storage</i> <i class="material-icons" title="Search">search</i>
<input type="text" placeholder="Search or execute a command..."> <input type="text" placeholder="Search or execute a command...">
<div> <div>
<div>Loading...</div> <div>Loading...</div>
@ -49,20 +49,17 @@
<!-- BOTTOM BAR --> <!-- BOTTOM BAR -->
<div> <div>
<div> <div>
{{ $lnk := .PreviousLink }} {{ if ne .Name "/"}}
<div class="action{{ if eq $lnk ""}} disabled{{ end }}" id="prev"> <p id="breadcrumbs-button">Previous</p>
{{ if ne $lnk ""}}<a href="{{ $lnk }}">{{ end }} <ul id="breadcrumbs">
<i class="material-icons" title="Previous">subdirectory_arrow_left</i> {{ range $item := .BreadcrumbMap }}
{{ if ne $lnk ""}}</a>{{ end }} <a href="{{ $absURL }}{{ $item.URL }}"><li>{{ $item.Name }}</li></a>
{{ end }}
{{ if ne $lnk ""}} </ul><i class="material-icons">keyboard_arrow_right</i>
<ul class="prev-links">
{{ range $link, $name := .BreadcrumbMap }}<a href="{{ $absURL }}{{ $link }}"><li>{{ $name }}</li></a>{{ end }}
</ul>
{{ end }}
</div>
{{ if ne .Name "/"}}<p>{{ .Name }}</p>{{ end }} {{ end }}
<p id="current-file">{{ if ne .Name "/"}}{{ .Name }}{{ else }}Root{{ end }}</p>
</div> </div>
<!-- ACTIONS --> <!-- ACTIONS -->

View File

@ -2,41 +2,76 @@
{{ with .Data }} {{ with .Data }}
<div class="listing"> <div class="listing">
<div class="container" id="listing"> <div class="container" id="listing">
{{- range .Items}} <div>
{{ if .UserAllowed }} <div class="item header">
<div ondragstart="itemDragStart(event)" <div>
{{ if .IsDir}}ondragover="itemDragOver(event)" ondrop="itemDrop(event)"{{ end }}
draggable="true" </div>
class="item" <div>
onclick="selectItemEvent(event)" <span class="name">Name</span>
ondblclick="openItemEvent(event)" <p>Size</p>
data-dir="{{ .IsDir }}" <p>Modified time</p>
data-url="{{ .URL }}" </div>
id="{{ EncodeBase64 .Name }}">
<div>
{{- if .IsDir}}
<i class="material-icons">folder</i>
{{- else}}
<i class="material-icons">insert_drive_file</i>
{{- end}}
</div>
<div>
<span class="name">{{.Name}}</span>
{{- if .IsDir}}
<p data-order="-1">&mdash;</p>
{{- else}}
<p data-order="{{.Size}}">{{.HumanSize}}</p>
{{- end}}
<p>
<time datetime="{{.HumanModTime "2006-01-02T15:04:05Z"}}">{{.HumanModTime "2 Jan 2006 03:04 PM"}}</time>
</p>
</div> </div>
</div> </div>
{{ end }} <h2>Folders</h2>
{{- end}} <div>
{{- range .Items}}
{{ if and (.UserAllowed) (.IsDir) }}
{{ template "item" .}}
{{ end }}
{{- end}}
</div>
<h2>Files</h2>
<div>
{{- range .Items}}
{{ if and (.UserAllowed) (not .IsDir) }}
{{ template "item" .}}
{{ end }}
{{- end}}
</div>
</div> </div>
</div> </div>
<input style="display:none" type="file" id="upload-input" onchange="handleFiles(this.files, '')" value="Upload" multiple> <input style="display:none" type="file" id="upload-input" onchange="handleFiles(this.files, '')" value="Upload" multiple>
{{ end }} {{ end }}
{{ end }} {{ end }}
{{ define "item" }}
<div ondragstart="itemDragStart(event)"
{{ if .IsDir}}ondragover="itemDragOver(event)" ondrop="itemDrop(event)"{{ end }}
draggable="true"
class="item"
onclick="selectItemEvent(event)"
ondblclick="openItemEvent(event)"
data-dir="{{ .IsDir }}"
data-url="{{ .URL }}"
id="{{ EncodeBase64 .Name }}">
<div>
{{- if .IsDir}}
<i class="material-icons">folder</i>
{{- else}}
{{ if eq .Type "image" }}
<i class="material-icons">insert_photo</i>
{{ else if eq .Type "audio" }}
<i class="material-icons">volume_up</i>
{{ else if eq .Type "video" }}
<i class="material-icons">movie</i>
{{ else }}
<i class="material-icons">insert_drive_file</i>
{{ end }}
{{- end}}
</div>
<div>
<span class="name">{{.Name}}</span>
{{- if .IsDir}}
<p data-order="-1">&mdash;</p>
{{- else}}
<p data-order="{{.Size}}">{{.HumanSize}}</p>
{{- end}}
<p>
<time datetime="{{.HumanModTime "2006-01-02T15:04:05Z"}}">{{.HumanModTime "2 Jan 2006 03:04 PM"}}</time>
</p>
</div>
</div>
{{ end }}

View File

@ -67,11 +67,15 @@ func GetListing(u *config.User, filePath string, baseURL string) (*Listing, erro
// Absolute URL // Absolute URL
url := url.URL{Path: baseURL + name} url := url.URL{Path: baseURL + name}
fileinfos = append(fileinfos, Info{
i := Info{
FileInfo: f, FileInfo: f,
URL: url.String(), URL: url.String(),
UserAllowed: u.Allowed(filePath), UserAllowed: u.Allowed("/" + name),
}) }
i.RetrieveFileType()
fileinfos = append(fileinfos, i)
} }
return &Listing{ return &Listing{

View File

@ -31,7 +31,7 @@ func ServeListing(w http.ResponseWriter, r *http.Request, c *config.Config, u *c
// Copy the query values into the Listing struct // Copy the query values into the Listing struct
var limit int var limit int
listing.Sort, listing.Order, limit, err = handleSortOrder(w, r, c.Scope) listing.Sort, listing.Order, limit, err = handleSortOrder(w, r, c.BaseURL)
if err != nil { if err != nil {
return http.StatusBadRequest, err return http.StatusBadRequest, err
} }

View File

@ -32,10 +32,16 @@ type Info struct {
Token string Token string
} }
// BreadcrumbMapItem ...
type BreadcrumbMapItem struct {
Name string
URL string
}
// BreadcrumbMap returns p.Path where every element is a map // BreadcrumbMap returns p.Path where every element is a map
// of URLs and path segment names. // of URLs and path segment names.
func (i Info) BreadcrumbMap() map[string]string { func (i Info) BreadcrumbMap() []BreadcrumbMapItem {
result := map[string]string{} result := []BreadcrumbMapItem{}
if len(i.Path) == 0 { if len(i.Path) == 0 {
return result return result
@ -54,11 +60,17 @@ func (i Info) BreadcrumbMap() map[string]string {
} }
if i == 0 && part == "" { if i == 0 && part == "" {
// Leading slash (root) result = append([]BreadcrumbMapItem{{
result["/"] = "/" Name: "/",
URL: "/",
}}, result...)
continue continue
} }
result[strings.Join(parts[:i+1], "/")] = part
result = append([]BreadcrumbMapItem{{
Name: part,
URL: strings.Join(parts[:i+1], "/"),
}}, result...)
} }
return result return result