benny daon avatar benny daon committed 6627a2a Draft Merge

merge - with psf and the server

Comments (0)

Files changed (253)

 bfd8d88f72fcb511bc20126805a4a92d10c7ea7f beta31
 bf735d8095aa237e0283305fc0c37527572248e7 beta32
 4905d7d79486cee780b715a90dcd643e936b6a7a beta33
+55939cbde1a5d318c3342fabee841748cc3d7886 beta34
+f7bc22fbf660bd8ac57a1d715d6faabc3e34ba7f beta35
 74f768a162e1d941158bde5a3e42bb8a71af5090 v2.beta1
 371e690018ea59317682bce44e7b3c33c70d129a v2.beta2
 3e9457cfc6b195fc72760b5b22981e2e7b9c84d8 v2.beta3
 ab68f1d0f78e8a5363e30c191e58230ff83aa2ac v2.beta4
+62923420b7f86d7a1ca0dfe8853aa85f36abfec9 v2.beta5
+9447ea55539854311a4229fbef12e51ee8be6bf1 v2.beta6
+f5b95602507ac9884e7e943cc1eab9da91ff890b translate
+03a280f59e9be3cba2aad94c7fe99bd19fb4206b v2.beta7
+12e504938643433198571260a2797b82867bc7cc v2.beta9
+06a6d9b661d75129e8983d31ec1b48503c1fd26e v2.beta10
+c4e11c003b0c2913c020f6039a9dd1ca2b5cab61 v2.beta11
+f5b95602507ac9884e7e943cc1eab9da91ff890b translate
+a9fd951b67bb0027928012927f5f88771f6395c7 translate
+a9fd951b67bb0027928012927f5f88771f6395c7 translate
+7806dc3f693f46d1bc8a776419046856be1e0423 translate
+7806dc3f693f46d1bc8a776419046856be1e0423 translate
+6236e222f0077eb1731c9b69fd65f2083325245f translate
+2fe57fa90c7a8ea62d9e3494157ccbe4db2f4afb v2.beta12
+2fe57fa90c7a8ea62d9e3494157ccbe4db2f4afb v2.beta12
+df92aebce0f678c94fd859aafb0ffd2a4a8a5bd0 v2.beta12
+6236e222f0077eb1731c9b69fd65f2083325245f translate
+466c0538cd97b92d93f7f50836ae728548e29f5e translate
+466c0538cd97b92d93f7f50836ae728548e29f5e translate
+8dc2108d7cd2f420bc005cb408c0495b071448a1 translate
+8dc2108d7cd2f420bc005cb408c0495b071448a1 translate
+e9cf53cd59549680de96a8a2e1ef3ee6df2e853f translate
+e9cf53cd59549680de96a8a2e1ef3ee6df2e853f translate
+db1fb4f9e5b95887d2eade2922c104cce943bbf7 translate
+db1fb4f9e5b95887d2eade2922c104cce943bbf7 translate
+ea5e8d55a5f0f13f7369e987b873d310698d5537 translate
+ea5e8d55a5f0f13f7369e987b873d310698d5537 translate
+4712d09ace10bdb20789b16a6df0df9d252f5317 translate
+f5c6d8b75ec348911e2edcbdbf8191822c29efcf v2.0.0-rc1
+f7b21855d7d15ed4adecabf17c75b744401bd961 v2.0.0-rc2
+e32827e5d304c7379da8d6b221b06acaf38ac197 v2.0.0-rc3
+82bbab02dd954bd05984d610a96e33096195246c v2.0.0
+ab468c8f234b2544024a208d6453f9723879c1f8 v2.0.1
+944d1fe51ecd205a18df0acfc74e3e3d6c0709cf v2.0.2
-Copyright (c) 2009 Public Software Group e. V., Berlin, Germany
+Copyright (c) 2009-2012 Public Software Group e. V., Berlin, Germany
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
+Official release page
+http://www.public-software-group.org/liquid_feedback_frontend
 
-################
-# Installation #
-################
+Installation instruction (for Debian squeeze)
+http://dev.liquidfeedback.org/trac/lf/wiki/installation
 
 
-1. Choose a directory where to install the software, e.g. /opt :
-
-$ cd /opt
-
-
-2. Get the repositories of the core, the frondend and the web application
-   framework WebMCP:
-
-$ hg clone http://www.public-software-group.org/mercurial/liquid_feedback_core
-$ hg clone http://www.public-software-group.org/mercurial/liquid_feedback_frontend
-$ hg clone http://www.public-software-group.org/mercurial/webmcp
-
-
-3. Install LiquidFeedback Core:
-
-$ cd /opt/liquid_feedback_core
-$ make
-$ createdb liquid_feedback
-$ psql -v ON_ERROR_STOP=1 -f core.sql liquid_feedback
-
-You should initiatize your database using the command
-"psql liquid_feedback" and the examples shown in file "init.sql".
-
-
-4. Compile WebMCP
-
-$ cd /opt/webmcp
-$ make
-
-If you experience trouble during compilation, you might want to edit the
-file "Makefile.options" (i.e. to add -fPIC to compiler options) and then
-retry:
-
-$ vi Makefile.options
-$ make clean
-$ make
-
-
-5. Install Wiki-to-HTML converters
-
-Download latest LiquidFeedback Edition of RocketWiki from
-http://www.public-software-group.org/pub/projects/rocketwiki/liquid_feedback_edition/
-
-Compile the binaries by calling make, and copy them to a place of your
-choice, e.g. /opt/rocketwiki-lqfb/
-
-
-6. Configure the webserver and the LiquidFeedback Frontend application:
-
-Edit the configuration files in /opt/liquid_feedback_frontend/config/
-
-Use /opt/webmcp/doc/lighttpd.example.conf (or apache.sample.conf) to setup
-your webserver appropriatly.
-
-
-7. Compile help messages from wiki to html
-
-cd /opt/liquid_feedback_frontend/locale/
-make
-
-or by hand:
-
-for file in *.txt; do /opt/rocketwiki-lqfb/rocketwiki-lqfb < $file > $file.html; done
-
-
-

app/main/_filter/21_auth.lua

+local module = request.get_module()
+local view   = request.get_view()
+local action = request.get_action()
+
 local auth_needed = not (
-  request.get_module() == 'index'
+  module == 'index'
   and (
-       request.get_view()   == "index"
-    or request.get_view()   == "login"
-    or request.get_action() == "login"
-    or request.get_view()   == "register"
-    or request.get_action() == "register"
-    or request.get_view()   == "about"
-    or request.get_view()   == "reset_password"
-    or request.get_action() == "reset_password"
-    or request.get_view()   == "confirm_notify_email"
-    or request.get_action() == "confirm_notify_email"
-    or request.get_action() == "set_lang"
+       view   == "index"
+    or view   == "login"
+    or action == "login"
+    or view   == "register"
+    or action == "register"
+    or view   == "about"
+    or view   == "reset_password"
+    or action == "reset_password"
+    or view   == "confirm_notify_email"
+    or action == "confirm_notify_email"
+    or view   == "menu"
+    or action == "set_lang"
   )
-  or request.get_module() == "openid"
 )
 
