| rev | 
   line source | 
| 
bsw/jbe@19
 | 
     1 local issue = Issue:by_id(param.get("issue_id"), atom.integer)
 | 
| 
bsw/jbe@19
 | 
     2 
 | 
| 
bsw/jbe@19
 | 
     3 local member_id = param.get("member_id", atom.integer)
 | 
| 
bsw/jbe@19
 | 
     4 local member
 | 
| 
jbe@945
 | 
     5 local readonly = false
 | 
| 
bsw/jbe@19
 | 
     6 
 | 
| 
jbe@950
 | 
     7 local preview = param.get("preview") and true or false
 | 
| 
poelzi@156
 | 
     8 
 | 
| 
bsw/jbe@19
 | 
     9 if member_id then
 | 
| 
bsw/jbe@19
 | 
    10   if not issue.closed then
 | 
| 
bsw/jbe@19
 | 
    11     error("access denied")
 | 
| 
bsw/jbe@19
 | 
    12   end
 | 
| 
bsw/jbe@19
 | 
    13   member = Member:by_id(member_id)
 | 
| 
bsw/jbe@19
 | 
    14   readonly = true
 | 
| 
bsw/jbe@19
 | 
    15 end
 | 
| 
bsw/jbe@19
 | 
    16 
 | 
| 
poelzi@138
 | 
    17 if issue.closed then
 | 
| 
poelzi@156
 | 
    18   if not member then
 | 
| 
poelzi@158
 | 
    19     member = app.session.member
 | 
| 
poelzi@158
 | 
    20   end
 | 
| 
poelzi@156
 | 
    21   readonly = true
 | 
| 
poelzi@138
 | 
    22 end
 | 
| 
poelzi@138
 | 
    23 
 | 
| 
bsw@1045
 | 
    24 if preview then
 | 
| 
bsw@1045
 | 
    25   readonly = true
 | 
| 
bsw@1045
 | 
    26 end
 | 
| 
bsw@1045
 | 
    27 
 | 
| 
bsw@879
 | 
    28 local submit_button_text = _"Finish voting"
 | 
| 
bsw@1045
 | 
    29 local edit_button_text = _"Edit again"
 | 
| 
bsw@879
 | 
    30 
 | 
| 
bsw@879
 | 
    31 if issue.closed then
 | 
| 
bsw@1045
 | 
    32   submit_button_text = _"Save voting comment"
 | 
| 
bsw@1045
 | 
    33   edit_button_text = _"Edit voting comment"
 | 
| 
bsw@879
 | 
    34 end
 | 
| 
bsw@879
 | 
    35 
 | 
| 
bsw@1045
 | 
    36 execute.view {
 | 
| 
bsw@1045
 | 
    37   module = "issue", view = "_head", params = { issue = issue }
 | 
| 
bsw@1045
 | 
    38 }
 | 
| 
bsw@1045
 | 
    39 
 | 
| 
bsw@879
 | 
    40 local direct_voter
 | 
| 
bsw@879
 | 
    41 
 | 
| 
bsw/jbe@19
 | 
    42 if member then
 | 
| 
bsw@879
 | 
    43   direct_voter = DirectVoter:by_pk(issue.id, member.id)
 | 
| 
bsw/jbe@19
 | 
    44 else
 | 
| 
bsw/jbe@19
 | 
    45   member = app.session.member
 | 
| 
bsw@879
 | 
    46   direct_voter = DirectVoter:by_pk(issue.id, member.id)
 | 
| 
bsw/jbe@19
 | 
    47 end
 | 
| 
bsw/jbe@19
 | 
    48 
 | 
| 
bsw/jbe@19
 | 
    49 
 | 
| 
bsw@879
 | 
    50 
 | 
| 
bsw/jbe@19
 | 
    51 local tempvoting_string = param.get("scoring")
 | 
| 
bsw/jbe@19
 | 
    52 
 | 
| 
bsw/jbe@19
 | 
    53 local tempvotings = {}
 | 
| 
bsw/jbe@19
 | 
    54 if tempvoting_string then
 | 
| 
bsw/jbe@19
 | 
    55   for match in tempvoting_string:gmatch("([^;]+)") do
 | 
| 
bsw/jbe@19
 | 
    56     for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do
 | 
| 
bsw/jbe@19
 | 
    57       tempvotings[tonumber(initiative_id)] = tonumber(grade)
 | 
| 
bsw/jbe@19
 | 
    58     end
 | 
| 
bsw/jbe@5
 | 
    59   end
 | 
| 
bsw/jbe@19
 | 
    60 end
 | 
| 
bsw/jbe@5
 | 
    61 
 | 
| 
bsw@95
 | 
    62 local initiatives = issue:get_reference_selector("initiatives"):add_where("initiative.admitted"):add_order_by("initiative.satisfied_supporter_count DESC"):exec()
 | 
| 
bsw/jbe@5
 | 
    63 
 | 
| 
bsw/jbe@5
 | 
    64 local min_grade = -1;
 | 
| 
bsw/jbe@5
 | 
    65 local max_grade = 1;
 | 
| 
bsw/jbe@5
 | 
    66 
 | 
| 
bsw/jbe@5
 | 
    67 for i, initiative in ipairs(initiatives) do
 | 
| 
bsw/jbe@5
 | 
    68   -- TODO performance
 | 
| 
bsw/jbe@19
 | 
    69   initiative.vote = Vote:by_pk(initiative.id, member.id)
 | 
| 
bsw/jbe@19
 | 
    70   if tempvotings[initiative.id] then
 | 
| 
bsw/jbe@19
 | 
    71     initiative.vote = {}
 | 
| 
bsw/jbe@19
 | 
    72     initiative.vote.grade = tempvotings[initiative.id]
 | 
