bsw/jbe@19: local issue = Issue:by_id(param.get("issue_id"), atom.integer)
bsw/jbe@19: 
bsw/jbe@19: local member_id = param.get("member_id", atom.integer)
bsw/jbe@19: local member
jbe@945: local readonly = false
bsw/jbe@19: 
jbe@950: local preview = param.get("preview") and true or false
poelzi@156: 
bsw/jbe@19: if member_id then
bsw/jbe@19:   if not issue.closed then
bsw/jbe@19:     error("access denied")
bsw/jbe@19:   end
bsw/jbe@19:   member = Member:by_id(member_id)
bsw/jbe@19:   readonly = true
bsw/jbe@19: end
bsw/jbe@19: 
poelzi@138: if issue.closed then
poelzi@156:   if not member then
poelzi@158:     member = app.session.member
poelzi@158:   end
poelzi@156:   readonly = true
poelzi@138: end
poelzi@138: 
bsw@879: local submit_button_text = _"Finish voting"
bsw@879: 
bsw@879: if issue.closed then
bsw@879:   submit_button_text = _"Update voting comment"
bsw@879: end
bsw@879: 
bsw@879: local direct_voter
bsw@879: 
bsw/jbe@19: if member then
bsw@879:   direct_voter = DirectVoter:by_pk(issue.id, member.id)
poelzi@156:   local str = _("Ballot of '#{member_name}' for issue ##{issue_id}",
poelzi@156:                   {member_name = string.format('%s',
poelzi@156:                                           encode.url{
poelzi@156:                                             module    = "member",
poelzi@156:                                             view      = "show",
poelzi@156:                                             id        = member.id,
poelzi@156:                                           },
poelzi@156:                                           encode.html(member.name)),
poelzi@156:                    issue_id = string.format('%s',
poelzi@156:                                           encode.url{
poelzi@156:                                             module    = "issue",
poelzi@156:                                             view      = "show",
poelzi@156:                                             id        = issue.id,
poelzi@156:                                           },
poelzi@156:                                           encode.html(tostring(issue.id)))
poelzi@156:                   }
poelzi@156:               )
bsw@880:   ui.raw_title(str)
bsw/jbe@19: else
bsw/jbe@19:   member = app.session.member
bsw@879: 
bsw@879:   direct_voter = DirectVoter:by_pk(issue.id, member.id)
bsw@879: 
bsw@604:   ui.title(_"Voting")
bsw/jbe@19: 
bsw@604:   ui.actions(function()
bsw/jbe@19:     ui.link{
bsw@604:       text = _"Cancel",
bsw/jbe@19:       module = "issue",
bsw/jbe@19:       view = "show",
bsw/jbe@19:       id = issue.id
bsw/jbe@19:     }
bsw@879:     if direct_voter then
bsw@879:       slot.put(" · ")
bsw@879:       ui.link{
bsw@879:         text = _"Discard voting",
bsw@879:         module = "vote",
bsw@879:         action = "update",
bsw@879:         params = {
bsw@879:           issue_id = issue.id,
bsw@879:           discard = true
bsw@879:         },
bsw@879:         routing = {
bsw@879:           default = {
bsw@879:             mode = "redirect",
bsw@879:             module = "issue",
bsw@879:             view = "show",
bsw@879:             id = issue.id
bsw@879:           }
bsw@26:         }
bsw@26:       }
bsw@879:     end
bsw/jbe@19:   end)
bsw/jbe@19: end
bsw/jbe@19: 
bsw/jbe@19: 
bsw@879: 
bsw/jbe@19: local tempvoting_string = param.get("scoring")
bsw/jbe@19: 
bsw/jbe@19: local tempvotings = {}
bsw/jbe@19: if tempvoting_string then
bsw/jbe@19:   for match in tempvoting_string:gmatch("([^;]+)") do
bsw/jbe@19:     for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do
bsw/jbe@19:       tempvotings[tonumber(initiative_id)] = tonumber(grade)
bsw/jbe@19:     end
bsw/jbe@5:   end
bsw/jbe@19: end
bsw/jbe@5: 
bsw@95: local initiatives = issue:get_reference_selector("initiatives"):add_where("initiative.admitted"):add_order_by("initiative.satisfied_supporter_count DESC"):exec()
bsw/jbe@5: 
bsw/jbe@5: local min_grade = -1;
bsw/jbe@5: local max_grade = 1;
bsw/jbe@5: 
bsw/jbe@5: for i, initiative in ipairs(initiatives) do
bsw/jbe@5:   -- TODO performance
bsw/jbe@19:   initiative.vote = Vote:by_pk(initiative.id, member.id)
bsw/jbe@19:   if tempvotings[initiative.id] then
bsw/jbe@19:     initiative.vote = {}
bsw/jbe@19:     initiative.vote.grade = tempvotings[initiative.id]
bsw/jbe@19:   end
bsw/jbe@5:   if initiative.vote then
bsw/jbe@5:     if initiative.vote.grade > max_grade then
bsw/jbe@5:       max_grade = initiative.vote.grade
bsw/jbe@5:     end
bsw/jbe@5:     if initiative.vote.grade < min_grade then
bsw/jbe@5:       min_grade = initiative.vote.grade
bsw/jbe@5:     end
bsw/jbe@5:   end
bsw/jbe@5: end
bsw/jbe@5: 
bsw/jbe@5: local sections = {}
bsw/jbe@5: for i = min_grade, max_grade do
bsw/jbe@5:   sections[i] = {}
bsw/jbe@5:   for j, initiative in ipairs(initiatives) do
bsw/jbe@5:     if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then
bsw/jbe@5:       sections[i][#(sections[i])+1] = initiative
bsw/jbe@5:     end
bsw/jbe@5:   end
bsw/jbe@5: end
bsw/jbe@5: 
bsw/jbe@19: local approval_count, disapproval_count = 0, 0
bsw/jbe@19: for i = min_grade, -1 do
bsw/jbe@19:   if #sections[i] > 0 then
bsw/jbe@19:     disapproval_count = disapproval_count + 1
bsw/jbe@19:   end
bsw/jbe@19: end
bsw/jbe@19: local approval_count = 0
bsw/jbe@19: for i = 1, max_grade do
bsw/jbe@19:   if #sections[i] > 0 then
bsw/jbe@19:     approval_count = approval_count + 1
bsw/jbe@19:   end
bsw/jbe@19: end
bsw/jbe@5: 
bsw/jbe@5: 
bsw/jbe@5: 
bsw/jbe@19: if not readonly then
bsw/jbe@19:   util.help("vote.list", _"Voting")
bsw/jbe@19:   slot.put('')
bsw/jbe@19:   slot.put('')
bsw/jbe@19: end
bsw/jbe@19: 
bsw/jbe@19: ui.script{
bsw/jbe@19:   script = function()
bsw/jbe@19:     slot.put(
bsw/jbe@19:       "voting_text_approval_single               = ", encode.json(_"Approval [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_approval_multi                = ", encode.json(_"Approval [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_first_preference_single       = ", encode.json(_"Approval (first preference) [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_first_preference_multi        = ", encode.json(_"Approval (first preference) [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_second_preference_single      = ", encode.json(_"Approval (second preference) [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_second_preference_multi       = ", encode.json(_"Approval (second preference) [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_third_preference_single       = ", encode.json(_"Approval (third preference) [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_third_preference_multi        = ", encode.json(_"Approval (third preference) [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_numeric_preference_single     = ", encode.json(_"Approval (#th preference) [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_numeric_preference_multi      = ", encode.json(_"Approval (#th preference) [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_abstention_single             = ", encode.json(_"Abstention [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_abstention_multi              = ", encode.json(_"Abstention [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_disapproval_above_one_single  = ", encode.json(_"Disapproval (prefer to lower block) [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_disapproval_above_one_multi   = ", encode.json(_"Disapproval (prefer to lower block) [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_disapproval_above_many_single = ", encode.json(_"Disapproval (prefer to lower blocks) [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_disapproval_above_many_multi  = ", encode.json(_"Disapproval (prefer to lower blocks) [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_disapproval_above_last_single = ", encode.json(_"Disapproval (prefer to last block) [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_disapproval_above_last_multi  = ", encode.json(_"Disapproval (prefer to last block) [many entries]"), ";\n",
bsw/jbe@19:       "voting_text_disapproval_single            = ", encode.json(_"Disapproval [single entry]"), ";\n",
bsw/jbe@19:       "voting_text_disapproval_multi             = ", encode.json(_"Disapproval [many entries]"), ";\n"
bsw/jbe@19:     )
bsw/jbe@19:   end
bsw/jbe@19: }
bsw/jbe@5: 
bsw/jbe@5: ui.form{
bsw@879:   record = direct_voter,
bsw/jbe@19:   attr = {
bsw/jbe@19:     id = "voting_form",
bsw/jbe@19:     class = readonly and "voting_form_readonly" or "voting_form_active"
bsw/jbe@19:   },
bsw/jbe@5:   module = "vote",
bsw/jbe@5:   action = "update",
bsw/jbe@5:   params = { issue_id = issue.id },
bsw/jbe@5:   content = function()
bsw@879:     if not readonly or preview then
bsw/jbe@19:       local scoring = param.get("scoring")
bsw/jbe@19:       if not scoring then
bsw/jbe@19:         for i, initiative in ipairs(initiatives) do
bsw/jbe@19:           local vote = initiative.vote
bsw/jbe@19:           if vote then
bsw/jbe@19:             tempvotings[initiative.id] = vote.grade
bsw@522:           else
bsw@522:             tempvotings[initiative.id] = 0
bsw/jbe@19:           end
bsw/jbe@19:         end
bsw/jbe@19:         local tempvotings_list = {}
bsw/jbe@19:         for key, val in pairs(tempvotings) do
bsw/jbe@19:           tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val)
bsw/jbe@19:         end
bsw/jbe@19:         if #tempvotings_list > 0 then
bsw/jbe@19:           scoring = table.concat(tempvotings_list, ";")
bsw/jbe@19:         else
bsw/jbe@19:           scoring = ""
bsw/jbe@19:         end
bsw/jbe@19:       end
bsw/jbe@19:       slot.put('')
bsw/jbe@19:       -- TODO abstrahieren
bsw/jbe@19:       ui.tag{
bsw/jbe@19:         tag = "input",
bsw/jbe@19:         attr = {
bsw@86:           type = "submit",
bsw@879:           class = "voting_done1",
bsw@879:           value = submit_button_text
bsw/jbe@19:         }
bsw/jbe@5:       }
bsw/jbe@19:     end
bsw/jbe@5:     ui.container{
bsw/jbe@5:       attr = { id = "voting" },
bsw/jbe@5:       content = function()
bsw/jbe@19:         local approval_index, disapproval_index = 0, 0
bsw/jbe@5:         for grade = max_grade, min_grade, -1 do 
bsw/jbe@19:           local entries = sections[grade]
bsw/jbe@5:           local class
bsw/jbe@5:           if grade > 0 then
bsw/jbe@5:             class = "approval"
bsw/jbe@5:           elseif grade < 0 then
bsw/jbe@5:             class = "disapproval"
bsw/jbe@5:           else
bsw/jbe@5:             class = "abstention"
bsw/jbe@5:           end
bsw/jbe@19:           if
bsw/jbe@19:             #entries > 0 or
bsw/jbe@19:             (grade == 1 and not approval_used) or
bsw/jbe@19:             (grade == -1 and not disapproval_used) or
bsw/jbe@19:             grade == 0
bsw/jbe@19:           then
bsw/jbe@19:             ui.container{
bsw/jbe@19:               attr = { class = class },
bsw/jbe@19:               content = function()
bsw/jbe@19:                 local heading
bsw/jbe@19:                 if class == "approval" then
bsw/jbe@19:                   approval_used = true
bsw/jbe@19:                   approval_index = approval_index + 1
bsw/jbe@19:                   if approval_count > 1 then
bsw/jbe@19:                     if approval_index == 1 then
bsw/jbe@19:                       if #entries == 1 then
bsw/jbe@19:                         heading = _"Approval (first preference) [single entry]"
bsw/jbe@19:                       else
bsw/jbe@19:                         heading = _"Approval (first preference) [many entries]"
bsw/jbe@19:                       end
bsw/jbe@19:                     elseif approval_index == 2 then
bsw/jbe@19:                       if #entries == 1 then
bsw/jbe@19:                         heading = _"Approval (second preference) [single entry]"
bsw/jbe@19:                       else
bsw/jbe@19:                         heading = _"Approval (second preference) [many entries]"
bsw/jbe@19:                       end
bsw/jbe@19:                     elseif approval_index == 3 then
bsw/jbe@19:                       if #entries == 1 then
bsw/jbe@19:                         heading = _"Approval (third preference) [single entry]"
bsw/jbe@19:                       else
bsw/jbe@19:                         heading = _"Approval (third preference) [many entries]"
bsw/jbe@19:                       end
bsw/jbe@19:                     else
bsw/jbe@19:                       if #entries == 1 then
bsw/jbe@19:                         heading = _"Approval (#th preference) [single entry]"
bsw/jbe@19:                       else
bsw/jbe@19:                         heading = _"Approval (#th preference) [many entries]"
bsw/jbe@19:                       end
bsw/jbe@19:                     end
bsw/jbe@19:                   else
bsw/jbe@19:                     if #entries == 1 then
bsw/jbe@19:                       heading = _"Approval [single entry]"
bsw/jbe@19:                     else
bsw/jbe@19:                       heading = _"Approval [many entries]"
bsw/jbe@19:                     end
bsw/jbe@19:                   end
bsw/jbe@19:                 elseif class == "abstention" then
bsw/jbe@19:                     if #entries == 1 then
bsw/jbe@19:                       heading = _"Abstention [single entry]"
bsw/jbe@19:                     else
bsw/jbe@19:                       heading = _"Abstention [many entries]"
bsw/jbe@19:                     end
bsw/jbe@19:                 elseif class == "disapproval" then
bsw/jbe@19:                   disapproval_used = true
bsw/jbe@19:                   disapproval_index = disapproval_index + 1
bsw/jbe@19:                   if disapproval_count > disapproval_index + 1 then
bsw/jbe@19:                     if #entries == 1 then
bsw/jbe@19:                       heading = _"Disapproval (prefer to lower blocks) [single entry]"
bsw/jbe@19:                     else
bsw/jbe@19:                       heading = _"Disapproval (prefer to lower blocks) [many entries]"
bsw/jbe@19:                     end
bsw/jbe@19:                   elseif disapproval_count == 2 and disapproval_index == 1 then
bsw/jbe@19:                     if #entries == 1 then
bsw/jbe@19:                       heading = _"Disapproval (prefer to lower block) [single entry]"
bsw/jbe@19:                     else
bsw/jbe@19:                       heading = _"Disapproval (prefer to lower block) [many entries]"
bsw/jbe@19:                     end
bsw/jbe@19:                   elseif disapproval_index == disapproval_count - 1 then
bsw/jbe@19:                     if #entries == 1 then
bsw/jbe@19:                       heading = _"Disapproval (prefer to last block) [single entry]"
bsw/jbe@19:                     else
bsw/jbe@19:                       heading = _"Disapproval (prefer to last block) [many entries]"
bsw/jbe@19:                     end
bsw/jbe@19:                   else
bsw/jbe@19:                     if #entries == 1 then
bsw/jbe@19:                       heading = _"Disapproval [single entry]"
bsw/jbe@19:                     else
bsw/jbe@19:                       heading = _"Disapproval [many entries]"
bsw/jbe@6:                     end
bsw/jbe@19:                   end
bsw/jbe@19:                 end
bsw/jbe@19:                 ui.tag {
bsw/jbe@19:                   tag     = "div",
bsw/jbe@19:                   attr    = { class = "cathead" },
bsw/jbe@19:                   content = heading
bsw/jbe@19:                 }
bsw/jbe@19:                 for i, initiative in ipairs(entries) do
bsw/jbe@19:                   ui.container{
bsw/jbe@19:                     attr = {
bsw/jbe@19:                       class = "movable",
bsw/jbe@19:                       id = "entry_" .. tostring(initiative.id)
bsw/jbe@19:                     },
bsw/jbe@19:                     content = function()
bsw/jbe@19:                       local initiators_selector = initiative:get_reference_selector("initiating_members")
bsw/jbe@19:                         :add_where("accepted")
bsw/jbe@19:                       local initiators = initiators_selector:exec()
bsw/jbe@19:                       local initiator_names = {}
bsw/jbe@19:                       for i, initiator in ipairs(initiators) do
bsw/jbe@19:                         initiator_names[#initiator_names+1] = initiator.name
bsw/jbe@19:                       end
bsw/jbe@19:                       local initiator_names_string = table.concat(initiator_names, ", ")
bsw/jbe@19:                       ui.container{
bsw@519:                         attr = { style = "float: right; position: relative;" },
bsw/jbe@19:                         content = function()
bsw/jbe@19:                           ui.link{
bsw/jbe@19:                             attr = { class = "clickable" },
bsw/jbe@19:                             content = _"Show",
bsw/jbe@19:                             module = "initiative",
bsw/jbe@19:                             view = "show",
bsw/jbe@19:                             id = initiative.id
bsw/jbe@19:                           }
bsw/jbe@19:                           slot.put(" ")
bsw/jbe@19:                           ui.link{
bsw/jbe@19:                             attr = { class = "clickable", target = "_blank" },
bsw/jbe@19:                             content = _"(new window)",
bsw/jbe@19:                             module = "initiative",
bsw/jbe@19:                             view = "show",
bsw/jbe@19:                             id = initiative.id
bsw/jbe@19:                           }
bsw/jbe@19:                           if not readonly then
bsw/jbe@19:                             slot.put(" ")
bsw/jbe@19:                             ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" }
bsw/jbe@19:                           end
bsw/jbe@19:                         end
bsw/jbe@19:                       }
bsw/jbe@19:                       if not readonly then
bsw/jbe@19:                         ui.container{
bsw@519:                           attr = { style = "float: left; position: relative;" },
bsw/jbe@19:                           content = function()
bsw/jbe@19:                             ui.tag{
bsw/jbe@19:                               tag = "input",
bsw/jbe@19:                               attr = {
bsw@519:                                 onclick = "if (jsFail) return true; voting_moveUp(this.parentNode.parentNode); return(false);",
bsw@519:                                 name = "move_up_" .. tostring(initiative.id),
bsw/jbe@19:                                 class = not disabled and "clickable" or nil,
bsw/jbe@19:                                 type = "image",
bsw/jbe@19:                                 src = encode.url{ static = "icons/move_up.png" },
bsw/jbe@19:                                 alt = _"Move up"
bsw/jbe@19:                               }
bsw/jbe@19:                             }
bsw/jbe@19:                             slot.put(" ")
bsw/jbe@19:                             ui.tag{
bsw/jbe@19:                               tag = "input",
bsw/jbe@19:                               attr = {
bsw@519:                                 onclick = "if (jsFail) return true; voting_moveDown(this.parentNode.parentNode); return(false);",
bsw@519:                                 name = "move_down_" .. tostring(initiative.id),
bsw/jbe@19:                                 class = not disabled and "clickable" or nil,
bsw/jbe@19:                                 type = "image",
bsw/jbe@19:                                 src = encode.url{ static = "icons/move_down.png" },
bsw/jbe@19:                                 alt = _"Move down"
bsw/jbe@19:                               }
bsw/jbe@19:                             }
bsw/jbe@19:                             slot.put(" ")
bsw/jbe@19:                           end
bsw/jbe@6:                         }
bsw/jbe@6:                       end
bsw/jbe@6:                       ui.container{
bsw/jbe@19:                         content = function()
bsw@285:                           ui.tag{ content = "i" .. initiative.id .. ": " }
bsw@285:                           ui.tag{ content = initiative.shortened_name }
bsw@286:                           slot.put("
")
bsw@286:                           for i, initiator in ipairs(initiators) do
bsw@286:                             ui.link{
bsw@286:                               attr = { class = "clickable" },
bsw@286:                               content = function ()
bsw@286:                                 execute.view{
bsw@286:                                   module = "member_image",
bsw@286:                                   view = "_show",
bsw@286:                                   params = {
bsw@286:                                     member = initiator,
bsw@286:                                     image_type = "avatar",
bsw@286:                                     show_dummy = true,
bsw@286:                                     class = "micro_avatar",
bsw@286:                                     popup_text = text
bsw@286:                                   }
bsw@286:                                 }
bsw@286:                               end,
bsw@286:                               module = "member", view = "show", id = initiator.id
bsw/jbe@19:                             }
bsw@286:                             slot.put(" ")
bsw@290:                             ui.tag{ content = initiator.name }
bsw@286:                             slot.put(" ")
bsw/jbe@19:                           end
bsw/jbe@19:                         end
bsw/jbe@6:                       }
bsw/jbe@6:                     end
bsw/jbe@19:                   }
bsw/jbe@19:                 end
bsw/jbe@5:               end
bsw/jbe@19:             }
bsw/jbe@19:           end
bsw/jbe@5:         end
bsw/jbe@5:       end
bsw/jbe@5:     }
bsw@879:     if app.session.member_id and preview then
bsw@879:       local formatting_engine = param.get("formatting_engine")
bsw@879:       local comment = param.get("comment")
bsw@879:       local rendered_comment = format.wiki_text(comment, formatting_engine)
bsw@879:       slot.put(rendered_comment)
bsw@879:     end
bsw@885:     if (readonly or direct_voter and direct_voter.comment) and not preview then
bsw@880:       local text
bsw@881:       if direct_voter and direct_voter.comment_changed then
bsw@880:         text = _("Voting comment (last updated: #{timestamp})", { timestamp = format.timestamp(direct_voter.comment_changed) })
bsw@881:       elseif direct_voter and direct_voter.comment then
bsw@880:         text = _"Voting comment"
bsw@880:       end
bsw@881:       if text then
bsw@880:         ui.heading{ level = "2", content = text }
bsw@881:       end
bsw@881:       if direct_voter and direct_voter.comment then
bsw@879:         local rendered_comment = direct_voter:get_content('html')
bsw@879:         ui.container{ attr = { class = "member_statement" }, content = function()
bsw@879:           slot.put(rendered_comment)
bsw@879:         end }
bsw@879:         slot.put("
")
bsw@879:       end
bsw@879:     end
bsw@879:     if app.session.member_id and app.session.member_id == member.id then
bsw@879:       if not readonly or direct_voter then
bsw@879:         ui.field.hidden{ name = "update_comment", value = param.get("update_comment") or issue.closed and "1" }
bsw@879:         ui.field.select{
bsw@879:           label = _"Wiki engine for statement",
bsw@879:           name = "formatting_engine",
bsw@879:           foreign_records = {
bsw@879:             { id = "rocketwiki", name = "RocketWiki" },
bsw@879:             { id = "compat", name = _"Traditional wiki syntax" }
bsw@879:           },
bsw@879:           attr = {id = "formatting_engine"},
bsw@879:           foreign_id = "id",
bsw@879:           foreign_name = "name",
bsw@879:           value = param.get("formatting_engine") or direct_voter and direct_voter.formatting_engine
bsw/jbe@19:         }
bsw@879:         ui.field.text{
bsw@879:           label = _"Voting comment (optional)",
bsw@879:           name = "comment",
bsw@879:           multiline = true,
bsw@879:           value = param.get("comment") or direct_voter and direct_voter.comment,
bsw@879:           attr = { style = "height: 20ex;" },
bsw@879:         }
bsw@879:         ui.submit{
bsw@879:           name = "preview",
bsw@879:           value = _"Preview voting comment",
bsw@879:           attr = { class = "preview" }
bsw@879:         }
bsw@879:       end
bsw@879:       if not readonly or preview or direct_voter then
bsw@879:         slot.put(" ")
bsw@879:         ui.tag{
bsw@879:           tag = "input",
bsw@879:           attr = {
bsw@879:             type = "submit",
bsw@879:             class = "voting_done2",
bsw@879:             value = submit_button_text
bsw@879:           }
bsw@879:         }
bsw@879:       end
bsw/jbe@19:     end
bsw/jbe@5:   end
bsw/jbe@5: }
bsw/jbe@5: 
bsw/jbe@5: