diff options
author | jan <jan@ruken.pw> | 2016-01-16 18:39:21 (UTC) |
---|---|---|
committer | jan <jan@ruken.pw> | 2016-01-16 18:39:21 (UTC) |
commit | b16c4ef8e1ef3458f186139172362a511f925043 (patch) | |
tree | b965638fccbbddee16206c88ba61b76a9656cefc | |
parent | 928ab739e2b4b40077610a7913adb0cf086f2ee1 (diff) |
grils können nun zu listen hinzugefügt werden, da lukas zu faul war. javascript wird vorausgesetzt. grils werden direkt hinzugefügt beim klicken ohne ladezeit. musste dafür ein paar hacks im templating verwenden, da ein gewisser jemand kein frontend framework verwenden will.
-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 | ||