diff --git a/_embed/public/css/styles.css b/_embed/public/css/styles.css index 6b9b4927..0fa6c0cc 100644 --- a/_embed/public/css/styles.css +++ b/_embed/public/css/styles.css @@ -558,7 +558,17 @@ header p i { top: 100%; } -#search div { +#search ul { + padding: 0; + margin: 0; + list-style: none; +} + +#search li { + margin-bottom: .5em; +} + +#search>div { position: absolute; top: 0; width: 100%; @@ -577,6 +587,9 @@ header p i { overflow-x: hidden; overflow-y: auto; max-height: 50vh; +} + +#search>div div { white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; @@ -584,6 +597,18 @@ header p i { word-wrap: break-word; } +#search>div p { + width: 100%; + text-align: center; + display: none; + margin: 0; + max-width: none; +} + +#search.ongoing p { + display: block; +} + #search.active div i, #sidebar #search.active div i { color: #ccc; diff --git a/_embed/public/js/application.js b/_embed/public/js/application.js index 4878ae1f..a3583d00 100644 --- a/_embed/public/js/application.js +++ b/_embed/public/js/application.js @@ -466,10 +466,12 @@ var redefineDownloadURLs = function() { var searchEvent = function(event) { let value = this.value; - let box = document.querySelector('#search div'); + let search = document.getElementById('search'); + let scrollable = document.querySelector('#search > div'); + let box = document.querySelector('#search > div div'); if (value.length == 0) { - box.innerHTML = "Write one of your supported commands: " + user.Commands.join(", ") + "."; + box.innerHTML = "Search or use one of your supported commands: " + user.Commands.join(", ") + "."; return; } @@ -483,27 +485,47 @@ var searchEvent = function(event) { }); if (!supported) { - box.innerHTML = "Command not supported." - return; + box.innerHTML = "Press enter to search." + } else { + box.innerHTML = "Press enter to execute." } - box.innerHTML = "Press enter to continue." - if (event.keyCode == 13) { - box.innerHTML = 'autorenew'; + box.innerHTML = ''; + search.classList.add('ongoing'); - var conn = new WebSocket('ws://' + window.location.host + window.location.pathname + '?command=true'); - conn.onopen = function() { - conn.send(value); - }; + if (supported) { + var conn = new WebSocket('ws://' + window.location.host + window.location.pathname + '?command=true'); + conn.onopen = function() { + conn.send(value); + }; - conn.onmessage = function(event) { - box.innerHTML = event.data - box.scrollTop = box.scrollHeight; - } + conn.onmessage = function(event) { + box.innerHTML = event.data; + scrollable.scrollTop = scrollable.scrollHeight; + } - conn.onclose = function(event) { - reloadListing(); + conn.onclose = function(event) { + search.classList.remove('ongoing'); + reloadListing(); + } + } else { + box.innerHTML = ''; + let ul = box.querySelector('ul'); + + var conn = new WebSocket('ws://' + window.location.host + window.location.pathname + '?search=true'); + conn.onopen = function() { + conn.send(value); + }; + + conn.onmessage = function(event) { + ul.innerHTML += '
  • ' + event.data + '
  • '; + scrollable.scrollTop = scrollable.scrollHeight; + } + + conn.onclose = function(event) { + search.classList.remove('ongoing'); + } } } } @@ -557,7 +579,7 @@ document.addEventListener('listing', event => { document.getElementById('search').classList.remove('active'); }); - document.querySelector('#search div').innerHTML = "Write one of yours suported commands: " + user.Commands.join(", ") + "."; + document.querySelector('#search > div div').innerHTML = "Search or use one of yours suported commands: " + user.Commands.join(", ") + "."; document.querySelector('#search input').addEventListener('keyup', searchEvent); } @@ -900,4 +922,4 @@ document.addEventListener("DOMContentLoaded", function(event) { } return false; -}); +}); \ No newline at end of file diff --git a/_embed/templates/base.tmpl b/_embed/templates/base.tmpl index 88a4568f..78c9aa10 100644 --- a/_embed/templates/base.tmpl +++ b/_embed/templates/base.tmpl @@ -52,7 +52,10 @@ {{ end }} diff --git a/filemanager.go b/filemanager.go index b2da027f..9a64c276 100644 --- a/filemanager.go +++ b/filemanager.go @@ -67,10 +67,6 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err user = c.User } - if r.URL.Query().Get("command") != "" { - return handlers.Command(w, r, c, user) - } - // Checks if the request URL is for the WebDav server if strings.HasPrefix(r.URL.Path, c.WebDavURL) { // Checks for user permissions relatively to this PATH @@ -112,6 +108,14 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err return http.StatusForbidden, nil } + if r.URL.Query().Get("search") != "" { + return handlers.Search(w, r, c, user) + } + + if r.URL.Query().Get("command") != "" { + return handlers.Command(w, r, c, user) + } + if r.Method == http.MethodGet { // Gets the information of the directory/file fi, code, err = file.GetInfo(r.URL, c, user) diff --git a/handlers/search.go b/handlers/search.go new file mode 100644 index 00000000..13fde593 --- /dev/null +++ b/handlers/search.go @@ -0,0 +1,65 @@ +package handlers + +import ( + "net/http" + "os" + "path/filepath" + "strings" + + "github.com/gorilla/websocket" + "github.com/hacdias/caddy-filemanager/config" +) + +func Search(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { + // Upgrades the connection to a websocket and checks for errors. + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + return 0, err + } + defer conn.Close() + + var search string + + // Starts an infinite loop until a valid command is captured. + for { + _, message, err := conn.ReadMessage() + if err != nil { + return http.StatusInternalServerError, err + } + + if len(message) != 0 { + search = string(message) + break + } + } + + scope := strings.Replace(r.URL.Path, c.BaseURL, "", 1) + scope = strings.TrimPrefix(scope, "/") + scope = "/" + scope + scope = u.Scope + scope + scope = strings.Replace(scope, "\\", "/", -1) + scope = filepath.Clean(scope) + + err = filepath.Walk(scope, func(path string, f os.FileInfo, err error) error { + // TODO: check user permissions? + + if strings.Contains(path, search) { + path = strings.TrimPrefix(path, scope) + path = strings.Replace(path, "\\", "/", -1) + path = strings.TrimPrefix(path, "/") + + err = conn.WriteMessage(websocket.TextMessage, []byte(path)) + if err != nil { + return err + } + } + + return nil + }) + + if err != nil { + return http.StatusInternalServerError, err + } + + return http.StatusOK, nil +} diff --git a/page/page.go b/page/page.go index 9d30d851..3cc08fd5 100644 --- a/page/page.go +++ b/page/page.go @@ -139,7 +139,7 @@ func (p Page) PrintAsHTML(w http.ResponseWriter, templates ...string) (int, erro // PrintAsJSON prints the current Page infromation in JSON func (p Page) PrintAsJSON(w http.ResponseWriter) (int, error) { - marsh, err := json.Marshal(p.Info.Data) + marsh, err := json.MarshalIndent(p.Info.Data, "", " ") if err != nil { return http.StatusInternalServerError, err }