liquid_feedback_frontend
diff app/main/draft/new.lua @ 1496:ed3c40911ae1
Completed image attachments feature
author | bsw |
---|---|
date | Tue Feb 11 15:24:36 2020 +0100 (2020-02-11) |
parents | 17e7082c377a |
children | a59dd2ae9cd8 |
line diff
1.1 --- a/app/main/draft/new.lua Mon Feb 10 21:10:49 2020 +0100 1.2 +++ b/app/main/draft/new.lua Tue Feb 11 15:24:36 2020 +0100 1.3 @@ -1,24 +1,68 @@ 1.4 -local initiative = Initiative:by_id(param.get("initiative_id")) 1.5 -initiative:load_everything_for_member_id(app.session.member_id) 1.6 -initiative.issue:load_everything_for_member_id(app.session.member_id) 1.7 +local issue 1.8 +local area 1.9 +local area_id 1.10 1.11 -if initiative.issue.closed then 1.12 - slot.put_into("error", _"This issue is already closed.") 1.13 - return 1.14 -elseif initiative.issue.half_frozen then 1.15 - slot.put_into("error", _"This issue is already frozen.") 1.16 - return 1.17 -elseif initiative.issue.phase_finished then 1.18 - slot.put_into("error", _"Current phase is already closed.") 1.19 - return 1.20 +local issue_id = param.get("issue_id", atom.integer) 1.21 +if issue_id then 1.22 + issue = Issue:new_selector():add_where{"id=?",issue_id}:single_object_mode():exec() 1.23 + issue:load_everything_for_member_id(app.session.member_id) 1.24 + area = issue.area 1.25 +else 1.26 + area_id = param.get("area_id", atom.integer) 1.27 + if area_id then 1.28 + area = Area:new_selector():add_where{"id=?",area_id}:single_object_mode():exec() 1.29 + area:load_delegation_info_once_for_member_id(app.session.member_id) 1.30 + end 1.31 +end 1.32 + 1.33 +local polling = param.get("polling", atom.boolean) 1.34 + 1.35 +local policy_id = param.get("policy_id", atom.integer) 1.36 +local policy 1.37 + 1.38 +local preview = param.get("preview") 1.39 + 1.40 +if #(slot.get_content("error")) > 0 then 1.41 + preview = false 1.42 +end 1.43 + 1.44 +if policy_id then 1.45 + policy = Policy:by_id(policy_id) 1.46 end 1.47 1.48 -local draft = initiative.current_draft 1.49 -if config.initiative_abstract then 1.50 - draft.abstract = string.match(draft.content, "(.+)<!%--END_OF_ABSTRACT%-->") 1.51 - if draft.abstract then 1.52 - draft.content = string.match(draft.content, "<!%--END_OF_ABSTRACT%-->(.*)") 1.53 + 1.54 + 1.55 + 1.56 +local initiative_id = param.get("initiative_id") 1.57 +local initiative = Initiative:by_id(initiative_id) 1.58 +local draft 1.59 +if initiative then 1.60 + initiative:load_everything_for_member_id(app.session.member_id) 1.61 + initiative.issue:load_everything_for_member_id(app.session.member_id) 1.62 + 1.63 + if initiative.issue.closed then 1.64 + slot.put_into("error", _"This issue is already closed.") 1.65 + return 1.66 + elseif initiative.issue.half_frozen then 1.67 + slot.put_into("error", _"This issue is already frozen.") 1.68 + return 1.69 + elseif initiative.issue.phase_finished then 1.70 + slot.put_into("error", _"Current phase is already closed.") 1.71 + return 1.72 end 1.73 + 1.74 + draft = initiative.current_draft 1.75 + if config.initiative_abstract then 1.76 + draft.abstract = string.match(draft.content, "(.+)<!%--END_OF_ABSTRACT%-->") 1.77 + if draft.abstract then 1.78 + draft.content = string.match(draft.content, "<!%--END_OF_ABSTRACT%-->(.*)") 1.79 + end 1.80 + end 1.81 +end 1.82 + 1.83 +if not initiative and not issue and not area then 1.84 + ui.heading{ content = _"Missing parameter" } 1.85 + return false 1.86 end 1.87 1.88 ui.form{ 1.89 @@ -26,13 +70,17 @@ 1.90 attr = { class = "vertical section", enctype = 'multipart/form-data' }, 1.91 module = "draft", 1.92 action = "add", 1.93 - params = { initiative_id = initiative.id }, 1.94 + params = { 1.95 + area_id = area and area.id, 1.96 + issue_id = issue and issue.id or nil, 1.97 + initiative_id = initiative_id 1.98 + }, 1.99 routing = { 1.100 ok = { 1.101 mode = "redirect", 1.102 module = "initiative", 1.103 view = "show", 1.104 - id = initiative.id 1.105 + id = initiative_id 1.106 } 1.107 }, 1.108 content = function() 1.109 @@ -41,11 +89,30 @@ 1.110 ui.cell_main{ content = function() 1.111 ui.container{ attr = { class = "mdl-card mdl-shadow--2dp mdl-card__fullwidth" }, content = function() 1.112 ui.container{ attr = { class = "mdl-card__title mdl-card--border" }, content = function() 1.113 - ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = initiative.display_name } 1.114 + if initiative then 1.115 + ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = initiative.display_name } 1.116 + elseif param.get("name") then 1.117 + ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = param.get("name") } 1.118 + elseif issue then 1.119 + ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = _("New competing initiative in issue '#{issue}'", { issue = issue.name }) } 1.120 + elseif area then 1.121 + ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = _("New issue in area '#{area}'", { area = area.name }) } 1.122 + end 1.123 end } 1.124 ui.container{ attr = { class = "mdl-card__content mdl-card--border" }, content = function() 1.125 + 1.126 +-- -------- PREVIEW 1.127 if param.get("preview") then 1.128 ui.sectionRow( function() 1.129 + if not issue and not initiative then 1.130 + ui.container { content = policy.name } 1.131 + end 1.132 + if param.get("free_timing") then 1.133 + ui.container { content = param.get("free_timing") } 1.134 + end 1.135 + slot.put("<br />") 1.136 + ui.field.hidden{ name = "policy_id", value = param.get("policy_id") } 1.137 + ui.field.hidden{ name = "name", value = param.get("name") } 1.138 if config.initiative_abstract then 1.139 ui.field.hidden{ name = "abstract", value = param.get("abstract") } 1.140 ui.container{ 1.141 @@ -72,31 +139,35 @@ 1.142 ) 1.143 file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "") 1.144 ui.field.hidden{ name = "file_upload_session", value = file_upload_session } 1.145 - local files = File:new_selector() 1.146 - :left_join("draft_attachment", nil, "draft_attachment.file_id = file.id") 1.147 - :add_where{ "draft_attachment.draft_id = ?", initiative.current_draft.id } 1.148 - :reset_fields() 1.149 - :add_field("file.id") 1.150 - :add_field("draft_attachment.title") 1.151 - :add_field("draft_attachment.description") 1.152 - :add_order_by("draft_attachment.id") 1.153 - :exec() 1.154 + if initiative then 1.155 + local files = File:new_selector() 1.156 + :left_join("draft_attachment", nil, "draft_attachment.file_id = file.id") 1.157 + :add_where{ "draft_attachment.draft_id = ?", initiative.current_draft.id } 1.158 + :reset_fields() 1.159 + :add_field("file.id") 1.160 + :add_field("draft_attachment.title") 1.161 + :add_field("draft_attachment.description") 1.162 + :add_order_by("draft_attachment.id") 1.163 + :exec() 1.164 1.165 - if #files > 0 then 1.166 - ui.container { 1.167 - content = function() 1.168 - for i, file in ipairs(files) do 1.169 - if param.get("file_delete_" .. file.id, atom.boolean) then 1.170 - ui.field.hidden{ name = "file_delete_" .. file.id, value = "1" } 1.171 - else 1.172 - ui.image{ module = "file", view = "show.jpg", id = file.id, params = { preview = true } } 1.173 - ui.container{ content = file.title or "" } 1.174 - ui.container{ content = file.description or "" } 1.175 - slot.put("<br /><br />") 1.176 + if #files > 0 then 1.177 + ui.container { 1.178 + content = function() 1.179 + for i, file in ipairs(files) do 1.180 + if param.get("file_delete_" .. file.id, atom.boolean) then 1.181 + ui.field.hidden{ name = "file_delete_" .. file.id, value = "1" } 1.182 + else 1.183 + ui.image{ module = "file", view = "show.jpg", id = file.id, params = { preview = true } } 1.184 + ui.container{ content = function() 1.185 + ui.tag{ tag = "strong", content = file.title or "" } 1.186 + end } 1.187 + ui.container{ content = file.description or "" } 1.188 + slot.put("<br /><br />") 1.189 + end 1.190 end 1.191 end 1.192 - end 1.193 - } 1.194 + } 1.195 + end 1.196 end 1.197 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json") 1.198 local fh = io.open(filename, "r") 1.199 @@ -106,7 +177,9 @@ 1.200 ui.image{ module = "draft", view = "show_file_upload", params = { 1.201 file_upload_session = file_upload_session, file_id = file_upload.id, preview = true 1.202 } } 1.203 - ui.container{ content = file_upload.title or "" } 1.204 + ui.container{ content = function() 1.205 + ui.tag{ tag = "strong", content = file_upload.title or "" } 1.206 + end } 1.207 ui.container{ content = file_upload.description or "" } 1.208 slot.put("<br />") 1.209 end 1.210 @@ -139,47 +212,108 @@ 1.211 ui.link{ 1.212 attr = { class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect" }, 1.213 content = _"Cancel", 1.214 - module = "initiative", 1.215 + module = initiative and "initiative" or "area", 1.216 view = "show", 1.217 - id = initiative.id 1.218 + id = initiative_id or area_id 1.219 } 1.220 end ) 1.221 1.222 +-- -------- EDIT 1.223 else 1.224 - ui.sectionRow( function() 1.225 - if config.initiative_abstract then 1.226 - ui.container { content = _"Enter abstract:" } 1.227 - ui.container{ attr = { class = "mdl-textfield mdl-js-textfield mdl-textfield--expandable mdl-textfield__fullwidth" }, content = function() 1.228 + 1.229 + if not issue_id and not initiative_id then 1.230 + local tmp = { { id = -1, name = "" } } 1.231 + for i, allowed_policy in ipairs(area.allowed_policies) do 1.232 + if not allowed_policy.polling or app.session.member:has_polling_right_for_unit_id(area.unit_id) then 1.233 + tmp[#tmp+1] = allowed_policy 1.234 + end 1.235 + end 1.236 + ui.container{ content = _"Please choose a policy for the new issue:" } 1.237 + ui.field.select{ 1.238 + name = "policy_id", 1.239 + foreign_records = tmp, 1.240 + foreign_id = "id", 1.241 + foreign_name = "name", 1.242 + value = param.get("policy_id", atom.integer) or area.default_policy and area.default_policy.id 1.243 + } 1.244 + if policy and policy.free_timeable then 1.245 + local available_timings 1.246 + if config.free_timing and config.free_timing.available_func then 1.247 + available_timings = config.free_timing.available_func(policy) 1.248 + if available_timings == false then 1.249 + slot.put_into("error", "error in free timing config") 1.250 + return false 1.251 + end 1.252 + end 1.253 + ui.heading{ level = 4, content = _"Free timing:" } 1.254 + if available_timings then 1.255 + ui.field.select{ 1.256 + name = "free_timing", 1.257 + foreign_records = available_timings, 1.258 + foreign_id = "id", 1.259 + foreign_name = "name", 1.260 + value = param.get("free_timing") 1.261 + } 1.262 + else 1.263 ui.field.text{ 1.264 - name = "abstract", 1.265 - multiline = true, 1.266 - attr = { id = "abstract", style = "height: 20ex; width: 100%;" }, 1.267 - value = param.get("abstract") 1.268 + name = "free_timing", 1.269 + value = param.get("free_timing") 1.270 } 1.271 - end } 1.272 + end 1.273 end 1.274 - 1.275 - ui.container { content = _"Enter your proposal and/or reasons:" } 1.276 - ui.field.wysihtml{ 1.277 - name = "content", 1.278 - multiline = true, 1.279 - attr = { id = "draft", style = "height: 50ex; width: 100%;" }, 1.280 - value = param.get("content") 1.281 - } 1.282 - if not issue or issue.state == "admission" or issue.state == "discussion" then 1.283 - ui.container { content = _"You can change your text again anytime during admission and discussion phase" } 1.284 - else 1.285 - ui.container { content = _"You cannot change your text again later, because this issue is already in verfication phase!" } 1.286 - end 1.287 + end 1.288 + 1.289 + if issue and issue.policy.polling and app.session.member:has_polling_right_for_unit_id(area.unit_id) then 1.290 + slot.put("<br />") 1.291 + ui.field.boolean{ name = "polling", label = _"No admission needed", value = polling } 1.292 + end 1.293 + 1.294 + if not initiative then 1.295 + ui.container{ attr = { class = "mdl-textfield mdl-js-textfield mdl-textfield--floating-label mdl-card__fullwidth" }, content = function () 1.296 + ui.field.text{ 1.297 + attr = { id = "lf-initiative__name", class = "mdl-textfield__input" }, 1.298 + label_attr = { class = "mdl-textfield__label", ["for"] = "lf-initiative__name" }, 1.299 + label = _"Title", 1.300 + name = "name", 1.301 + value = param.get("name") 1.302 + } 1.303 + end } 1.304 + end 1.305 1.306 - slot.put("<br />") 1.307 - if config.attachments then 1.308 - local file_upload_session = param.get("file_upload_session") or multirand.string( 1.309 - 32, 1.310 - '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' 1.311 - ) 1.312 - file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "") 1.313 - ui.field.hidden{ name = "file_upload_session", value = file_upload_session } 1.314 + if config.initiative_abstract then 1.315 + ui.container { content = _"Enter abstract:" } 1.316 + ui.container{ attr = { class = "mdl-textfield mdl-js-textfield mdl-textfield--expandable mdl-textfield__fullwidth" }, content = function() 1.317 + ui.field.text{ 1.318 + name = "abstract", 1.319 + multiline = true, 1.320 + attr = { id = "abstract", style = "height: 20ex; width: 100%;" }, 1.321 + value = param.get("abstract") 1.322 + } 1.323 + end } 1.324 + end 1.325 + 1.326 + ui.container { content = _"Enter your proposal and/or reasons:" } 1.327 + ui.field.wysihtml{ 1.328 + name = "content", 1.329 + multiline = true, 1.330 + attr = { id = "draft", style = "height: 50ex; width: 100%;" }, 1.331 + value = param.get("content") 1.332 + } 1.333 + if not issue or issue.state == "admission" or issue.state == "discussion" then 1.334 + ui.container { content = _"You can change your text again anytime during admission and discussion phase" } 1.335 + else 1.336 + ui.container { content = _"You cannot change your text again later, because this issue is already in verfication phase!" } 1.337 + end 1.338 + 1.339 + slot.put("<br />") 1.340 + if config.attachments then 1.341 + local file_upload_session = param.get("file_upload_session") or multirand.string( 1.342 + 32, 1.343 + '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' 1.344 + ) 1.345 + file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "") 1.346 + ui.field.hidden{ name = "file_upload_session", value = file_upload_session } 1.347 + if initiative then 1.348 local files = File:new_selector() 1.349 :left_join("draft_attachment", nil, "draft_attachment.file_id = file.id") 1.350 :add_where{ "draft_attachment.draft_id = ?", initiative.current_draft.id } 1.351 @@ -195,7 +329,9 @@ 1.352 content = function() 1.353 for i, file in ipairs(files) do 1.354 ui.image{ module = "file", view = "show.jpg", id = file.id, params = { preview = true } } 1.355 - ui.container{ content = file.title or "" } 1.356 + ui.container{ content = function() 1.357 + ui.tag{ tag = "strong", content = file.title or "" } 1.358 + end } 1.359 ui.container{ content = file.description or "" } 1.360 ui.field.boolean{ label = _"delete", name = "file_delete_" .. file.id, value = param.get("file_delete_" .. file.id) and true or false } 1.361 slot.put("<br /><br />") 1.362 @@ -203,61 +339,63 @@ 1.363 end 1.364 } 1.365 end 1.366 - 1.367 - local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json") 1.368 - local fh = io.open(filename, "r") 1.369 - if fh then 1.370 - local file_uploads = json.import(fh:read("*a")) 1.371 - for i, file_upload in ipairs(file_uploads) do 1.372 - ui.image{ module = "draft", view = "show_file_upload", params = { 1.373 - file_upload_session = file_upload_session, file_id = file_upload.id, preview = true 1.374 - } } 1.375 - ui.container{ content = file_upload.title or "" } 1.376 - ui.container{ content = file_upload.description or "" } 1.377 - ui.field.boolean{ label = _"delete", name = "file_upload_delete_" .. file_upload.id } 1.378 - slot.put("<br />") 1.379 - end 1.380 + end 1.381 + local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json") 1.382 + local fh = io.open(filename, "r") 1.383 + if fh then 1.384 + local file_uploads = json.import(fh:read("*a")) 1.385 + for i, file_upload in ipairs(file_uploads) do 1.386 + ui.image{ module = "draft", view = "show_file_upload", params = { 1.387 + file_upload_session = file_upload_session, file_id = file_upload.id, preview = true 1.388 + } } 1.389 + ui.container{ content = function() 1.390 + ui.tag{ tag = "strong", content = file_upload.title or "" } 1.391 + end } 1.392 + ui.container{ content = file_upload.description or "" } 1.393 + ui.field.boolean{ label = _"delete", name = "file_upload_delete_" .. file_upload.id } 1.394 + slot.put("<br />") 1.395 end 1.396 - ui.container{ attr = { id = "file_upload_template", style = "display: none;" }, content = function() 1.397 - ui.field.text{ label = _"Title", name = "__ID_title__" } 1.398 - ui.field.text{ label = _"Description", name = "__ID_description__" } 1.399 - ui.field.image{ field_name = "__ID_file__" } 1.400 - end } 1.401 - ui.container{ attr = { id = "file_upload" }, content = function() 1.402 - end } 1.403 - ui.field.hidden{ attr = { id = "file_upload_last_id" }, name = "file_upload_last_id" } 1.404 - ui.script{ script = [[ var file_upload_id = 1; ]] } 1.405 - ui.tag{ tag = "a", content = _"Attach image", attr = { 1.406 - href = "#", 1.407 - onclick = "var html = document.getElementById('file_upload_template').innerHTML; html = html.replace('__ID_file__', 'file_' + file_upload_id); html = html.replace('__ID_title__', 'title_' + file_upload_id); html = html.replace('__ID_description__', 'description_' + file_upload_id); var el = document.createElement('div'); el.innerHTML = html; document.getElementById('file_upload').appendChild(el); document.getElementById('file_upload_last_id').value = file_upload_id; file_upload_id++; return false;" 1.408 - } } 1.409 - slot.put("<br />") 1.410 - 1.411 - slot.put("<br />") 1.412 + end 1.413 + ui.container{ attr = { id = "file_upload_template", style = "display: none;" }, content = function() 1.414 + ui.field.text{ label = _"Title", name = "__ID_title__" } 1.415 + ui.field.text{ label = _"Description", name = "__ID_description__" } 1.416 + ui.field.image{ field_name = "__ID_file__" } 1.417 + end } 1.418 + ui.container{ attr = { id = "file_upload" }, content = function() 1.419 + end } 1.420 + ui.field.hidden{ attr = { id = "file_upload_last_id" }, name = "file_upload_last_id" } 1.421 + ui.script{ script = [[ var file_upload_id = 1; ]] } 1.422 + ui.tag{ tag = "a", content = _"Attach image", attr = { 1.423 + href = "#", 1.424 + onclick = "var html = document.getElementById('file_upload_template').innerHTML; html = html.replace('__ID_file__', 'file_' + file_upload_id); html = html.replace('__ID_title__', 'title_' + file_upload_id); html = html.replace('__ID_description__', 'description_' + file_upload_id); var el = document.createElement('div'); el.innerHTML = html; document.getElementById('file_upload').appendChild(el); document.getElementById('file_upload_last_id').value = file_upload_id; file_upload_id++; return false;" 1.425 + } } 1.426 + slot.put("<br />") 1.427 + 1.428 + slot.put("<br />") 1.429 1.430 - end 1.431 + end 1.432 1.433 - ui.tag{ 1.434 - tag = "input", 1.435 - attr = { 1.436 - type = "submit", 1.437 - name = "preview", 1.438 - class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored", 1.439 - value = _'Preview' 1.440 - }, 1.441 - content = "" 1.442 - } 1.443 - slot.put(" ") 1.444 - 1.445 - ui.link{ 1.446 - content = _"Cancel", 1.447 - module = "initiative", 1.448 - view = "show", 1.449 - id = initiative.id, 1.450 - attr = { class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect" } 1.451 - } 1.452 - 1.453 - end ) 1.454 + ui.tag{ 1.455 + tag = "input", 1.456 + attr = { 1.457 + type = "submit", 1.458 + name = "preview", 1.459 + class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored", 1.460 + value = _'Preview' 1.461 + }, 1.462 + content = "" 1.463 + } 1.464 + slot.put(" ") 1.465 + 1.466 + ui.link{ 1.467 + content = _"Cancel", 1.468 + module = initiative and "initiative" or issue and "issue" or "index", 1.469 + view = area and "index" or "show", 1.470 + id = initiative_id or issue_id, 1.471 + params = { area = area_id, unit = area and area.unit_id or nil }, 1.472 + attr = { class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect" } 1.473 + } 1.474 + 1.475 end 1.476 end } 1.477 end }