| 
bsw/jbe@19
 | 
    73   end
 | 
| 
bsw/jbe@5
 | 
    74   if initiative.vote then
 | 
| 
bsw/jbe@5
 | 
    75     if initiative.vote.grade > max_grade then
 | 
| 
bsw/jbe@5
 | 
    76       max_grade = initiative.vote.grade
 | 
| 
bsw/jbe@5
 | 
    77     end
 | 
| 
bsw/jbe@5
 | 
    78     if initiative.vote.grade < min_grade then
 | 
| 
bsw/jbe@5
 | 
    79       min_grade = initiative.vote.grade
 | 
| 
bsw/jbe@5
 | 
    80     end
 | 
| 
bsw/jbe@5
 | 
    81   end
 | 
| 
bsw/jbe@5
 | 
    82 end
 | 
| 
bsw/jbe@5
 | 
    83 
 | 
| 
bsw/jbe@5
 | 
    84 local sections = {}
 | 
| 
bsw/jbe@5
 | 
    85 for i = min_grade, max_grade do
 | 
| 
bsw/jbe@5
 | 
    86   sections[i] = {}
 | 
| 
bsw/jbe@5
 | 
    87   for j, initiative in ipairs(initiatives) do
 | 
| 
bsw/jbe@5
 | 
    88     if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then
 | 
