diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..4f90f6f --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,18 @@ +body { + font-family: monospace; +} + +#dropZone { + background-color: rgba(0, 0, 0.2, 0.75); + color: white; + font-size: 60px; + font-weight: bold; + height: 100%; + left: 0; + padding: 1em; + position: fixed; + top: 0; + transition: visibility 175ms, opacity 175ms; + width: 100%; + z-index: 999; +} \ No newline at end of file diff --git a/assets/js/dragdrop.js b/assets/js/dragdrop.js new file mode 100644 index 0000000..5b6165b --- /dev/null +++ b/assets/js/dragdrop.js @@ -0,0 +1,48 @@ +"use strict"; + +window.addEventListener('DOMContentLoaded', (event) => { + // The implementation of this drag-drop logic is largely based on the + // answer described in . + // + // The gist is this: every time the drag enters a new DOM object, it will + // fire a new 'dragenter' event on that element. That is a pain, because + // we do not know which element will be the last to receive a dragleave + // event, in case the user aborts the process. + // + // Therefore, we use an Ugly Hackā„¢. There will be an element with id + // 'dropZone', which blocks the complete page. When a 'dragenter' event + // is received on any DOM element, we will unhide this modal page-blocker. + // This will guarantee us that the next 'enter' event will be received on + // this page-block element. This event we shall ignore. + // + // Then, whenever the user stop their drag action, we will receive the + // 'dragleave' on the '#dropZone' element. Now we know when exactly + // a drag action is cancelled (and we will hide the modal element + // accordingly). + + let dropZone = document.getElementById("dropZone"); + window.addEventListener("dragenter", (event) => { + // User starts a drag action + dropZone.style.visibility = ""; + dropZone.style.opacity = 1; + }); + + dropZone.addEventListener("drop", (event) => { + // User drops a file + event.preventDefault(); + document.getElementById("fileUploadField").files = event.dataTransfer.files; + document.getElementById("fileUploadForm").submit(); + }); + + dropZone.addEventListener("dragleave", (event) => { + // User cancels drag action + dropZone.style.visibility = "hidden"; + dropZone.style.opacity = 0; + }); + + window.addEventListener("dragover", (event) => { + // Prevent the browser from opening the file, because of a drop event + // on the window. () + event.preventDefault(); + }); +}); \ No newline at end of file diff --git a/assets/templates/html/base.html.tmpl b/assets/templates/html/base.html.tmpl index 0911945..a1ee2e8 100644 --- a/assets/templates/html/base.html.tmpl +++ b/assets/templates/html/base.html.tmpl @@ -2,7 +2,9 @@ - {{block "title" .}}rushlink{{end}}{{block "head-append" .}}{{end}} + {{block "title" .}}rushlink{{end}} + + {{block "head-append" .}}{{end -}} {{block "body" .}} diff --git a/assets/templates/html/index.html.tmpl b/assets/templates/html/index.html.tmpl index 5a5d321..367a347 100644 --- a/assets/templates/html/index.html.tmpl +++ b/assets/templates/html/index.html.tmpl @@ -1,4 +1,9 @@ +{{define "head-append"}} + +{{end}} + {{define "body"}} +

#RU paste-dump

Based on https://0x0.st/, this site allows you to easily upload files and shorten URLs using @@ -6,17 +11,17 @@ the command line.

Web-API

-
+ - - + +
-
+ - - + +
diff --git a/handlers.go b/handlers.go index 5d9da67..c491f34 100644 --- a/handlers.go +++ b/handlers.go @@ -28,6 +28,10 @@ const ( const cookieDeleteToken = "owner_token" +func (rl *rushlink) staticGetHandler(w http.ResponseWriter, r *http.Request) { + rl.renderStatic(w, r, mux.Vars(r)["path"]) +} + func (rl *rushlink) indexGetHandler(w http.ResponseWriter, r *http.Request) { rl.render(w, r, "index", map[string]interface{}{}) } diff --git a/router.go b/router.go index 4330f5a..0ca2743 100644 --- a/router.go +++ b/router.go @@ -14,6 +14,7 @@ import ( "github.com/pkg/errors" ) +const staticFilenameExpr = "[A-Za-z0-9-_.]+" const urlKeyExpr = "{key:[A-Za-z0-9-_]{4,}}" const urlKeyWithExtExpr = urlKeyExpr + "{ext:\\.[A-Za-z0-9-_]+}" @@ -101,6 +102,9 @@ func StartMainServer(addr string, db *db.Database, fs *db.FileStore, rawhost *st router.Use(rl.recoveryMiddleware) router.Use(rl.metricsMiddleware) router.HandleFunc("/uploads/{id:[A-Za-z0-9-_]+}/{filename:.+}", rl.uploadFileGetHandler).Methods("GET", "HEAD") + router.HandleFunc("/{path:img/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD") + router.HandleFunc("/{path:css/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD") + router.HandleFunc("/{path:js/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD") router.HandleFunc("/", rl.indexGetHandler).Methods("GET", "HEAD") router.HandleFunc("/", rl.newPasteHandler).Methods("POST") router.HandleFunc("/"+urlKeyExpr, rl.viewPasteHandler).Methods("GET", "HEAD") diff --git a/views.go b/views.go index 5a0c135..10d5f6a 100644 --- a/views.go +++ b/views.go @@ -17,6 +17,7 @@ import ( "strconv" "strings" text "text/template" + "time" "gitea.hashru.nl/dsprenkels/rushlink/internal/db" @@ -88,6 +89,19 @@ func mapExtend(m map[string]interface{}, key string, value interface{}) { m[key] = value } +func (rl *rushlink) renderStatic(w http.ResponseWriter, r *http.Request, path string) { + var modTime time.Time + if info, err := AssetInfo(path); err != nil { + modTime = info.ModTime() + } + contents, err := Asset(path) + if err != nil { + rl.renderError(w, r, http.StatusNotFound, err.Error()) + return + } + http.ServeContent(w, r, path, modTime, bytes.NewReader(contents)) +} + func (rl *rushlink) render(w http.ResponseWriter, r *http.Request, tmplName string, data map[string]interface{}) { contentType, err := resolveResponseContentType(r, []string{"text/plain", "text/html"}) if err != nil {