liquid_feedback_frontend

view app/main/draft/new.lua @ 1845:71916d0badca

Reworked WYSIWYG editor, added pre formatting
author bsw
date Thu Feb 03 16:03:09 2022 +0100 (2022-02-03)
parents 7b04f14c6d0a
children
line source
1 local issue
2 local area
3 local area_id
5 local issue_id = param.get("issue_id", atom.integer)
6 if issue_id then
7 issue = Issue:new_selector():add_where{"id=?",issue_id}:single_object_mode():exec()
8 issue:load_everything_for_member_id(app.session.member_id)
9 area = issue.area
10 else
11 area_id = param.get("area_id", atom.integer)
12 if area_id then
13 area = Area:new_selector():add_where{"id=?",area_id}:single_object_mode():exec()
14 area:load_delegation_info_once_for_member_id(app.session.member_id)
15 else
16 local firstlife_id = param.get("firstlife_id")
17 if firstlife_id then
18 area = Area:new_selector():join("unit", nil, "unit.id = area.unit_id"):add_where{"attr->>'firstlife_id'=?",firstlife_id}:single_object_mode():exec()
19 area:load_delegation_info_once_for_member_id(app.session.member_id)
20 area_id = area.id
21 end
22 end
23 end
25 local polling = param.get("polling", atom.boolean)
27 local policy_id = param.get("policy_id", atom.integer)
28 local policy
30 local preview = param.get("preview")
32 if #(slot.get_content("error")) > 0 then
33 preview = false
34 end
36 if policy_id then
37 policy = Policy:by_id(policy_id)
38 end
40 local callback = param.get("callback")
43 local initiative_id = param.get("initiative_id")
44 local initiative = Initiative:by_id(initiative_id)
45 local draft
46 if initiative then
47 initiative:load_everything_for_member_id(app.session.member_id)
48 initiative.issue:load_everything_for_member_id(app.session.member_id)
50 if initiative.issue.closed then
51 slot.put_into("error", _"This issue is already closed.")
52 return
53 elseif initiative.issue.half_frozen then
54 slot.put_into("error", _"This issue is already frozen.")
55 return
56 elseif initiative.issue.phase_finished then
57 slot.put_into("error", _"Current phase is already closed.")
58 return
59 end
61 draft = initiative.current_draft
62 if config.initiative_abstract then
63 draft.abstract = string.match(draft.content, "(.+)<!%--END_OF_ABSTRACT%-->")
64 if draft.abstract then
65 draft.content = string.match(draft.content, "<!%--END_OF_ABSTRACT%-->(.*)")
66 end
67 end
68 end
70 if not initiative and not issue and not area then
71 ui.heading{ content = _"Missing parameter" }
72 return false
73 end
75 if not initiative and not issue and #(area.allowed_policies) < 1 then
76 slot.put_into("error", _"Subject area configuration invalid. Please contact the administrator.")
77 return false
78 end
81 ui.form{
82 record = draft,
83 attr = { class = "vertical section", enctype = 'multipart/form-data' },
84 module = "draft",
85 action = "add",
86 params = {
87 area_id = area and area.id,
88 issue_id = issue and issue.id or nil,
89 initiative_id = initiative_id,
90 callback = callback
91 },
92 routing = {
93 ok = {
94 mode = "redirect",
95 module = "initiative",
96 view = "show",
97 id = initiative_id
98 }
99 },
100 content = function()
102 if issue or initiative then
103 execute.view {
104 module = "issue", view = "_head", params = {
105 issue = issue or initiative.issue,
106 member = app.session.member
107 }
108 }
109 else
110 execute.view {
111 module = "area", view = "_head", params = {
112 area = area,
113 member = app.session.member
114 }
115 }
116 end
118 ui.grid{ content = function()
119 ui.cell_main{ content = function()
120 ui.container{ attr = { class = "mdl-card mdl-shadow--2dp mdl-card__fullwidth" }, content = function()
121 ui.container{ attr = { class = "mdl-card__title mdl-card--border" }, content = function()
122 if initiative then
123 ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = initiative.display_name }
124 elseif param.get("name") then
125 ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = param.get("name") }
126 elseif issue then
127 ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = _("New competing initiative in issue '#{issue}'", { issue = issue.name }) }
128 elseif area then
129 ui.heading { attr = { class = "mdl-card__title-text" }, level = 2, content = _"New issue" }
130 end
131 end }
132 ui.container{ attr = { class = "mdl-card__content mdl-card--border" }, content = function()
134 -- -------- PREVIEW
135 if param.get("preview") and slot.get_content("error") == "" then
136 ui.sectionRow( function()
137 if not issue and not initiative and #area.allowed_policies > 1 then
138 ui.container { content = policy and policy.name or "" }
139 slot.put("<br />")
140 end
141 if param.get("free_timing") then
142 ui.container { content = param.get("free_timing") }
143 slot.put("<br />")
144 end
145 ui.field.hidden{ name = "policy_id", value = param.get("policy_id") }
146 ui.field.hidden{ name = "name", value = param.get("name") }
147 if config.initiative_abstract then
148 ui.field.hidden{ name = "abstract", value = param.get("abstract") }
149 ui.container{
150 attr = { class = "abstract" },
151 content = param.get("abstract")
152 }
153 slot.put("<br />")
154 end
155 local draft_text = param.get("content")
156 local draft_text = util.wysihtml_preproc(draft_text)
157 ui.field.hidden{ name = "content", value = draft_text }
158 ui.container{
159 attr = { class = "draft" },
160 content = function()
161 slot.put(draft_text)
162 end
163 }
164 slot.put("<br />")
166 if config.attachments then
167 local file_upload_session = param.get("file_upload_session") or multirand.string(
168 32,
169 '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
170 )
171 file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "")
172 ui.field.hidden{ name = "file_upload_session", value = file_upload_session }
173 if initiative then
174 local files = File:new_selector()
175 :left_join("draft_attachment", nil, "draft_attachment.file_id = file.id")
176 :add_where{ "draft_attachment.draft_id = ?", initiative.current_draft.id }
177 :reset_fields()
178 :add_field("file.id")
179 :add_field("draft_attachment.title")
180 :add_field("draft_attachment.description")
181 :add_order_by("draft_attachment.id")
182 :exec()
184 if #files > 0 then
185 ui.container {
186 content = function()
187 for i, file in ipairs(files) do
188 if param.get("file_delete_" .. file.id, atom.boolean) then
189 ui.field.hidden{ name = "file_delete_" .. file.id, value = "1" }
190 else
191 ui.image{ module = "file", view = "show.jpg", id = file.id, params = { preview = true } }
192 ui.container{ content = function()
193 ui.tag{ tag = "strong", content = file.title or "" }
194 end }
195 ui.container{ content = file.description or "" }
196 slot.put("<br /><br />")
197 end
198 end
199 end
200 }
201 end
202 end
203 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json")
204 local fh = io.open(filename, "r")
205 if fh then
206 local file_uploads = json.import(fh:read("*a"))
207 for i, file_upload in ipairs(file_uploads) do
208 ui.image{ module = "draft", view = "show_file_upload", params = {
209 file_upload_session = file_upload_session, file_id = file_upload.id, preview = true
210 } }
211 ui.container{ content = function()
212 ui.tag{ tag = "strong", content = file_upload.title or "" }
213 end }
214 ui.container{ content = file_upload.description or "" }
215 slot.put("<br />")
216 end
217 end
218 end
220 ui.tag{
221 tag = "input",
222 attr = {
223 type = "submit",
224 class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored",
225 value = _'Publish now'
226 },
227 content = ""
228 }
229 slot.put(" &nbsp; ")
231 ui.tag{
232 tag = "input",
233 attr = {
234 type = "submit",
235 name = "edit",
236 class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect",
237 value = _'Edit again'
238 },
239 content = ""
240 }
241 slot.put(" &nbsp; ")
243 ui.link{
244 attr = { class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect" },
245 content = _"Cancel",
246 module = initiative and "initiative" or "index",
247 view = initiative and "show" or "index",
248 id = initiative_id,
249 params = { unit = area and area.unit_id or nil, area = area_id }
250 }
251 end )
253 -- -------- EDIT
254 else
256 if not issue_id and not initiative_id then
257 local tmp = { { id = -1, name = "" } }
258 for i, allowed_policy in ipairs(area.allowed_policies) do
259 if not allowed_policy.polling or app.session.member:has_polling_right_for_unit_id(area.unit_id) then
260 tmp[#tmp+1] = allowed_policy
261 end
262 end
263 if #area.allowed_policies > 1 then
264 ui.container{ content = _"Please choose a policy for the new issue:" }
265 ui.field.select{
266 name = "policy_id",
267 foreign_records = tmp,
268 foreign_id = "id",
269 foreign_name = "name",
270 value = param.get("policy_id", atom.integer) or area.default_policy and area.default_policy.id
271 }
272 else
273 ui.field.hidden{
274 name = "policy_id",
275 value = area.allowed_policies[1].id
276 }
277 end
278 if policy and policy.free_timeable then
279 local available_timings
280 if config.free_timing and config.free_timing.available_func then
281 available_timings = config.free_timing.available_func(policy)
282 if available_timings == false then
283 slot.put_into("error", "error in free timing config")
284 return false
285 end
286 end
287 ui.heading{ level = 4, content = _"Free timing:" }
288 if available_timings then
289 ui.field.select{
290 name = "free_timing",
291 foreign_records = available_timings,
292 foreign_id = "id",
293 foreign_name = "name",
294 value = param.get("free_timing")
295 }
296 else
297 ui.field.text{
298 name = "free_timing",
299 value = param.get("free_timing")
300 }
301 end
302 end
303 end
305 if issue and issue.policy.polling and app.session.member:has_polling_right_for_unit_id(area.unit_id) then
306 slot.put("<br />")
307 ui.field.boolean{ name = "polling", label = _"No admission needed", value = polling }
308 end
310 if not initiative then
311 ui.container{ attr = { class = "mdl-textfield mdl-js-textfield mdl-textfield--floating-label mdl-card__fullwidth" }, content = function ()
312 ui.field.text{
313 attr = { id = "lf-initiative__name", class = "mdl-textfield__input" },
314 label_attr = { class = "mdl-textfield__label", ["for"] = "lf-initiative__name" },
315 label = _"Title",
316 name = "name",
317 value = param.get("name")
318 }
319 end }
320 end
322 if config.initiative_abstract then
323 ui.container { content = _"Enter abstract:" }
324 ui.container{ attr = { class = "mdl-textfield mdl-js-textfield mdl-textfield--expandable mdl-textfield__fullwidth" }, content = function()
325 ui.field.text{
326 name = "abstract",
327 multiline = true,
328 attr = { id = "abstract", style = "height: 20ex; width: 100%;" },
329 value = param.get("abstract")
330 }
331 end }
332 end
334 ui.field.wysihtml{
335 name = "content",
336 multiline = true,
337 attr = { id = "draft", style = "height: 50ex; width: 100%;" },
338 value = param.get("content")
339 }
340 if not issue or issue.state == "admission" or issue.state == "discussion" then
341 ui.container { content = _"You can change your text again anytime during admission and discussion phase" }
342 else
343 ui.container { content = _"You cannot change your text again later, because this issue is already in verfication phase!" }
344 end
346 slot.put("<br />")
347 if config.attachments then
348 local file_upload_session = param.get("file_upload_session") or multirand.string(
349 32,
350 '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
351 )
352 file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "")
353 ui.field.hidden{ name = "file_upload_session", value = file_upload_session }
354 if initiative then
355 local files = File:new_selector()
356 :left_join("draft_attachment", nil, "draft_attachment.file_id = file.id")
357 :add_where{ "draft_attachment.draft_id = ?", initiative.current_draft.id }
358 :reset_fields()
359 :add_field("file.id")
360 :add_field("draft_attachment.title")
361 :add_field("draft_attachment.description")
362 :add_order_by("draft_attachment.id")
363 :exec()
365 if #files > 0 then
366 ui.container {
367 content = function()
368 for i, file in ipairs(files) do
369 ui.image{ module = "file", view = "show.jpg", id = file.id, params = { preview = true } }
370 ui.container{ content = function()
371 ui.tag{ tag = "strong", content = file.title or "" }
372 end }
373 ui.container{ content = file.description or "" }
374 ui.field.boolean{ label = _"delete", name = "file_delete_" .. file.id, value = param.get("file_delete_" .. file.id) and true or false }
375 slot.put("<br /><br />")
376 end
377 end
378 }
379 end
380 end
381 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json")
382 local fh = io.open(filename, "r")
383 if fh then
384 local file_uploads = json.import(fh:read("*a"))
385 for i, file_upload in ipairs(file_uploads) do
386 ui.image{ module = "draft", view = "show_file_upload", params = {
387 file_upload_session = file_upload_session, file_id = file_upload.id, preview = true
388 } }
389 ui.container{ content = function()
390 ui.tag{ tag = "strong", content = file_upload.title or "" }
391 end }
392 ui.container{ content = file_upload.description or "" }
393 ui.field.boolean{ label = _"delete", name = "file_upload_delete_" .. file_upload.id }
394 slot.put("<br />")
395 end
396 end
397 ui.container{ attr = { id = "file_upload_template", style = "display: none;" }, content = function()
398 ui.field.text{ label = _"Title", name = "__ID_title__" }
399 ui.field.text{ label = _"Description", name = "__ID_description__" }
400 ui.field.image{ field_name = "__ID_file__" }
401 end }
402 ui.container{ attr = { id = "file_upload" }, content = function()
403 end }
404 ui.field.hidden{ attr = { id = "file_upload_last_id" }, name = "file_upload_last_id" }
405 ui.script{ script = [[ var file_upload_id = 1; ]] }
406 ui.tag{ tag = "a", content = _"Attach image", attr = {
407 href = "#",
408 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;"
409 } }
410 slot.put("<br />")
412 slot.put("<br />")
414 end
416 ui.tag{
417 tag = "input",
418 attr = {
419 type = "submit",
420 name = "preview",
421 class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored",
422 value = _'Preview'
423 },
424 content = ""
425 }
426 slot.put(" &nbsp; ")
428 ui.link{
429 content = _"Cancel",
430 module = initiative and "initiative" or issue and "issue" or "index",
431 view = area and not issue and "index" or "show",
432 id = initiative_id or issue_id,
433 params = { area = area_id, unit = area and area.unit_id or nil },
434 attr = { class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect" }
435 }
437 end
438 end }
439 end }
440 end }
442 if config.map or config.firstlife then
443 ui.cell_sidebar{ content = function()
444 ui.container{ attr = { class = "mdl-special-card map mdl-shadow--2dp" }, content = function()
445 local location = param.get("location")
446 local lat = param.get("lat", atom.number)
447 local lon = param.get("lon", atom.number)
448 if lat and lon then
449 location = json.export(json.object{
450 type = "Point",
451 coordinates = json.array{ lon, lat }
452 })
453 end
454 ui.field.location{ name = "location", value = location }
455 end }
456 end }
457 end
459 if config.firstlife then
460 ui.field.hidden{ name = "external_reference", value = param.get("external_reference") }
461 end
463 end }
464 end
465 }

Impressum / About Us