liquid_feedback_frontend

diff app/main/initiative/_show.lua @ 19:00d1004545f1

Dynamic interface using XMLHttpRequests, and many other changes

Bugfixes:
- Only allow voting on admitted initiatives
- Repaired issue search
- Don't display delegations for closed issues on member page
- Don't show revoke link in initiative, when issue is already half_frozen
- Localization for voting JavaScript
- Display author of suggestions

Disclosure of voting data after voting is finished:
- Possibility to inspect every ballot including preferences
- Show number of voters preferring one initiative to another initiative

Interface behaviour changes:
- Reversed default order of drafts
- Default order of suggestions changed
- Show new drafts of initiatives only once per day in timeline

Accessibility:
- Barrier-free voting implemented
- POST links are now accessible without JavaScript
- Changed gray for unsatisfied supporters in bar graph to a lighter gray

Other interface improvements:
- Optical enhancements
- Dynamic interface using XMLHttpRequests
- Show usage terms in about section
- Show own membership in area listing
- Show uninformed supporters greyed out and marked with yellow question mark
- Warning box in non-admitted initiatives
- When voted, don't display voting notice and change label of voting link
- Show object counts in more tabulator heads
- Enlarged member statement input field

Miscellaneous:
- Code cleanup
- Added README file containing installation instructions
- Use new WebMCP function ui.filters{...} instead of own ui.filter and ui.order functions
author bsw/jbe
date Sat Feb 20 22:10:31 2010 +0100 (2010-02-20)
parents
children 81586ea68d57
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/app/main/initiative/_show.lua	Sat Feb 20 22:10:31 2010 +0100
     1.3 @@ -0,0 +1,236 @@
     1.4 +local initiative = param.get("initiative", "table")
     1.5 +local initiator = param.get("initiator", "table")
     1.6 +
     1.7 +util.help("initiative.show")
     1.8 +
     1.9 +if initiative.issue.ranks_available and initiative.admitted then
    1.10 +  local class = initiative.rank == 1 and "admitted_info" or "not_admitted_info"
    1.11 +  ui.container{
    1.12 +    attr = { class = class },
    1.13 +    content = function()
    1.14 +      local max_value = initiative.issue.voter_count
    1.15 +      slot.put(" ")
    1.16 +      local positive_votes = initiative.positive_votes
    1.17 +      local negative_votes = initiative.negative_votes
    1.18 +      slot.put(_"Yes" .. ": <b>" .. tostring(positive_votes) .. "</b>")
    1.19 +      slot.put(" &middot; ")
    1.20 +      slot.put(_"Abstention" .. ": <b>" .. tostring(max_value - initiative.negative_votes - initiative.positive_votes)  .. "</b>")
    1.21 +      slot.put(" &middot; ")
    1.22 +      slot.put(_"No" .. ": <b>" .. tostring(initiative.negative_votes) .. "</b>")
    1.23 +      slot.put(" &middot; ")
    1.24 +      slot.put("<b>")
    1.25 +      if initiative.rank == 1 then
    1.26 +        slot.put(_"Approved")
    1.27 +      elseif initiative.rank then
    1.28 +        slot.put(_("Not approved (rank #{rank})", { rank = initiative.rank }))
    1.29 +      end
    1.30 +      slot.put("</b>")
    1.31 +    end
    1.32 +  }
    1.33 +end
    1.34 +
    1.35 +if initiative.admitted == false then
    1.36 +  local policy = initiative.issue.policy
    1.37 +  ui.container{
    1.38 +    attr = { class = "not_admitted_info" },
    1.39 +    content = _("This initiative has not been admitted! It failed the quorum of #{quorum}.", { quorum = format.percentage(policy.initiative_quorum_num / policy.initiative_quorum_den) })
    1.40 +  }
    1.41 +end
    1.42 +
    1.43 +local web20 = config.user_tab_mode == "accordeon"
    1.44 +  or config.user_tab_mode == "accordeon_first_expanded"
    1.45 +  or config.user_tab_mode == "accordeon_all_expanded"
    1.46 +
    1.47 +if not web20 and initiative.issue.state == "cancelled" then
    1.48 +  local policy = initiative.issue.policy
    1.49 +  ui.container{
    1.50 +    attr = { class = "not_admitted_info" },
    1.51 +    content = _("This issue has been cancelled. It failed the quorum of #{quorum}.", { quorum = format.percentage(policy.issue_quorum_num / policy.issue_quorum_den) })
    1.52 +  }
    1.53 +end
    1.54 +
    1.55 +if initiative.revoked then
    1.56 +  ui.container{
    1.57 +    attr = { class = "revoked_info" },
    1.58 +    content = function()
    1.59 +      slot.put(_("This initiative has been revoked at #{revoked}", { revoked = format.timestamp(initiative.revoked) }))
    1.60 +      local suggested_initiative = initiative.suggested_initiative
    1.61 +      if suggested_initiative then
    1.62 +        slot.put("<br /><br />")
    1.63 +        slot.put(_("The initiators suggest to support the following initiative:"))
    1.64 +        slot.put(" ")
    1.65 +        ui.link{
    1.66 +          content = _("Issue ##{id}", { id = suggested_initiative.issue.id } ) .. ": " .. encode.html(suggested_initiative.name),
    1.67 +          module = "initiative",
    1.68 +          view = "show",
    1.69 +          id = suggested_initiative.id
    1.70 +        }
    1.71 +      end
    1.72 +    end
    1.73 +  }
    1.74 +end
    1.75 +
    1.76 +if initiator and initiator.accepted == nil then
    1.77 +  ui.container{
    1.78 +    attr = { class = "initiator_invite_info" },
    1.79 +    content = function()
    1.80 +      slot.put(_"You are invited to become initiator of this initiative.")
    1.81 +      slot.put(" ")
    1.82 +      ui.link{
    1.83 +        image  = { static = "icons/16/tick.png" },
    1.84 +        text   = _"Accept invitation",
    1.85 +        module = "initiative",
    1.86 +        action = "accept_invitation",
    1.87 +        id     = initiative.id,
    1.88 +        routing = {
    1.89 +          default = {
    1.90 +            mode = "redirect",
    1.91 +            module = request.get_module(),
    1.92 +            view = request.get_view(),
    1.93 +            id = param.get_id_cgi(),
    1.94 +            params = param.get_all_cgi()
    1.95 +          }
    1.96 +        }
    1.97 +      }
    1.98 +      slot.put(" ")
    1.99 +      ui.link{
   1.100 +        image  = { static = "icons/16/cross.png" },
   1.101 +        text   = _"Refuse invitation",
   1.102 +        module = "initiative",
   1.103 +        action = "reject_initiator_invitation",
   1.104 +        params = {
   1.105 +          initiative_id = initiative.id,
   1.106 +          member_id = app.session.member.id
   1.107 +        },
   1.108 +        routing = {
   1.109 +          default = {
   1.110 +            mode = "redirect",
   1.111 +            module = request.get_module(),
   1.112 +            view = request.get_view(),
   1.113 +            id = param.get_id_cgi(),
   1.114 +            params = param.get_all_cgi()
   1.115 +          }
   1.116 +        }
   1.117 +      }
   1.118 +    end
   1.119 +  }
   1.120 +  slot.put("<br />")
   1.121 +end
   1.122 +
   1.123 +
   1.124 +local supporter = app.session.member:get_reference_selector("supporters")
   1.125 +  :add_where{ "initiative_id = ?", initiative.id }
   1.126 +  :optional_object_mode()
   1.127 +  :exec()
   1.128 +
   1.129 +if supporter and not initiative.issue.closed then
   1.130 +  local old_draft_id = supporter.draft_id
   1.131 +  local new_draft_id = initiative.current_draft.id
   1.132 +  if old_draft_id ~= new_draft_id then
   1.133 +    ui.container{
   1.134 +      attr = { class = "draft_updated_info" },
   1.135 +      content = function()
   1.136 +        slot.put(_"The draft of this initiative has been updated!")
   1.137 +        slot.put(" ")
   1.138 +        ui.link{
   1.139 +          content = _"Show diff",
   1.140 +          module = "draft",
   1.141 +          view = "diff",
   1.142 +          params = {
   1.143 +            old_draft_id = old_draft_id,
   1.144 +            new_draft_id = new_draft_id
   1.145 +          }
   1.146 +        }
   1.147 +        slot.put(" ")
   1.148 +        ui.link{
   1.149 +          text   = _"Refresh support to current draft",
   1.150 +          module = "initiative",
   1.151 +          action = "add_support",
   1.152 +          id     = initiative.id,
   1.153 +          routing = {
   1.154 +            default = {
   1.155 +              mode = "redirect",
   1.156 +              module = "initiative",
   1.157 +              view = "show",
   1.158 +              id = initiative.id
   1.159 +            }
   1.160 +          }
   1.161 +        }
   1.162 +      end
   1.163 +    }
   1.164 +  end
   1.165 +end
   1.166 +
   1.167 +
   1.168 +
   1.169 +ui.container{
   1.170 +  attr = {
   1.171 +    id = "initiative_" .. tostring(initiative.id) .. "_support"
   1.172 +  },
   1.173 +  content = function()
   1.174 +    execute.view{
   1.175 +      module = "initiative",
   1.176 +      view = "show_support",
   1.177 +      params = {
   1.178 +        initiative = initiative
   1.179 +      }
   1.180 +    }
   1.181 +  end
   1.182 +}
   1.183 +
   1.184 +if (initiative.discussion_url and #initiative.discussion_url > 0)
   1.185 +  or (initiator and initiator.accepted and not initiative.issue.half_frozen and not initiative.issue.closed and not initiative.revoked) then
   1.186 +  ui.container{
   1.187 +    attr = { class = "vertical" },
   1.188 +    content = function()
   1.189 +      ui.container{
   1.190 +        attr = { class = "ui_field_label" },
   1.191 +        content = _"Discussion with initiators"
   1.192 +      }
   1.193 +      ui.tag{
   1.194 +        tag = "span",
   1.195 +        content = function()
   1.196 +          if initiative.discussion_url:find("^https?://") then
   1.197 +            if initiative.discussion_url and #initiative.discussion_url > 0 then
   1.198 +              ui.link{
   1.199 +                attr = {
   1.200 +                  class = "actions",
   1.201 +                  target = "_blank",
   1.202 +                  title = initiative.discussion_url
   1.203 +                },
   1.204 +                content = function()
   1.205 +                  slot.put(encode.html(initiative.discussion_url))
   1.206 +                end,
   1.207 +                external = initiative.discussion_url
   1.208 +              }
   1.209 +            end
   1.210 +          else
   1.211 +            slot.put(encode.html(initiative.discussion_url))
   1.212 +          end
   1.213 +          slot.put(" ")
   1.214 +          if initiator and initiator.accepted and not initiative.issue.half_frozen and not initiative.issue.closed and not initiative.revoked then
   1.215 +            ui.link{
   1.216 +              attr   = { class = "actions" },
   1.217 +              text   = _"(change URL)",
   1.218 +              module = "initiative",
   1.219 +              view   = "edit",
   1.220 +              id     = initiative.id
   1.221 +            }
   1.222 +          end
   1.223 +        end
   1.224 +      }
   1.225 +    end
   1.226 +  }
   1.227 +end
   1.228 +
   1.229 +
   1.230 +
   1.231 +execute.view{
   1.232 +  module = "initiative",
   1.233 +  view = "show_tab",
   1.234 +  params = {
   1.235 +    initiative = initiative,
   1.236 +    initiator = initiator
   1.237 +  }
   1.238 +}
   1.239 +

Impressum / About Us