mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-18 10:07:02 +00:00
Make links clickable in text view of emails
This commit is contained in:
@@ -5,16 +5,20 @@ import (
|
|||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var TemplateFuncs = template.FuncMap{
|
var TemplateFuncs = template.FuncMap{
|
||||||
"friendlyTime": friendlyTime,
|
"friendlyTime": friendlyTime,
|
||||||
"reverse": reverse,
|
"reverse": reverse,
|
||||||
"textToHtml": textToHtml,
|
"textToHtml": textToHtml,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From http://daringfireball.net/2010/07/improved_regex_for_matching_urls
|
||||||
|
var urlRE = regexp.MustCompile("(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))")
|
||||||
|
|
||||||
// Friendly date & time rendering
|
// Friendly date & time rendering
|
||||||
func friendlyTime(t time.Time) template.HTML {
|
func friendlyTime(t time.Time) template.HTML {
|
||||||
ty, tm, td := t.Date()
|
ty, tm, td := t.Date()
|
||||||
@@ -45,6 +49,13 @@ func reverse(name string, things ...interface{}) string {
|
|||||||
// HTML display
|
// HTML display
|
||||||
func textToHtml(text string) template.HTML {
|
func textToHtml(text string) template.HTML {
|
||||||
text = html.EscapeString(text)
|
text = html.EscapeString(text)
|
||||||
|
text = urlRE.ReplaceAllStringFunc(text, wrapUrl)
|
||||||
replacer := strings.NewReplacer("\r\n", "<br/>\n", "\r", "<br/>\n", "\n", "<br/>\n")
|
replacer := strings.NewReplacer("\r\n", "<br/>\n", "\r", "<br/>\n", "\n", "<br/>\n")
|
||||||
return template.HTML(replacer.Replace(text))
|
return template.HTML(replacer.Replace(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapUrl wraps a <a href> tag around the provided URL
|
||||||
|
func wrapUrl(url string) string {
|
||||||
|
unescaped := strings.Replace(url, "&", "&", -1)
|
||||||
|
return fmt.Sprintf("<a href=\"%s\" target=\"_blank\">%s</a>", unescaped, url)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,18 +2,28 @@ package web
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchrcom/testify/assert"
|
"github.com/stretchrcom/testify/assert"
|
||||||
|
"html/template"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTextToHtml(t *testing.T) {
|
func TestTextToHtml(t *testing.T) {
|
||||||
// Identity
|
// Identity
|
||||||
assert.Equal(t, textToHtml("html"), "html")
|
assert.Equal(t, textToHtml("html"), template.HTML("html"))
|
||||||
|
|
||||||
// Check it escapes
|
// Check it escapes
|
||||||
assert.Equal(t, textToHtml("<html>"), "<html>")
|
assert.Equal(t, textToHtml("<html>"), template.HTML("<html>"))
|
||||||
|
|
||||||
// Check for linebreaks
|
// Check for linebreaks
|
||||||
assert.Equal(t, textToHtml("line\nbreak"), "line<br/>\nbreak")
|
assert.Equal(t, textToHtml("line\nbreak"), template.HTML("line<br/>\nbreak"))
|
||||||
assert.Equal(t, textToHtml("line\r\nbreak"), "line<br/>\nbreak")
|
assert.Equal(t, textToHtml("line\r\nbreak"), template.HTML("line<br/>\nbreak"))
|
||||||
assert.Equal(t, textToHtml("line\rbreak"), "line<br/>\nbreak")
|
assert.Equal(t, textToHtml("line\rbreak"), template.HTML("line<br/>\nbreak"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestURLDetection(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
textToHtml("http://google.com/"),
|
||||||
|
template.HTML("<a href=\"http://google.com/\" target=\"_blank\">http://google.com/</a>"))
|
||||||
|
assert.Equal(t,
|
||||||
|
textToHtml("http://a.com/?q=a&n=v"),
|
||||||
|
template.HTML("<a href=\"http://a.com/?q=a&n=v\" target=\"_blank\">http://a.com/?q=a&n=v</a>"))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user