-if config.public_access then
+if app.session:has_access("anonymous") then
 
   if
-    request.get_module() == "area" and request.get_view() == "show"
-    or request.get_module() == "unit" and request.get_view() == "show"
-    or request.get_module() == "policy" and request.get_view() == "show"
-    or request.get_module() == "policy" and request.get_view() == "list"
-    or request.get_module() == "issue" and request.get_view() == "show"
-    or request.get_module() == "initiative" and request.get_view() == "show"
-    or request.get_module() == "suggestion" and request.get_view() == "show"
-    or request.get_module() == "draft" and request.get_view() == "diff"
+    module == "area" and view == "show"
+    or module == "unit" and view == "show"
+    or module == "policy" and view == "show"
+    or module == "policy" and view == "list"
+    or module == "issue" and view == "show"
+    or module == "initiative" and view == "show"
+    or module == "suggestion" and view == "show"
+    or module == "draft" and view == "diff"
+    or module == "draft" and view == "show"
+    or module == "draft" and view == "list"
+    or module == "index" and view == "search"
+    or module == "index" and view == "usage_terms"
   then
     auth_needed = false
   end
 
 end
 
-if config.api_enabled and request.get_module() == "api" or request.get_module() == "sitemap" then
+if app.session:has_access("all_pseudonymous") then
+  if module == "member_image" and view == "show"
+   or module == "vote" and view == "show_incoming"
+   or module == "interest" and view == "show_incoming"
+   or module == "supporter" and view == "show_incoming" then
+    auth_needed = false
+  end
+end
+
+if app.session:has_access("everything") then
+  if module == "member" and (view == "show" or view == "history") then
+    auth_needed = false
+  end
+end
+
+if module == "sitemap" then
   auth_needed = false
 end
 
-if config.public_access and not app.session.member_id and auth_needed and request.get_module() == "index" and request.get_view() == "index" then
+if app.session:has_access("anonymous") and not app.session.member_id and auth_needed and module == "index" and view == "index" then
   if config.single_unit_id then
     request.redirect{ module = "unit", view = "show", id = config.single_unit_id }
   else
   trace.debug("Not authenticated yet.")
   request.redirect{
     module = 'index', view = 'login', params = {
-      redirect_module = request.get_module(),
-      redirect_view = request.get_view(),
+      redirect_module = module,
+      redirect_view = view,
       redirect_id = param.get_id()
     }
   }

app/main/_filter_view/30_navigation.lua

-slot.put_into("app_name", config.app_title)
-
 slot.select('navigation', function()
 
   ui.link{
-    attr = { class = "logolf" },
-    content = _"Home",
+    content = function()
+      ui.tag{ attr = { class = "logo_liquidfeedback" }, content = "LiquidFeedback" }
+      slot.put(" &middot; ")
+      ui.tag{ content = config.instance_name }
+    end,
     module = 'index',
     view   = 'index'
   }
   
-  if app.session.member_id then
+  if app.session:has_access("anonymous") then
+
     ui.link{
-      content = _"Units",
-      module = 'unit',
-      view   = 'list'
+      content = _"Search",
+      module = 'index',
+      view   = 'search'
     }
-    ui.link{
-      content = _"Members",
-      module = 'member',
-      view   = 'list'
-    }
-    ui.link{
-      content = _"Contacts",
-      module = 'contact',
-      view   = 'list'
-    }
-  end
-
-  ui.link{
-    content = _"Search",
-    module = 'index',
-    view   = 'search'
-  }
   
-  if config.public_access and app.session.member == nil then
-    ui.link{
-      text   = _"Login",
-      module = 'index',
-      view   = 'login',
-      params = {
-        redirect_module = request.get_module(),
-        redirect_view = request.get_view(),
-        redirect_id = param.get_id()
+    if app.session.member == nil then
+      ui.link{
+        text   = _"Login",
+        module = 'index',
+        view   = 'login',
+        params = {
+          redirect_module = request.get_module(),
+          redirect_view = request.get_view(),
+          redirect_id = param.get_id()
+        }
       }
-    }
+    end
+    
   end
 
   if app.session.member == nil then
       module = 'index',
       view   = 'reset_password'
     }
-  else 
+  end
+end)
 
-    ui.container{ attr = { class = "member_info" }, content = function()
-      ui.link{
+
+slot.select('navigation_right', function()
+  ui.tag{ 
+    tag = "ul",
+    attr = { id = "member_menu" },
+    content = function()
+      ui.tag{ 
+        tag = "li",
         content = function()
-          execute.view{
-            module = "member_image",
-            view = "_show",
-            params = {
-              member = app.session.member,
-              image_type = "avatar",
-              show_dummy = true,
-              class = "micro_avatar",
-            }
+          ui.link{
+            module = "index",
+            view = "menu",
+            content = function()
+              if app.session.member_id then
+                execute.view{
+                  module = "member_image",
+                  view = "_show",
+                  params = {
+                    member = app.session.member,
+                    image_type = "avatar",
+                    show_dummy = true,
+                    class = "micro_avatar",
+                  }
+                }
+                ui.tag{ content = app.session.member.name }
+              else
+                ui.tag{ content = _"Select language" }
+              end
+            end
           }
-          ui.tag{ content = app.session.member.name }
-        end,
-        module = "member",
-        view = "show",
-        id = app.session.member_id
+          execute.view{ module = "index", view = "_menu" }
+        end
       }
-
-      ui.link{
-        text   = _"Settings",
-        module = "member",
-        view = "settings"
-      }
-
-      if app.session.member_id then
-        ui.link{
-        --    image  = { static = "icons/16/stop.png" },
-          text   = _"Logout",
-          module = 'index',
-          action = 'logout',
-          routing = {
-            default = {
-              mode = "redirect",
-              module = "index",
-              view = "index"
-            }
-          }
-        }
-      end
-      
-    end }
-
-  end
-
+    end
+  }
 end)
 
 slot.select("footer", function()
   }
 end)
 
-
-if config.app_logo then
-  slot.select("logo", function()
-    ui.image{ static = config.app_logo }
-  end)
-end
-
 execute.inner()

app/main/_filter_view/35_openid.lua

-auth.openid.xrds_header{
-  module = "openid",
-  view = "announce.xrds"
-}
-
-execute.inner()

app/main/_filter_view/36_html_title.lua

   ..
   ( app.html_title.subtitle or "" )
   ..
-  config.app_title
+  _"LiquidFeedback" .. " - " .. config.instance_name
 )
 

