Compare commits
2 Commits
c3b10ae239
...
133d8bcfe9
Author | SHA1 | Date | |
---|---|---|---|
133d8bcfe9 | |||
a15bbcee3d |
@ -257,11 +257,10 @@ func (app *application) postGuestbookCommentCreateRemote(w http.ResponseWriter,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if normalizeUrl(r.Header.Get("Origin")) != normalizeUrl(website.SiteUrl) {
|
if !matchOrigin(r.Header.Get("Origin"), website.Url) {
|
||||||
app.clientError(w, http.StatusForbidden)
|
app.clientError(w, http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !website.Guestbook.CanComment() {
|
if !website.Guestbook.CanComment() {
|
||||||
app.clientError(w, http.StatusForbidden)
|
app.clientError(w, http.StatusForbidden)
|
||||||
return
|
return
|
||||||
@ -279,10 +278,16 @@ func (app *application) postGuestbookCommentCreateRemote(w http.ResponseWriter,
|
|||||||
form.CheckField(validator.MaxChars(form.AuthorEmail, 256), "authorEmail", "This field cannot be more than 256 characters long")
|
form.CheckField(validator.MaxChars(form.AuthorEmail, 256), "authorEmail", "This field cannot be more than 256 characters long")
|
||||||
form.CheckField(validator.MaxChars(form.AuthorSite, 256), "authorSite", "This field cannot be more than 256 characters long")
|
form.CheckField(validator.MaxChars(form.AuthorSite, 256), "authorSite", "This field cannot be more than 256 characters long")
|
||||||
form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")
|
form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")
|
||||||
// TODO: Add optional field filled with window.location.href
|
|
||||||
// If it is populated, use as redirect URL
|
// if redirect path is filled out, redirect to that path on the website host
|
||||||
// Else redirect to homepage as stored in the website struct
|
// otherwise redirect to the guestbook by default
|
||||||
redirectUrl := r.Header.Get("Referer")
|
redirectUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(website.ShortId))
|
||||||
|
if form.Redirect != "" {
|
||||||
|
u, err := website.Url.Parse(form.Redirect)
|
||||||
|
if err == nil {
|
||||||
|
redirectUrl = u.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !form.Valid() {
|
if !form.Valid() {
|
||||||
views.GuestbookCommentCreateRemoteErrorView(redirectUrl, "Invalid Input").Render(r.Context(), w)
|
views.GuestbookCommentCreateRemoteErrorView(redirectUrl, "Invalid Input").Render(r.Context(), w)
|
||||||
|
@ -144,3 +144,88 @@ func TestPostGuestbookCommentCreate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPostGuestbookCommentCreateRemote(t *testing.T) {
|
||||||
|
app := newTestApplication(t)
|
||||||
|
ts := newTestServer(t, app.routes())
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
_, _, body := ts.get(t, fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(1)))
|
||||||
|
validCSRFToken := extractCSRFToken(t, body)
|
||||||
|
|
||||||
|
const (
|
||||||
|
validAuthorName = "John Test"
|
||||||
|
validAuthorEmail = "test@example.com"
|
||||||
|
validAuthorSite = "example.com"
|
||||||
|
validContent = "This is a comment"
|
||||||
|
)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
authorName string
|
||||||
|
authorEmail string
|
||||||
|
authorSite string
|
||||||
|
content string
|
||||||
|
csrfToken string
|
||||||
|
wantCode int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid input",
|
||||||
|
authorName: validAuthorName,
|
||||||
|
authorEmail: validAuthorEmail,
|
||||||
|
authorSite: validAuthorSite,
|
||||||
|
content: validContent,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusSeeOther,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blank name",
|
||||||
|
authorName: "",
|
||||||
|
authorEmail: validAuthorEmail,
|
||||||
|
authorSite: validAuthorSite,
|
||||||
|
content: validContent,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blank email",
|
||||||
|
authorName: validAuthorName,
|
||||||
|
authorEmail: "",
|
||||||
|
authorSite: validAuthorSite,
|
||||||
|
content: validContent,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusSeeOther,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blank site",
|
||||||
|
authorName: validAuthorName,
|
||||||
|
authorEmail: validAuthorEmail,
|
||||||
|
authorSite: "",
|
||||||
|
content: validContent,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusSeeOther,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blank content",
|
||||||
|
authorName: validAuthorName,
|
||||||
|
authorEmail: validAuthorEmail,
|
||||||
|
authorSite: validAuthorSite,
|
||||||
|
content: "",
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
form := url.Values{}
|
||||||
|
form.Add("authorname", tt.authorName)
|
||||||
|
form.Add("authoremail", tt.authorEmail)
|
||||||
|
form.Add("authorsite", tt.authorSite)
|
||||||
|
form.Add("content", tt.content)
|
||||||
|
form.Add("csrf_token", tt.csrfToken)
|
||||||
|
code, _, body := ts.postForm(t, fmt.Sprintf("/websites/%s/guestbook/comments/create/remote", shortIdToSlug(1)), form)
|
||||||
|
assert.Equal(t, code, tt.wantCode)
|
||||||
|
assert.Equal(t, body, body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"git.32bit.cafe/32bitcafe/guestbook/internal/forms"
|
"git.32bit.cafe/32bitcafe/guestbook/internal/forms"
|
||||||
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
||||||
@ -32,14 +33,20 @@ func (app *application) postWebsiteCreate(w http.ResponseWriter, r *http.Request
|
|||||||
form.CheckField(validator.MaxChars(form.Name, 256), "sitename", "This field cannot exceed 256 characters")
|
form.CheckField(validator.MaxChars(form.Name, 256), "sitename", "This field cannot exceed 256 characters")
|
||||||
form.CheckField(validator.NotBlank(form.SiteUrl), "siteurl", "This field cannot be blank")
|
form.CheckField(validator.NotBlank(form.SiteUrl), "siteurl", "This field cannot be blank")
|
||||||
form.CheckField(validator.MaxChars(form.SiteUrl, 512), "siteurl", "This field cannot exceed 512 characters")
|
form.CheckField(validator.MaxChars(form.SiteUrl, 512), "siteurl", "This field cannot exceed 512 characters")
|
||||||
|
form.CheckField(validator.Matches(form.SiteUrl, validator.WebRX), "siteurl", "This field must be a valid URL (including http:// or https://)")
|
||||||
|
|
||||||
|
u, err := url.Parse(form.SiteUrl)
|
||||||
|
if err != nil {
|
||||||
|
form.CheckField(false, "siteurl", "This field must be a valid URL")
|
||||||
|
}
|
||||||
if !form.Valid() {
|
if !form.Valid() {
|
||||||
data := app.newCommonData(r)
|
data := app.newCommonData(r)
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
views.WebsiteCreate("Add a Website", data, form).Render(r.Context(), w)
|
views.WebsiteCreate("Add a Website", data, form).Render(r.Context(), w)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
websiteShortID := app.createShortId()
|
websiteShortID := app.createShortId()
|
||||||
_, err = app.websites.Insert(websiteShortID, userId, form.Name, form.SiteUrl, form.AuthorName)
|
_, err = app.websites.Insert(websiteShortID, userId, form.Name, u.String(), form.AuthorName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.serverError(w, r, err)
|
app.serverError(w, r, err)
|
||||||
return
|
return
|
||||||
@ -75,10 +82,6 @@ func (app *application) getWebsiteList(w http.ResponseWriter, r *http.Request) {
|
|||||||
app.serverError(w, r, err)
|
app.serverError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r.Header.Get("HX-Request") == "true" {
|
|
||||||
views.HxWebsiteList(websites)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data := app.newCommonData(r)
|
data := app.newCommonData(r)
|
||||||
views.WebsiteList("My Websites", data, websites).Render(r.Context(), w)
|
views.WebsiteList("My Websites", data, websites).Render(r.Context(), w)
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
||||||
@ -130,11 +130,13 @@ func (app *application) durationToTime(duration string) (time.Time, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeUrl(url string) string {
|
func matchOrigin(origin string, u *url.URL) bool {
|
||||||
r, f := strings.CutPrefix(url, "http://")
|
o, err := url.Parse(origin)
|
||||||
if f {
|
if err != nil {
|
||||||
return r
|
return false
|
||||||
}
|
}
|
||||||
r, _ = strings.CutPrefix(url, "https://")
|
if o.Host != u.Host {
|
||||||
return r
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ type CommentCreateForm struct {
|
|||||||
AuthorEmail string `schema:"authoremail"`
|
AuthorEmail string `schema:"authoremail"`
|
||||||
AuthorSite string `schema:"authorsite"`
|
AuthorSite string `schema:"authorsite"`
|
||||||
Content string `schema:"content"`
|
Content string `schema:"content"`
|
||||||
|
Redirect string `schema:"redirect"`
|
||||||
validator.Validator `schema:"-"`
|
validator.Validator `schema:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,12 @@ var mockGuestbookComment = models.GuestbookComment{
|
|||||||
IsPublished: true,
|
IsPublished: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mockSerializedGuestbookComment = models.GuestbookCommentSerialized{
|
||||||
|
AuthorName: "John Test",
|
||||||
|
CommentText: "Hello, world",
|
||||||
|
Created: time.Now().Format(time.RFC3339),
|
||||||
|
}
|
||||||
|
|
||||||
type GuestbookCommentModel struct{}
|
type GuestbookCommentModel struct{}
|
||||||
|
|
||||||
func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
|
func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
|
||||||
@ -45,6 +51,17 @@ func (m *GuestbookCommentModel) GetAll(guestbookId int64) ([]models.GuestbookCom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *GuestbookCommentModel) GetAllSerialized(guestbookId int64) ([]models.GuestbookCommentSerialized, error) {
|
||||||
|
switch guestbookId {
|
||||||
|
case 1:
|
||||||
|
return []models.GuestbookCommentSerialized{mockSerializedGuestbookComment}, nil
|
||||||
|
case 2:
|
||||||
|
return []models.GuestbookCommentSerialized{}, nil
|
||||||
|
default:
|
||||||
|
return []models.GuestbookCommentSerialized{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *GuestbookCommentModel) GetDeleted(guestbookId int64) ([]models.GuestbookComment, error) {
|
func (m *GuestbookCommentModel) GetDeleted(guestbookId int64) ([]models.GuestbookComment, error) {
|
||||||
switch guestbookId {
|
switch guestbookId {
|
||||||
default:
|
default:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
||||||
@ -22,10 +23,14 @@ var mockGuestbook = models.Guestbook{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mockWebsite = models.Website{
|
var mockWebsite = models.Website{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
ShortId: 1,
|
ShortId: 1,
|
||||||
Name: "Example",
|
Name: "Example",
|
||||||
SiteUrl: "example.com",
|
// SiteUrl: "example.com",
|
||||||
|
Url: &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: "example.com",
|
||||||
|
},
|
||||||
AuthorName: "John Test",
|
AuthorName: "John Test",
|
||||||
UserId: 1,
|
UserId: 1,
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
|
@ -3,15 +3,17 @@ package models
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Website struct {
|
type Website struct {
|
||||||
ID int64
|
ID int64
|
||||||
ShortId uint64
|
ShortId uint64
|
||||||
Name string
|
Name string
|
||||||
SiteUrl string
|
// SiteUrl string
|
||||||
|
Url *url.URL
|
||||||
AuthorName string
|
AuthorName string
|
||||||
UserId int64
|
UserId int64
|
||||||
Created time.Time
|
Created time.Time
|
||||||
@ -179,7 +181,8 @@ func (m *WebsiteModel) Get(shortId uint64) (Website, error) {
|
|||||||
}
|
}
|
||||||
row := tx.QueryRow(stmt, shortId)
|
row := tx.QueryRow(stmt, shortId)
|
||||||
var w Website
|
var w Website
|
||||||
err = row.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created)
|
var u string
|
||||||
|
err = row.Scan(&w.ID, &w.ShortId, &w.Name, &u, &w.AuthorName, &w.UserId, &w.Created)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
err = ErrNoRecord
|
err = ErrNoRecord
|
||||||
@ -189,6 +192,10 @@ func (m *WebsiteModel) Get(shortId uint64) (Website, error) {
|
|||||||
}
|
}
|
||||||
return Website{}, err
|
return Website{}, err
|
||||||
}
|
}
|
||||||
|
w.Url, err = url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return Website{}, err
|
||||||
|
}
|
||||||
|
|
||||||
stmt = `SELECT Id, ShortId, UserId, WebsiteId, Created, IsActive FROM guestbooks
|
stmt = `SELECT Id, ShortId, UserId, WebsiteId, Created, IsActive FROM guestbooks
|
||||||
WHERE WebsiteId = ? AND Deleted IS NULL`
|
WHERE WebsiteId = ? AND Deleted IS NULL`
|
||||||
@ -244,11 +251,16 @@ func (m *WebsiteModel) GetAllUser(userId int64) ([]Website, error) {
|
|||||||
var websites []Website
|
var websites []Website
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var w Website
|
var w Website
|
||||||
err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created,
|
var u string
|
||||||
|
err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &u, &w.AuthorName, &w.UserId, &w.Created,
|
||||||
&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive)
|
&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
w.Url, err = url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
websites = append(websites, w)
|
websites = append(websites, w)
|
||||||
}
|
}
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
@ -268,11 +280,16 @@ func (m *WebsiteModel) GetAll() ([]Website, error) {
|
|||||||
var websites []Website
|
var websites []Website
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var w Website
|
var w Website
|
||||||
err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created,
|
var u string
|
||||||
|
err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &u, &w.AuthorName, &w.UserId, &w.Created,
|
||||||
&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive)
|
&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
w.Url, err = url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
websites = append(websites, w)
|
websites = append(websites, w)
|
||||||
}
|
}
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
@ -8,51 +8,52 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var EmailRX = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
var EmailRX = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
||||||
|
var WebRX = regexp.MustCompile("^https?:\\/\\/")
|
||||||
|
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
NonFieldErrors []string
|
NonFieldErrors []string
|
||||||
FieldErrors map[string]string
|
FieldErrors map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) Valid() bool {
|
func (v *Validator) Valid() bool {
|
||||||
return len(v.FieldErrors) == 0 && len(v.NonFieldErrors) == 0
|
return len(v.FieldErrors) == 0 && len(v.NonFieldErrors) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) AddFieldError(key, message string) {
|
func (v *Validator) AddFieldError(key, message string) {
|
||||||
if v.FieldErrors == nil {
|
if v.FieldErrors == nil {
|
||||||
v.FieldErrors = make(map[string]string)
|
v.FieldErrors = make(map[string]string)
|
||||||
}
|
}
|
||||||
if _, exists := v.FieldErrors[key]; !exists {
|
if _, exists := v.FieldErrors[key]; !exists {
|
||||||
v.FieldErrors[key] = message
|
v.FieldErrors[key] = message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) AddNonFieldError(message string) {
|
func (v *Validator) AddNonFieldError(message string) {
|
||||||
v.NonFieldErrors = append(v.NonFieldErrors, message)
|
v.NonFieldErrors = append(v.NonFieldErrors, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) CheckField(ok bool, key, message string) {
|
func (v *Validator) CheckField(ok bool, key, message string) {
|
||||||
if !ok {
|
if !ok {
|
||||||
v.AddFieldError(key, message)
|
v.AddFieldError(key, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotBlank(value string) bool {
|
func NotBlank(value string) bool {
|
||||||
return strings.TrimSpace(value) != ""
|
return strings.TrimSpace(value) != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func MaxChars(value string, n int) bool {
|
func MaxChars(value string, n int) bool {
|
||||||
return utf8.RuneCountInString(value) <= n
|
return utf8.RuneCountInString(value) <= n
|
||||||
}
|
}
|
||||||
|
|
||||||
func PermittedValue[T comparable](value T, permittedValues ...T) bool {
|
func PermittedValue[T comparable](value T, permittedValues ...T) bool {
|
||||||
return slices.Contains(permittedValues, value)
|
return slices.Contains(permittedValues, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MinChars(value string, n int) bool {
|
func MinChars(value string, n int) bool {
|
||||||
return utf8.RuneCountInString(value) >= n
|
return utf8.RuneCountInString(value) >= n
|
||||||
}
|
}
|
||||||
|
|
||||||
func Matches(value string, rx *regexp.Regexp) bool {
|
func Matches(value string, rx *regexp.Regexp) bool {
|
||||||
return rx.MatchString(value)
|
return rx.MatchString(value)
|
||||||
}
|
}
|
||||||
|
1
migrations/000005_normalize_site_urls.down.sql
Normal file
1
migrations/000005_normalize_site_urls.down.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
UPDATE websites SET SiteUrl = substr(SiteUrl, 8) WHERE substr(SiteUrl, 1, 4) = 'http';
|
1
migrations/000005_normalize_site_urls.up.sql
Normal file
1
migrations/000005_normalize_site_urls.up.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
UPDATE websites SET SiteUrl = 'http://' || SiteUrl WHERE substr(SiteUrl, 1, 4) <> 'http';
|
@ -1,6 +1,74 @@
|
|||||||
|
class GuestbookForm extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['guestbook'];
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.attachShadow({ mode: 'open' });
|
||||||
|
this._guestbook = this.getAttribute('guestbook') || '';
|
||||||
|
this._postUrl = `${this._guestbook}/comments/create/remote`
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldValue, newValue) {
|
||||||
|
if (name === 'guestbook') {
|
||||||
|
this._guestbook = newValue;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.shadowRoot.innerHTML = `
|
||||||
|
<style>
|
||||||
|
form div {
|
||||||
|
margin-bottom: 0.75em;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
}
|
||||||
|
input[type="text"], textarea {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
input[type="submit"] {
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<form action="${this._postUrl}" method="post">
|
||||||
|
<div>
|
||||||
|
<label for="authorname">Name</label>
|
||||||
|
<input type="text" name="authorname" id="authorname"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="authoremail">Email (Optional)</label>
|
||||||
|
<input type="text" name="authoremail" id="authoremail"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="authorsite">Site Url (Optional)</label>
|
||||||
|
<input type="text" name="authorsite" id="authorsite"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="content">Comment</label>
|
||||||
|
<textarea name="content" id="content"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="hidden" value="${window.location.pathname}" name="redirect" id="redirect" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="submit" value="Submit"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CommentList extends HTMLElement {
|
class CommentList extends HTMLElement {
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ['src'];
|
return ['guestbook'];
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -12,26 +80,28 @@ class CommentList extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
if (this.hasAttribute('src')) {
|
if (this.hasAttribute('guestbook')) {
|
||||||
this.fetchComments();
|
this.fetchComments();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(name, oldValue, newValue) {
|
attributeChangedCallback(name, oldValue, newValue) {
|
||||||
if (name === 'src' && oldValue !== newValue) {
|
if (name === 'guestbook' && oldValue !== newValue) {
|
||||||
this.fetchComments();
|
this.fetchComments();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchComments() {
|
async fetchComments() {
|
||||||
const src = this.getAttribute('src');
|
const guestbook = this.getAttribute('guestbook');
|
||||||
if (!src) return;
|
if (!guestbook) return;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
this.render();
|
this.render();
|
||||||
|
|
||||||
|
const commentsUrl = `${guestbook}/comments`
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(src);
|
const response = await fetch(commentsUrl);
|
||||||
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
|
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.comments = Array.isArray(data) ? data : [];
|
this.comments = Array.isArray(data) ? data : [];
|
||||||
@ -102,4 +172,6 @@ class CommentList extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('comment-list', CommentList);
|
customElements.define('guestbook-form', GuestbookForm);
|
||||||
|
customElements.define('guestbook-comments', CommentList);
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ templ GuestbookDashboardCommentsView(title string, data CommonData, website mode
|
|||||||
<div id="dashboard">
|
<div id="dashboard">
|
||||||
@wSidebar(website)
|
@wSidebar(website)
|
||||||
<div>
|
<div>
|
||||||
<h1>Comments on { website.SiteUrl }</h1>
|
<h1>Comments on { website.Name }</h1>
|
||||||
<hr/>
|
<hr/>
|
||||||
if len(comments) == 0 {
|
if len(comments) == 0 {
|
||||||
<p>No comments yet!</p>
|
<p>No comments yet!</p>
|
||||||
|
@ -59,9 +59,9 @@ func GuestbookDashboardCommentsView(title string, data CommonData, website model
|
|||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var3 string
|
var templ_7745c5c3_Var3 string
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(website.SiteUrl)
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 13, Col: 37}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 13, Col: 34}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
|
@ -16,7 +16,7 @@ templ wSidebar(website models.Website) {
|
|||||||
<h2>{ website.Name }</h2>
|
<h2>{ website.Name }</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href={ templ.URL(dashUrl) }>Dashboard</a></li>
|
<li><a href={ templ.URL(dashUrl) }>Dashboard</a></li>
|
||||||
<li><a href={ templ.URL(externalUrl(website.SiteUrl)) } target="_blank">View Website</a></li>
|
<li><a href={ templ.URL(externalUrl(website.Url.String())) } target="_blank">View Website</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Guestbook</h3>
|
<h3>Guestbook</h3>
|
||||||
<ul>
|
<ul>
|
||||||
@ -70,7 +70,7 @@ templ websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) {
|
|||||||
if exists {
|
if exists {
|
||||||
<label class="error">{ err }</label>
|
<label class="error">{ err }</label>
|
||||||
}
|
}
|
||||||
<input type="text" name="sitename" id="sitename" required/>
|
<input type="text" name="sitename" id="sitename" value={ form.Name } required/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{{ err, exists = form.FieldErrors["siteurl"] }}
|
{{ err, exists = form.FieldErrors["siteurl"] }}
|
||||||
@ -78,7 +78,7 @@ templ websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) {
|
|||||||
if exists {
|
if exists {
|
||||||
<label class="error">{ err }</label>
|
<label class="error">{ err }</label>
|
||||||
}
|
}
|
||||||
<input type="text" name="siteurl" id="siteurl" required/>
|
<input type="text" name="siteurl" id="siteurl" value={ form.SiteUrl } required/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{{ err, exists = form.FieldErrors["authorname"] }}
|
{{ err, exists = form.FieldErrors["authorname"] }}
|
||||||
@ -86,22 +86,18 @@ templ websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) {
|
|||||||
if exists {
|
if exists {
|
||||||
<label class="error">{ err }</label>
|
<label class="error">{ err }</label>
|
||||||
}
|
}
|
||||||
<input type="text" name="authorname" id="authorname" required/>
|
<input type="text" name="authorname" id="authorname" value={ form.AuthorName } required/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button type="submit">Submit</button>
|
<button type="submit">Submit</button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
templ WebsiteCreateButton() {
|
|
||||||
<button hx-get="/websites/create" hx-target="closest div">Add Website</button>
|
|
||||||
}
|
|
||||||
|
|
||||||
templ WebsiteList(title string, data CommonData, websites []models.Website) {
|
templ WebsiteList(title string, data CommonData, websites []models.Website) {
|
||||||
@base(title, data) {
|
@base(title, data) {
|
||||||
<h1>My Websites</h1>
|
<h1>My Websites</h1>
|
||||||
<div>
|
<div>
|
||||||
@WebsiteCreateButton()
|
<a href="/websites/create">Add Website</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@displayWebsites(websites)
|
@displayWebsites(websites)
|
||||||
@ -116,15 +112,6 @@ templ WebsiteDashboard(title string, data CommonData, website models.Website) {
|
|||||||
<div>
|
<div>
|
||||||
<h1>{ website.Name }</h1>
|
<h1>{ website.Name }</h1>
|
||||||
<h2>Embed your Guestbook</h2>
|
<h2>Embed your Guestbook</h2>
|
||||||
<h3>Comment form</h3>
|
|
||||||
<p>
|
|
||||||
Use this form to allow readers of your website to comment on your guestbook!
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
//<button>Copy to Clipboard</button>
|
|
||||||
@embeddableForm(data.RootUrl, website)
|
|
||||||
</div>
|
|
||||||
<h3>Embed your comments</h3>
|
|
||||||
<p>
|
<p>
|
||||||
Upload <a href="/static/js/guestbook.js" download>this JavaScript WebComponent</a> to your site and include it in your <code>{ `<head>` }</code> tag.
|
Upload <a href="/static/js/guestbook.js" download>this JavaScript WebComponent</a> to your site and include it in your <code>{ `<head>` }</code> tag.
|
||||||
</p>
|
</p>
|
||||||
@ -139,16 +126,26 @@ templ WebsiteDashboard(title string, data CommonData, website models.Website) {
|
|||||||
</code>
|
</code>
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
Then add the custom element where you want the comments to show up
|
Then add the custom elements where you want your form and comments to show up
|
||||||
</p>
|
</p>
|
||||||
{{ getUrl := fmt.Sprintf("https://%s/websites/%s/guestbook/comments", data.RootUrl, shortIdToSlug(website.ShortId)) }}
|
{{ gbUrl := fmt.Sprintf("https://%s/websites/%s/guestbook", data.RootUrl, shortIdToSlug(website.ShortId)) }}
|
||||||
//<button>Copy to Clipboard</button>
|
//<button>Copy to Clipboard</button>
|
||||||
<pre>
|
<pre>
|
||||||
<code>
|
<code>
|
||||||
{ fmt.Sprintf(`<comment-list src="%s"></comment-list>`, getUrl) }
|
{ fmt.Sprintf(`<guestbook-form guestbook="%s"></guestbook-form>
|
||||||
|
<guestbook-comments guestbook="%s"></guestbook-comments>`, gbUrl, gbUrl) }
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
If your web host does not allow CORS requests, use an iframe instead
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
{ fmt.Sprintf(`<iframe src="%s" title="Guestbook"></iframe>`, gbUrl) }
|
||||||
</code>
|
</code>
|
||||||
</pre>
|
</pre>
|
||||||
@embedJavaScriptSnippet(data.RootUrl, website)
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -170,42 +167,9 @@ templ WebsiteDashboardComingSoon(title string, data CommonData, website models.W
|
|||||||
}
|
}
|
||||||
|
|
||||||
templ WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm) {
|
templ WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm) {
|
||||||
<form hx-post="/websites/create" hx-target="closest div">
|
@base(title, data) {
|
||||||
@websiteCreateForm(data.CSRFToken, form)
|
<form action="/websites/create" method="post">
|
||||||
</form>
|
@websiteCreateForm(data.CSRFToken, form)
|
||||||
}
|
</form>
|
||||||
|
}
|
||||||
templ embeddableForm(root string, website models.Website) {
|
|
||||||
{{ postUrl := fmt.Sprintf("https://%s/websites/%s/guestbook/comments/create/remote", root, shortIdToSlug(website.ShortId)) }}
|
|
||||||
{{formStr :=
|
|
||||||
`<form action="%s" method="post">
|
|
||||||
<div>
|
|
||||||
<label for="authorname">Name</label>
|
|
||||||
<input type="text" name="authorname" id="authorname"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="authoremail">Email (Optional) </label>
|
|
||||||
<input type="text" name="authoremail" id="authoremail"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="authorsite">Site Url (Optional) </label>
|
|
||||||
<input type="text" name="authorsite" id="authorsite"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="content">Comment</label>
|
|
||||||
<textarea name="content" id="content"></textarea>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input type="submit" value="Submit"/>
|
|
||||||
</div>
|
|
||||||
</form>`
|
|
||||||
}}
|
|
||||||
<pre>
|
|
||||||
<code>
|
|
||||||
{ fmt.Sprintf(formStr, postUrl) }
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
}
|
|
||||||
|
|
||||||
templ embedJavaScriptSnippet(root string, website models.Website) {
|
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ func wSidebar(website models.Website) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var4 templ.SafeURL = templ.URL(externalUrl(website.SiteUrl))
|
var templ_7745c5c3_Var4 templ.SafeURL = templ.URL(externalUrl(website.Url.String()))
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
@ -271,92 +271,102 @@ func websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) templ.Com
|
|||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<input type=\"text\" name=\"sitename\" id=\"sitename\" required></div><div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<input type=\"text\" name=\"sitename\" id=\"sitename\" value=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var18 string
|
||||||
|
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(form.Name)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 73, Col: 68}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\" required></div><div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
err, exists = form.FieldErrors["siteurl"]
|
err, exists = form.FieldErrors["siteurl"]
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<label for=\"siteurl\">Site URL: </label> ")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<label for=\"siteurl\">Site URL: </label> ")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<label class=\"error\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<label class=\"error\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var18 string
|
|
||||||
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(err)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 79, Col: 29}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</label> ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<input type=\"text\" name=\"siteurl\" id=\"siteurl\" required></div><div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
err, exists = form.FieldErrors["authorname"]
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<label for=\"authorname\">Site Author: </label> ")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if exists {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<label class=\"error\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var19 string
|
var templ_7745c5c3_Var19 string
|
||||||
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(err)
|
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(err)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 87, Col: 29}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 79, Col: 29}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</label> ")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</label> ")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<input type=\"text\" name=\"authorname\" id=\"authorname\" required></div><div><button type=\"submit\">Submit</button></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<input type=\"text\" name=\"siteurl\" id=\"siteurl\" value=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
return nil
|
var templ_7745c5c3_Var20 string
|
||||||
})
|
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(form.SiteUrl)
|
||||||
}
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 81, Col: 69}
|
||||||
func WebsiteCreateButton() templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
|
||||||
if !templ_7745c5c3_IsBuffer {
|
if templ_7745c5c3_Err != nil {
|
||||||
defer func() {
|
return templ_7745c5c3_Err
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\" required></div><div>")
|
||||||
templ_7745c5c3_Var20 := templ.GetChildren(ctx)
|
if templ_7745c5c3_Err != nil {
|
||||||
if templ_7745c5c3_Var20 == nil {
|
return templ_7745c5c3_Err
|
||||||
templ_7745c5c3_Var20 = templ.NopComponent
|
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
err, exists = form.FieldErrors["authorname"]
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<button hx-get=\"/websites/create\" hx-target=\"closest div\">Add Website</button>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<label for=\"authorname\">Site Author: </label> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<label class=\"error\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var21 string
|
||||||
|
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(err)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 87, Col: 29}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</label> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "<input type=\"text\" name=\"authorname\" id=\"authorname\" value=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var22 string
|
||||||
|
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(form.AuthorName)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 89, Col: 78}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "\" required></div><div><button type=\"submit\">Submit</button></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -365,69 +375,6 @@ func WebsiteCreateButton() templ.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WebsiteList(title string, data CommonData, websites []models.Website) templ.Component {
|
func WebsiteList(title string, data CommonData, websites []models.Website) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
||||||
if !templ_7745c5c3_IsBuffer {
|
|
||||||
defer func() {
|
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
ctx = templ.InitializeContext(ctx)
|
|
||||||
templ_7745c5c3_Var21 := templ.GetChildren(ctx)
|
|
||||||
if templ_7745c5c3_Var21 == nil {
|
|
||||||
templ_7745c5c3_Var21 = templ.NopComponent
|
|
||||||
}
|
|
||||||
ctx = templ.ClearChildren(ctx)
|
|
||||||
templ_7745c5c3_Var22 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
||||||
if !templ_7745c5c3_IsBuffer {
|
|
||||||
defer func() {
|
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
ctx = templ.InitializeContext(ctx)
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "<h1>My Websites</h1><div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = WebsiteCreateButton().Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</div><div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = displayWebsites(websites).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var22), templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func WebsiteDashboard(title string, data CommonData, website models.Website) templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -460,7 +407,62 @@ func WebsiteDashboard(title string, data CommonData, website models.Website) tem
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
ctx = templ.InitializeContext(ctx)
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "<div id=\"dashboard\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<h1>My Websites</h1><div><a href=\"/websites/create\">Add Website</a></div><div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = displayWebsites(websites).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var24), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WebsiteDashboard(title string, data CommonData, website models.Website) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var25 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var25 == nil {
|
||||||
|
templ_7745c5c3_Var25 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var26 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<div id=\"dashboard\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -468,37 +470,29 @@ func WebsiteDashboard(title string, data CommonData, website models.Website) tem
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<div><h1>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<div><h1>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var25 string
|
var templ_7745c5c3_Var27 string
|
||||||
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
|
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 117, Col: 22}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 113, Col: 22}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</h1><h2>Embed your Guestbook</h2><h3>Comment form</h3><p>Use this form to allow readers of your website to comment on your guestbook!</p><div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</h1><h2>Embed your Guestbook</h2><p>Upload <a href=\"/static/js/guestbook.js\" download>this JavaScript WebComponent</a> to your site and include it in your <code>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = embeddableForm(data.RootUrl, website).Render(ctx, templ_7745c5c3_Buffer)
|
var templ_7745c5c3_Var28 string
|
||||||
|
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(`<head>`)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 116, Col: 140}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</div><h3>Embed your comments</h3><p>Upload <a href=\"/static/js/guestbook.js\" download>this JavaScript WebComponent</a> to your site and include it in your <code>")
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var26 string
|
|
||||||
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(`<head>`)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 129, Col: 140}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -506,51 +500,57 @@ func WebsiteDashboard(title string, data CommonData, website models.Website) tem
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var27 string
|
var templ_7745c5c3_Var29 string
|
||||||
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(
|
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(
|
||||||
`<head>
|
`<head>
|
||||||
<script type="module" src="js/guestbook.js"></script>
|
<script type="module" src="js/guestbook.js"></script>
|
||||||
</head>`)
|
</head>`)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 138, Col: 8}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 125, Col: 8}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "</code></pre><p>Then add the custom element where you want the comments to show up</p>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "</code></pre><p>Then add the custom elements where you want your form and comments to show up</p>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
getUrl := fmt.Sprintf("https://%s/websites/%s/guestbook/comments", data.RootUrl, shortIdToSlug(website.ShortId))
|
gbUrl := fmt.Sprintf("https://%s/websites/%s/guestbook", data.RootUrl, shortIdToSlug(website.ShortId))
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<pre><code>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<pre><code>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var28 string
|
var templ_7745c5c3_Var30 string
|
||||||
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(`<comment-list src="%s"></comment-list>`, getUrl))
|
templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(`<guestbook-form guestbook="%s"></guestbook-form>
|
||||||
|
<guestbook-comments guestbook="%s"></guestbook-comments>`, gbUrl, gbUrl))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 148, Col: 70}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 136, Col: 72}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "</code></pre>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "</code></pre></div><p>If your web host does not allow CORS requests, use an iframe instead</p><div><pre><code>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = embedJavaScriptSnippet(data.RootUrl, website).Render(ctx, templ_7745c5c3_Buffer)
|
var templ_7745c5c3_Var31 string
|
||||||
|
templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(`<iframe src="%s" title="Guestbook"></iframe>`, gbUrl))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 146, Col: 75}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "</div></div></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "</code></pre></div></div></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var24), templ_7745c5c3_Buffer)
|
templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var26), templ_7745c5c3_Buffer)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -574,12 +574,12 @@ func WebsiteDashboardComingSoon(title string, data CommonData, website models.We
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
ctx = templ.InitializeContext(ctx)
|
||||||
templ_7745c5c3_Var29 := templ.GetChildren(ctx)
|
templ_7745c5c3_Var32 := templ.GetChildren(ctx)
|
||||||
if templ_7745c5c3_Var29 == nil {
|
if templ_7745c5c3_Var32 == nil {
|
||||||
templ_7745c5c3_Var29 = templ.NopComponent
|
templ_7745c5c3_Var32 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
ctx = templ.ClearChildren(ctx)
|
||||||
templ_7745c5c3_Var30 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
templ_7745c5c3_Var33 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
if !templ_7745c5c3_IsBuffer {
|
if !templ_7745c5c3_IsBuffer {
|
||||||
@ -603,12 +603,12 @@ func WebsiteDashboardComingSoon(title string, data CommonData, website models.We
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var31 string
|
var templ_7745c5c3_Var34 string
|
||||||
templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
|
templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 163, Col: 22}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 160, Col: 22}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -618,7 +618,7 @@ func WebsiteDashboardComingSoon(title string, data CommonData, website models.We
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var30), templ_7745c5c3_Buffer)
|
templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var33), templ_7745c5c3_Buffer)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -627,108 +627,6 @@ func WebsiteDashboardComingSoon(title string, data CommonData, website models.We
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm) templ.Component {
|
func WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
||||||
if !templ_7745c5c3_IsBuffer {
|
|
||||||
defer func() {
|
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
ctx = templ.InitializeContext(ctx)
|
|
||||||
templ_7745c5c3_Var32 := templ.GetChildren(ctx)
|
|
||||||
if templ_7745c5c3_Var32 == nil {
|
|
||||||
templ_7745c5c3_Var32 = templ.NopComponent
|
|
||||||
}
|
|
||||||
ctx = templ.ClearChildren(ctx)
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<form hx-post=\"/websites/create\" hx-target=\"closest div\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = websiteCreateForm(data.CSRFToken, form).Render(ctx, templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</form>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func embeddableForm(root string, website models.Website) templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
||||||
if !templ_7745c5c3_IsBuffer {
|
|
||||||
defer func() {
|
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
ctx = templ.InitializeContext(ctx)
|
|
||||||
templ_7745c5c3_Var33 := templ.GetChildren(ctx)
|
|
||||||
if templ_7745c5c3_Var33 == nil {
|
|
||||||
templ_7745c5c3_Var33 = templ.NopComponent
|
|
||||||
}
|
|
||||||
ctx = templ.ClearChildren(ctx)
|
|
||||||
postUrl := fmt.Sprintf("https://%s/websites/%s/guestbook/comments/create/remote", root, shortIdToSlug(website.ShortId))
|
|
||||||
formStr :=
|
|
||||||
`<form action="%s" method="post">
|
|
||||||
<div>
|
|
||||||
<label for="authorname">Name</label>
|
|
||||||
<input type="text" name="authorname" id="authorname"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="authoremail">Email (Optional) </label>
|
|
||||||
<input type="text" name="authoremail" id="authoremail"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="authorsite">Site Url (Optional) </label>
|
|
||||||
<input type="text" name="authorsite" id="authorsite"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="content">Comment</label>
|
|
||||||
<textarea name="content" id="content"></textarea>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input type="submit" value="Submit"/>
|
|
||||||
</div>
|
|
||||||
</form>`
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "<pre><code>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var34 string
|
|
||||||
templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(formStr, postUrl))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 205, Col: 34}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "</code></pre>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func embedJavaScriptSnippet(root string, website models.Website) templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -749,6 +647,36 @@ func embedJavaScriptSnippet(root string, website models.Website) templ.Component
|
|||||||
templ_7745c5c3_Var35 = templ.NopComponent
|
templ_7745c5c3_Var35 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Var36 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<form action=\"/websites/create\" method=\"post\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = websiteCreateForm(data.CSRFToken, form).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</form>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var36), templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user