web: remove go template dependency

All vue pages now request `/nav` to get a JSON array of navigation
instead of relying on the Go template to have the nav built in. This
cleans up all of the crufty `{{ "{{ thing }}" }}` that was making it
hard to wriet vue.

This also paves the way to using the new Go resource embedding so that
the pages don't need to be wrapped in Go files.
This commit is contained in:
Chris Sexton 2021-01-09 13:46:28 -05:00
parent 92da19e5a8
commit bbf5b27790
13 changed files with 81 additions and 53 deletions

View File

@ -61,7 +61,8 @@ type bot struct {
} }
type EndPoint struct { type EndPoint struct {
Name, URL string Name string `json:"name"`
URL string `json:"url"`
} }
// Variable represents a $var replacement // Variable represents a $var replacement
@ -104,6 +105,7 @@ func New(config *config.Config, connector Connector) Bot {
bot.RefreshPluginWhitelist() bot.RefreshPluginWhitelist()
http.HandleFunc("/", bot.serveRoot) http.HandleFunc("/", bot.serveRoot)
http.HandleFunc("/nav", bot.serveNav)
connector.RegisterEvent(bot.Receive) connector.RegisterEvent(bot.Receive)

View File

@ -1,16 +1,24 @@
package bot package bot
import ( import (
"html/template" "encoding/json"
"fmt"
"net/http" "net/http"
"strings" "strings"
) )
func (b *bot) serveRoot(w http.ResponseWriter, r *http.Request) { func (b *bot) serveRoot(w http.ResponseWriter, r *http.Request) {
context := make(map[string]interface{}) fmt.Fprint(w, rootIndex)
context["Nav"] = b.GetWebNavigation() }
t := template.Must(template.New("rootIndex").Parse(rootIndex))
t.Execute(w, context) func (b *bot) serveNav(w http.ResponseWriter, r *http.Request) {
enc := json.NewEncoder(w)
err := enc.Encode(b.GetWebNavigation())
if err != nil {
jsonErr, _ := json.Marshal(err)
w.WriteHeader(500)
w.Write(jsonErr)
}
} }
// GetWebNavigation returns a list of bootstrap-vue <b-nav-item> links // GetWebNavigation returns a list of bootstrap-vue <b-nav-item> links
@ -54,7 +62,7 @@ var rootIndex = `
<b-navbar> <b-navbar>
<b-navbar-brand>catbase</b-navbar-brand> <b-navbar-brand>catbase</b-navbar-brand>
<b-navbar-nav> <b-navbar-nav>
<b-nav-item v-for="item in nav" :href="item.URL">{{ "{{ item.Name }}" }}</b-nav-item> <b-nav-item v-for="item in nav" :href="item.url">{{ item.name }}</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
</b-navbar> </b-navbar>
</div> </div>
@ -64,8 +72,15 @@ var rootIndex = `
el: '#app', el: '#app',
data: { data: {
err: '', err: '',
nav: {{ .Nav }}, nav: [],
}, },
mounted: function() {
axios.get('/nav')
.then(resp => {
this.nav = resp.data;
})
.catch(err => console.log(err))
}
}) })
</script> </script>
</body> </body>

View File

