| rev |
line source |
|
bsw@11
|
1 execute.view{
|
|
bsw@11
|
2 module = "timeline",
|
|
bsw@11
|
3 view = "_constants"
|
|
bsw@11
|
4 }
|
|
bsw@11
|
5
|
|
bsw@11
|
6 local options_box_count = param.get("options_box_count", atom.number) or 1
|
|
bsw@11
|
7 if options_box_count > 10 then
|
|
bsw@11
|
8 options_box_count = 10
|
|
bsw@11
|
9 end
|
|
bsw@10
|
10
|
|
bsw@10
|
11 local function format_dow(dow)
|
|
bsw@10
|
12 local dows = {
|
|
bsw@10
|
13 _"Monday",
|
|
bsw@10
|
14 _"Tuesday",
|
|
bsw@10
|
15 _"Wednesday",
|
|
bsw@10
|
16 _"Thursday",
|
|
bsw@10
|
17 _"Friday",
|
|
bsw@10
|
18 _"Saturday",
|
|
bsw@10
|
19 _"Sunday"
|
|
bsw@10
|
20 }
|
|
bsw@10
|
21 return dows[dow+1]
|
|
bsw@10
|
22 end
|
|
bsw@11
|
23 slot.put_into("title", _"Timeline")
|
|
bsw@10
|
24
|
|
bsw@11
|
25 slot.select("actions", function()
|
|
bsw@11
|
26 local setting_key = "liquidfeedback_frontend_timeline_current_options"
|
|
bsw@11
|
27 local setting = Setting:by_pk(app.session.member.id, setting_key)
|
|
bsw@11
|
28 local current_options = ""
|
|
bsw@11
|
29 if setting then
|
|
bsw@11
|
30 current_options = setting.value
|
|
bsw@11
|
31 end
|
|
bsw@11
|
32 local setting_maps = app.session.member:get_setting_maps_by_key("timeline_filters")
|
|
bsw@11
|
33 for i, setting_map in ipairs(setting_maps) do
|
|
bsw@11
|
34 local active
|
|
bsw@11
|
35 local options_string = setting_map.value
|
|
bsw@11
|
36 local name = setting_map.subkey
|
|
bsw@11
|
37 if options_string == current_options then
|
|
bsw@11
|
38 active = true
|
|
bsw@11
|
39 end
|
|
bsw@11
|
40 timeline_params.date = param.get("date")
|
|
bsw@11
|
41 ui.link{
|
|
bsw@11
|
42 attr = { class = active and "action_active" or nil },
|
|
bsw@11
|
43 content = function()
|
|
bsw@11
|
44 ui.image{ static = "icons/16/time.png" }
|
|
bsw@11
|
45 slot.put(encode.html(name))
|
|
bsw@11
|
46 end,
|
|
bsw@11
|
47 module = 'timeline',
|
|
bsw@11
|
48 action = 'update',
|
|
bsw@11
|
49 params = {
|
|
bsw@11
|
50 options_string = options_string
|
|
bsw@11
|
51 },
|
|
bsw@11
|
52 }
|
|
bsw@11
|
53 end
|
|
bsw@11
|
54 if #setting_maps > 0 then
|
|
bsw@11
|
55 ui.link{
|
|
bsw@11
|
56 content = function()
|
|
bsw@11
|
57 ui.image{ static = "icons/16/wrench.png" }
|
|
bsw@11
|
58 slot.put(_"Manage filter")
|
|
bsw@11
|
59 end,
|
|
bsw@11
|
60 module = "timeline",
|
|
bsw@11
|
61 view = "list_filter",
|
|
bsw@11
|
62 }
|
|
bsw@11
|
63 end
|
|
bsw@11
|
64 ui.link{
|
|
bsw@11
|
65 content = function()
|
|
bsw@11
|
66 ui.image{ static = "icons/16/bullet_disk.png" }
|
|
bsw@11
|
67 slot.put(_"Save current filter")
|
|
bsw@11
|
68 end,
|
|
bsw@11
|
69 module = "timeline",
|
|
bsw@11
|
70 view = "save_filter",
|
|
bsw@11
|
71 attr = {
|
|
bsw@11
|
72 onclick = "el=document.getElementById('timeline_save');el.checked=true;el.form.submit();return(false);"
|
|
bsw@11
|
73 }
|
|
bsw@11
|
74 }
|
|
bsw@11
|
75 end)
|
|
bsw@10
|
76
|
|
bsw@11
|
77 util.help("timeline.index", _"Timeline")
|
|
bsw@10
|
78
|
|
bsw@10
|
79 ui.form{
|
|
bsw@10
|
80 module = "timeline",
|
|
bsw@11
|
81 action = "update",
|
|
bsw@10
|
82 content = function()
|
|
bsw@11
|
83
|
|
bsw@11
|
84
|
|
bsw@11
|
85 ui.tag{
|
|
bsw@11
|
86 tag = "label",
|
|
bsw@11
|
87 attr = { style = "font-size: 130%;" },
|
|
bsw@11
|
88 content = _"Date" .. ":"
|
|
bsw@11
|
89 }
|
|
bsw@11
|
90 slot.put(" ")
|
|
bsw@11
|
91 local date = param.get("date")
|
|
bsw@11
|
92 if not date or #date == 0 then
|
|
bsw@11
|
93 date = tostring(db:query("select now()::date as date")[1].date)
|
|
bsw@10
|
94 end
|
|
bsw@11
|
95 ui.tag{
|
|
bsw@11
|
96 tag = "input",
|
|
bsw@11
|
97 attr = {
|
|
bsw@11
|
98 type = "text",
|
|
bsw@11
|
99 id = "timeline_search_date",
|
|
bsw@11
|
100 style = "width: 10em;",
|
|
bsw@11
|
101 onchange = "this.form.submit();",
|
|
bsw@11
|
102 name = "date",
|
|
bsw@11
|
103 value = date
|
|
bsw@11
|
104 },
|
|
bsw@11
|
105 content = function() end
|
|
bsw@11
|
106 }
|
|
bsw@11
|
107
|
|
bsw@11
|
108 ui.script{ static = "gregor.js/gregor.js" }
|
|
bsw@11
|
109 util.gregor("timeline_search_date", "document.getElementById('timeline_search_date').form.submit();")
|
|
bsw@11
|
110
|
|
bsw@11
|
111
|
|
bsw@11
|
112 ui.link{
|
|
bsw@11
|
113 attr = { style = "margin-left: 1em; font-size: 130%; font-weight: bold;", onclick = "document.getElementById('timeline_search_date').form.submit();return(false);" },
|
|
bsw@11
|
114 content = function()
|
|
bsw@11
|
115 ui.image{
|
|
bsw@11
|
116 attr = { style = "margin-right: 0.25em;" },
|
|
bsw@11
|
117 static = "icons/16/magnifier.png"
|
|
bsw@11
|
118 }
|
|
bsw@11
|
119 slot.put(_"Search")
|
|
bsw@11
|
120 end,
|
|
bsw@11
|
121 external = "#",
|
|
bsw@11
|
122 }
|
|
bsw@11
|
123 local show_options = param.get("show_options", atom.boolean)
|
|
bsw@11
|
124 ui.link{
|
|
bsw@11
|
125 attr = { style = "margin-left: 1em; font-size: 130%;", onclick = "el=document.getElementById('timeline_show_options');el.checked=" .. tostring(not show_options) .. ";el.form.submit();return(false);" },
|
|
bsw@11
|
126 content = function()
|
|
bsw@11
|
127 ui.image{
|
|
bsw@11
|
128 attr = { style = "margin-right: 0.25em;" },
|
|
bsw@11
|
129 static = "icons/16/text_list_bullets.png"
|
|
bsw@11
|
130 }
|
|
bsw@11
|
131 slot.put(not show_options and _"Show filter details" or _"Hide filter details")
|
|
bsw@11
|
132 end,
|
|
bsw@11
|
133 external = "#",
|
|
bsw@11
|
134 }
|
|
bsw@11
|
135
|
|
bsw@11
|
136 ui.field.boolean{
|
|
bsw@11
|
137 attr = { id = "timeline_show_options", style = "display: none;", onchange="this.form.submit();" },
|
|
bsw@11
|
138 name = "show_options",
|
|
bsw@11
|
139 value = param.get("show_options", atom.boolean)
|
|
bsw@11
|
140 }
|
|
bsw@11
|
141
|
|
bsw@11
|
142 ui.field.boolean{
|
|
bsw@11
|
143 attr = { id = "timeline_save", style = "display: none;", onchange="this.form.submit();" },
|
|
bsw@11
|
144 name = "save",
|
|
bsw@11
|
145 value = false
|
|
bsw@10
|
146 }
|
|
bsw@11
|
147
|
|
bsw@11
|
148 ui.container{
|
|
bsw@11
|
149 attr = {
|
|
bsw@11
|
150 id = "timeline_options_boxes",
|
|
bsw@11
|
151 class = "vertical",
|
|
bsw@11
|
152 style = not param.get("show_options", atom.boolean) and "display: none;" or nil
|
|
bsw@10
|
153 },
|
|
bsw@11
|
154 content = function()
|
|
bsw@11
|
155
|
|
bsw@11
|
156 local function option_field(event_ident, filter_ident)
|
|
bsw@11
|
157 local param_name
|
|
bsw@11
|
158 if not filter_ident then
|
|
bsw@11
|
159 param_name = "option_" .. event_ident
|
|
bsw@11
|
160 else
|
|
bsw@11
|
161 param_name = "option_" .. event_ident .. "_" .. filter_ident
|
|
bsw@11
|
162 end
|
|
bsw@11
|
163 local value = param.get(param_name, atom.boolean)
|
|
bsw@11
|
164 ui.field.boolean{
|
|
bsw@11
|
165 attr = { id = param_name },
|
|
bsw@11
|
166 name = param_name,
|
|
bsw@11
|
167 value = value,
|
|
bsw@11
|
168 }
|
|
bsw@11
|
169 end
|
|
bsw@11
|
170
|
|
bsw@11
|
171 local function filter_option_fields(event_ident, filter_idents)
|
|
bsw@11
|
172
|
|
bsw@11
|
173 for i, filter_ident in ipairs(filter_idents) do
|
|
bsw@11
|
174 slot.put("<td>")
|
|
bsw@11
|
175 option_field(event_ident, filter_ident)
|
|
bsw@11
|
176 slot.put("</td><td><div class='ui_field_label label_right'>")
|
|
bsw@11
|
177 ui.tag{
|
|
bsw@11
|
178 attr = { ["for"] = "option_" .. event_ident .. "_" .. filter_ident },
|
|
bsw@11
|
179 tag = "label",
|
|
bsw@11
|
180 content = filter_names[filter_ident]
|
|
bsw@11
|
181 }
|
|
bsw@11
|
182 slot.put("</div></td>")
|
|
bsw@11
|
183 end
|
|
bsw@11
|
184
|
|
bsw@11
|
185 end
|
|
bsw@10
|
186
|
|
bsw@11
|
187 local event_groups = {
|
|
bsw@11
|
188 {
|
|
bsw@11
|
189 title = _"Issue events",
|
|
bsw@11
|
190 event_idents = {
|
|
bsw@11
|
191 "issue_created",
|
|
bsw@11
|
192 "issue_canceled",
|
|
bsw@11
|
193 "issue_accepted",
|
|
bsw@11
|
194 "issue_half_frozen",
|
|
bsw@11
|
195 "issue_finished_without_voting",
|
|
bsw@11
|
196 "issue_voting_started",
|
|
bsw@11
|
197 "issue_finished_after_voting",
|
|
bsw@11
|
198 },
|
|
bsw@11
|
199 filter_idents = {
|
|
bsw@11
|
200 "membership",
|
|
bsw@11
|
201 "interested"
|
|
bsw@11
|
202 }
|
|
bsw@11
|
203 },
|
|
bsw@11
|
204 {
|
|
bsw@11
|
205 title = _"Initiative events",
|
|
bsw@11
|
206 event_idents = {
|
|
bsw@11
|
207 "initiative_created",
|
|
bsw@11
|
208 "initiative_revoked",
|
|
bsw@11
|
209 "draft_created",
|
|
bsw@11
|
210 "suggestion_created",
|
|
bsw@11
|
211 },
|
|
bsw@11
|
212 filter_idents = {
|
|
bsw@11
|
213 "membership",
|
|
bsw@11
|
214 "interested",
|
|
bsw@11
|
215 "supporter",
|
|
bsw@11
|
216 "potential_supporter",
|
|
bsw@11
|
217 "initiator"
|
|
bsw@11
|
218 }
|
|
bsw@11
|
219 }
|
|
bsw@11
|
220 }
|
|
bsw@11
|
221
|
|
bsw@11
|
222 slot.put("<br />")
|
|
bsw@11
|
223
|
|
bsw@11
|
224 slot.put("<table>")
|
|
bsw@11
|
225
|
|
bsw@11
|
226 for i_event_group, event_group in ipairs(event_groups) do
|
|
bsw@11
|
227 slot.put("<tr>")
|
|
bsw@11
|
228 slot.put("<th colspan='2'>")
|
|
bsw@11
|
229 slot.put(event_group.title)
|
|
bsw@11
|
230 slot.put("</th><th colspan='10'>")
|
|
bsw@11
|
231 slot.put(_"Show only events which match... (or associtated)")
|
|
bsw@11
|
232 slot.put("</th>")
|
|
bsw@11
|
233 slot.put("</tr>")
|
|
bsw@11
|
234 local event_idents = event_group.event_idents
|
|
bsw@11
|
235 for i, event_ident in ipairs(event_idents) do
|
|
bsw@11
|
236 slot.put("<tr><td>")
|
|
bsw@11
|
237 option_field(event_ident)
|
|
bsw@11
|
238 slot.put("</td><td><div class='ui_field_label label_right'>")
|
|
bsw@11
|
239 ui.tag{
|
|
bsw@11
|
240 attr = { ["for"] = "option_" .. event_ident },
|
|
bsw@11
|
241 tag = "label",
|
|
bsw@11
|
242 content = event_names[event_ident]
|
|
bsw@11
|
243 }
|
|
bsw@11
|
244 slot.put("</div></td>")
|
|
bsw@11
|
245 filter_option_fields(event_ident, event_group.filter_idents)
|
|
bsw@11
|
246 slot.put("</tr>")
|
|
bsw@11
|
247 end
|
|
bsw@11
|
248 end
|
|
bsw@11
|
249
|
|
bsw@11
|
250 slot.put("</table>")
|
|
bsw@11
|
251
|
|
bsw@11
|
252 end
|
|
bsw@10
|
253 }
|
|
bsw@10
|
254 end
|
|
bsw@10
|
255 }
|
|
bsw@10
|
256
|
|
bsw@10
|
257 local date = param.get("date")
|
|
bsw@11
|
258 if not date or #date == 0 then
|
|
bsw@10
|
259 date = "today"
|
|
bsw@10
|
260 end
|
|
bsw@11
|
261
|
|
bsw@11
|
262 local timeline_selector
|
|
bsw@11
|
263
|
|
bsw@11
|
264 for event, event_name in pairs(event_names) do
|
|
bsw@11
|
265
|
|
bsw@11
|
266 if param.get("option_" .. event, atom.boolean) then
|
|
bsw@11
|
267
|
|
bsw@11
|
268 local tmp = Timeline:new_selector()
|
|
bsw@11
|
269 :add_where{ "occurrence::date = ?", date }
|
|
bsw@11
|
270
|
|
bsw@11
|
271 :left_join("draft", nil, "draft.id = timeline.draft_id")
|
|
bsw@11
|
272 :left_join("suggestion", nil, "suggestion.id = timeline.suggestion_id")
|
|
bsw@11
|
273 :left_join("initiative", nil, "initiative.id = timeline.initiative_id or initiative.id = draft.initiative_id or initiative.id = suggestion.initiative_id")
|
|
bsw@11
|
274 :left_join("issue", nil, "issue.id = timeline.issue_id or issue.id = initiative.issue_id")
|
|
bsw@11
|
275 :left_join("area", nil, "area.id = issue.area_id")
|
|
bsw@11
|
276
|
|
bsw@11
|
277 :left_join("interest", "_interest", { "_interest.issue_id = issue.id AND _interest.member_id = ?", app.session.member.id} )
|
|
bsw@11
|
278 :left_join("membership", "_membership", { "_membership.area_id = area.id AND _membership.member_id = ?", app.session.member.id} )
|
|
bsw@11
|
279 :left_join("initiator", "_initiator", { "_initiator.initiative_id = initiative.id AND _initiator.member_id = ?", app.session.member.id} )
|
|
bsw@11
|
280 :left_join("supporter", "_supporter", { "_supporter.initiative_id = initiative.id AND _supporter.member_id = ?", app.session.member.id} )
|
|
bsw@11
|
281
|
|
bsw@11
|
282 :add_field("(_interest.member_id NOTNULL)", "is_interested")
|
|
bsw@11
|
283 :add_field("(_initiator.member_id NOTNULL)", "is_initiator")
|
|
bsw@11
|
284 :add_field({"(_supporter.member_id NOTNULL) AND NOT EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1)", app.session.member.id }, "is_supporter")
|
|
bsw@11
|
285 :add_field({"EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1)", app.session.member.id }, "is_potential_supporter")
|
|
bsw@11
|
286 -- :left_join("member", nil, "member.id = timeline.member_id")
|
|
bsw@11
|
287
|
|
bsw@11
|
288 tmp:add_where{ "event = ?", event }
|
|
bsw@11
|
289
|
|
bsw@11
|
290 local filters = {}
|
|
bsw@11
|
291 if param.get("option_" .. event .. "_membership", atom.boolean) then
|
|
bsw@11
|
292 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _membership.member_id NOTNULL"
|
|
bsw@11
|
293 end
|
|
bsw@11
|
294
|
|
bsw@11
|
295 if param.get("option_" .. event .. "_supporter", atom.boolean) then
|
|
bsw@11
|
296 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR ((_supporter.member_id NOTNULL) AND NOT EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1))"
|
|
bsw@11
|
297 end
|
|
bsw@11
|
298
|
|
bsw@11
|
299 if param.get("option_" .. event .. "_potential_supporter", atom.boolean) then
|
|
bsw@11
|
300 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR ((_supporter.member_id NOTNULL) AND EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1))"
|
|
bsw@11
|
301 end
|
|
bsw@10
|
302
|
|
bsw@11
|
303 if param.get("option_" .. event .. "_interested", atom.boolean) then
|
|
bsw@11
|
304 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _interest.member_id NOTNULL"
|
|
bsw@11
|
305 end
|
|
bsw@11
|
306
|
|
bsw@11
|
307 if param.get("option_" .. event .. "_initiator", atom.boolean) then
|
|
bsw@11
|
308 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _initiator.member_id NOTNULL"
|
|
bsw@11
|
309 end
|
|
bsw@11
|
310
|
|
bsw@11
|
311 if #filters > 0 then
|
|
bsw@11
|
312 local filter_string = "(" .. table.concat(filters, ") OR (") .. ")"
|
|
bsw@11
|
313 tmp:add_where{ filter_string, app.session.member.id }
|
|
bsw@11
|
314 end
|
|
bsw@11
|
315
|
|
bsw@11
|
316 if not timeline_selector then
|
|
bsw@11
|
317 timeline_selector = tmp
|
|
bsw@11
|
318 else
|
|
bsw@11
|
319 timeline_selector:union_all(tmp)
|
|
bsw@11
|
320 end
|
|
bsw@11
|
321 end
|
|
bsw@11
|
322 end
|
|
bsw@11
|
323
|
|
bsw@11
|
324 if timeline_selector then
|
|
bsw@11
|
325
|
|
bsw@11
|
326 local initiatives_per_page = param.get("initiatives_per_page", atom.number)
|
|
bsw@11
|
327
|
|
bsw@11
|
328 local outer_timeline_selector = db:new_selector()
|
|
bsw@11
|
329 outer_timeline_selector._class = Timeline
|
|
bsw@11
|
330 outer_timeline_selector:add_field{ "timeline.*" }
|
|
bsw@11
|
331 outer_timeline_selector:from({"($)", { timeline_selector }}, "timeline" )
|
|
bsw@11
|
332 outer_timeline_selector:add_order_by("occurrence DESC")
|
|
bsw@11
|
333
|
|
bsw@11
|
334 slot.put("<br />")
|
|
bsw@11
|
335 execute.view{
|
|
bsw@11
|
336 module = "timeline",
|
|
bsw@11
|
337 view = "_list",
|
|
bsw@11
|
338 params = {
|
|
bsw@11
|
339 timeline_selector = outer_timeline_selector,
|
|
bsw@11
|
340 per_page = param.get("per_page", atom.number),
|
|
bsw@11
|
341 event_names = event_names,
|
|
bsw@11
|
342 initiatives_per_page = initiatives_per_page
|
|
bsw@11
|
343 }
|
|
bsw@10
|
344 }
|
|
bsw@11
|
345
|
|
bsw@11
|
346 else
|
|
bsw@10
|
347
|
|
bsw@11
|
348 slot.put(_"No events selected to list")
|
|
bsw@11
|
349
|
|
bsw@11
|
350 end |