Externalizing web assets
mostly to ease editing, but also for practice with file manipulation, gzipping, base64'ing, etc.
This commit is contained in:
110
conway/web_assets/gen.go
Normal file
110
conway/web_assets/gen.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
webAssetsTmpl = template.Must(template.New("web_assets").Parse("" +
|
||||
"package conway\n" +
|
||||
"\n" +
|
||||
"const (\n" +
|
||||
" GAME_OF_LIFE_INDEX_HTML = `{{.IndexHTML}}`\n" +
|
||||
" NORMALIZE_CSS = `{{.NormalizeCSS}}`\n" +
|
||||
" JQUERY_MIN_JS = `{{.JqueryMinJS}}`\n" +
|
||||
")\n"))
|
||||
normalizeCssUrl = "http://necolas.github.com/normalize.css/2.0.1/normalize.css"
|
||||
jqueryMinJsUrl = "http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"
|
||||
)
|
||||
|
||||
type webAssetStrings struct {
|
||||
IndexHTML string
|
||||
NormalizeCSS string
|
||||
JqueryMinJS string
|
||||
Now time.Time
|
||||
}
|
||||
|
||||
func die(err error) {
|
||||
log.Fatal("CRUD:", err)
|
||||
}
|
||||
|
||||
func toB64(input []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(input)
|
||||
}
|
||||
|
||||
func toGz(input []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
|
||||
zwriter := gzip.NewWriter(&buf)
|
||||
|
||||
zbuf := bufio.NewWriter(zwriter)
|
||||
|
||||
toWrite := len(input)
|
||||
for written := 0; written < toWrite; {
|
||||
n, err := zbuf.Write(input[written:])
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
written += n
|
||||
}
|
||||
|
||||
zbuf.Flush()
|
||||
zwriter.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func fetchUrl(url string) []byte {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func fetchIndexHtml(indexHtmlPath string) []byte {
|
||||
fd, err := os.Open(indexHtmlPath)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(fd)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
die(errors.New(fmt.Sprintf("Usage: %s <index.html-path>", os.Args[0])))
|
||||
}
|
||||
|
||||
assets := &webAssetStrings{
|
||||
IndexHTML: toB64(toGz(fetchIndexHtml(os.Args[1]))),
|
||||
NormalizeCSS: toB64(toGz(fetchUrl(normalizeCssUrl))),
|
||||
JqueryMinJS: toB64(toGz(fetchUrl(jqueryMinJsUrl))),
|
||||
Now: time.Now(),
|
||||
}
|
||||
|
||||
webAssetsTmpl.Execute(os.Stdout, assets)
|
||||
}
|
51
conway/web_assets/index.html
Normal file
51
conway/web_assets/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Conway's Game of Life</title>
|
||||
<link type="text/css" rel="stylesheet" href="/static/normalize.css" />
|
||||
<script type="text/javascript" src="/static/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
curState = {};
|
||||
curImg = "";
|
||||
|
||||
function populateInitialState() {
|
||||
$.getJSON('/state', {}, onPopulateResponse);
|
||||
}
|
||||
|
||||
function goToNextState(state) {
|
||||
$.post('/state', JSON.stringify({s: state}, null, 2), onPopulateResponse, 'json');
|
||||
}
|
||||
|
||||
function playGame() {
|
||||
goToNextState(curState);
|
||||
setTimeout(playGame, 500);
|
||||
}
|
||||
|
||||
function onPopulateResponse(data, textStatus, jqXHR) {
|
||||
$.extend(curState, data.s);
|
||||
curImg = data.i;
|
||||
var $stateImg = $('#state_img');
|
||||
if ($stateImg.length < 1) {
|
||||
$stateImg = $('<img id="state_img" />').appendTo($('#state_container'));
|
||||
}
|
||||
$stateImg.attr('src', 'data:image/png;base64,' + encodeURI(data.i));
|
||||
}
|
||||
|
||||
$(function() {
|
||||
populateInitialState();
|
||||
$('#step').click(function() { goToNextState(curState); });
|
||||
$('#play').click(playGame);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Conway's Game of Life</h1>
|
||||
<div id="controls">
|
||||
<button id="step">Step</button>
|
||||
<button id="play">Play</button>
|
||||
</div>
|
||||
<hr />
|
||||
<div id="state_container">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user