Skip to content

Commit

Permalink
Merge pull request #140 from shift72/AB#12429-fix-errors-breaking-html
Browse files Browse the repository at this point in the history
Dev mode: nicer HTML injection of error message / live reload
  • Loading branch information
sam-shift72 authored May 29, 2024
2 parents 4b5cdda + e75cdd3 commit 627eb43
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 23 deletions.
2 changes: 1 addition & 1 deletion kibble/api/translations.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func LoadAllTranslations(cfg *models.Config, site *models.Site) error {
site.Translations[formatPathLocale(code)] = wholeLanguage
}

log.Infof("Translations Recieved and Parsed")
log.Infof("Translations received and parsed")
return nil
}

Expand Down
122 changes: 100 additions & 22 deletions kibble/render/live_reload.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
fsnotify "gopkg.in/fsnotify/fsnotify.v1"
)

var embed = `
var liveReloadEmbed = `
<script>
(function(){
var etag = ''; // IE 11 can't handle the 'If-Modified-Since' header
Expand Down Expand Up @@ -60,6 +60,55 @@ var embed = `
</script>
`

var kibbleErrorMessage = `
<div class="kibble-errors">
<b>Kibble errors</b>
<p>This may prevent the site from working properly. Check terminal output for details<p>
</div>
<script>
const el = document.querySelector('.kibble-errors');
const hide = () => {
el.classList.add("kibble-errors--hidden");
setTimeout(() => el.remove(), 1000);
};
el.addEventListener('click', hide);
setTimeout(hide, 5000);
</script>
<style>
.kibble-errors {
position: fixed;
bottom: 1rem;
right: 1rem;
width: 350px;
z-index: 10000;
border-radius: 0.25rem;
border: 1px solid #a61e4d;
color: #a61e4d;
background-color: #fcc2d7;
box-shadow: 0 10px 10px rgba(0,0,0,0.2);
transition: transform, opacity, 0.5s;
transform: translate(0,0);
opacity: 1;
font-size: 16px;
padding: 0.75em 1em;
}
.kibble-errors p {
margin: 0;
font-size: 0.8em;
opacity: 0.8;
}
.kibble-errors--hidden {
transform: translateY(100px);
opacity: 0;
}
</style>
`

// LiveReload -
type LiveReload struct {
lastModified time.Time
Expand All @@ -73,9 +122,9 @@ type LiveReload struct {
// intercepts all write calls so as to append the live reload script
type WrapperResponseWriter struct {
http.ResponseWriter
status int
buf bytes.Buffer
prefixBuf bytes.Buffer
status int
buf bytes.Buffer
htmlToInject bytes.Buffer
}

// NewWrapperResponseWriter - create a new response writer
Expand All @@ -94,25 +143,50 @@ func (w *WrapperResponseWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}

// PrefixWithLogs - write the logs to the head of the page
func (w *WrapperResponseWriter) PrefixWithLogs(logs []string) {
if len(logs) == 0 {
return
}

w.prefixBuf.Write([]byte("<div>"))
for _, s := range logs {
w.prefixBuf.Write([]byte(fmt.Sprintf("<pre>%s</pre>", s)))
}
w.prefixBuf.Write([]byte("</div>"))
func (w *WrapperResponseWriter) AddHtmlInject(html string) {
w.htmlToInject.WriteString(html)
}

// Done - called when are ready to return a result
func (w *WrapperResponseWriter) Done() (n int, err error) {
w.Header().Set("Content-Length", strconv.Itoa(w.buf.Len()+w.prefixBuf.Len()))
func (w *WrapperResponseWriter) Done() (err error) {
if w.htmlToInject.Len() > 0 {
responseBytes := w.buf.Bytes()

// Find the end of the HTML body to inject our stuff. This is a little
// bit flaky as it assumes "sensible" html style on the body closing tag
endOfBodyIndex := bytes.LastIndex(responseBytes, []byte("</body>"))
if endOfBodyIndex >= 0 {
chunks := [][]byte{
responseBytes[0:endOfBodyIndex],
w.htmlToInject.Bytes(),
responseBytes[endOfBodyIndex:],
}

length := 0
for _, chunk := range chunks {
length += len(chunk)
}

w.Header().Set("Content-Length", strconv.Itoa(length))
w.ResponseWriter.WriteHeader(w.status)

for _, chunk := range chunks {
if _, err = w.ResponseWriter.Write(chunk); err != nil {
return err
}
}

return nil
}

// If no end of body can be found, don't inject anything. It might be a
// partial, or not a valid HTML doc.
}

w.Header().Set("Content-Length", strconv.Itoa(w.buf.Len()))
w.ResponseWriter.WriteHeader(w.status)
_, _ = w.ResponseWriter.Write(w.prefixBuf.Bytes())
return w.ResponseWriter.Write(w.buf.Bytes())
_, err = w.ResponseWriter.Write(w.buf.Bytes())
return err
}

// WriteHeader - wrap the write header
Expand All @@ -132,15 +206,19 @@ func (live *LiveReload) GetMiddleware(next http.Handler) http.Handler {
strings.HasSuffix(r.RequestURI, ".html") {

if ww.Status() == 200 {
ww.PrefixWithLogs(live.logReader.Logs())
if len(live.logReader.Logs()) > 0 {
ww.AddHtmlInject(kibbleErrorMessage)
}

if live.reloadBrowserOnFileChange {
_, _ = ww.Write([]byte(embed))
ww.AddHtmlInject(liveReloadEmbed)
}
}
}

_, _ = ww.Done()
if err := ww.Done(); err != nil {
panic(err)
}
})
}

Expand Down

0 comments on commit 627eb43

Please sign in to comment.