liquid_feedback_frontend

view model/issue.lua @ 19:00d1004545f1

Dynamic interface using XMLHttpRequests, and many other changes

Bugfixes:
- Only allow voting on admitted initiatives
- Repaired issue search
- Don't display delegations for closed issues on member page
- Don't show revoke link in initiative, when issue is already half_frozen
- Localization for voting JavaScript
- Display author of suggestions

Disclosure of voting data after voting is finished:
- Possibility to inspect every ballot including preferences
- Show number of voters preferring one initiative to another initiative

Interface behaviour changes:
- Reversed default order of drafts
- Default order of suggestions changed
- Show new drafts of initiatives only once per day in timeline

Accessibility:
- Barrier-free voting implemented
- POST links are now accessible without JavaScript
- Changed gray for unsatisfied supporters in bar graph to a lighter gray

Other interface improvements:
- Optical enhancements
- Dynamic interface using XMLHttpRequests
- Show usage terms in about section
- Show own membership in area listing
- Show uninformed supporters greyed out and marked with yellow question mark
- Warning box in non-admitted initiatives
- When voted, don't display voting notice and change label of voting link
- Show object counts in more tabulator heads
- Enlarged member statement input field

Miscellaneous:
- Code cleanup
- Added README file containing installation instructions
- Use new WebMCP function ui.filters{...} instead of own ui.filter and ui.order functions
author bsw/jbe
date Sat Feb 20 22:10:31 2010 +0100 (2010-02-20)
parents 72c5e0ee7c98
children 4b2af207cefa
line source
1 Issue = mondelefant.new_class()
2 Issue.table = 'issue'
4 Issue:add_reference{
5 mode = 'm1',
6 to = "Area",
7 this_key = 'area_id',
8 that_key = 'id',
9 ref = 'area',
10 }
12 Issue:add_reference{
13 mode = 'm1',
14 to = "Policy",
15 this_key = 'policy_id',
16 that_key = 'id',
17 ref = 'policy',
18 }
20 Issue:add_reference{
21 mode = '1m',
22 to = "Initiative",
23 this_key = 'id',
24 that_key = 'issue_id',
25 ref = 'initiatives',
26 back_ref = 'issue'
27 }
29 Issue:add_reference{
30 mode = '1m',
31 to = "Interest",
32 this_key = 'id',
33 that_key = 'issue_id',
34 ref = 'interests',
35 back_ref = 'issue',
36 default_order = '"id"'
37 }
39 Issue:add_reference{
40 mode = '1m',
41 to = "Supporter",
42 this_key = 'id',
43 that_key = 'issue_id',
44 ref = 'supporters',
45 back_ref = 'issue',
46 default_order = '"id"'
47 }
49 Issue:add_reference{
50 mode = '1m',
51 to = "DirectVoter",
52 this_key = 'id',
53 that_key = 'issue_id',
54 ref = 'direct_voters',
55 back_ref = 'issue',
56 default_order = '"member_id"'
57 }
59 Issue:add_reference{
60 mode = '1m',
61 to = "Vote",
62 this_key = 'id',
63 that_key = 'issue_id',
64 ref = 'votes',
65 back_ref = 'issue',
66 default_order = '"member_id", "initiative_id"'
67 }
69 Issue:add_reference{
70 mode = '1m',
71 to = "Delegation",
72 this_key = 'id',
73 that_key = 'issue_id',
74 ref = 'delegations',
75 back_ref = 'issue'
76 }
78 Issue:add_reference{
79 mode = 'mm',
80 to = "Member",
81 this_key = 'id',
82 that_key = 'id',
83 connected_by_table = 'interest',
84 connected_by_this_key = 'issue_id',
85 connected_by_that_key = 'member_id',
86 ref = 'members'
87 }
89 Issue:add_reference{
90 mode = 'mm',
91 to = "Member",
92 this_key = 'id',
93 that_key = 'id',
94 connected_by_table = 'direct_interest_snapshot',
95 connected_by_this_key = 'issue_id',
96 connected_by_that_key = 'member_id',
97 ref = 'interested_members_snapshot'
98 }
100 Issue:add_reference{
101 mode = 'mm',
102 to = "Member",
103 this_key = 'id',
104 that_key = 'id',
105 connected_by_table = 'direct_voter',
106 connected_by_this_key = 'issue_id',
107 connected_by_that_key = 'member_id',
108 ref = 'direct_voters'
109 }
113 function Issue:get_state_name_for_state(value)
114 local state_name_table = {
115 new = _"New",
116 accepted = _"Discussion",
117 frozen = _"Frozen",
118 voting = _"Voting",
119 finished = _"Finished",
120 cancelled = _"Cancelled"
121 }
122 return state_name_table[value] or value or ''
123 end
125 function Issue:get_search_selector(search_string)
126 return self:new_selector()
127 :join('"initiative"', nil, '"initiative"."issue_id" = "issue"."id"')
128 :join('"draft"', nil, '"draft"."initiative_id" = "initiative"."id"')
129 :add_where{ '"initiative"."text_search_data" @@ "text_search_query"(?) OR "draft"."text_search_data" @@ "text_search_query"(?)', search_string, search_string }
130 :add_group_by('"issue"."id"')
131 :add_group_by('"issue"."area_id"')
132 :add_group_by('"issue"."policy_id"')
133 :add_group_by('"issue"."created"')
134 :add_group_by('"issue"."accepted"')
135 :add_group_by('"issue"."half_frozen"')
136 :add_group_by('"issue"."fully_frozen"')
137 :add_group_by('"issue"."closed"')
138 :add_group_by('"issue"."ranks_available"')
139 :add_group_by('"issue"."snapshot"')
140 :add_group_by('"issue"."latest_snapshot_event"')
141 :add_group_by('"issue"."population"')
142 :add_group_by('"issue"."vote_now"')
143 :add_group_by('"issue"."vote_later"')
144 :add_group_by('"issue"."voter_count"')
145 :add_group_by('"_interest"."member_id"')
146 --:set_distinct()
147 end
149 function Issue.object_get:state()
150 if self.accepted then
151 if self.closed then
152 return "finished"
153 elseif self.fully_frozen then
154 return "voting"
155 elseif self.half_frozen then
156 return "frozen"
157 else
158 return "accepted"
159 end
160 else
161 if self.closed then
162 return "cancelled"
163 else
164 return "new"
165 end
166 end
167 end
169 function Issue.object_get:state_name()
170 return Issue:get_state_name_for_state(self.state)
171 end
173 function Issue.object_get:state_time_left()
174 local state = self.state
175 local last_event_time
176 local duration
177 if state == "new" then
178 last_event_time = self.created
179 duration = self.policy.admission_time
180 elseif state == "accepted" then
181 last_event_time = self.accepted
182 duration = self.policy.discussion_time
183 elseif state == "frozen" then
184 last_event_time = self.half_frozen
185 duration = self.policy.verification_time
186 elseif state == "voting" then
187 last_event_time = self.fully_frozen
188 duration = self.policy.voting_time
189 end
190 return db:query{ "SELECT ?::timestamp + ?::interval - now() as time_left", last_event_time, duration }[1].time_left
191 end
193 function Issue.object_get:next_states()
194 local state = self.state
195 local next_states
196 if state == "new" then
197 next_states = { "accepted", "cancelled" }
198 elseif state == "accepted" then
199 next_states = { "frozen" }
200 elseif state == "frozen" then
201 next_states = { "voting" }
202 elseif state == "voting" then
203 next_states = { "finished" }
204 end
205 return next_states
206 end
208 function Issue.object_get:next_states_names()
209 local next_states = self.next_states
210 if not next_states then
211 return
212 end
213 local state_names = {}
214 for i, state in ipairs(self.next_states) do
215 state_names[#state_names+1] = Issue:get_state_name_for_state(state)
216 end
217 return table.concat(state_names, ", ")
218 end

Impressum / About Us