| 
bsw/jbe@5
 | 
    89       sections[i][#(sections[i])+1] = initiative
 | 
| 
bsw/jbe@5
 | 
    90     end
 | 
| 
bsw/jbe@5
 | 
    91   end
 | 
| 
bsw/jbe@5
 | 
    92 end
 | 
| 
bsw/jbe@5
 | 
    93 
 | 
| 
bsw/jbe@19
 | 
    94 local approval_count, disapproval_count = 0, 0
 | 
| 
bsw/jbe@19
 | 
    95 for i = min_grade, -1 do
 | 
| 
bsw/jbe@19
 | 
    96   if #sections[i] > 0 then
 | 
| 
bsw/jbe@19
 | 
    97     disapproval_count = disapproval_count + 1
 | 
| 
bsw/jbe@19
 | 
    98   end
 | 
| 
bsw/jbe@19
 | 
    99 end
 | 
| 
bsw/jbe@19
 | 
   100 local approval_count = 0
 | 
| 
bsw/jbe@19
 | 
   101 for i = 1, max_grade do
 | 
| 
bsw/jbe@19
 | 
   102   if #sections[i] > 0 then
 | 
| 
bsw/jbe@19
 | 
   103     approval_count = approval_count + 1
 | 
| 
bsw/jbe@19
 | 
   104   end
 | 
| 
bsw/jbe@19
 | 
   105 end
 | 
| 
bsw/jbe@5
 | 
   106 
 | 
| 
bsw/jbe@19
 | 
   107 if not readonly then
 | 
| 
bsw/jbe@19
 | 
   108   slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/dragdrop.js"></script>')
 | 
| 
bsw/jbe@19
 | 
   109   slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/voting.js"></script>')
 | 
| 
bsw/jbe@19
 | 
   110 end
 | 
| 
bsw/jbe@19
 | 
   111 
 | 
| 
bsw/jbe@19
 | 
   112 ui.script{
 | 
| 
bsw/jbe@19
 | 
   113   script = function()
 | 
| 
bsw/jbe@19
 | 
   114     slot.put(
 | 
| 
bsw/jbe@19
 | 
   115       "voting_text_approval_single               = ", encode.json(_"Approval [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   116       "voting_text_approval_multi                = ", encode.json(_"Approval [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   117       "voting_text_first_preference_single       = ", encode.json(_"Approval (first preference) [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   118       "voting_text_first_preference_multi        = ", encode.json(_"Approval (first preference) [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   119       "voting_text_second_preference_single      = ", encode.json(_"Approval (second preference) [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   120       "voting_text_second_preference_multi       = ", encode.json(_"Approval (second preference) [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   121       "voting_text_third_preference_single       = ", encode.json(_"Approval (third preference) [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   122       "voting_text_third_preference_multi        = ", encode.json(_"Approval (third preference) [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   123       "voting_text_numeric_preference_single     = ", encode.json(_"Approval (#th preference) [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   124       "voting_text_numeric_preference_multi      = ", encode.json(_"Approval (#th preference) [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   125       "voting_text_abstention_single             = ", encode.json(_"Abstention [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   126       "voting_text_abstention_multi              = ", encode.json(_"Abstention [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   127       "voting_text_disapproval_above_one_single  = ", encode.json(_"Disapproval (prefer to lower block) [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   128       "voting_text_disapproval_above_one_multi   = ", encode.json(_"Disapproval (prefer to lower block) [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   129       "voting_text_disapproval_above_many_single = ", encode.json(_"Disapproval (prefer to lower blocks) [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   130       "voting_text_disapproval_above_many_multi  = ", encode.json(_"Disapproval (prefer to lower blocks) [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   131       "voting_text_disapproval_above_last_single = ", encode.json(_"Disapproval (prefer to last block) [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   132       "voting_text_disapproval_above_last_multi  = ", encode.json(_"Disapproval (prefer to last block) [many entries]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   133       "voting_text_disapproval_single            = ", encode.json(_"Disapproval [single entry]"), ";\n",
 | 
| 
bsw/jbe@19
 | 
   134       "voting_text_disapproval_multi             = ", encode.json(_"Disapproval [many entries]"), ";\n"
 | 
| 
bsw/jbe@19
 | 
   135     )
 | 
| 
bsw/jbe@19
 | 
   136   end
 | 
| 
bsw/jbe@19
 | 
   137 }
 | 
| 
bsw/jbe@5
 | 
   138 
 | 
| 
bsw@1045
 | 
   139 if issue.state == "finished_with_winner" 
 | 
| 
bsw@1045
 | 
   140   or issue.state == "finished_without_winner" 
 | 
| 
bsw@1045
 | 
   141 then
 | 
| 
bsw@1045
 | 
   142 
 | 
| 
bsw@1045
 | 
   143   local members_selector = Member:new_selector()
 | 
| 
bsw@1045
 | 
   144     :join("delegating_voter", nil, "delegating_voter.member_id = member.id")
 | 
| 
bsw@1045
 | 
   145     :add_where{ "delegating_voter.issue_id = ?", issue.id }
 | 
| 
bsw@1045
 | 
   146     :add_where{ "delegating_voter.delegate_member_ids[1] = ?", member.id }
 | 
| 
bsw@1045
 | 
   147     :add_field("delegating_voter.weight", "voter_weight")
 | 
| 
bsw@1045
 | 
   148     :join("issue", nil, "issue.id = delegating_voter.issue_id")
 | 
| 
bsw@1045
 | 
   149     
 | 
| 
bsw@1045
 | 
   150   ui.sidebar( "tab-members", function()
 | 
| 
bsw@1045
 | 
   151     ui.sidebarHead(function()
 | 
| 
bsw@1045
 | 
   152       ui.heading{ level = 2, content = _"Incoming delegations" }
 | 
| 
bsw@1045
 | 
   153     end)
 | 
| 
bsw@1045
 | 
   154     execute.view{
 | 
| 
bsw@1045
 | 
   155       module = "member",
 | 
| 
bsw@1045
 | 
   156       view = "_list",
 | 
| 
bsw@1045
 | 
   157       params = {
 | 
| 
bsw@1045
 | 
   158         members_selector = members_selector,
 | 
| 
bsw@1045
 | 
   159         trustee = member,
 | 
| 
bsw@1045
 | 
   160         issue = issue,
 | 
| 
bsw@1045
 | 
   161         initiative = initiative,
 | 
| 
bsw@1045
 | 
   162         for_votes = true, no_filter = true,
 | 
| 
bsw@1045
 | 
   163         member_class = "sidebarRow sidebarRowNarrow",
 | 
| 
bsw/jbe@5
 | 
   164       }
 | 
| 
bsw@1045
 | 
   165     }
 | 
| 
bsw@1045
 | 
   166   end)
 | 
| 
bsw@1045
 | 
   167 end
 | 
| 
bsw@1045
 | 
   168 
 | 
| 
bsw@1045
 | 
   169 
 | 
| 
bsw@1045
 | 
   170 ui.section( function()
 | 
| 
bsw@1045
 | 
   171 
 | 
| 
bsw@1045
 | 
   172   ui.sectionHead( function()
 | 
| 
bsw@1045
 | 
   173     if preview then
 | 
| 
bsw@1045
 | 
   174       ui.heading { level = 1, content = _"Preview of voting ballot" }
 | 
| 
bsw@1045
 | 
   175     elseif readonly then
 | 
| 
bsw@1045
 | 
   176       local str = _("Ballot of '#{member_name}'",
 | 
| 
bsw@1045
 | 
   177                       {member_name = string.format('<a href="%s">%s</a>',
 | 
| 
bsw@1045
 | 
   178                                               encode.url{
 | 
| 
bsw@1045
 | 
   179                                                 module    = "member",
 | 
| 
bsw@1045
 | 
   180                                                 view      = "show",
 | 
| 
bsw@1045
 | 
   181                                                 id        = member.id,
 | 
| 
bsw@1045
 | 
   182                                               },
 | 
| 
bsw@1045
 | 
   183                                               encode.html(member.name))
 | 
| 
bsw@1045
 | 
   184                       }
 | 
| 
bsw@1045
 | 
   185                   )
 | 
| 
bsw@1045
 | 
   186       ui.heading { level = 1, content = function () slot.put ( str ) end }
 | 
| 
bsw@1045
 | 
   187     else
 | 
| 
bsw@1045
 | 
   188       ui.heading { level = 1, content = _"Voting" }
 | 
| 
bsw/jbe@19
 | 
   189     end
 | 
| 
bsw@1045
 | 
   190   end )
 | 
| 
bsw@1045
 | 
   191   
 | 
| 
bsw@1045
 | 
   192   ui.sectionRow( function()
 | 
| 
bsw@1045
 | 
   193 
 | 
| 
bsw@1045
 | 
   194     ui.form{
 | 
| 
bsw@1045
 | 
   195       record = direct_voter,
 | 
| 
bsw@1045
 | 
   196       attr = {
 | 
| 
bsw@1045
 | 
   197         id = "voting_form",
 | 
| 
bsw@1045
 | 
   198         class = readonly and "voting_form_readonly" or "voting_form_active"
 | 
| 
bsw@1045
 | 
   199       },
 | 
| 
bsw@1045
 | 
   200       module = "vote",
 | 
| 
bsw@1045
 | 
   201       action = "update",
 | 
| 
bsw@1045
 | 
   202       params = { issue_id = issue.id },
 | 
| 
bsw/jbe@5
 | 
   203       content = function()
 | 
| 
bsw@1045
 | 
   204         if not readonly or preview then
 | 
| 
bsw@1045
 | 
   205           local scoring = param.get("scoring")
 | 
| 
bsw@1045
 | 
   206           if not scoring then
 | 
| 
bsw@1045
 | 
   207             for i, initiative in ipairs(initiatives) do
 | 
| 
bsw@1045
 | 
   208               local vote = initiative.vote
 | 
| 
bsw@1045
 | 
   209               if vote then
 | 
| 
bsw@1045
 | 
   210                 tempvotings[initiative.id] = vote.grade
 | 
| 
bsw@1045
 | 
   211               else
 | 
| 
bsw@1045
 | 
   212                 tempvotings[initiative.id] = 0
 | 
| 
bsw@1045
 | 
   213               end
 | 
| 
bsw@1045
 | 
   214             end
 | 
| 
bsw@1045
 | 
   215             local tempvotings_list = {}
 | 
| 
bsw@1045
 | 
   216             for key, val in pairs(tempvotings) do
 | 
| 
bsw@1045
 | 
   217               tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val)
 | 
| 
bsw@1045
 | 
   218             end
 | 
| 
bsw@1045
 | 
   219             if #tempvotings_list > 0 then
 | 
| 
bsw@1045
 | 
   220               scoring = table.concat(tempvotings_list, ";")
 | 
| 
bsw@1045
 | 
   221             else
 | 
| 
bsw@1045
 | 
   222               scoring = ""
 | 
| 
bsw@1045
 | 
   223             end
 | 
| 
bsw/jbe@5
 | 
   224           end
 | 
| 
bsw@1045
 | 
   225           slot.put('<input type="hidden" name="scoring" value="' .. scoring .. '"/>')
 | 
| 
bsw@1045
 | 
   226         end
 | 
| 
bsw@1045
 | 
   227         if preview then
 | 
| 
bsw@1045
 | 
   228           ui.heading{ level = 2, content = _"Your choice" }
 | 
| 
bsw@1045
 | 
   229         elseif not readonly then
 | 
| 
bsw@1045
 | 
   230           ui.heading{ level = 2, content = _"Make your choice by placing the initiatives" }
 | 
| 
bsw@1045
 | 
   231         end
 | 
| 
bsw@1045
 | 
   232         
 | 
| 
bsw@1045
 | 
   233         ui.container{
 | 
| 
bsw@1045
 | 
   234           attr = { id = "voting" },
 | 
| 
bsw@1045
 | 
   235           content = function()
 | 
| 
bsw@1045
 | 
   236             local approval_index, disapproval_index = 0, 0
 | 
| 
bsw@1145
 | 
   237             local approval_used, disapproval_used
 | 
| 
bsw@1045
 | 
   238             for grade = max_grade, min_grade, -1 do 
 | 
| 
bsw@1045
 | 
   239               local entries = sections[grade]
 | 
| 
bsw@1045
 | 
   240               local class
 | 
| 
bsw@1045
 | 
   241               if grade > 0 then
 | 
| 
bsw@1045
 | 
   242                 class = "approval"
 | 
| 
bsw@1045
 | 
   243               elseif grade < 0 then
 | 
| 
bsw@1045
 | 
   244                 class = "disapproval"
 | 
| 
bsw@1045
 | 
   245               else
 | 
| 
bsw@1045
 | 
   246                 class = "abstention"
 | 
| 
bsw@1045
 | 
   247               end
 | 
| 
bsw@1045
 | 
   248               if
 | 
| 
bsw@1045
 | 
   249                 #entries > 0 or
 | 
| 
bsw@1045
 | 
   250                 (grade == 1 and not approval_used) or
 | 
| 
bsw@1045
 | 
   251                 (grade == -1 and not disapproval_used) or
 | 
| 
bsw@1045
 | 
   252                 grade == 0
 | 
| 
bsw@1045
 | 
   253               then
 | 
| 
bsw@1045
 | 
   254                 ui.container{
 | 
| 
bsw@1045
 | 
   255                   attr = { class = class },
 | 
| 
bsw@1045
 | 
   256                   content = function()
 | 
| 
bsw@1045
 | 
   257                     local heading
 | 
| 
bsw@1045
 | 
   258                     if class == "approval" then
 | 
| 
bsw@1045
 | 
   259                       approval_used = true
 | 
| 
bsw@1045
 | 
   260                       approval_index = approval_index + 1
 | 
| 
bsw@1045
 | 
   261                       if approval_count > 1 then
 | 
| 
bsw@1045
 | 
   262                         if approval_index == 1 then
 | 
| 
bsw@1045
 | 
   263                           if #entries == 1 then
 | 
| 
bsw@1045
 | 
   264                             heading = _"Approval (first preference) [single entry]"
 | 
| 
bsw@1045
 | 
   265                           else
 | 
| 
bsw@1045
 | 
   266                             heading = _"Approval (first preference) [many entries]"
 | 
| 
bsw@1045
 | 
   267                           end
 | 
| 
bsw@1045
 | 
   268                         elseif approval_index == 2 then
 | 
| 
bsw@1045
 | 
   269                           if #entries == 1 then
 | 
| 
bsw@1045
 | 
   270                             heading = _"Approval (second preference) [single entry]"
 | 
| 
bsw@1045
 | 
   271                           else
 | 
| 
bsw@1045
 | 
   272                             heading = _"Approval (second preference) [many entries]"
 | 
| 
bsw@1045
 | 
   273                           end
 | 
| 
bsw@1045
 | 
   274                         elseif approval_index == 3 then
 | 
| 
bsw@1045
 | 
   275                           if #entries == 1 then
 | 
| 
bsw@1045
 | 
   276                             heading = _"Approval (third preference) [single entry]"
 | 
| 
bsw@1045
 | 
   277                           else
 | 
| 
bsw@1045
 | 
   278                             heading = _"Approval (third preference) [many entries]"
 | 
| 
bsw@1045
 | 
   279                           end
 | 
| 
bsw@1045
 | 
   280                         else
 | 
| 
bsw@1045
 | 
   281                           if #entries == 1 then
 | 
| 
bsw@1045
 | 
   282                             heading = _"Approval (#th preference) [single entry]"
 | 
| 
bsw@1045
 | 
   283                           else
 | 
| 
bsw@1045
 | 
   284                             heading = _"Approval (#th preference) [many entries]"
 | 
| 
bsw@1045
 | 
   285                           end
 | 
| 
bsw@1045
 | 
   286                         end
 | 
| 
bsw/jbe@19
 | 
   287                       else
 | 
| 
bsw@1045
 | 
   288                         if #entries == 1 then
 | 
| 
bsw@1045
 | 
   289                           heading = _"Approval [single entry]"
 | 
| 
bsw@1045
 | 
   290                         else
 | 
| 
bsw@1045
 | 
   291                           heading = _"Approval [many entries]"
 | 
| 
bsw@1045
 | 
   292                         end
 | 
| 
bsw/jbe@19
 | 
   293                       end
 | 
| 
bsw@1045
 | 
   294                     elseif class == "abstention" then
 | 
| 
bsw@1045
 | 
   295                         if #entries == 1 then
 | 
| 
bsw@1045
 | 
   296                           heading = _"Abstention [single entry]"
 | 
| 
bsw@1045
 | 
   297                         else
 | 
| 
bsw@1045
 | 
   298                           heading = _"Abstention [many entries]"
 | 
| 
bsw@1045
 | 
   299                         end
 | 
| 
bsw@1045
 | 
   300                     elseif class == "disapproval" then
 | 
| 
bsw@1045
 | 
   301                       disapproval_used = true
 | 
| 
bsw@1045
 | 
   302                       disapproval_index = disapproval_index + 1
 | 
| 
bsw@1045
 | 
   303                       if disapproval_count > disapproval_index + 1 then
 | 
| 
bsw@1045
 | 
   304                         if #entries == 1 then
 | 
| 
bsw@1045
 | 
   305                           heading = _"Disapproval (prefer to lower blocks) [single entry]"
 | 
| 
bsw@1045
 | 
   306                         else
 | 
| 
bsw@1045
 | 
   307                           heading = _"Disapproval (prefer to lower blocks) [many entries]"
 | 
| 
bsw@1045
 | 
   308                         end
 | 
| 
bsw@1045
 | 
   309                       elseif disapproval_count == 2 and disapproval_index == 1 then
 | 
| 
bsw@1045
 | 
   310                         if #entries == 1 then
 | 
| 
bsw@1045
 | 
   311                           heading = _"Disapproval (prefer to lower block) [single entry]"
 | 
| 
bsw@1045
 | 
   312                         else
 | 
| 
bsw@1045
 | 
   313                           heading = _"Disapproval (prefer to lower block) [many entries]"
 | 
| 
bsw@1045
 | 
   314                         end
 | 
| 
bsw@1045
 | 
   315                       elseif disapproval_index == disapproval_count - 1 then
 | 
| 
bsw@1045
 | 
   316                         if #entries == 1 then
 | 
| 
bsw@1045
 | 
   317                           heading = _"Disapproval (prefer to last block) [single entry]"
 | 
| 
bsw@1045
 | 
   318                         else
 | 
| 
bsw@1045
 | 
   319                           heading = _"Disapproval (prefer to last block) [many entries]"
 | 
| 
bsw@1045
 | 
   320                         end
 | 
| 
bsw/jbe@19
 | 
   321                       else
 | 
| 
bsw@1045
 | 
   322                         if #entries == 1 then
 | 
| 
bsw@1045
 | 
   323                           heading = _"Disapproval [single entry]"
 | 
| 
bsw@1045
 | 
   324                         else
 | 
| 
bsw@1045
 | 
   325                           heading = _"Disapproval [many entries]"
 | 
| 
bsw@1045
 | 
   326                         end
 | 
| 
bsw/jbe@19
 | 
   327                       end
 | 
| 
bsw/jbe@19
 | 
   328                     end
 | 
| 
bsw@1045
 | 
   329                     ui.tag {
 | 
| 
bsw@1045
 | 
   330                       tag     = "div",
 | 
| 
bsw@1045
 | 
   331                       attr    = { class = "cathead" },
 | 
| 
bsw@1045
 | 
   332                       content = heading
 | 
| 
bsw@1045
 | 
   333                     }
 | 
| 
bsw@1045
 | 
   334                     for i, initiative in ipairs(entries) do
 | 
| 
bsw/jbe@19
 | 
   335                       ui.container{
 | 
| 
bsw@1045
 | 
   336                         attr = {
 | 
| 
bsw@1045
 | 
   337                           class = "movable",
 | 
| 
bsw@1045
 | 
   338                           id = "entry_" .. tostring(initiative.id)
 | 
| 
bsw@1045
 | 
   339                         },
 | 
| 
bsw/jbe@19
 | 
   340                         content = function()
 | 
| 
bsw@1045
 | 
   341                           local initiators_selector = initiative:get_reference_selector("initiating_members")
 | 
| 
bsw@1045
 | 
   342                             :add_where("accepted")
 | 
| 
bsw@1045
 | 
   343                           local initiators = initiators_selector:exec()
 | 
| 
bsw@1045
 | 
   344                           local initiator_names = {}
 | 
| 
bsw@1045
 | 
   345                           for i, initiator in ipairs(initiators) do
 | 
| 
bsw@1045
 | 
   346                             initiator_names[#initiator_names+1] = initiator.name
 | 
| 
bsw@1045
 | 
   347                           end
 | 
| 
bsw@1045
 | 
   348                           local initiator_names_string = table.concat(initiator_names, ", ")
 | 
| 
bsw@1045
 | 
   349                           ui.container{
 | 
| 
bsw@1045
 | 
   350                             attr = { style = "float: right; position: relative;" },
 | 
| 
bsw@1045
 | 
   351                             content = function()
 | 
| 
bsw@1045
 | 
   352                               ui.link{
 | 
| 
bsw@1045
 | 
   353                                 attr = { class = "clickable" },
 | 
| 
bsw@1045
 | 
   354                                 content = _"Show",
 | 
| 
bsw@1045
 | 
   355                                 module = "initiative",
 | 
| 
bsw@1045
 | 
   356                                 view = "show",
 | 
| 
bsw@1045
 | 
   357                                 id = initiative.id
 | 
| 
bsw@1045
 | 
   358                               }
 | 
| 
bsw@1045
 | 
   359                               slot.put(" ")
 | 
| 
bsw@1045
 | 
   360                               ui.link{
 | 
| 
bsw@1045
 | 
   361                                 attr = { class = "clickable", target = "_blank" },
 | 
| 
bsw@1045
 | 
   362                                 content = _"(new window)",
 | 
| 
bsw@1045
 | 
   363                                 module = "initiative",
 | 
| 
bsw@1045
 | 
   364                                 view = "show",
 | 
| 
bsw@1045
 | 
   365                                 id = initiative.id
 | 
| 
bsw@1045
 | 
   366                               }
 | 
| 
bsw@1045
 | 
   367                               if not readonly then
 | 
| 
bsw@1045
 | 
   368                                 slot.put(" ")
 | 
| 
bsw@1045
 | 
   369                                 ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" }
 | 
| 
bsw@1045
 | 
   370                               end
 | 
| 
bsw@1045
 | 
   371                             end
 | 
| 
bsw/jbe@19
 | 
   372                           }
 | 
| 
bsw/jbe@19
 | 
   373                           if not readonly then
 | 
| 
bsw@1045
 | 
   374                             ui.container{
 | 
| 
bsw@1045
 | 
   375                               attr = { style = "float: left; position: relative;" },
 | 
| 
bsw@1045
 | 
   376                               content = function()
 | 
| 
bsw@1045
 | 
   377                                 ui.tag{
 | 
| 
bsw@1045
 | 
   378                                   tag = "input",
 | 
| 
bsw@1045
 | 
   379                                   attr = {
 | 
| 
bsw@1045
 | 
   380                                     onclick = "if (jsFail) return true; voting_moveUp(this.parentNode.parentNode); return(false);",
 | 
| 
bsw@1045
 | 
   381                                     name = "move_up_" .. tostring(initiative.id),
 | 
| 
bsw@1045
 | 
   382                                     class = not disabled and "clickable" or nil,
 | 
| 
bsw@1045
 | 
   383                                     type = "image",
 | 
| 
bsw@1045
 | 
   384                                     src = encode.url{ static = "icons/move_up.png" },
 | 
| 
bsw@1045
 | 
   385                                     alt = _"Move up"
 | 
| 
bsw@1045
 | 
   386                                   }
 | 
| 
bsw@1045
 | 
   387                                 }
 | 
| 
bsw@1045
 | 
   388                                 slot.put(" ")
 | 
| 
bsw@1045
 | 
   389                                 ui.tag{
 | 
| 
bsw@1045
 | 
   390                                   tag = "input",
 | 
| 
bsw@1045
 | 
   391                                   attr = {
 | 
| 
bsw@1045
 | 
   392                                     onclick = "if (jsFail) return true; voting_moveDown(this.parentNode.parentNode); return(false);",
 | 
| 
bsw@1045
 | 
   393                                     name = "move_down_" .. tostring(initiative.id),
 | 
| 
bsw@1045
 | 
   394                                     class = not disabled and "clickable" or nil,
 | 
| 
bsw@1045
 | 
   395                                     type = "image",
 | 
| 
bsw@1045
 | 
   396                                     src = encode.url{ static = "icons/move_down.png" },
 | 
| 
bsw@1045
 | 
   397                                     alt = _"Move down"
 | 
| 
bsw@286
 | 
   398                                   }
 | 
| 
bsw@286
 | 
   399                                 }
 | 
| 
bsw@1045
 | 
   400                                 slot.put(" ")
 | 
| 
bsw@1045
 | 
   401                               end
 | 
| 
bsw/jbe@19
 | 
   402                             }
 | 
| 
bsw/jbe@19
 | 
   403                           end
 | 
| 
bsw@1045
 | 
   404                           ui.container{
 | 
| 
bsw@1045
 | 
   405                             content = function()
 | 
| 
bsw@1045
 | 
   406                               ui.tag{ content = "i" .. initiative.id .. ": " }
 | 
| 
bsw@1045
 | 
   407                               ui.tag{ content = initiative.shortened_name }
 | 
| 
bsw@1045
 | 
   408                               slot.put("<br />")
 | 
| 
bsw@1045
 | 
   409                               for i, initiator in ipairs(initiators) do
 | 
| 
bsw@1045
 | 
   410                                 ui.link{
 | 
| 
bsw@1045
 | 
   411                                   attr = { class = "clickable" },
 | 
| 
bsw@1045
 | 
   412                                   content = function ()
 | 
| 
bsw@1045
 | 
   413                                     execute.view{
 | 
| 
bsw@1045
 | 
   414                                       module = "member_image",
 | 
| 
bsw@1045
 | 
   415                                       view = "_show",
 | 
| 
bsw@1045
 | 
   416                                       params = {
 | 
| 
bsw@1045
 | 
   417                                         member = initiator,
 | 
| 
bsw@1045
 | 
   418                                         image_type = "avatar",
 | 
| 
bsw@1045
 | 
   419                                         show_dummy = true,
 | 
| 
bsw@1045
 | 
   420                                         class = "micro_avatar",
 | 
| 
bsw@1045
 | 
   421                                         popup_text = text
 | 
| 
bsw@1045
 | 
   422                                       }
 | 
| 
bsw@1045
 | 
   423                                     }
 | 
| 
bsw@1045
 | 
   424                                   end,
 | 
| 
bsw@1045
 | 
   425                                   module = "member", view = "show", id = initiator.id
 | 
| 
bsw@1045
 | 
   426                                 }
 | 
| 
bsw@1045
 | 
   427                                 slot.put(" ")
 | 
| 
bsw@1045
 | 
   428                                 ui.tag{ content = initiator.name }
 | 
| 
bsw@1045
 | 
   429                                 slot.put(" ")
 | 
| 
bsw@1045
 | 
   430                               end
 | 
| 
bsw@1045
 | 
   431                             end
 | 
| 
bsw@1045
 | 
   432                           }
 | 
| 
bsw/jbe@19
 | 
   433                         end
 | 
| 
bsw/jbe@6
 | 
   434                       }
 | 
| 
bsw/jbe@6
 | 
   435                     end
 | 
| 
bsw@1045
 | 
   436                   end
 | 
| 
bsw@1045
 | 
   437                 }
 | 
| 
bsw@1045
 | 
   438               end
 | 
| 
bsw@1045
 | 
   439             end
 | 
| 
bsw@1045
 | 
   440           end
 | 
| 
bsw@1045
 | 
   441         }
 | 
| 
bsw@1045
 | 
   442         if app.session.member_id and preview then
 | 
| 
bsw@1045
 | 
   443           local formatting_engine = param.get("formatting_engine") or config.enforce_formatting_engine
 | 
| 
bsw@1045
 | 
   444           local comment = param.get("comment")
 | 
| 
bsw@1045
 | 
   445           if comment and #comment > 0 then
 | 
| 
bsw@1045
 | 
   446             local rendered_comment = format.wiki_text(comment, formatting_engine)
 | 
| 
bsw@1045
 | 
   447             ui.heading{ level = "2", content = _"Voting comment" }
 | 
| 
bsw@1045
 | 
   448             ui.container { attr = { class = "member_statement" }, content = function()
 | 
| 
bsw@1045
 | 
   449               slot.put(rendered_comment)
 | 
| 
bsw@1045
 | 
   450             end }
 | 
| 
bsw@1045
 | 
   451             slot.put("<br />")
 | 
| 
bsw@1045
 | 
   452           end
 | 
| 
bsw@1045
 | 
   453         end
 | 
| 
bsw@1045
 | 
   454         if (readonly or direct_voter and direct_voter.comment) and not preview and not (app.session.member_id == member.id) then
 | 
| 
bsw@1045
 | 
   455           local text
 | 
| 
bsw@1045
 | 
   456           if direct_voter and direct_voter.comment_changed then
 | 
| 
bsw@1045
 | 
   457             text = _("Voting comment (last updated: #{timestamp})", { timestamp = format.timestamp(direct_voter.comment_changed) })
 | 
| 
bsw@1045
 | 
   458           elseif direct_voter and direct_voter.comment then
 | 
| 
bsw@1045
 | 
   459             text = _"Voting comment"
 | 
| 
bsw@1045
 | 
   460           end
 | 
| 
bsw@1045
 | 
   461           if text then
 | 
| 
bsw@1045
 | 
   462             ui.heading{ level = "2", content = text }
 | 
| 
bsw@1045
 | 
   463           end
 | 
| 
bsw@1045
 | 
   464           if direct_voter and direct_voter.comment then
 | 
| 
bsw@1045
 | 
   465             local rendered_comment = direct_voter:get_content('html')
 | 
| 
bsw@1045
 | 
   466             ui.container { attr = { class = "member_statement" }, content = function()
 | 
| 
bsw@1045
 | 
   467               slot.put(rendered_comment)
 | 
| 
bsw@1045
 | 
   468             end }
 | 
| 
bsw@1045
 | 
   469             slot.put("<br />")
 | 
| 
bsw@1045
 | 
   470           end
 | 
| 
bsw@1045
 | 
   471         end
 | 
| 
bsw@1045
 | 
   472         if app.session.member_id and app.session.member_id == member.id then
 | 
| 
bsw@1045
 | 
   473           if (not readonly or direct_voter) and not preview then
 | 
| 
bsw@1045
 | 
   474             ui.container{ content = function()
 | 
| 
bsw@1045
 | 
   475               if not config.enforce_formatting_engine then
 | 
| 
bsw@1045
 | 
   476                 ui.field.select{
 | 
| 
bsw@1045
 | 
   477                   label = _"Wiki engine for statement",
 | 
| 
bsw@1045
 | 
   478                   name = "formatting_engine",
 | 
| 
bsw@1045
 | 
   479                   foreign_records = config.formatting_engines,
 | 
| 
bsw@1045
 | 
   480                   attr = {id = "formatting_engine"},
 | 
| 
bsw@1045
 | 
   481                   foreign_id = "id",
 | 
| 
bsw@1045
 | 
   482                   foreign_name = "name",
 | 
| 
bsw@1045
 | 
   483                   value = param.get("formatting_engine") or direct_voter and direct_voter.formatting_engine
 | 
| 
bsw@1045
 | 
   484                 }
 | 
| 
bsw@1045
 | 
   485               end
 | 
| 
bsw@1045
 | 
   486               ui.heading { level = 2, content = _"Voting comment (optional)" }
 | 
| 
bsw@1045
 | 
   487               ui.field.text{
 | 
| 
bsw@1045
 | 
   488                 name = "comment",
 | 
| 
bsw@1045
 | 
   489                 multiline = true,
 | 
| 
bsw@1045
 | 
   490                 value = param.get("comment") or direct_voter and direct_voter.comment,
 | 
| 
bsw@1045
 | 
   491                 attr = { style = "height: 10ex; width: 100%;" },
 | 
| 
bsw@1045
 | 
   492               }
 | 
| 
bsw@1045
 | 
   493             end }
 | 
| 
bsw@1045
 | 
   494           end
 | 
| 
bsw@1045
 | 
   495 
 | 
| 
bsw@1045
 | 
   496           if preview then
 | 
| 
bsw@1045
 | 
   497             if not config.enforce_formatting_engine then
 | 
| 
bsw@1045
 | 
   498               ui.field.hidden{ name = "formatting_engine", value = param.get("formatting_engine") }
 | 
| 
bsw@1045
 | 
   499             end
 | 
| 
bsw@1045
 | 
   500             ui.field.hidden{ name = "comment", value = param.get("comment") or direct_voter and direct_voter.comment }
 | 
| 
bsw@1045
 | 
   501           end
 | 
| 
bsw@1045
 | 
   502           
 | 
| 
bsw@1045
 | 
   503           if not readonly or direct_voter or preview then
 | 
| 
bsw@1045
 | 
   504             ui.container{ content = function()
 | 
| 
bsw@1045
 | 
   505               if preview  then
 | 
| 
bsw@1045
 | 
   506                 slot.put(" ")
 | 
| 
bsw@1045
 | 
   507                 ui.tag{
 | 
| 
bsw@1045
 | 
   508                   tag = "input",
 | 
| 
bsw@1045
 | 
   509                   attr = {
 | 
| 
bsw@1045
 | 
   510                     type = "submit",
 | 
| 
bsw@1045
 | 
   511                     class = "btn btn-default",
 | 
| 
bsw@1045
 | 
   512                     name = issue.closed and "update_comment" or nil,
 | 
| 
bsw@1045
 | 
   513                     value = submit_button_text -- finish voting / update comment
 | 
| 
bsw/jbe@19
 | 
   514                   }
 | 
| 
bsw@1045
 | 
   515                 }
 | 
| 
bsw/jbe@5
 | 
   516               end
 | 
| 
bsw@1045
 | 
   517               if not preview then
 | 
| 
bsw@1045
 | 
   518                 ui.tag{
 | 
| 
bsw@1045
 | 
   519                   tag = "input",
 | 
| 
bsw@1045
 | 
   520                   attr = {
 | 
| 
bsw@1045
 | 
   521                     type = "submit",
 | 
| 
bsw@1045
 | 
   522                     name = "preview",
 | 
| 
bsw@1045
 | 
   523                     class = "btn btn-default",
 | 
| 
bsw@1045
 | 
   524                     value = _"Preview",
 | 
| 
bsw@1045
 | 
   525                   }
 | 
| 
bsw@1045
 | 
   526                 }
 | 
| 
bsw@1045
 | 
   527               else
 | 
| 
bsw@1045
 | 
   528                 slot.put(" ")
 | 
| 
bsw@1045
 | 
   529                 ui.tag{
 | 
| 
bsw@1045
 | 
   530                   tag = "input",
 | 
| 
bsw@1045
 | 
   531                   attr = {
 | 
| 
bsw@1045
 | 
   532                     type = "submit",
 | 
| 
bsw@1045
 | 
   533                     name = "edit",
 | 
| 
bsw@1045
 | 
   534                     class = "btn-link",
 | 
| 
bsw@1045
 | 
   535                     value = edit_button_text,
 | 
| 
bsw@1045
 | 
   536                   }
 | 
| 
bsw@1045
 | 
   537                 }
 | 
| 
bsw@1045
 | 
   538               end
 | 
| 
bsw@1045
 | 
   539             end }
 | 
| 
bsw/jbe@19
 | 
   540           end
 | 
| 
bsw/jbe@5
 | 
   541         end
 | 
| 
bsw/jbe@5
 | 
   542       end
 | 
| 
bsw/jbe@5
 | 
   543     }
 | 
| 
bsw@1045
 | 
   544     slot.put("<br />")
 | 
| 
bsw@1045
 | 
   545     ui.link{
 | 
| 
bsw@1045
 | 
   546       text = _"Cancel",
 | 
| 
bsw@1045
 | 
   547       module = "issue",
 | 
| 
bsw@1045
 | 
   548       view = "show",
 | 
| 
bsw@1045
 | 
   549       id = issue.id
 | 
| 
bsw@1045
 | 
   550     }
 | 
| 
bsw@1045
 | 
   551     if direct_voter then
 | 
| 
bsw@1045
 | 
   552       slot.put(" | ")
 | 
| 
bsw@1045
 | 
   553       ui.link {
 | 
| 
bsw@1045
 | 
   554         module = "vote", action = "update",
 | 
| 
bsw@1045
 | 
   555         params = {
 | 
| 
bsw@1045
 | 
   556           issue_id = issue.id,
 | 
| 
bsw@1045
 | 
   557           discard = true
 | 
| 
bsw@1045
 | 
   558         },
 | 
| 
bsw@1045
 | 
   559         routing = {
 | 
| 
bsw@1045
 | 
   560           default = {
 | 
| 
bsw@1045
 | 
   561             mode = "redirect",
 | 
| 
bsw@1045
 | 
   562             module = "issue",
 | 
| 
bsw@1045
 | 
   563             view = "show",
 | 
| 
bsw@1045
 | 
   564             id = issue.id
 | 
| 
bsw@1045
 | 
   565           }
 | 
| 
bsw@1045
 | 
   566         },
 | 
| 
bsw@1045
 | 
   567         text = _"Discard my vote"
 | 
| 
bsw@1045
 | 
   568       }
 | 
| 
bsw@879
 | 
   569     end
 | 
| 
bsw/jbe@5
 | 
   570 
 | 
| 
bsw@1045
 | 
   571   end )
 | 
| 
bsw@1045
 | 
   572 end ) |