aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets_src/js/lib/dom.js10
-rw-r--r--assets_src/js/like.js22
-rw-r--r--frontend/renderer.go9
-rw-r--r--main.go2
-rw-r--r--models/like.go14
-rw-r--r--modules/likes/likes.go70
-rw-r--r--views/includes/js.html3
-rw-r--r--views/includes/like.html3
-rw-r--r--views/pages/list.html2
9 files changed, 135 insertions, 0 deletions
diff --git a/assets_src/js/lib/dom.js b/assets_src/js/lib/dom.js
index bfbeea7..3c2f4d9 100644
--- a/assets_src/js/lib/dom.js
+++ b/assets_src/js/lib/dom.js
@@ -17,6 +17,16 @@ export function closest(el, fn) {
17 return null; 17 return null;
18} 18}
19 19
20export function withClass(className) {
21 const els = document.getElementsByClassName(className);
22 const arr = [];
23
24 for (let i = 0; i < els.length; i++) {
25 arr.push(els.item(i));
26 }
27 return arr;
28}
29
20export function next(el, fn) { 30export function next(el, fn) {
21 if (!el) { 31 if (!el) {
22 return null; 32 return null;
diff --git a/assets_src/js/like.js b/assets_src/js/like.js
new file mode 100644
index 0000000..03b15a1
--- /dev/null
+++ b/assets_src/js/like.js
@@ -0,0 +1,22 @@
1import * as ajax from './lib/ajax';
2import * as dom from './lib/dom';
3
4async function updateLikeCount(el) {
5 const type = parseInt(el.getAttribute('content-type'), 10);
6 const contentId = parseInt(el.getAttribute('content-id'), 10);
7
8 if (isNaN(type) || isNaN(contentId)) {
9 return;
10 }
11
12 const count = await ajax.get(`/api/likes/count?id=${contentId}&type=${type}`, {});
13
14 el.textContent = count;
15}
16
17dom.ready(() => {
18 dom.withClass('like-count')
19 .forEach(el => {
20 updateLikeCount(el);
21 });
22});
diff --git a/frontend/renderer.go b/frontend/renderer.go
index d529dff..9c1f7a7 100644
--- a/frontend/renderer.go
+++ b/frontend/renderer.go
@@ -65,6 +65,15 @@ func New(path string, functions map[string]interface{}) *Renderer {
65 "makeRangePair": func(idx int, value interface{}) RangePair { 65 "makeRangePair": func(idx int, value interface{}) RangePair {
66 return RangePair{idx, value} 66 return RangePair{idx, value}
67 }, 67 },
68 "map": func(values ...interface{}) map[string]interface{} {
69 m := make(map[string]interface{}, len(values)/2)
70 for i := 0; i < len(values); i += 2 {
71 key, _ := values[i].(string)
72 m[key] = values[i+1]
73 }
74
75 return m
76 },
68 "makeObject": func(name string, existing interface{}, newKey string, newData interface{}) map[string]interface{} { 77 "makeObject": func(name string, existing interface{}, newKey string, newData interface{}) map[string]interface{} {
69 d := make(map[string]interface{}) 78 d := make(map[string]interface{})
70 d[name] = existing 79 d[name] = existing
diff --git a/main.go b/main.go
index dd00a9b..02ef9e7 100644
--- a/main.go
+++ b/main.go
@@ -12,6 +12,7 @@ import (
12 "fagott.pw/grilist/frontend" 12 "fagott.pw/grilist/frontend"
13 "fagott.pw/grilist/grilist" 13 "fagott.pw/grilist/grilist"
14 "fagott.pw/grilist/modules/grils" 14 "fagott.pw/grilist/modules/grils"
15 "fagott.pw/grilist/modules/likes"
15 "fagott.pw/grilist/modules/lists" 16 "fagott.pw/grilist/modules/lists"
16 "fagott.pw/grilist/modules/search" 17 "fagott.pw/grilist/modules/search"
17 "fagott.pw/grilist/modules/series" 18 "fagott.pw/grilist/modules/series"
@@ -106,6 +107,7 @@ func main() {
106 loadModule(search.New()) 107 loadModule(search.New())
107 loadModule(user.New()) 108 loadModule(user.New())
108 loadModule(series.New()) 109 loadModule(series.New())
110 loadModule(likes.New())
109 router.GET("/dashboard", viewDashboard) 111 router.GET("/dashboard", viewDashboard)
110 112
111 log.Fatal(http.ListenAndServe(":8080", nil)) 113 log.Fatal(http.ListenAndServe(":8080", nil))
diff --git a/models/like.go b/models/like.go
new file mode 100644
index 0000000..2faf384
--- /dev/null
+++ b/models/like.go
@@ -0,0 +1,14 @@
1package models
2
3import "fagott.pw/charakterin"
4
5const (
6 LIKE_LIST = 0
7)
8
9type Like struct {
10 ContentID int
11 Content interface{}
12 User *charakterin.User
13 ContentType int
14}
diff --git a/modules/likes/likes.go b/modules/likes/likes.go
new file mode 100644
index 0000000..949cba2
--- /dev/null
+++ b/modules/likes/likes.go
@@ -0,0 +1,70 @@
1package likes
2
3import (
4 "fmt"
5 "log"
6 "net/http"
7 "strconv"
8
9 "fagott.pw/charakterin"
10 "fagott.pw/grilist/grilist"
11 "fagott.pw/grilist/modules/lists"
12
13 "github.com/julienschmidt/httprouter"
14)
15
16type Module struct {
17 g *grilist.Grilist
18 lists *lists.Module
19}
20
21func New() *Module {
22 return &Module{}
23}
24
25func (m *Module) Name() string {
26 return "Likes"
27}
28
29func (m *Module) Init(g *grilist.Grilist) {
30 m.g = g
31 gm, ok := g.Modules["Lists"]
32 if !ok {
33 log.Fatal("tags: lists module not found")
34 }
35 m.lists = gm.(*lists.Module)
36 m.g.Router.GET("/api/likes/count", m.getLikeCount)
37}
38
39func (m *Module) Interface() interface{} {
40 return m
41}
42
43func (m *Module) ProvideDashboardData(user *charakterin.User) []grilist.DashboardCategory {
44 return make([]grilist.DashboardCategory, 0)
45}
46
47func (m *Module) getLikeCount(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
48 params := r.URL.Query()
49
50 contentId, err := strconv.Atoi(params.Get("id"))
51 if err != nil {
52 http.Error(w, "invalid content id", http.StatusBadRequest)
53 return
54 }
55 contentType, err := strconv.Atoi(params.Get("type"))
56 if err != nil {
57 http.Error(w, "invalid content id", http.StatusBadRequest)
58 return
59 }
60
61 var res int
62 if err := m.g.DB.QueryRow(`SELECT COUNT(*) FROM grilist.likes WHERE content = $1 AND type = $2`, contentId, contentType).Scan(&res); err != nil {
63 http.Error(w, "pq error", http.StatusInternalServerError)
64 log.Printf("error getting like count: %s", err)
65 return
66 }
67
68 w.WriteHeader(200)
69 w.Write([]byte(fmt.Sprintf("%d", res)))
70}
diff --git a/views/includes/js.html b/views/includes/js.html
new file mode 100644
index 0000000..784c3b6
--- /dev/null
+++ b/views/includes/js.html
@@ -0,0 +1,3 @@
1{{ define "js" }}
2<script src="/assets/js/{{ . }}.js"></script>
3{{ end }}
diff --git a/views/includes/like.html b/views/includes/like.html
new file mode 100644
index 0000000..226aaff
--- /dev/null
+++ b/views/includes/like.html
@@ -0,0 +1,3 @@
1{{ define "like" }}
2<span class="like-count" content-type={{ .ContentType }} content-id={{ .ContentID }}></span> Likes
3{{ end }}
diff --git a/views/pages/list.html b/views/pages/list.html
index f3c652b..f884a63 100644
--- a/views/pages/list.html
+++ b/views/pages/list.html
@@ -4,6 +4,7 @@
4<html> 4<html>
5 <head> 5 <head>
6 {{ template "materialize" }} 6 {{ template "materialize" }}
7 {{ template "js" "like" }}
7 <title>grilist</title> 8 <title>grilist</title>
8 <link rel="stylesheet" href="/assets/css/list.css" /> 9 <link rel="stylesheet" href="/assets/css/list.css" />
9 <link rel="stylesheet" href="/assets/css/search.css" /> 10 <link rel="stylesheet" href="/assets/css/search.css" />
@@ -24,6 +25,7 @@
24 </div> 25 </div>
25 </div>{{ end }} 26 </div>{{ end }}
26 <blockquote>{{ $list.Description }}</blockquote><br /> 27 <blockquote>{{ $list.Description }}</blockquote><br />
28 {{ template "like" (map "ContentType" 0 "ContentID" $list.ID) }}
27 <div class="row"> 29 <div class="row">
28 <div class="col s12 {{ if ($user) and eq $user.ID $list.Owner.ID }}l8{{ end }}"> 30 <div class="col s12 {{ if ($user) and eq $user.ID $list.Owner.ID }}l8{{ end }}">
29 <ul id="gril-list" class="gril-list"> 31 <ul id="gril-list" class="gril-list">