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