liquid_feedback_frontend
view app/main/vote/list.lua @ 58:29caccea23cb
Icon static/icons/16/bell.png added
| author | bsw | 
|---|---|
| date | Sun Apr 18 18:19:58 2010 +0200 (2010-04-18) | 
| parents | 3036f2732b83 | 
| children | 1f1f8c78ba3a | 
 line source
     1 local issue = Issue:by_id(param.get("issue_id"), atom.integer)
     3 local member_id = param.get("member_id", atom.integer)
     4 local member
     6 local readonly = false
     7 if member_id then
     8   if not issue.closed then
     9     error("access denied")
    10   end
    11   member = Member:by_id(member_id)
    12   readonly = true
    13 end
    15 if member then
    16   slot.put_into("title", _("Ballot of '#{member_name}' for issue ##{issue_id}", {
    17     member_name = member.name,
    18     issue_id = issue.id
    19   }))
    20 else
    21   member = app.session.member
    22   slot.put_into("title", _"Voting")
    24   slot.select("actions", function()
    25     ui.link{
    26       content = function()
    27           ui.image{ static = "icons/16/cancel.png" }
    28           slot.put(_"Cancel")
    29       end,
    30       module = "issue",
    31       view = "show",
    32       id = issue.id
    33     }
    34     ui.link{
    35       content = function()
    36           ui.image{ static = "icons/16/email_delete.png" }
    37           slot.put(_"Discard voting")
    38       end,
    39       module = "vote",
    40       action = "update",
    41       params = {
    42         issue_id = issue.id,
    43         discard = true
    44       },
    45       routing = {
    46         default = {
    47           mode = "redirect",
    48           module = "issue",
    49           view = "show",
    50           id = issue.id
    51         }
    52       }
    53     }
    54   end)
    55 end
    58 local warning_text = _"Some JavaScript based functions (voting in particular) will not work.\nFor this beta, please use a current version of Firefox, Safari, Opera(?), Konqueror or another (more) standard compliant browser.\nAlternative access without JavaScript will be available soon."
    60 ui.script{ static = "js/browser_warning.js" }
    61 ui.script{ script = "checkBrowser(" .. encode.json(_"Your web browser is not fully supported yet." .. " " .. warning_text:gsub("\n", "\n\n")) .. ");" }
    64 local tempvoting_string = param.get("scoring")
    66 local tempvotings = {}
    67 if tempvoting_string then
    68   for match in tempvoting_string:gmatch("([^;]+)") do
    69     for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do
    70       tempvotings[tonumber(initiative_id)] = tonumber(grade)
    71     end
    72   end
    73 end
    75 local initiatives = issue:get_reference_selector("initiatives"):add_where("initiative.admitted"):exec()
    77 local min_grade = -1;
    78 local max_grade = 1;
    80 for i, initiative in ipairs(initiatives) do
    81   -- TODO performance
    82   initiative.vote = Vote:by_pk(initiative.id, member.id)
    83   if tempvotings[initiative.id] then
    84     initiative.vote = {}
    85     initiative.vote.grade = tempvotings[initiative.id]
    86   end
    87   if initiative.vote then
    88     if initiative.vote.grade > max_grade then
    89       max_grade = initiative.vote.grade
    90     end
    91     if initiative.vote.grade < min_grade then
    92       min_grade = initiative.vote.grade
    93     end
    94   end
    95 end
    97 local sections = {}
    98 for i = min_grade, max_grade do
    99   sections[i] = {}
   100   for j, initiative in ipairs(initiatives) do
   101     if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then
   102       sections[i][#(sections[i])+1] = initiative
   103     end
   104   end
   105 end
   107 local approval_count, disapproval_count = 0, 0
   108 for i = min_grade, -1 do
   109   if #sections[i] > 0 then
   110     disapproval_count = disapproval_count + 1
   111   end
   112 end
   113 local approval_count = 0
   114 for i = 1, max_grade do
   115   if #sections[i] > 0 then
   116     approval_count = approval_count + 1
   117   end
   118 end
   122 if not readonly then
   123   util.help("vote.list", _"Voting")
   124   slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/dragdrop.js"></script>')
   125   slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/voting.js"></script>')
   126 end
   128 ui.script{
   129   script = function()
   130     slot.put(
   131       "voting_text_approval_single               = ", encode.json(_"Approval [single entry]"), ";\n",
   132       "voting_text_approval_multi                = ", encode.json(_"Approval [many entries]"), ";\n",
   133       "voting_text_first_preference_single       = ", encode.json(_"Approval (first preference) [single entry]"), ";\n",
   134       "voting_text_first_preference_multi        = ", encode.json(_"Approval (first preference) [many entries]"), ";\n",
   135       "voting_text_second_preference_single      = ", encode.json(_"Approval (second preference) [single entry]"), ";\n",
   136       "voting_text_second_preference_multi       = ", encode.json(_"Approval (second preference) [many entries]"), ";\n",
   137       "voting_text_third_preference_single       = ", encode.json(_"Approval (third preference) [single entry]"), ";\n",
   138       "voting_text_third_preference_multi        = ", encode.json(_"Approval (third preference) [many entries]"), ";\n",
   139       "voting_text_numeric_preference_single     = ", encode.json(_"Approval (#th preference) [single entry]"), ";\n",
   140       "voting_text_numeric_preference_multi      = ", encode.json(_"Approval (#th preference) [many entries]"), ";\n",
   141       "voting_text_abstention_single             = ", encode.json(_"Abstention [single entry]"), ";\n",
   142       "voting_text_abstention_multi              = ", encode.json(_"Abstention [many entries]"), ";\n",
   143       "voting_text_disapproval_above_one_single  = ", encode.json(_"Disapproval (prefer to lower block) [single entry]"), ";\n",
   144       "voting_text_disapproval_above_one_multi   = ", encode.json(_"Disapproval (prefer to lower block) [many entries]"), ";\n",
   145       "voting_text_disapproval_above_many_single = ", encode.json(_"Disapproval (prefer to lower blocks) [single entry]"), ";\n",
   146       "voting_text_disapproval_above_many_multi  = ", encode.json(_"Disapproval (prefer to lower blocks) [many entries]"), ";\n",
   147       "voting_text_disapproval_above_last_single = ", encode.json(_"Disapproval (prefer to last block) [single entry]"), ";\n",
   148       "voting_text_disapproval_above_last_multi  = ", encode.json(_"Disapproval (prefer to last block) [many entries]"), ";\n",
   149       "voting_text_disapproval_single            = ", encode.json(_"Disapproval [single entry]"), ";\n",
   150       "voting_text_disapproval_multi             = ", encode.json(_"Disapproval [many entries]"), ";\n"
   151     )
   152   end
   153 }
   155 ui.form{
   156   attr = {
   157     id = "voting_form",
   158     class = readonly and "voting_form_readonly" or "voting_form_active"
   159   },
   160   module = "vote",
   161   action = "update",
   162   params = { issue_id = issue.id },
   163   routing = {
   164     default = {
   165       mode = "redirect",
   166       module = "issue",
   167       view = "show",
   168       id = issue.id
   169     }
   170   },
   171   content = function()
   172     if not readonly then
   173       local scoring = param.get("scoring")
   174       if not scoring then
   175         for i, initiative in ipairs(initiatives) do
   176           local vote = initiative.vote
   177           if vote then
   178             tempvotings[initiative.id] = vote.grade
   179           end
   180         end
   181         local tempvotings_list = {}
   182         for key, val in pairs(tempvotings) do
   183           tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val)
   184         end
   185         if #tempvotings_list > 0 then
   186           scoring = table.concat(tempvotings_list, ";")
   187         else
   188           scoring = ""
   189         end
   190       end
   191       slot.put('<input type="hidden" name="scoring" value="' .. scoring .. '"/>')
   192       -- TODO abstrahieren
   193       ui.tag{
   194         tag = "input",
   195         attr = {
   196           type = "button",
   197           class = "voting_done",
   198           value = _"Finish voting"
   199         }
   200       }
   201     end
   202     ui.container{
   203       attr = { id = "voting" },
   204       content = function()
   205         local approval_index, disapproval_index = 0, 0
   206         for grade = max_grade, min_grade, -1 do 
   207           local entries = sections[grade]
   208           local class
   209           if grade > 0 then
   210             class = "approval"
   211           elseif grade < 0 then
   212             class = "disapproval"
   213           else
   214             class = "abstention"
   215           end
   216           if
   217             #entries > 0 or
   218             (grade == 1 and not approval_used) or
   219             (grade == -1 and not disapproval_used) or
   220             grade == 0
   221           then
   222             ui.container{
   223               attr = { class = class },
   224               content = function()
   225                 local heading
   226                 if class == "approval" then
   227                   approval_used = true
   228                   approval_index = approval_index + 1
   229                   if approval_count > 1 then
   230                     if approval_index == 1 then
   231                       if #entries == 1 then
   232                         heading = _"Approval (first preference) [single entry]"
   233                       else
   234                         heading = _"Approval (first preference) [many entries]"
   235                       end
   236                     elseif approval_index == 2 then
   237                       if #entries == 1 then
   238                         heading = _"Approval (second preference) [single entry]"
   239                       else
   240                         heading = _"Approval (second preference) [many entries]"
   241                       end
   242                     elseif approval_index == 3 then
   243                       if #entries == 1 then
   244                         heading = _"Approval (third preference) [single entry]"
   245                       else
   246                         heading = _"Approval (third preference) [many entries]"
   247                       end
   248                     else
   249                       if #entries == 1 then
   250                         heading = _"Approval (#th preference) [single entry]"
   251                       else
   252                         heading = _"Approval (#th preference) [many entries]"
   253                       end
   254                     end
   255                   else
   256                     if #entries == 1 then
   257                       heading = _"Approval [single entry]"
   258                     else
   259                       heading = _"Approval [many entries]"
   260                     end
   261                   end
   262                 elseif class == "abstention" then
   263                     if #entries == 1 then
   264                       heading = _"Abstention [single entry]"
   265                     else
   266                       heading = _"Abstention [many entries]"
   267                     end
   268                 elseif class == "disapproval" then
   269                   disapproval_used = true
   270                   disapproval_index = disapproval_index + 1
   271                   if disapproval_count > disapproval_index + 1 then
   272                     if #entries == 1 then
   273                       heading = _"Disapproval (prefer to lower blocks) [single entry]"
   274                     else
   275                       heading = _"Disapproval (prefer to lower blocks) [many entries]"
   276                     end
   277                   elseif disapproval_count == 2 and disapproval_index == 1 then
   278                     if #entries == 1 then
   279                       heading = _"Disapproval (prefer to lower block) [single entry]"
   280                     else
   281                       heading = _"Disapproval (prefer to lower block) [many entries]"
   282                     end
   283                   elseif disapproval_index == disapproval_count - 1 then
   284                     if #entries == 1 then
   285                       heading = _"Disapproval (prefer to last block) [single entry]"
   286                     else
   287                       heading = _"Disapproval (prefer to last block) [many entries]"
   288                     end
   289                   else
   290                     if #entries == 1 then
   291                       heading = _"Disapproval [single entry]"
   292                     else
   293                       heading = _"Disapproval [many entries]"
   294                     end
   295                   end
   296                 end
   297                 ui.tag {
   298                   tag     = "div",
   299                   attr    = { class = "cathead" },
   300                   content = heading
   301                 }
   302                 for i, initiative in ipairs(entries) do
   303                   ui.container{
   304                     attr = {
   305                       class = "movable",
   306                       id = "entry_" .. tostring(initiative.id)
   307                     },
   308                     content = function()
   309                       local initiators_selector = initiative:get_reference_selector("initiating_members")
   310                         :add_where("accepted")
   311                       local initiators = initiators_selector:exec()
   312                       local initiator_names = {}
   313                       for i, initiator in ipairs(initiators) do
   314                         initiator_names[#initiator_names+1] = initiator.name
   315                       end
   316                       local initiator_names_string = table.concat(initiator_names, ", ")
   317                       ui.container{
   318                         attr = { style = "float: right;" },
   319                         content = function()
   320                           ui.link{
   321                             attr = { class = "clickable" },
   322                             content = _"Show",
   323                             module = "initiative",
   324                             view = "show",
   325                             id = initiative.id
   326                           }
   327                           slot.put(" ")
   328                           ui.link{
   329                             attr = { class = "clickable", target = "_blank" },
   330                             content = _"(new window)",
   331                             module = "initiative",
   332                             view = "show",
   333                             id = initiative.id
   334                           }
   335                           if not readonly then
   336                             slot.put(" ")
   337                             ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" }
   338                           end
   339                         end
   340                       }
   341                       if not readonly then
   342                         ui.container{
   343                           attr = { style = "float: left;" },
   344                           content = function()
   345                             ui.tag{
   346                               tag = "input",
   347                               attr = {
   348                                 onclick = "voting_moveUp(this.parentNode.parentNode); return(false);",
   349                                 name = "move_up",
   350                                 value = initiative.id,
   351                                 class = not disabled and "clickable" or nil,
   352                                 type = "image",
   353                                 src = encode.url{ static = "icons/move_up.png" },
   354                                 alt = _"Move up"
   355                               }
   356                             }
   357                             slot.put(" ")
   358                             ui.tag{
   359                               tag = "input",
   360                               attr = {
   361                                 onclick = "voting_moveDown(this.parentNode.parentNode); return(false);",
   362                                 name = "move_down",
   363                                 value = initiative.id,
   364                                 class = not disabled and "clickable" or nil,
   365                                 type = "image",
   366                                 src = encode.url{ static = "icons/move_down.png" },
   367                                 alt = _"Move down"
   368                               }
   369                             }
   370                             slot.put(" ")
   371                           end
   372                         }
   373                       end
   374                       ui.container{
   375                         content = function()
   376                           slot.put(encode.html(initiative.shortened_name))
   377                           if #initiators > 1 then
   378                             ui.container{
   379                               attr = { style = "font-size: 80%;" },
   380                               content = _"Initiators" .. ": " .. initiator_names_string
   381                             }
   382                           else
   383                             ui.container{
   384                               attr = { style = "font-size: 80%;" },
   385                               content = _"Initiator" .. ": " .. initiator_names_string
   386                             }
   387                           end
   388                         end
   389                       }
   390                     end
   391                   }
   392                 end
   393               end
   394             }
   395           end
   396         end
   397       end
   398     }
   399     if not readonly then
   400       ui.tag{
   401         tag = "input",
   402         attr = {
   403           type = "button",
   404           class = "voting_done",
   405           value = _"Finish voting"
   406         }
   407       }
   408     end
   409   end
   410 }
