liquid_feedback_frontend
changeset 2:5c601807d397 alpha3
Version alpha3
Dark green part of issue supporter bargraph represents all satisfied supporters, regardless of having seen the latest draft
Wiki formatting for drafts
Showing differences between two drafts of the same initiative
Display of outgoing delegation chains
Many other improvements
Dark green part of issue supporter bargraph represents all satisfied supporters, regardless of having seen the latest draft
Wiki formatting for drafts
Showing differences between two drafts of the same initiative
Display of outgoing delegation chains
Many other improvements
line diff
1.1 --- a/app/main/_layout/default.html Wed Nov 18 12:00:00 2009 +0100 1.2 +++ b/app/main/_layout/default.html Mon Nov 23 12:00:00 2009 +0100 1.3 @@ -18,27 +18,29 @@ 1.4 <!-- WEBMCP SLOT navigation --> 1.5 </div> 1.6 </div> 1.7 - <div class="infobox" id="infobox"> 1.8 - <div class="interest" id="interest"> 1.9 - <!-- WEBMCP SLOT interest --> 1.10 + <div class="title_bar"> 1.11 + <div class="issue_info" id="issue_info"> 1.12 + <!-- WEBMCP SLOT issue_info --> 1.13 </div> 1.14 - <div class="support" id="support"> 1.15 - <!-- WEBMCP SLOT support --> 1.16 - </div> 1.17 - <div class="delegation" id="delegation"> 1.18 - <!-- WEBMCP SLOT delegation --> 1.19 - </div> 1.20 - </div> 1.21 - <div class="title_bar"> 1.22 <div class="path" id="path"> 1.23 <!-- WEBMCP SLOT path --> 1.24 </div> 1.25 <div class="title" id="title"> 1.26 <!-- WEBMCP SLOT title --> 1.27 </div> 1.28 + <div class="interest vote_info" id="interest"> 1.29 + <!-- WEBMCP SLOT interest --> 1.30 + </div> 1.31 + <div class="support vote_info" id="support"> 1.32 + <!-- WEBMCP SLOT support --> 1.33 + </div> 1.34 + <div class="delegation vote_info" id="delegation"> 1.35 + <!-- WEBMCP SLOT delegation --> 1.36 + </div> 1.37 <div class="actions" id="actions"> 1.38 <!-- WEBMCP SLOT actions --> 1.39 </div> 1.40 + <br style="clear: left;" /> 1.41 </div> 1.42 <div class="main" id="default"> 1.43 <!-- WEBMCP SLOT default -->
2.1 --- a/app/main/area/_list.lua Wed Nov 18 12:00:00 2009 +0100 2.2 +++ b/app/main/area/_list.lua Mon Nov 23 12:00:00 2009 +0100 2.3 @@ -35,7 +35,7 @@ 2.4 local max_value = MemberCount:get() 2.5 ui.bargraph{ 2.6 max_value = max_value, 2.7 - width = 100, 2.8 + width = 200, 2.9 bars = { 2.10 { color = "#444", value = record.direct_member_count }, 2.11 { color = "#777", value = record.member_weight - record.direct_member_count },
3.1 --- a/app/main/area/show.lua Wed Nov 18 12:00:00 2009 +0100 3.2 +++ b/app/main/area/show.lua Mon Nov 23 12:00:00 2009 +0100 3.3 @@ -13,19 +13,19 @@ 3.4 slot.select("actions", function() 3.5 ui.link{ 3.6 content = function() 3.7 - ui.image{ static = "icons/16/folder_add.png" } 3.8 - slot.put(_"Create new issue") 3.9 + ui.image{ static = "icons/16/table_go.png" } 3.10 + slot.put(_"Delegate") 3.11 end, 3.12 - module = "initiative", 3.13 + module = "delegation", 3.14 view = "new", 3.15 params = { area_id = area.id } 3.16 } 3.17 ui.link{ 3.18 content = function() 3.19 - ui.image{ static = "icons/16/table_go.png" } 3.20 - slot.put(_"Delegate") 3.21 + ui.image{ static = "icons/16/folder_add.png" } 3.22 + slot.put(_"Create new issue") 3.23 end, 3.24 - module = "delegation", 3.25 + module = "initiative", 3.26 view = "new", 3.27 params = { area_id = area.id } 3.28 } 3.29 @@ -45,68 +45,35 @@ 3.30 3.31 ui.tabs{ 3.32 { 3.33 - name = "new", 3.34 - label = _"New", 3.35 - content = function() 3.36 - execute.view{ 3.37 - module = "issue", 3.38 - view = "_list", 3.39 - params = { issues_selector = area:get_reference_selector("issues"):add_where("issue.accepted ISNULL AND issue.closed ISNULL"), for_area_list = true } 3.40 - } 3.41 - end 3.42 - }, 3.43 - { 3.44 - name = "accepted", 3.45 - label = _"In discussion", 3.46 - content = function() 3.47 - execute.view{ 3.48 - module = "issue", 3.49 - view = "_list", 3.50 - params = { issues_selector = area:get_reference_selector("issues"):add_where("issue.accepted NOTNULL AND issue.half_frozen ISNULL AND issue.closed ISNULL"), for_area_list = true } 3.51 - } 3.52 - end 3.53 - }, 3.54 - { 3.55 - name = "half_frozen", 3.56 - label = _"Frozen", 3.57 + name = "issues", 3.58 + label = _"Issues", 3.59 content = function() 3.60 execute.view{ 3.61 module = "issue", 3.62 view = "_list", 3.63 - params = { issues_selector = area:get_reference_selector("issues"):add_where("issue.half_frozen NOTNULL AND issue.closed ISNULL"), for_area_list = true } 3.64 - } 3.65 - end 3.66 - }, 3.67 - { 3.68 - name = "frozen", 3.69 - label = _"Voting", 3.70 - content = function() 3.71 - execute.view{ 3.72 - module = "issue", 3.73 - view = "_list", 3.74 - params = { issues_selector = area:get_reference_selector("issues"):add_where("issue.fully_frozen NOTNULL AND issue.closed ISNULL"), for_area_list = true } 3.75 + params = { issues_selector = area:get_reference_selector("issues"), for_area_list = true } 3.76 } 3.77 end 3.78 }, 3.79 { 3.80 - name = "finished", 3.81 - label = _"Finished", 3.82 + name = "members", 3.83 + label = _"Members", 3.84 content = function() 3.85 execute.view{ 3.86 - module = "issue", 3.87 + module = "member", 3.88 view = "_list", 3.89 - params = { issues_selector = area:get_reference_selector("issues"):add_where("issue.closed NOTNULL AND ranks_available"), for_area_list = true } 3.90 + params = { members_selector = area:get_reference_selector("members") } 3.91 } 3.92 end 3.93 }, 3.94 { 3.95 - name = "cancelled", 3.96 - label = _"Cancelled", 3.97 + name = "delegations", 3.98 + label = _"Delegations", 3.99 content = function() 3.100 execute.view{ 3.101 - module = "issue", 3.102 + module = "delegation", 3.103 view = "_list", 3.104 - params = { issues_selector = area:get_reference_selector("issues"):add_where("issue.closed NOTNULL AND NOT ranks_available"), for_area_list = true } 3.105 + params = { delegations_selector = area:get_reference_selector("delegations") } 3.106 } 3.107 end 3.108 },
4.1 --- a/app/main/delegation/_list.lua Wed Nov 18 12:00:00 2009 +0100 4.2 +++ b/app/main/delegation/_list.lua Mon Nov 23 12:00:00 2009 +0100 4.3 @@ -1,50 +1,73 @@ 4.4 -local selector = param.get("selector", "table") 4.5 +local delegations_selector = param.get("delegations_selector", "table") 4.6 +local outgoing = param.get("outgoing", atom.boolean) 4.7 +local incoming = param.get("incoming", atom.boolean) 4.8 + 4.9 +local function delegation_scope(delegation) 4.10 + ui.container{ 4.11 + attr = { class = "delegation_scope" }, 4.12 + content = function() 4.13 + local area 4.14 + if delegation.issue then 4.15 + area = delegation.issue.area 4.16 + else 4.17 + area = delegation.area 4.18 + end 4.19 + if not area then 4.20 + ui.field.text{ value = _"Global delegation" } 4.21 + end 4.22 + if area then 4.23 + ui.link{ 4.24 + content = _"Area '#{name}'":gsub("#{name}", area.name), 4.25 + module = "area", 4.26 + view = "show", 4.27 + id = area.id 4.28 + } 4.29 + end 4.30 + if delegation.issue then 4.31 + ui.link{ 4.32 + content = _"Issue ##{id}":gsub("#{id}", delegation.issue.id), 4.33 + module = "issue", 4.34 + view = "show", 4.35 + id = delegation.issue.id 4.36 + } 4.37 + end 4.38 + end 4.39 + } 4.40 +end 4.41 + 4.42 4.43 ui.paginate{ 4.44 - selector = selector, 4.45 + selector = delegations_selector, 4.46 content = function() 4.47 - ui.list{ 4.48 - records = selector:exec(), 4.49 - columns = { 4.50 - { 4.51 - label = _"Truster", 4.52 - content = function(record) 4.53 - ui.link{ 4.54 - content = record.truster.name, 4.55 + for i, delegation in ipairs(delegations_selector:exec()) do 4.56 + ui.container{ 4.57 + attr = { class = "delegation_list_entry" }, 4.58 + content = function() 4.59 + if outgoing then 4.60 + delegation_scope(delegation) 4.61 + else 4.62 + execute.view{ 4.63 module = "member", 4.64 - view = "show", 4.65 - id = record.truster.id 4.66 + view = "_show_thumb", 4.67 + params = { member = delegation.truster } 4.68 } 4.69 end 4.70 - }, 4.71 - { 4.72 - label = _"Trustee", 4.73 - content = function(record) 4.74 - ui.link{ 4.75 - content = record.trustee.name, 4.76 + ui.image{ 4.77 + attr = { class = "delegation_arrow" }, 4.78 + static = "delegation_arrow.jpg" 4.79 + } 4.80 + if incoming then 4.81 + delegation_scope(delegation) 4.82 + else 4.83 + execute.view{ 4.84 module = "member", 4.85 - view = "show", 4.86 - id = record.trustee.id 4.87 + view = "_show_thumb", 4.88 + params = { member = delegation.trustee } 4.89 } 4.90 end 4.91 - }, 4.92 - { 4.93 - label = _"Area", 4.94 - content = function(record) 4.95 - if record.area then 4.96 - ui.field.text{ value = record.area.name } 4.97 - end 4.98 - end 4.99 - }, 4.100 - { 4.101 - label = _"Issue", 4.102 - content = function(record) 4.103 - if record.issue then 4.104 - ui.field.text{ value = record.issue.id } 4.105 - end 4.106 - end 4.107 - }, 4.108 + end 4.109 } 4.110 - } 4.111 + end 4.112 + slot.put("<br style='clear: left;' />") 4.113 end 4.114 }
5.1 --- a/app/main/delegation/_show_box.lua Wed Nov 18 12:00:00 2009 +0100 5.2 +++ b/app/main/delegation/_show_box.lua Mon Nov 23 12:00:00 2009 +0100 5.3 @@ -50,63 +50,70 @@ 5.4 ui.container{ 5.5 attr = { class = "content", id = "delegation_content" }, 5.6 content = function() 5.7 + ui.container{ 5.8 + attr = { 5.9 + class = "close", 5.10 + style = "cursor: pointer;", 5.11 + onclick = "document.getElementById('delegation_content').style.display = 'none';" 5.12 + }, 5.13 + content = _"X" 5.14 + } 5.15 5.16 local delegation_chain = db:query{ "SELECT * FROM delegation_chain(?, ?, ?) JOIN member ON member.id = member_id ORDER BY index", app.session.member.id, area_id, issue_id } 5.17 5.18 for i, record in ipairs(delegation_chain) do 5.19 local style 5.20 - if record.participation then 5.21 - style = "font-weight: bold;" 5.22 - end 5.23 - if record.overridden then 5.24 - style = "color: #777;" 5.25 - end 5.26 - if not record.active then 5.27 - style = "text-decoration: line-through;" 5.28 - end 5.29 - if record.scope_in then 5.30 - ui.field.text{ 5.31 - value = " v " .. record.scope_in .. " v " 5.32 + execute.view{ 5.33 + module = "member", 5.34 + view = "_show_thumb", 5.35 + params = { member = record } 5.36 + } 5.37 + slot.put("<br style='clear: left'/>") 5.38 + if record.scope_out then 5.39 + ui.container{ 5.40 + attr = { class = "delegation_info" }, 5.41 + content = function() 5.42 + ui.image{ 5.43 + attr = { class = "delegation_arrow" }, 5.44 + static = "delegation_arrow_vertical.jpg" 5.45 + } 5.46 + ui.container{ 5.47 + attr = { class = "delegation_scope" }, 5.48 + content = function() 5.49 + if record.scope_out == "global" then 5.50 + slot.put(_"Global delegation") 5.51 + elseif record.scope_out == "area" then 5.52 + slot.put(_"Area delegation") 5.53 + elseif record.scope_out == "issue" then 5.54 + slot.put(_"Issue delegation") 5.55 + end 5.56 + end 5.57 + } 5.58 + if record.id == app.session.member.id then 5.59 + ui.link{ 5.60 + attr = { class = "revoke" }, 5.61 + content = function() 5.62 + ui.image{ static = "icons/16/delete.png" } 5.63 + slot.put(_"Revoke") 5.64 + end, 5.65 + module = "delegation", 5.66 + action = "update", 5.67 + params = { issue_id = delegation.issue_id, area_id = delegation.area_id, delete = true }, 5.68 + routing = { 5.69 + default = { 5.70 + mode = "redirect", 5.71 + module = request.get_module(), 5.72 + view = request.get_view(), 5.73 + id = param.get_id_cgi(), 5.74 + params = param.get_all_cgi() 5.75 + } 5.76 + } 5.77 + } 5.78 + end 5.79 + end 5.80 } 5.81 end 5.82 - local name = record.name 5.83 - if record.member_id == app.session.member.id then 5.84 - name = _"Me" 5.85 - end 5.86 - ui.field.text{ 5.87 - attr = { style = style }, 5.88 - value = name 5.89 - } 5.90 end 5.91 - 5.92 - ui.link{ 5.93 - attr = { class = "revoke" }, 5.94 - content = function() 5.95 - ui.image{ static = "icons/16/delete.png" } 5.96 - slot.put(_"Revoke") 5.97 - end, 5.98 - module = "delegation", 5.99 - action = "update", 5.100 - params = { issue_id = delegation.issue_id, area_id = delegation.area_id, delete = true }, 5.101 - routing = { 5.102 - default = { 5.103 - mode = "redirect", 5.104 - module = request.get_module(), 5.105 - view = request.get_view(), 5.106 - id = param.get_id_cgi(), 5.107 - params = param.get_all_cgi() 5.108 - } 5.109 - } 5.110 - } 5.111 - 5.112 - ui.container{ 5.113 - attr = { 5.114 - class = "head", 5.115 - style = "cursor: pointer;", 5.116 - onclick = "document.getElementById('delegation_content').style.display = 'none';" 5.117 - }, 5.118 - content = _"Click here to close." 5.119 - } 5.120 end 5.121 } 5.122 end
6.1 --- a/app/main/draft/_list.lua Wed Nov 18 12:00:00 2009 +0100 6.2 +++ b/app/main/draft/_list.lua Mon Nov 23 12:00:00 2009 +0100 6.3 @@ -1,30 +1,43 @@ 6.4 -ui.list{ 6.5 - records = param.get("drafts", "table"), 6.6 - columns = { 6.7 - { 6.8 - label = _"Id", 6.9 - name = "id" 6.10 - }, 6.11 - { 6.12 - label = _"Created at", 6.13 - content = function(record) 6.14 - ui.field.text{ value = format.timestamp(record.created) } 6.15 - end 6.16 - }, 6.17 - { 6.18 - label = _"Author", 6.19 - name = "author_name" 6.20 - }, 6.21 - { 6.22 - content = function(record) 6.23 - ui.link{ 6.24 - attr = { class = "action" }, 6.25 - text = _"Show", 6.26 - module = "draft", 6.27 - view = "show", 6.28 - id = record.id 6.29 +ui.form{ 6.30 + method = "get", 6.31 + module = "draft", 6.32 + view = "diff", 6.33 + content = function() 6.34 + ui.list{ 6.35 + records = param.get("drafts", "table"), 6.36 + columns = { 6.37 + { 6.38 + label = _"Created at", 6.39 + content = function(record) 6.40 + ui.field.text{ readonly = true, value = format.timestamp(record.created) } 6.41 + end 6.42 + }, 6.43 + { 6.44 + label = _"Author", 6.45 + content = function(record) 6.46 + ui.field.text{ readonly = true, value = record.author.name } 6.47 + end 6.48 + }, 6.49 + { 6.50 + content = function(record) 6.51 + ui.link{ 6.52 + attr = { class = "action" }, 6.53 + text = _"Show", 6.54 + module = "draft", 6.55 + view = "show", 6.56 + id = record.id 6.57 + } 6.58 + end 6.59 + }, 6.60 + { 6.61 + label = _"Compare", 6.62 + content = function(record) 6.63 + slot.put('<input type="radio" name="old_draft_id" value="' .. tostring(record.id) .. '">') 6.64 + slot.put('<input type="radio" name="new_draft_id" value="' .. tostring(record.id) .. '">') 6.65 + end 6.66 } 6.67 - end 6.68 + } 6.69 } 6.70 - } 6.71 + ui.submit{ text = _"Compare" } 6.72 + end 6.73 }
7.1 --- a/app/main/draft/_show.lua Wed Nov 18 12:00:00 2009 +0100 7.2 +++ b/app/main/draft/_show.lua Mon Nov 23 12:00:00 2009 +0100 7.3 @@ -6,9 +6,13 @@ 7.4 readonly = true, 7.5 content = function() 7.6 7.7 - ui.field.text{ label = _"Initiative", value = draft.initiative.name } 7.8 ui.field.text{ label = _"Author", name = "author_name" } 7.9 - ui.field.text{ label = _"Content", name = "content" } 7.10 - 7.11 + ui.field.timestamp{ label = _"Created at", name = "created" } 7.12 + ui.container{ 7.13 + attr = { class = "draft_content" }, 7.14 + content = function() 7.15 + slot.put(format.wiki_text(draft.content)) 7.16 + end 7.17 + } 7.18 end 7.19 }
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/app/main/draft/diff.lua Mon Nov 23 12:00:00 2009 +0100 8.3 @@ -0,0 +1,93 @@ 8.4 +slot.put_into("title", _"Diff") 8.5 + 8.6 +local old_draft_id = param.get("old_draft_id", atom.integer) 8.7 +local new_draft_id = param.get("new_draft_id", atom.integer) 8.8 + 8.9 +if old_draft_id > new_draft_id then 8.10 + local tmp = old_draft_id 8.11 + old_draft_id = new_draft_id 8.12 + new_draft_id = tmp 8.13 +end 8.14 + 8.15 +local old_draft = Draft:by_id(old_draft_id) 8.16 +local new_draft = Draft:by_id(new_draft_id) 8.17 + 8.18 +local key = multirand.string(26, "123456789bcdfghjklmnpqrstvwxyz"); 8.19 + 8.20 +local old_draft_filename = encode.file_path(request.get_app_basepath(), 'tmp', "diff-" .. key .. "-old.tmp") 8.21 +local new_draft_filename = encode.file_path(request.get_app_basepath(), 'tmp', "diff-" .. key .. "-new.tmp") 8.22 + 8.23 +local old_draft_file = assert(io.open(old_draft_filename, "w")) 8.24 +old_draft_file:write(old_draft.content) 8.25 +old_draft_file:write("\n") 8.26 +old_draft_file:close() 8.27 + 8.28 +local new_draft_file = assert(io.open(new_draft_filename, "w")) 8.29 +new_draft_file:write(new_draft.content) 8.30 +new_draft_file:write("\n") 8.31 +new_draft_file:close() 8.32 + 8.33 +local output, err, status = os.pfilter(nil, "sh", "-c", "diff -U 100000 '" .. old_draft_filename .. "' '" .. new_draft_filename .. "' | grep -v ^--- | grep -v ^+++ | grep -v ^@") 8.34 + 8.35 +os.remove(old_draft_filename) 8.36 +os.remove(new_draft_filename) 8.37 + 8.38 +if not status then 8.39 + ui.field.text{ value = _"The drafts do not differ" } 8.40 +else 8.41 + slot.put('<table class="diff">') 8.42 + slot.put('<tr><th width="50%">' .. _"Old draft revision" .. '</th><th width="50%">' .. _"New draft revision" .. '</th></tr>') 8.43 + local last_state = "unchanged" 8.44 + local lines = {} 8.45 + local removed_lines = nil 8.46 + output = output .. " " 8.47 + output = output:gsub("[^\n\r]+", function(line) 8.48 + local state = "unchanged" 8.49 + local char = line:sub(1,1) 8.50 + line = line:sub(2) 8.51 + state = "unchanged" 8.52 + if char == "-" then 8.53 + state = "-" 8.54 + elseif char == "+" then 8.55 + state = "+" 8.56 + end 8.57 + if last_state == "unchanged" then 8.58 + if state == "unchanged" then 8.59 + lines[#lines+1] = line 8.60 + elseif (state == "-") or (state == "+") then 8.61 + local text = table.concat(lines, "<br />") 8.62 + slot.put("<tr><td>", text, "</td><td>", text, "</td></tr>") 8.63 + lines = { line } 8.64 + end 8.65 + elseif last_state == "-" then 8.66 + if state == "-" then 8.67 + lines[#lines+1] = line 8.68 + elseif state == "+" then 8.69 + removed_lines = lines 8.70 + lines = { line } 8.71 + elseif state == "unchanged" then 8.72 + local text = table.concat(lines,"<br />") 8.73 + slot.put('<tr><td class="removed">', text, "</td><td></td></tr>") 8.74 + lines = { line } 8.75 + end 8.76 + elseif last_state == "+" then 8.77 + if state == "+" then 8.78 + lines[#lines+1] = line 8.79 + elseif (state == "-") or (state == "unchanged") then 8.80 + if removed_lines then 8.81 + local text = table.concat(lines, "<br />") 8.82 + local removed_text = table.concat(removed_lines, "<br />") 8.83 + slot.put('<tr><td class="removed">', removed_text, '</td><td class="added">', text, "</td></tr>") 8.84 + else 8.85 + local text = table.concat(lines, "<br />") 8.86 + slot.put('<tr><td></td><td class="added">', text, "</td></tr>") 8.87 + end 8.88 + removed_lines = nil 8.89 + lines = { line } 8.90 + end 8.91 + end 8.92 + last_state = state 8.93 + end) 8.94 + slot.put("</table>") 8.95 +end 8.96 +
9.1 --- a/app/main/draft/new.lua Wed Nov 18 12:00:00 2009 +0100 9.2 +++ b/app/main/draft/new.lua Mon Nov 23 12:00:00 2009 +0100 9.3 @@ -1,24 +1,30 @@ 9.4 slot.put_into("title", _"Add new draft") 9.5 9.6 -local initiative_id = param.get("initiative_id") 9.7 +local initiative = Initiative:by_id(param.get("initiative_id")) 9.8 9.9 ui.form{ 9.10 + record = initiative.current_draft, 9.11 attr = { class = "vertical" }, 9.12 module = "draft", 9.13 action = "add", 9.14 - params = { initiative_id = initiative_id }, 9.15 + params = { initiative_id = initiative.id }, 9.16 routing = { 9.17 default = { 9.18 mode = "redirect", 9.19 module = "initiative", 9.20 view = "show", 9.21 - id = initiative_id 9.22 + id = initiative.id 9.23 } 9.24 }, 9.25 content = function() 9.26 9.27 ui.field.text{ label = _"Author", value = app.session.member.name, readonly = true } 9.28 - ui.field.text{ label = _"Content", name = "content", multiline = true } 9.29 + ui.field.text{ 9.30 + label = _"Content", 9.31 + name = "content", 9.32 + multiline = true, 9.33 + attr = { style = "height: 50ex;" } 9.34 + } 9.35 9.36 ui.submit{ text = _"Save" } 9.37 end
10.1 --- a/app/main/index/search.lua Wed Nov 18 12:00:00 2009 +0100 10.2 +++ b/app/main/index/search.lua Mon Nov 23 12:00:00 2009 +0100 10.3 @@ -5,49 +5,40 @@ 10.4 10.5 slot.put_into("title", _("Search results for: '#{search}'", { search = search_string })) 10.6 10.7 - 10.8 -local members = {} 10.9 -local issues = {} 10.10 -local initiatives = {} 10.11 - 10.12 - 10.13 if search_for == "global" or search_for == "member" then 10.14 - members = Member:search(search_string) 10.15 -end 10.16 - 10.17 -if search_for == "global" or search_for == "issue" then 10.18 - issues = Issue:search(search_string) 10.19 -end 10.20 - 10.21 -if search_for == "initiative" then 10.22 - initiatives = Initiative:search(search_string) 10.23 -end 10.24 - 10.25 - 10.26 -if #members > 0 then 10.27 + members_selector = Member:get_search_selector(search_string) 10.28 +--if #members > 0 then 10.29 ui.heading{ content = _"Members" } 10.30 execute.view{ 10.31 module = "member", 10.32 view = "_list", 10.33 - params = { members = members, highlight_string = search_string }, 10.34 + params = { members_selector = members_selector }, 10.35 } 10.36 +--end 10.37 end 10.38 10.39 -if #issues > 0 then 10.40 +if search_for == "global" or search_for == "issue" then 10.41 + issues_selector = Issue:get_search_selector(search_string) 10.42 +--if #issues > 0 then 10.43 ui.heading{ content = _"Issues" } 10.44 execute.view{ 10.45 module = "issue", 10.46 view = "_list", 10.47 - params = { issues = issues, highlight_string = search_string }, 10.48 + params = { issues_selector = issues_selector, highlight_string = search_string }, 10.49 } 10.50 +--end 10.51 end 10.52 10.53 -if #initiatives > 0 then 10.54 +if search_for == "initiative" then 10.55 + initiatives_selector = Initiative:get_search_selector(search_string) 10.56 +--if #initiatives > 0 then 10.57 ui.heading{ content = _"Initiatives" } 10.58 execute.view{ 10.59 module = "initiative", 10.60 view = "_list", 10.61 - params = { initiatives = initiatives, highlight_string = search_string }, 10.62 + params = { initiatives_selector = initiatives_selector }, 10.63 } 10.64 +--end 10.65 end 10.66 10.67 +
11.1 --- a/app/main/initiative/_list.lua Wed Nov 18 12:00:00 2009 +0100 11.2 +++ b/app/main/initiative/_list.lua Mon Nov 23 12:00:00 2009 +0100 11.3 @@ -52,21 +52,15 @@ 11.4 content = function() 11.5 local initiatives = initiatives_selector:exec() 11.6 local columns = {} 11.7 - local issue = initiatives[1] and initiatives[1].issue or {} 11.8 - if issue.accepted and issue.closed and issue.ranks_available then 11.9 - columns[#columns+1] = { 11.10 - content = function(record) 11.11 + columns[#columns+1] = { 11.12 + content = function(record) 11.13 + if record.issue.accepted and record.issue.closed and record.issue.ranks_available then 11.14 ui.field.rank{ value = record.rank } 11.15 - end 11.16 - } 11.17 - columns[#columns+1] = { 11.18 - content = function(record) 11.19 if record.negative_votes and record.positive_votes then 11.20 local max_value = record.issue.voter_count 11.21 - trace.debug(record.issue.voter_count) 11.22 ui.bargraph{ 11.23 max_value = max_value, 11.24 - width = 100, 11.25 + width = 200, 11.26 bars = { 11.27 { color = "#0a0", value = record.positive_votes }, 11.28 { color = "#aaa", value = max_value - record.negative_votes - record.positive_votes }, 11.29 @@ -74,34 +68,41 @@ 11.30 } 11.31 } 11.32 end 11.33 - end 11.34 - } 11.35 - else 11.36 - columns[#columns+1] = { 11.37 - content = function(record) 11.38 + else 11.39 local max_value = (record.issue.population or 0) 11.40 ui.bargraph{ 11.41 max_value = max_value, 11.42 - width = 100, 11.43 + width = 200, 11.44 bars = { 11.45 - { color = "#0a0", value = (record.satisfied_informed_supporter_count or 0) }, 11.46 - { color = "#8f8", value = (record.supporter_count or 0) - (record.satisfied_informed_supporter_count or 0) }, 11.47 + { color = "#0a0", value = (record.satisfied_supporter_count or 0) }, 11.48 + { color = "#8f8", value = (record.supporter_count or 0) - (record.satisfied_supporter_count or 0) }, 11.49 { color = "#ddd", value = max_value - (record.supporter_count or 0) }, 11.50 } 11.51 } 11.52 end 11.53 - } 11.54 - end 11.55 + end 11.56 + } 11.57 columns[#columns+1] = { 11.58 content = function(record) 11.59 ui.link{ 11.60 content = function() 11.61 - util.put_highlighted_string(record.shortened_name) 11.62 + local name 11.63 + if record.name_highlighted then 11.64 + name = encode.highlight(record.name_highlighted) 11.65 + else 11.66 + name = encode.html(record.name) 11.67 + end 11.68 + slot.put(name) 11.69 end, 11.70 module = "initiative", 11.71 view = "show", 11.72 id = record.id 11.73 } 11.74 + if record.issue.state == "new" then 11.75 + ui.image{ 11.76 + static = "icons/16/new.png" 11.77 + } 11.78 + end 11.79 end 11.80 } 11.81
12.1 --- a/app/main/initiative/new.lua Wed Nov 18 12:00:00 2009 +0100 12.2 +++ b/app/main/initiative/new.lua Mon Nov 23 12:00:00 2009 +0100 12.3 @@ -39,7 +39,7 @@ 12.4 } 12.5 end 12.6 ui.field.text{ label = _"Name", name = "name" } 12.7 - ui.field.text{ label = _"Draft", name = "draft", multiline = true } 12.8 + ui.field.text{ label = _"Draft", name = "draft", multiline = true, attr = { style = "height: 50ex;" } } 12.9 ui.submit{ text = _"Save" } 12.10 end 12.11 } 12.12 \ No newline at end of file
13.1 --- a/app/main/initiative/show.lua Wed Nov 18 12:00:00 2009 +0100 13.2 +++ b/app/main/initiative/show.lua Mon Nov 23 12:00:00 2009 +0100 13.3 @@ -14,6 +14,11 @@ 13.4 params = { issue_id = initiative.issue_id } 13.5 } 13.6 13.7 +execute.view{ 13.8 + module = "issue", 13.9 + view = "_show_box", 13.10 + params = { issue = initiative.issue } 13.11 +} 13.12 13.13 slot.select("path", function() 13.14 ui.link{ 13.15 @@ -24,7 +29,7 @@ 13.16 } 13.17 ui.container{ content = "::" } 13.18 ui.link{ 13.19 - content = _"Issue ##{id} (#{policy_name})":gsub("#{id}", initiative.issue.id):gsub("#{policy_name}", initiative.issue.policy.name), 13.20 + content = _"Issue ##{id}":gsub("#{id}", initiative.issue.id), 13.21 module = "issue", 13.22 view = "show", 13.23 id = initiative.issue.id 13.24 @@ -35,6 +40,18 @@ 13.25 13.26 slot.select("actions", function() 13.27 13.28 + if Initiator:by_pk(initiative.id, app.session.member.id) then 13.29 + ui.link{ 13.30 + content = function() 13.31 + ui.image{ static = "icons/16/script_add.png" } 13.32 + slot.put(_"Edit draft") 13.33 + end, 13.34 + module = "draft", 13.35 + view = "new", 13.36 + params = { initiative_id = initiative.id } 13.37 + } 13.38 + end 13.39 + 13.40 ui.twitter("http://example.com/i" .. tostring(initiative.id) .. " " .. initiative.name) 13.41 13.42 end) 13.43 @@ -88,6 +105,48 @@ 13.44 end 13.45 } 13.46 13.47 +local supporter = app.session.member:get_reference_selector("supporters") 13.48 + :add_where{ "initiative_id = ?", initiative.id } 13.49 + :optional_object_mode() 13.50 + :exec() 13.51 + 13.52 +if supporter then 13.53 + local old_draft_id = supporter.draft_id 13.54 + local new_draft_id = initiative.current_draft.id 13.55 + if old_draft_id ~= new_draft_id then 13.56 + ui.container{ 13.57 + attr = { class = "draft_updated_info" }, 13.58 + content = function() 13.59 + slot.put("The draft of this initiative has been updated!") 13.60 + slot.put(" ") 13.61 + ui.link{ 13.62 + content = _"Show diff", 13.63 + module = "draft", 13.64 + view = "diff", 13.65 + params = { 13.66 + old_draft_id = old_draft_id, 13.67 + new_draft_id = new_draft_id 13.68 + } 13.69 + } 13.70 + slot.put(" ") 13.71 + ui.link{ 13.72 + content = _"Refresh support to current draft", 13.73 + module = "initiative", 13.74 + action = "add_support", 13.75 + id = initiative.id, 13.76 + routing = { 13.77 + default = { 13.78 + mode = "redirect", 13.79 + module = "initiative", 13.80 + view = "show", 13.81 + id = initiative.id 13.82 + } 13.83 + } 13.84 + } 13.85 + end 13.86 + } 13.87 + end 13.88 +end 13.89 13.90 ui.tabs{ 13.91 { 13.92 @@ -95,41 +154,6 @@ 13.93 label = _"Current draft", 13.94 content = function() 13.95 execute.view{ module = "draft", view = "_show", params = { draft = initiative.current_draft } } 13.96 - if Initiator:by_pk(initiative.id, app.session.member.id) then 13.97 - ui.link{ 13.98 - content = function() 13.99 - ui.image{ static = "icons/16/script_add.png" } 13.100 - slot.put(_"Add new draft") 13.101 - end, 13.102 - module = "draft", 13.103 - view = "new", 13.104 - params = { initiative_id = initiative.id } 13.105 - } 13.106 - end 13.107 - end 13.108 - }, 13.109 - { 13.110 - name = "details", 13.111 - label = _"Details", 13.112 - content = function() 13.113 - ui.form{ 13.114 - attr = { class = "vertical" }, 13.115 - record = initiative, 13.116 - readonly = true, 13.117 - content = function() 13.118 - ui.field.text{ label = _"Issue policy", value = initiative.issue.policy.name } 13.119 - ui.field.text{ 13.120 - label = _"Created at", 13.121 - value = tostring(initiative.created) 13.122 - } 13.123 - ui.field.text{ 13.124 - label = _"Created at", 13.125 - value = format.timestamp(initiative.created) 13.126 - } 13.127 - ui.field.date{ label = _"Revoked at", name = "revoked" } 13.128 - ui.field.boolean{ label = _"Admitted", name = "admitted" } 13.129 - end 13.130 - } 13.131 end 13.132 }, 13.133 { 13.134 @@ -171,6 +195,30 @@ 13.135 execute.view{ module = "draft", view = "_list", params = { drafts = initiative.drafts } } 13.136 end 13.137 }, 13.138 + { 13.139 + name = "details", 13.140 + label = _"Details", 13.141 + content = function() 13.142 + ui.form{ 13.143 + attr = { class = "vertical" }, 13.144 + record = initiative, 13.145 + readonly = true, 13.146 + content = function() 13.147 + ui.field.text{ label = _"Issue policy", value = initiative.issue.policy.name } 13.148 + ui.field.text{ 13.149 + label = _"Created at", 13.150 + value = tostring(initiative.created) 13.151 + } 13.152 + ui.field.text{ 13.153 + label = _"Created at", 13.154 + value = format.timestamp(initiative.created) 13.155 + } 13.156 + ui.field.date{ label = _"Revoked at", name = "revoked" } 13.157 + ui.field.boolean{ label = _"Admitted", name = "admitted" } 13.158 + end 13.159 + } 13.160 + end 13.161 + }, 13.162 } 13.163 13.164
14.1 --- a/app/main/issue/_list.lua Wed Nov 18 12:00:00 2009 +0100 14.2 +++ b/app/main/issue/_list.lua Mon Nov 23 12:00:00 2009 +0100 14.3 @@ -1,89 +1,163 @@ 14.4 local issues_selector = param.get("issues_selector", "table") 14.5 14.6 -local paginate = ui.paginate 14.7 14.8 -local issues 14.9 - 14.10 -if not issues_selector then 14.11 - issues = param.get("issues", "table") 14.12 - paginate = function(args) 14.13 - args.content() 14.14 - end 14.15 -end 14.16 - 14.17 -ui.order{ 14.18 - name = "issue_list", 14.19 +ui.filter{ 14.20 selector = issues_selector, 14.21 - options = { 14.22 + filters = { 14.23 + { 14.24 + type = "boolean", 14.25 + name = "any", 14.26 + label = _"Any", 14.27 + selector_modifier = function() end 14.28 + }, 14.29 { 14.30 - name = "population", 14.31 - label = _"Population", 14.32 - order_by = "issue.population DESC" 14.33 + type = "boolean", 14.34 + name = "new", 14.35 + label = _"New", 14.36 + selector_modifier = function(selector, value) 14.37 + if value then 14.38 + selector:add_where("issue.accepted ISNULL AND issue.closed ISNULL") 14.39 + end 14.40 + end 14.41 + }, 14.42 + { 14.43 + type = "boolean", 14.44 + name = "accepted", 14.45 + label = _"In discussion", 14.46 + selector_modifier = function(selector, value) 14.47 + if value then 14.48 + selector:add_where("issue.accepted NOTNULL AND issue.half_frozen ISNULL AND issue.closed ISNULL") 14.49 + end 14.50 + end 14.51 }, 14.52 { 14.53 - name = "newest", 14.54 - label = _"Newest", 14.55 - order_by = "issue.created DESC" 14.56 + type = "boolean", 14.57 + name = "half_frozen", 14.58 + label = _"Frozen", 14.59 + selector_modifier = function(selector, value) 14.60 + if value then 14.61 + selector:add_where("issue.half_frozen NOTNULL AND issue.closed ISNULL") 14.62 + end 14.63 + end 14.64 + }, 14.65 + { 14.66 + type = "boolean", 14.67 + name = "frozen", 14.68 + label = _"Voting", 14.69 + selector_modifier = function(selector, value) 14.70 + if value then 14.71 + selector:add_where("issue.fully_frozen NOTNULL AND issue.closed ISNULL") 14.72 + end 14.73 + end 14.74 }, 14.75 { 14.76 - name = "oldest", 14.77 - label = _"Oldest", 14.78 - order_by = "issue.created" 14.79 - } 14.80 + type = "boolean", 14.81 + name = "finished", 14.82 + label = _"Finished", 14.83 + selector_modifier = function(selector, value) 14.84 + if value then 14.85 + selector:add_where("issue.closed NOTNULL AND ranks_available") 14.86 + end 14.87 + end 14.88 + }, 14.89 + { 14.90 + type = "boolean", 14.91 + name = "cancelled", 14.92 + label = _"Cancelled", 14.93 + selector_modifier = function(selector, value) 14.94 + if value then 14.95 + selector:add_where("issue.closed NOTNULL AND NOT ranks_available") 14.96 + end 14.97 + end 14.98 + }, 14.99 }, 14.100 content = function() 14.101 - paginate{ 14.102 + ui.order{ 14.103 + name = "issue_list", 14.104 selector = issues_selector, 14.105 + options = { 14.106 + { 14.107 + name = "population", 14.108 + label = _"Population", 14.109 + order_by = "issue.population DESC" 14.110 + }, 14.111 + { 14.112 + name = "newest", 14.113 + label = _"Newest", 14.114 + order_by = "issue.created DESC" 14.115 + }, 14.116 + { 14.117 + name = "oldest", 14.118 + label = _"Oldest", 14.119 + order_by = "issue.created" 14.120 + } 14.121 + }, 14.122 content = function() 14.123 - local highlight_string = param.get("highlight_string", "string") 14.124 - ui.list{ 14.125 - attr = { class = "issues" }, 14.126 - records = issues or issues_selector:exec(), 14.127 - columns = { 14.128 - { 14.129 - label = _"Issue", 14.130 - content = function(record) 14.131 - if not param.get("for_area_list", atom.boolean) then 14.132 - ui.field.text{ 14.133 - value = record.area.name 14.134 - } 14.135 - slot.put("<br />") 14.136 - end 14.137 - ui.link{ 14.138 - text = _"Issue ##{id}":gsub("#{id}", tostring(record.id)), 14.139 - module = "issue", 14.140 - view = "show", 14.141 - id = record.id 14.142 - } 14.143 - slot.put("<br />") 14.144 - slot.put("<br />") 14.145 - end 14.146 - }, 14.147 - { 14.148 - label = _"State", 14.149 - content = function(record) 14.150 - ui.field.issue_state{ value = record.state } 14.151 - end 14.152 - }, 14.153 - { 14.154 - label = _"Initiatives", 14.155 - content = function(record) 14.156 - execute.view{ 14.157 - module = "initiative", 14.158 - view = "_list", 14.159 - params = { 14.160 - issue = record, 14.161 - initiatives_selector = record:get_reference_selector("initiatives"), 14.162 - highlight_string = highlight_string, 14.163 - limit = 3 14.164 - } 14.165 - } 14.166 - end 14.167 - }, 14.168 - } 14.169 + ui.paginate{ 14.170 + selector = issues_selector, 14.171 + content = function() 14.172 + local highlight_string = param.get("highlight_string", "string") 14.173 + local issues = issues or issues_selector:exec() 14.174 +-- issues:load(initiatives) 14.175 + ui.list{ 14.176 + attr = { class = "issues" }, 14.177 + records = issues, 14.178 + columns = { 14.179 + { 14.180 + label = _"Issue", 14.181 + content = function(record) 14.182 + if not param.get("for_area_list", atom.boolean) then 14.183 + ui.field.text{ 14.184 + value = record.area.name 14.185 + } 14.186 + slot.put("<br />") 14.187 + end 14.188 + ui.link{ 14.189 + text = _"Issue ##{id}":gsub("#{id}", tostring(record.id)), 14.190 + module = "issue", 14.191 + view = "show", 14.192 + id = record.id 14.193 + } 14.194 + if record.state == "new" then 14.195 + ui.image{ 14.196 + static = "icons/16/new.png" 14.197 + } 14.198 + end 14.199 + slot.put("<br />") 14.200 + slot.put("<br />") 14.201 + end 14.202 + }, 14.203 + { 14.204 + label = _"State", 14.205 + content = function(record) 14.206 + ui.field.issue_state{ value = record.state } 14.207 + end 14.208 + }, 14.209 + { 14.210 + label = _"Initiatives", 14.211 + content = function(record) 14.212 + local initiatives_selector = record:get_reference_selector("initiatives") 14.213 + local highlight_string = param.get("highlight_string") 14.214 + if highlight_string then 14.215 + initiatives_selector:add_field( {'"highlight"("initiative"."name", ?)', highlight_string }, "name_highlighted") 14.216 + end 14.217 + execute.view{ 14.218 + module = "initiative", 14.219 + view = "_list", 14.220 + params = { 14.221 + issue = record, 14.222 + initiatives_selector = initiatives_selector, 14.223 + highlight_string = highlight_string, 14.224 + limit = 3 14.225 + } 14.226 + } 14.227 + end 14.228 + }, 14.229 + } 14.230 + } 14.231 + end 14.232 } 14.233 - 14.234 end 14.235 } 14.236 end 14.237 -} 14.238 \ No newline at end of file 14.239 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/app/main/issue/_show_box.lua Mon Nov 23 12:00:00 2009 +0100 15.3 @@ -0,0 +1,22 @@ 15.4 +local issue = param.get("issue", "table") 15.5 + 15.6 +slot.select("issue_info", function() 15.7 + ui.field.text{ 15.8 + label = _"State", 15.9 + value = issue.state_name 15.10 + } 15.11 + local time_left = issue.state_time_left 15.12 + if time_left then 15.13 + ui.field.text{ 15.14 + label = "Time left", 15.15 + value = time_left 15.16 + } 15.17 + end 15.18 + local next_state_names = issue.next_states_names 15.19 + if next_state_names then 15.20 + ui.field.text{ 15.21 + label = _"Next states", 15.22 + value = next_state_names 15.23 + } 15.24 + end 15.25 +end)
16.1 --- a/app/main/issue/show.lua Wed Nov 18 12:00:00 2009 +0100 16.2 +++ b/app/main/issue/show.lua Mon Nov 23 12:00:00 2009 +0100 16.3 @@ -42,12 +42,17 @@ 16.4 params = { issue_id = issue.id } 16.5 } 16.6 16.7 +execute.view{ 16.8 + module = "issue", 16.9 + view = "_show_box", 16.10 + params = { issue = issue } 16.11 +} 16.12 + 16.13 ui.tabs{ 16.14 { 16.15 name = "initiatives", 16.16 label = _"Initiatives", 16.17 - content = function() 16.18 - execute.view{ 16.19 + content = function() execute.view{ 16.20 module = "initiative", 16.21 view = "_list", 16.22 params = { 16.23 @@ -83,24 +88,48 @@ 16.24 }, 16.25 --]] 16.26 { 16.27 + name = "delegations", 16.28 + label = _"Delegations", 16.29 + content = function() 16.30 + execute.view{ 16.31 + module = "delegation", 16.32 + view = "_list", 16.33 + params = { delegations_selector = issue:get_reference_selector("delegations") } 16.34 + } 16.35 + end 16.36 + }, 16.37 + { 16.38 name = "details", 16.39 label = _"Details", 16.40 content = function() 16.41 + local policy = issue.policy 16.42 ui.form{ 16.43 record = issue, 16.44 readonly = true, 16.45 attr = { class = "vertical" }, 16.46 content = function() 16.47 - trace.debug(issue.created) 16.48 ui.field.text{ label = _"State", name = "state" } 16.49 - ui.field.timestamp{ label = _"Created at", name = "created" } 16.50 - ui.field.timestamp{ label = _"Accepted", name = "accepted" } 16.51 - ui.field.timestamp{ label = _"Half frozen", name = "half_frozen" } 16.52 - ui.field.timestamp{ label = _"Fully frozen", name = "fully_frozen" } 16.53 - ui.field.timestamp{ label = _"Closed", name = "closed" } 16.54 - ui.field.potential_issue_weight{ label = _"Potential weight", name = "potential_weight" } 16.55 - ui.field.vote_now{ label = _"Vote now", name = "vote_now" } 16.56 + ui.field.timestamp{ label = _"Created at", name = "created" } 16.57 + ui.field.text{ label = _"admission_time", value = policy.admission_time } 16.58 + ui.field.integer{ label = _"issue_quorum_num", value = policy.issue_quorum_num } 16.59 + ui.field.integer{ label = _"issue_quorum_den", value = policy.issue_quorum_den } 16.60 + ui.field.timestamp{ label = _"Accepted", name = "accepted" } 16.61 + ui.field.text{ label = _"discussion_time", value = policy.discussion_time } 16.62 + ui.field.vote_now{ label = _"Vote now", name = "vote_now" } 16.63 ui.field.vote_later{ label = _"Vote later", name = "vote_later" } 16.64 + ui.field.timestamp{ label = _"Half frozen", name = "half_frozen" } 16.65 + ui.field.text{ label = _"verification_time", value = policy.verification_time } 16.66 + ui.field.integer{ label = _"initiative_quorum_num", value = policy.initiative_quorum_num } 16.67 + ui.field.integer{ label = _"initiative_quorum_den", value = policy.initiative_quorum_den } 16.68 + ui.field.timestamp{ label = _"Fully frozen", name = "fully_frozen" } 16.69 + ui.field.text{ label = _"voting_time", value = policy.voting_time } 16.70 + ui.field.timestamp{ label = _"Closed", name = "closed" } 16.71 + end 16.72 + } 16.73 + ui.form{ 16.74 + record = issue.policy, 16.75 + readonly = true, 16.76 + content = function() 16.77 end 16.78 } 16.79 end
17.1 --- a/app/main/member/_action/update.lua Wed Nov 18 12:00:00 2009 +0100 17.2 +++ b/app/main/member/_action/update.lua Mon Nov 23 12:00:00 2009 +0100 17.3 @@ -1,4 +1,20 @@ 17.4 -param.update(app.session.member, "name") 17.5 +param.update(app.session.member, 17.6 + "name", 17.7 + "organizational_unit", 17.8 + "internal_posts", 17.9 + "realname", 17.10 + "birthday", 17.11 + "address", 17.12 + "email", 17.13 + "xmpp_address", 17.14 + "website", 17.15 + "phone", 17.16 + "mobile_phone", 17.17 + "profession", 17.18 + "external_memberships", 17.19 + "external_posts", 17.20 + "statement" 17.21 +) 17.22 17.23 app.session.member:save() 17.24
18.1 --- a/app/main/member/_action/update_avatar.lua Wed Nov 18 12:00:00 2009 +0100 18.2 +++ b/app/main/member/_action/update_avatar.lua Mon Nov 23 12:00:00 2009 +0100 18.3 @@ -1,20 +1,52 @@ 18.4 -local data = param.get("avatar") 18.5 +local member_id = app.session.member_id 18.6 + 18.7 +local member_image = MemberImage:by_pk(member_id, "avatar", false) 18.8 +local member_image_scaled = MemberImage:by_pk(member_id, "avatar", true) 18.9 18.10 if param.get("avatar_delete", atom.boolean) then 18.11 - app.session.member.avatar = nil 18.12 - app.session.member:save() 18.13 + if member_image then 18.14 + member_image:destroy() 18.15 + end 18.16 + if member_image_scaled then 18.17 + member_image_scaled:destroy() 18.18 + end 18.19 slot.put_into("notice", _"Avatar has been deleted") 18.20 return 18.21 end 18.22 18.23 -local data, err, status = os.pfilter(data, "convert", "-", "-thumbnail", "48x48", "-") 18.24 +local data = param.get("avatar") 18.25 18.26 -if status ~= 0 or data == nil then 18.27 +local data_scaled, err, status = os.pfilter(data, "convert", "-", "-thumbnail", "48x48", "-") 18.28 + 18.29 +if status ~= 0 or data_scaled == nil then 18.30 error("error while converting image") 18.31 end 18.32 18.33 +if not member_image then 18.34 + member_image = MemberImage:new() 18.35 + member_image.member_id = member_id 18.36 + member_image.image_type = "avatar" 18.37 + member_image.scaled = false 18.38 + member_image.data = "" 18.39 + member_image:save() 18.40 +end 18.41 + 18.42 +if not member_image_scaled then 18.43 + member_image_scaled = MemberImage:new() 18.44 + member_image_scaled.member_id = member_id 18.45 + member_image_scaled.image_type = "avatar" 18.46 + member_image_scaled.scaled = true 18.47 + member_image_scaled.content_type = true 18.48 + member_image_scaled.data = "" 18.49 + member_image_scaled:save() 18.50 +end 18.51 + 18.52 if data and #data > 0 then 18.53 - db:query{ 'UPDATE member SET avatar = $ WHERE id = ?', { db:quote_binary(data) }, app.session.member.id } 18.54 + db:query{ "UPDATE member_image SET data = $ WHERE member_id = ? AND image_type='avatar' AND scaled=FALSE", { db:quote_binary(data) }, app.session.member.id } 18.55 +end 18.56 + 18.57 +if data_scaled and #data_scaled > 0 then 18.58 + db:query{ "UPDATE member_image SET data = $ WHERE member_id = ? AND image_type='avatar' AND scaled=TRUE", { db:quote_binary(data_scaled) }, app.session.member.id } 18.59 end 18.60 18.61 slot.put_into("notice", _"Avatar has been updated")
19.1 --- a/app/main/member/_list.lua Wed Nov 18 12:00:00 2009 +0100 19.2 +++ b/app/main/member/_list.lua Mon Nov 23 12:00:00 2009 +0100 19.3 @@ -1,81 +1,39 @@ 19.4 local members_selector = param.get("members_selector", "table") 19.5 19.6 -ui.paginate{ 19.7 +ui.order{ 19.8 + name = "member_list", 19.9 selector = members_selector, 19.10 - content = function() 19.11 - ui.list{ 19.12 - records = members_selector:exec(), 19.13 - columns = { 19.14 - { 19.15 - content = function(record) 19.16 - ui.image{ 19.17 - attr = { style="height: 24px;" }, 19.18 - module = "member", 19.19 - view = "avatar", 19.20 - extension = "jpg", 19.21 - id = record.id 19.22 - } 19.23 - end 19.24 - }, 19.25 - { 19.26 - label = _"Login", 19.27 - content = function(record) 19.28 - ui.link{ 19.29 - text = record.login, 19.30 - module = "member", 19.31 - view = "show", 19.32 - id = record.id 19.33 - } 19.34 - end 19.35 - }, 19.36 - { 19.37 - label = _"Name", 19.38 - content = function(record) 19.39 - ui.link{ 19.40 - content = function() 19.41 - util.put_highlighted_string(record.name) 19.42 - end, 19.43 - module = "member", 19.44 - view = "show", 19.45 - id = record.id 19.46 - } 19.47 - end 19.48 - }, 19.49 - { 19.50 - label = _"Ident number", 19.51 - name = "ident_number" 19.52 - }, 19.53 - { 19.54 - label = _"Admin?", 19.55 - name = "admin" 19.56 - }, 19.57 - { 19.58 - label = "Locked?", 19.59 - content = function(record) 19.60 - ui.field.boolean{ value = record.locked } 19.61 - end 19.62 - }, 19.63 - { 19.64 - content = function(record) 19.65 - ui.link{ 19.66 - attr = { class = "action" }, 19.67 - text = _"Add to my contacts", 19.68 - module = "contact", 19.69 - action = "add_member", 19.70 - id = record.id, 19.71 - routing = { 19.72 - default = { 19.73 - mode = "redirect", 19.74 - module = request.get_module(), 19.75 - view = request.get_view(), 19.76 - id = param.get_id_cgi(), 19.77 - params = param.get_all_cgi() 19.78 - } 19.79 + options = { 19.80 + { 19.81 + name = "name", 19.82 + label = _"A-Z", 19.83 + order_by = "name" 19.84 + }, 19.85 + { 19.86 + name = "name_desc", 19.87 + label = _"Z-A", 19.88 + order_by = "name DESC" 19.89 + }, 19.90 + }, 19.91 + content = function() 19.92 + ui.paginate{ 19.93 + selector = members_selector, 19.94 + per_page = 100, 19.95 + content = function() 19.96 + ui.container{ 19.97 + attr = { class = "member_list" }, 19.98 + content = function() 19.99 + for i, member in ipairs(members_selector:exec()) do 19.100 + execute.view{ 19.101 + module = "member", 19.102 + view = "_show_thumb", 19.103 + params = { member = member } 19.104 } 19.105 - } 19.106 + end 19.107 end 19.108 } 19.109 - } 19.110 + slot.put('<br style="clear: left;" />') 19.111 + end 19.112 } 19.113 end 19.114 } 19.115 \ No newline at end of file
20.1 --- a/app/main/member/_show.lua Wed Nov 18 12:00:00 2009 +0100 20.2 +++ b/app/main/member/_show.lua Mon Nov 23 12:00:00 2009 +0100 20.3 @@ -5,11 +5,11 @@ 20.4 record = member, 20.5 readonly = true, 20.6 content = function() 20.7 - ui.field.text{ label = _"Login", name = "login" } 20.8 - ui.field.text{ label = _"Name", name = "name" } 20.9 ui.field.boolean{ label = _"Admin?", name = "admin" } 20.10 ui.field.boolean{ label = _"Locked?", name = "locked" } 20.11 - ui.field.text{ label = _"Ident number", name = "ident_number" } 20.12 + if member.ident_number then 20.13 + ui.field.text{ label = _"Ident number", name = "ident_number" } 20.14 + end 20.15 ui.submit{ text = _"Save" } 20.16 end 20.17 } 20.18 @@ -55,7 +55,7 @@ 20.19 execute.view{ 20.20 module = "delegation", 20.21 view = "_list", 20.22 - params = { selector = member:get_reference_selector("incoming_delegations") } 20.23 + params = { delegations_selector = member:get_reference_selector("incoming_delegations"), incoming = true } 20.24 } 20.25 end 20.26 }, 20.27 @@ -66,7 +66,7 @@ 20.28 execute.view{ 20.29 module = "delegation", 20.30 view = "_list", 20.31 - params = { selector = member:get_reference_selector("outgoing_delegations") } 20.32 + params = { delegations_selector = member:get_reference_selector("outgoing_delegations"), outgoing = true } 20.33 } 20.34 end 20.35 },
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/app/main/member/_show_thumb.lua Mon Nov 23 12:00:00 2009 +0100 21.3 @@ -0,0 +1,25 @@ 21.4 +local member = param.get("member", "table") 21.5 + 21.6 +local name 21.7 +if member.name_highlighted then 21.8 + name = encode.highlight(member.name_highlighted) 21.9 +else 21.10 + name = encode.html(member.name) 21.11 +end 21.12 + 21.13 +ui.link{ 21.14 + attr = { class = "member_thumb" }, 21.15 + module = "member", 21.16 + view = "show", 21.17 + id = member.id, 21.18 + content = function() 21.19 + ui.image{ 21.20 + attr = { width = 48, height = 48 }, 21.21 + module = "member", 21.22 + view = "avatar", 21.23 + id = member.id, 21.24 + extension = "jpg" 21.25 + } 21.26 + slot.put(name) 21.27 + end 21.28 +} 21.29 \ No newline at end of file
22.1 --- a/app/main/member/avatar.lua Wed Nov 18 12:00:00 2009 +0100 22.2 +++ b/app/main/member/avatar.lua Mon Nov 23 12:00:00 2009 +0100 22.3 @@ -1,14 +1,14 @@ 22.4 -local record = Member:by_id(param.get_id()) 22.5 +local record = MemberImage:by_pk(param.get_id(), "avatar", true) 22.6 22.7 -if false and (not record or not record.avatar) then 22.8 - print('Location: ' .. encode.url{ static = 'no_image.png' } .. '\n\n') 22.9 +if record == nil then 22.10 + print('Location: ' .. encode.url{ static = 'avatar.jpg' } .. '\n\n') 22.11 exit() 22.12 end 22.13 22.14 -print('Content-type: image/jpg\n') 22.15 +print('Content-type: ' .. record.content_type .. '\n') 22.16 22.17 if record then 22.18 - io.stdout:write(record.avatar) 22.19 + io.stdout:write(record.data) 22.20 else 22.21 end 22.22
23.1 --- a/app/main/member/edit.lua Wed Nov 18 12:00:00 2009 +0100 23.2 +++ b/app/main/member/edit.lua Mon Nov 23 12:00:00 2009 +0100 23.3 @@ -25,6 +25,20 @@ 23.4 }, 23.5 content = function() 23.6 ui.field.text{ label = _"Name", name = "name" } 23.7 + ui.field.text{ label = _"Organizational unit", name = "organizational_unit" } 23.8 + ui.field.text{ label = _"Internal posts", name = "internal_posts" } 23.9 + ui.field.text{ label = _"Real name", name = "realname" } 23.10 + ui.field.text{ label = _"Birthday", name = "birthday" } 23.11 + ui.field.text{ label = _"Address", name = "address", multiline = true } 23.12 + ui.field.text{ label = _"email", name = "email" } 23.13 + ui.field.text{ label = _"xmpp", name = "xmpp_address" } 23.14 + ui.field.text{ label = _"Website", name = "website" } 23.15 + ui.field.text{ label = _"Phone", name = "phone" } 23.16 + ui.field.text{ label = _"Mobile phone", name = "mobile_phone" } 23.17 + ui.field.text{ label = _"Profession", name = "profession" } 23.18 + ui.field.text{ label = _"External memberships", name = "external_memberships", multiline = true } 23.19 + ui.field.text{ label = _"External posts", name = "external_posts", multiline = true } 23.20 + ui.field.text{ label = _"Statement", name = "statement", multiline = true } 23.21 ui.submit{ value = _"Save" } 23.22 end 23.23 } 23.24 \ No newline at end of file
24.1 --- a/app/main/membership/_show_box.lua Wed Nov 18 12:00:00 2009 +0100 24.2 +++ b/app/main/membership/_show_box.lua Mon Nov 23 12:00:00 2009 +0100 24.3 @@ -6,7 +6,7 @@ 24.4 ui.container{ 24.5 attr = { 24.6 class = "head", 24.7 - onclick = "document.getElementById('interest_content').style.display = 'block';" 24.8 + onclick = "document.getElementById('membership_content').style.display = 'block';" 24.9 }, 24.10 content = function() 24.11 if membership then 24.12 @@ -18,8 +18,16 @@ 24.13 } 24.14 24.15 ui.container{ 24.16 - attr = { class = "content", id = "interest_content" }, 24.17 + attr = { class = "content", id = "membership_content" }, 24.18 content = function() 24.19 + ui.container{ 24.20 + attr = { 24.21 + class = "close", 24.22 + style = "cursor: pointer;", 24.23 + onclick = "document.getElementById('membership_content').style.display = 'none';" 24.24 + }, 24.25 + content = _"X" 24.26 + } 24.27 if membership then 24.28 ui.link{ 24.29 content = _"Remove my membership", 24.30 @@ -56,14 +64,6 @@ 24.31 routing = { default = { mode = "redirect", module = "area", view = "show", id = area.id } } 24.32 } 24.33 end 24.34 - ui.container{ 24.35 - attr = { 24.36 - class = "head", 24.37 - style = "cursor: pointer;", 24.38 - onclick = "document.getElementById('interest_content').style.display = 'none';" 24.39 - }, 24.40 - content = _"Click here to close." 24.41 - } 24.42 end 24.43 } 24.44 end)
25.1 --- a/app/main/suggestion/_list.lua Wed Nov 18 12:00:00 2009 +0100 25.2 +++ b/app/main/suggestion/_list.lua Mon Nov 23 12:00:00 2009 +0100 25.3 @@ -4,6 +4,7 @@ 25.4 selector = suggestions_selector, 25.5 content = function() 25.6 ui.list{ 25.7 + attr = { style = "table-layout: fixed;" }, 25.8 records = suggestions_selector:exec(), 25.9 columns = { 25.10 { 25.11 @@ -24,7 +25,7 @@ 25.12 local max_value = record.initiative.issue.population 25.13 ui.bargraph{ 25.14 max_value = max_value, 25.15 - width = 50, 25.16 + width = 100, 25.17 bars = { 25.18 { color = "#ddd", value = max_value - record.minus2_unfulfilled_count - record.minus1_unfulfilled_count - record.minus2_fulfilled_count - record.minus1_fulfilled_count }, 25.19 { color = "#f88", value = record.minus1_unfulfilled_count + record.minus1_fulfilled_count }, 25.20 @@ -102,13 +103,14 @@ 25.21 end 25.22 }, 25.23 { 25.24 - label = _"Not fullfilled", 25.25 + label = _"Suggestion currently not implemented", 25.26 + label_attr = { style = "width: 101px;" }, 25.27 content = function(record) 25.28 if record.minus2_unfulfilled_count then 25.29 local max_value = record.initiative.issue.population 25.30 ui.bargraph{ 25.31 max_value = max_value, 25.32 - width = 50, 25.33 + width = 100, 25.34 bars = { 25.35 { color = "#ddd", value = max_value - record.minus2_unfulfilled_count - record.minus1_unfulfilled_count }, 25.36 { color = "#f88", value = record.minus1_unfulfilled_count }, 25.37 @@ -122,13 +124,14 @@ 25.38 end 25.39 }, 25.40 { 25.41 - label = _"Fullfilled", 25.42 + label = _"Suggestion currently implemented", 25.43 + label_attr = { style = "width: 101px;" }, 25.44 content = function(record) 25.45 if record.minus2_fulfilled_count then 25.46 local max_value = record.initiative.issue.population 25.47 ui.bargraph{ 25.48 max_value = max_value, 25.49 - width = 50, 25.50 + width = 100, 25.51 bars = { 25.52 { color = "#ddd", value = max_value - record.minus2_fulfilled_count - record.minus1_fulfilled_count }, 25.53 { color = "#f88", value = record.minus1_fulfilled_count }, 25.54 @@ -153,7 +156,7 @@ 25.55 ui.image{ static = "icons/16/cross.png" } 25.56 ui.link{ 25.57 attr = { class = "action" }, 25.58 - text = _"set fulfilled", 25.59 + text = _"set implented", 25.60 module = "opinion", 25.61 action = "update", 25.62 routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } }, 25.63 @@ -166,7 +169,7 @@ 25.64 ui.image{ static = "icons/16/tick.png" } 25.65 ui.link{ 25.66 attr = { class = "action" }, 25.67 - text = _"remove fulfilled", 25.68 + text = _"remove implemented", 25.69 module = "opinion", 25.70 action = "update", 25.71 routing = { default = { mode = "redirect", module = request.get_module(), view = request.get_view(), id = param.get_id_cgi(), params = param.get_all_cgi() } },
26.1 --- a/app/main/supporter/_show_box.lua Wed Nov 18 12:00:00 2009 +0100 26.2 +++ b/app/main/supporter/_show_box.lua Mon Nov 23 12:00:00 2009 +0100 26.3 @@ -27,6 +27,14 @@ 26.4 ui.container{ 26.5 attr = { class = "content", id = "support_content" }, 26.6 content = function() 26.7 + ui.container{ 26.8 + attr = { 26.9 + class = "close", 26.10 + style = "cursor: pointer;", 26.11 + onclick = "document.getElementById('support_content').style.display = 'none';" 26.12 + }, 26.13 + content = _"X" 26.14 + } 26.15 if supported then 26.16 ui.link{ 26.17 content = function()
27.1 --- a/config/default.lua Wed Nov 18 12:00:00 2009 +0100 27.2 +++ b/config/default.lua Mon Nov 23 12:00:00 2009 +0100 27.3 @@ -1,10 +1,14 @@ 27.4 config.app_name = "LiquidFeedback" 27.5 -config.app_version = "alpha2" 27.6 +config.app_version = "alpha3" 27.7 27.8 config.app_title = config.app_name .. " (" .. request.get_config_name() .. " environment)" 27.9 27.10 config.app_service_provider = "Snake Oil<br/>10000 Berlin<br/>Germany" 27.11 27.12 +config.member_image_convert = { 27.13 + avatar = { "convert", "-", "-thumbnail", "48x48", "-" } 27.14 +} 27.15 + 27.16 -- uncomment the following two lines to use C implementations of chosen 27.17 -- functions and to disable garbage collection during the request, to 27.18 -- increase speed: 27.19 @@ -37,7 +41,7 @@ 27.20 27.21 27.22 27.23 - 27.24 +-- TODO abstraction 27.25 -- get record by id 27.26 function mondelefant.class_prototype:by_id(id) 27.27 local selector = self:new_selector() 27.28 @@ -46,3 +50,4 @@ 27.29 return selector:exec() 27.30 end 27.31 27.32 +
28.1 --- a/config/development.lua Wed Nov 18 12:00:00 2009 +0100 28.2 +++ b/config/development.lua Mon Nov 23 12:00:00 2009 +0100 28.3 @@ -1,2 +1,3 @@ 28.4 execute.config("default") 28.5 28.6 +config.wiki_parser_executeable = "/opt/rocketwiki/rocketwiki"
29.1 --- a/config/testing.lua Wed Nov 18 12:00:00 2009 +0100 29.2 +++ b/config/testing.lua Mon Nov 23 12:00:00 2009 +0100 29.3 @@ -1,6 +1,3 @@ 29.4 execute.config("default") 29.5 29.6 - 29.7 - 29.8 - 29.9 - 29.10 +config.wiki_parser_executeable = "/opt/liquid_feedback_testing/rocketwiki/rocketwiki"
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/env/encode/highlight.lua Mon Nov 23 12:00:00 2009 +0100 30.3 @@ -0,0 +1,10 @@ 30.4 +function encode.highlight(text) 30.5 + local text = encode.html(text) 30.6 + text = text:gsub("\027", "") 30.7 + text = text:gsub("\\\\", "\027b") 30.8 + text = text:gsub("\\%*", "\027a") 30.9 + text = text:gsub("%*([^%*]*)%*", '<span class="highlighted">%1</span>') 30.10 + text = text:gsub("\027a", "*") 30.11 + text = text:gsub("\027b", "\\") 30.12 + return text 30.13 +end 30.14 \ No newline at end of file
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/env/format/wiki_text.lua Mon Nov 23 12:00:00 2009 +0100 31.3 @@ -0,0 +1,11 @@ 31.4 +function format.wiki_text(wiki_text) 31.5 + local html, errmsg, exitcode = assert( 31.6 + os.pfilter(wiki_text, config.wiki_parser_executeable) 31.7 + ) 31.8 + if exitcode > 0 then 31.9 + error("Wiki parser process returned with error code " .. tostring(exitcode)) 31.10 + elseif exitcode < 0 then 31.11 + error("Wiki parser process was terminated by signal " .. tostring(-exitcode)) 31.12 + end 31.13 + return html 31.14 +end
32.1 --- a/env/ui/bargraph.lua Wed Nov 18 12:00:00 2009 +0100 32.2 +++ b/env/ui/bargraph.lua Mon Nov 23 12:00:00 2009 +0100 32.3 @@ -5,14 +5,16 @@ 32.4 }, 32.5 content = function() 32.6 for i, bar in ipairs(args.bars) do 32.7 - local value = bar.value * args.width / args.max_value / 2 32.8 - ui.container{ 32.9 - attr = { 32.10 - style = "width: " .. tostring(value) .. "px; background-color: " .. bar.color .. ";", 32.11 - title = tostring(bar.value) 32.12 - }, 32.13 - content = function() slot.put(" ") end 32.14 - } 32.15 + if bar.value > 0 then 32.16 + local value = bar.value * args.width / args.max_value / 2 32.17 + ui.container{ 32.18 + attr = { 32.19 + style = "width: " .. tostring(value) .. "px; background-color: " .. bar.color .. ";", 32.20 + title = tostring(bar.value) 32.21 + }, 32.22 + content = function() slot.put(" ") end 32.23 + } 32.24 + end 32.25 end 32.26 end 32.27 }
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/env/ui/filter.lua Mon Nov 23 12:00:00 2009 +0100 33.3 @@ -0,0 +1,40 @@ 33.4 +function ui.filter(args) 33.5 + local name = args.name or "filter" 33.6 + local current_filter = atom.string:load(cgi.params[name]) or args.filters[1].name 33.7 + local id = param.get_id_cgi() 33.8 + local params = param.get_all_cgi() 33.9 + ui.container{ 33.10 + attr = { class = "ui_filter" }, 33.11 + content = function() 33.12 + ui.container{ 33.13 + attr = { class = "ui_filter_head" }, 33.14 + content = function() 33.15 + slot.put(_"Filter") 33.16 + slot.put(": ") 33.17 + for i, filter in ipairs(args.filters) do 33.18 + params[name] = filter.name 33.19 + local attr = {} 33.20 + if current_filter == filter.name then 33.21 + attr.class = "active" 33.22 + filter.selector_modifier(args.selector, true) 33.23 + end 33.24 + ui.link{ 33.25 + attr = attr, 33.26 + module = request.get_module(), 33.27 + view = request.get_view(), 33.28 + id = id, 33.29 + params = params, 33.30 + content = filter.label 33.31 + } 33.32 + end 33.33 + end 33.34 + } 33.35 + ui.container{ 33.36 + attr = { class = "ui_filter_content" }, 33.37 + content = function() 33.38 + args.content() 33.39 + end 33.40 + } 33.41 + end 33.42 + } 33.43 +end
34.1 --- a/locale/translations.de.lua Wed Nov 18 12:00:00 2009 +0100 34.2 +++ b/locale/translations.de.lua Mon Nov 23 12:00:00 2009 +0100 34.3 @@ -11,25 +11,33 @@ 34.4 ["Add new initiative to issue"] = "Neue Initiative zum Thema hinzufügen"; 34.5 ["Add new suggestion"] = "Neue Anregung hinzufügen"; 34.6 ["Add to my contacts"] = "Zu meinen Kontakten hinzufügen"; 34.7 +["Address"] = "Anschrift"; 34.8 ["Admin"] = "Admin"; 34.9 ["Admin menu"] = "Admin Menü"; 34.10 ["Admin?"] = "Admin?"; 34.11 ["Admitted"] = "zugelassen"; 34.12 +["Any"] = "Alle"; 34.13 ["Area"] = "Themenbereich"; 34.14 ["Area '#{name}'"] = "Themenbereich '#{name}'"; 34.15 +["Area delegation"] = "Area-Delegation"; 34.16 ["Area list"] = "Liste der Themenbereiche"; 34.17 ["Area successfully updated"] = "Themenbereich erfolgreich aktualisiert"; 34.18 ["Areas"] = "Themenbereiche"; 34.19 ["Author"] = "Autor"; 34.20 ["Autoreject is off."] = "Auto-Ablehnen ist aus"; 34.21 ["Autoreject is on."] = "Auto-Ablehnen ist an"; 34.22 -["Cancel"] = false; 34.23 +["Avatar"] = false; 34.24 +["Avatar has been deleted"] = "Avatar wurde gelöscht"; 34.25 +["Avatar has been updated"] = "Avatar wurde aktualisiert"; 34.26 +["Birthday"] = "Geburtstag"; 34.27 +["Cancel"] = "Abbrechen"; 34.28 ["Cancelled"] = "Abgebrochen"; 34.29 ["Change password"] = "Kennwort ändern"; 34.30 ["Click here to close."] = "Zum Schließen hier klicken"; 34.31 ["Close"] = "Schließen"; 34.32 ["Closed"] = "geschlossen"; 34.33 ["Commit suggestion"] = "Anregung speichern"; 34.34 +["Compare"] = "Vergleichen"; 34.35 ["Contacts"] = "Kontakte"; 34.36 ["Content"] = "Inhalt"; 34.37 ["Create new area"] = "Neuen Themenbereich anlegen"; 34.38 @@ -38,39 +46,45 @@ 34.39 ["Current draft"] = "Aktueller Entwurf"; 34.40 ["Degree"] = "Grad"; 34.41 ["Delegate"] = "Delegieren"; 34.42 +["Delegations"] = "Delegationen"; 34.43 ["Description"] = "Beschreibung"; 34.44 ["Details"] = "Details"; 34.45 +["Diff"] = false; 34.46 ["Direct member count"] = "Anzahl Direktmitglieder"; 34.47 ["Direct supporter [change]"] = "Direkte Unterstützung [ändern]"; 34.48 ["Draft"] = "Entwurf"; 34.49 ["Edit"] = "Bearbeiten"; 34.50 +["Edit draft"] = "Entwurf bearbeiten"; 34.51 ["Edit my page"] = "Meine Seite bearbeiten"; 34.52 ["Error while updating member, database reported:<br /><br /> (#{errormessage})"] = "Fehler beim aktualisieren des Mitglieds, die Datenbank berichtet folgenden Fehler:<br /><br /> (#{errormessage})"; 34.53 +["External memberships"] = "Externe Mitgliedschaften"; 34.54 +["External posts"] = "Externe Ämter"; 34.55 +["Filter"] = false; 34.56 ["Finished"] = "Abgeschlossen"; 34.57 ["Frozen"] = "Eingefroren"; 34.58 ["Fulfilled"] = "Erfüllt"; 34.59 -["Fullfilled"] = "Erfüllt"; 34.60 -["Fully frozen"] = false; 34.61 +["Fully frozen"] = "Ganz eingefroren"; 34.62 ["Global delegation"] = "Globale Delegation"; 34.63 -["Half frozen"] = false; 34.64 +["Half frozen"] = "Halb eingefroren"; 34.65 ["Hide"] = "Verstecken"; 34.66 ["Home"] = "Startseite"; 34.67 ["Id"] = "Id"; 34.68 ["Ident number"] = "Ident-Nummer"; 34.69 ["In discussion"] = "In Diskussion"; 34.70 ["Incoming delegations"] = "Eingehende Delegationen"; 34.71 -["Initiative"] = "Initiative"; 34.72 ["Initiative successfully created"] = "Initiative erfolgreich erzeugt"; 34.73 ["Initiative: '#{name}'"] = "Initiative: '#{name}'"; 34.74 ["Initiatives"] = "Initiativen"; 34.75 ["Initiators"] = "Initiatoren"; 34.76 -["Interest not existant"] = false; 34.77 +["Interest not existant"] = "Interesse existiert nicht"; 34.78 ["Interest removed"] = "Interesse entfernt"; 34.79 ["Interest updated"] = "Interesse aktualisiert"; 34.80 +["Internal posts"] = "Interne Ämter"; 34.81 ["Invalid username or password!"] = "Ungültiger Benutzername oder Kennwort"; 34.82 ["Issue"] = "Thema"; 34.83 ["Issue ##{id}"] = "Issue ##{id}"; 34.84 ["Issue ##{id} (#{policy_name})"] = "Thema ##{id} (#{policy_name})"; 34.85 +["Issue delegation"] = "Issue-Delegation"; 34.86 ["Issue policy"] = "Regelwerk für Thema"; 34.87 ["Issues"] = "Themen"; 34.88 ["License"] = "Lizenz"; 34.89 @@ -80,7 +94,6 @@ 34.90 ["Login successful!"] = "Anmeldung erfolgreich"; 34.91 ["Logout"] = "Abmelden"; 34.92 ["Logout successful"] = "Abmeldung erfolgreich"; 34.93 -["Me"] = "Ich"; 34.94 ["Member '#{member}'"] = "Mitglied '#{member}'"; 34.95 ["Member has been removed from your contacts"] = "Mitglied wurde aus Deinen Kontakten entfernt"; 34.96 ["Member has been saved as private contact"] = "Mitglied wurde als privater Kontakt gespeichert"; 34.97 @@ -93,33 +106,40 @@ 34.98 ["Member successfully updated"] = "Mitglied erfolgreich aktualisert"; 34.99 ["Member: '#{login}' (#{name})"] = "Mitlied: '#{login}' (#{name})"; 34.100 ["Members"] = "Mitglieder"; 34.101 -["Membership not existant"] = false; 34.102 +["Membership not existant"] = "Mitgliedschaft exisitert nicht"; 34.103 ["Membership removed"] = "Mitgliedschaft entfernt"; 34.104 ["Membership updated"] = "Mitgliedschaft aktualisiert"; 34.105 +["Mobile phone"] = "Mobiltelefon"; 34.106 ["Name"] = "Name"; 34.107 ["New"] = "Neu"; 34.108 ["New draft has been added to initiative"] = "Neuer Entwurf wurde der Initiative hinzugefügt"; 34.109 +["New draft revision"] = "Neue Revision des Entwurfs"; 34.110 ["New password"] = "Neues Kennwort"; 34.111 ["New passwords does not match."] = "Du hast nicht zweimal das gleiche Kennwort eingegeben"; 34.112 ["New passwords is too short."] = "Das neue Kennwort ist zu kurz"; 34.113 ["Newest"] = "Neueste"; 34.114 +["Next states"] = "Nächste Statuse"; 34.115 ["No supporter [change]"] = "Keine Unterstützung (ändern)"; 34.116 -["Not fullfilled"] = "Nicht erfüllt"; 34.117 ["OK"] = "OK"; 34.118 +["Old draft revision"] = "Alte Revision des Entwurfs"; 34.119 ["Old drafts"] = "Alte Entwürfe"; 34.120 ["Old password"] = "Altes Kennwort"; 34.121 ["Old password is wrong"] = "Das alte Kennwort ist falsch"; 34.122 ["Oldest"] = "Älteste"; 34.123 ["Order by"] = "Sortieren nach"; 34.124 +["Organizational unit"] = "Organisationseinheit"; 34.125 ["Outgoing delegations"] = "Ausgehende Delegationen"; 34.126 ["Password"] = "Kennwort"; 34.127 +["Phone"] = "Telefon"; 34.128 ["Policy"] = "Regelwerk"; 34.129 ["Population"] = "Grundgesamtheit"; 34.130 -["Potential weight"] = "Potentielles Gewicht"; 34.131 +["Profession"] = "Beruf"; 34.132 ["Publish"] = "Veröffentlichen"; 34.133 ["Published"] = "veröffentlicht"; 34.134 ["Published contacts"] = "Veröffentlichte Kontakte"; 34.135 ["Rank"] = "Rang"; 34.136 +["Real name"] = "Realname"; 34.137 +["Refresh support to current draft"] = "Unterstützung auf aktuellen Entwurf aktualisieren"; 34.138 ["Register new member"] = "Neues Mitglied registrieren"; 34.139 ["Remove"] = "Entfernen"; 34.140 ["Remove autoreject"] = "Auto-Ablehnen abschalten"; 34.141 @@ -142,9 +162,13 @@ 34.142 ["Show active members"] = "Zeige aktive Mitglieder"; 34.143 ["Show areas in use"] = "Zeige verwendete Themenbereiche"; 34.144 ["Show areas not in use"] = "Zeige nicht verwendente Themenbereiche"; 34.145 +["Show diff"] = "Änderungen anzeigen"; 34.146 ["Show locked members"] = "Zeige gesperrte Mitglieder"; 34.147 ["Software"] = false; 34.148 ["State"] = "Zustand"; 34.149 +["Statement"] = false; 34.150 +["Suggestion currently implemented"] = "Anregung zur Zeit umgesetzt"; 34.151 +["Suggestion currently not implemented"] = "Anregung zur Zeit nicht umgesetzt"; 34.152 ["Suggestion for initiative: '#{name}'"] = "Anregung für Initiative '#{name}'"; 34.153 ["Suggestions"] = "Anregungen"; 34.154 ["Support"] = "Unterstützung"; 34.155 @@ -152,8 +176,8 @@ 34.156 ["Support this initiative"] = "Diese Initiative unterstützen"; 34.157 ["Supporter"] = "Unterstützer"; 34.158 ["That's me!"] = "Das bin ich"; 34.159 +["The drafts do not differ"] = "Die Entwürfe unterscheiden sich nicht"; 34.160 ["Trustee"] = "Bevollmächtigter"; 34.161 -["Truster"] = "Delegierender"; 34.162 ["Unknown author"] = "Unbekannter Autor"; 34.163 ["Upload avatar"] = "Avatar hochladen"; 34.164 ["Username"] = "Benutzername"; 34.165 @@ -162,6 +186,8 @@ 34.166 ["Vote now"] = "Jetzt abstimmen"; 34.167 ["Voting"] = "Abstimmung"; 34.168 ["Voting requests"] = "Abstimmanträge"; 34.169 +["Website"] = "Webseite"; 34.170 +["X"] = false; 34.171 ["You are already not supporting this initiative"] = "Diese Initiative hat bereits keine Unterstützung von Dir"; 34.172 ["You are already supporting the latest draft"] = "Du unterstützt bereits den neuesten Entwurf"; 34.173 ["You are interested. [more]"] = "Du bist interessiert. [mehr]"; 34.174 @@ -176,6 +202,7 @@ 34.175 ["Your global delegation has been deleted."] = "Deine globale Delegation wurde gelöscht"; 34.176 ["Your global delegation has been updated."] = "Deine globale Delegation würde geändert"; 34.177 ["Your opinion has been updated"] = "Deine Meinung wurde aktualisiert"; 34.178 +["Your page has been updated"] = "Deine Seite wurde aktualisiert"; 34.179 ["Your password has been updated successfully"] = "Das Kennwort wurde erfolgreich geändert"; 34.180 ["Your suggestion has been added"] = "Deine Anregung wurde hinzufügt"; 34.181 ["Your support has been added to this initiative"] = "Deine Unterstützung wurde der Initiative hinzugefügt"; 34.182 @@ -183,11 +210,22 @@ 34.183 ["Your support has been updated to the latest draft"] = "Deine Unterstützung wurde auf den neuesten Entwurf aktualisiert"; 34.184 ["Your vote is delegated. [more]"] = "Deine Stimme ist delegiert. [mehr]"; 34.185 ["Z-A"] = false; 34.186 +["admission_time"] = false; 34.187 +["delete<br /><br />"] = false; 34.188 +["discussion_time"] = false; 34.189 +["email"] = false; 34.190 +["initiative_quorum_den"] = false; 34.191 +["initiative_quorum_num"] = false; 34.192 +["issue_quorum_den"] = false; 34.193 +["issue_quorum_num"] = false; 34.194 ["must"] = "muss"; 34.195 ["must not"] = "darf nicht"; 34.196 ["neutral"] = "neutral"; 34.197 -["remove fulfilled"] = "erfüllt entfernen"; 34.198 -["set fulfilled"] = "erfüllt setzten"; 34.199 +["remove implemented"] = "entferne umgesetzt"; 34.200 +["set implented"] = "setze umgesetzt"; 34.201 ["should"] = "soll"; 34.202 ["should not"] = "soll nicht"; 34.203 +["verification_time"] = false; 34.204 +["voting_time"] = false; 34.205 +["xmpp"] = false; 34.206 }
35.1 --- a/model/area.lua Wed Nov 18 12:00:00 2009 +0100 35.2 +++ b/model/area.lua Mon Nov 23 12:00:00 2009 +0100 35.3 @@ -20,6 +20,15 @@ 35.4 } 35.5 35.6 Area:add_reference{ 35.7 + mode = '1m', 35.8 + to = "Delegation", 35.9 + this_key = 'id', 35.10 + that_key = 'area_id', 35.11 + ref = 'delegations', 35.12 + back_ref = 'area' 35.13 +} 35.14 + 35.15 +Area:add_reference{ 35.16 mode = 'mm', 35.17 to = "Member", 35.18 this_key = 'id',
36.1 --- a/model/initiative.lua Wed Nov 18 12:00:00 2009 +0100 36.2 +++ b/model/initiative.lua Mon Nov 23 12:00:00 2009 +0100 36.3 @@ -91,12 +91,18 @@ 36.4 ref = 'supporting_members' 36.5 } 36.6 36.7 -function Initiative:search(search_string) 36.8 +function Initiative:get_search_selector(search_string) 36.9 return self:new_selector() 36.10 - :add_where{ '"initiative"."name" ILIKE ?', "%" .. search_string:gsub("%%", "") .. "%" } 36.11 - :exec() 36.12 + :add_field( {'"highlight"("initiative"."name", ?)', search_string }, "name_highlighted") 36.13 + :add_where{ '"initiative"."text_search_data" @@ "text_search_query"(?)', search_string } 36.14 end 36.15 36.16 +function Member:get_search_selector(search_string) 36.17 + return self:new_selector() 36.18 + :add_where("active") 36.19 +end 36.20 + 36.21 + 36.22 function Initiative.object_get:current_draft() 36.23 return Draft:new_selector() 36.24 :add_where{ '"initiative_id" = ?', self.id }
37.1 --- a/model/issue.lua Wed Nov 18 12:00:00 2009 +0100 37.2 +++ b/model/issue.lua Mon Nov 23 12:00:00 2009 +0100 37.3 @@ -67,6 +67,15 @@ 37.4 } 37.5 37.6 Issue:add_reference{ 37.7 + mode = '1m', 37.8 + to = "Delegation", 37.9 + this_key = 'id', 37.10 + that_key = 'issue_id', 37.11 + ref = 'delegations', 37.12 + back_ref = 'issue' 37.13 +} 37.14 + 37.15 +Issue:add_reference{ 37.16 mode = 'mm', 37.17 to = "Member", 37.18 this_key = 'id', 37.19 @@ -78,32 +87,95 @@ 37.20 } 37.21 37.22 function Issue:get_state_name_for_state(value) 37.23 - local state_name_table = {} 37.24 + local state_name_table = { 37.25 + new = _"New", 37.26 + accepted = _"Accepted", 37.27 + frozen = _"Frozen", 37.28 + voting = _"Voting", 37.29 + finished = _"Finished", 37.30 + cancelled = _"Cancelled" 37.31 + } 37.32 return state_name_table[value] or value 37.33 end 37.34 37.35 -function Issue:search(search_string) 37.36 +function Issue:get_search_selector(search_string) 37.37 return self:new_selector() 37.38 :join('"initiative"', nil, '"initiative"."issue_id" = "issue"."id"') 37.39 - :add_where{ '"initiative"."name" ILIKE ?', "%" .. search_string:gsub("%%", "") .. "%" } 37.40 + :add_where{ '"initiative"."text_search_data" @@ "text_search_query"(?)', search_string } 37.41 :set_distinct() 37.42 - :exec() 37.43 end 37.44 37.45 function Issue.object_get:state() 37.46 if self.accepted then 37.47 - if self.frozen then 37.48 + if self.fully_frozen then 37.49 + return "voting" 37.50 + elseif self.half_frozen then 37.51 return "frozen" 37.52 elseif self.closed then 37.53 - return "closed" 37.54 + if self.ranks_available then 37.55 + return "finished" 37.56 + else 37.57 + return "cancelled" 37.58 + end 37.59 else 37.60 return "accepted" 37.61 end 37.62 else 37.63 if self.closed then 37.64 - return "closed" 37.65 + return "cancelled" 37.66 else 37.67 return "new" 37.68 end 37.69 end 37.70 +end 37.71 + 37.72 +function Issue.object_get:state_name() 37.73 + return Issue:get_state_name_for_state(self.state) 37.74 +end 37.75 + 37.76 +function Issue.object_get:state_time_left() 37.77 + local state = self.state 37.78 + local last_event_time 37.79 + local duration 37.80 + if state == "new" then 37.81 + last_event_time = self.created 37.82 + duration = self.policy.admission_time 37.83 + elseif state == "accepted" then 37.84 + last_event_time = self.accepted 37.85 + duration = self.policy.discussion_time 37.86 + elseif state == "frozen" then 37.87 + last_event_time = self.half_frozen 37.88 + duration = self.policy.verification_time 37.89 + elseif state == "voting" then 37.90 + last_event_time = self.fully_frozen 37.91 + duration = self.policy.voting_time 37.92 + end 37.93 + return db:query{ "SELECT ?::timestamp + ?::interval - now() as time_left", last_event_time, duration }[1].time_left 37.94 +end 37.95 + 37.96 +function Issue.object_get:next_states() 37.97 + local state = self.state 37.98 + local next_states 37.99 + if state == "new" then 37.100 + next_states = { "accepted", "cancelled" } 37.101 + elseif state == "accepted" then 37.102 + next_states = { "frozen" } 37.103 + elseif state == "frozen" then 37.104 + next_states = { "voting" } 37.105 + elseif state == "voting" then 37.106 + next_states = { "finished" } 37.107 + end 37.108 + return next_states 37.109 +end 37.110 + 37.111 +function Issue.object_get:next_states_names() 37.112 + local next_states = self.next_states 37.113 + if not next_states then 37.114 + return 37.115 + end 37.116 + local state_names = {} 37.117 + for i, state in ipairs(self.next_states) do 37.118 + state_names[#state_names+1] = Issue:get_state_name_for_state(state) 37.119 + end 37.120 + return table.concat(state_names, ", ") 37.121 end 37.122 \ No newline at end of file
38.1 --- a/model/member.lua Wed Nov 18 12:00:00 2009 +0100 38.2 +++ b/model/member.lua Mon Nov 23 12:00:00 2009 +0100 38.3 @@ -2,6 +2,15 @@ 38.4 Member.table = 'member' 38.5 38.6 Member:add_reference{ 38.7 + mode = '11', 38.8 + to = "MemberImage", 38.9 + this_key = 'id', 38.10 + that_key = 'member_id', 38.11 + ref = 'image', 38.12 + back_ref = 'member' 38.13 +} 38.14 + 38.15 +Member:add_reference{ 38.16 mode = '1m', 38.17 to = "Contact", 38.18 this_key = 'id', 38.19 @@ -87,8 +96,7 @@ 38.20 this_key = 'id', 38.21 that_key = 'member_id', 38.22 ref = 'supporters', 38.23 - back_ref = 'member', 38.24 - default_order = '"id"' 38.25 + back_ref = 'member' 38.26 } 38.27 38.28 Member:add_reference{ 38.29 @@ -248,9 +256,10 @@ 38.30 end 38.31 end 38.32 38.33 -function Member:search(search_string) 38.34 +function Member:get_search_selector(search_string) 38.35 return self:new_selector() 38.36 - :add_where{ '"member"."name" ILIKE ?', "%" .. search_string:gsub("%%", "") .. "%" } 38.37 + :add_field( {'"highlight"("member"."name", ?)', search_string }, "name_highlighted") 38.38 + :add_where{ '"member"."text_search_data" @@ "text_search_query"(?)', search_string } 38.39 :add_where("active") 38.40 - :exec() 38.41 end 38.42 +
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 39.2 +++ b/model/member_image.lua Mon Nov 23 12:00:00 2009 +0100 39.3 @@ -0,0 +1,12 @@ 39.4 +MemberImage = mondelefant.new_class() 39.5 +MemberImage.table = "member_image" 39.6 +MemberImage.primary_key = { "member_id", "image_type" } 39.7 + 39.8 +function MemberImage:by_pk(member_id, image_type, scaled) 39.9 + return self:new_selector() 39.10 + :add_where{ "member_id = ?", member_id } 39.11 + :add_where{ "image_type = ?", image_type } 39.12 + :add_where{ "scaled = ?", scaled } 39.13 + :optional_object_mode() 39.14 + :exec() 39.15 +end
40.1 Binary file static/avatar.jpg has changed
41.1 Binary file static/delegation_arrow.jpg has changed
42.1 Binary file static/delegation_arrow_vertical.jpg has changed
43.1 Binary file static/icons/16/new.png has changed
44.1 --- a/static/style.css Wed Nov 18 12:00:00 2009 +0100 44.2 +++ b/static/style.css Mon Nov 23 12:00:00 2009 +0100 44.3 @@ -23,8 +23,17 @@ 44.4 } 44.5 44.6 td, th { 44.7 + padding: 0.5ex 0.5em 0.5ex 0.5em; 44.8 +} 44.9 + 44.10 +td { 44.11 vertical-align: top; 44.12 - padding: 0.5ex 0.5em 0.5ex 0.5em; 44.13 +} 44.14 + 44.15 +th { 44.16 + vertical-align: bottom; 44.17 + font-size: 75%; 44.18 + font-weight: bold; 44.19 } 44.20 44.21 a.active { 44.22 @@ -40,6 +49,10 @@ 44.23 font-style: italic; 44.24 } 44.25 44.26 +a { 44.27 + vertical-align: middle; 44.28 +} 44.29 + 44.30 /************************************************************************* 44.31 * Notices, warnings and errors 44.32 */ 44.33 @@ -195,6 +208,8 @@ 44.34 .avatar { 44.35 float: left; 44.36 margin-right: 0.5em; 44.37 + width: 48px; 44.38 + height: 48px; 44.39 } 44.40 44.41 .actions { 44.42 @@ -224,6 +239,62 @@ 44.43 } 44.44 44.45 /************************************************************************* 44.46 + * vote info / delegation 44.47 + */ 44.48 + 44.49 +.slot_interest, 44.50 +.slot_support, 44.51 +.slot_delegation { 44.52 + float: left; 44.53 + font-size: 75%; 44.54 + margin-right: 1em; 44.55 +} 44.56 + 44.57 +.vote_info .head { 44.58 + line-height: 200%; 44.59 +} 44.60 + 44.61 +.vote_info .close { 44.62 + background-color: #f44; 44.63 + float: right; 44.64 + padding: 1ex; 44.65 +} 44.66 + 44.67 +.vote_info .content { 44.68 + display: none; 44.69 + position: absolute; 44.70 + z-index: 10; 44.71 + background-color: #fff; 44.72 + border: 2px solid #444; 44.73 + padding: 1em; 44.74 +} 44.75 + 44.76 +.vote_info .delegation_arrow { 44.77 + margin-top: 1ex; 44.78 + margin-bottom: 1ex; 44.79 + vertical-align: middle; 44.80 +} 44.81 + 44.82 +.vote_info .delegation_scope { 44.83 + display: inline; 44.84 +} 44.85 + 44.86 +.vote_info .delegation_info { 44.87 +} 44.88 + 44.89 +.vote_info .member_thumb { 44.90 + clear: left; 44.91 +} 44.92 + 44.93 +.delegation .revoke { 44.94 + margin: 0.5ex; 44.95 +} 44.96 + 44.97 +.delegation .revoke img { 44.98 + vertical-align: middle; 44.99 +} 44.100 + 44.101 +/************************************************************************* 44.102 * Main content 44.103 */ 44.104 44.105 @@ -268,6 +339,28 @@ 44.106 * ui.order 44.107 */ 44.108 44.109 +.ui_filter_head { 44.110 + color: #777; 44.111 + float: left; 44.112 + margin-bottom: 1ex; 44.113 + font-size: 75%; 44.114 +} 44.115 + 44.116 +.ui_filter_head a { 44.117 + color: #777; 44.118 + padding: 0.5ex; 44.119 +} 44.120 + 44.121 +.ui_filter_head a.active{ 44.122 + color: #fff; 44.123 + background-color: #777; 44.124 + padding: 0.5ex; 44.125 +} 44.126 + 44.127 +/************************************************************************* 44.128 + * ui.order 44.129 + */ 44.130 + 44.131 .ui_order_head { 44.132 color: #777; 44.133 text-align: right; 44.134 @@ -299,13 +392,13 @@ 44.135 */ 44.136 44.137 .bargraph { 44.138 - width: 50px; 44.139 + width: 101px; 44.140 } 44.141 44.142 .bargraph div { 44.143 float: left; 44.144 margin-top: 0.5ex; 44.145 - height: 1ex; 44.146 + height: 1.3ex; 44.147 } 44.148 44.149 /************************************************************************* 44.150 @@ -320,8 +413,8 @@ 44.151 .vertical select { 44.152 font-family: sans-serif; 44.153 font-size: 100%; 44.154 + width: 50em; 44.155 border: 1px solid #444; 44.156 - width: 40em; 44.157 padding: 0.2ex 0.2em 0.2ex 0.2em; 44.158 margin-bottom: 1ex; 44.159 } 44.160 @@ -498,62 +591,109 @@ 44.161 */ 44.162 44.163 .issues tr { 44.164 - border-bottom: 1px solid #444; 44.165 + border: 1px solid #ccc; 44.166 } 44.167 44.168 .issues tr tr { 44.169 - border-bottom: none; 44.170 -} 44.171 - 44.172 -/************************************************************************* 44.173 - * delegation 44.174 - */ 44.175 - 44.176 -.infobox { 44.177 - float: right; 44.178 - margin-right: 1em; 44.179 -} 44.180 - 44.181 -.slot_interest, 44.182 -.slot_support, 44.183 -.slot_delegation { 44.184 - border: 2px solid #444; 44.185 - width: 20em; 44.186 - font-size: 75%; 44.187 - padding: 0; 44.188 - margin-bottom: 0.5ex; 44.189 -} 44.190 - 44.191 -.infobox .head { 44.192 - margin: 0.5ex; 44.193 -} 44.194 - 44.195 -.infobox .content { 44.196 - display: none; 44.197 - position: absolute; 44.198 - z-index: 10; 44.199 - width: 20em; 44.200 - background-color: #fff; 44.201 - border: 2px solid #444; 44.202 -} 44.203 - 44.204 -.infobox .text { 44.205 - margin: 0.5ex; 44.206 - margin-bottom: 1ex; 44.207 -} 44.208 - 44.209 -.infobox .member { 44.210 - margin: 0.5ex; 44.211 - display: block; 44.212 - font-weight: bold; 44.213 - margin-bottom: 1ex; 44.214 -} 44.215 - 44.216 -.delegation .revoke { 44.217 - margin: 0.5ex; 44.218 + border: none; 44.219 } 44.220 44.221 .lang_chooser { 44.222 float: right; 44.223 margin-right: 0.5em; 44.224 } 44.225 + 44.226 +.delegation_list_entry { 44.227 + margin-right: 2em; 44.228 + margin-bottom: 2ex; 44.229 + float: left; 44.230 + clear: left; 44.231 +} 44.232 + 44.233 +.delegation_list_entry .delegation_arrow { 44.234 + float: left; 44.235 +} 44.236 + 44.237 +.delegation_list_entry .delegation_scope { 44.238 + float: left; 44.239 + width: 25em; 44.240 +} 44.241 + 44.242 +.delegation_list_entry .delegation_scope a { 44.243 + display: block; 44.244 +} 44.245 + 44.246 +.member_list .member_thumb { 44.247 + float: left; 44.248 + margin-right: 1em; 44.249 + margin-bottom: 2ex; 44.250 +} 44.251 + 44.252 +.member_thumb { 44.253 + text-decoration: none; 44.254 + min-width: 150px; 44.255 + display: block; 44.256 + float: left; 44.257 + border: 1px solid #ccc; 44.258 +} 44.259 + 44.260 +.member_thumb:hover { 44.261 + border: 1px solid #000; 44.262 +} 44.263 + 44.264 +.member_thumb img { 44.265 + margin-right: 0.5em; 44.266 + vertical-align: bottom; 44.267 +} 44.268 + 44.269 +.member_thumb div { 44.270 + display: inline; 44.271 + margin-right: 0.5em; 44.272 +} 44.273 + 44.274 +.draft_content { 44.275 + background-color: #eee; 44.276 + border: 1px solid #ccc; 44.277 + padding: 1ex; 44.278 +} 44.279 + 44.280 +.diff { 44.281 + background-color: #eee; 44.282 + border: 1px solid #ccc; 44.283 + padding: 1ex; 44.284 +} 44.285 + 44.286 +.diff .added { 44.287 + background-color: #cfc; 44.288 +} 44.289 + 44.290 +.diff .removed { 44.291 + background-color: #fcc; 44.292 +} 44.293 + 44.294 +.slot_issue_info { 44.295 + background-color: #eee; 44.296 + border: 1px solid #ccc; 44.297 + float: right; 44.298 + padding: 0.5ex; 44.299 + line-height: 130%; 44.300 + margin-right: 1em; 44.301 +} 44.302 + 44.303 +.issue_info label { 44.304 + float: left; 44.305 + width: 8em; 44.306 + text-transform: uppercase; 44.307 + font-size: 70%; 44.308 + color: #777; 44.309 + font-weight: bold; 44.310 + clear: left; 44.311 + text-align: right; 44.312 + margin-right: 0.7em; 44.313 +} 44.314 + 44.315 +.draft_updated_info { 44.316 + border: 2px solid #faa; 44.317 + background-color: #fee; 44.318 + padding: 1ex; 44.319 +} 44.320 \ No newline at end of file