bsw@1045: local initiative = Initiative:by_id ( param.get_id() ) bsw@1045: local member = app.session.member bsw@1045: bsw@1045: if not initiative then bsw@1045: execute.view { module = "index", view = "404" } bsw@1045: request.set_status("404 Not Found") bsw@1045: return bsw@1045: end bsw@1045: bsw@1045: local issue_info bsw@1045: bsw@1045: if member then bsw@1045: initiative:load_everything_for_member_id(member.id) bsw@1045: initiative.issue:load_everything_for_member_id(member.id) bsw@1045: issue_info = initiative.issue.member_info bsw@1045: end bsw@1045: bsw@1045: execute.view { bsw@1045: module = "issue", view = "_head", bsw@1045: params = { bsw@1045: issue = initiative.issue, bsw@1045: initiative = initiative, bsw@1045: member = app.session.member bsw@1045: } bsw@1045: } bsw@1045: bsw@1045: if app.session.member_id then bsw@1045: direct_supporter = initiative.issue.member_info.own_participation and initiative.member_info.supported bsw@1045: end bsw@718: bsw@1045: ui.script { script = [[ bsw@1045: function showTab(tabId) { bsw@1045: $('.tab').hide(); bsw@1045: $('.main').hide(); bsw@1045: $('.main, .slot_extra .section').hide(); bsw@1045: $('.' + tabId).show(); bsw@1045: if (tabId == "main") $('.slot_extra .section').show(); bsw@1045: }; bsw@1045: showTab('main'); bsw@1045: ]]} bsw@1045: bsw@1045: execute.view{ module = "issue", view = "_sidebar_state", params = { bsw@1045: initiative = initiative bsw@1045: } } bsw@1045: bsw@1045: execute.view { bsw@1045: module = "issue", view = "_sidebar_issue", bsw@1045: params = { bsw@1045: issue = initiative.issue, bsw@1045: highlight_initiative_id = initiative.id bsw@1045: } bsw@1045: } bsw@1045: bsw@1045: execute.view { bsw@1045: module = "issue", view = "_sidebar_whatcanido", bsw@1045: params = { initiative = initiative } bsw@1045: } bsw@1045: bsw@1045: execute.view { bsw@1045: module = "issue", view = "_sidebar_members", params = { bsw@1045: issue = initiative.issue, initiative = initiative bsw@718: } bsw@718: } bsw@1045: bsw@1045: ui.section( function () bsw@1045: execute.view{ bsw@1045: module = "initiative", view = "_head", params = { bsw@1045: initiative = initiative bsw@1045: } bsw@1045: } bsw@1045: bsw@1045: if direct_supporter and not initiative.issue.closed then bsw@1045: local supporter = app.session.member:get_reference_selector("supporters") bsw@1045: :add_where{ "initiative_id = ?", initiative.id } bsw@1045: :optional_object_mode() bsw@1045: :exec() bsw@1045: bsw@1045: if supporter then bsw@1045: bsw@1045: local old_draft_id = supporter.draft_id bsw@1045: local new_draft_id = initiative.current_draft.id bsw@1045: bsw@1045: if old_draft_id ~= new_draft_id then bsw@1045: ui.sectionRow( "draft_updated_info", function () bsw@1045: ui.container{ bsw@1045: attr = { class = "info" }, bsw@1045: content = _"The draft of this initiative has been updated!" bsw@1045: } bsw@1045: slot.put(" ") bsw@1045: ui.link{ bsw@1045: content = _"show differences", bsw@1045: module = "draft", bsw@1045: view = "diff", bsw@1045: params = { bsw@1045: old_draft_id = old_draft_id, bsw@1045: new_draft_id = new_draft_id bsw@1045: } bsw@1045: } bsw@1045: if not initiative.revoked then bsw@1045: slot.put(" | ") bsw@1045: ui.link{ bsw@1045: text = _"refresh my support", bsw@1045: module = "initiative", bsw@1045: action = "add_support", bsw@1045: id = initiative.id, bsw@1045: params = { draft_id = initiative.current_draft.id }, bsw@1045: routing = { bsw@1045: default = { bsw@1045: mode = "redirect", bsw@1045: module = "initiative", bsw@1045: view = "show", bsw@1045: id = initiative.id bsw@1045: } bsw@1045: } bsw@1045: } bsw@1045: slot.put(" | ") bsw@1045: end bsw@1045: bsw@1045: ui.link{ bsw@1045: text = _"remove my support", bsw@1045: module = "initiative", bsw@1045: action = "remove_support", bsw@1045: id = initiative.id, bsw@1045: routing = { bsw@1045: default = { bsw@1045: mode = "redirect", bsw@1045: module = "initiative", bsw@1045: view = "show", bsw@1045: id = initiative.id bsw@1045: } bsw@1045: } bsw@1045: } bsw@1045: bsw@1045: end ) bsw@1045: end bsw@1045: end bsw@1045: end bsw@1045: bsw@1045: bsw@1045: ui.sectionRow( function () bsw@1045: ui.container { bsw@1045: attr = { class = "draft" }, bsw@1045: content = function () bsw@1045: slot.put ( initiative.current_draft:get_content ( "html" ) ) bsw@1045: end bsw@1045: } bsw@1045: end ) bsw@1045: bsw@1045: end) bsw@1045: bsw@1045: ui.link { attr = { name = "suggestions" }, text = "" } bsw@1045: bsw@1045: bsw@1045: ui.container { bsw@1045: attr = { class = "section suggestions" }, bsw@1045: content = function () bsw@1045: bsw@1045: if # ( initiative.suggestions ) > 0 then bsw@1045: bsw@1045: ui.sectionHead( function () bsw@1045: ui.heading { bsw@1045: level = 1, bsw@1045: content = _("Suggestions for improvement (#{count})", { count = # ( initiative.suggestions ) } ) bsw@1045: } bsw@1045: ui.container { content = _"written and rated by the supportes of this initiative to improve the proposal and its reasons" } bsw@1045: end ) bsw@1045: bsw@1045: for i, suggestion in ipairs(initiative.suggestions) do bsw@1045: bsw@1045: local opinion = Opinion:by_pk(app.session.member_id, suggestion.id) bsw@1045: bsw@1045: local class = "sectionRow suggestion" bsw@1045: if suggestion.id == param.get("suggestion_id", atom.number) then bsw@1045: class = class .. " highlighted" bsw@1045: end bsw@1045: if member and not initiative.issue.fully_frozen and not initiative.issue.closed and initiative.member_info.supported then bsw@1045: class = class .. " rateable" bsw@1045: end bsw@1045: bsw@1045: bsw@1045: ui.tag { tag = "div", attr = { class = class, id = "s" .. suggestion.id }, content = function () bsw@1045: bsw@1045: if opinion then bsw@1045: bsw@1045: ui.container { attr = { class = "opinion"}, content = function() bsw@1045: local class = "" bsw@1045: local text = "" bsw@1045: bsw@1045: if opinion.degree == 2 then bsw@1045: class = "must" bsw@1045: text = _"must" bsw@1045: elseif opinion.degree == 1 then bsw@1045: class = "should" bsw@1045: text = _"should" bsw@1045: elseif opinion.degree == 0 then bsw@1045: class = "neutral" bsw@1045: text = _"neutral" bsw@1045: elseif opinion.degree == -1 then bsw@1045: class = "shouldnot" bsw@1045: text = _"should not" bsw@1045: elseif opinion.degree == -2 then bsw@1045: class = "mustnot" bsw@1045: text = _"must not" bsw@1045: end bsw@1045: bsw@1045: ui.tag { bsw@1045: attr = { class = class }, bsw@1045: content = text bsw@1045: } bsw@1045: bsw@1045: slot.put ( " " ) bsw@1045: bsw@1045: if bsw@1045: (opinion.degree > 0 and not opinion.fulfilled) bsw@1045: or (opinion.degree < 0 and opinion.fulfilled) bsw@1045: then bsw@1045: ui.tag{ content = _"but" } bsw@1045: else bsw@1045: ui.tag{ content = _"and" } bsw@1045: end bsw@1045: bsw@1045: slot.put ( " " ) bsw@1045: bsw@1045: local class = "" bsw@1045: local text = "" bsw@1045: bsw@1045: if opinion.fulfilled then bsw@1045: class = "implemented" bsw@1045: text = _"is implemented" bsw@1045: else bsw@1045: class = "notimplemented" bsw@1045: text = _"is not implemented" bsw@1045: end bsw@1045: bsw@1045: ui.tag { bsw@1045: attr = { class = class }, bsw@1045: content = text bsw@1045: } bsw@1045: bsw@1045: if bsw@1045: (opinion.degree > 0 and not opinion.fulfilled) bsw@1045: or (opinion.degree < 0 and opinion.fulfilled) bsw@1045: then bsw@1045: if math.abs(opinion.degree) > 1 then bsw@1045: slot.put(" !!") bsw@1045: else bsw@1045: slot.put(" !") bsw@1045: end bsw@1045: else bsw@1045: slot.put(" ✓") bsw@1045: end bsw@1045: bsw@1045: end } bsw@1045: bsw@1045: end bsw@1045: bsw@1045: bsw@1045: ui.link { attr = { name = "s" .. suggestion.id }, text = "" } bsw@1045: ui.heading { level = 2, bsw@1045: attr = { class = "suggestionHead" }, bsw@1045: content = format.string(suggestion.name, { bsw@1045: truncate_at = 160, truncate_suffix = true bsw@1045: }) } bsw@1045: bsw@1045: bsw@1045: local plus2 = (suggestion.plus2_unfulfilled_count or 0) bsw@1045: + (suggestion.plus2_fulfilled_count or 0) bsw@1045: local plus1 = (suggestion.plus1_unfulfilled_count or 0) bsw@1045: + (suggestion.plus1_fulfilled_count or 0) bsw@1045: local minus1 = (suggestion.minus1_unfulfilled_count or 0) bsw@1045: + (suggestion.minus1_fulfilled_count or 0) bsw@1045: local minus2 = (suggestion.minus2_unfulfilled_count or 0) bsw@1045: + (suggestion.minus2_fulfilled_count or 0) bsw@1045: bsw@1045: local with_opinion = plus2 + plus1 + minus1 + minus2 bsw@1045: bsw@1045: local neutral = (suggestion.initiative.supporter_count or 0) bsw@1045: - with_opinion bsw@1045: bsw@1045: local neutral2 = with_opinion bsw@1045: - (suggestion.plus2_fulfilled_count or 0) bsw@1045: - (suggestion.plus1_fulfilled_count or 0) bsw@1045: - (suggestion.minus1_fulfilled_count or 0) bsw@1045: - (suggestion.minus2_fulfilled_count or 0) bsw@1045: bsw@1045: ui.container { bsw@1045: attr = { class = "suggestionInfo" }, bsw@1045: content = function () bsw@1045: bsw@1045: if with_opinion > 0 then bsw@1045: ui.container { attr = { class = "suggestion-rating" }, content = function () bsw@1045: ui.tag { content = _"collective rating:" } bsw@1045: slot.put(" ") bsw@1045: ui.bargraph{ bsw@1045: max_value = suggestion.initiative.supporter_count, bsw@1045: width = 100, bsw@1045: bars = { bsw@1045: { color = "#0a0", value = plus2 }, bsw@1045: { color = "#8a8", value = plus1 }, bsw@1045: { color = "#eee", value = neutral }, bsw@1045: { color = "#a88", value = minus1 }, bsw@1045: { color = "#a00", value = minus2 }, bsw@1045: } bsw@1045: } bsw@1045: slot.put(" | ") bsw@1045: ui.tag { content = _"implemented:" } bsw@1045: slot.put ( " " ) bsw@1045: ui.bargraph{ bsw@1045: max_value = with_opinion, bsw@1045: width = 100, bsw@1045: bars = { bsw@1045: { color = "#0a0", value = suggestion.plus2_fulfilled_count }, bsw@1045: { color = "#8a8", value = suggestion.plus1_fulfilled_count }, bsw@1045: { color = "#eee", value = neutral2 }, bsw@1045: { color = "#a88", value = suggestion.minus1_fulfilled_count }, bsw@1045: { color = "#a00", value = suggestion.minus2_fulfilled_count }, bsw@1045: } bsw@1045: } bsw@1045: end } bsw@1045: end bsw@1045: bsw@1045: if app.session:has_access("authors_pseudonymous") then bsw@1045: util.micro_avatar ( suggestion.author ) bsw@1045: else bsw@1045: slot.put("
") bsw@1045: end bsw@1045: bsw@1045: ui.container { bsw@1045: attr = { class = "suggestion-text" }, bsw@1045: content = function () bsw@1045: slot.put ( suggestion:get_content( "html" ) ) bsw@1045: bsw@1045: if direct_supporter then bsw@1045: bsw@1045: ui.container { bsw@1045: attr = { class = "rating" }, bsw@1045: content = function () bsw@1045: bsw@1045: if not opinion then bsw@1045: opinion = {} bsw@1045: end bsw@1045: ui.form { bsw@1045: module = "opinion", action = "update", params = { bsw@1045: suggestion_id = suggestion.id bsw@1045: }, bsw@1045: routing = { default = { bsw@1045: mode = "redirect", bsw@1045: module = "initiative", view = "show", id = suggestion.initiative_id, bsw@1045: params = { suggestion_id = suggestion.id }, bsw@1045: anchor = "s" .. suggestion.id -- TODO webmcp bsw@1045: } }, bsw@1045: content = function () bsw@1045: bsw@1045: bsw@1045: ui.heading { level = 3, content = _"Should the initiator implement this suggestion?" } bsw@1045: ui.container { content = function () bsw@1045: bsw@1045: local active = opinion.degree == 2 bsw@1045: ui.tag { tag = "input", attr = { bsw@1045: type = "radio", name = "degree", value = 2, bsw@1045: id = "s" .. suggestion.id .. "_degree2", bsw@1045: checked = active and "checked" or nil bsw@1045: } } bsw@1045: ui.tag { bsw@1045: tag = "label", bsw@1045: attr = { bsw@1045: ["for"] = "s" .. suggestion.id .. "_degree2", bsw@1045: class = active and "active-plus2" or nil, bsw@1045: }, bsw@1045: content = _"must" bsw@1045: } bsw@1045: bsw@1045: local active = opinion.degree == 1 bsw@1045: ui.tag { tag = "input", attr = { bsw@1045: type = "radio", name = "degree", value = 1, bsw@1045: id = "s" .. suggestion.id .. "_degree1", bsw@1045: checked = active and "checked" or nil bsw@1045: } } bsw@1045: ui.tag { bsw@1045: tag = "label", bsw@1045: attr = { bsw@1045: ["for"] = "s" .. suggestion.id .. "_degree1", bsw@1045: class = active and "active-plus1" or nil, bsw@1045: }, bsw@1045: content = _"should" bsw@1045: } bsw@1045: bsw@1045: local active = not opinion.member_id bsw@1045: ui.tag { tag = "input", attr = { bsw@1045: type = "radio", name = "degree", value = 0, bsw@1045: id = "s" .. suggestion.id .. "_degree0", bsw@1045: checked = active and "checked" or nil bsw@1045: } } bsw@1045: ui.tag { bsw@1045: tag = "label", bsw@1045: attr = { bsw@1045: ["for"] = "s" .. suggestion.id .. "_degree0", bsw@1045: class = active and "active-neutral" or nil, bsw@1045: }, bsw@1045: content = _"neutral" bsw@1045: } bsw@1045: bsw@1045: local active = opinion.degree == -1 bsw@1045: ui.tag { tag = "input", attr = { bsw@1045: type = "radio", name = "degree", value = -1, bsw@1045: id = "s" .. suggestion.id .. "_degree-1", bsw@1045: checked = active and "checked" or nil bsw@1045: } } bsw@1045: ui.tag { bsw@1045: tag = "label", bsw@1045: attr = { bsw@1045: ["for"] = "s" .. suggestion.id .. "_degree-1", bsw@1045: class = active and "active-minus1" or nil, bsw@1045: }, bsw@1045: content = _"should not" bsw@1045: } bsw@1045: bsw@1045: local active = opinion.degree == -2 bsw@1045: ui.tag { tag = "input", attr = { bsw@1045: type = "radio", name = "degree", value = -2, bsw@1045: id = "s" .. suggestion.id .. "_degree-2", bsw@1045: checked = active and "checked" or nil bsw@1045: } } bsw@1045: ui.tag { bsw@1045: tag = "label", bsw@1045: attr = { bsw@1045: ["for"] = "s" .. suggestion.id .. "_degree-2", bsw@1045: class = active and "active-minus2" or nil, bsw@1045: }, bsw@1045: content = _"must not" bsw@1045: } bsw@1045: end } bsw@1045: bsw@1045: slot.put("
") bsw@1045: bsw@1045: ui.heading { level = 3, content = _"Did the initiator implement this suggestion?" } bsw@1045: ui.container { content = function () bsw@1045: local active = opinion.fulfilled == false bsw@1045: ui.tag { tag = "input", attr = { bsw@1045: type = "radio", name = "fulfilled", value = "false", bsw@1045: id = "s" .. suggestion.id .. "_notfulfilled", bsw@1045: checked = active and "checked" or nil bsw@1045: } } bsw@1045: ui.tag { bsw@1045: tag = "label", bsw@1045: attr = { bsw@1045: ["for"] = "s" .. suggestion.id .. "_notfulfilled", bsw@1045: class = active and "active-notfulfilled" or nil, bsw@1045: }, bsw@1045: content = _"No (not yet)" bsw@1045: } bsw@1045: bsw@1045: local active = opinion.fulfilled bsw@1045: ui.tag { tag = "input", attr = { bsw@1045: type = "radio", name = "fulfilled", value = "true", bsw@1045: id = "s" .. suggestion.id .. "_fulfilled", bsw@1045: checked = active and "checked" or nil bsw@1045: } } bsw@1045: ui.tag { bsw@1045: tag = "label", bsw@1045: attr = { bsw@1045: ["for"] = "s" .. suggestion.id .. "_fulfilled", bsw@1045: class = active and "active-fulfilled" or nil, bsw@1045: }, bsw@1045: content = _"Yes, it's implemented" bsw@1045: } bsw@1045: end } bsw@1045: slot.put("
") bsw@1045: bsw@1045: ui.tag{ bsw@1045: tag = "input", bsw@1045: attr = { bsw@1045: type = "submit", bsw@1045: class = "btn btn-default", bsw@1045: value = _"publish my rating" bsw@1045: }, bsw@1045: content = "" bsw@1045: } bsw@1045: bsw@1045: end bsw@1045: } bsw@1045: bsw@1045: end -- if not issue,fully_frozen or closed bsw@1045: } bsw@1045: end bsw@1045: bsw@1045: local text = _"Read more" bsw@1045: bsw@1045: if direct_supporter then bsw@1045: text = _"Show more and rate this" bsw@1045: end bsw@1045: bsw@1045: ui.link { bsw@1045: attr = { bsw@1045: class = "suggestion-more", bsw@1045: onclick = "$('#s" .. suggestion.id .. "').removeClass('folded').addClass('unfolded'); return false;" bsw@1045: }, bsw@1045: text = text bsw@1045: } bsw@1045: bsw@1045: ui.link { bsw@1045: attr = { bsw@1045: class = "suggestion-less", bsw@1045: onclick = "$('#s" .. suggestion.id .. "').addClass('folded').removeClass('unfolded'); return false;" bsw@1045: }, bsw@1045: text = _"Show less" bsw@1045: } bsw@1045: end bsw@1045: } bsw@1045: bsw@1045: ui.script{ script = [[ bsw@1045: var textEl = $('#s]] .. suggestion.id .. [[ .suggestion-text'); bsw@1045: var height = textEl.height(); bsw@1045: if (height > 150) $('#s]] .. suggestion.id .. [[').addClass('folded'); bsw@1045: ]] } bsw@1045: bsw@1045: end bsw@1045: } -- ui.paragraph bsw@1045: bsw@1045: bsw@1045: bsw@1045: end } -- ui.tag "li" bsw@1045: bsw@1045: end -- for i, suggestion bsw@1045: bsw@1045: else -- if #initiative.suggestions > 0 bsw@1045: bsw@1045: local text bsw@1045: if initiative.issue.closed then bsw@1045: text = "No suggestions" bsw@1045: else bsw@1045: text = "No suggestions (yet)" bsw@1045: end bsw@1045: ui.sectionHead( function() bsw@1045: ui.heading { level = 1, content = text } bsw@1045: end) bsw@1045: bsw@1045: end -- if #initiative.suggestions > 0 bsw@1045: bsw@1045: end bsw@1045: }