diff options
-rw-r--r-- | assets/js/list.js | 8 | ||||
-rw-r--r-- | frontend/renderer.go | 15 | ||||
-rw-r--r-- | modules/lists/lists.go | 44 | ||||
-rw-r--r-- | views/list.html | 39 | ||||
-rw-r--r-- | views/list_gril.html | 38 |
5 files changed, 104 insertions, 40 deletions
diff --git a/assets/js/list.js b/assets/js/list.js index 3a58971..25ff80d 100644 --- a/assets/js/list.js +++ b/assets/js/list.js | |||
@@ -2,7 +2,13 @@ function clickSearchResult(resId) { | |||
2 | var xhr = new XMLHttpRequest(); | 2 | var xhr = new XMLHttpRequest(); |
3 | xhr.onreadystatechange = function() { | 3 | xhr.onreadystatechange = function() { |
4 | if (xhr.readyState == XMLHttpRequest.DONE) { | 4 | if (xhr.readyState == XMLHttpRequest.DONE) { |
5 | alert(xhr.status + ": " + xhr.response); | 5 | if (xhr.status !== 200) { |
6 | alert(xhr.status + ": " + xhr.response); | ||
7 | return; | ||
8 | } | ||
9 | |||
10 | data = xhr.responseText; | ||
11 | document.getElementById("gril-list").innerHTML += data; | ||
6 | } | 12 | } |
7 | } | 13 | } |
8 | xhr.open('POST', window.location, true); | 14 | xhr.open('POST', window.location, true); |
diff --git a/frontend/renderer.go b/frontend/renderer.go index 524c2c8..f311462 100644 --- a/frontend/renderer.go +++ b/frontend/renderer.go | |||
@@ -26,6 +26,12 @@ type Renderer struct { | |||
26 | defaultData map[string]interface{} | 26 | defaultData map[string]interface{} |
27 | } | 27 | } |
28 | 28 | ||
29 | // RangePair für Range-Dingens. Damit man die ID weiterhin accessen kann. | ||
30 | type RangePair struct { | ||
31 | Index int | ||
32 | Value interface{} | ||
33 | } | ||
34 | |||
29 | // DefaultData gibt die Standard-Daten für die Views zurück. Das ist immer eine Kopie weil Reasons. | 35 | // DefaultData gibt die Standard-Daten für die Views zurück. Das ist immer eine Kopie weil Reasons. |
30 | func (r *Renderer) DefaultData() map[string]interface{} { | 36 | func (r *Renderer) DefaultData() map[string]interface{} { |
31 | d := make(map[string]interface{}) | 37 | d := make(map[string]interface{}) |
@@ -53,6 +59,15 @@ func New(path string) *Renderer { | |||
53 | "sub": func(a, b int) int { | 59 | "sub": func(a, b int) int { |
54 | return a - b | 60 | return a - b |
55 | }, | 61 | }, |
62 | "makeRangePair": func(idx int, value interface{}) RangePair { | ||
63 | return RangePair{idx, value} | ||
64 | }, | ||
65 | "makeObject": func(name string, existing interface{}, newKey string, newData interface{}) map[string]interface{} { | ||
66 | d := make(map[string]interface{}) | ||
67 | d[name] = existing | ||
68 | d[newKey] = newData | ||
69 | return d | ||
70 | }, | ||
56 | } | 71 | } |
57 | 72 | ||
58 | r := &Renderer{ | 73 | r := &Renderer{ |
diff --git a/modules/lists/lists.go b/modules/lists/lists.go index 8957c5f..85e6ce5 100644 --- a/modules/lists/lists.go +++ b/modules/lists/lists.go | |||
@@ -15,6 +15,7 @@ import ( | |||
15 | "net/http" | 15 | "net/http" |
16 | "net/url" | 16 | "net/url" |
17 | "strconv" | 17 | "strconv" |
18 | "sort" | ||
18 | ) | 19 | ) |
19 | 20 | ||
20 | // Module und so. | 21 | // Module und so. |
@@ -40,6 +41,12 @@ type ListGril struct { | |||
40 | Order int | 41 | Order int |
41 | } | 42 | } |
42 | 43 | ||
44 | // ListGrils ist die Sort-Interface Implementation für Grils einer Liste. | ||
45 | type ListGrils []*ListGril | ||
46 | func (l ListGrils) Len() int { return len(l) } | ||
47 | func (l ListGrils) Swap(i, j int) { l[i], l[j] = l[j], l[i] } | ||
48 | func (l ListGrils) Less(i, j int) bool { return l[i].Order < l[j].Order } | ||
49 | |||
43 | // Name gibt den Namen des Moduls zurück | 50 | // Name gibt den Namen des Moduls zurück |
44 | func (m *Module) Name() string { | 51 | func (m *Module) Name() string { |
45 | return "Lists" | 52 | return "Lists" |
@@ -90,6 +97,7 @@ func (m *Module) getListGrils(list *List) error { | |||
90 | 97 | ||
91 | list.Grils = append(list.Grils, lg) | 98 | list.Grils = append(list.Grils, lg) |
92 | } | 99 | } |
100 | sort.Sort(ListGrils(list.Grils)) | ||
93 | return nil | 101 | return nil |
94 | } | 102 | } |
95 | 103 | ||
@@ -258,8 +266,40 @@ func (m *Module) addGrilToList(w http.ResponseWriter, r *http.Request, p httprou | |||
258 | return | 266 | return |
259 | } | 267 | } |
260 | 268 | ||
261 | log.Println("implement: add gril", grilID, "to list", listID) | 269 | list, err := m.FromID(listID) |
262 | http.Error(w, "not implemented", 500) | 270 | if err != nil { |
271 | http.Error(w, "invalid list", 404) | ||
272 | return | ||
273 | } | ||
274 | |||
275 | rank := 0 | ||
276 | if len(list.Grils) > 0 { | ||
277 | rank = list.Grils[len(list.Grils) - 1].Order + 1 | ||
278 | } | ||
279 | |||
280 | // rein in die DB damit | ||
281 | _, err = m.g.DB.Query(`INSERT INTO grilist.lists_grils(list_id, gril_id, "order") VALUES($1, $2, $3)`, listID, grilID, rank) | ||
282 | if err != nil { | ||
283 | log.Println("error inserting gril into list:", err) | ||
284 | http.Error(w, "could not insert gril", 500) | ||
285 | return | ||
286 | } | ||
287 | |||
288 | gril, err := m.grils.FromID(grilID) | ||
289 | if err != nil { | ||
290 | log.Println("inserted gril into list but couldnt get gril afterwards:", err) | ||
291 | http.Error(w, "error after insert", 500) | ||
292 | return | ||
293 | } | ||
294 | |||
295 | data := m.g.Renderer.DefaultData() | ||
296 | data["Index"] = len(list.Grils) | ||
297 | value := make(map[string]interface{}) | ||
298 | value["IsListOwner"] = true | ||
299 | value["Gril"] = ListGril{ gril, rank } | ||
300 | data["Value"] = value | ||
301 | m.g.Renderer.RenderPage("list_gril", w, data) | ||
302 | return | ||
263 | } | 303 | } |
264 | 304 | ||
265 | func (m *Module) displayCreateList(w http.ResponseWriter, r *http.Request, p httprouter.Params) { | 305 | func (m *Module) displayCreateList(w http.ResponseWriter, r *http.Request, p httprouter.Params) { |
diff --git a/views/list.html b/views/list.html index fa58f91..b9ef7c8 100644 --- a/views/list.html +++ b/views/list.html | |||
@@ -18,44 +18,9 @@ | |||
18 | <blockquote>{{ $list.Description }}</blockquote><br /> | 18 | <blockquote>{{ $list.Description }}</blockquote><br /> |
19 | <div class="row"> | 19 | <div class="row"> |
20 | <div class="col s12 {{ if ($user) and eq $user.ID $list.Owner.ID }}l8{{ end }}"> | 20 | <div class="col s12 {{ if ($user) and eq $user.ID $list.Owner.ID }}l8{{ end }}"> |
21 | <ul class="gril-list"> | 21 | <ul id="gril-list" class="gril-list"> |
22 | {{ range $index, $lg := $list.Grils }} | 22 | {{ range $index, $lg := $list.Grils }} |
23 | <li id="{{ $index }}"> | 23 | {{ template "list_gril" makeRangePair $index (makeObject "Gril" $lg "IsListOwner" (and ($user) (eq $user.ID $list.Owner.ID) )) }} |
24 | <div class="card-panel hoverable list-entry"> | ||
25 | <div class="row valign-wrapper"> | ||
26 | <div class="col s3 m2"> | ||
27 | <div class="circle gril-img" style="background-image: url(/{{ $lg.Gril.ImagePath true }})"> </div> | ||
28 | </div> | ||
29 | <div class="col s6 m6"> | ||
30 | <span><a href="/gril/{{ $lg.Gril.Slug }}">{{ $lg.Gril.RomajiName }}</a><br /> | ||
31 | <span class="jap-name">{{ $lg.Gril.KanjiName }}</span> | ||
32 | </span> | ||
33 | </div> | ||
34 | {{ if ($user) and eq $user.ID $list.Owner.ID }} | ||
35 | <div class="col s3 m5"> | ||
36 | <div class="hide-on-med-and-up"> | ||
37 | <div class="row list-controls valign-wrapper"> | ||
38 | <div class="col s6 left-align"> | ||
39 | <i class="material-icons grey-text" onClick="">keyboard_arrow_up</i> | ||
40 | <i class="material-icons grey-text" onClick="">keyboard_arrow_down</i> | ||
41 | </div> | ||
42 | <div class="col s4 left-align"> | ||
43 | <i class="hide-on-med-and-up material-icons delete-icon grey-text" onClick="">delete</i> | ||
44 | </div> | ||
45 | </div> | ||
46 | </div> | ||
47 | <div class="hide-on-small-only"> | ||
48 | <div class="valign-wrapper"> | ||
49 | <i class="medium material-icons grey-text" onClick="">keyboard_arrow_up</i> | ||
50 | <i class="medium material-icons grey-text" onClick="">keyboard_arrow_down</i> | ||
51 | <i class="material-icons grey-text" onClick="">delete</i> | ||
52 | </div> | ||
53 | </div> | ||
54 | </div> | ||
55 | {{ end }} | ||
56 | </div> | ||
57 | </div> | ||
58 | </li> | ||
59 | {{ end }} | 24 | {{ end }} |
60 | </ul> | 25 | </ul> |
61 | </div> | 26 | </div> |
diff --git a/views/list_gril.html b/views/list_gril.html new file mode 100644 index 0000000..5cfd0df --- /dev/null +++ b/views/list_gril.html | |||
@@ -0,0 +1,38 @@ | |||
1 | {{ define "list_gril" }} | ||
2 | <li id="{{ .Index }}"> | ||
3 | <div class="card-panel hoverable list-entry"> | ||
4 | <div class="row valign-wrapper"> | ||
5 | <div class="col s3 m2"> | ||
6 | <div class="circle gril-img" style="background-image: url(/{{ .Value.Gril.Gril.ImagePath true }})"> </div> | ||
7 | </div> | ||
8 | <div class="col s6 m6"> | ||
9 | <span><a href="/gril/{{ .Value.Gril.Gril.Slug }}">{{ .Value.Gril.Gril.RomajiName }}</a><br /> | ||
10 | <span class="jap-name">{{ .Value.Gril.Gril.KanjiName }}</span> | ||
11 | </span> | ||
12 | </div> | ||
13 | {{ if (.Value.IsListOwner) }} | ||
14 | <div class="col s3 m5"> | ||
15 | <div class="hide-on-med-and-up"> | ||
16 | <div class="row list-controls valign-wrapper"> | ||
17 | <div class="col s6 left-align"> | ||
18 | <i class="material-icons grey-text" onClick="">keyboard_arrow_up</i> | ||
19 | <i class="material-icons grey-text" onClick="">keyboard_arrow_down</i> | ||
20 | </div> | ||
21 | <div class="col s4 left-align"> | ||
22 | <i class="hide-on-med-and-up material-icons delete-icon grey-text" onClick="">delete</i> | ||
23 | </div> | ||
24 | </div> | ||
25 | </div> | ||
26 | <div class="hide-on-small-only"> | ||
27 | <div class="valign-wrapper"> | ||
28 | <i class="medium material-icons grey-text" onClick="">keyboard_arrow_up</i> | ||
29 | <i class="medium material-icons grey-text" onClick="">keyboard_arrow_down</i> | ||
30 | <i class="material-icons grey-text" onClick="">delete</i> | ||
31 | </div> | ||
32 | </div> | ||
33 | </div> | ||
34 | {{ end }} | ||
35 | </div> | ||
36 | </div> | ||
37 | </li> | ||
38 | {{ end }} \ No newline at end of file | ||