liquid_feedback_frontend
view app/main/vote/list.lua @ 519:7492497005bd
Fixed voting for non javascript capable browser, removed browser warning
| author | bsw | 
|---|---|
| date | Mon Apr 16 23:27:07 2012 +0200 (2012-04-16) | 
| parents | 24f8920e05f1 | 
| children | a930d2ab9e76 | 
 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
     8 if member_id then
     9   if not issue.closed then
    10     error("access denied")
    11   end
    12   member = Member:by_id(member_id)
    13   readonly = true
    14 end
    16 if issue.closed then
    17   if not member then
    18     slot.put_into("error", _"This issue is already closed.")
    19   end
    20   if not member then
    21     member = app.session.member
    22   end
    23   readonly = true
    24 end
    26 if member then
    27   local str = _("Ballot of '#{member_name}' for issue ##{issue_id}",
    28                   {member_name = string.format('<a href="%s">%s</a>',
    29                                           encode.url{
    30                                             module    = "member",
    31                                             view      = "show",
    32                                             id        = member.id,
    33                                           },
    34                                           encode.html(member.name)),
    35                    issue_id = string.format('<a href="%s">%s</a>',
    36                                           encode.url{
    37                                             module    = "issue",
    38                                             view      = "show",
    39                                             id        = issue.id,
    40                                           },
    41                                           encode.html(tostring(issue.id)))
    42                   }
    43               )
    44   slot.put_into("title", str)
    45 else
    46   member = app.session.member
    47   slot.put_into("title", _"Voting")
    49   slot.select("actions", function()
    50     ui.link{
    51       content = function()
    52           ui.image{ static = "icons/16/cancel.png" }
    53           slot.put(_"Cancel")
    54       end,
    55       module = "issue",
    56       view = "show",
    57       id = issue.id
    58     }
    59     ui.link{
    60       text = _"Discard voting",
    61       content = function()
    62           ui.image{ static = "icons/16/email_delete.png" }
    63           slot.put(_"Discard voting")
    64       end,
    65       module = "vote",
    66       action = "update",
    67       params = {
    68         issue_id = issue.id,
    69         discard = true
    70       },
    71       routing = {
    72         default = {
    73           mode = "redirect",
    74           module = "issue",
    75           view = "show",
    76           id = issue.id
    77         }
    78       }
    79     }
    80   end)
    81 end
    84 local tempvoting_string = param.get("scoring")
    86 local tempvotings = {}
    87 if tempvoting_string then
    88   for match in tempvoting_string:gmatch("([^;]+)") do
    89     for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do
    90       tempvotings[tonumber(initiative_id)] = tonumber(grade)
    91     end
    92   end
    93 end
    95 local initiatives = issue:get_reference_selector("initiatives"):add_where("initiative.admitted"):add_order_by("initiative.satisfied_supporter_count DESC"):exec()
    97 local min_grade = -1;
    98 local max_grade = 1;
   100 for i, initiative in ipairs(initiatives) do
   101   -- TODO performance
   102   initiative.vote = Vote:by_pk(initiative.id, member.id)
   103   if tempvotings[initiative.id] then
   104     initiative.vote = {}
   105     initiative.vote.grade = tempvotings[initiative.id]
   106   end
   107   if initiative.vote then
   108     if initiative.vote.grade > max_grade then
   109       max_grade = initiative.vote.grade
   110     end
   111     if initiative.vote.grade < min_grade then
   112       min_grade = initiative.vote.grade
   113     end
   114   end
   115 end
   117 local sections = {}
   118 for i = min_grade, max_grade do
   119   sections[i] = {}
   120   for j, initiative in ipairs(initiatives) do
   121     if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then
   122       sections[i][#(sections[i])+1] = initiative
   123     end
   124   end
   125 end
   127 local approval_count, disapproval_count = 0, 0
   128 for i = min_grade, -1 do
   129   if #sections[i] > 0 then
   130     disapproval_count = disapproval_count + 1
   131   end
   132 end
   133 local approval_count = 0
   134 for i = 1, max_grade do
   135   if #sections[i] > 0 then
   136     approval_count = approval_count + 1
   137   end
   138 end
   142 if not readonly then
   143   util.help("vote.list", _"Voting")
   144   slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/dragdrop.js"></script>')
   145   slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/voting.js"></script>')
   146 end
   148 ui.script{
   149   script = function()
   150     slot.put(
   151       "voting_text_approval_single               = ", encode.json(_"Approval [single entry]"), ";\n",
   152       "voting_text_approval_multi                = ", encode.json(_"Approval [many entries]"), ";\n",
   153       "voting_text_first_preference_single       = ", encode.json(_"Approval (first preference) [single entry]"), ";\n",
   154       "voting_text_first_preference_multi        = ", encode.json(_"Approval (first preference) [many entries]"), ";\n",
   155       "voting_text_second_preference_single      = ", encode.json(_"Approval (second preference) [single entry]"), ";\n",
   156       "voting_text_second_preference_multi       = ", encode.json(_"Approval (second preference) [many entries]"), ";\n",
   157       "voting_text_third_preference_single       = ", encode.json(_"Approval (third preference) [single entry]"), ";\n",
   158       "voting_text_third_preference_multi        = ", encode.json(_"Approval (third preference) [many entries]"), ";\n",
   159       "voting_text_numeric_preference_single     = ", encode.json(_"Approval (#th preference) [single entry]"), ";\n",
   160       "voting_text_numeric_preference_multi      = ", encode.json(_"Approval (#th preference) [many entries]"), ";\n",
   161       "voting_text_abstention_single             = ", encode.json(_"Abstention [single entry]"), ";\n",
   162       "voting_text_abstention_multi              = ", encode.json(_"Abstention [many entries]"), ";\n",
   163       "voting_text_disapproval_above_one_single  = ", encode.json(_"Disapproval (prefer to lower block) [single entry]"), ";\n",
   164       "voting_text_disapproval_above_one_multi   = ", encode.json(_"Disapproval (prefer to lower block) [many entries]"), ";\n",
   165       "voting_text_disapproval_above_many_single = ", encode.json(_"Disapproval (prefer to lower blocks) [single entry]"), ";\n",
   166       "voting_text_disapproval_above_many_multi  = ", encode.json(_"Disapproval (prefer to lower blocks) [many entries]"), ";\n",
   167       "voting_text_disapproval_above_last_single = ", encode.json(_"Disapproval (prefer to last block) [single entry]"), ";\n",
   168       "voting_text_disapproval_above_last_multi  = ", encode.json(_"Disapproval (prefer to last block) [many entries]"), ";\n",
   169       "voting_text_disapproval_single            = ", encode.json(_"Disapproval [single entry]"), ";\n",
   170       "voting_text_disapproval_multi             = ", encode.json(_"Disapproval [many entries]"), ";\n"
   171     )
   172   end
   173 }
   175 ui.form{
   176   attr = {
   177     id = "voting_form",
   178     class = readonly and "voting_form_readonly" or "voting_form_active"
   179   },
   180   module = "vote",
   181   action = "update",
   182   params = { issue_id = issue.id },
   183   routing = {
   184     default = {
   185       mode = "redirect",
   186       module = "issue",
   187       view = "show",
   188       id = issue.id
   189     }
   190   },
   191   content = function()
   192     if not readonly then
   193       local scoring = param.get("scoring")
   194       if not scoring then
   195         for i, initiative in ipairs(initiatives) do
   196           local vote = initiative.vote
   197           if vote then
   198             tempvotings[initiative.id] = vote.grade
   199           end
   200         end
   201         local tempvotings_list = {}
   202         for key, val in pairs(tempvotings) do
   203           tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val)
   204         end
   205         if #tempvotings_list > 0 then
   206           scoring = table.concat(tempvotings_list, ";")
   207         else
   208           scoring = ""
   209         end
   210       end
   211       slot.put('<input type="hidden" name="scoring" value="' .. scoring .. '"/>')
   212       -- TODO abstrahieren
   213       ui.tag{
   214         tag = "input",
   215         attr = {
   216           type = "submit",
   217           class = "voting_done",
   218           value = _"Finish voting"
   219         }
   220       }
   221     end
   222     ui.container{
   223       attr = { id = "voting" },
   224       content = function()
   225         local approval_index, disapproval_index = 0, 0
   226         for grade = max_grade, min_grade, -1 do 
   227           local entries = sections[grade]
   228           local class
   229           if grade > 0 then
   230             class = "approval"
   231           elseif grade < 0 then
   232             class = "disapproval"
   233           else
   234             class = "abstention"
   235           end
   236           if
   237             #entries > 0 or
   238             (grade == 1 and not approval_used) or
   239             (grade == -1 and not disapproval_used) or
   240             grade == 0
   241           then
   242             ui.container{
   243               attr = { class = class },
   244               content = function()
   245                 local heading
   246                 if class == "approval" then
   247                   approval_used = true
   248                   approval_index = approval_index + 1
   249                   if approval_count > 1 then
   250                     if approval_index == 1 then
   251                       if #entries == 1 then
   252                         heading = _"Approval (first preference) [single entry]"
   253                       else
   254                         heading = _"Approval (first preference) [many entries]"
   255                       end
   256                     elseif approval_index == 2 then
   257                       if #entries == 1 then
   258                         heading = _"Approval (second preference) [single entry]"
   259                       else
   260                         heading = _"Approval (second preference) [many entries]"
   261                       end
   262                     elseif approval_index == 3 then
   263                       if #entries == 1 then
   264                         heading = _"Approval (third preference) [single entry]"
   265                       else
   266                         heading = _"Approval (third preference) [many entries]"
   267                       end
   268                     else
   269                       if #entries == 1 then
   270                         heading = _"Approval (#th preference) [single entry]"
   271                       else
   272                         heading = _"Approval (#th preference) [many entries]"
   273                       end
   274                     end
   275                   else
   276                     if #entries == 1 then
   277                       heading = _"Approval [single entry]"
   278                     else
   279                       heading = _"Approval [many entries]"
   280                     end
   281                   end
   282                 elseif class == "abstention" then
   283                     if #entries == 1 then
   284                       heading = _"Abstention [single entry]"
   285                     else
   286                       heading = _"Abstention [many entries]"
   287                     end
   288                 elseif class == "disapproval" then
   289                   disapproval_used = true
   290                   disapproval_index = disapproval_index + 1
   291                   if disapproval_count > disapproval_index + 1 then
   292                     if #entries == 1 then
   293                       heading = _"Disapproval (prefer to lower blocks) [single entry]"
   294                     else
   295                       heading = _"Disapproval (prefer to lower blocks) [many entries]"
   296                     end
   297                   elseif disapproval_count == 2 and disapproval_index == 1 then
   298                     if #entries == 1 then
   299                       heading = _"Disapproval (prefer to lower block) [single entry]"
   300                     else
   301                       heading = _"Disapproval (prefer to lower block) [many entries]"
   302                     end
   303                   elseif disapproval_index == disapproval_count - 1 then
   304                     if #entries == 1 then
   305                       heading = _"Disapproval (prefer to last block) [single entry]"
   306                     else
   307                       heading = _"Disapproval (prefer to last block) [many entries]"
   308                     end
   309                   else
   310                     if #entries == 1 then
   311                       heading = _"Disapproval [single entry]"
   312                     else
   313                       heading = _"Disapproval [many entries]"
   314                     end
   315                   end
   316                 end
   317                 ui.tag {
   318                   tag     = "div",
   319                   attr    = { class = "cathead" },
   320                   content = heading
   321                 }
   322                 for i, initiative in ipairs(entries) do
   323                   ui.container{
   324                     attr = {
   325                       class = "movable",
   326                       id = "entry_" .. tostring(initiative.id)
   327                     },
   328                     content = function()
   329                       local initiators_selector = initiative:get_reference_selector("initiating_members")
   330                         :add_where("accepted")
   331                       local initiators = initiators_selector:exec()
   332                       local initiator_names = {}
   333                       for i, initiator in ipairs(initiators) do
   334                         initiator_names[#initiator_names+1] = initiator.name
   335                       end
   336                       local initiator_names_string = table.concat(initiator_names, ", ")
   337                       ui.container{
   338                         attr = { style = "float: right; position: relative;" },
   339                         content = function()
   340                           ui.link{
   341                             attr = { class = "clickable" },
   342                             content = _"Show",
   343                             module = "initiative",
   344                             view = "show",
   345                             id = initiative.id
   346                           }
   347                           slot.put(" ")
   348                           ui.link{
   349                             attr = { class = "clickable", target = "_blank" },
   350                             content = _"(new window)",
   351                             module = "initiative",
   352                             view = "show",
   353                             id = initiative.id
   354                           }
   355                           if not readonly then
   356                             slot.put(" ")
   357                             ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" }
   358                           end
   359                         end
   360                       }
   361                       if not readonly then
   362                         ui.container{
   363                           attr = { style = "float: left; position: relative;" },
   364                           content = function()
   365                             ui.tag{
   366                               tag = "input",
   367                               attr = {
   368                                 onclick = "if (jsFail) return true; voting_moveUp(this.parentNode.parentNode); return(false);",
   369                                 name = "move_up_" .. tostring(initiative.id),
   370                                 class = not disabled and "clickable" or nil,
   371                                 type = "image",
   372                                 src = encode.url{ static = "icons/move_up.png" },
   373                                 alt = _"Move up"
   374                               }
   375                             }
   376                             slot.put(" ")
   377                             ui.tag{
   378                               tag = "input",
   379                               attr = {
   380                                 onclick = "if (jsFail) return true; voting_moveDown(this.parentNode.parentNode); return(false);",
   381                                 name = "move_down_" .. tostring(initiative.id),
   382                                 class = not disabled and "clickable" or nil,
   383                                 type = "image",
   384                                 src = encode.url{ static = "icons/move_down.png" },
   385                                 alt = _"Move down"
   386                               }
   387                             }
   388                             slot.put(" ")
   389                           end
   390                         }
   391                       end
   392                       ui.container{
   393                         content = function()
   394                           ui.tag{ content = "i" .. initiative.id .. ": " }
   395                           ui.tag{ content = initiative.shortened_name }
   396                           slot.put("<br />")
   397                           for i, initiator in ipairs(initiators) do
   398                             ui.link{
   399                               attr = { class = "clickable" },
   400                               content = function ()
   401                                 execute.view{
   402                                   module = "member_image",
   403                                   view = "_show",
   404                                   params = {
   405                                     member = initiator,
   406                                     image_type = "avatar",
   407                                     show_dummy = true,
   408                                     class = "micro_avatar",
   409                                     popup_text = text
   410                                   }
   411                                 }
   412                               end,
   413                               module = "member", view = "show", id = initiator.id
   414                             }
   415                             slot.put(" ")
   416                             ui.tag{ content = initiator.name }
   417                             slot.put(" ")
   418                           end
   419                         end
   420                       }
   421                     end
   422                   }
   423                 end
   424               end
   425             }
   426           end
   427         end
   428       end
   429     }
   430     if not readonly then
   431       ui.tag{
   432         tag = "input",
   433         attr = {
   434           type = "submit",
   435           class = "voting_done",
   436           value = _"Finish voting"
   437         }
   438       }
   439     end
   440   end
   441 }