@ -5,7 +5,6 @@ package admin
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"os" "os"
"regexp" "regexp"
@ -328,10 +327,8 @@ func (p *AdminPlugin) registerWeb() {
p.bot.RegisterWeb("/vars", "Variables") p.bot.RegisterWeb("/vars", "Variables")
} }
var tpl = template.Must(template.New("factoidIndex").Parse(varIndex))
func (p *AdminPlugin) handleWeb(w http.ResponseWriter, r *http.Request) { func (p *AdminPlugin) handleWeb(w http.ResponseWriter, r *http.Request) {
tpl.Execute(w, struct{ Nav []bot.EndPoint }{p.bot.GetWebNavigation()}) fmt.Fprint(w, varIndex)
} }
func (p *AdminPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) { func (p *AdminPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) {

View File

@ -24,7 +24,7 @@ var varIndex = `
<b-navbar> <b-navbar>
<b-navbar-brand>Variables</b-navbar-brand> <b-navbar-brand>Variables</b-navbar-brand>
<b-navbar-nav> <b-navbar-nav>
<b-nav-item v-for="item in nav" :href="item.URL" :active="item.Name === 'Variables'">{{ "{{ item.Name }}" }}</b-nav-item> <b-nav-item v-for="item in nav" :href="item.url" :active="item.name === 'Variables'">{{ item.name }}</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
</b-navbar> </b-navbar>
<b-alert <b-alert
@ -32,7 +32,7 @@ var varIndex = `
variant="error" variant="error"
v-if="err" v-if="err"
@dismissed="err = ''"> @dismissed="err = ''">
{{ "{{ err }}" }} {{ err }}
</b-alert> </b-alert>
<b-container> <b-container>
<b-table <b-table
@ -48,7 +48,7 @@ var varIndex = `
el: '#app', el: '#app',
data: { data: {
err: '', err: '',
nav: {{ .Nav }}, nav: [],
vars: [], vars: [],
sortBy: 'key', sortBy: 'key',
fields: [ fields: [
@ -58,6 +58,11 @@ var varIndex = `
}, },
mounted() { mounted() {
this.getData(); this.getData();
axios.get('/nav')
.then(resp => {
this.nav = resp.data;
})
.catch(err => console.log(err))
}, },
methods: { methods: {
getData: function() { getData: function() {

View File

@ -5,7 +5,6 @@ package cli
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"time" "time"
@ -91,10 +90,8 @@ func (p *CliPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) {
w.Write(data) w.Write(data)
} }
var tpl = template.Must(template.New("factoidIndex").Parse(indexHTML))
func (p *CliPlugin) handleWeb(w http.ResponseWriter, r *http.Request) { func (p *CliPlugin) handleWeb(w http.ResponseWriter, r *http.Request) {
tpl.Execute(w, struct{ Nav []bot.EndPoint }{p.bot.GetWebNavigation()}) fmt.Fprint(w, indexHTML)
} }
// Completing the Connector interface, but will not actually be a connector // Completing the Connector interface, but will not actually be a connector

View File

@ -24,14 +24,14 @@ var indexHTML = `
<b-navbar> <b-navbar>
<b-navbar-brand>CLI</b-navbar-brand> <b-navbar-brand>CLI</b-navbar-brand>
<b-navbar-nav> <b-navbar-nav>
<b-nav-item v-for="item in nav" :href="item.URL" :active="item.Name === 'CLI'">{{ "{{ item.Name }}" }}</b-nav-item> <b-nav-item v-for="item in nav" :href="item.url" :active="item.name === 'CLI'">{{ item.name }}</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
</b-navbar> </b-navbar>
<b-alert <b-alert
dismissable dismissable
variant="error" variant="error"
:show="err"> :show="err">
{{ "{{ err }}" }} {{ err }}
</b-alert> </b-alert>
<b-container> <b-container>
<b-row> <b-row>
@ -80,13 +80,20 @@ var indexHTML = `
el: '#app', el: '#app',
data: { data: {
err: '', err: '',
nav: {{ .Nav }}, nav: [],
answer: '', answer: '',
correct: 0, correct: 0,
textarea: [], textarea: [],
user: '', user: '',
input: '', input: '',
}, },
mounted: function() {
axios.get('/nav')
.then(resp => {
this.nav = resp.data;
})
.catch(err => console.log(err))
},
computed: { computed: {
authenticated: function() { authenticated: function() {
if (this.user !== '') if (this.user !== '')

View File

@ -4,7 +4,6 @@ import (
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"math/rand" "math/rand"
"net/http" "net/http"
"regexp" "regexp"
@ -626,10 +625,8 @@ func (p *CounterPlugin) registerWeb() {
p.Bot.RegisterWeb("/counter", "Counter") p.Bot.RegisterWeb("/counter", "Counter")
} }
var tpl = template.Must(template.New("factoidIndex").Parse(html))
func (p *CounterPlugin) handleCounter(w http.ResponseWriter, r *http.Request) { func (p *CounterPlugin) handleCounter(w http.ResponseWriter, r *http.Request) {
tpl.Execute(w, struct{ Nav []bot.EndPoint }{p.Bot.GetWebNavigation()}) fmt.Fprint(w, html)
} }
func (p *CounterPlugin) handleCounterAPI(w http.ResponseWriter, r *http.Request) { func (p *CounterPlugin) handleCounterAPI(w http.ResponseWriter, r *http.Request) {

View File

@ -22,14 +22,14 @@ var html = `
<b-navbar> <b-navbar>
<b-navbar-brand>Counters</b-navbar-brand> <b-navbar-brand>Counters</b-navbar-brand>
<b-navbar-nav> <b-navbar-nav>
<b-nav-item v-for="item in nav" :href="item.URL" :active="item.Name === 'Counter'">{{ "{{ item.Name }}" }}</b-nav-item> <b-nav-item v-for="item in nav" :href="item.url" :active="item.name === 'Counter'">{{ item.name }}</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
</b-navbar> </b-navbar>
<b-alert <b-alert
dismissable dismissable
:show="err" :show="err"
variant="error"> variant="error">
{{ "{{ err }}" }} {{ err }}
</b-alert> </b-alert>
<b-container> <b-container>
<b-row> <b-row>
@ -37,14 +37,14 @@ var html = `
<b-col><b-input v-model="answer"></b-col> <b-col><b-input v-model="answer"></b-col>
</b-row> </b-row>
<b-row v-for="(counter, user) in counters"> <b-row v-for="(counter, user) in counters">
{{ "{{ user }}" }}: {{ user }}:
<b-container> <b-container>
<b-row v-for="(count, thing) in counter"> <b-row v-for="(count, thing) in counter">
<b-col offset="1"> <b-col offset="1">
{{ "{{ thing }}" }}: {{ thing }}:
</b-col> </b-col>
<b-col> <b-col>
{{ "{{ count }}" }} {{ count }}
</b-col> </b-col>
<b-col cols="2"> <b-col cols="2">
<button @click="subtract(user,thing,count)">-</button> <button @click="subtract(user,thing,count)">-</button>
@ -72,12 +72,17 @@ var html = `
el: '#app', el: '#app',
data: { data: {
err: '', err: '',
nav: {{ .Nav }}, nav: [],
answer: '', answer: '',
correct: 0, correct: 0,
counters: {} counters: {}
}, },
mounted() { mounted() {
axios.get('/nav')
.then(resp => {
this.nav = resp.data;
})
.catch(err => console.log(err))
axios.get('/counter/api') axios.get('/counter/api')
.then(resp => (this.counters = convertData(resp.data))) .then(resp => (this.counters = convertData(resp.data)))
.catch(err => (this.err = err)); .catch(err => (this.err = err));

View File

@ -842,8 +842,6 @@ func (p *FactoidPlugin) serveAPI(w http.ResponseWriter, r *http.Request) {
w.Write(data) w.Write(data)
} }
var tpl = template.Must(template.New("factoidIndex").Parse(factoidIndex))
func (p *FactoidPlugin) serveQuery(w http.ResponseWriter, r *http.Request) { func (p *FactoidPlugin) serveQuery(w http.ResponseWriter, r *http.Request) {
tpl.Execute(w, struct{ Nav []bot.EndPoint }{p.Bot.GetWebNavigation()}) fmt.Fprint(w, factoidIndex)
} }

View File

@ -32,7 +32,7 @@ var factoidIndex = `
<b-navbar> <b-navbar>
<b-navbar-brand>Factoids</b-navbar-brand> <b-navbar-brand>Factoids</b-navbar-brand>
<b-navbar-nav> <b-navbar-nav>
<b-nav-item v-for="item in nav" :href="item.URL" :active="item.Name === 'Factoid'">{{ "{{ item.Name }}" }}</b-nav-item> <b-nav-item v-for="item in nav" :href="item.url" :active="item.name === 'Factoid'">{{ item.name }}</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
</b-navbar> </b-navbar>
<b-alert <b-alert
@ -40,7 +40,7 @@ var factoidIndex = `
variant="error" variant="error"
v-if="err" v-if="err"
@dismissed="err = ''"> @dismissed="err = ''">
{{ "{{ err }}" }} {{ err }}
</b-alert> </b-alert>
<b-form @submit="runQuery"> <b-form @submit="runQuery">
<b-container> <b-container>
@ -74,7 +74,7 @@ var factoidIndex = `
router, router,
data: { data: {
err: '', err: '',
nav: {{ .Nav }}, nav: [],
query: '', query: '',
results: [], results: [],
fields: [ fields: [
@ -85,6 +85,11 @@ var factoidIndex = `
] ]
}, },
mounted() { mounted() {
axios.get('/nav')
.then(resp => {
this.nav = resp.data;
})
.catch(err => console.log(err))
if (this.$route.query.query) { if (this.$route.query.query) {
this.query = this.$route.query.query; this.query = this.$route.query.query;
this.runQuery() this.runQuery()

View File

@ -80,5 +80,4 @@ func (p *GitPlugin) registerWeb() {
http.HandleFunc("/git/gitea/event", p.giteaEvent) http.HandleFunc("/git/gitea/event", p.giteaEvent)
http.HandleFunc("/git/github/event", p.githubEvent) http.HandleFunc("/git/github/event", p.githubEvent)
http.HandleFunc("/git/gitlab/event", p.gitlabEvent) http.HandleFunc("/git/gitlab/event", p.gitlabEvent)
p.b.RegisterWeb("/git", "Git")
} }

View File

@ -25,7 +25,7 @@ var memeIndex = `
<b-navbar> <b-navbar>
<b-navbar-brand>Memes</b-navbar-brand> <b-navbar-brand>Memes</b-navbar-brand>
<b-navbar-nav> <b-navbar-nav>
<b-nav-item v-for="item in nav" :href="item.URL" :active="item.Name === 'Meme'">{{ "{{ item.Name }}" }}</b-nav-item> <b-nav-item v-for="item in nav" :href="item.url" :active="item.name === 'Meme'">{{ item.name }}</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
</b-navbar> </b-navbar>
<b-alert <b-alert
@ -33,7 +33,7 @@ var memeIndex = `
variant="error" variant="error"
v-if="err" v-if="err"
@dismissed="err = ''"> @dismissed="err = ''">
{{ "{{ err }}" }} {{ err }}
</b-alert> </b-alert>
<b-form @submit="addMeme"> <b-form @submit="addMeme">
<b-container> <b-container>
@ -58,7 +58,7 @@ var memeIndex = `
:items="results" :items="results"
:fields="fields"> :fields="fields">
<template v-slot:cell(config)="data"> <template v-slot:cell(config)="data">
<pre>{{ "{{data.item.config}}" }}</pre> <pre>{{data.item.config}}</pre>
</template> </template>
<template v-slot:cell(image)="data"> <template v-slot:cell(image)="data">
<b-img :src="data.item.url" rounded block fluid /> <b-img :src="data.item.url" rounded block fluid />
@ -80,7 +80,7 @@ var memeIndex = `
router, router,
data: { data: {
err: '', err: '',
nav: {{ .Nav }}, nav: [],
name: "", name: "",
url: "", url: "",
config: "", config: "",
@ -93,10 +93,13 @@ var memeIndex = `
] ]
}, },
mounted() { mounted() {
axios.get('/nav')
.then(resp => {
this.nav = resp.data;
})
.catch(err => console.log(err))
this.refresh(); this.refresh();
}, },
computed: {
},
methods: { methods: {
refresh: function() { refresh: function() {
axios.get('/meme/all') axios.get('/meme/all')

View File

@ -3,7 +3,6 @@ package meme
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"net/url" "net/url"
"path" "path"
@ -130,8 +129,7 @@ func (p *MemePlugin) addMeme(w http.ResponseWriter, r *http.Request) {
} }
func (p *MemePlugin) webRoot(w http.ResponseWriter, r *http.Request) { func (p *MemePlugin) webRoot(w http.ResponseWriter, r *http.Request) {
var tpl = template.Must(template.New("factoidIndex").Parse(string(memeIndex))) fmt.Fprint(w, memeIndex)
tpl.Execute(w, struct{ Nav []bot.EndPoint }{p.bot.GetWebNavigation()})
} }
func (p *MemePlugin) img(w http.ResponseWriter, r *http.Request) { func (p *MemePlugin) img(w http.ResponseWriter, r *http.Request) {