liquid_feedback_frontend

changeset 5:afd9f769c7ae beta1

Version beta1

Final voting with Schulze-Method is now possible

Many bug fixes and code cleanup

Registration with invite codes

More sort and filter options

Seperated display of "supporters" and "potential supporters"

Optical changes

Flood limit / initiative contigent is now checked by frontend

Neccessary changes to access core beta11
author bsw/jbe
date Fri Dec 25 12:00:00 2009 +0100 (2009-12-25)
parents 80c215dbf076
children 8d91bccab0bf
files app/main/_filter/21_auth.lua app/main/_filter_action/10_transaction.lua app/main/_filter_view/30_navigation.lua app/main/_layout/default.html app/main/admin/_action/area_update.lua app/main/admin/area_show.lua app/main/area/_action/update.lua app/main/contact/_action/add_member.lua app/main/delegation/_action/update.lua app/main/delegation/_show_box.lua app/main/draft/_action/add.lua app/main/index/_action/register.lua app/main/index/index.lua app/main/index/login.lua app/main/index/register.lua app/main/initiative/_action/add_support.lua app/main/initiative/_action/create.lua app/main/initiative/_action/remove_support.lua app/main/initiative/_list.lua app/main/initiative/new.lua app/main/initiative/show.lua app/main/interest/_action/update.lua app/main/interest/_show_box.lua app/main/issue/_list.lua app/main/issue/_show_head.lua app/main/issue/show.lua app/main/member/_action/update.lua app/main/member/edit.lua app/main/opinion/_action/update.lua app/main/suggestion/_action/add.lua app/main/suggestion/_list.lua app/main/supporter/_show_box.lua app/main/vote/_action/update.lua app/main/vote/list.lua config/default.lua env/ui/order.lua fastpath/Makefile fastpath/getpic.c locale/help/area.show.de.txt locale/help/vote.list.de.txt locale/translations.de.lua model/direct_voter.lua model/invite_code.lua model/issue.lua model/member.lua model/policy.lua model/supporter.lua model/vote.lua static/icons/16/email_open.png static/icons/16/eye.png static/icons/16/thumb_up.png static/icons/16/time.png static/js/browser_warning.js static/js/dragdrop.js static/js/voting.js static/style.css
line diff
     1.1 --- a/app/main/_filter/21_auth.lua	Thu Dec 10 12:00:00 2009 +0100
     1.2 +++ b/app/main/_filter/21_auth.lua	Fri Dec 25 12:00:00 2009 +0100
     1.3 @@ -1,9 +1,11 @@
     1.4  local auth_needed = not (
     1.5    request.get_module() == 'index'
     1.6    and (
     1.7 -    request.get_view() == 'login'
     1.8 +       request.get_view()   == 'login'
     1.9      or request.get_action() == 'login'
    1.10 -    or request.get_view() == "about"
    1.11 +    or request.get_view()   == "register"
    1.12 +    or request.get_action() == "register"
    1.13 +    or request.get_view()   == "about"
    1.14    )
    1.15  )
    1.16  
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/app/main/_filter_action/10_transaction.lua	Fri Dec 25 12:00:00 2009 +0100
     2.3 @@ -0,0 +1,5 @@
     2.4 +db:query("BEGIN;")
     2.5 +
     2.6 +execute.inner()
     2.7 +
     2.8 +db:query("COMMIT;")
     2.9 \ No newline at end of file
     3.1 --- a/app/main/_filter_view/30_navigation.lua	Thu Dec 10 12:00:00 2009 +0100
     3.2 +++ b/app/main/_filter_view/30_navigation.lua	Fri Dec 25 12:00:00 2009 +0100
     3.3 @@ -6,13 +6,21 @@
     3.4      ui.link{
     3.5        content = function()
     3.6          ui.image{ static = "icons/16/key.png" }
     3.7 -        slot.put('Login')
     3.8 +        slot.put(_"Login")
     3.9        end,
    3.10        module = 'index',
    3.11        view = 'login'
    3.12      }
    3.13      ui.link{
    3.14        content = function()
    3.15 +        ui.image{ static = "icons/16/book_edit.png" }
    3.16 +        slot.put(_"Registration")
    3.17 +      end,
    3.18 +      module = 'index',
    3.19 +      view = 'register'
    3.20 +    }
    3.21 +    ui.link{
    3.22 +      content = function()
    3.23          ui.image{ static = "icons/16/information.png" }
    3.24          slot.put('About / Impressum')
    3.25        end,
    3.26 @@ -29,7 +37,7 @@
    3.27      ui.link{
    3.28        content = function()
    3.29          ui.image{ static = "icons/16/house.png" }
    3.30 -        slot.put(_'Home')
    3.31 +        slot.put(_"Home")
    3.32        end,
    3.33        module = 'index',
    3.34        view = 'index'
    3.35 @@ -38,7 +46,7 @@
    3.36      ui.link{
    3.37        content = function()
    3.38          ui.image{ static = "icons/16/package.png" }
    3.39 -        slot.put(_'Areas')
    3.40 +        slot.put(_"Areas")
    3.41        end,
    3.42        module = 'area',
    3.43        view = 'list'
    3.44 @@ -47,7 +55,7 @@
    3.45      ui.link{
    3.46        content = function()
    3.47          ui.image{ static = "icons/16/group.png" }
    3.48 -        slot.put(_'Members')
    3.49 +        slot.put(_"Members")
    3.50        end,
    3.51        module = 'member',
    3.52        view = 'list'
    3.53 @@ -56,7 +64,7 @@
    3.54      ui.link{
    3.55        content = function()
    3.56          ui.image{ static = "icons/16/book_edit.png" }
    3.57 -        slot.put(_'Contacts')
    3.58 +        slot.put(_"Contacts")
    3.59        end,
    3.60        module = 'contact',
    3.61        view = 'list'
    3.62 @@ -65,7 +73,7 @@
    3.63      ui.link{
    3.64        content = function()
    3.65          ui.image{ static = "icons/16/information.png" }
    3.66 -        slot.put(_'About')
    3.67 +        slot.put(_"About")
    3.68        end,
    3.69        module = 'index',
    3.70        view = 'about'
    3.71 @@ -74,7 +82,7 @@
    3.72      ui.link{
    3.73        content = function()
    3.74          ui.image{ static = "icons/16/bug.png" }
    3.75 -        slot.put(_'Bug report')
    3.76 +        slot.put(_"Bug report")
    3.77        end,
    3.78        external = "http://trac.public-software-group.org/projects/lf" --/newticket?description=" .. encode.url_part("\n\n\n\nReport for: " .. os.getenv("REQUEST_URI") )
    3.79      }
     4.1 --- a/app/main/_layout/default.html	Thu Dec 10 12:00:00 2009 +0100
     4.2 +++ b/app/main/_layout/default.html	Fri Dec 25 12:00:00 2009 +0100
     4.3 @@ -38,12 +38,12 @@
     4.4          <div class="path" id="path">
     4.5            <!-- WEBMCP SLOT path -->
     4.6          </div>
     4.7 +        <div class="help_hidden" id="help_hidden">
     4.8 +          <!-- WEBMCP SLOT help_hidden -->
     4.9 +        </div>
    4.10          <div class="title" id="title">
    4.11            <!-- WEBMCP SLOT title -->
    4.12          </div>
    4.13 -        <div class="help_hidden" id="help_hidden">
    4.14 -          <!-- WEBMCP SLOT help_hidden -->
    4.15 -        </div>
    4.16          <div class="actions" id="actions">
    4.17            <div class="interest vote_info" id="interest">
    4.18              <!-- WEBMCP SLOT interest -->
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/app/main/admin/_action/area_update.lua	Fri Dec 25 12:00:00 2009 +0100
     5.3 @@ -0,0 +1,19 @@
     5.4 +if not app.session.member.admin then
     5.5 +  error()
     5.6 +end
     5.7 +
     5.8 +local id = param.get_id()
     5.9 +
    5.10 +local area
    5.11 +if id then
    5.12 +  area = Area:new_selector():add_where{ "id = ?", id }:single_object_mode():exec()
    5.13 +else
    5.14 +  area = Area:new()
    5.15 +end
    5.16 +
    5.17 +
    5.18 +param.update(area, "name", "description", "active")
    5.19 +
    5.20 +area:save()
    5.21 +
    5.22 +slot.put_into("notice", _"Area successfully updated")
     6.1 --- a/app/main/admin/area_show.lua	Thu Dec 10 12:00:00 2009 +0100
     6.2 +++ b/app/main/admin/area_show.lua	Fri Dec 25 12:00:00 2009 +0100
     6.3 @@ -10,8 +10,8 @@
     6.4  ui.form{
     6.5    attr = { class = "vertical" },
     6.6    record = area,
     6.7 -  module = "area",
     6.8 -  action = "update",
     6.9 +  module = "admin",
    6.10 +  action = "area_update",
    6.11    routing = {
    6.12      default = {
    6.13        mode = "redirect",
     7.1 --- a/app/main/area/_action/update.lua	Thu Dec 10 12:00:00 2009 +0100
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,19 +0,0 @@
     7.4 -if not app.session.member.admin then
     7.5 -  error()
     7.6 -end
     7.7 -
     7.8 -local id = param.get_id()
     7.9 -
    7.10 -local area
    7.11 -if id then
    7.12 -  area = Area:new_selector():add_where{ "id = ?", id }:single_object_mode():exec()
    7.13 -else
    7.14 -  area = Area:new()
    7.15 -end
    7.16 -
    7.17 -
    7.18 -param.update(area, "name", "description", "active")
    7.19 -
    7.20 -area:save()
    7.21 -
    7.22 -slot.put_into("notice", _"Area successfully updated")
     8.1 --- a/app/main/contact/_action/add_member.lua	Thu Dec 10 12:00:00 2009 +0100
     8.2 +++ b/app/main/contact/_action/add_member.lua	Fri Dec 25 12:00:00 2009 +0100
     8.3 @@ -20,8 +20,3 @@
     8.4  contact.public = public or false
     8.5  contact:save()
     8.6  
     8.7 -if public then
     8.8 ---  slot.put_into("notice", _"Member has been saved as public contact")
     8.9 -else
    8.10 ---  slot.put_into("notice", _"Member has been saved as private contact")
    8.11 -end
     9.1 --- a/app/main/delegation/_action/update.lua	Thu Dec 10 12:00:00 2009 +0100
     9.2 +++ b/app/main/delegation/_action/update.lua	Fri Dec 25 12:00:00 2009 +0100
     9.3 @@ -15,9 +15,9 @@
     9.4  if param.get("delete") or trustee_id == -1 then
     9.5  
     9.6    if delegation then
     9.7 -  
     9.8 +
     9.9      delegation:destroy()
    9.10 -  
    9.11 +
    9.12      if issue_id then
    9.13        slot.put_into("notice", _"Your delegation for this issue has been deleted.")
    9.14      elseif area_id then
    9.15 @@ -27,7 +27,7 @@
    9.16      end
    9.17  
    9.18    end
    9.19 -  
    9.20 +
    9.21  else
    9.22  
    9.23    if not delegation then
    9.24 @@ -35,6 +35,13 @@
    9.25      delegation.truster_id = truster_id
    9.26      delegation.area_id    = area_id
    9.27      delegation.issue_id   = issue_id
    9.28 +    if issue_id then
    9.29 +      delegation.scope = "issue"
    9.30 +    elseif area_id then
    9.31 +      delegation.scope = "area"
    9.32 +    else
    9.33 +      delegation.scope = "global"
    9.34 +    end
    9.35    end
    9.36  
    9.37    delegation.trustee_id = trustee_id
    10.1 --- a/app/main/delegation/_show_box.lua	Thu Dec 10 12:00:00 2009 +0100
    10.2 +++ b/app/main/delegation/_show_box.lua	Fri Dec 25 12:00:00 2009 +0100
    10.3 @@ -1,48 +1,47 @@
    10.4  slot.select("actions", function()
    10.5  
    10.6 -  ui.container{
    10.7 -    attr = { class = "delegation vote_info"},
    10.8 -    content = function()
    10.9 -    
   10.10 -      local delegation
   10.11 -      local area_id
   10.12 -      local issue_id
   10.13 -    
   10.14 -      local scope = "global"
   10.15 -    
   10.16 -      if param.get("initiative_id", atom.integer) then
   10.17 -        issue_id = Initiative:by_id(param.get("initiative_id", atom.integer)).issue_id
   10.18 -        scope = "issue"
   10.19 -      end
   10.20 -    
   10.21 -      if param.get("issue_id", atom.integer) then
   10.22 -        issue_id = param.get("issue_id", atom.integer)
   10.23 -        scope = "issue"
   10.24 -      end
   10.25 -    
   10.26 -      if param.get("area_id", atom.integer) then
   10.27 -        area_id = param.get("area_id", atom.integer)
   10.28 -        scope = "area"
   10.29 -      end
   10.30 -    
   10.31 -    
   10.32 -    
   10.33 -      local delegation
   10.34 -    
   10.35 -      if issue_id then
   10.36 -        delegation = Delegation:by_pk(app.session.member.id, nil, issue_id)
   10.37 -        if not delegation then
   10.38 -          local issue = Issue:by_id(issue_id)
   10.39 -          delegation = Delegation:by_pk(app.session.member.id, issue.area_id)
   10.40 -        end
   10.41 -      elseif area_id then
   10.42 -        delegation = Delegation:by_pk(app.session.member.id, area_id)
   10.43 -      end
   10.44 -    
   10.45 -      if not delegation then
   10.46 -        delegation = Delegation:by_pk(app.session.member.id)
   10.47 -      end
   10.48 -      if delegation then
   10.49 +  local delegation
   10.50 +  local area_id
   10.51 +  local issue_id
   10.52 +
   10.53 +  local scope = "global"
   10.54 +
   10.55 +  if param.get("initiative_id", atom.integer) then
   10.56 +    issue_id = Initiative:by_id(param.get("initiative_id", atom.integer)).issue_id
   10.57 +    scope = "issue"
   10.58 +  end
   10.59 +
   10.60 +  if param.get("issue_id", atom.integer) then
   10.61 +    issue_id = param.get("issue_id", atom.integer)
   10.62 +    scope = "issue"
   10.63 +  end
   10.64 +
   10.65 +  if param.get("area_id", atom.integer) then
   10.66 +    area_id = param.get("area_id", atom.integer)
   10.67 +    scope = "area"
   10.68 +  end
   10.69 +
   10.70 +
   10.71 +
   10.72 +  local delegation
   10.73 +  local issue
   10.74 +  if issue_id then
   10.75 +    issue = Issue:by_id(issue_id)
   10.76 +    delegation = Delegation:by_pk(app.session.member.id, nil, issue_id)
   10.77 +    if not delegation then
   10.78 +      delegation = Delegation:by_pk(app.session.member.id, issue.area_id)
   10.79 +    end
   10.80 +  elseif area_id then
   10.81 +    delegation = Delegation:by_pk(app.session.member.id, area_id)
   10.82 +  end
   10.83 +
   10.84 +  if not delegation then
   10.85 +    delegation = Delegation:by_pk(app.session.member.id)
   10.86 +  end
   10.87 +  if delegation then
   10.88 +    ui.container{
   10.89 +      attr = { class = "delegation vote_info"},
   10.90 +      content = function()
   10.91          ui.container{
   10.92            attr = {
   10.93              title = _"Click for details",
   10.94 @@ -117,25 +116,27 @@
   10.95                        end
   10.96                      }
   10.97                      if i == 2 then
   10.98 -                      ui.link{
   10.99 -                        attr = { class = "revoke" },
  10.100 -                        content = function()
  10.101 -                          ui.image{ static = "icons/16/delete.png" }
  10.102 -                          slot.put(_"Revoke")
  10.103 -                        end,
  10.104 -                        module = "delegation",
  10.105 -                        action = "update",
  10.106 -                        params = { issue_id = delegation.issue_id, area_id = delegation.area_id, delete = true },
  10.107 -                        routing = {
  10.108 -                          default = {
  10.109 -                            mode = "redirect",
  10.110 -                            module = request.get_module(),
  10.111 -                            view = request.get_view(),
  10.112 -                            id = param.get_id_cgi(),
  10.113 -                            params = param.get_all_cgi()
  10.114 +                      if not issue or (issue.state ~= "finished" and issue.state ~= "cancelled") then
  10.115 +                        ui.link{
  10.116 +                          attr = { class = "revoke" },
  10.117 +                          content = function()
  10.118 +                            ui.image{ static = "icons/16/delete.png" }
  10.119 +                            slot.put(_"Revoke")
  10.120 +                          end,
  10.121 +                          module = "delegation",
  10.122 +                          action = "update",
  10.123 +                          params = { issue_id = delegation.issue_id, area_id = delegation.area_id, delete = true },
  10.124 +                          routing = {
  10.125 +                            default = {
  10.126 +                              mode = "redirect",
  10.127 +                              module = request.get_module(),
  10.128 +                              view = request.get_view(),
  10.129 +                              id = param.get_id_cgi(),
  10.130 +                              params = param.get_all_cgi()
  10.131 +                            }
  10.132                            }
  10.133                          }
  10.134 -                      }
  10.135 +                      end
  10.136                      end
  10.137                    end
  10.138                  }
  10.139 @@ -163,30 +164,39 @@
  10.140            end
  10.141          }
  10.142        end
  10.143 -      ui.link{
  10.144 -        content = function()
  10.145 +    }
  10.146 +
  10.147 +
  10.148 +  end
  10.149 +  ui.link{
  10.150 +    content = function()
  10.151 +      if scope == "global" and delegation then
  10.152 +        ui.image{ static = "icons/16/table_go.png" }
  10.153 +        slot.put(_"Change global delegation")
  10.154 +      elseif scope == "global" and not delegation then
  10.155 +        ui.image{ static = "icons/16/table_go.png" }
  10.156 +        slot.put(_"Set global delegation")
  10.157 +      elseif scope == "area" and delegation and delegation.area_id then
  10.158 +        ui.image{ static = "icons/16/table_go.png" }
  10.159 +        slot.put(_"Change area delegation")
  10.160 +      elseif scope == "area" and not (delegation and delegation.area_id) then
  10.161 +        ui.image{ static = "icons/16/table_go.png" }
  10.162 +        slot.put(_"Set area delegation")
  10.163 +      elseif scope == "issue" then
  10.164 +        if delegation and delegation.issue_id then
  10.165            ui.image{ static = "icons/16/table_go.png" }
  10.166 -          if scope == "global" and delegation then
  10.167 -            slot.put(_"Change global delegation")
  10.168 -          elseif scope == "global" and not delegation then
  10.169 -            slot.put(_"Set global delegation")
  10.170 -          elseif scope == "area" and delegation and delegation.area_id then
  10.171 -            slot.put(_"Change area delegation")
  10.172 -          elseif scope == "area" and not (delegation and delegation.area_id) then
  10.173 -            slot.put(_"Set area delegation")
  10.174 -          elseif scope == "issue" and delegation and delegation.issue_id then
  10.175 -            slot.put(_"Change issue delegation")
  10.176 -          elseif scope == "issue" and not (delegation and delegation.issue_id) then
  10.177 -            slot.put(_"Set issue delegation")
  10.178 -          end
  10.179 -        end,
  10.180 -        module = "delegation",
  10.181 -        view = "new",
  10.182 -        params = {
  10.183 -          area_id = area_id,
  10.184 -          issue_id = issue_id 
  10.185 -        }
  10.186 -      }
  10.187 -    end
  10.188 +          slot.put(_"Change issue delegation")
  10.189 +        elseif issue.state ~= "finished" and issue.state ~= "cancelled" then
  10.190 +          ui.image{ static = "icons/16/table_go.png" }
  10.191 +          slot.put(_"Set issue delegation")
  10.192 +        end
  10.193 +      end
  10.194 +    end,
  10.195 +    module = "delegation",
  10.196 +    view = "new",
  10.197 +    params = {
  10.198 +      area_id = area_id,
  10.199 +      issue_id = issue_id 
  10.200 +    }
  10.201    }
  10.202  end)
    11.1 --- a/app/main/draft/_action/add.lua	Thu Dec 10 12:00:00 2009 +0100
    11.2 +++ b/app/main/draft/_action/add.lua	Fri Dec 25 12:00:00 2009 +0100
    11.3 @@ -1,5 +1,22 @@
    11.4 +local tmp = db:query({ "SELECT text_entries_left FROM member_contingent_left WHERE member_id = ?", app.session.member.id }, "opt_object")
    11.5 +if tmp and tmp.text_entries_left and tmp.text_entries_left < 1 then
    11.6 +  slot.put_into("error", _"Sorry, you have reached your personal flood limit. Please be slower...")
    11.7 +  return false
    11.8 +end
    11.9 +
   11.10  local initiative = Initiative:by_id(param.get("initiative_id", atom.integer))
   11.11  
   11.12 +-- TODO important m1 selectors returning result _SET_!
   11.13 +local issue = initiative:get_reference_selector("issue"):for_share():single_object_mode():exec()
   11.14 +
   11.15 +if issue.closed then
   11.16 +  slot.put_into("error", _"This issue is already closed.")
   11.17 +  return false
   11.18 +elseif issue.half_frozen then 
   11.19 +  slot.put_into("error", _"This issue is already frozen.")
   11.20 +  return false
   11.21 +end
   11.22 +
   11.23  if Initiator:by_pk(initiative.id, app.session.member.id) then
   11.24    local draft = Draft:new()
   11.25    draft.author_id = app.session.member.id
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/app/main/index/_action/register.lua	Fri Dec 25 12:00:00 2009 +0100
    12.3 @@ -0,0 +1,132 @@
    12.4 +local invite_code = InviteCode:by_code(param.get("code"))
    12.5 +
    12.6 +if not invite_code or invite_code.used then
    12.7 +  slot.put_into("error", _"The code you've entered is invalid")
    12.8 +  request.redirect{
    12.9 +    mode   = "forward",
   12.10 +    module = "index",
   12.11 +    view   = "register"
   12.12 +  }
   12.13 +  return false
   12.14 +end
   12.15 +
   12.16 +local name = param.get("name")
   12.17 +
   12.18 +if invite_code and not name then
   12.19 +  slot.put_into("notice", _"Invite code valid!")
   12.20 +  request.redirect{
   12.21 +    mode   = "redirect",
   12.22 +    module = "index",
   12.23 +    view   = "register",
   12.24 +    params = { code = invite_code.code }
   12.25 +  }
   12.26 +  return false
   12.27 +end
   12.28 +
   12.29 +if Member:by_name(name) then
   12.30 +  slot.put_into("error", _"This name is already taken, please choose another one!")
   12.31 +  request.redirect{
   12.32 +    mode   = "redirect",
   12.33 +    module = "index",
   12.34 +    view   = "register",
   12.35 +    params = { code = invite_code.code }
   12.36 +  }
   12.37 +  return false
   12.38 +end
   12.39 +
   12.40 +local login = param.get("login")
   12.41 +
   12.42 +if name and not login then
   12.43 +  slot.put_into("notice", _"Name is available")
   12.44 +  request.redirect{
   12.45 +    mode   = "redirect",
   12.46 +    module = "index",
   12.47 +    view   = "register",
   12.48 +    params = { 
   12.49 +      code = invite_code.code,
   12.50 +      name = name
   12.51 +    }
   12.52 +  }
   12.53 +  return false
   12.54 +end
   12.55 +
   12.56 +if Member:by_login(login) then 
   12.57 +  slot.put_into("error", _"This login is already taken, please choose another one!")
   12.58 +  request.redirect{
   12.59 +    mode   = "redirect",
   12.60 +    module = "index",
   12.61 +    view   = "register",
   12.62 +    params = { 
   12.63 +      code = invite_code.code,
   12.64 +      name = name
   12.65 +    }
   12.66 +  }
   12.67 +  return false
   12.68 +end
   12.69 +
   12.70 +local password1 = param.get("password1")
   12.71 +local password2 = param.get("password2")
   12.72 +
   12.73 +if login and not password1 then
   12.74 +  slot.put_into("notice", _"Login is available")
   12.75 +  request.redirect{
   12.76 +    mode   = "redirect",
   12.77 +    module = "index",
   12.78 +    view   = "register",
   12.79 +    params = { 
   12.80 +      code = invite_code.code,
   12.81 +      name = name,
   12.82 +      login = login
   12.83 +    }
   12.84 +  }
   12.85 +  return false
   12.86 +end
   12.87 +
   12.88 +if password1 ~= password2 then
   12.89 +  slot.put_into("error", _"Passwords don't match!")
   12.90 +  request.redirect{
   12.91 +    mode   = "redirect",
   12.92 +    module = "index",
   12.93 +    view   = "register",
   12.94 +    params = { 
   12.95 +      code = invite_code.code,
   12.96 +      name = name,
   12.97 +      login = login
   12.98 +    }
   12.99 +  }
  12.100 +  return false
  12.101 +end
  12.102 +
  12.103 +if #password1 < 8 then
  12.104 +  slot.put_into("error", _"Passwords must consist of at least 8 characters!")
  12.105 +  request.redirect{
  12.106 +    mode   = "redirect",
  12.107 +    module = "index",
  12.108 +    view   = "register",
  12.109 +    params = { 
  12.110 +      code = invite_code.code,
  12.111 +      name = name,
  12.112 +      login = login
  12.113 +    }
  12.114 +  }
  12.115 +  return false
  12.116 +end
  12.117 +
  12.118 +local member = Member:new()
  12.119 +
  12.120 +member.login = login
  12.121 +member.name = name
  12.122 +member:set_password(password1)
  12.123 +member:save()
  12.124 +
  12.125 +invite_code.member_id = member.id
  12.126 +invite_code.used = "now"
  12.127 +invite_code:save()
  12.128 +
  12.129 +slot.put_into("notice", _"You've successfully registered and you can login now with your login and password!")
  12.130 +
  12.131 +  request.redirect{
  12.132 +    mode   = "redirect",
  12.133 +    module = "index",
  12.134 +    view   = "login",
  12.135 +  }
    13.1 --- a/app/main/index/index.lua	Thu Dec 10 12:00:00 2009 +0100
    13.2 +++ b/app/main/index/index.lua	Fri Dec 25 12:00:00 2009 +0100
    13.3 @@ -96,6 +96,90 @@
    13.4  
    13.5  util.help("index.index", _"Home")
    13.6  
    13.7 +
    13.8 +local selector = Area:new_selector()
    13.9 +  :reset_fields()
   13.10 +  :add_field("area.id", nil, { "grouped" })
   13.11 +  :add_field("area.name", nil, { "grouped" })
   13.12 +  :add_field("membership.member_id NOTNULL", "is_member", { "grouped" })
   13.13 +  :add_field("count(issue.id)", "issues_to_vote_count")
   13.14 +  :add_field("count(interest.member_id)", "interested_issues_to_vote_count")
   13.15 +  :join("issue", nil, "issue.area_id = area.id AND issue.fully_frozen NOTNULL AND issue.closed ISNULL")
   13.16 +  :left_join("direct_voter", nil, { "direct_voter.issue_id = issue.id AND direct_voter.member_id = ?", app.session.member.id })
   13.17 +  :add_where{ "direct_voter.member_id ISNULL" }
   13.18 +  :left_join("interest", nil, { "interest.issue_id = issue.id AND interest.member_id = ?", app.session.member.id })
   13.19 +  :left_join("membership", nil, { "membership.area_id = area.id AND membership.member_id = ? ", app.session.member.id })
   13.20 +
   13.21 +local areas = {}
   13.22 +for i, area in ipairs(selector:exec()) do
   13.23 +  if area.is_member or area.interested_issues_to_vote_count > 0 then
   13.24 +    areas[#areas+1] = area
   13.25 +  end
   13.26 +end
   13.27 +
   13.28 +if #areas > 0 then
   13.29 +  ui.container{
   13.30 +    attr = { style = "font-weight: bold;" },
   13.31 +    content = _"Current votings in areas you are member of and issues you are interested in:"
   13.32 +  }
   13.33 +  
   13.34 +  ui.list{
   13.35 +    records = areas,
   13.36 +    columns = {
   13.37 +      {
   13.38 +        name = "name"
   13.39 +      },
   13.40 +      {
   13.41 +        content = function(record)
   13.42 +          if record.is_member and record.issues_to_vote_count > 0 then
   13.43 +            ui.link{
   13.44 +              content = function()
   13.45 +                if record.issues_to_vote_count > 1 then
   13.46 +                  slot.put(_("#{issues_to_vote_count} issue(s)", { issues_to_vote_count = record.issues_to_vote_count }))
   13.47 +                else
   13.48 +                  slot.put(_("One issue"))
   13.49 +                end
   13.50 +              end,
   13.51 +              module = "area",
   13.52 +              view = "show",
   13.53 +              id = record.id,
   13.54 +              params = { 
   13.55 +                filter = "frozen",
   13.56 +                filter_voting = "not_voted"
   13.57 +              }
   13.58 +            }
   13.59 +          else
   13.60 +            slot.put(_"Not a member")
   13.61 +          end
   13.62 +        end
   13.63 +      },
   13.64 +      {
   13.65 +        content = function(record)
   13.66 +          if record.interested_issues_to_vote_count > 0 then
   13.67 +            ui.link{
   13.68 +              content = function()
   13.69 +                if record.interested_issues_to_vote_count > 1 then
   13.70 +                  slot.put(_("#{interested_issues_to_vote_count} issue(s) you are interested in", { interested_issues_to_vote_count = record.interested_issues_to_vote_count }))
   13.71 +                else
   13.72 +                  slot.put(_"One issue you are interested in")
   13.73 +                end
   13.74 +              end,
   13.75 +              module = "area",
   13.76 +              view = "show",
   13.77 +              id = record.id,
   13.78 +              params = { 
   13.79 +                filter = "frozen",
   13.80 +                filter_interest = "my",
   13.81 +                filter_voting = "not_voted"
   13.82 +              }
   13.83 +            }
   13.84 +          end
   13.85 +        end
   13.86 +      },
   13.87 +    }
   13.88 +  }
   13.89 +end
   13.90 +
   13.91  execute.view{
   13.92    module = "member",
   13.93    view = "_show",
    14.1 --- a/app/main/index/login.lua	Thu Dec 10 12:00:00 2009 +0100
    14.2 +++ b/app/main/index/login.lua	Fri Dec 25 12:00:00 2009 +0100
    14.3 @@ -1,3 +1,15 @@
    14.4 +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."
    14.5 +
    14.6 +ui.script{ static = "js/browser_warning.js" }
    14.7 +ui.script{ script = "checkBrowser(" .. encode.json(_"Your web browser is not fully supported yet." .. " " .. warning_text:gsub("\n", "\n\n")) .. ");" }
    14.8 +
    14.9 +ui.tag{
   14.10 +  tag = "noscript",
   14.11 +  content = function()
   14.12 +    slot.put(_"JavaScript is disabled or not available." .. " " .. encode.html_newlines(warning_text))
   14.13 +  end
   14.14 +}
   14.15 +
   14.16  slot.put_into("title", encode.html(config.app_title))
   14.17  
   14.18  ui.tag{
   14.19 @@ -24,7 +36,7 @@
   14.20    content = function()
   14.21      ui.field.text{
   14.22        attr = { id = "username_field" },
   14.23 -      label     = _'Username',
   14.24 +      label     = _'login name',
   14.25        html_name = 'login',
   14.26        value     = ''
   14.27      }
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/app/main/index/register.lua	Fri Dec 25 12:00:00 2009 +0100
    15.3 @@ -0,0 +1,96 @@
    15.4 +slot.put_into("title", _"Registration")
    15.5 +
    15.6 +slot.select("actions", function()
    15.7 +  ui.link{
    15.8 +    content = function()
    15.9 +        ui.image{ static = "icons/16/cancel.png" }
   15.10 +        slot.put(_"Cancel")
   15.11 +    end,
   15.12 +    module = "index",
   15.13 +    view = "index"
   15.14 +  }
   15.15 +end)
   15.16 +
   15.17 +local code = param.get("code")
   15.18 +local name = param.get("name")
   15.19 +local login = param.get("login")
   15.20 +
   15.21 +ui.form{
   15.22 +  attr = { class = "login" },
   15.23 +  module = 'index',
   15.24 +  action = 'register',
   15.25 +  params = {
   15.26 +    code = code,
   15.27 +    name = name,
   15.28 +    login = login
   15.29 +  },
   15.30 +  content = function()
   15.31 +
   15.32 +    if not code then
   15.33 +      ui.tag{
   15.34 +        tag = "p",
   15.35 +        content = _"Please enter the invite code you've received."
   15.36 +      }
   15.37 +      ui.field.text{
   15.38 +        label     = _'Invite code',
   15.39 +        name = 'code',
   15.40 +      }
   15.41 +
   15.42 +    elseif not name then
   15.43 +      ui.tag{
   15.44 +        tag = "p",
   15.45 +        content = _"Please choose a name, i.e. your real name or your nick name. This name will be shown to others to identify you. You CAN'T change this name later, so please choose it wisely!"
   15.46 +      }
   15.47 +      ui.field.text{
   15.48 +        label     = _'Name',
   15.49 +        name      = 'name',
   15.50 +        value     = param.get("name")
   15.51 +      }
   15.52 +
   15.53 +    elseif not login then
   15.54 +      ui.tag{
   15.55 +        tag = "p",
   15.56 +        content = _"Please choose a login name. This name will not be shown to others and is used only by you to login into the system. The login name is case sensitive."
   15.57 +      }
   15.58 +      ui.field.text{
   15.59 +        label     = _'Login name',
   15.60 +        name      = 'login',
   15.61 +        value     = param.get("login")
   15.62 +      }
   15.63 +
   15.64 +    else
   15.65 +      ui.field.text{
   15.66 +        label     = _'Name',
   15.67 +        name      = 'name',
   15.68 +        value     = param.get("name"),
   15.69 +        readonly = true
   15.70 +      }
   15.71 +      ui.field.text{
   15.72 +        label     = _'Login name',
   15.73 +        name      = 'login',
   15.74 +        value     = param.get("login"),
   15.75 +        readonly = true
   15.76 +      }
   15.77 +      ui.tag{
   15.78 +        tag = "p",
   15.79 +        content = _"Please choose a password and enter it twice. The password is case sensitive."
   15.80 +      }
   15.81 +      ui.field.password{
   15.82 +        label     = _'Password',
   15.83 +        name      = 'password1',
   15.84 +      }
   15.85 +      ui.field.password{
   15.86 +        label     = _'Password (repeat)',
   15.87 +        name      = 'password2',
   15.88 +      }
   15.89 +
   15.90 +    end
   15.91 +
   15.92 +    ui.submit{
   15.93 +      text = _'Register'
   15.94 +    }
   15.95 +
   15.96 +  end
   15.97 +}
   15.98 +
   15.99 +
    16.1 --- a/app/main/initiative/_action/add_support.lua	Thu Dec 10 12:00:00 2009 +0100
    16.2 +++ b/app/main/initiative/_action/add_support.lua	Fri Dec 25 12:00:00 2009 +0100
    16.3 @@ -1,5 +1,16 @@
    16.4  local initiative = Initiative:new_selector():add_where{ "id = ?", param.get_id()}:single_object_mode():exec()
    16.5  
    16.6 +-- TODO important m1 selectors returning result _SET_!
    16.7 +local issue = initiative:get_reference_selector("issue"):for_share():single_object_mode():exec()
    16.8 +
    16.9 +if issue.closed then
   16.10 +  slot.put_into("error", _"This issue is already closed.")
   16.11 +  return false
   16.12 +elseif issue.fully_frozen then 
   16.13 +  slot.put_into("error", _"Voting for this issue has already begun.")
   16.14 +  return false
   16.15 +end
   16.16 +
   16.17  local member = app.session.member
   16.18  
   16.19  local supporter = Supporter:by_pk(initiative.id, member.id)
    17.1 --- a/app/main/initiative/_action/create.lua	Thu Dec 10 12:00:00 2009 +0100
    17.2 +++ b/app/main/initiative/_action/create.lua	Fri Dec 25 12:00:00 2009 +0100
    17.3 @@ -1,13 +1,29 @@
    17.4 +local tmp = db:query({ "SELECT text_entries_left, initiatives_left FROM member_contingent_left WHERE member_id = ?", app.session.member.id }, "opt_object")
    17.5 +if tmp then
    17.6 +  if tmp.initiatives_left and tmp.initiatives_left < 1 then
    17.7 +    slot.put_into("error", _"Sorry, your contingent for creating initiatives has been used up. Please try again later.")
    17.8 +    return false
    17.9 +  end
   17.10 +  if tmp.text_entries_left and tmp.text_entries_left < 1 then
   17.11 +    slot.put_into("error", _"Sorry, you have reached your personal flood limit. Please be slower...")
   17.12 +    return false
   17.13 +  end
   17.14 +end
   17.15 +
   17.16  local issue
   17.17  local area
   17.18  
   17.19 -db:query("BEGIN")
   17.20 -
   17.21  local issue_id = param.get("issue_id", atom.integer)
   17.22  if issue_id then
   17.23    issue = Issue:new_selector():add_where{"id=?",issue_id}:single_object_mode():exec()
   17.24 +  if issue.closed then
   17.25 +    slot.put_into("error", _"This issue is already closed.")
   17.26 +    return false
   17.27 +  elseif issue.fully_frozen then 
   17.28 +    slot.put_into("error", _"Voting for this issue has already begun.")
   17.29 +    return false
   17.30 +  end
   17.31    area = issue.area
   17.32 -
   17.33  else
   17.34    local area_id = param.get("area_id", atom.integer)
   17.35    area = Area:new_selector():add_where{"id=?",area_id}:single_object_mode():exec()
   17.36 @@ -22,6 +38,8 @@
   17.37    issue:save()
   17.38  end
   17.39  
   17.40 +
   17.41 +
   17.42  initiative.issue_id = issue.id
   17.43  
   17.44  param.update(initiative, "name", "discussion_url")
   17.45 @@ -55,8 +73,6 @@
   17.46  supporter.draft_id = draft.id
   17.47  supporter:save()
   17.48  
   17.49 -db:query("COMMIT")
   17.50 -
   17.51  slot.put_into("notice", _"Initiative successfully created")
   17.52  
   17.53  request.redirect{
    18.1 --- a/app/main/initiative/_action/remove_support.lua	Thu Dec 10 12:00:00 2009 +0100
    18.2 +++ b/app/main/initiative/_action/remove_support.lua	Fri Dec 25 12:00:00 2009 +0100
    18.3 @@ -1,5 +1,16 @@
    18.4  local initiative = Initiative:new_selector():add_where{ "id = ?", param.get_id()}:single_object_mode():exec()
    18.5  
    18.6 +-- TODO important m1 selectors returning result _SET_!
    18.7 +local issue = initiative:get_reference_selector("issue"):for_share():single_object_mode():exec()
    18.8 +
    18.9 +if issue.closed then
   18.10 +  slot.put_into("error", _"This issue is already closed.")
   18.11 +  return false
   18.12 +elseif issue.fully_frozen then 
   18.13 +  slot.put_into("error", _"Voting for this issue has already begun.")
   18.14 +  return false
   18.15 +end
   18.16 +
   18.17  local member = app.session.member
   18.18  
   18.19  local supporter = Supporter:by_pk(initiative.id, member.id)
    19.1 --- a/app/main/initiative/_list.lua	Thu Dec 10 12:00:00 2009 +0100
    19.2 +++ b/app/main/initiative/_list.lua	Fri Dec 25 12:00:00 2009 +0100
    19.3 @@ -9,32 +9,32 @@
    19.4    order_options[#order_options+1] = {
    19.5      name = "rank",
    19.6      label = _"Rank",
    19.7 -    order_by = "initiative.rank"
    19.8 +    order_by = "initiative.rank, initiative.admitted DESC, vote_ratio(initiative.positive_votes, initiative.negative_votes) DESC, initiative.id"
    19.9    }
   19.10  end
   19.11  
   19.12  order_options[#order_options+1] = {
   19.13 +  name = "potential_support",
   19.14 +  label = _"Potential support",
   19.15 +  order_by = "initiative.supporter_count::float / issue.population::float DESC, initiative.id"
   19.16 +}
   19.17 +
   19.18 +order_options[#order_options+1] = {
   19.19    name = "support",
   19.20    label = _"Support",
   19.21 -  order_by = "initiative.supporter_count::float / issue.population::float DESC"
   19.22 -}
   19.23 -
   19.24 -order_options[#order_options+1] = {
   19.25 -  name = "support_si",
   19.26 -  label = _"Support S+I",
   19.27 -  order_by = "initiative.satisfied_informed_supporter_count::float / issue.population::float DESC"
   19.28 +  order_by = "initiative.satisfied_supporter_count::float / issue.population::float DESC, initiative.id"
   19.29  }
   19.30  
   19.31  order_options[#order_options+1] = {
   19.32    name = "newest",
   19.33    label = _"Newest",
   19.34 -  order_by = "initiative.created DESC"
   19.35 +  order_by = "initiative.created DESC, initiative.id"
   19.36  }
   19.37  
   19.38  order_options[#order_options+1] = {
   19.39    name = "oldest",
   19.40    label = _"Oldest",
   19.41 -  order_by = "initiative.created"
   19.42 +  order_by = "initiative.created, initiative.id"
   19.43  }
   19.44  
   19.45  local name = "initiative_list"
   19.46 @@ -61,18 +61,22 @@
   19.47          }
   19.48          columns[#columns+1] = {
   19.49            content = function(record)
   19.50 -            if record.issue.accepted and record.issue.closed and record.issue.ranks_available then 
   19.51 -              if record.negative_votes and record.positive_votes then
   19.52 -                local max_value = record.issue.voter_count
   19.53 -                ui.bargraph{
   19.54 -                  max_value = max_value,
   19.55 -                  width = 100,
   19.56 -                  bars = {
   19.57 -                    { color = "#0a0", value = record.positive_votes },
   19.58 -                    { color = "#aaa", value = max_value - record.negative_votes - record.positive_votes },
   19.59 -                    { color = "#a00", value = record.negative_votes },
   19.60 +            if record.issue.accepted and record.issue.closed then
   19.61 +              if record.issue.ranks_available then 
   19.62 +                if record.negative_votes and record.positive_votes then
   19.63 +                  local max_value = record.issue.voter_count
   19.64 +                  ui.bargraph{
   19.65 +                    max_value = max_value,
   19.66 +                    width = 100,
   19.67 +                    bars = {
   19.68 +                      { color = "#0a0", value = record.positive_votes },
   19.69 +                      { color = "#aaa", value = max_value - record.negative_votes - record.positive_votes },
   19.70 +                      { color = "#a00", value = record.negative_votes },
   19.71 +                    }
   19.72                    }
   19.73 -                }
   19.74 +                end
   19.75 +              else
   19.76 +                slot.put(_"Counting of votes")
   19.77                end
   19.78              else
   19.79                local max_value = (record.issue.population or 0)
   19.80 @@ -81,7 +85,7 @@
   19.81                  width = 100,
   19.82                  bars = {
   19.83                    { color = "#0a0", value = (record.satisfied_supporter_count or 0) },
   19.84 -                  { color = "#8f8", value = (record.supporter_count or 0) - (record.satisfied_supporter_count or 0) },
   19.85 +                  { color = "#777", value = (record.supporter_count or 0) - (record.satisfied_supporter_count or 0) },
   19.86                    { color = "#ddd", value = max_value - (record.supporter_count or 0) },
   19.87                  }
   19.88                }
    20.1 --- a/app/main/initiative/new.lua	Thu Dec 10 12:00:00 2009 +0100
    20.2 +++ b/app/main/initiative/new.lua	Fri Dec 25 12:00:00 2009 +0100
    20.3 @@ -33,7 +33,7 @@
    20.4        ui.field.select{
    20.5          label = _"Policy",
    20.6          name = "policy_id",
    20.7 -        foreign_records = Policy:new_selector():exec(),
    20.8 +        foreign_records = Policy:new_selector():add_order_by("index"):exec(),
    20.9          foreign_id = "id",
   20.10          foreign_name = "name"
   20.11        }
    21.1 --- a/app/main/initiative/show.lua	Thu Dec 10 12:00:00 2009 +0100
    21.2 +++ b/app/main/initiative/show.lua	Fri Dec 25 12:00:00 2009 +0100
    21.3 @@ -1,6 +1,16 @@
    21.4  local initiative = Initiative:new_selector():add_where{ "id = ?", param.get_id()}:single_object_mode():exec()
    21.5  
    21.6 -
    21.7 +slot.select("actions", function()
    21.8 +  ui.link{
    21.9 +    content = function()
   21.10 +      ui.image{ static = "icons/16/script.png" }
   21.11 +      slot.put(_"Show all initiatives")
   21.12 +    end,
   21.13 +    module = "issue",
   21.14 +    view = "show",
   21.15 +    id = initiative.issue.id
   21.16 +  }
   21.17 +end)
   21.18  
   21.19  execute.view{
   21.20    module = "issue",
   21.21 @@ -18,55 +28,11 @@
   21.22    params = { initiative = initiative }
   21.23  }
   21.24  
   21.25 ---[[
   21.26 -
   21.27 -execute.view{
   21.28 -  module = "delegation",
   21.29 -  view = "_show_box",
   21.30 -  params = { issue_id = initiative.issue_id }
   21.31 -}
   21.32 -
   21.33 -execute.view{
   21.34 -  module = "issue",
   21.35 -  view = "_show_box",
   21.36 -  params = { issue = initiative.issue }
   21.37 -}
   21.38 -
   21.39 -
   21.40 -slot.select("path", function()
   21.41 -  ui.link{
   21.42 -    content = _"Area '#{name}'":gsub("#{name}", initiative.issue.area.name),
   21.43 -    module = "area",
   21.44 -    view = "show",
   21.45 -    id = initiative.issue.area.id
   21.46 -  }
   21.47 -  ui.container{ content = "::" }
   21.48 -  ui.link{
   21.49 -    content = _"Issue ##{id}":gsub("#{id}", initiative.issue.id),
   21.50 -    module = "issue",
   21.51 -    view = "show",
   21.52 -    id = initiative.issue.id
   21.53 -  }
   21.54 -end)
   21.55 -
   21.56 -slot.put_into("title", encode.html(_"Initiative: '#{name}'":gsub("#{name}", initiative.shortened_name) ))
   21.57 ---]]
   21.58 -
   21.59  slot.put_into("sub_title", encode.html(_"Initiative: '#{name}'":gsub("#{name}", initiative.shortened_name) ))
   21.60  
   21.61  slot.select("actions", function()
   21.62 -
   21.63    if not initiative.issue.fully_frozen and not initiative.issue.closed then
   21.64      ui.link{
   21.65 -      content = function()
   21.66 -        ui.image{ static = "icons/16/script.png" }
   21.67 -        slot.put(_"Show other initiatives")
   21.68 -      end,
   21.69 -      module = "issue",
   21.70 -      view = "show",
   21.71 -      id = initiative.issue.id
   21.72 -    }
   21.73 -    ui.link{
   21.74        attr = { class = "action" },
   21.75        content = function()
   21.76          ui.image{ static = "icons/16/script_add.png" }
   21.77 @@ -77,8 +43,6 @@
   21.78        params = { issue_id = initiative.issue.id }
   21.79      }
   21.80    end
   21.81 ---  ui.twitter("http://example.com/i" .. tostring(initiative.id) .. " " .. initiative.name)
   21.82 -
   21.83  end)
   21.84  
   21.85  
   21.86 @@ -99,7 +63,7 @@
   21.87            ui.link{
   21.88              attr = {
   21.89                class = "actions",
   21.90 -              target = _"blank",
   21.91 +              target = "_blank",
   21.92                title = initiative.discussion_url
   21.93              },
   21.94              content = function()
   21.95 @@ -256,7 +220,7 @@
   21.96          }
   21.97        }
   21.98        slot.put("<br />")
   21.99 -      if not initiative.issue.frozen and not initiative.issue.closed then
  21.100 +      if not initiative.issue.fully_frozen and not initiative.issue.closed then
  21.101          ui.link{
  21.102            content = function()
  21.103              ui.image{ static = "icons/16/comment_add.png" }
  21.104 @@ -269,7 +233,7 @@
  21.105      end
  21.106    },
  21.107    {
  21.108 -    name = "supporter",
  21.109 +    name = "satisfied_supporter",
  21.110      label = _"Supporter",
  21.111      content = function()
  21.112        execute.view{
  21.113 @@ -282,6 +246,26 @@
  21.114              :join("direct_interest_snapshot", nil, "direct_interest_snapshot.event = issue.latest_snapshot_event AND direct_interest_snapshot.issue_id = issue.id AND direct_interest_snapshot.member_id = member.id")
  21.115              :add_field("direct_interest_snapshot.weight")
  21.116              :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event")
  21.117 +            :add_where("direct_supporter_snapshot.satisfied")
  21.118 +        }
  21.119 +      }
  21.120 +    end
  21.121 +  },
  21.122 +  {
  21.123 +    name = "supporter",
  21.124 +    label = _"Potential supporter",
  21.125 +    content = function()
  21.126 +      execute.view{
  21.127 +        module = "member",
  21.128 +        view = "_list",
  21.129 +        params = {
  21.130 +          initiative = initiative,
  21.131 +          members_selector =  initiative:get_reference_selector("supporting_members_snapshot")
  21.132 +            :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id")
  21.133 +            :join("direct_interest_snapshot", nil, "direct_interest_snapshot.event = issue.latest_snapshot_event AND direct_interest_snapshot.issue_id = issue.id AND direct_interest_snapshot.member_id = member.id")
  21.134 +            :add_field("direct_interest_snapshot.weight")
  21.135 +            :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event")
  21.136 +            :add_where("NOT direct_supporter_snapshot.satisfied")
  21.137          }
  21.138        }
  21.139      end
    22.1 --- a/app/main/interest/_action/update.lua	Thu Dec 10 12:00:00 2009 +0100
    22.2 +++ b/app/main/interest/_action/update.lua	Fri Dec 25 12:00:00 2009 +0100
    22.3 @@ -1,6 +1,18 @@
    22.4  local issue_id = assert(param.get("issue_id", atom.integer), "no issue id given")
    22.5 +
    22.6  local interest = Interest:by_pk(issue_id, app.session.member.id)
    22.7  
    22.8 +-- TODO important m1 selectors returning result _SET_!
    22.9 +local issue = interest:get_reference_selector("issue"):for_share():single_object_mode():exec()
   22.10 +
   22.11 +if issue.closed then
   22.12 +  slot.put_into("error", _"This issue is already closed.")
   22.13 +  return false
   22.14 +elseif issue.fully_frozen then 
   22.15 +  slot.put_into("error", _"Voting for this issue has already begun.")
   22.16 +  return false
   22.17 +end
   22.18 +
   22.19  if param.get("delete", atom.boolean) then
   22.20    if interest then
   22.21      interest:destroy()
    23.1 --- a/app/main/interest/_show_box.lua	Thu Dec 10 12:00:00 2009 +0100
    23.2 +++ b/app/main/interest/_show_box.lua	Fri Dec 25 12:00:00 2009 +0100
    23.3 @@ -15,6 +15,9 @@
    23.4              onclick = "document.getElementById('interest_content').style.display = 'block';"
    23.5            },
    23.6            content = function()
    23.7 +            ui.image{
    23.8 +              static = "icons/16/eye.png"
    23.9 +            }
   23.10              slot.put(_"Your are interested")
   23.11              ui.image{
   23.12                static = "icons/16/dropdown.png"
   23.13 @@ -35,33 +38,39 @@
   23.14                  ui.image{ static = "icons/16/cross.png" }
   23.15                end
   23.16              }
   23.17 -            ui.link{
   23.18 -              content = _"Remove my interest",
   23.19 -              module = "interest",
   23.20 -              action = "update",
   23.21 -              params = { issue_id = issue.id, delete = true },
   23.22 -              routing = { default = { mode = "redirect", module = "issue", view = "show", id = issue.id } }
   23.23 -            }
   23.24 -            slot.put("<br />")
   23.25 -            slot.put("<br />")
   23.26 +            if issue.state ~= "finished" and issue.state ~= "cancelled" and issue.state ~= "voting" then
   23.27 +              ui.link{
   23.28 +                content = _"Remove my interest",
   23.29 +                module = "interest",
   23.30 +                action = "update",
   23.31 +                params = { issue_id = issue.id, delete = true },
   23.32 +                routing = { default = { mode = "redirect", module = "issue", view = "show", id = issue.id } }
   23.33 +              }
   23.34 +              slot.put("<br />")
   23.35 +              slot.put("<br />")
   23.36 +            end
   23.37              if interest.autoreject then
   23.38                ui.field.text{ value = _"Autoreject is on." }
   23.39 -              ui.link{
   23.40 -                content = _"Remove autoreject",
   23.41 -                module = "interest",
   23.42 -                action = "update",
   23.43 -                params = { issue_id = issue.id, autoreject = false },
   23.44 -                routing = { default = { mode = "redirect", module = "issue", view = "show", id = issue.id } }
   23.45 -              }
   23.46 +              if issue.state ~= "finished" and issue.state ~= "cancelled" then
   23.47 +                ui.link{
   23.48 +                  content = _"Remove autoreject",
   23.49 +                  module = "interest",
   23.50 +                  action = "update",
   23.51 +                  params = { issue_id = issue.id, autoreject = false },
   23.52 +                  routing = { default = { mode = "redirect", module = "issue", view = "show", id = issue.id } }
   23.53 +                }
   23.54 +              end
   23.55              else
   23.56                ui.field.text{ value = _"Autoreject is off." }
   23.57 -              ui.link{
   23.58 -                content = _"Set autoreject",
   23.59 -                module = "interest",
   23.60 -                action = "update",
   23.61 -                params = { issue_id = issue.id, autoreject = true },
   23.62 -                routing = { default = { mode = "redirect", module = "issue", view = "show", id = issue.id } }
   23.63 -              }
   23.64 +              if issue.state ~= "finished" and issue.state ~= "cancelled" then
   23.65 +                ui.link{
   23.66 +                  content = _"Set autoreject",
   23.67 +                  module = "interest",
   23.68 +                  action = "update",
   23.69 +                  params = { issue_id = issue.id, autoreject = true },
   23.70 +                  routing = { default = { mode = "redirect", module = "issue", view = "show", id = issue.id } }
   23.71 +                }
   23.72 +              end
   23.73              end
   23.74            end
   23.75          }
    24.1 --- a/app/main/issue/_list.lua	Thu Dec 10 12:00:00 2009 +0100
    24.2 +++ b/app/main/issue/_list.lua	Fri Dec 25 12:00:00 2009 +0100
    24.3 @@ -1,7 +1,12 @@
    24.4  local issues_selector = param.get("issues_selector", "table")
    24.5  
    24.6 +local ui_filter = ui.filter
    24.7 +if param.get("filter", atom.boolean) == false then
    24.8 +  ui_filter = function(args) args.content() end
    24.9 +end
   24.10  
   24.11 -ui.filter{
   24.12 +local filter_voting = false
   24.13 +ui_filter{
   24.14    selector = issues_selector,
   24.15    filters = {
   24.16      {
   24.17 @@ -36,7 +41,7 @@
   24.18        label = _"Frozen",
   24.19        selector_modifier = function(selector, value)
   24.20          if value then
   24.21 -          selector:add_where("issue.half_frozen NOTNULL AND issue.closed ISNULL")
   24.22 +          selector:add_where("issue.half_frozen NOTNULL AND issue.fully_frozen ISNULL")
   24.23          end
   24.24        end
   24.25      },
   24.26 @@ -47,6 +52,7 @@
   24.27        selector_modifier = function(selector, value)
   24.28          if value then
   24.29            selector:add_where("issue.fully_frozen NOTNULL AND issue.closed ISNULL")
   24.30 +          filter_voting = true
   24.31          end
   24.32        end
   24.33      },
   24.34 @@ -56,7 +62,7 @@
   24.35        label = _"Finished",
   24.36        selector_modifier = function(selector, value)
   24.37          if value then
   24.38 -          selector:add_where("issue.closed NOTNULL AND ranks_available")
   24.39 +          selector:add_where("issue.closed NOTNULL AND issue.fully_frozen NOTNULL")
   24.40          end
   24.41        end
   24.42      },
   24.43 @@ -66,98 +72,203 @@
   24.44        label = _"Cancelled",
   24.45        selector_modifier = function(selector, value)
   24.46          if value then
   24.47 -          selector:add_where("issue.closed NOTNULL AND NOT ranks_available")
   24.48 +          selector:add_where("issue.closed NOTNULL AND issue.accepted ISNULL")
   24.49          end
   24.50        end
   24.51      },
   24.52    },
   24.53    content = function()
   24.54 -    ui.order{
   24.55 -      name = "issue_list",
   24.56 +    local ui_filter = ui.filter
   24.57 +    if not filter_voting then
   24.58 +      ui_filter = function(args) args.content() end
   24.59 +    end
   24.60 +    ui_filter{
   24.61        selector = issues_selector,
   24.62 -      options = {
   24.63 +      name = "filter_voting",
   24.64 +      filters = {
   24.65          {
   24.66 -          name = "population",
   24.67 -          label = _"Population",
   24.68 -          order_by = "issue.population DESC"
   24.69 +          type = "boolean",
   24.70 +          name = "any",
   24.71 +          label = _"Any",
   24.72 +          selector_modifier = function()  end
   24.73          },
   24.74          {
   24.75 -          name = "newest",
   24.76 -          label = _"Newest",
   24.77 -          order_by = "issue.created DESC"
   24.78 +          type = "boolean",
   24.79 +          name = "not_voted",
   24.80 +          label = _"Not voted",
   24.81 +          selector_modifier = function(selector, value)
   24.82 +            if value then
   24.83 +              selector:left_join("direct_voter", nil, { "direct_voter.issue_id = issue.id AND direct_voter.member_id = ?", app.session.member.id })
   24.84 +              selector:add_where("direct_voter.member_id ISNULL")
   24.85 +            end
   24.86 +          end
   24.87          },
   24.88          {
   24.89 -          name = "oldest",
   24.90 -          label = _"Oldest",
   24.91 -          order_by = "issue.created"
   24.92 -        }
   24.93 +          type = "boolean",
   24.94 +          name = "voted",
   24.95 +          label = _"Voted",
   24.96 +          selector_modifier = function(selector, value)
   24.97 +            if value then
   24.98 +              selector:join("direct_voter", nil, { "direct_voter.issue_id = issue.id AND direct_voter.member_id = ?", app.session.member.id })
   24.99 +            end
  24.100 +          end
  24.101 +        },
  24.102        },
  24.103        content = function()
  24.104 -        ui.paginate{
  24.105 +        local ui_filter = ui.filter
  24.106 +        if param.get("filter", atom.boolean) == false then
  24.107 +          ui_filter = function(args) args.content() end
  24.108 +        end
  24.109 +        ui_filter{
  24.110            selector = issues_selector,
  24.111 +          name = "filter_interest",
  24.112 +          filters = {
  24.113 +            {
  24.114 +              type = "boolean",
  24.115 +              name = "any",
  24.116 +              label = _"Any",
  24.117 +              selector_modifier = function()  end
  24.118 +            },
  24.119 +            {
  24.120 +              type = "boolean",
  24.121 +              name = "my",
  24.122 +              label = _"Interested",
  24.123 +              selector_modifier = function(selector, value)
  24.124 +                if value then
  24.125 +                  selector:join("interest", "filter_interest", { "filter_interest.issue_id = issue.id AND filter_interest.member_id = ? ", app.session.member.id })
  24.126 +                end
  24.127 +              end
  24.128 +            },
  24.129 +          },
  24.130            content = function()
  24.131 -            local highlight_string = param.get("highlight_string", "string")
  24.132 -            local issues = issues or issues_selector:exec()
  24.133 ---            issues:load(initiatives)
  24.134 -            ui.list{
  24.135 -              attr = { class = "issues" },
  24.136 -              records = issues,
  24.137 -              columns = {
  24.138 +
  24.139 +            ui.order{
  24.140 +              name = "issue_list",
  24.141 +              selector = issues_selector,
  24.142 +              options = {
  24.143                  {
  24.144 -                  label = _"Issue",
  24.145 -                  content = function(record)
  24.146 -                    if not param.get("for_area_list", atom.boolean) then
  24.147 -                      ui.field.text{
  24.148 -                        value = record.area.name
  24.149 -                      }
  24.150 -                      slot.put("<br />")
  24.151 -                    end
  24.152 -                    ui.link{
  24.153 -                      text = _"Issue ##{id}":gsub("#{id}", tostring(record.id)),
  24.154 -                      module = "issue",
  24.155 -                      view = "show",
  24.156 -                      id = record.id
  24.157 -                    }
  24.158 -                    if record.state == "new" then
  24.159 -                      ui.image{
  24.160 -                        static = "icons/16/new.png"
  24.161 -                      }
  24.162 -                    end
  24.163 -                    slot.put("<br />")
  24.164 -                    slot.put("<br />")
  24.165 +                  name = "max_potential_support",
  24.166 +                  label = _"Max potential support",
  24.167 +                  selector_modifier = function(selector)
  24.168 +                    selector:add_order_by("(SELECT max(supporter_count) FROM initiative WHERE initiative.issue_id = issue.id)")
  24.169                    end
  24.170                  },
  24.171                  {
  24.172 -                  label = _"State",
  24.173 -                  content = function(record)
  24.174 -                    ui.field.issue_state{ value = record.state }
  24.175 +                  name = "max_support",
  24.176 +                  label = _"Max support",
  24.177 +                  selector_modifier = function(selector)
  24.178 +                    selector:add_order_by("(SELECT max(satisfied_supporter_count) FROM initiative WHERE initiative.issue_id = issue.id)")
  24.179                    end
  24.180                  },
  24.181                  {
  24.182 -                  label = _"Initiatives",
  24.183 -                  content = function(record)
  24.184 -                    local initiatives_selector = record:get_reference_selector("initiatives")
  24.185 -                    local highlight_string = param.get("highlight_string")
  24.186 -                    if highlight_string then
  24.187 -                      initiatives_selector:add_field( {'"highlight"("initiative"."name", ?)', highlight_string }, "name_highlighted")
  24.188 -                    end
  24.189 -                    execute.view{
  24.190 -                      module = "initiative",
  24.191 -                      view = "_list",
  24.192 -                      params = {
  24.193 -                        issue = record,
  24.194 -                        initiatives_selector = initiatives_selector,
  24.195 -                        highlight_string = highlight_string,
  24.196 -                        limit = 3
  24.197 +                  name = "population",
  24.198 +                  label = _"Population",
  24.199 +                  order_by = "issue.population DESC"
  24.200 +                },
  24.201 +                {
  24.202 +                  name = "newest",
  24.203 +                  label = _"Newest",
  24.204 +                  order_by = "issue.created DESC"
  24.205 +                },
  24.206 +                {
  24.207 +                  name = "oldest",
  24.208 +                  label = _"Oldest",
  24.209 +                  order_by = "issue.created"
  24.210 +                }
  24.211 +              },
  24.212 +              content = function()
  24.213 +                ui.paginate{
  24.214 +                  selector = issues_selector,
  24.215 +                  content = function()
  24.216 +                    local highlight_string = param.get("highlight_string", "string")
  24.217 +                    local issues = issues or issues_selector:exec()
  24.218 +        --            issues:load(initiatives)
  24.219 +                    ui.list{
  24.220 +                      attr = { class = "issues" },
  24.221 +                      records = issues,
  24.222 +                      columns = {
  24.223 +                        {
  24.224 +                          label = _"Issue",
  24.225 +                          content = function(record)
  24.226 +                            if not param.get("for_area_list", atom.boolean) then
  24.227 +                              ui.field.text{
  24.228 +                                value = record.area.name
  24.229 +                              }
  24.230 +                              slot.put("<br />")
  24.231 +                            end
  24.232 +                            ui.link{
  24.233 +                              text = _"Issue ##{id}":gsub("#{id}", tostring(record.id)),
  24.234 +                              module = "issue",
  24.235 +                              view = "show",
  24.236 +                              id = record.id
  24.237 +                            }
  24.238 +                            if record.state == "new" then
  24.239 +                              ui.image{
  24.240 +                                static = "icons/16/new.png"
  24.241 +                              }
  24.242 +                            end
  24.243 +                            slot.put("<br />")
  24.244 +                            slot.put("<br />")
  24.245 +                          end
  24.246 +                        },
  24.247 +                        {
  24.248 +                          label = _"State",
  24.249 +                          content = function(record)
  24.250 +                            ui.field.issue_state{ value = record.state }
  24.251 +                          end
  24.252 +                        },
  24.253 +                        {
  24.254 +                          label = _"Initiatives",
  24.255 +                          content = function(record)
  24.256 +                            local initiatives_selector = record:get_reference_selector("initiatives")
  24.257 +                            local highlight_string = param.get("highlight_string")
  24.258 +                            if highlight_string then
  24.259 +                              initiatives_selector:add_field( {'"highlight"("initiative"."name", ?)', highlight_string }, "name_highlighted")
  24.260 +                            end
  24.261 +                            execute.view{
  24.262 +                              module = "initiative",
  24.263 +                              view = "_list",
  24.264 +                              params = {
  24.265 +                                issue = record,
  24.266 +                                initiatives_selector = initiatives_selector,
  24.267 +                                highlight_string = highlight_string,
  24.268 +                                limit = 3
  24.269 +                              }
  24.270 +                            }
  24.271 +                          end
  24.272 +                        },
  24.273                        }
  24.274                      }
  24.275                    end
  24.276 -                },
  24.277 -              }
  24.278 +                }
  24.279 +              end
  24.280              }
  24.281            end
  24.282          }
  24.283        end
  24.284      }
  24.285 +    if param.get("legend", atom.boolean) ~= false then
  24.286 +      local filter = param.get_all_cgi().filter
  24.287 +      if not filter or filter == "any" or filter ~= "finished" then
  24.288 +        ui.bargraph_legend{
  24.289 +          width = 25,
  24.290 +          bars = {
  24.291 +            { color = "#0a0", label = _"Supporter" },
  24.292 +            { color = "#777", label = _"Potential supporter" },
  24.293 +            { color = "#ddd", label = _"No support at all" },
  24.294 +          }
  24.295 +        }
  24.296 +      end
  24.297 +      if not filter or filter == "any" or filter == "finished" then
  24.298 +        ui.bargraph_legend{
  24.299 +          width = 25,
  24.300 +          bars = {
  24.301 +            { color = "#0a0", label = _"Yes" },
  24.302 +            { color = "#aaa", label = _"Abstention" },
  24.303 +            { color = "#a00", label = _"No" },
  24.304 +          }
  24.305 +        }
  24.306 +      end
  24.307 +    end
  24.308    end
  24.309  }
    25.1 --- a/app/main/issue/_show_head.lua	Thu Dec 10 12:00:00 2009 +0100
    25.2 +++ b/app/main/issue/_show_head.lua	Fri Dec 25 12:00:00 2009 +0100
    25.3 @@ -11,21 +11,35 @@
    25.4    }
    25.5  end)
    25.6  
    25.7 -slot.put_into("title", encode.html(_"Issue ##{id} (#{policy_name})":gsub("#{id}", issue.id):gsub("#{policy_name}", issue.policy.name)))
    25.8 +slot.select("title", function()
    25.9 +  ui.link{
   25.10 +    content = _"Issue ##{id} (#{policy_name})":gsub("#{id}", issue.id):gsub("#{policy_name}", issue.policy.name),
   25.11 +    module = "issue",
   25.12 +    view = "show",
   25.13 +    id = issue.id
   25.14 +  }
   25.15 +end)
   25.16 +
   25.17  
   25.18  slot.select("actions", function()
   25.19 +
   25.20 +  if issue.state == 'voting' then
   25.21 +    ui.link{
   25.22 +      content = function()
   25.23 +        ui.image{ static = "icons/16/email_open.png" }
   25.24 +        slot.put(_"Vote now")
   25.25 +      end,
   25.26 +      module = "vote",
   25.27 +      view = "list",
   25.28 +      params = { issue_id = issue.id }
   25.29 +    }
   25.30 +  end
   25.31 +
   25.32    execute.view{
   25.33      module = "interest",
   25.34      view = "_show_box",
   25.35      params = { issue = issue }
   25.36    }
   25.37 -  
   25.38 -  execute.view{
   25.39 -    module = "delegation",
   25.40 -    view = "_show_box",
   25.41 -    params = { issue_id = issue.id }
   25.42 -  }
   25.43 -  
   25.44    -- TODO performance
   25.45    local interest = Interest:by_pk(issue.id, app.session.member.id)
   25.46    if not issue.closed and not issue.fully_frozen then
   25.47 @@ -43,6 +57,23 @@
   25.48      end
   25.49    end
   25.50  
   25.51 +  if not issue.closed then
   25.52 +    execute.view{
   25.53 +      module = "delegation",
   25.54 +      view = "_show_box",
   25.55 +      params = { issue_id = issue.id }
   25.56 +    }
   25.57 +  end
   25.58 + 
   25.59 +  if issue.state == "accepted" then
   25.60 +    -- TODO
   25.61 +    ui.link{
   25.62 +      content = function()
   25.63 +        ui.image{ static = "icons/16/time.png" }
   25.64 +        slot.put(_"Vote now/later")
   25.65 +      end,
   25.66 +    }
   25.67 +  end
   25.68  
   25.69  end)
   25.70  
    26.1 --- a/app/main/issue/show.lua	Thu Dec 10 12:00:00 2009 +0100
    26.2 +++ b/app/main/issue/show.lua	Fri Dec 25 12:00:00 2009 +0100
    26.3 @@ -12,7 +12,8 @@
    26.4    {
    26.5      name = "initiatives",
    26.6      label = _"Initiatives",
    26.7 -    content = function()      execute.view{
    26.8 +    content = function()
    26.9 +      execute.view{
   26.10          module = "initiative",
   26.11          view = "_list",
   26.12          params = { 
    27.1 --- a/app/main/member/_action/update.lua	Thu Dec 10 12:00:00 2009 +0100
    27.2 +++ b/app/main/member/_action/update.lua	Fri Dec 25 12:00:00 2009 +0100
    27.3 @@ -1,5 +1,4 @@
    27.4  param.update(app.session.member,
    27.5 -  "name",
    27.6    "organizational_unit",
    27.7    "internal_posts",
    27.8    "realname",
    28.1 --- a/app/main/member/edit.lua	Thu Dec 10 12:00:00 2009 +0100
    28.2 +++ b/app/main/member/edit.lua	Fri Dec 25 12:00:00 2009 +0100
    28.3 @@ -26,7 +26,6 @@
    28.4      }
    28.5    },
    28.6    content = function()
    28.7 -    ui.field.text{ label = _"Name", name = "name" }
    28.8      ui.field.text{ label = _"Organizational unit", name = "organizational_unit" }
    28.9      ui.field.text{ label = _"Internal posts", name = "internal_posts" }
   28.10      ui.field.text{ label = _"Real name", name = "realname" }
    29.1 --- a/app/main/opinion/_action/update.lua	Thu Dec 10 12:00:00 2009 +0100
    29.2 +++ b/app/main/opinion/_action/update.lua	Fri Dec 25 12:00:00 2009 +0100
    29.3 @@ -4,6 +4,19 @@
    29.4  
    29.5  local opinion = Opinion:by_pk(member_id, suggestion_id)
    29.6  
    29.7 +-- TODO important m1 selectors returning result _SET_!
    29.8 +local issue = opinion.initiative:get_reference_selector("issue"):for_share():single_object_mode():exec()
    29.9 +
   29.10 +if issue.closed then
   29.11 +  slot.put_into("error", _"This issue is already closed.")
   29.12 +  return false
   29.13 +elseif issue.fully_frozen then 
   29.14 +  slot.put_into("error", _"Voting for this issue has already begun.")
   29.15 +  return false
   29.16 +end
   29.17 +
   29.18 +
   29.19 +
   29.20  if param.get("delete") then
   29.21    if opinion then
   29.22      opinion:destroy()
    30.1 --- a/app/main/suggestion/_action/add.lua	Thu Dec 10 12:00:00 2009 +0100
    30.2 +++ b/app/main/suggestion/_action/add.lua	Fri Dec 25 12:00:00 2009 +0100
    30.3 @@ -1,4 +1,8 @@
    30.4 -db:query("BEGIN")
    30.5 +local tmp = db:query({ "SELECT text_entries_left FROM member_contingent_left WHERE member_id = ?", app.session.member.id }, "opt_object")
    30.6 +if tmp and tmp.text_entries_left and tmp.text_entries_left < 1 then
    30.7 +  slot.put_into("error", _"Sorry, you have reached your personal flood limit. Please be slower...")
    30.8 +  return false
    30.9 +end
   30.10  
   30.11  local suggestion = Suggestion:new()
   30.12  
   30.13 @@ -6,6 +10,17 @@
   30.14  param.update(suggestion, "name", "description", "initiative_id")
   30.15  suggestion:save()
   30.16  
   30.17 +-- TODO important m1 selectors returning result _SET_!
   30.18 +local issue = suggestion.initiative:get_reference_selector("issue"):for_share():single_object_mode():exec()
   30.19 +
   30.20 +if issue.closed then
   30.21 +  slot.put_into("error", _"This issue is already closed.")
   30.22 +  return false
   30.23 +elseif issue.fully_frozen then 
   30.24 +  slot.put_into("error", _"Voting for this issue has already begun.")
   30.25 +  return false
   30.26 +end
   30.27 +
   30.28  local opinion = Opinion:new()
   30.29  
   30.30  opinion.suggestion_id = suggestion.id
   30.31 @@ -15,6 +30,4 @@
   30.32  
   30.33  opinion:save()
   30.34  
   30.35 -db:query("COMMIT")
   30.36 -
   30.37  slot.put_into("notice", _"Your suggestion has been added")
   30.38 \ No newline at end of file
    31.1 --- a/app/main/suggestion/_list.lua	Thu Dec 10 12:00:00 2009 +0100
    31.2 +++ b/app/main/suggestion/_list.lua	Fri Dec 25 12:00:00 2009 +0100
    31.3 @@ -105,60 +105,69 @@
    31.4                  if opinion then
    31.5                    degree = opinion.degree
    31.6                  end
    31.7 -                ui.link{
    31.8 -                  attr = { class = "action" .. (degree == -2 and " active_red2" or "") },
    31.9 -                  text = _"must not",
   31.10 -                  module = "opinion",
   31.11 -                  action = "update",
   31.12 -                  routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
   31.13 -                  params = {
   31.14 -                    suggestion_id = record.id,
   31.15 -                    degree = -2
   31.16 -                  }
   31.17 -                }
   31.18 -                ui.link{
   31.19 -                  attr = { class = "action" .. (degree == -1 and " active_red1" or "") },
   31.20 -                  text = _"should not",
   31.21 -                  module = "opinion",
   31.22 -                  action = "update",
   31.23 -                  routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
   31.24 -                  params = {
   31.25 -                    suggestion_id = record.id,
   31.26 -                    degree = -1
   31.27 -                  }
   31.28 -                }
   31.29 -                ui.link{
   31.30 -                  attr = { class = "action" .. (degree == nil and " active" or "") },
   31.31 -                  text = _"neutral",
   31.32 -                  module = "opinion",
   31.33 -                  action = "update",
   31.34 -                  routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
   31.35 -                  params = {
   31.36 -                    suggestion_id = record.id,
   31.37 -                    delete = true
   31.38 -                  }
   31.39 -                }
   31.40 -                ui.link{
   31.41 -                  attr = { class = "action" .. (degree == 1 and " active_green1" or "") },
   31.42 -                  text = _"should",
   31.43 -                  module = "opinion",
   31.44 -                  action = "update",
   31.45 -                  routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
   31.46 -                  params = {
   31.47 -                    suggestion_id = record.id,
   31.48 -                    degree = 1
   31.49 -                  }
   31.50 -                }
   31.51 -                ui.link{
   31.52 -                  attr = { class = "action" .. (degree == 2 and " active_green2" or "") },
   31.53 -                  text = _"must",
   31.54 -                  module = "opinion",
   31.55 -                  action = "update",
   31.56 -                  routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
   31.57 -                  params = {
   31.58 -                    suggestion_id = record.id,
   31.59 -                    degree = 2
   31.60 -                  }
   31.61 +                ui.container{
   31.62 +                  attr = { class = "suggestion_my_opinion" },
   31.63 +                  content = function()
   31.64 +                    ui.link{
   31.65 +                      attr = { class = "action" .. (degree == -2 and " active_red2" or "") },
   31.66 +                      text = _"must not",
   31.67 +                      module = "opinion",
   31.68 +                      action = "update",
   31.69 +                      routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
   31.70 +                      params = {
   31.71 +                        suggestion_id = record.id,
   31.72 +                        degree = -2
   31.73 +                      }
   31.74 +                    }
   31.75 +                    slot.put(" ")
   31.76 +                    ui.link{
   31.77 +                      attr = { class = "action" .. (degree == -1 and " active_red1" or "") },
   31.78 +                      text = _"should not",
   31.79 +                      module = "opinion",
   31.80 +                      action = "update",
   31.81 +                      routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
   31.82 +                      params = {
   31.83 +                        suggestion_id = record.id,
   31.84 +                        degree = -1
   31.85 +                      }
   31.86 +                    }
   31.87 +                    slot.put(" ")
   31.88 +                    ui.link{
   31.89 +                      attr = { class = "action" .. (degree == nil and " active" or "") },
   31.90 +                      text = _"neutral",
   31.91 +                      module = "opinion",
   31.92 +                      action = "update",
   31.93 +                      routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
   31.94 +                      params = {
   31.95 +                        suggestion_id = record.id,
   31.96 +                        delete = true
   31.97 +                      }
   31.98 +                    }
   31.99 +                    slot.put(" ")
  31.100 +                    ui.link{
  31.101 +                      attr = { class = "action" .. (degree == 1 and " active_green1" or "") },
  31.102 +                      text = _"should",
  31.103 +                      module = "opinion",
  31.104 +                      action = "update",
  31.105 +                      routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
  31.106 +                      params = {
  31.107 +                        suggestion_id = record.id,
  31.108 +                        degree = 1
  31.109 +                      }
  31.110 +                    }
  31.111 +                    slot.put(" ")
  31.112 +                    ui.link{
  31.113 +                      attr = { class = "action" .. (degree == 2 and " active_green2" or "") },
  31.114 +                      text = _"must",
  31.115 +                      module = "opinion",
  31.116 +                      action = "update",
  31.117 +                      routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
  31.118 +                      params = {
  31.119 +                        suggestion_id = record.id,
  31.120 +                        degree = 2
  31.121 +                      }
  31.122 +                    }
  31.123 +                  end
  31.124                  }
  31.125                end
  31.126              },
    32.1 --- a/app/main/supporter/_show_box.lua	Thu Dec 10 12:00:00 2009 +0100
    32.2 +++ b/app/main/supporter/_show_box.lua	Fri Dec 25 12:00:00 2009 +0100
    32.3 @@ -1,29 +1,48 @@
    32.4  
    32.5  slot.select("support", function()
    32.6    local initiative = param.get("initiative", "table")
    32.7 -  local supported = Supporter:by_pk(initiative.id, app.session.member.id) and true or false
    32.8 +  local supporter = Supporter:by_pk(initiative.id, app.session.member.id)
    32.9  
   32.10    ui.container{
   32.11      attr = { class = "actions" },
   32.12      content = function()
   32.13 -      if not initiative.issue.frozen and not initiative.issue.closed then
   32.14 -        if supported then
   32.15 -          ui.container{
   32.16 -            attr = {
   32.17 -              class = "head head_active",
   32.18 -              style = "cursor: pointer;",
   32.19 -              onclick = "document.getElementById('support_content').style.display = 'block';"
   32.20 -            },
   32.21 -            content = function()
   32.22 -              ui.image{
   32.23 -                static = "icons/16/thumb_up_green.png"
   32.24 -              }
   32.25 -              slot.put(_"Your are supporter")
   32.26 -              ui.image{
   32.27 -                static = "icons/16/dropdown.png"
   32.28 -              }
   32.29 -            end
   32.30 -          }
   32.31 +      if not initiative.issue.fully_frozen and not initiative.issue.closed then
   32.32 +        if supporter then
   32.33 +          if not supporter:has_critical_opinion() then
   32.34 +            ui.container{
   32.35 +              attr = {
   32.36 +                class = "head head_supporter",
   32.37 +                style = "cursor: pointer;",
   32.38 +                onclick = "document.getElementById('support_content').style.display = 'block';"
   32.39 +              },
   32.40 +              content = function()
   32.41 +                ui.image{
   32.42 +                  static = "icons/16/thumb_up_green.png"
   32.43 +                }
   32.44 +                slot.put(_"Your are supporter")
   32.45 +                ui.image{
   32.46 +                  static = "icons/16/dropdown.png"
   32.47 +                }
   32.48 +              end
   32.49 +            }
   32.50 +          else
   32.51 +            ui.container{
   32.52 +              attr = {
   32.53 +                class = "head head_potential_supporter",
   32.54 +                style = "cursor: pointer;",
   32.55 +                onclick = "document.getElementById('support_content').style.display = 'block';"
   32.56 +              },
   32.57 +              content = function()
   32.58 +                ui.image{
   32.59 +                  static = "icons/16/thumb_up.png"
   32.60 +                }
   32.61 +                slot.put(_"Your are potential supporter")
   32.62 +                ui.image{
   32.63 +                  static = "icons/16/dropdown.png"
   32.64 +                }
   32.65 +              end
   32.66 +            }
   32.67 +          end
   32.68            ui.container{
   32.69              attr = { class = "content", id = "support_content" },
   32.70              content = function()
   32.71 @@ -37,7 +56,7 @@
   32.72                    ui.image{ static = "icons/16/cross.png" }
   32.73                  end
   32.74                }
   32.75 -              if supported then
   32.76 +              if supporter then
   32.77                  ui.link{
   32.78                    content = function()
   32.79                      ui.image{ static = "icons/16/thumb_down_red.png" }
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/app/main/vote/_action/update.lua	Fri Dec 25 12:00:00 2009 +0100
    33.3 @@ -0,0 +1,47 @@
    33.4 +local issue = Issue:new_selector():add_where{ "id = ?", param.get("issue_id", atom.integer) }:for_share():single_object_mode():exec()
    33.5 +
    33.6 +if issue.closed then
    33.7 +  slot.put_into("error", _"This issue is already closed.")
    33.8 +  return false
    33.9 +end
   33.10 +
   33.11 +if issue.state ~= "voting" then
   33.12 +  slot.put_into("error", _"Voting has not started yet.")
   33.13 +  return false
   33.14 +end
   33.15 +
   33.16 +local direct_voter = DirectVoter:by_pk(issue.id, app.session.member_id)
   33.17 +
   33.18 +if not direct_voter then
   33.19 +  direct_voter = DirectVoter:new()
   33.20 +  direct_voter.issue_id = issue.id
   33.21 +  direct_voter.member_id = app.session.member_id
   33.22 +end
   33.23 +
   33.24 +direct_voter.autoreject = false
   33.25 +
   33.26 +direct_voter:save()
   33.27 +
   33.28 +
   33.29 +local scoring = param.get("scoring")
   33.30 +
   33.31 +for initiative_id, grade in scoring:gmatch("([^:;]+):([^:;]+)") do
   33.32 +  local initiative_id = tonumber(initiative_id)
   33.33 +  local grade = tonumber(grade)
   33.34 +  local initiative = Initiative:by_id(initiative_id)
   33.35 +  if initiative.issue.id ~= issue.id then
   33.36 +    error("initiative from wrong issue")
   33.37 +  end
   33.38 +  local vote = Vote:by_pk(initiative_id, app.session.member.id)
   33.39 +  if not vote then
   33.40 +    vote = Vote:new()
   33.41 +    vote.issue_id = issue.id
   33.42 +    vote.initiative_id = initiative.id
   33.43 +    vote.member_id = app.session.member.id
   33.44 +  end
   33.45 +  vote.grade = grade
   33.46 +  vote:save()
   33.47 +end
   33.48 +
   33.49 +trace.debug(scoring)
   33.50 +
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/app/main/vote/list.lua	Fri Dec 25 12:00:00 2009 +0100
    34.3 @@ -0,0 +1,138 @@
    34.4 +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."
    34.5 +
    34.6 +ui.script{ static = "js/browser_warning.js" }
    34.7 +ui.script{ script = "checkBrowser(" .. encode.json(_"Your web browser is not fully supported yet." .. " " .. warning_text:gsub("\n", "\n\n")) .. ");" }
    34.8 +
    34.9 +ui.tag{
   34.10 +  tag = "noscript",
   34.11 +  content = function()
   34.12 +    slot.put(_"JavaScript is disabled or not available." .. " " .. encode.html_newlines(warning_text))
   34.13 +  end
   34.14 +}
   34.15 +
   34.16 +
   34.17 +local issue = Issue:by_id(param.get("issue_id"), atom.integer)
   34.18 +
   34.19 +local initiatives = issue.initiatives
   34.20 +
   34.21 +local min_grade = -1;
   34.22 +local max_grade = 1;
   34.23 +
   34.24 +for i, initiative in ipairs(initiatives) do
   34.25 +  -- TODO performance
   34.26 +  initiative.vote = Vote:by_pk(initiative.id, app.session.member.id)
   34.27 +  if initiative.vote then
   34.28 +    if initiative.vote.grade > max_grade then
   34.29 +      max_grade = initiative.vote.grade
   34.30 +    end
   34.31 +    if initiative.vote.grade < min_grade then
   34.32 +      min_grade = initiative.vote.grade
   34.33 +    end
   34.34 +  end
   34.35 +end
   34.36 +
   34.37 +local sections = {}
   34.38 +for i = min_grade, max_grade do
   34.39 +  sections[i] = {}
   34.40 +  for j, initiative in ipairs(initiatives) do
   34.41 +    if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then
   34.42 +      sections[i][#(sections[i])+1] = initiative
   34.43 +    end
   34.44 +  end
   34.45 +end
   34.46 +
   34.47 +slot.put_into("title", _"Voting")
   34.48 +
   34.49 +slot.select("actions", function()
   34.50 +  ui.link{
   34.51 +    content = function()
   34.52 +        ui.image{ static = "icons/16/cancel.png" }
   34.53 +        slot.put(_"Cancel")
   34.54 +    end,
   34.55 +    module = "issue",
   34.56 +    view = "show",
   34.57 +    id = issue.id
   34.58 +  }
   34.59 +end)
   34.60 +
   34.61 +util.help("vote.list", _"Voting")
   34.62 +
   34.63 +
   34.64 +slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/dragdrop.js"></script>')
   34.65 +slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/voting.js"></script>')
   34.66 +
   34.67 +ui.form{
   34.68 +  attr = { id = "voting_form" },
   34.69 +  module = "vote",
   34.70 +  action = "update",
   34.71 +  params = { issue_id = issue.id },
   34.72 +  routing = {
   34.73 +    default = {
   34.74 +      mode = "redirect",
   34.75 +      module = "issue",
   34.76 +      view = "show",
   34.77 +      id = issue.id
   34.78 +    }
   34.79 +  },
   34.80 +  content = function()
   34.81 +    slot.put('<input type="hidden" name="scoring" value=""/>')
   34.82 +    -- TODO abstrahieren
   34.83 +    ui.tag{
   34.84 +      tag = "input",
   34.85 +      attr = {
   34.86 +        type = "button",
   34.87 +        class = "voting_done",
   34.88 +        value = _"Finish voting"
   34.89 +      }
   34.90 +    }
   34.91 +    ui.container{
   34.92 +      attr = { id = "voting" },
   34.93 +      content = function()
   34.94 +        for grade = max_grade, min_grade, -1 do 
   34.95 +          local section = sections[grade]
   34.96 +          local class
   34.97 +          if grade > 0 then
   34.98 +            class = "approval"
   34.99 +          elseif grade < 0 then
  34.100 +            class = "disapproval"
  34.101 +          else
  34.102 +            class = "abstention"
  34.103 +          end
  34.104 +          ui.container{
  34.105 +            attr = { class = class },
  34.106 +            content = function()
  34.107 +              slot.put('<div class="cathead"></div>')
  34.108 +              for i, initiative in ipairs(section) do
  34.109 +                ui.container{
  34.110 +                  attr = {
  34.111 +                    class = "movable",
  34.112 +                    id = "entry_" .. tostring(initiative.id)
  34.113 +                  },
  34.114 +                  content = function()
  34.115 +                    ui.link{
  34.116 +                      attr = { class = "clickable" },
  34.117 +                      content = initiative.name,
  34.118 +                      module = "initiative",
  34.119 +                      view = "show",
  34.120 +                      id = initiative.id
  34.121 +                    }
  34.122 +                  end
  34.123 +                }
  34.124 +              end
  34.125 +            end
  34.126 +          }
  34.127 +        end
  34.128 +      end
  34.129 +    }
  34.130 +    ui.tag{
  34.131 +      tag = "input",
  34.132 +      attr = {
  34.133 +        type = "button",
  34.134 +        class = "voting_done",
  34.135 +        value = _"Finish voting"
  34.136 +      }
  34.137 +    }
  34.138 +  end
  34.139 +}
  34.140 +
  34.141 +
    35.1 --- a/config/default.lua	Thu Dec 10 12:00:00 2009 +0100
    35.2 +++ b/config/default.lua	Fri Dec 25 12:00:00 2009 +0100
    35.3 @@ -1,5 +1,5 @@
    35.4  config.app_name = "LiquidFeedback"
    35.5 -config.app_version = "alpha5"
    35.6 +config.app_version = "beta1"
    35.7  
    35.8  config.app_title = config.app_name .. " (" .. request.get_config_name() .. " environment)"
    35.9  
    36.1 --- a/env/ui/order.lua	Thu Dec 10 12:00:00 2009 +0100
    36.2 +++ b/env/ui/order.lua	Fri Dec 25 12:00:00 2009 +0100
    36.3 @@ -16,7 +16,11 @@
    36.4              local attr = {}
    36.5              if current_order == option.name then
    36.6                attr.class = "active"
    36.7 -              args.selector:add_order_by(option.order_by)
    36.8 +              if option.selector_modifier then
    36.9 +                option.selector_modifier(args.selector)
   36.10 +              else
   36.11 +                args.selector:add_order_by(option.order_by)
   36.12 +              end
   36.13              end
   36.14              ui.link{
   36.15                attr    = attr,
    37.1 --- a/fastpath/Makefile	Thu Dec 10 12:00:00 2009 +0100
    37.2 +++ b/fastpath/Makefile	Fri Dec 25 12:00:00 2009 +0100
    37.3 @@ -1,5 +1,5 @@
    37.4  getpic: getpic.c
    37.5 -	cc -g -Wall -o getpic getpic.c -I /usr/pkg/include/ -I /usr/include/postgresql -L /usr/pkg/lib -L /usr/lib/postgresql -lpq -Wl,-rpath,/usr/pkg/lib -Wl,-rpath,/usr/lib/postgresql
    37.6 +	cc -g -Wall -o getpic getpic.c -I `pg_config --includedir` -L `pg_config --libdir` -lpq -Wl,-rpath,`pg_config --libdir`
    37.7  
    37.8  clean::
    37.9  	rm -f getpic
    38.1 --- a/fastpath/getpic.c	Thu Dec 10 12:00:00 2009 +0100
    38.2 +++ b/fastpath/getpic.c	Fri Dec 25 12:00:00 2009 +0100
    38.3 @@ -16,67 +16,50 @@
    38.4  #endif
    38.5  
    38.6  int main(int argc, const char * const *argv) {
    38.7 -  PGconn *conn;
    38.8 -  PGresult *dbr;
    38.9 -
   38.10 -  char *cookies = getenv("HTTP_COOKIE");
   38.11  
   38.12    char *args_string;
   38.13    char *member_id;
   38.14    char *image_type;
   38.15 -
   38.16 -  char *sql_session_params[1];
   38.17    char *sql_member_image_params[2];
   38.18  
   38.19 +  char *cookies;
   38.20 +  regex_t session_ident_regex;
   38.21    ssize_t start, length;
   38.22 -
   38.23 +  regmatch_t session_ident_regmatch[3];
   38.24    char *session_ident;
   38.25 +  char *sql_session_params[1];
   38.26  
   38.27 -  regex_t session_ident_regex;
   38.28 -  regmatch_t session_ident_regmatch[2];
   38.29 -
   38.30 -  cookies = getenv("HTTP_COOKIE");
   38.31 +  PGconn *conn;
   38.32 +  PGresult *dbr;
   38.33  
   38.34    args_string = getenv("QUERY_STRING");
   38.35 -
   38.36 -  if (!cookies || !args_string) {
   38.37 +  cookies = getenv("HTTP_COOKIE");
   38.38 +  if (!args_string || !cookies) {
   38.39      fputs("Status: 403 Access Denied\n\n", stdout);
   38.40      return 0;
   38.41    }
   38.42  
   38.43    member_id   = strtok(args_string, "+");
   38.44    image_type  = strtok(NULL, "+");
   38.45 -
   38.46    sql_member_image_params[0] = member_id;
   38.47    sql_member_image_params[1] = image_type;
   38.48  
   38.49 -  // get session from cookie
   38.50 -
   38.51 -  // TODO improve regex to fit better
   38.52 -  if (regcomp(&session_ident_regex, "liquid_feedback_session=([a-zA-Z0-9]+)", REG_EXTENDED) != 0) {
   38.53 +  if (regcomp(&session_ident_regex, "(^|[; \t])liquid_feedback_session=([0-9A-Za-z]+)", REG_EXTENDED) != 0) {
   38.54      // shouldn't happen
   38.55      abort();
   38.56    }
   38.57 -
   38.58    if (regexec(&session_ident_regex, cookies, 2, session_ident_regmatch, 0) != 0) {
   38.59      fputs("Status: 403 Access Denied\n\n", stdout);
   38.60      return 0;
   38.61    }
   38.62 -
   38.63 -  start = session_ident_regmatch[1].rm_so;
   38.64 -  length = session_ident_regmatch[1].rm_eo - session_ident_regmatch[1].rm_so;
   38.65 -
   38.66 +  start = session_ident_regmatch[2].rm_so;
   38.67 +  length = session_ident_regmatch[2].rm_eo - session_ident_regmatch[2].rm_so;
   38.68    session_ident = malloc(length + 1);
   38.69 -
   38.70 +  if (!session_ident) abort();  // shouldn't happen
   38.71    strncpy(session_ident, cookies + start, length);
   38.72 -
   38.73    session_ident[length] = 0;
   38.74 -
   38.75    sql_session_params[0] = session_ident;
   38.76  
   38.77 -
   38.78 -  // connect to database
   38.79 -
   38.80    conn = PQconnectdb(GETPIC_CONNINFO);
   38.81    if (!conn) {
   38.82      fputs("Could not create PGconn structure.\n", stderr);
   38.83 @@ -84,27 +67,25 @@
   38.84    }
   38.85    if (PQstatus(conn) != CONNECTION_OK) {
   38.86      fputs(PQerrorMessage(conn), stderr);
   38.87 +    PQfinish(conn);
   38.88      return 1;
   38.89    }
   38.90  
   38.91 -  // check session
   38.92    dbr = PQexecParams(conn,
   38.93      "SELECT NULL FROM session JOIN member ON member.id = session.member_id WHERE session.ident = $1 AND member.active",
   38.94      1, NULL, sql_session_params, NULL, NULL, 0
   38.95    );
   38.96 -
   38.97    if (PQresultStatus(dbr) != PGRES_TUPLES_OK) {
   38.98      fputs(PQresultErrorMessage(dbr), stderr);
   38.99 +    PQfinish(conn);
  38.100      return 1;
  38.101    }
  38.102 -
  38.103    if (PQntuples(dbr) != 1) {
  38.104      fputs("Status: 403 Access Denied\n\n", stdout);
  38.105 +    PQfinish(conn);
  38.106      return 0;
  38.107    }
  38.108  
  38.109 -
  38.110 -  // get picture
  38.111    dbr = PQexecParams(conn,
  38.112      "SELECT content_type, data "
  38.113      "FROM member_image "
  38.114 @@ -114,35 +95,34 @@
  38.115      "LIMIT 1;",
  38.116      2, NULL, sql_member_image_params, NULL, NULL, 1
  38.117    );
  38.118 -
  38.119    if (PQresultStatus(dbr) != PGRES_TUPLES_OK) {
  38.120      fputs(PQresultErrorMessage(dbr), stderr);
  38.121 -		return 1;
  38.122 -  }
  38.123 -  if (PQntuples(dbr) > 1) {
  38.124 +    PQfinish(conn);
  38.125      return 1;
  38.126    }
  38.127 -  fputs("Cache-Control: private; max-age=86400\n", stdout);
  38.128    if (PQntuples(dbr) == 0) {
  38.129      struct stat sb;
  38.130      PQclear(dbr);
  38.131      PQfinish(conn);
  38.132      fputs("Content-Type: image/jpeg\n\n", stdout);
  38.133      if (stat(GETPIC_DEFAULT_AVATAR, &sb)) return 1;
  38.134 -    fprintf(stdout, "Content-Length: %i\n", sb.st_size);
  38.135 +    fprintf(stdout, "Content-Length: %i\n", (int)sb.st_size);
  38.136      execl("/bin/cat", "cat", GETPIC_DEFAULT_AVATAR, NULL);
  38.137      return 1;
  38.138    } else {
  38.139      if (PQnfields(dbr) < 0) {
  38.140        fputs("Too few columns returned by database.\n", stderr);
  38.141 +      PQfinish(conn);
  38.142        return 1;
  38.143      }
  38.144      if (PQfformat(dbr, 0) != 1 || PQfformat(dbr, 1) != 1) {
  38.145        fputs("Database did not return data in binary format.\n", stderr);
  38.146 +      PQfinish(conn);
  38.147        return 1;
  38.148      }
  38.149      if (PQgetisnull(dbr, 0, 0) || PQgetisnull(dbr, 0, 1)) {
  38.150        fputs("Unexpected NULL in database result.\n", stderr);
  38.151 +      PQfinish(conn);
  38.152        return 1;
  38.153      }
  38.154      fputs("Content-Type: ", stdout);
  38.155 @@ -151,7 +131,7 @@
  38.156      fputs("\n\n", stdout);
  38.157      fwrite(PQgetvalue(dbr, 0, 1), PQgetlength(dbr, 0, 1), 1, stdout);
  38.158    }
  38.159 -  PQclear(dbr);
  38.160    PQfinish(conn);
  38.161    return 0;
  38.162 +
  38.163  }
    39.1 --- a/locale/help/area.show.de.txt	Thu Dec 10 12:00:00 2009 +0100
    39.2 +++ b/locale/help/area.show.de.txt	Fri Dec 25 12:00:00 2009 +0100
    39.3 @@ -1,6 +1,8 @@
    39.4 -=Themenbereich, Mitgliedschaft=
    39.5 -Für die Teilnahme an der Diskussion und Endabstimmung einzelner Themen ist die Mitgliedschaft im Themenbereich **keine** Voraussetzung. Mit der Mitgliedschaft erklärst du vielmehr ein generelles Interesse an diesem Themenbereich.
    39.6 -=Delegation, Auto-Ablehnen=
    39.7 -Du kannst deine Stimme für diesen Themenbereich (unabhängig von deiner Mitgliedschaft im Themenbereich) an eine Person in deiner Kontaktliste delegieren. Als Themenbereichsmitglied kannst du ,,Auto-Ablehnen'' als Standardabstimmverhalten festlegen. Diese Weisung gilt nur für den Fall, dass du nicht selbst an der Endabstimmung teilnimmst, es keine tatsächlich genutzte Delegation und keine Weisung für das jeweilige konkrete Thema gibt.
    39.8 -=Neues Thema=
    39.9 -Hier kannst du mit einer eigenen Initiative ein neues Thema eröffnen. **Bevor** du ein neues Thema eröffnest, solltest du prüfen, ob es dieses Thema vieleicht schon gibt. Eine Initiative zu einem bestehenden Thema (Alternativantrag) kannst du von der jeweilige Themenseite aus starten.
   39.10 +=Thema, Interesse=
   39.11 +Auf dieser Seite werden alle Initiativen zu diesem Thema aufgelistet. Wenn du ,,Interesse am Thema'' anmeldest, wirst du für dieses Thema den Mitgliedern des übergeordneten Themenbereichs gleichgestellt und erhöhst die Bemessungsgrundlage der von Initiativen zu erreichenden Unterstützerquoren. Sobald du eine Initiative dieses Themas unterstützt, wird dein Interesse auch automatisch angemeldet. Sofern du allen Initiativen die Unterstützung entziehst, bleibt dein Interesse dennoch bestehen bis du es abmeldest. 
   39.12 +=Delegation, Auto-Ablehnung=
   39.13 +Eine Delegation zu diesem Thema geht einer eventuell vorhandenen globalen Delegation und/oder Delegation für den übergeordneten Themenbereich vor. Eine eventuelle Weisung zur Auto-Ablehung gilt nur für den Fall, dass du nicht selbst an der Endabstimmung teilnimmst und es keine tatsächlich genutzte Delegation gibt. Bei angemeldetem Interesse werden ausgehende Delegationen während der Diskussionsphase ausgesetzt, gelten aber in der Endabstimmung.
   39.14 +=Diskussionsphase=
   39.15 +Während der Diskussionsphase (Zustände ,,Neu'' und ,,Diskussion'') solltest du **alle** Initiativen, die du grundsätzlich (oder unter bestimmten Bedingungen) für zustimmungsfähig hältst, unterstützen und Anregungen zur Verbesserung geben (Näheres dazu findest du auf der Initiativenseite). Hierdurch gibst du den Initiatoren die Chance, den Entwurf zu verbessern. Während dieser Phase hast du auch die Möglichkeit, eine eigene (konkurrierende) Initiative zu diesem Thema zu starten und um Unterstützung zu ringen. 
   39.16 +=Endabstimmung=
   39.17 +Initiativen, die ein bestimmtes Quorum erreichen, werden in die Endabstimmung übernommen. Du kannst dann alle Initiativen, denen du zustimmen möchtest, in eine Präferenzreihenfolge bringen. Bei den anderen Initiativen kannst Du dich enthalten oder auch dagegen stimmen (letzteres ebenfalls mit Präferenz). Beschlossen werden können nur Initiativen die insgesamt mehr Ja- als Nein-Stimmen erhalten.
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/locale/help/vote.list.de.txt	Fri Dec 25 12:00:00 2009 +0100
    40.3 @@ -0,0 +1,8 @@
    40.4 +=Abstimmmung=
    40.5 +Je nachdem, welche Standardeinstellungen du gewählt hast, befinden sich zu Beginn der Abstimmung alle Initiativen im Feld Enthaltung oder im Feld Ablehnung. Beginne am besten mit deinem Favoriten und ziehe ihn mit der Maus in das Feld Zustimmung. Danach wählst du die nächste Initiative, der du zustimmen möchtest und ziehst sie
    40.6 +- in die gleiche grüne Box, falls du dieser Initiative gleichberechtigt zustimmen möchtest oder
    40.7 +- zwischen die Zustimmungs- und Enthaltungsbox, falls diese Initiative dein Ersatzwunsch sein soll.
    40.8 +
    40.9 +Auf diese Weise fährst du fort und legst die Präferenzreihenfolge der Initiativen, denen du zustimmen möchtest fest, wobei du gleichwertige Initiativen jeweils in die gleiche Box hineinziehst. Dann legst du deine Enthaltungen und Ablehnungen fest, wobei du auch die Ablehnungen in eine Rangreihenfolge bringen kannst, falls eine der Initiativen so etwas wie das ,,kleinere Übel'' darstellen sollte.
   40.10 +
   40.11 +**Wichtig:** Verlasse diese Seite über die Schaltfläche ,,Stimmabgabe abschließen''. Bis zum Ende der Abstimmung kannst du deine Angaben jederzeit ändern. Es werden keine Zwischenergebnisse der Abstimmung veröffentlicht. Die Unterstützerangaben auf der Themenübersichtsseite beziehen sich auf die abgeschlossene Diskussion, beziehen sich jeweils auf die einzelne Initiative und sind nur sehr bedingt geeignet, zwischen den Initiativen zu vergleichen. Insbesondere enthalten sie keinerlei Informationen über Präferenzen. Darüber hinaus kann sich der Teilnehmerkreis von Diskussion und Abstimmung erheblich unterscheiden.
    41.1 --- a/locale/translations.de.lua	Thu Dec 10 12:00:00 2009 +0100
    41.2 +++ b/locale/translations.de.lua	Fri Dec 25 12:00:00 2009 +0100
    41.3 @@ -1,12 +1,15 @@
    41.4  #!/usr/bin/env lua
    41.5  return {
    41.6 +["#{interested_issues_to_vote_count} issue(s) you are interested in"] = "#{interested_issues_to_vote_count} Themen, die Dich interessieren";
    41.7 +["#{issues_to_vote_count} issue(s)"] = "#{issues_to_vote_count} Themen";
    41.8  ["#{number} Image(s) has been deleted"] = "Es wurde(n) #{number} Bild(er) gelöscht";
    41.9  ["#{number} Image(s) has been updated"] = "Es wurde(n) #{number} Bild(er) aktualisiert";
   41.10  ["(change URL)"] = "(URL ändern)";
   41.11 -["+ #{weight}"] = false;
   41.12 -["A-Z"] = false;
   41.13 -["About"] = false;
   41.14 +["+ #{weight}"] = "+ #{weight}";
   41.15 +["A-Z"] = "A-Z";
   41.16 +["About"] = "About";
   41.17  ["About LiquidFeedback"] = "Über LiquidFeedback";
   41.18 +["Abstention"] = "Enthaltung";
   41.19  ["Accepted at"] = "Angenommen am/um";
   41.20  ["Active?"] = "Aktiv?";
   41.21  ["Add my interest"] = "Mein Interesse anmelden";
   41.22 @@ -17,7 +20,7 @@
   41.23  ["Admin"] = "Admin";
   41.24  ["Admin menu"] = "Admin Menü";
   41.25  ["Admin?"] = "Admin?";
   41.26 -["Administrator"] = false;
   41.27 +["Administrator"] = "Administrator";
   41.28  ["Admission time"] = "Zeit für die Zulassung";
   41.29  ["Admitted"] = "zugelassen";
   41.30  ["Any"] = "Alle";
   41.31 @@ -31,7 +34,7 @@
   41.32  ["Author"] = "Autor";
   41.33  ["Autoreject is off."] = "Auto-Ablehnen ist aus";
   41.34  ["Autoreject is on."] = "Auto-Ablehnen ist an";
   41.35 -["Avatar"] = false;
   41.36 +["Avatar"] = "Avatar";
   41.37  ["Become a member"] = "Mitglied werden";
   41.38  ["Birthday"] = "Geburtstag";
   41.39  ["Bug report"] = "Fehlerbericht";
   41.40 @@ -49,16 +52,18 @@
   41.41  ["Compare"] = "Vergleichen";
   41.42  ["Contacts"] = "Kontakte";
   41.43  ["Content"] = "Inhalt";
   41.44 +["Counting of votes"] = "Auszählung";
   41.45  ["Create alternative initiative"] = "Alternative Initiative hinzufügen";
   41.46  ["Create new area"] = "Neuen Themenbereich anlegen";
   41.47  ["Create new issue"] = "Neues Thema anlegen";
   41.48  ["Created at"] = "Erzeugt am/um";
   41.49  ["Current draft"] = "Aktueller Entwurf";
   41.50 +["Current votings in areas you are member of and issues you are interested in:"] = "Jetzt laufende Abstimmungen zu Themen aus Deinen Themenbereichen oder solchen an denen Du interessiert bist:";
   41.51  ["Degree"] = "Grad";
   41.52  ["Delegations"] = "Delegationen";
   41.53  ["Description"] = "Beschreibung";
   41.54  ["Details"] = "Details";
   41.55 -["Diff"] = false;
   41.56 +["Diff"] = "Differenz";
   41.57  ["Direct member count"] = "Anzahl Direktmitglieder";
   41.58  ["Direct membership"] = "Direkte Mitgliedschaft";
   41.59  ["Discussion"] = "Diskussion";
   41.60 @@ -70,11 +75,12 @@
   41.61  ["Edit initiative"] = "Initiative bearbeiten";
   41.62  ["Edit my page"] = "Meine Seite bearbeiten";
   41.63  ["Edit my profile"] = "Mein Profil bearbeiten";
   41.64 -["Empty help text: #{id}.#{lang}.txt"] = false;
   41.65 +["Empty help text: #{id}.#{lang}.txt"] = "Leerer Hilfe-Text: #{id}.#{lang}.txt";
   41.66  ["Error while updating member, database reported:<br /><br /> (#{errormessage})"] = "Fehler beim aktualisieren des Mitglieds, die Datenbank berichtet folgenden Fehler:<br /><br /> (#{errormessage})";
   41.67  ["External memberships"] = "Externe Mitgliedschaften";
   41.68  ["External posts"] = "Externe Ämter";
   41.69 -["Filter"] = false;
   41.70 +["Filter"] = "Filter";
   41.71 +["Finish voting"] = "Stimmabgabe abschließen";
   41.72  ["Finished"] = "Abgeschlossen";
   41.73  ["Frozen"] = "Eingefroren";
   41.74  ["Fulfilled"] = "Erfüllt";
   41.75 @@ -101,9 +107,12 @@
   41.76  ["Interest not existant"] = "Interesse existiert nicht";
   41.77  ["Interest removed"] = "Interesse entfernt";
   41.78  ["Interest updated"] = "Interesse aktualisiert";
   41.79 +["Interested"] = "Interessiert";
   41.80  ["Interested members"] = "Interessierte Mitglieder";
   41.81  ["Internal posts"] = "Interne Ämter";
   41.82  ["Invalid username or password!"] = "Ungültiger Benutzername oder Kennwort";
   41.83 +["Invite code"] = "Invite-Code";
   41.84 +["Invite code valid!"] = "Invite-Code gültig!";
   41.85  ["Issue"] = "Thema";
   41.86  ["Issue ##{id}"] = "Issue ##{id}";
   41.87  ["Issue ##{id} (#{policy_name})"] = "Thema ##{id} (#{policy_name})";
   41.88 @@ -112,11 +121,14 @@
   41.89  ["Issue policy"] = "Regelwerk für Thema";
   41.90  ["Issue quorum"] = "Quorum Thema";
   41.91  ["Issues"] = "Themen";
   41.92 +["JavaScript is disabled or not available."] = "JavaScript ist abgeschaltet oder nicht verfügbar.";
   41.93  ["Last snapshot:"] = "Letzte Auszählung:";
   41.94  ["Legend:"] = "Legende:";
   41.95  ["License"] = "Lizenz";
   41.96  ["Locked?"] = "Gesperrt?";
   41.97  ["Login"] = "Anmeldung";
   41.98 +["Login is available"] = "Anmeldename ist verfügbar";
   41.99 +["Login name"] = "Anmeldename";
  41.100  ["Login successful!"] = "Anmeldung erfolgreich";
  41.101  ["Logout"] = "Abmelden";
  41.102  ["Logout successful"] = "Abmeldung erfolgreich";
  41.103 @@ -124,16 +136,16 @@
  41.104  ["Mark suggestion as implemented and express satisfaction"] = "Anregung als umgesetzt markieren und Zufriedenheit ausdrücken";
  41.105  ["Mark suggestion as not implemented and express dissatisfaction"] = "Anregung als nicht umgesetzt markieren und Unzufriedenheit ausdrücken";
  41.106  ["Mark suggestion as not implemented and express satisfaction"] = "Anregung als nicht umgesetzt markieren und Zufriedenheit ausdrücken";
  41.107 +["Max potential support"] = "Max. potentielle Unterstützer";
  41.108 +["Max support"] = "Max. Unterstützer";
  41.109  ["Member '#{member}'"] = "Mitglied '#{member}'";
  41.110  ["Member has been removed from your contacts"] = "Mitglied wurde aus Deinen Kontakten entfernt";
  41.111 -["Member has been saved as private contact"] = "Mitglied wurde als privater Kontakt gespeichert";
  41.112 -["Member has been saved as public contact"] = "Mitglied wurde als öffentlicher Kontakt gespeichert";
  41.113  ["Member is administrator"] = "Mitglied ist Administrator";
  41.114  ["Member is already saved in your contacts!"] = "Mitglied ist schon in Deinen Kontakten!";
  41.115  ["Member list"] = "Mitgliederliste";
  41.116  ["Member login"] = "Mitglied Login";
  41.117  ["Member name"] = "Mitglied Name";
  41.118 -["Member page"] = false;
  41.119 +["Member page"] = "Mitgliederseite";
  41.120  ["Member successfully registered"] = "Mitglied erfolgreich registriert";
  41.121  ["Member successfully updated"] = "Mitglied erfolgreich aktualisert";
  41.122  ["Member: '#{login}' (#{name})"] = "Mitlied: '#{login}' (#{name})";
  41.123 @@ -143,10 +155,11 @@
  41.124  ["Membership removed"] = "Mitgliedschaft entfernt";
  41.125  ["Membership updated"] = "Mitgliedschaft aktualisiert";
  41.126  ["Memberships"] = "Mitgliedschaften";
  41.127 -["Missing help text: #{id}.#{lang}.txt"] = false;
  41.128 +["Missing help text: #{id}.#{lang}.txt"] = "Fehlender Hilfe-Text: #{id}.#{lang}.txt";
  41.129  ["Mobile phone"] = "Mobiltelefon";
  41.130  ["My opinion"] = "Meine Meinung";
  41.131  ["Name"] = "Name";
  41.132 +["Name is available"] = "Name ist verfügbar";
  41.133  ["New"] = "Neu";
  41.134  ["New draft has been added to initiative"] = "Neuer Entwurf wurde der Initiative hinzugefügt";
  41.135  ["New draft revision"] = "Neue Revision des Entwurfs";
  41.136 @@ -155,9 +168,13 @@
  41.137  ["New passwords is too short."] = "Das neue Kennwort ist zu kurz";
  41.138  ["Newest"] = "Neueste";
  41.139  ["Next state"] = "Nächster Zustand";
  41.140 +["No"] = "Nein";
  41.141  ["No changes to your images were made"] = "An Deinen Bildern wurde nichts geändert";
  41.142  ["No delegation"] = "Keine Delegation";
  41.143  ["No membership at all"] = "Gar keine Mitgliedschaft";
  41.144 +["No support at all"] = "Gar keine Unterstützung";
  41.145 +["Not a member"] = "Kein Mitglied";
  41.146 +["Not voted"] = "Nicht abgestimmt";
  41.147  ["Number of incoming delegations, follow link to see more details"] = "Anzahl eingehender Delegationen, Link folgen für mehr Details";
  41.148  ["OK"] = "OK";
  41.149  ["Old draft revision"] = "Alte Revision des Entwurfs";
  41.150 @@ -165,15 +182,26 @@
  41.151  ["Old password"] = "Altes Kennwort";
  41.152  ["Old password is wrong"] = "Das alte Kennwort ist falsch";
  41.153  ["Oldest"] = "Älteste";
  41.154 +["One issue"] = "Ein Thema";
  41.155 +["One issue you are interested in"] = "Ein Thema, das Dich interessiert";
  41.156  ["Order by"] = "Sortieren nach";
  41.157  ["Organizational unit"] = "Organisationseinheit";
  41.158  ["Outgoing delegations"] = "Ausgehende Delegationen";
  41.159  ["Password"] = "Kennwort";
  41.160 +["Password (repeat)"] = "Kennwort (wiederholen)";
  41.161 +["Passwords don't match!"] = "Kennwörter stimmen nicht überein!";
  41.162 +["Passwords must consist of at least 8 characters!"] = "Das Kennwort muß zumindest 8 Zeichen lang sein!";
  41.163  ["Phone"] = "Telefon";
  41.164  ["Photo"] = "Foto";
  41.165 +["Please choose a login name. This name will not be shown to others and is used only by you to login into the system. The login name is case sensitive."] = "Bitte wähle einen Anmeldenamen. Dieser wird anderen nicht gezeigt und nur von Dir zum Anmelden verwendet. Groß- und Kleinschreibung wird berücksichtigt.";
  41.166 +["Please choose a name, i.e. your real name or your nick name. This name will be shown to others to identify you. You CAN'T change this name later, so please choose it wisely!"] = "Bitte wähle einen Namen, z. B. Deinen Real- oder Nicknamen. Dieser wird anderen angezeigt um Dich zu identifizieren. Du kannst Deinen Namen später NICHT ändern, wähle ihn also weise!";
  41.167 +["Please choose a password and enter it twice. The password is case sensitive."] = "Bitte wähle ein Kennwort und gebe es zweimal ein. Groß- und Kleinschreibung wird berücksichtigt.";
  41.168 +["Please enter the invite code you've received."] = "Bitte gib den Invite-Code ein, den Du erhalten hast.";
  41.169  ["Policy"] = "Regelwerk";
  41.170  ["Population"] = "Grundgesamtheit";
  41.171  ["Posts"] = "Ämter";
  41.172 +["Potential support"] = "Potentielle Unterstützung";
  41.173 +["Potential supporter"] = "Potentielle Unterstützer";
  41.174  ["Profession"] = "Beruf";
  41.175  ["Profile"] = "Profil";
  41.176  ["Publish"] = "Veröffentlichen";
  41.177 @@ -182,7 +210,9 @@
  41.178  ["Rank"] = "Rang";
  41.179  ["Real name"] = "Realname";
  41.180  ["Refresh support to current draft"] = "Unterstützung auf aktuellen Entwurf aktualisieren";
  41.181 +["Register"] = "Registrieren";
  41.182  ["Register new member"] = "Neues Mitglied registrieren";
  41.183 +["Registration"] = "Registrierung";
  41.184  ["Remove"] = "Entfernen";
  41.185  ["Remove autoreject"] = "Auto-Ablehnen abschalten";
  41.186  ["Remove from contacts"] = "Aus den Kontakten entfernen";
  41.187 @@ -207,57 +237,72 @@
  41.188  ["Set issue delegation"] = "Delegation für Thema festlegen";
  41.189  ["Show"] = "Zeige";
  41.190  ["Show active members"] = "Zeige aktive Mitglieder";
  41.191 +["Show all initiatives"] = "Zeige alle Initiativen";
  41.192  ["Show areas in use"] = "Zeige verwendete Themenbereiche";
  41.193  ["Show areas not in use"] = "Zeige nicht verwendente Themenbereiche";
  41.194  ["Show diff"] = "Änderungen anzeigen";
  41.195  ["Show locked members"] = "Zeige gesperrte Mitglieder";
  41.196  ["Show member"] = "Mitglied anzeigen";
  41.197 -["Show other initiatives"] = "Zeige alternative Initiativen";
  41.198 -["Software"] = false;
  41.199 +["Software"] = "Software";
  41.200 +["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."] = "Einige auf JavaScript basierende Funktionen (insbesondere der Abstimmung) sind nicht benutzbar.\nFür diese Beta verwende bitte eine aktuelle Version von Firefox, Safari, Opera(?), Konqueror oder einen anderen (mehr) den Standards entsprechenden Browser.\nEin alternativer Zugriff ohne JavaScript wird bald zur Verfügung stehen.";
  41.201 +["Sorry, you have reached your personal flood limit. Please be slower..."] = "Sorry, Du hast Dein persönliches Flood-Limit erreicht. Bitte sei langsamer...";
  41.202 +["Sorry, your contingent for creating initiatives has been used up. Please try again later."] = "Sorry, Dein Antragskontingent ist zur Zeit ausgeschöpft. Bitte versuche es später erneut!";
  41.203  ["State"] = "Zustand";
  41.204 -["Statement"] = false;
  41.205 +["Statement"] = "Statement";
  41.206  ["Suggestion"] = "Anregung";
  41.207  ["Suggestion currently implemented"] = "Anregung zur Zeit umgesetzt";
  41.208  ["Suggestion currently not implemented"] = "Anregung zur Zeit nicht umgesetzt";
  41.209  ["Suggestion for initiative: '#{name}'"] = "Anregung für Initiative '#{name}'";
  41.210  ["Suggestions"] = "Anregungen";
  41.211  ["Support"] = "Unterstützung";
  41.212 -["Support S+I"] = "Unterstütung S+I";
  41.213  ["Support this initiative"] = "Diese Initiative unterstützen";
  41.214  ["Supported initiatives"] = "Unterstützte Initiativen";
  41.215  ["Supporter"] = "Unterstützer";
  41.216  ["That's me!"] = "Das bin ich";
  41.217 +["The code you've entered is invalid"] = "Den Code den Du eingeben hast ist nicht gültig!";
  41.218  ["The drafts do not differ"] = "Die Entwürfe unterscheiden sich nicht";
  41.219 +["This issue is already closed."] = "Das Thema ist schon geschlossen.";
  41.220 +["This issue is already frozen."] = "Das Thema ist schon eingefroren";
  41.221 +["This login is already taken, please choose another one!"] = "Dieser Anmeldename ist bereits vergeben, bitte wähle einen anderen!";
  41.222 +["This name is already taken, please choose another one!"] = "Dieser Name ist bereits vergeben, bitte wähle einen anderen!";
  41.223  ["Time left"] = "Restzeit";
  41.224 -["Title (80 chars max)"] = "Titel (max. 80 Zeichen)";
  41.225 +["Title (80 chars max)"] = "Title (max. 80 Zeichen)";
  41.226 +["Traditional wiki syntax"] = "Traditionaller Wiki-Syntax";
  41.227  ["Trustee"] = "Bevollmächtigter";
  41.228  ["Unknown author"] = "Unbekannter Autor";
  41.229  ["Upload images"] = "Bilder hochladen";
  41.230 -["Username"] = "Benutzername";
  41.231  ["Verification time"] = "Zeit für die Überprüfung";
  41.232 -["Version"] = false;
  41.233 +["Version"] = "Version";
  41.234  ["Vote later"] = "Später abstimmen";
  41.235  ["Vote now"] = "Jetzt abstimmen";
  41.236 +["Vote now/later"] = "Jetzt/später abstimmen";
  41.237 +["Voted"] = "Abgestimmt";
  41.238  ["Voting"] = "Abstimmung";
  41.239 +["Voting for this issue has already begun."] = "Die Abstimmung für dieses Thema hat schon begonnen.";
  41.240 +["Voting has not started yet."] = "Die Abstimmung hat noch nicht begonnen.";
  41.241  ["Voting requests"] = "Abstimmanträge";
  41.242  ["Voting time"] = "Zeit für die Abstimmung";
  41.243  ["Website"] = "Webseite";
  41.244 +["Wiki engine"] = "Wiki engine";
  41.245 +["Yes"] = "Ja";
  41.246  ["You are already not supporting this initiative"] = "Diese Initiative hat bereits keine Unterstützung von Dir";
  41.247  ["You are already supporting the latest draft"] = "Du unterstützt bereits den neuesten Entwurf";
  41.248 -["You are currently not supporting this initiative. By adding suggestions to this initiative you will automatically become a potential supporter."] = false;
  41.249 +["You are currently not supporting this initiative. By adding suggestions to this initiative you will automatically become a potential supporter."] = "Du bist zur Zeit kein Unterstützer dieser Initiative. Wenn Du eine Anregung hinzufügst wirst Du automatisch potentieller Unterstützer!";
  41.250  ["You are member"] = "Du bist Mitglied";
  41.251  ["You didn't saved any member as contact yet."] = "Du hast noch kein Mitglied als Kontakt gespeichert!";
  41.252  ["You have saved this member as contact"] = "Du hast das Mitglied als Kontakt gespeichert";
  41.253  ["You have saved this member as contact."] = "Du hast das Mitglied als Kontakt gespeichert.";
  41.254  ["You need to be logged in, to use this system."] = "Du musst eingeloggt sein, um das System zu benutzen";
  41.255 +["You've successfully registered and you can login now with your login and password!"] = "Du hast Dich erfolgreich registriert und kannst Dich jetzt mit Deinen Benutzernamen und Kennwort anmelden!";
  41.256  ["Your are interested"] = "Du bist interessiert";
  41.257 +["Your are potential supporter"] = "Du bist potentieller Unterstützer";
  41.258  ["Your are supporter"] = "Du bist Unterstützer";
  41.259  ["Your delegation for this area has been deleted."] = "Deine Delegation für dieses Themengebiet wurde gelöscht";
  41.260  ["Your delegation for this area has been updated."] = "Deine Delegation für dieses Themengebiet wurde geändert";
  41.261  ["Your delegation for this issue has been deleted."] = "Deine Delegation für dieses Thema wurde gelöscht";
  41.262  ["Your delegation for this issue has been updated."] = "Deine Delegation für dieses Thema wurde geändert";
  41.263  ["Your global delegation has been deleted."] = "Deine globale Delegation wurde gelöscht";
  41.264 -["Your global delegation has been updated."] = "Deine globale Delegation würde geändert";
  41.265 +["Your global delegation has been updated."] = "Deine globale Delegation wurde geändert";
  41.266  ["Your opinion has been deleted"] = "Deine Meinung wurde gelöscht";
  41.267  ["Your opinion has been updated"] = "Deine Meinung wurde aktualisiert";
  41.268  ["Your page has been updated"] = "Deine Seite wurde aktualisiert";
  41.269 @@ -266,11 +311,12 @@
  41.270  ["Your support has been added to this initiative"] = "Deine Unterstützung wurde der Initiative hinzugefügt";
  41.271  ["Your support has been removed from this initiative"] = "Deine Unterstützung wurde der Initiave entzogen";
  41.272  ["Your support has been updated to the latest draft"] = "Deine Unterstützung wurde auf den neuesten Entwurf aktualisiert";
  41.273 -["Z-A"] = false;
  41.274 +["Your web browser is not fully supported yet."] = "Dein Web-Browser wird noch nicht vollständig unterstützt.";
  41.275 +["Z-A"] = "Z-A";
  41.276  ["all"] = "Alle";
  41.277 -["blank"] = false;
  41.278  ["delete<br /><br />"] = "löschen<br /><br />";
  41.279 -["email"] = false;
  41.280 +["email"] = "E-Mail";
  41.281 +["login name"] = "Anmeldename";
  41.282  ["must"] = "muss";
  41.283  ["must not"] = "darf nicht";
  41.284  ["must/should"] = "muss/soll";
  41.285 @@ -279,5 +325,5 @@
  41.286  ["not implemented"] = "nicht umgesetzt";
  41.287  ["should"] = "soll";
  41.288  ["should not"] = "soll nicht";
  41.289 -["xmpp"] = false;
  41.290 +["xmpp"] = "Jabber (XMPP)";
  41.291  }
    42.1 --- a/model/direct_voter.lua	Thu Dec 10 12:00:00 2009 +0100
    42.2 +++ b/model/direct_voter.lua	Fri Dec 25 12:00:00 2009 +0100
    42.3 @@ -1,5 +1,6 @@
    42.4  DirectVoter = mondelefant.new_class()
    42.5 -DirectVoter.table = 'member'
    42.6 +DirectVoter.table = 'direct_voter'
    42.7 +DirectVoter.primary_key = { "issue_id", "member_id" }
    42.8  
    42.9  DirectVoter:add_reference{
   42.10    mode          = 'm1',
   42.11 @@ -16,3 +17,10 @@
   42.12    that_key      = 'id',
   42.13    ref           = 'member',
   42.14  }
   42.15 +
   42.16 +function DirectVoter:by_pk(issue_id, member_id)
   42.17 +  return self:new_selector()
   42.18 +    :add_where{ "issue_id = ? AND member_id = ?", issue_id, member_id }
   42.19 +    :optional_object_mode()
   42.20 +    :exec()
   42.21 +end
   42.22 \ No newline at end of file
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/model/invite_code.lua	Fri Dec 25 12:00:00 2009 +0100
    43.3 @@ -0,0 +1,10 @@
    43.4 +InviteCode = mondelefant.new_class()
    43.5 +InviteCode.table = 'invite_code'
    43.6 +InviteCode.primary_key = "code"
    43.7 +
    43.8 +function InviteCode:by_code(code)
    43.9 +  local selector = self:new_selector()
   43.10 +  selector:add_where{'"code" = ?', code }
   43.11 +  selector:optional_object_mode()
   43.12 +  return selector:exec()
   43.13 +end
    44.1 --- a/model/issue.lua	Thu Dec 10 12:00:00 2009 +0100
    44.2 +++ b/model/issue.lua	Fri Dec 25 12:00:00 2009 +0100
    44.3 @@ -119,11 +119,7 @@
    44.4  function Issue.object_get:state()
    44.5    if self.accepted then
    44.6      if self.closed then
    44.7 -      if self.ranks_available then
    44.8 -        return "finished"
    44.9 -      else
   44.10 -        return "cancelled"
   44.11 -      end
   44.12 +      return "finished"
   44.13      elseif self.fully_frozen then
   44.14        return "voting"
   44.15      elseif self.half_frozen then
    45.1 --- a/model/member.lua	Thu Dec 10 12:00:00 2009 +0100
    45.2 +++ b/model/member.lua	Fri Dec 25 12:00:00 2009 +0100
    45.3 @@ -245,7 +245,7 @@
    45.4  
    45.5  function Member:by_login_and_password(login, password)
    45.6    local selector = self:new_selector()
    45.7 -  selector:add_where{'"login" = ?', login, password }
    45.8 +  selector:add_where{'"login" = ?', login }
    45.9    selector:add_where('"active"')
   45.10    selector:optional_object_mode()
   45.11    local member = selector:exec()
   45.12 @@ -256,6 +256,20 @@
   45.13    end
   45.14  end
   45.15  
   45.16 +function Member:by_login(login)
   45.17 +  local selector = self:new_selector()
   45.18 +  selector:add_where{'"login" = ?', login }
   45.19 +  selector:optional_object_mode()
   45.20 +  return selector:exec()
   45.21 +end
   45.22 +
   45.23 +function Member:by_name(name)
   45.24 +  local selector = self:new_selector()
   45.25 +  selector:add_where{'"name" = ?', name }
   45.26 +  selector:optional_object_mode()
   45.27 +  return selector:exec()
   45.28 +end
   45.29 +
   45.30  function Member:get_search_selector(search_string)
   45.31    return self:new_selector()
   45.32      :add_field( {'"highlight"("member"."name", ?)', search_string }, "name_highlighted")
    46.1 --- a/model/policy.lua	Thu Dec 10 12:00:00 2009 +0100
    46.2 +++ b/model/policy.lua	Fri Dec 25 12:00:00 2009 +0100
    46.3 @@ -7,6 +7,5 @@
    46.4    this_key      = 'id',
    46.5    that_key      = 'policy_id',
    46.6    ref           = 'issues',
    46.7 -  back_ref      = 'policy',
    46.8 -  default_order = '"created", "id"'
    46.9 +  back_ref      = 'policy'
   46.10  }
    47.1 --- a/model/supporter.lua	Thu Dec 10 12:00:00 2009 +0100
    47.2 +++ b/model/supporter.lua	Fri Dec 25 12:00:00 2009 +0100
    47.3 @@ -25,3 +25,12 @@
    47.4      :optional_object_mode()
    47.5      :exec()
    47.6  end
    47.7 +
    47.8 +function Supporter.object:has_critical_opinion()
    47.9 +  return Opinion:new_selector()
   47.10 +    :add_where{ "initiative_id = ?", self.initiative_id }
   47.11 +    :add_where{ "member_id = ?", self.member_id }
   47.12 +    :add_where("(degree = -2 AND fulfilled) OR (degree = 2 AND NOT fulfilled)")
   47.13 +    :limit(1)
   47.14 +    :exec()[1] and true or false
   47.15 +end
   47.16 \ No newline at end of file
    48.1 --- a/model/vote.lua	Thu Dec 10 12:00:00 2009 +0100
    48.2 +++ b/model/vote.lua	Fri Dec 25 12:00:00 2009 +0100
    48.3 @@ -1,5 +1,6 @@
    48.4  Vote = mondelefant.new_class()
    48.5  Vote.table = 'vote'
    48.6 +Vote.primary_key = { "initiative_id", "member_id" }
    48.7  
    48.8  Vote:add_reference{
    48.9    mode          = 'm1',
   48.10 @@ -24,3 +25,10 @@
   48.11    that_key      = 'id',
   48.12    ref           = 'author',
   48.13  }
   48.14 +
   48.15 +function Vote:by_pk(initiative_id, member_id)
   48.16 +  return self:new_selector()
   48.17 +    :add_where{ "initiative_id = ? AND member_id = ?", initiative_id, member_id }
   48.18 +    :optional_object_mode()
   48.19 +    :exec()
   48.20 +end
   48.21 \ No newline at end of file
    49.1 Binary file static/icons/16/email_open.png has changed
    50.1 Binary file static/icons/16/eye.png has changed
    51.1 Binary file static/icons/16/thumb_up.png has changed
    52.1 Binary file static/icons/16/time.png has changed
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/static/js/browser_warning.js	Fri Dec 25 12:00:00 2009 +0100
    53.3 @@ -0,0 +1,9 @@
    53.4 +function evilBrowser() {
    53.5 +  return (navigator.appName == "Microsoft Internet Explorer" || ! window.addEventListener);
    53.6 +}
    53.7 +
    53.8 +function checkBrowser(message) {
    53.9 +  if (evilBrowser()) {
   53.10 +    alert(message);
   53.11 +  }
   53.12 +}
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/static/js/dragdrop.js	Fri Dec 25 12:00:00 2009 +0100
    54.3 @@ -0,0 +1,73 @@
    54.4 +window.addEventListener("load", function(event) {
    54.5 +  var originalElement;
    54.6 +  var draggedElement;
    54.7 +  var mouseX;
    54.8 +  var mouseY;
    54.9 +  var mouseOffsetX;
   54.10 +  var mouseOffsetY;
   54.11 +  var elementOffsetX;
   54.12 +  var elementOffsetY;
   54.13 +  var dropFunc;
   54.14 +  var dragElement = function(element, func) {
   54.15 +    //if (typeof(element) == "string") element = document.getElementById(element);
   54.16 +    originalElement = element;
   54.17 +    draggedElement = originalElement.cloneNode(true);
   54.18 +    originalElement.style.visibility = "hidden";
   54.19 +    draggedElement.style.margin = 0;
   54.20 +    draggedElement.style.position = "absolute";
   54.21 +    draggedElement.style.left = elementOffsetX = originalElement.offsetLeft;
   54.22 +    draggedElement.style.top  = elementOffsetY = originalElement.offsetTop;
   54.23 +    draggedElement.style.width  = originalElement.clientWidth;
   54.24 +    draggedElement.style.height = originalElement.clientHeight;
   54.25 +    draggedElement.style.backgroundColor = "#eee";
   54.26 +    draggedElement.style.opacity = 0.8;
   54.27 +    originalElement.offsetParent.appendChild(draggedElement);
   54.28 +    // workaround for wrong clientWidth and clientHeight information:
   54.29 +    draggedElement.style.width = 2*originalElement.clientWidth - draggedElement.clientWidth;
   54.30 +    draggedElement.style.height = 2*originalElement.clientHeight - draggedElement.clientHeight;
   54.31 +    mouseOffsetX = mouseX;
   54.32 +    mouseOffsetY = mouseY;
   54.33 +    dropFunc = func;
   54.34 +  };
   54.35 +  window.addEventListener("mousemove", function(event) {
   54.36 +    mouseX = event.pageX;
   54.37 +    mouseY = event.pageY;
   54.38 +    if (draggedElement) {
   54.39 +      draggedElement.style.left = elementOffsetX + mouseX - mouseOffsetX;
   54.40 +      draggedElement.style.top  = elementOffsetY + mouseY - mouseOffsetY;
   54.41 +    }
   54.42 +  }, true);
   54.43 +  var mouseDrop = function(event) {
   54.44 +    if (draggedElement) {
   54.45 +      dropFunc(
   54.46 +        originalElement,
   54.47 +        elementOffsetX + mouseX - mouseOffsetX,
   54.48 +        elementOffsetY + mouseY - mouseOffsetY
   54.49 +      );
   54.50 +      originalElement.style.visibility = '';
   54.51 +      draggedElement.parentNode.removeChild(draggedElement);
   54.52 +      originalElement = null;
   54.53 +      draggedElement = null;
   54.54 +    }
   54.55 +  };
   54.56 +  window.addEventListener("mouseup",   mouseDrop, true);
   54.57 +  window.addEventListener("mousedown", mouseDrop, true);
   54.58 +  var elements = document.getElementsByTagName("*");
   54.59 +  for (var i=0; i<elements.length; i++) {
   54.60 +    var element = elements[i];
   54.61 +    if (element.className == "movable") {
   54.62 +      element.addEventListener("mousedown", function(event) {
   54.63 +        event.target.style.cursor = "move";
   54.64 +        dragElement(event.currentTarget, function(element, dropX, dropY) {
   54.65 +          event.target.style.cursor = null;
   54.66 +          elementDropped(element, dropX, dropY);
   54.67 +        });
   54.68 +        event.preventDefault();
   54.69 +      }, false);
   54.70 +    } else if (element.className == "clickable") {
   54.71 +      element.addEventListener("mousedown", function(event) {
   54.72 +        event.stopPropagation();
   54.73 +      }, false);
   54.74 +    }
   54.75 +  }
   54.76 +}, false);
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/static/js/voting.js	Fri Dec 25 12:00:00 2009 +0100
    55.3 @@ -0,0 +1,227 @@
    55.4 +function setCategoryHeadings() {
    55.5 +  var approvalCount = 0;
    55.6 +  var disapprovalCount = 0;
    55.7 +  var sections = document.getElementById("voting").childNodes;
    55.8 +  for (var i=0; i<sections.length; i++) {
    55.9 +    var section = sections[i];
   55.10 +    if (section.className == "approval")       approvalCount++;
   55.11 +    if (section.className == "disapproval") disapprovalCount++;
   55.12 +  }
   55.13 +  var approvalIndex = 0;
   55.14 +  var disapprovalIndex = 0;
   55.15 +  for (var i=0; i<sections.length; i++) {
   55.16 +    var section = sections[i];
   55.17 +    if (
   55.18 +      section.className == "approval" ||
   55.19 +      section.className == "abstention" ||
   55.20 +      section.className == "disapproval"
   55.21 +    ) {
   55.22 +      var setHeading = function(heading) {
   55.23 +        var headingNodes = section.childNodes;
   55.24 +        for (var j=0; j<headingNodes.length; j++) {
   55.25 +          var headingNode = headingNodes[j];
   55.26 +          if (headingNode.className == "cathead") {
   55.27 +            headingNode.textContent = heading;
   55.28 +          }
   55.29 +        }
   55.30 +      }
   55.31 +      var count = 0;
   55.32 +      var entries = section.childNodes;
   55.33 +      for (var j=0; j<entries.length; j++) {
   55.34 +        var entry = entries[j];
   55.35 +        if (entry.className == "movable") count++;
   55.36 +      }
   55.37 +      if (section.className == "approval") {
   55.38 +        if (approvalCount > 1) {
   55.39 +          if (approvalIndex == 0) {
   55.40 +            if (count == 1) setHeading("Zustimmung (Erstwunsch)");
   55.41 +            else setHeading("Zustimmung (Erstwünsche)");
   55.42 +          } else if (approvalIndex == 1) {
   55.43 +            if (count == 1) setHeading("Zustimmung (Zweitwunsch)");
   55.44 +            else setHeading("Zustimmung (Zweitwünsche)");
   55.45 +          } else if (approvalIndex == 2) {
   55.46 +            if (count == 1) setHeading("Zustimmung (Drittwunsch)");
   55.47 +            else setHeading("Zustimmung (Drittwünsche)");
   55.48 +          } else {
   55.49 +            if (count == 1) setHeading("Zustimmung (" + (approvalIndex+1) + ".-Wunsch)");
   55.50 +            else setHeading("Zustimmung (" + (approvalIndex+1) + ".-Wünsche)");
   55.51 +          }
   55.52 +        } else {
   55.53 +          setHeading("Zustimmung");
   55.54 +        }
   55.55 +        approvalIndex++;
   55.56 +      } else if (section.className == "abstention") {
   55.57 +        setHeading("Enthaltung");
   55.58 +      } else if (section.className == "disapproval") {
   55.59 +        if (disapprovalCount > disapprovalIndex + 2) {
   55.60 +          setHeading("Ablehnung (jedoch Bevorzugung gegenüber unteren Ablehnungsblöcken)")
   55.61 +        } else if (disapprovalCount == 2 && disapprovalIndex == 0) {
   55.62 +          setHeading("Ablehnung (jedoch Bevorzugung gegenüber unterem Ablehnungsblock)")
   55.63 +        } else if (disapprovalIndex == disapprovalCount - 2) {
   55.64 +          setHeading("Ablehnung (jedoch Bevorzugung gegenüber letztem Ablehnungsblock)")
   55.65 +        } else {
   55.66 +          setHeading("Ablehnung");
   55.67 +        }
   55.68 +        disapprovalIndex++;
   55.69 +      }
   55.70 +    }
   55.71 +  }
   55.72 +}
   55.73 +function elementDropped(element, dropX, dropY) {
   55.74 +  var oldParent = element.parentNode;
   55.75 +  var centerY = dropY + element.clientHeight / 2
   55.76 +  var approvalCount = 0;
   55.77 +  var disapprovalCount = 0;
   55.78 +  var mainDiv = document.getElementById("voting");
   55.79 +  var sections = mainDiv.childNodes;
   55.80 +  for (var i=0; i<sections.length; i++) {
   55.81 +    var section = sections[i];
   55.82 +    if (section.className == "approval")       approvalCount++;
   55.83 +    if (section.className == "disapproval") disapprovalCount++;
   55.84 +  }
   55.85 +  for (var i=0; i<sections.length; i++) {
   55.86 +    var section = sections[i];
   55.87 +    if (
   55.88 +      section.className == "approval" ||
   55.89 +      section.className == "abstention" ||
   55.90 +      section.className == "disapproval"
   55.91 +    ) {
   55.92 +      if (
   55.93 +        centerY >= section.offsetTop &&
   55.94 +        centerY <  section.offsetTop + section.clientHeight
   55.95 +      ) {
   55.96 +        var entries = section.childNodes;
   55.97 +        for (var j=0; j<entries.length; j++) {
   55.98 +          var entry = entries[j];
   55.99 +          if (entry.className == "movable") {
  55.100 +            if (centerY < entry.offsetTop + entry.clientHeight / 2) {
  55.101 +              if (element != entry) {
  55.102 +                oldParent.removeChild(element);
  55.103 +                section.insertBefore(element, entry);
  55.104 +              }
  55.105 +              break;
  55.106 +            }
  55.107 +          }
  55.108 +        }
  55.109 +        if (j == entries.length) {
  55.110 +          oldParent.removeChild(element);
  55.111 +          section.appendChild(element);
  55.112 +        }
  55.113 +        break;
  55.114 +      }
  55.115 +    }
  55.116 +  }
  55.117 +  if (i == sections.length) {
  55.118 +    var newSection = document.createElement("div");
  55.119 +    var cathead = document.createElement("div");
  55.120 +    cathead.setAttribute("class", "cathead");
  55.121 +    newSection.appendChild(cathead);
  55.122 +    for (var i=0; i<sections.length; i++) {
  55.123 +      var section = sections[i];
  55.124 +      if (
  55.125 +        section.className == "approval" ||
  55.126 +        section.className == "abstention" ||
  55.127 +        section.className == "disapproval"
  55.128 +      ) {
  55.129 +        if (centerY < section.offsetTop + section.clientHeight / 2) {
  55.130 +          if (section.className == "disapproval") {
  55.131 +            newSection.setAttribute("class", "disapproval");
  55.132 +            disapprovalCount++;
  55.133 +          } else {
  55.134 +            newSection.setAttribute("class", "approval");
  55.135 +            approvalCount++;
  55.136 +          }
  55.137 +          mainDiv.insertBefore(newSection, section);
  55.138 +          break;
  55.139 +        }
  55.140 +      }
  55.141 +    }
  55.142 +    if (i == sections.length) {
  55.143 +      newSection.setAttribute("class", "disapproval");
  55.144 +      disapprovalCount++;
  55.145 +      mainDiv.appendChild(newSection);
  55.146 +    }
  55.147 +    oldParent.removeChild(element);
  55.148 +    newSection.appendChild(element);
  55.149 +  }
  55.150 +  sections = mainDiv.childNodes;
  55.151 +  for (i=0; i<sections.length; i++) {
  55.152 +    var section = sections[i];
  55.153 +    if (
  55.154 +      (section.className == "approval"    &&    approvalCount > 1) ||
  55.155 +      (section.className == "disapproval" && disapprovalCount > 1)
  55.156 +    ) {
  55.157 +      var entries = section.childNodes;
  55.158 +      for (var j=0; j<entries.length; j++) {
  55.159 +        var entry = entries[j];
  55.160 +        if (entry.className == "movable") break;
  55.161 +      }
  55.162 +      if (j == entries.length) {
  55.163 +        section.parentNode.removeChild(section);
  55.164 +      }
  55.165 +    }
  55.166 +  }
  55.167 +  setCategoryHeadings();
  55.168 +}
  55.169 +window.addEventListener("load", function(event) {
  55.170 +  setCategoryHeadings();
  55.171 +  var mainDiv = document.getElementById("voting");
  55.172 +  var form = document.getElementById("voting_form");
  55.173 +  var elements = document.getElementsByTagName("input");
  55.174 +  for (var i=0; i<elements.length; i++) {
  55.175 +    var element = elements[i];
  55.176 +    if (element.className == "voting_done") {
  55.177 +      element.addEventListener("click", function(event) {
  55.178 +        var scoringString = "";
  55.179 +        var approvalCount = 0;
  55.180 +        var disapprovalCount = 0;
  55.181 +        var sections = mainDiv.childNodes;
  55.182 +        for (var j=0; j<sections.length; j++) {
  55.183 +          var section = sections[j];
  55.184 +          if (section.className == "approval")       approvalCount++;
  55.185 +          if (section.className == "disapproval") disapprovalCount++;
  55.186 +        }
  55.187 +        var approvalIndex = 0;
  55.188 +        var disapprovalIndex = 0;
  55.189 +        for (var j=0; j<sections.length; j++) {
  55.190 +          var section = sections[j];
  55.191 +          if (
  55.192 +            section.className == "approval"    ||
  55.193 +            section.className == "abstention"  ||
  55.194 +            section.className == "disapproval"
  55.195 +          ) {
  55.196 +            var score;
  55.197 +            if (section.className == "approval") {
  55.198 +              score = approvalCount - approvalIndex;
  55.199 +              approvalIndex++;
  55.200 +            } else if (section.className == "abstention") {
  55.201 +              score = 0;
  55.202 +            } else if (section.className == "disapproval") {
  55.203 +              score = -1 - disapprovalIndex;
  55.204 +              disapprovalIndex++;
  55.205 +            }
  55.206 +            var entries = section.childNodes;
  55.207 +            for (var k=0; k<entries.length; k++) {
  55.208 +              var entry = entries[k];
  55.209 +              if (entry.className == "movable") {
  55.210 +                var id = entry.id.match(/[0-9]+/);
  55.211 +                var field = document.createElement("input");
  55.212 +                scoringString += id + ":" + score + ";";
  55.213 +              }
  55.214 +            }
  55.215 +          }
  55.216 +        }
  55.217 +        var fields = form.childNodes;
  55.218 +        for (var j=0; j<fields.length; j++) {
  55.219 +          var field = fields[j];
  55.220 +          if (field.name == "scoring") {
  55.221 +            field.setAttribute("value", scoringString);
  55.222 +            form.submit();
  55.223 +            return;
  55.224 +          }
  55.225 +        }
  55.226 +        alert('Hidden input field named "scoring" not found.');
  55.227 +      }, false);
  55.228 +    }
  55.229 +  }
  55.230 +}, false);
    56.1 --- a/static/style.css	Thu Dec 10 12:00:00 2009 +0100
    56.2 +++ b/static/style.css	Fri Dec 25 12:00:00 2009 +0100
    56.3 @@ -94,6 +94,7 @@
    56.4  }
    56.5  
    56.6  .topbar a {
    56.7 +  background-color: #444;
    56.8    color: #fff;
    56.9  }
   56.10  
   56.11 @@ -200,7 +201,7 @@
   56.12  }
   56.13  
   56.14  .title a {
   56.15 -  color: #fff;
   56.16 +  color: #000;
   56.17  }
   56.18  
   56.19  .member_image_avatar {
   56.20 @@ -220,7 +221,7 @@
   56.21  .actions a {
   56.22    float: left;
   56.23    display: block;
   56.24 -  padding: 0.5ex 0.5em 0.5ex 0.0em;
   56.25 +  padding: 1px 0.5em 1px 0.0em;
   56.26    margin-right: 1em;
   56.27    vertical-align: middle;
   56.28  }
   56.29 @@ -262,19 +263,20 @@
   56.30    margin-right: 1em;
   56.31  }
   56.32  
   56.33 -.interest .head_active {
   56.34 -  background-color: #dfd;
   56.35 -  border: 1px solid #8b8;
   56.36 +.interest .head_active,
   56.37 +.slot_support .head_potential_supporter {
   56.38 +  background-color: #fec;
   56.39 +  border: 1px solid #b96;
   56.40  }
   56.41  
   56.42 -.slot_support .head_active {
   56.43 -  background-color: #dfd;
   56.44 +.slot_support .head_supporter {
   56.45 +  background-color: #dfc;
   56.46    border: 1px solid #8b8;
   56.47  }
   56.48  
   56.49  .delegation .head_active {
   56.50 -  background-color: #ffd;
   56.51 -  border: 1px solid #bb8;
   56.52 +  background-color: #ddf;
   56.53 +  border: 1px solid #88b;
   56.54  }
   56.55  
   56.56  .vote_info .close {
   56.57 @@ -389,44 +391,26 @@
   56.58  }
   56.59  
   56.60  /*************************************************************************
   56.61 + * ui.filter
   56.62   * ui.order
   56.63   */
   56.64  
   56.65 -.ui_filter_head {
   56.66 +.ui_filter_head,
   56.67 +.ui_order_head {
   56.68    color: #777;
   56.69 -  float: left;
   56.70 -  margin-bottom: 1ex;
   56.71 +  margin-top: 1ex;
   56.72 +  margin-bottom: 1.5ex;
   56.73    font-size: 75%;
   56.74  }
   56.75  
   56.76 -.ui_filter_head a {
   56.77 -  color: #777;
   56.78 -  padding: 0.5ex;
   56.79 -}
   56.80 -
   56.81 -.ui_filter_head a.active{
   56.82 -  color: #fff;
   56.83 -  background-color: #777;
   56.84 -  padding: 0.5ex;
   56.85 -}
   56.86 -
   56.87 -/*************************************************************************
   56.88 - * ui.order
   56.89 - */
   56.90 -
   56.91 -.ui_order_head {
   56.92 -  color: #777;
   56.93 -  text-align: right;
   56.94 -  margin-bottom: 1ex;
   56.95 -  font-size: 75%;
   56.96 -}
   56.97 -
   56.98 +.ui_filter_head a,
   56.99  .ui_order_head a {
  56.100    color: #777;
  56.101    padding: 0.5ex;
  56.102  }
  56.103  
  56.104 -.ui_order_head a.active{
  56.105 +.ui_filter_head a.active,
  56.106 +.ui_order_head a.active {
  56.107    color: #fff;
  56.108    background-color: #777;
  56.109    padding: 0.5ex;
  56.110 @@ -643,7 +627,11 @@
  56.111    padding: 0.3ex 0.5em 0.3ex 0.5em;
  56.112  }
  56.113  
  56.114 -
  56.115 +.suggestion_my_opinion a {
  56.116 +  white-space: nowrap;
  56.117 +  padding-left: 0.2ex !important;
  56.118 +  padding-right: 0.2ex !important;
  56.119 +}
  56.120  
  56.121  .active {
  56.122    background-color: #444;
  56.123 @@ -880,3 +868,53 @@
  56.124    margin-bottom: 2ex;
  56.125    padding: 1ex;
  56.126  }
  56.127 +
  56.128 +
  56.129 +/*************************************************************************
  56.130 + * Voting
  56.131 + */
  56.132 +
  56.133 +#voting {
  56.134 +  position: relative;
  56.135 +}
  56.136 +#voting .approval, .abstention, .disapproval {
  56.137 +  border: 2px black solid;
  56.138 +  margin-top:    5ex;
  56.139 +  margin-bottom: 5ex;
  56.140 +  padding: 1ex;
  56.141 +  padding-bottom: 2ex;
  56.142 +}
  56.143 +#voting .approval {
  56.144 +  background-color: #9f9;
  56.145 +}
  56.146 +#voting .approval .movable {
  56.147 +  background-color: #dfd;
  56.148 +}
  56.149 +#voting .abstention {
  56.150 +  background-color: #ccc;
  56.151 +}
  56.152 +#voting .abstention .movable {
  56.153 +  background-color: #eee;
  56.154 +}
  56.155 +#voting .disapproval {
  56.156 +  background-color: #f88;
  56.157 +}
  56.158 +#voting .disapproval .movable {
  56.159 +  background-color: #fbb;
  56.160 +}
  56.161 +#voting .cathead {
  56.162 +  font-weight: bold;
  56.163 +}
  56.164 +#voting .movable {
  56.165 +  position: relative;
  56.166 +  border: 1px black solid;
  56.167 +  margin: 1ex;
  56.168 +  padding: 0.5ex;
  56.169 +  cursor: pointer;
  56.170 +}
  56.171 +#voting .clickable {
  56.172 +  cursor: auto;
  56.173 +}
  56.174 +#voting a.clickable {
  56.175 +  cursor: pointer;
  56.176 +}

Impressum / About Us