Skip to content

Commit

Permalink
infinite scroll and swap addition leading into code refactory
Browse files Browse the repository at this point in the history
  • Loading branch information
donseba committed Dec 4, 2024
1 parent 4e5b195 commit c415326
Show file tree
Hide file tree
Showing 10 changed files with 817 additions and 326 deletions.
117 changes: 117 additions & 0 deletions examples/infinitescroll/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package main

import (
"context"
"fmt"
"log/slog"
"net/http"
"path/filepath"
"strconv"

"github.com/donseba/go-partial"
"github.com/donseba/go-partial/connector"
)

type (
App struct {
PartialService *partial.Service
}
)

func main() {
logger := slog.Default()

app := &App{
PartialService: partial.NewService(&partial.Config{
Logger: logger,
Connector: connector.NewPartial(&connector.Config{
UseURLQuery: true,
}),
}),
}

mux := http.NewServeMux()

mux.Handle("GET /js/", http.StripPrefix("/js/", http.FileServer(http.Dir("../../js"))))

mux.HandleFunc("GET /", app.home)

server := &http.Server{
Addr: ":8080",
Handler: mux,
}

logger.Info("starting server on :8080")
err := server.ListenAndServe()
if err != nil {
logger.Error("error starting server", "error", err)
}
}

// super simple example of how to use the partial service to render a layout with a content partial
func (a *App) home(w http.ResponseWriter, r *http.Request) {
// layout, footer, index could be abstracted away and shared over multiple handlers within the same module, for instance.
layout := a.PartialService.NewLayout()
footer := partial.NewID("footer", filepath.Join("templates", "footer.gohtml"))
index := partial.NewID("index", filepath.Join("templates", "index.gohtml")).WithOOB(footer)

content := partial.NewID("content", filepath.Join("templates", "content.gohtml")).WithAction(func(ctx context.Context, p *partial.Partial, data *partial.Data) (*partial.Partial, error) {
switch p.GetRequestedAction() {
case "infinite-scroll":
return handleInfiniteScroll(p, data)
default:
return p, nil
}
})

// set the layout content and wrap it with the main template
layout.Set(content).Wrap(index)

err := layout.WriteWithRequest(r.Context(), w, r)
if err != nil {
http.Error(w, fmt.Errorf("error rendering layout: %w", err).Error(), http.StatusInternalServerError)
}
}

type (
Row struct {
ID int
Name string
Desc string
}
)

func handleInfiniteScroll(p *partial.Partial, data *partial.Data) (*partial.Partial, error) {
startID := 0
if p.GetRequest().URL.Query().Get("ID") != "" {
startID, _ = strconv.Atoi(p.GetRequest().URL.Query().Get("ID"))
}

if startID >= 100 {
p.SetResponseHeaders(map[string]string{
"X-Swap": "innerHTML",
"X-Infinite-Scroll": "stop",
})
p = partial.NewID("rickrolled", filepath.Join("templates", "rickrolled.gohtml"))
} else {
data.Data["Rows"] = generateNextRows(startID, 10)
}

return p, nil
}

func generateNextRows(lastID int, count int) []Row {
var out []Row
start := lastID + 1
end := lastID + count

for i := start; i <= end; i++ {
out = append(out, Row{
ID: i,
Name: fmt.Sprintf("Name %d", i),
Desc: fmt.Sprintf("Description %d", i),
})
}

return out
}
18 changes: 18 additions & 0 deletions examples/infinitescroll/templates/content.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{ with .Data.rickrolled }}
{{ . }}
{{ else }}
{{ range $k, $v := .Data.Rows }}
<div class="row" x-params='{"ID": {{ $v.ID }}}'>
<div class="col-sm">
{{ $v.ID }}
</div>
<div class="col-sm">
{{ $v.Name }}
</div>
<div class="col-sm">
{{ $v.Desc }}
</div>
</div>
{{ end}}
{{ end }}

