liquid_feedback_frontend

view app/main/initiative/_suggestions.lua @ 1491:4badb51649f7

Suggestion opinion defaults to neutral
author bsw
date Mon Aug 26 15:27:05 2019 +0200 (2019-08-26)
parents 32cc544d5a5b
children 4188405c2425
line source
1 local initiative = param.get("initiative", "table")
2 local direct_supporter
3 if app.session.member_id then
4 direct_supporter = initiative.issue.member_info.own_participation and initiative.member_info.supported
5 end
8 ui.link { attr = { name = "suggestions" }, text = "" }
11 ui.container {
12 attr = { class = "section suggestions" },
13 content = function ()
15 if # ( initiative.suggestions ) > 0 then
17 ui.heading {
18 level = 1,
19 content = _("Suggestions for improvement (#{count})", { count = # ( initiative.suggestions ) } )
20 }
21 ui.container { content = _"written and rated by the supportes of this initiative to improve the proposal and its reasons" }
22 slot.put("<br />")
24 for i, suggestion in ipairs(initiative.suggestions) do
26 local opinion = Opinion:by_pk(app.session.member_id, suggestion.id)
28 local class = "mdl-card mdl-card__fullwidth mdl-shadow--2dp not-folded"
29 if suggestion.id == param.get("suggestion_id", atom.number) then
30 class = class .. " highlighted"
31 end
32 if member and not initiative.issue.fully_frozen and not initiative.issue.closed and initiative.member_info.supported then
33 class = class .. " rateable"
34 end
36 ui.link { attr = { name = "s" .. suggestion.id }, text = "" }
37 ui.tag { tag = "div", attr = { class = class, id = "s" .. suggestion.id }, content = function ()
38 ui.tag{ attr = { class = "mdl-card__title mdl-card--border" }, content = function()
39 ui.heading { level = 2,
40 attr = { class = "mdl-card__title-text" },
41 content = format.string(suggestion.name, {
42 truncate_at = 160, truncate_suffix = true
43 }) }
45 if opinion then
47 ui.container { attr = { class = "mdl-card__content"}, content = function()
48 local class = ""
49 local text = ""
51 if opinion.degree == 2 then
52 class = "must"
53 text = _"must"
54 elseif opinion.degree == 1 then
55 class = "should"
56 text = _"should"
57 elseif opinion.degree == 0 then
58 class = "neutral"
59 text = _"neutral"
60 elseif opinion.degree == -1 then
61 class = "shouldnot"
62 text = _"should not"
63 elseif opinion.degree == -2 then
64 class = "mustnot"
65 text = _"must not"
66 end
68 ui.tag {
69 attr = { class = class },
70 content = text
71 }
73 slot.put ( " " )
75 if
76 (opinion.degree > 0 and not opinion.fulfilled)
77 or (opinion.degree < 0 and opinion.fulfilled)
78 then
79 ui.tag{ content = _"but" }
80 else
81 ui.tag{ content = _"and" }
82 end
84 slot.put ( " " )
86 local class = ""
87 local text = ""
89 if opinion.fulfilled then
90 class = "implemented"
91 text = _"is implemented"
92 else
93 class = "notimplemented"
94 text = _"is not implemented"
95 end
97 ui.tag {
98 attr = { class = class },
99 content = text
100 }
102 if
103 (opinion.degree > 0 and not opinion.fulfilled)
104 or (opinion.degree < 0 and opinion.fulfilled)
105 then
106 if math.abs(opinion.degree) > 1 then
107 slot.put(" !!")
108 else
109 slot.put(" !")
110 end
111 else
112 slot.put(" ✓")
113 end
115 end }
117 end
119 end }
121 ui.container{ attr = { class = "suggestion-content" }, content = function()
123 local plus2 = (suggestion.plus2_unfulfilled_count or 0)
124 + (suggestion.plus2_fulfilled_count or 0)
125 local plus1 = (suggestion.plus1_unfulfilled_count or 0)
126 + (suggestion.plus1_fulfilled_count or 0)
127 local minus1 = (suggestion.minus1_unfulfilled_count or 0)
128 + (suggestion.minus1_fulfilled_count or 0)
129 local minus2 = (suggestion.minus2_unfulfilled_count or 0)
130 + (suggestion.minus2_fulfilled_count or 0)
132 local with_opinion = plus2 + plus1 + minus1 + minus2
134 local neutral = (suggestion.initiative.supporter_count or 0)
135 - with_opinion
137 local neutral2 = with_opinion
138 - (suggestion.plus2_fulfilled_count or 0)
139 - (suggestion.plus1_fulfilled_count or 0)
140 - (suggestion.minus1_fulfilled_count or 0)
141 - (suggestion.minus2_fulfilled_count or 0)
143 ui.container {
144 attr = { class = "mdl-card__content mdl-card--border suggestionInfo" },
145 content = function ()
147 if app.session:has_access("authors_pseudonymous") then
148 util.micro_avatar ( suggestion.author )
149 end
151 if with_opinion > 0 then
152 ui.container { attr = { class = "suggestion-rating" }, content = function ()
153 ui.tag { content = _"collective rating:" }
154 slot.put("&nbsp;")
155 ui.bargraph{
156 max_value = suggestion.initiative.supporter_count,
157 width = 100,
158 bars = {
159 { color = "#0a0", value = plus2 },
160 { color = "#8a8", value = plus1 },
161 { color = "#eee", value = neutral },
162 { color = "#a88", value = minus1 },
163 { color = "#a00", value = minus2 },
164 }
165 }
166 slot.put(" | ")
167 ui.tag { content = _"implemented:" }
168 slot.put ( "&nbsp;" )
169 ui.bargraph{
170 max_value = with_opinion,
171 width = 100,
172 bars = {
173 { color = "#0a0", value = suggestion.plus2_fulfilled_count },
174 { color = "#8a8", value = suggestion.plus1_fulfilled_count },
175 { color = "#eee", value = neutral2 },
176 { color = "#a88", value = suggestion.minus1_fulfilled_count },
177 { color = "#a00", value = suggestion.minus2_fulfilled_count },
178 }
179 }
180 end }
181 end
183 end
184 }
186 ui.container {
187 attr = { class = "mdl-card__content mdl-card--border suggestion-text draft" },
188 content = function ()
189 slot.put ( suggestion:get_content( "html" ) )
191 end
192 }
194 if direct_supporter then
195 ui.container{ attr = { class = "mdl-card__content rating" }, content = function ()
197 if not opinion then
198 opinion = {}
199 end
200 ui.form {
201 module = "opinion", action = "update", params = {
202 suggestion_id = suggestion.id
203 },
204 routing = { default = {
205 mode = "redirect",
206 module = "initiative", view = "show", id = suggestion.initiative_id,
207 params = { suggestion_id = suggestion.id },
208 anchor = "s" .. suggestion.id -- TODO webmcp
209 } },
210 content = function ()
212 ui.container{ attr = { class = "opinon-question" }, content = _"Should the initiator implement this suggestion?" }
213 ui.container { content = function ()
215 local options = {
216 { degree = 2, label = _"must" },
217 { degree = 1, label = _"should" },
218 { degree = 0, label = _"neutral" },
219 { degree = -1, label = _"should not" },
220 { degree = -2, label = _"must not" },
221 }
223 for i, option in ipairs(options) do
224 local active = opinion.degree == option.degree or opinion.degree == nil and option.degree == 0
225 ui.tag{
226 tag = "label",
227 attr = { class = "mdl-radio mdl-js-radio mdl-js-ripple-effect" },
228 ["for"] = "s" .. suggestion.id .. "_degree" .. option.degree,
229 content = function()
230 ui.tag{
231 tag = "input",
232 attr = {
233 class = "mdl-radio__button",
234 type = "radio",
235 name = "degree",
236 value = option.degree,
237 id = "s" .. suggestion.id .. "_degree" .. option.degree,
238 checked = active and "checked" or nil
239 }
240 }
241 ui.tag{
242 attr = { class = "mdl-radio__label" },
243 content = option.label
244 }
245 end
246 }
247 slot.put(" &nbsp;&nbsp;&nbsp; ")
248 end
249 end }
251 slot.put("<br />")
253 ui.container{ attr = { class = "opinon-question" }, content = _"Did the initiator implement this suggestion?" }
254 ui.container { content = function ()
256 local options = {
257 { degree = "false", id = "notfulfilled", label = _"No (not yet)" },
258 { degree = "true", id = "fulfilled", label = _"Yes, it's implemented" },
259 }
261 for i, option in ipairs(options) do
262 local active = opinion.fulfilled == (option.degree == "true" and true or false)
263 ui.tag{
264 tag = "label",
265 attr = { class = "mdl-radio mdl-js-radio mdl-js-ripple-effect" },
266 ["for"] = "s" .. suggestion.id .. "_" .. option.id,
267 content = function()
268 ui.tag{
269 tag = "input",
270 attr = {
271 class = "mdl-radio__button",
272 type = "radio",
273 name = "fulfilled",
274 value = option.degree,
275 id = "s" .. suggestion.id .. "_" .. option.id,
276 checked = active and "checked" or nil
277 }
278 }
279 ui.tag{
280 attr = { class = "mdl-radio__label" },
281 content = option.label
282 }
283 end
284 }
285 slot.put(" &nbsp;&nbsp;&nbsp; ")
286 end
287 end }
289 slot.put("<br />")
291 ui.tag{
292 tag = "input",
293 attr = {
294 type = "submit",
295 class = "mdl-button mdl-js-button mdl-button--raised mdl-button--colored",
296 value = _"publish my rating"
297 },
298 content = ""
299 }
301 end
302 }
304 end }
305 end
307 end }
309 ui.container { attr = { class = "rating-button" }, content = function()
311 local text = _"Read more"
313 if direct_supporter then
314 text = text .. " / " .. _"Rate suggestion"
315 end
317 ui.link {
318 attr = {
319 class = "mdl-button mdl-js-button suggestion-more",
320 onclick = "document.querySelector('#s" .. suggestion.id .. "').classList.remove('folded');document.querySelector('#s" .. suggestion.id .. "').classList.add('unfolded'); return false;"
321 },
322 text = text
323 }
325 ui.link {
326 attr = {
327 class = "mdl-button suggestion-less",
328 onclick = "document.querySelector('#s" .. suggestion.id .. "').classList.add('folded');document.querySelector('#s" .. suggestion.id .. "').classList.remove('unfolded'); return false;"
329 },
330 text = _"Show less"
331 }
332 --[[
333 ui.link{
334 attr = { class = "mdl-button" },
335 content = _"Details",
336 module = "suggestion", view = "show", id = suggestion.id
337 }
338 --]]
339 end }
340 ui.script{ script = [[
341 window.addEventListener("load", function() {
342 var textEl = document.querySelector('#s]] .. suggestion.id .. [[ .suggestion-content');
343 var height = textEl.clientHeight;
344 if (height > 180) {
345 document.querySelector('#s]] .. suggestion.id .. [[').classList.add('folded');
346 document.querySelector('#s]] .. suggestion.id .. [[ .rating-button').classList.add('mdl-card__actions');
347 document.querySelector('#s]] .. suggestion.id .. [[ .rating-button').classList.add('mdl-card--border');
348 }
349 });
350 ]] }
352 end }
354 end -- for i, suggestion
356 end -- if #initiative.suggestions > 0
357 end
358 }

Impressum / About Us