app/main/_layout/default.html

     <link rel="stylesheet" type="text/css" media="screen" href="__BASEURL__/static/gregor.js/gregor.css" />
     <link rel="stylesheet" type="text/css" media="screen" href="<!-- WEBMCP SLOTNODIV stylesheet_url -->" />
     <!-- WEBMCP SLOTNODIV html_head -->
+    <script type="text/javascript">jsFail = true;</script>
+    <![if !IE]>
+      <script type="text/javascript">jsFail = false;</script>
+    <![endif]>
     <script type="text/javascript" src="__BASEURL__/static/js/partialload.js"></script>
     <script type="text/javascript">var ui_tabs_active = {};</script>
   </head>
   <body>
     <div class="topbar">
       <div class="topbar_content">
-        <div class="logout_button" id="logout_button">
-          <!-- WEBMCP SLOT logout_button -->
-        </div>
-        <div class="searchbox" id="searchbox">
-          <!-- WEBMCP SLOT searchbox -->
-        </div>
         <div class="navigation" id="navigation">
           <!-- WEBMCP SLOT navigation -->
         </div>
+        <div class="navigation_right" id="navigation_right">
+          <!-- WEBMCP SLOT navigation_right -->
+        </div>
+        <div class="help_hidden" id="help_hidden">
+          <!-- WEBMCP SLOT help_hidden -->
+        </div>
         <br style="clear: both;" />
       </div>
     </div>
     <div class="page">
+      <div class="page_head" id="head">
+        <!-- WEBMCP SLOT head -->
+      </div>
       <div class="layout_notice" id="layout_notice" onclick="document.getElementById('layout_notice').style.display='none';">
         <!-- WEBMCP SLOT notice -->
       </div>
       <div class="layout_error" id="layout_error" onclick="document.getElementById('layout_error').style.display='none';">
         <!-- WEBMCP SLOT error -->
       </div>
-      <div class="logo" id="logo">
-        <!-- WEBMCP SLOT logo -->
-      </div>
-      <div class="help_hidden" id="help_hidden">
-        <!-- WEBMCP SLOT help_hidden -->
-      </div>
-      <div class="title" id="title">
-        <!-- WEBMCP SLOT title -->
-      </div>
-      <div class="title2" id="title2">
-        <!-- WEBMCP SLOT title2 -->
-      </div>
-      <div class="actions" id="actions">
-        <div class="interest vote_info" id="interest">
-          <!-- WEBMCP SLOT interest -->
-        </div>
-        <!-- WEBMCP SLOT actions -->
-        <div style="clear: left;"></div>
-      </div>
-      <div class="initiatives_list" id="initiatives_list">
-        <!-- WEBMCP SLOT initiatives_list -->
-      </div>
-      <div class="initiative_head" id="initiative_head">
-        <!-- WEBMCP SLOT initiative_head -->
-      </div>
-      <div class="support vote_info" id="support">
-        <!-- WEBMCP SLOT support -->
-      </div>
-      <div class="initiative_main" id="initiative_main">
-        <!-- WEBMCP SLOT initiative_main -->
-      </div>
       <div class="main" id="default">
         <!-- WEBMCP SLOT default -->
       </div>

app/main/_layout/report.html

-<html>
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-    <title><!-- WEBMCP SLOTNODIV app_name --></title>
-    <link rel="stylesheet" type="text/css" media="screen" href="<!-- WEBMCP SLOTNODIV stylesheet_url -->" />
-    <script>
-      var lastEls = new Array();
-      function openEl(el) {
-        var el = document.getElementById(el);
-        if (! el) {
-          return;
-        }
-        if (lastEls.length > 0) {
-          lastEls[lastEls.length-1].style.display='none';
-        };
-        lastEls.push(el);
-        el.style.display = 'block';
-      }
-      function undo() {
-        if (lastEls.length > 1) {
-          var el = lastEls.pop();
-          el.style.display='none';
-        };
-        if (lastEls.length > 0) {
-          lastEls[lastEls.length-1].style.display = 'block';
-        };
-      }
-      var prev_issues = {};
-      var prev_initiatives = {};
-      var parents = {};
-      var next_initiatives = {};
-      var next_issues = {};
-      function openPrevIssue() {
-        openEl(prev_issues[lastEls[lastEls.length-1].id]);
-      };
-      function openPrevInitiative() {
-        openEl(prev_initiatives[lastEls[lastEls.length-1].id]);
-      };
-      function openParent() {
-        openEl(parents[lastEls[lastEls.length-1].id]);
-      };
-      function openNextInitiative() {
-        openEl(next_initiatives[lastEls[lastEls.length-1].id]);
-      };
-      function openNextIssue() {
-        openEl(next_issues[lastEls[lastEls.length-1].id]);
-      };
-      function openElDirect() {
-        var issue_id_el = document.getElementById("input_issue");
-        var initiative_id_el = document.getElementById("input_initiative");
-        if (initiative_id_el.value) {
-          openEl("initiative_" + initiative_id_el.value);
-        } else if (issue_id_el.value) {
-          openEl("issue_" + issue_id_el.value);
-        };
-        issue_id_el.value = "";
-        initiative_id_el.value = "";
-      }
-    </script>
-    <style>
-      .nav {
-        font-size: 75%;
-      }
-      .nav .left {
-        float: left;
-      }
-
-      .nav a {
-        text-decoration: none;
-        margin-left: 0.5em;
-        padding: 1ex;
-        background-color: #ddd;
-      }
-      .nav img {
-        vertical-align: middle;
-      }
-    </style>
-  </head>
-  <body>
-    <div class="main" id="default">
-      <!-- WEBMCP SLOT default -->
-    </div>
-  </body>
-  <script>
-  </script>
-</html>
-

app/main/_layout/rss.html

-<?xml version="1.0" encoding="utf-8"?>
-
-<rss version="2.0">
-  <channel>
-    <!-- WEBMCP SLOTNODIV default -->
-  </channel>
-</rss>

app/main/_layout/xml.html

-<?xml version="1.0" encoding="utf-8"?>
-<!-- WEBMCP SLOTNODIV default -->

app/main/admin/_action/area_update.lua

     pol:save()
   end
 end
-
-slot.put_into("notice", _"Area successfully updated")

app/main/admin/_action/member_update.lua

 
 param.update(member, "identification", "notify_email", "admin")
 