1 change: 1 addition & 0 deletions examples/infinitescroll/templates/footer.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div id="footer" {{ if swapOOB }}x-swap-oob="outerHTML"{{end}} class="container">footer time : {{ formatDate now "15:04:05" }} - {{ if swapOOB }}swapped with OOB{{else}}rendered on load{{end}}</div>
52 changes: 52 additions & 0 deletions examples/infinitescroll/templates/index.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Infinite Scroll</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<script type="application/javascript" src="/js/partial.js"></script>
</head>

<body>


<div class="mt-3 container">
<div>(rendered on load at : {{ formatDate now "15:04:05" }})</div>
<div class="mt-3">What the handler looks like: </div>

<pre class="mt-3 p-1" style="background-color: gray"><small>func (a *App) home(w http.ResponseWriter, r *http.Request) {
// layout, footer, index could be abstracted away and shared over multiple handlers within the same module, for instance.
layout := a.PartialService.NewLayout()
footer := partial.NewID("footer", filepath.Join("templates", "footer.gohtml"))
index := partial.NewID("index", filepath.Join("templates", "index.gohtml")).WithOOB(footer)

content := partial.NewID("content", filepath.Join("templates", "content.gohtml")).WithAction(func(ctx context.Context, p *partial.Partial, data *partial.Data) (*partial.Partial, error) {
switch p.GetRequestedAction() {
case "infinite-scroll":
return handleInfiniteScroll(p, data)
default:
return p, nil
}
})

// set the layout content and wrap it with the main template
layout.Set(content).Wrap(index)

err := layout.WriteWithRequest(r.Context(), w, r)
if err != nil {
http.Error(w, fmt.Errorf("error rendering layout: %w", err).Error(), http.StatusInternalServerError)
}
}</small></pre>
</div>

{{ child "footer" }}

<div class="mt-3 container" id="content" x-infinite-scroll="true" x-get="/" x-swap="beforeend">
{{ child "content" }}
</div>

<script>
// Initialize the handler with optional configuration
const partial = new Partial();
</script>
</body>
</html>
5 changes: 5 additions & 0 deletions examples/infinitescroll/templates/rickrolled.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div>
<h1>Don’t scroll too far, there are consequences</h1>
<div>That's enough scrolling for you today.</div>
<iframe id="rick" width="560" height="315" src="https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=1" allow='autoplay'></iframe>
</div>
8 changes: 4 additions & 4 deletions examples/tabs/templates/content.gohtml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<div class="container mt-5">
<!-- Tab Navigation -->
<ul class="nav nav-tabs" role="tablist">
<ul class="nav nav-tabs" role="tablist" x-target="#content" x-swap="innerHTML" >
<li class="nav-item">
<span class="nav-link {{ ifRequestedSelect "active" "tab1" ""}}" style="cursor:pointer;" x-get="/" x-target="#content" x-select="tab1">Tab 1</span>
<span class="nav-link {{ ifRequestedSelect "active" "tab1" ""}}" style="cursor:pointer;" x-get="/" x-select="tab1">Tab 1</span>
</li>
<li class="nav-item">
<span class="nav-link {{ ifRequestedSelect "active" "tab2"}}" style="cursor:pointer;" x-get="/" x-target="#content" x-select="tab2">Tab 2</span>
<span class="nav-link {{ ifRequestedSelect "active" "tab2"}}" style="cursor:pointer;" x-get="/" x-select="tab2" >Tab 2</span>
</li>
<li class="nav-item">
<span class="nav-link {{ ifRequestedSelect "active" "tab3"}}" style="cursor:pointer;" x-get="/" x-target="#content" x-select="tab3" x-debounce="1000">Tab 3 (debounce 1000ms)</span>
<span class="nav-link {{ ifRequestedSelect "active" "tab3"}}" style="cursor:pointer;" x-get="/" x-select="tab3" x-debounce="1000" x-loading-class="bg-warning" >Tab 3 (debounce 1000ms)</span>
</li>
</ul>

Expand Down
Loading

0 comments on commit c415326

Please sign in to comment.