hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

livereloadinject.go (2268B)

    1 // Copyright 2018 The Hugo Authors. All rights reserved.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 // http://www.apache.org/licenses/LICENSE-2.0
    7 //
    8 // Unless required by applicable law or agreed to in writing, software
    9 // distributed under the License is distributed on an "AS IS" BASIS,
   10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11 // See the License for the specific language governing permissions and
   12 // limitations under the License.
   13 
   14 package livereloadinject
   15 
   16 import (
   17 	"bytes"
   18 	"fmt"
   19 	"html"
   20 	"net/url"
   21 	"strings"
   22 
   23 	"github.com/gohugoio/hugo/helpers"
   24 	"github.com/gohugoio/hugo/transform"
   25 )
   26 
   27 type tag struct {
   28 	markup       []byte
   29 	appendScript bool
   30 }
   31 
   32 var tags = []tag{
   33 	{markup: []byte("<head>"), appendScript: true},
   34 	{markup: []byte("<HEAD>"), appendScript: true},
   35 	{markup: []byte("</body>")},
   36 	{markup: []byte("</BODY>")},
   37 }
   38 
   39 // New creates a function that can be used
   40 // to inject a script tag for the livereload JavaScript in a HTML document.
   41 func New(baseURL url.URL) transform.Transformer {
   42 	return func(ft transform.FromTo) error {
   43 		b := ft.From().Bytes()
   44 		idx := -1
   45 		var match tag
   46 		// We used to insert the livereload script right before the closing body.
   47 		// This does not work when combined with tools such as Turbolinks.
   48 		// So we try to inject the script as early as possible.
   49 		for _, t := range tags {
   50 			idx = bytes.Index(b, t.markup)
   51 			if idx != -1 {
   52 				match = t
   53 				break
   54 			}
   55 		}
   56 
   57 		path := strings.TrimSuffix(baseURL.Path, "/")
   58 
   59 		src := path + "/livereload.js?mindelay=10&v=2"
   60 		src += "&port=" + baseURL.Port()
   61 		src += "&path=" + strings.TrimPrefix(path+"/livereload", "/")
   62 
   63 		c := make([]byte, len(b))
   64 		copy(c, b)
   65 
   66 		if idx == -1 {
   67 			_, err := ft.To().Write(c)
   68 			return err
   69 		}
   70 
   71 		script := []byte(fmt.Sprintf(`<script src="%s" data-no-instant defer></script>`, html.EscapeString(src)))
   72 
   73 		i := idx
   74 		if match.appendScript {
   75 			i += len(match.markup)
   76 		}
   77 
   78 		c = append(c[:i], append(script, c[i:]...)...)
   79 
   80 		if _, err := ft.To().Write(c); err != nil {
   81 			helpers.DistinctWarnLog.Println("Failed to inject LiveReload script:", err)
   82 		}
   83 		return nil
   84 	}
   85 }