From 027f5cce42b39c3fa0b7dc9766c5bc8aaa9a3cf6 Mon Sep 17 00:00:00 2001 From: Atrox Date: Wed, 15 Jun 2016 17:42:57 +0200 Subject: [PATCH] Add ability to short urls for uploaded content (#85) Add ability to short urls for uploaded content --- .travis.yml | 1 + README.md | 1 + display.go | 16 +- meta.go | 4 + server.go | 9 + shorturl.go | 89 +++++ static/css/hint.css | 450 ++++++++++++++++++++-- static/js/clipboard.js | 740 ++++++++++++++++++++++++++++++++++++ static/js/shorturl.js | 39 ++ templates/base.html | 1 + templates/display/base.html | 17 +- templates/paste.html | 4 - 12 files changed, 1317 insertions(+), 54 deletions(-) create mode 100644 shorturl.go create mode 100644 static/js/clipboard.js create mode 100644 static/js/shorturl.js diff --git a/.travis.yml b/.travis.yml index b82869c..eaf499f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: go go: - 1.5 + - 1.6 before_script: - go vet ./... diff --git a/README.md b/README.md index c3dc252..af844e3 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ allowhotlink = true - ```-xframeoptions "..." ``` -- X-Frame-Options header (default is "SAMEORIGIN") - ```-remoteuploads``` -- (optionally) enable remote uploads (/upload?url=https://...) - ```-nologs``` -- (optionally) disable request logs in stdout +- ```-googleapikey``` -- (optionally) API Key for Google's URL Shortener. ([How to create one](https://developers.google.com/url-shortener/v1/getting_started#APIKey)) #### SSL with built-in server - ```-certfile path/to/your.crt``` -- Path to the ssl certificate (required if you want to use the https server) diff --git a/display.go b/display.go index 4d3896b..f26b665 100644 --- a/display.go +++ b/display.go @@ -113,13 +113,15 @@ func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) { } err = renderTemplate(tpl, pongo2.Context{ - "mime": metadata.Mimetype, - "filename": fileName, - "size": sizeHuman, - "expiry": expiryHuman, - "extra": extra, - "lines": lines, - "files": metadata.ArchiveFiles, + "mime": metadata.Mimetype, + "filename": fileName, + "size": sizeHuman, + "expiry": expiryHuman, + "extra": extra, + "lines": lines, + "files": metadata.ArchiveFiles, + "shorturlEnabled": Config.googleShorterAPIKey != "", + "shorturl": metadata.ShortURL, }, r, w) if err != nil { diff --git a/meta.go b/meta.go index 7487176..df2e0b5 100644 --- a/meta.go +++ b/meta.go @@ -26,6 +26,7 @@ type MetadataJSON struct { Size int64 `json:"size"` Expiry int64 `json:"expiry"` ArchiveFiles []string `json:"archive_files,omitempty"` + ShortURL string `json:"short_url"` } type Metadata struct { @@ -35,6 +36,7 @@ type Metadata struct { Size int64 Expiry time.Time ArchiveFiles []string + ShortURL string } var NotFoundErr = errors.New("File not found.") @@ -146,6 +148,7 @@ func metadataWrite(filename string, metadata *Metadata) error { mjson.Sha256sum = metadata.Sha256sum mjson.Expiry = metadata.Expiry.Unix() mjson.Size = metadata.Size + mjson.ShortURL = metadata.ShortURL byt, err := json.Marshal(mjson) if err != nil { @@ -188,6 +191,7 @@ func metadataRead(filename string) (metadata Metadata, err error) { metadata.Sha256sum = mjson.Sha256sum metadata.Expiry = time.Unix(mjson.Expiry, 0) metadata.Size = mjson.Size + metadata.ShortURL = mjson.ShortURL return } diff --git a/server.go b/server.go index d43f941..3ff5c7f 100644 --- a/server.go +++ b/server.go @@ -55,6 +55,7 @@ var Config struct { authFile string remoteAuthFile string addHeaders headerList + googleShorterAPIKey string } var Templates = make(map[string]*pongo2.Template) @@ -145,6 +146,7 @@ func setup() *web.Mux { selifRe := regexp.MustCompile("^" + Config.sitePath + `selif/(?P[a-z0-9-\.]+)$`) selifIndexRe := regexp.MustCompile("^" + Config.sitePath + `selif/$`) torrentRe := regexp.MustCompile("^" + Config.sitePath + `(?P[a-z0-9-\.]+)/torrent$`) + shortRe := regexp.MustCompile("^" + Config.sitePath + `(?P[a-z0-9-\.]+)/short$`) if Config.authFile == "" { mux.Get(Config.sitePath, indexHandler) @@ -182,6 +184,11 @@ func setup() *web.Mux { mux.Get(selifRe, fileServeHandler) mux.Get(selifIndexRe, unauthorizedHandler) mux.Get(torrentRe, fileTorrentHandler) + + if Config.googleShorterAPIKey != "" { + mux.Get(shortRe, shortURLHandler) + } + mux.NotFound(notFoundHandler) return mux @@ -228,6 +235,8 @@ func main() { "value of X-Frame-Options header") flag.Var(&Config.addHeaders, "addheader", "Add an arbitrary header to the response. This option can be used multiple times.") + flag.StringVar(&Config.googleShorterAPIKey, "googleapikey", "", + "API Key for Google's URL Shortener.") iniflags.Parse() diff --git a/shorturl.go b/shorturl.go new file mode 100644 index 0000000..afdaf00 --- /dev/null +++ b/shorturl.go @@ -0,0 +1,89 @@ +package main + +import ( + "bytes" + "encoding/json" + "errors" + "net/http" + + "github.com/zenazn/goji/web" +) + +type shortenerRequest struct { + LongURL string `json:"longUrl"` +} + +type shortenerResponse struct { + Kind string `json:"kind"` + ID string `json:"id"` + LongURL string `json:"longUrl"` + Error struct { + Code int `json:"code"` + Message string `json:"message"` + } `json:"error"` +} + +func shortURLHandler(c web.C, w http.ResponseWriter, r *http.Request) { + fileName := c.URLParams["name"] + + err := checkFile(fileName) + if err == NotFoundErr { + notFoundHandler(c, w, r) + return + } + + metadata, err := metadataRead(fileName) + if err != nil { + oopsHandler(c, w, r, RespJSON, "Corrupt metadata.") + return + } + + if metadata.ShortURL == "" { + url, err := shortenURL(getSiteURL(r) + fileName) + if err != nil { + oopsHandler(c, w, r, RespJSON, err.Error()) + return + } + + metadata.ShortURL = url + + err = metadataWrite(fileName, &metadata) + if err != nil { + oopsHandler(c, w, r, RespJSON, "Corrupt metadata.") + return + } + } + + js, _ := json.Marshal(map[string]string{ + "shortUrl": metadata.ShortURL, + }) + w.Write(js) + return +} + +func shortenURL(url string) (string, error) { + apiURL := "https://www.googleapis.com/urlshortener/v1/url?key=" + Config.googleShorterAPIKey + jsonStr, _ := json.Marshal(shortenerRequest{LongURL: url}) + + req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonStr)) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + shortenerResponse := new(shortenerResponse) + err = json.NewDecoder(resp.Body).Decode(shortenerResponse) + if err != nil { + return "", err + } + + if shortenerResponse.Error.Message != "" { + return "", errors.New(shortenerResponse.Error.Message) + } + + return shortenerResponse.ID, nil +} diff --git a/static/css/hint.css b/static/css/hint.css index 9165763..fd889cc 100644 --- a/static/css/hint.css +++ b/static/css/hint.css @@ -1,9 +1,8 @@ -/*! Hint.css - v1.3.1 - 2013-11-23 +/*! Hint.css - v2.3.1 - 2016-06-05 * http://kushagragour.in/lab/hint/ -* Copyright (c) 2013 Kushagra Gour; Licensed MIT */ +* Copyright (c) 2016 Kushagra Gour; Licensed */ -/*-------------------------------------*\ - HINT.css - A CSS tooltip library +/*-------------------------------------* HINT.css - A CSS tooltip library \*-------------------------------------*/ /** * HINT.css is a tooltip library made in pure CSS. @@ -21,20 +20,20 @@ * Each tooltip is made of 2 parts: * 1) body (:after) * 2) arrow (:before) - * + * * Classes added: * 1) hint */ -.hint, [data-hint] { +[class*="hint--"] { position: relative; display: inline-block; /** - * tooltip arrow - */ + * tooltip arrow + */ /** - * tooltip body - */ } - .hint:before, .hint:after, [data-hint]:before, [data-hint]:after { + * tooltip body + */ } + [class*="hint--"]:before, [class*="hint--"]:after { position: absolute; -webkit-transform: translate3d(0, 0, 0); -moz-transform: translate3d(0, 0, 0); @@ -45,26 +44,40 @@ pointer-events: none; -webkit-transition: 0.3s ease; -moz-transition: 0.3s ease; - transition: 0.3s ease; } - .hint:hover:before, .hint:hover:after, .hint:focus:before, .hint:focus:after, [data-hint]:hover:before, [data-hint]:hover:after, [data-hint]:focus:before, [data-hint]:focus:after { + transition: 0.3s ease; + -webkit-transition-delay: 0ms; + -moz-transition-delay: 0ms; + transition-delay: 0ms; } + [class*="hint--"]:hover:before, [class*="hint--"]:hover:after { visibility: visible; opacity: 1; } - .hint:before, [data-hint]:before { + [class*="hint--"]:hover:before, [class*="hint--"]:hover:after { + -webkit-transition-delay: 100ms; + -moz-transition-delay: 100ms; + transition-delay: 100ms; } + [class*="hint--"]:before { content: ''; position: absolute; background: transparent; border: 6px solid transparent; z-index: 1000001; } - .hint:after, [data-hint]:after { - content: attr(data-hint); - background: #556A7F; + [class*="hint--"]:after { + background: #383838; color: white; - text-shadow: 0 -1px 0px black; padding: 8px 10px; font-size: 12px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 12px; - white-space: nowrap; - box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.3); } + white-space: nowrap; } + [class*="hint--"][aria-label]:after { + content: attr(aria-label); } + [class*="hint--"][data-hint]:after { + content: attr(data-hint); } + +[aria-label='']:before, [aria-label='']:after, +[data-hint='']:before, +[data-hint='']:after { + display: none !important; } /** * source: hint-position.scss @@ -80,60 +93,106 @@ /** * set default color for tooltip arrows */ +.hint--top-left:before { + border-top-color: #383838; } + +.hint--top-right:before { + border-top-color: #383838; } + .hint--top:before { - border-top-color: #556A7F; } + border-top-color: #383838; } + +.hint--bottom-left:before { + border-bottom-color: #383838; } + +.hint--bottom-right:before { + border-bottom-color: #383838; } .hint--bottom:before { - border-bottom-color: #556A7F; } + border-bottom-color: #383838; } .hint--left:before { - border-left-color: #556A7F; } + border-left-color: #383838; } .hint--right:before { - border-right-color: #556A7F; } + border-right-color: #383838; } /** * top tooltip */ .hint--top:before { - margin-bottom: -12px; } -.hint--top:after { - margin-left: -18px; } + margin-bottom: -11px; } + .hint--top:before, .hint--top:after { bottom: 100%; left: 50%; } -.hint--top:hover:after, .hint--top:hover:before, .hint--top:focus:after, .hint--top:focus:before { + +.hint--top:before { + left: calc(50% - 6px); } + +.hint--top:after { + -webkit-transform: translateX(-50%); + -moz-transform: translateX(-50%); + transform: translateX(-50%); } + +.hint--top:hover:before { -webkit-transform: translateY(-8px); -moz-transform: translateY(-8px); transform: translateY(-8px); } +.hint--top:hover:after { + -webkit-transform: translateX(-50%) translateY(-8px); + -moz-transform: translateX(-50%) translateY(-8px); + transform: translateX(-50%) translateY(-8px); } + /** * bottom tooltip */ .hint--bottom:before { - margin-top: -12px; } -.hint--bottom:after { - margin-left: -18px; } + margin-top: -11px; } + .hint--bottom:before, .hint--bottom:after { top: 100%; left: 50%; } -.hint--bottom:hover:after, .hint--bottom:hover:before, .hint--bottom:focus:after, .hint--bottom:focus:before { + +.hint--bottom:before { + left: calc(50% - 6px); } + +.hint--bottom:after { + -webkit-transform: translateX(-50%); + -moz-transform: translateX(-50%); + transform: translateX(-50%); } + +.hint--bottom:hover:before { -webkit-transform: translateY(8px); -moz-transform: translateY(8px); transform: translateY(8px); } +.hint--bottom:hover:after { + -webkit-transform: translateX(-50%) translateY(8px); + -moz-transform: translateX(-50%) translateY(8px); + transform: translateX(-50%) translateY(8px); } + /** * right tooltip */ .hint--right:before { - margin-left: -12px; + margin-left: -11px; margin-bottom: -6px; } + .hint--right:after { margin-bottom: -14px; } + .hint--right:before, .hint--right:after { left: 100%; bottom: 50%; } -.hint--right:hover:after, .hint--right:hover:before, .hint--right:focus:after, .hint--right:focus:before { + +.hint--right:hover:before { + -webkit-transform: translateX(8px); + -moz-transform: translateX(8px); + transform: translateX(8px); } + +.hint--right:hover:after { -webkit-transform: translateX(8px); -moz-transform: translateX(8px); transform: translateX(8px); } @@ -142,18 +201,191 @@ * left tooltip */ .hint--left:before { - margin-right: -12px; + margin-right: -11px; margin-bottom: -6px; } + .hint--left:after { margin-bottom: -14px; } + .hint--left:before, .hint--left:after { right: 100%; bottom: 50%; } -.hint--left:hover:after, .hint--left:hover:before, .hint--left:focus:after, .hint--left:focus:before { + +.hint--left:hover:before { -webkit-transform: translateX(-8px); -moz-transform: translateX(-8px); transform: translateX(-8px); } +.hint--left:hover:after { + -webkit-transform: translateX(-8px); + -moz-transform: translateX(-8px); + transform: translateX(-8px); } + +/** + * top-left tooltip + */ +.hint--top-left:before { + margin-bottom: -11px; } + +.hint--top-left:before, .hint--top-left:after { + bottom: 100%; + left: 50%; } + +.hint--top-left:before { + left: calc(50% - 6px); } + +.hint--top-left:after { + -webkit-transform: translateX(-100%); + -moz-transform: translateX(-100%); + transform: translateX(-100%); } + +.hint--top-left:after { + margin-left: 12px; } + +.hint--top-left:hover:before { + -webkit-transform: translateY(-8px); + -moz-transform: translateY(-8px); + transform: translateY(-8px); } + +.hint--top-left:hover:after { + -webkit-transform: translateX(-100%) translateY(-8px); + -moz-transform: translateX(-100%) translateY(-8px); + transform: translateX(-100%) translateY(-8px); } + +/** + * top-right tooltip + */ +.hint--top-right:before { + margin-bottom: -11px; } + +.hint--top-right:before, .hint--top-right:after { + bottom: 100%; + left: 50%; } + +.hint--top-right:before { + left: calc(50% - 6px); } + +.hint--top-right:after { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + transform: translateX(0); } + +.hint--top-right:after { + margin-left: -12px; } + +.hint--top-right:hover:before { + -webkit-transform: translateY(-8px); + -moz-transform: translateY(-8px); + transform: translateY(-8px); } + +.hint--top-right:hover:after { + -webkit-transform: translateY(-8px); + -moz-transform: translateY(-8px); + transform: translateY(-8px); } + +/** + * bottom-left tooltip + */ +.hint--bottom-left:before { + margin-top: -11px; } + +.hint--bottom-left:before, .hint--bottom-left:after { + top: 100%; + left: 50%; } + +.hint--bottom-left:before { + left: calc(50% - 6px); } + +.hint--bottom-left:after { + -webkit-transform: translateX(-100%); + -moz-transform: translateX(-100%); + transform: translateX(-100%); } + +.hint--bottom-left:after { + margin-left: 12px; } + +.hint--bottom-left:hover:before { + -webkit-transform: translateY(8px); + -moz-transform: translateY(8px); + transform: translateY(8px); } + +.hint--bottom-left:hover:after { + -webkit-transform: translateX(-100%) translateY(8px); + -moz-transform: translateX(-100%) translateY(8px); + transform: translateX(-100%) translateY(8px); } + +/** + * bottom-right tooltip + */ +.hint--bottom-right:before { + margin-top: -11px; } + +.hint--bottom-right:before, .hint--bottom-right:after { + top: 100%; + left: 50%; } + +.hint--bottom-right:before { + left: calc(50% - 6px); } + +.hint--bottom-right:after { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + transform: translateX(0); } + +.hint--bottom-right:after { + margin-left: -12px; } + +.hint--bottom-right:hover:before { + -webkit-transform: translateY(8px); + -moz-transform: translateY(8px); + transform: translateY(8px); } + +.hint--bottom-right:hover:after { + -webkit-transform: translateY(8px); + -moz-transform: translateY(8px); + transform: translateY(8px); } + +/** + * source: hint-sizes.scss + * + * Defines width restricted tooltips that can span + * across multiple lines. + * + * Classes added: + * 1) hint--small + * 2) hint--medium + * 3) hint--large + * + */ +.hint--small:after, +.hint--medium:after, +.hint--large:after { + white-space: normal; + line-height: 1.4em; } + +.hint--small:after { + width: 80px; } + +.hint--medium:after { + width: 150px; } + +.hint--large:after { + width: 300px; } + +/** + * source: hint-theme.scss + * + * Defines basic theme for tooltips. + * + */ +[class*="hint--"] { + /** + * tooltip body + */ } + [class*="hint--"]:after { + text-shadow: 0 -1px 0px black; + box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.3); } + /** * source: hint-color-types.scss * @@ -172,12 +404,28 @@ .hint--error:after { background-color: #b34e4d; text-shadow: 0 -1px 0px #592726; } + +.hint--error.hint--top-left:before { + border-top-color: #b34e4d; } + +.hint--error.hint--top-right:before { + border-top-color: #b34e4d; } + .hint--error.hint--top:before { border-top-color: #b34e4d; } + +.hint--error.hint--bottom-left:before { + border-bottom-color: #b34e4d; } + +.hint--error.hint--bottom-right:before { + border-bottom-color: #b34e4d; } + .hint--error.hint--bottom:before { border-bottom-color: #b34e4d; } + .hint--error.hint--left:before { border-left-color: #b34e4d; } + .hint--error.hint--right:before { border-right-color: #b34e4d; } @@ -187,12 +435,28 @@ .hint--warning:after { background-color: #c09854; text-shadow: 0 -1px 0px #6c5328; } + +.hint--warning.hint--top-left:before { + border-top-color: #c09854; } + +.hint--warning.hint--top-right:before { + border-top-color: #c09854; } + .hint--warning.hint--top:before { border-top-color: #c09854; } + +.hint--warning.hint--bottom-left:before { + border-bottom-color: #c09854; } + +.hint--warning.hint--bottom-right:before { + border-bottom-color: #c09854; } + .hint--warning.hint--bottom:before { border-bottom-color: #c09854; } + .hint--warning.hint--left:before { border-left-color: #c09854; } + .hint--warning.hint--right:before { border-right-color: #c09854; } @@ -201,13 +465,29 @@ */ .hint--info:after { background-color: #3986ac; - text-shadow: 0 -1px 0px #193b4d; } + text-shadow: 0 -1px 0px #1a3c4d; } + +.hint--info.hint--top-left:before { + border-top-color: #3986ac; } + +.hint--info.hint--top-right:before { + border-top-color: #3986ac; } + .hint--info.hint--top:before { border-top-color: #3986ac; } + +.hint--info.hint--bottom-left:before { + border-bottom-color: #3986ac; } + +.hint--info.hint--bottom-right:before { + border-bottom-color: #3986ac; } + .hint--info.hint--bottom:before { border-bottom-color: #3986ac; } + .hint--info.hint--left:before { border-left-color: #3986ac; } + .hint--info.hint--right:before { border-right-color: #3986ac; } @@ -217,12 +497,28 @@ .hint--success:after { background-color: #458746; text-shadow: 0 -1px 0px #1a321a; } + +.hint--success.hint--top-left:before { + border-top-color: #458746; } + +.hint--success.hint--top-right:before { + border-top-color: #458746; } + .hint--success.hint--top:before { border-top-color: #458746; } + +.hint--success.hint--bottom-left:before { + border-bottom-color: #458746; } + +.hint--success.hint--bottom-right:before { + border-bottom-color: #458746; } + .hint--success.hint--bottom:before { border-bottom-color: #458746; } + .hint--success.hint--left:before { border-left-color: #458746; } + .hint--success.hint--right:before { border-right-color: #458746; } @@ -238,19 +534,83 @@ .hint--always:after, .hint--always:before { opacity: 1; visibility: visible; } -.hint--always.hint--top:after, .hint--always.hint--top:before { + +.hint--always.hint--top:before { -webkit-transform: translateY(-8px); -moz-transform: translateY(-8px); transform: translateY(-8px); } -.hint--always.hint--bottom:after, .hint--always.hint--bottom:before { + +.hint--always.hint--top:after { + -webkit-transform: translateX(-50%) translateY(-8px); + -moz-transform: translateX(-50%) translateY(-8px); + transform: translateX(-50%) translateY(-8px); } + +.hint--always.hint--top-left:before { + -webkit-transform: translateY(-8px); + -moz-transform: translateY(-8px); + transform: translateY(-8px); } + +.hint--always.hint--top-left:after { + -webkit-transform: translateX(-100%) translateY(-8px); + -moz-transform: translateX(-100%) translateY(-8px); + transform: translateX(-100%) translateY(-8px); } + +.hint--always.hint--top-right:before { + -webkit-transform: translateY(-8px); + -moz-transform: translateY(-8px); + transform: translateY(-8px); } + +.hint--always.hint--top-right:after { + -webkit-transform: translateY(-8px); + -moz-transform: translateY(-8px); + transform: translateY(-8px); } + +.hint--always.hint--bottom:before { -webkit-transform: translateY(8px); -moz-transform: translateY(8px); transform: translateY(8px); } -.hint--always.hint--left:after, .hint--always.hint--left:before { + +.hint--always.hint--bottom:after { + -webkit-transform: translateX(-50%) translateY(8px); + -moz-transform: translateX(-50%) translateY(8px); + transform: translateX(-50%) translateY(8px); } + +.hint--always.hint--bottom-left:before { + -webkit-transform: translateY(8px); + -moz-transform: translateY(8px); + transform: translateY(8px); } + +.hint--always.hint--bottom-left:after { + -webkit-transform: translateX(-100%) translateY(8px); + -moz-transform: translateX(-100%) translateY(8px); + transform: translateX(-100%) translateY(8px); } + +.hint--always.hint--bottom-right:before { + -webkit-transform: translateY(8px); + -moz-transform: translateY(8px); + transform: translateY(8px); } + +.hint--always.hint--bottom-right:after { + -webkit-transform: translateY(8px); + -moz-transform: translateY(8px); + transform: translateY(8px); } + +.hint--always.hint--left:before { -webkit-transform: translateX(-8px); -moz-transform: translateX(-8px); transform: translateX(-8px); } -.hint--always.hint--right:after, .hint--always.hint--right:before { + +.hint--always.hint--left:after { + -webkit-transform: translateX(-8px); + -moz-transform: translateX(-8px); + transform: translateX(-8px); } + +.hint--always.hint--right:before { + -webkit-transform: translateX(8px); + -moz-transform: translateX(8px); + transform: translateX(8px); } + +.hint--always.hint--right:after { -webkit-transform: translateX(8px); -moz-transform: translateX(8px); transform: translateX(8px); } @@ -273,9 +633,15 @@ * Defines various transition effects for the tooltips. * * Classes added: - * 1) hint--bounce + * 1) hint--no-animate + * 2) hint--bounce * */ +.hint--no-animate:before, .hint--no-animate:after { + -webkit-transition-duration: 0ms; + -moz-transition-duration: 0ms; + transition-duration: 0ms; } + .hint--bounce:before, .hint--bounce:after { -webkit-transition: opacity 0.3s ease, visibility 0.3s ease, -webkit-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24); -moz-transition: opacity 0.3s ease, visibility 0.3s ease, -moz-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24); diff --git a/static/js/clipboard.js b/static/js/clipboard.js new file mode 100644 index 0000000..e54411e --- /dev/null +++ b/static/js/clipboard.js @@ -0,0 +1,740 @@ +/*! + * clipboard.js v1.5.10 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Clipboard = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o{% block title %}{{ sitename }}{% endblock %} + {% block head %}{% endblock %} diff --git a/templates/display/base.html b/templates/display/base.html index 1c595b8..587e76f 100644 --- a/templates/display/base.html +++ b/templates/display/base.html @@ -16,7 +16,16 @@ file expires in {{ expiry }} | {% endif %} {% block infomore %}{% endblock %} - {{ size }} | + {{ size }} | + {% if shorturlEnabled %} + {% if shorturl %} + {{shorturl}} | + {% else %} + short url | + {% endif %} + {% endif %} torrent | get @@ -32,4 +41,10 @@ + + + + {% if shorturlEnabled %} + + {% endif %} {% endblock %} diff --git a/templates/paste.html b/templates/paste.html index 3d71c74..1294b5e 100644 --- a/templates/paste.html +++ b/templates/paste.html @@ -1,9 +1,5 @@ {% extends "base.html" %} -{% block head %} - -{% endblock %} - {% block content %}