-if param.get("invite_member", atom.boolean) then
-  member:send_invitation()
+local locked = param.get("locked", atom.boolean)
+if locked ~= nil then
+  member.locked = locked
+end
+local deactivate = param.get("deactivate", atom.boolean)
+if deactivate then
+  member.active = false
+end
+local login = param.get("login")
+if login then
+  member.login = login
+end
+local name = param.get("name")
+if name then
+  member.name = name
 end
 
 local err = member:try_save()
   end
 end
 
+if not member.activated and param.get("invite_member", atom.boolean) then
+  member:send_invitation()
+end
+
 if id then
   slot.put_into("notice", _"Member successfully updated")
 else

app/main/admin/_action/policy_update.lua

 )
 
 policy:save()
-
-slot.put_into("notice", _"Policy successfully updated")

app/main/admin/_action/unit_update.lua

+local unit = Unit:by_id(param.get_id()) or Unit:new()
+
+param.update(unit, "parent_id", "name", "description", "active")
+
+unit:save()

app/main/admin/area_list.lua

 local areas = Area:build_selector{ unit_id = unit_id, active = not show_not_in_use }:exec()
 
 
-slot.put_into("title", _("Area list of '#{unit_name}'", { unit_name = unit.name}))
+ui.title(_("Area list of '#{unit_name}'", { unit_name = unit.name }))
 
 
-slot.select("actions", function()
-
-  ui.link{
-    attr = { class = { "admin_only" } },
-    text = _"Back to unit list",
-    module = "admin",
-    view = "unit_list"
-  }
+ui.actions(function()
 
   if show_not_in_use then
     ui.link{
-      attr = { class = { "admin_only" } },
       text = _"Show areas in use",
       module = "admin",
       view = "area_list",
 
   else
     ui.link{
-      attr = { class = { "admin_only" } },
       text = _"Create new area",
       module = "admin",
       view = "area_show",
       params = { unit_id = unit_id }
     }
+
+    slot.put(" &middot; ")
+
     ui.link{
-      attr = { class = { "admin_only" } },
       text = _"Show areas not in use",
       module = "admin",
       view = "area_list",

app/main/admin/area_show.lua

   area.unit_id = param.get("unit_id", atom.integer)
 end
 
-slot.put_into("title", _"Create / edit area")
-
-slot.select("actions", function()
-  ui.link{
-    attr = { class = { "admin_only" } },
-    text = _"Cancel",
-    module = "admin",
-    view = "area_list",
-    params = { unit_id = area.unit_id }
-  }
-end)
+ui.title(_"Create / edit area")
 
 ui.form{
   attr = { class = "vertical" },

app/main/admin/member_edit.lua

 local member = Member:by_id(id)
 
 if member then
-  slot.put_into("title", encode.html(_("Member: '#{login}' (#{name})", { login = member.login, name = member.name })))
+  ui.title(_("Member: '#{identification}' (#{name})", { identification = member.identification, name = member.name }))
 else
-  slot.put_into("title", encode.html(_"Register new member"))
+  ui.title(_"Register new member")
 end
 
 local units_selector = Unit:new_selector()
   content = function()
     ui.field.text{     label = _"Identification", name = "identification" }
     ui.field.text{     label = _"Notification email", name = "notify_email" }
+    if member and member.activated then
+      ui.field.text{     label = _"Screen name",        name = "name" }
+      ui.field.text{     label = _"Login name",        name = "login" }
+    end
     ui.field.boolean{  label = _"Admin?",       name = "admin" }
 
     slot.put("<br />")
     end
     slot.put("<br /><br />")
 
-    ui.field.boolean{  label = _"Send invite?",       name = "invite_member" }
+    if not member or not member.activated then
+      ui.field.boolean{  label = _"Send invite?",       name = "invite_member" }
+    end
+    
+    if member and member.activated then
+      ui.field.boolean{  label = _"Lock member?",       name = "locked" }
+    end
+    
+    ui.field.boolean{ 
+      label = _"Member inactive?", name = "deactivate",
+      readonly = member and member.active, value = member and member.active == false
+    }
+    
+    slot.put("<br />")
     ui.submit{         text  = _"Save" }
   end
 }

app/main/admin/member_list.lua

-local show_locked = param.get("show_locked", atom.boolean)
+local search = param.get("search")
 
-local members_selector = Member:build_selector{ 
-  active = not show_locked,
-  order = "login"
-}
+ui.title(_"Member list")
 
-
-slot.put_into("title", _"Member list")
-
-
-slot.select("actions", function()
+ui.actions(function()
   ui.link{
     attr = { class = { "admin_only" } },
     text = _"Register new member",
     module = "admin",
     view = "member_edit"
   }
-  if show_locked then
-    ui.link{
-      attr = { class = { "admin_only" } },
-      text = _"Show active members",
-      module = "admin",
-      view = "member_list"
-    }
-  else
-    ui.link{
-      attr = { class = { "admin_only" } },
-      text = _"Show locked members",
-      module = "admin",
-      view = "member_list",
-      params = { show_locked = true }
-    }
+end)
+
+
+ui.form{
+  module = "admin", view = "member_list",
+  content = function()
+  
+    ui.field.text{ label = _"Search for members", name = "search" }
+    
+    ui.submit{ value = _"Start search" }
+  
   end
-end)
+}
+
+if not search then
+  return
+end
+
+local members_selector = Member:build_selector{
+  admin_search = search,
+  order = "identification"
+}
 
 
 ui.paginate{
           name = "id"
         },
         {
-          label = _"Login",
-          name = "login"
+          label = _"Identification",
+          name = "identification"
         },
         {
-          label = _"Name",
+          label = _"Screen name",
+          name = "name"
+        },
+        {
+          label = _"Admin?",
           content = function(record)
-            util.put_highlighted_string(record.name)
+            if record.admin then
+              ui.field.text{ value = "admin" }
+            end
           end
         },
         {
-          label = _"Ident number",
-          name = "ident_number"
-        },
-        {
-          label = _"Admin?",
-          name = "admin"
+          content = function(record)
+            if not record.activated then
+              ui.field.text{ value = "not activated" }
+            elseif not record.active then
+              ui.field.text{ value = "inactive" }
+            else
+              ui.field.text{ value = "active" }
+            end
+          end
         },
         {
           content = function(record)
-            if not record.active then
+            if record.locked then
               ui.field.text{ value = "locked" }
             end
           end

app/main/admin/policy_list.lua

 local policies = Policy:build_selector{ active = not show_not_in_use }:exec()
 
 
-slot.put_into("title", _"Policy list")
+ui.title(_"Policy list")
 
 
-slot.select("actions", function()
+ui.actions(function()
 
   if show_not_in_use then
     ui.link{
-      attr = { class = { "admin_only" } },
       text = _"Show policies in use",
       module = "admin",
       view = "policy_list"
 
   else
     ui.link{
-      attr = { class = { "admin_only" } },
       text = _"Create new policy",
       module = "admin",
       view = "policy_show"
     }
+    slot.put(" &middot; ")
     ui.link{
-      attr = { class = { "admin_only" } },
       text = _"Show policies not in use",
       module = "admin",
       view = "policy_list",
 
     { content = function(record)
         ui.link{
-          attr = { class = { "action admin_only" } },
           text = _"Edit",
           module = "admin",
           view = "policy_show",

app/main/admin/policy_show.lua

 local policy = Policy:by_id(param.get_id()) or Policy:new()
 
-
-slot.put_into("title", _"Create / edit policy")
-
-
-slot.select("actions", function()
-  ui.link{
-    attr = { class = { "admin_only" } },
-    text = _"Cancel",
-    module = "admin",
-    view = "policy_list"
-  }
-end)
-
+ui.title(_"Create / edit policy")
 
 ui.form{
   attr = { class = "vertical" },

app/main/admin/unit_edit.lua

+local id = param.get_id()
+
+local unit = Unit:by_id(id)
+
+if unit then
+  ui.title(_("Unit: '#{name}'", { name = unit.name }))
+else
+  ui.title(_"Add new unit")
+end
+
+local units = {
+  { id = nil, name = "" }
+}
+
+for i, unit in ipairs(Unit:get_flattened_tree()) do
+  units[#units+1] = { id = unit.id, name = unit.name }
+end
+
+ui.form{
+  attr = { class = "vertical" },
+  module = "admin",
+  action = "unit_update",
+  id = unit and unit.id,
+  record = unit,
+  routing = {
+    default = {
+      mode = "redirect",
+      modules = "admin",
+      view = "unit_list"
+    }
+  },
+  content = function()
+    ui.field.select{
+      label = _"Parent unit",
+      name = "parent_id",
+      foreign_records = units,
+      foreign_id      = "id",
+      foreign_name    = "name"
+    }
+    ui.field.text{     label = _"Name",         name = "name" }
+    ui.field.text{     label = _"Description",  name = "description", multiline = true }
+    ui.field.boolean{  label = _"Active?",      name = "active" }
+
+    slot.put("<br />")
+    ui.submit{         text  = _"Save" }
+  end
+}

app/main/admin/unit_list.lua

 local units = Unit:get_flattened_tree{ active = true }
 
-slot.put_into("title", _"Unit list")
+ui.title(_"Unit list")
 
-slot.select("actions", function()
+ui.actions(function()
   ui.link{
-    attr = { class = { "admin_only" } },
     text = _"Create new unit",
     module = "admin",
     view = "unit_edit"
     {
       content = function(unit)
         ui.link{
-          attr = { class = "action admin_only" },
           text = _"Edit unit",
           module = "admin", view = "unit_edit", id = unit.id
         }
+        slot.put(" ")
         ui.link{
-          attr = { class = "action admin_only" },
           text = _"Edit areas",
           module = "admin", view = "area_list", params = { unit_id = unit.id }
         }

app/main/api/_filter/00_api.lua

-if not config.api_enabled then
-  error("API is not enabled.")
-end
-
-local api_key = param.get("key")
-
-if not api_key then
-  error("No API key supplied.")
-end
-
-local accepted = false
-
-if config.api_keys then
-  for i, config_api_key in ipairs(config.api_keys) do
-    if api_key == config_api_key then
-      accepted = true
-    end
-  end
-end
-
-if not accepted then
-  local setting_key = "liquidfeedback_frontend_api_key"
-
-  local setting = Setting:new_selector()
-    :add_where{ "key = ?", setting_key }
-    :add_where{ "value = ?", api_key }
-    :join("member", nil, "member.id = setting.member_id")
-    :add_where("member.active")
-    :optional_object_mode()
-    :exec()
-
-  if setting then
-    accepted = true
-  end
-end
-
-if not accepted then
-  error("Supplied API key is not valid.")
-end
-
-execute.inner()

app/main/api/area.lua

-local id     = param.get("id")
-local min_id = param.get("min_id")
-local max_id = param.get("max_id")
-local order  = param.get("order")
-local limit  = param.get("limit", atom.integer)
-
-local areas_selector = Area:new_selector()
-
-if id then
-  areas_selector:add_where{"area.id = ?", id}
-end
-
-if min_id then
-  areas_selector:add_where{"area.id >= ?", min_id}
-end
-
-if max_id then
-  areas_selector:add_where{"area.id <= ?", max_id}
-end
-
-if order == "name" then
-  areas_selector:add_order_by("area.name")
-end
-
-if order == "member_weight" then
-  areas_selector:add_order_by("area.member_weight DESC")
-end
-
-areas_selector:add_order_by("area.id")
-
-if limit then
-  initiatives_selector:limit(limit)
-end
-
-local api_engine = param.get("api_engine") or "xml"
-
-local fields = {
-
-  { name = "id",                   field = "area.id" },
-  { name = "name",                 field = "area.name" },
-  { name = "description",          field = "area.description" },
-  { name = "direct_member_count",  field = "area.direct_member_count" },
-  { name = "member_weight",        field = "area.member_weight" },
-  { name = "autoreject_weight",    field = "area.autoreject_weight" },
-  { name = "active",               field = "area.active" },
-
-}
-
-util.autoapi{
-  relation_name = "area",
-  selector      = areas_selector,
-  fields        = fields,
-  api_engine    = api_engine
-}

app/main/api/initiative.lua

-local id             = param.get("id")
-local min_id         = param.get("min_id")
-local max_id         = param.get("max_id")
-local area_id        = param.get("area_id", atom.integer)
-local issue_id       = param.get("issue_id", atom.integer)
-local policy_id      = param.get("policy_id", atom.integer)
-local state          = param.get("state")
-local agreed         = param.get("agreed")
-local rank           = param.get("rank")
---local search         = param.get("search")
---local search_context = param.get("search_context") or "full"
-local limit          = param.get("limit", atom.integer)
-local order          = param.get("order")
-local render_draft   = param.get("render_draft")
-
-if render_draft and render_draft ~= "html" then
-  error("unsupported render target, only 'html' is supported right now")
-end
-
-local initiatives_selector = Initiative:new_selector()
-  :join("issue", nil, "issue.id = initiative.issue_id")
-  :join("area", nil, "area.id = issue.area_id")
-  :join("policy", nil, "policy.id = issue.policy_id")
-
-if id then
-  initiatives_selector:add_where{"initiative.id = ?", id}
-end
-
-if min_id then
-  initiatives_selector:add_where{"initiative.id >= ?", min_id}
-end
-
-if max_id then
-  initiatives_selector:add_where{"initiative.id <= ?", max_id}
-end
-
-if area_id then
-  initiatives_selector:add_where{"area.id = ?", area_id}
-end
-
-if issue_id then
-  initiatives_selector:add_where{"issue.id = ?", issue_id}
-end
-
-if policy_id then
-  initiatives_selector:add_where{"policy.id = ?", policy_id}
-end
-
-if state then
-  Issue:modify_selector_for_state(initiatives_selector, state)
-end
-
-if agreed then
-  initiatives_selector:add_where("initiative.agreed")
-end
-
-if rank then
-  initiatives_selector:add_where{ "initiative.rank = ?", rank }
-end
-
---[[
-if search then
-  if search_context == "full" then
-  elseif search_context == "title" then
-  end
-end
---]]
-
-if order == "supporter_count" then
-  initiatives_selector:add_order_by("initiative.supporter_count")
-end
-
-if order == "id_desc" then
-  initiatives_selector:add_order_by("initiative.id DESC")
-else
-  initiatives_selector:add_order_by("initiative.id")
-end
-
-if limit then
-  initiatives_selector:limit(limit)
-end
-
-local api_engine = param.get("api_engine") or "xml"
-
-local function format_timestamp(timestamp)
-  if timestamp then
-    return format.timestamp(timestamp)
-  else
-    return ""
-  end
-end
-
-local fields = {
-
-  { name = "area_id",                   field = "area.id" },
-  { name = "area_name",                 field = "area.name" },
-  { name = "issue_id",                  field = "issue.id" },
-  {
-    name = "issue_state",
-    func = function(record)
-      return record.issue.state
-    end
-  },
-  {
-    name = "issue_created",
-    field = "issue.created",
-    func = function(record)
-      return format_timestamp(record.issue_created)
-    end
-  },
-  {
-    name = "issue_accepted",
-    field = "issue.accepted",
-    func = function(record)
-      return format_timestamp(record.issue_accepted)
-    end
-  },
-  {
-    name = "issue_half_frozen",
-    field = "issue.half_frozen",
-    func = function(record)
-      return format_timestamp(record.issue_half_frozen)
-    end
-  },
-  {
-    name = "issue_fully_frozen",
-    field = "issue.fully_frozen",
-    func = function(record)
-      return format_timestamp(record.issue_fully_frozen)
-    end
-  },
-  {
-    name = "issue_closed",
-    field = "issue.closed",
-    func = function(record)
-      return format_timestamp(record.issue_closed)
-    end
-  },
-  { name = "issue_admission_time",      field = "issue.admission_time" },
-  { name = "issue_discussion_time",     field = "issue.discussion_time" },
-  { name = "issue_verification_time",   field = "issue.verification_time" },
-  { name = "issue_voting_time",         field = "issue.voting_time" },
-  { name = "issue_ranks_available",     field = "issue.ranks_available" },
-
-  { name = "policy_issue_quorum_num",   field = "policy.issue_quorum_num" },
-  { name = "policy_issue_quorum_den",   field = "policy.issue_quorum_den" },
-  { name = "policy_initiative_quorum_num",
-                                        field = "policy.initiative_quorum_num" },
-  { name = "policy_initiative_quorum_den",
-                                        field = "policy.initiative_quorum_den" },
-  { name = "policy_majority_num",       field = "policy.majority_num" },
-  { name = "policy_majority_den",       field = "policy.majority_den" },
-  { name = "policy_majority_strict",    field = "policy.majority_strict" },
-  { name = "id",                        field = "initiative.id" },
-  { name = "name",                      field = "initiative.name" },
-  { name = "discussion_url",            field = "initiative.discussion_url" },
-  {
-    name = "created",
-    field = "initiative.created",
-    func = function(record)
-      return format_timestamp(record.created)
-    end
-  },
-  {
-    name = "revoked",
-    field = "initiative.revoked",
-    func = function(record)
-      return format_timestamp(record.revoked)
-    end
-  },
-  { name = "suggested_initiative_id",   field = "initiative.suggested_initiative_id" },
-  { name = "admitted",                  field = "initiative.admitted" },
-  { name = "issue_population",          field = "issue.population" },
-  { name = "supporter_count",           field = "initiative.supporter_count" },
-  { name = "informed_supporter_count",  field = "initiative.informed_supporter_count" },
-  { name = "satisfied_supporter_count", field = "initiative.satisfied_supporter_count" },
-  { name = "satisfied_informed_supporter_count",
-                                        field = "initiative.satisfied_informed_supporter_count" },
-  { name = "issue_vote_now",            field = "issue.vote_now" },
-  { name = "issue_vote_later",          field = "issue.vote_later" },
-  { name = "issue_voter_count",         field = "issue.voter_count" },
-  { name = "positive_votes",            field = "initiative.positive_votes" },
-  { name = "negative_votes",            field = "initiative.negative_votes" },
-  { name = "agreed",                    field = "initiative.agreed" },
-  { name = "rank",                      field = "initiative.rank" },
-  {
-    name = "current_draft_created",
-    func = function(record)
-      return format_timestamp(record.current_draft.created)
-    end
-  },
-  {
-    name = "current_draft_formatting_engine",
-    func = function(record)
-      return record.current_draft.formatting_engine
-    end
-  },
-  {
-    name = "current_draft_content",
-    func = function(record)
-      if render_draft then
-        return record.current_draft:get_content(render_draft)
-      else
-        return record.current_draft.content
-      end
-    end
-  }
-}
-
-util.autoapi{
-  relation_name = "initiative",
-  selector      = initiatives_selector,
-  fields        = fields,
-  api_engine    = api_engine
-}

app/main/api/suggestion.lua

-local id     = param.get("id")
-local min_id = param.get("min_id")
-local max_id = param.get("max_id")
-local initiative_id = param.get("initiative_id")
-local order  = param.get("order")
-local limit  = param.get("limit", atom.integer)
-
-local suggestions_selector = Suggestion:new_selector()
-
-if id then
-  suggestions_selector:add_where{"suggestion.id = ?", id}
-end
-
-if min_id then
-  suggestions_selector:add_where{"suggestion.id >= ?", min_id}
-end
-
-if max_id then
-  suggestions_selector:add_where{"suggestion.id <= ?", max_id}
-end
-
-if initiative_id then
-  suggestions_selector:add_where{"suggestion.initiative_id = ?", initiative_id}
-end
-
-if order == "created_desc" then
-  suggestions_selector:add_order_by("suggestion.created DESC")
-elseif order == "created_asc" or order == "created" then
-  suggestions_selector:add_order_by("suggestion.id")
-elseif order == "id_desc" then
-  suggestions_selector:add_order_by("suggestion.id DESC")
-else
-  suggestions_selector:add_order_by("suggestion.id")
-end
-
-if limit then
-  suggestions_selector:limit(limit)
-end
-
-local api_engine = param.get("api_engine") or "xml"
-
-local fields = {
-
-  { name = "id",                       field = "suggestion.id" },
-  { name = "initiative_id",            field = "suggestion.initiative_id" },
-  { name = "created",                  field = "suggestion.created" },
--- FIXME: private api
---  { name = "author_id",                field = "suggestion.author_id" },
-  { name = "name",                     field = "suggestion.name" },
-  { name = "description",              field = "suggestion.description" },
-  { name = "minus2_unfulfilled_count", field = "suggestion.minus2_unfulfilled_count" },
-  { name = "minus2_fulfilled_count",   field = "suggestion.minus2_fulfilled_count" },
-  { name = "minus1_unfulfilled_count", field = "suggestion.minus1_unfulfilled_count" },
-  { name = "minus1_fulfilled_count",   field = "suggestion.minus1_fulfilled_count" },
-  { name = "plus1_unfulfilled_count",  field = "suggestion.plus1_unfulfilled_count" },
-  { name = "plus1_fulfilled_count",    field = "suggestion.plus1_fulfilled_count" },
-  { name = "plus2_unfulfilled_count",  field = "suggestion.plus2_unfulfilled_count" },
-  { name = "plus2_fulfilled_count",    field = "suggestion.plus2_fulfilled_count" },
-
-}
-
-util.autoapi{
-  relation_name = "suggestion",
-  selector      = suggestions_selector,
-  fields        = fields,
-  api_engine    = api_engine
-}

app/main/area/_head.lua

+local area = param.get("area", "table")
+local member = param.get("member", "table")
+
+local show_content = param.get("show_content", atom.boolean)
+
+if app.session.member_id then
+  area:load_delegation_info_once_for_member_id(app.session.member_id)
+end
+
+if not param.get("hide_unit", atom.boolean) then
+  execute.view{ module = "unit", view = "_head", params = { unit = area.unit, member = member } }
+end
+
+ui.container{ attr = { class = "area_head" }, content = function()
+
+  execute.view{ module = "delegation", view = "_info", params = { area = area, member = member } }
+
+  ui.container{ attr = { class = "title" }, content = function()
+    -- area name
+    ui.link{
+      module = "area", view = "show", id = area.id,
+      attr = { class = "area_name" }, content = area.name 
+    }
+  end }
+  
+  if show_content then
+    
+    ui.container{ attr = { class = "content" }, content = function()
+
+      -- actions (members with appropriate voting right only)
+      if member then
+
+        -- membership
+        local membership = Membership:by_pk(area.id, member.id)
+
+        if membership then
+          
+          if app.session.member_id == member.id then
+            ui.tag{ content = _"You are participating in this area" }
+            slot.put(" ")
+            ui.tag{ content = function()
+              slot.put("(")
+              ui.link{
+                text    = _"Withdraw",
+                module  = "membership",
+                action  = "update",
+                params  = { area_id = area.id, delete = true },
+                routing = {
+                  default = {
+                    mode = "redirect",
+                    module = request.get_module(),
+                    view = request.get_view(),
+                    id = param.get_id_cgi(),
+                    params = param.get_all_cgi()
+                  }
+                }
+              }
+              slot.put(")")
+            end }
+          else
+            ui.tag{ content = _"Member is participating in this area" }
+          end
+
+        elseif app.session.member_id == member.id and member:has_voting_right_for_unit_id(area.unit_id) then
+          ui.link{
+            text   = _"Participate in this area",
+            module = "membership",
+            action = "update",
+            params = { area_id = area.id },
+            routing = {
+              default = {
+                mode = "redirect",
+                module = request.get_module(),
+                view = request.get_view(),
+                id = param.get_id_cgi(),
+                params = param.get_all_cgi()
+              }
+            }
+          }
+        end
+        
+        if app.session.member_id == member.id and app.session.member:has_voting_right_for_unit_id(area.unit_id) then
+
+          slot.put(" &middot; ")
+          if area.delegation_info.own_delegation_scope ~= "area" then
+            ui.link{ text = _"Delegate area", module = "delegation", view = "show", params = { area_id = area.id } }
+          else
+            ui.link{ text = _"Change area delegation", module = "delegation", view = "show", params = { area_id = area.id } }
+          end
+          slot.put(" &middot; ")
+
+          ui.link{
+            content = function()
+              slot.put(_"Create new issue")
+            end,
+            module = "initiative",
+            view = "new",
+            params = { area_id = area.id }
+          }
+        end
+
+      end
+
+    end }
+
+  else
+    slot.put("<br />")
+  end
+
+end }

app/main/area/_list.lua

 local areas_selector = param.get("areas_selector", "table")
 local hide_membership = param.get("hide_membership", atom.boolean)
+local member = param.get("member", "table")
 
 areas_selector
   :reset_fields()
   :add_field("area.id", nil, { "grouped" })
+  :add_field("area.unit_id", nil, { "grouped" })
   :add_field("area.name", nil, { "grouped" })
   :add_field("member_weight", nil, { "grouped" })
   :add_field("direct_member_count", nil, { "grouped" })
   areas_selector:add_field("0", "issues_to_vote_count")
 end
 
+ui.container{ attr = { class = "area_list" }, content = function()
+  for i, area in ipairs(areas_selector:exec()) do
+    execute.view { module = "area", view = "_list_entry", params = { area = area, member = member } }
+  end 
+end }
 
-ui.container{ attr = { class = "box area_list" }, content = function()
-
-  ui.container{ attr = { class = "area head" }, content = function()
-
-    ui.container{ attr = { class = "phases" }, content = function()
-
-      ui.container{ attr = { class = "admission" }, content = function()
-        ui.image{ static = "icons/16/new.png", attr = { alt = _"New" } }
-      end }
-
-      ui.container{ attr = { class = "discussion" }, content = function()
-        ui.image{ static = "icons/16/comments.png", attr = { alt = _"Discussion" } }
-      end }
-
-      ui.container{ attr = { class = "verification" }, content = function()
-        ui.image{ static = "icons/16/lock.png", attr = { alt = _"Verification" } }
-      end }
-
-      ui.container{ attr = { class = "voting" }, content = function()
-        ui.image{ static = "icons/16/email_open.png", attr = { alt = _"Voting" } }
-      end }
-
-      ui.container{ attr = { class = "finished" }, content = function()
-        ui.image{ static = "icons/16/tick.png", attr = { alt = _"Finished" } }
-      end }
-
-      ui.container{ attr = { class = "cancelled" }, content = function()
-        ui.image{ static = "icons/16/cross.png", attr = { alt = _"Cancelled" } }
-      end }
-
-    end }
-
-  end }
-    
-  for i, area in ipairs(areas_selector:exec()) do
-
-    ui.container{ attr = { class = "area" }, content = function()
-
-      ui.container{ attr = { class = "bar" }, content = function()
-        if area.member_weight and area.direct_member_count then
-          local max_value = MemberCount:get()
-          ui.bargraph{
-            max_value = max_value,
-            width = 100,
-            bars = {
-              { color = "#444", value = area.direct_member_count },
-              { color = "#777", value = area.member_weight - area.direct_member_count },
-              { color = "#ddd", value = max_value - area.member_weight },
-            }
-          }
-        end
-      end }
-
-      ui.container{ attr = { class = "name" }, content = function()
-        ui.link{
-          text = area.name,
-          module = "area",
-          view = "show",
-          id = area.id
-        }
-        slot.put(" ")
-        ui.tag{ content = "" }
-      end }
-
-      if not hide_membership then
-        ui.container{ attr = { class = "membership" }, content = function()
-          if area.is_member then
-            local text = _"Member of area"
-            ui.image{
-              attr = { title = text, alt = text },
-              static = "icons/16/user_gray.png",
-            }
-          else
-            slot.put('<img src="null.png" width="16" height="1" alt="" />')
-          end
-        end }
-      end
-      
-      ui.container{ attr = { class = "delegatee" }, content = function()
-        if area.trustee_member_id then
-          local trustee_member = Member:by_id(area.trustee_member_id)
-          local text = _("Area delegated to '#{name}'", { name = area.trustee_member_name })
-          ui.image{
-            attr = { class = "delegation_arrow", alt = text, title = text },
-            static = "delegation_arrow_24_horizontal.png"
-          }
-          execute.view{
-            module = "member_image",
-            view = "_show",
-            params = {
-              member = trustee_member,
-              image_type = "avatar",
-              show_dummy = true,
-              class = "micro_avatar",
-              popup_text = text
-            }
-          }
-        else
-          slot.put('<img src="null.png" width="41" height="1" alt="" />')
-        end
-      end }
-  
-      ui.container{ attr = { class = "phases" }, content = function()
-
-        ui.container{ attr = { class = "admission" }, content = function()
-          ui.link{
-            text = tostring(area.issues_new_count),
-            module = "area",
-            view = "show",
-            id = area.id,
-            params = { filter = "new", tab = "open" }
-          }
-        end }
-
-        ui.container{ attr = { class = "discussion" }, content = function()
-          ui.link{
-            text = tostring(area.issues_discussion_count),
-            module = "area",
-            view = "show",
-            id = area.id,
-            params = { filter = "accepted", tab = "open" }
-          }
-        end }
-
-        ui.container{ attr = { class = "verification" }, content = function()
-          ui.link{
-            text = tostring(area.issues_frozen_count),
-            module = "area",
-            view = "show",
-            id = area.id,
-            params = { filter = "half_frozen", tab = "open" }
-          }
-        end }
-
-        ui.container{ attr = { class = "voting" }, content = function()
-          ui.link{
-            text = tostring(area.issues_voting_count),
-            module = "area",
-            view = "show",
-            id = area.id,
-            params = { filter = "frozen", tab = "open" }
-          }
-        end }
-
-        ui.container{ attr = { class = "finished" }, content = function()
-          ui.link{
-            text = tostring(area.issues_finished_count),
-            module = "area",
-            view = "show",
-            id = area.id,
-            params = { filter = "finished", tab = "closed" }
-          }
-        end }
-
-        ui.container{ attr = { class = "cancelled" }, content = function()
-          ui.link{
-            text = tostring(area.issues_cancelled_count),
-            module = "area",
-            view = "show",
-            id = area.id,
-            params = { filter = "cancelled", issue_list = "newest", tab = "closed" }
-          }
-        end }
-
-      end }
-      
-      slot.put("<br style='clear: right;' />")
-    end }
-    
-  end
-  
-end }

app/main/area/_list_entry.lua

+local area = param.get("area", "table")
+local member = param.get("member", "table")
+
+ui.container{ attr = { class = "area" }, content = function()
+
+  execute.view{ module = "area", view = "_head", params = { area = area, hide_unit = true, show_content = true, member = member } }
+  
+  ui.container{ attr = { class = "content" }, content = function()
+    ui.tag{ content = _"Issues:" }
+    slot.put(" ")
+    ui.link{ 
+      module = "area", view = "show", id = area.id, params = { tab = "open", filter = "new" },
+      text = _("#{count} new", { count = area.issues_new_count }) 
+    }
+    slot.put(" &middot; ")
+    ui.link{ 
+      module = "area", view = "show", id = area.id, params = { tab = "open", filter = "accepted" },
+      text = _("#{count} in discussion", { count = area.issues_discussion_count }) 
+    }
+    slot.put(" &middot; ")
+    ui.link{ 
+      module = "area", view = "show", id = area.id, params = { tab = "open", filter = "half_frozen" },
+      text = _("#{count} in verification", { count = area.issues_frozen_count }) 
+    }
+    slot.put(" &middot; ")
+    ui.link{ 
+      module = "area", view = "show", id = area.id, params = { tab = "open", filter = "frozen" },
+      text = _("#{count} in voting", { count = area.issues_voting_count }) 
+    }
+    slot.put(" &middot; ")
+    ui.link{ 
+      module = "area", view = "show", id = area.id, params = { tab = "closed", filter = "finished" },
+      text = _("#{count} finished", { count = area.issues_finished_count }) 
+    }
+    slot.put(" &middot; ")
+    ui.link{ 
+      module = "area", view = "show", id = area.id, params = { tab = "closed", filter = "cancelled" },
+      text = _("#{count} cancelled", { count = area.issues_cancelled_count }) 
+    }
+  end }
+
+end }

app/main/area/show.lua

 
 util.help("area.show")
 
-
-if config.feature_rss_enabled then
-  util.html_rss_head{ title = _"Initiatives in this area (last created first)", module = "initiative", view = "list_rss", params = { area_id = area.id } }
-  util.html_rss_head{ title = _"Initiatives in this area (last updated first)", module = "initiative", view = "list_rss", params = { area_id = area.id } }
-end
-
-
-slot.select("title", function()
-  ui.link{
-    content =  area.name,
-    module = "area", view = "show", id = area.id
-  }
-
-  if not config.single_unit_id then
-    slot.put(" &middot; ")
-    ui.link{
-      content = area.unit.name,
-      module = "unit",
-      view = "show",
-      id = area.unit_id
-    }
-  end
-
-
+slot.select("head", function()
+  execute.view{ module = "area", view = "_head", params = { area = area, show_content = true, member = app.session.member } }
 end)
 
 ui.container{
 }
 
 
-if app.session.member_id then
-  execute.view{
-    module = "membership",
-    view = "_show_box",
-    params = { area = area }