]> git.agnieray.net Git - galette.git/blob - galette/templates/default/pages/mailing_form.html.twig
Fix scrolling in emailing preview's modal
[galette.git] / galette / templates / default / pages / mailing_form.html.twig
1 {#
2 /**
3 * Copyright © 2003-2024 The Galette Team
4 *
5 * This file is part of Galette (https://galette.eu).
6 *
7 * Galette is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Galette is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
19 */
20 #}
21 {% extends 'page.html.twig' %}
22
23 {% block content %}
24 {% if preferences.pref_mail_method == constant('Galette\\Core\\Mailing::METHOD_DISABLED') and not callstatic('\\Galette\\Core\\Galette', 'isDemo') %}
25 <div id="errorbox" class="ui negative icon message">
26 <i class="ban icon" aria-hidden="true"></i>
27 <div class="content">
28 <p>{{ _T("Email sent is disabled in the preferences. Ask galette admin") }}</p>
29 </div>
30 </div>
31 {% elseif mailing_saved is not defined %}
32 <form action="{{ url_for('doMailing') }}" id="listform" method="post" enctype="multipart/form-data" class="ui form">
33 <div class="ui basic fitted segment">
34 <div class="ui styled fluid accordion row">
35 <div class="active title">
36 <i class="jsonly displaynone icon dropdown" aria-hidden="true"></i>
37 {{ _T("Mailing information") }}
38 </div>
39 <div class="active content field">
40 <div class="three fields">
41 <div class="field">
42 <label for="sender">{{ _T("Sender") }}</label>
43 <select name="sender" id="sender" class="ui dropdown">
44 <option value="{{ constant('Galette\\Core\\GaletteMail::SENDER_PREFS') }}">{{ _T("from preferences") }}</option>
45 {% if not login.isSuperAdmin() %}
46 <option value="{{ constant('Galette\\Core\\GaletteMail::SENDER_CURRENT') }}">{{ _T("current logged in user") }}</option>
47 {% endif %}
48 <option value="{{ constant('Galette\\Core\\GaletteMail::SENDER_OTHER') }}">{{ _T("other") }}</option>
49 </select>
50 </div>
51 <div class="field required">
52 <label for="sender_name">{{ _T("Name") }}</label>
53 <input type="text" name="sender_name" id="sender_name" value="{{ preferences.pref_email_nom }}" disabled="disabled"/>
54 </div>
55 <div class="field required">
56 <label for="sender_address">{{ _T("Address") }}</label>
57 <input type="text" name="sender_address" id="sender_address" value="{{ preferences.pref_email }}" disabled="disabled"/>
58 </div>
59 </div>
60 <div class="ui section divider"></div>
61 <div class="two fields">
62 <div class="field">
63 <label>{{ _T("Recipients") }}</label>
64 {% include "elements/mailing_recipients.html.twig" %}
65 {% if mailing.current_step == constant('Galette\\Core\\Mailing::STEP_SENT') %}
66 {% set path = url_for('members') %}
67 {% set text = _T("Go back to members list") %}
68 {% else %}
69 {% set path = '#' %}
70 {% set text = _T("Manage selected members") %}
71 {% endif %}
72 <a
73 id="btnusers"
74 href="{{ path }}"
75 class="jsonly disabled ui labeled icon button"
76 >
77 <i class="blue users icon" aria-hidden="true"></i>
78 {{ text }}
79 </a>
80 <noscript>
81 <div class="ui compact message">{{ _T("This feature requires javascript.") }}</div>
82 </noscript>
83 </div>
84 {% if mailing.current_step == constant('Galette\\Core\\Mailing::STEP_START') %}
85 <div class="field">
86 {% if attachments|length > 0 %}
87 <div class="ui tiny header">
88 <i class="paperclip icon" aria-hidden="true"></i>
89 <div class="content">{{ _T("Existing attachments:") }}</div>
90 </div>
91 <div id="existing_attachments" class="ui middle aligned divided selection list">
92 {% for attachment in attachments %}
93 <div class="item">
94 <div class="content">
95 <a
96 href="?remove_attachment={{ attachment.getFileName() }}"
97 class="rm_attachement delete"
98 >
99 <i class="ui trash alt red icon tooltip" aria-hidden="true"></i>
100 <span class="ui special popup">{{ _T("Remove attachment") }}</span>
101 </a>
102 {{ attachment.getFileName() }}
103 </div>
104 </div>
105 {% endfor %}
106 </div>
107 {% else %}
108 <div class="ui tiny header">
109 <i class="paperclip icon" aria-hidden="true"></i>
110 <div class="content">{{ _T("Attachments") }}</div>
111 </div>
112 {% endif %}
113 <div class="ui file action input">
114 <div class="ui corner labeled input">
115 <input type="file" name="attachment[]" id="attachment" multiple="multiple"/>
116 <div class="ui corner label">
117 <i class="circular inverted primary icon info tooltip" data-html="{{ _T("Select files to add as attachments.<br/>Multiple file selection using 'ctrl' or 'shift' keys are only available on compatible browsers.") }}" aria-hidden="true"></i>
118 </div>
119 </div>
120 <label for="attachment" class="ui button">
121 <i class="blue upload icon" aria-hidden="true"></i>
122 {{ _T("Add attachment") }}
123 </label>
124 </div>
125 </div>
126 {% endif %}
127 </div>
128 </div>
129 </div>
130 </div>
131 {% if mailing.current_step == constant('Galette\\Core\\Mailing::STEP_START') %}
132
133 <div class="ui basic fitted segment">
134 <div class="ui styled fluid accordion row">
135 <div class="active title">
136 <i class="jsonly displaynone icon dropdown" aria-hidden="true"></i>
137 {{ _T("Write your mailing") }}
138 </div>
139 <div class="active content field">
140 <div class="field required">
141 <label for="mailing_objet">{{ _T("Object:") }}</label>
142 <input type="text" name="mailing_objet" id="mailing_objet" value="{{ mailing.subject }}" size="80" required/>
143 </div>
144 <div class="field required">
145 <label for="mailing_corps">{{ _T("Message:") }}</label>
146 <textarea name="mailing_corps" id="mailing_corps" cols="80" rows="15" required>{% if mailing.message %}{{ mailing.message|escape }}{% endif %}</textarea>
147 <input type="hidden" name="html_editor_active" id="html_editor_active" value="{% if html_editor_active %}1{% else %}0{% endif %}"/>
148 </div>
149 <div class="ui basic horizontal equal width segments">
150 <div class="ui basic fitted segment">
151 <div class="ui toggle checkbox">
152 <input type="checkbox" name="mailing_html" id="mailing_html" value="1" {% if mailing.html == 1 or preferences.pref_editor_enabled == 1 %}checked="checked"{% endif %}/>
153 <label for="mailing_html">{{ _T("Interpret HTML") }}</label>
154 </div>
155 </div>
156 <div id="summernote_toggler" class="jsonly hidden ui basic fitted right aligned segment">
157 <a class="ui blue tertiary button" href="javascript:activateMailingEditor('mailing_corps');" id="activate_editor">{{ _T("Activate HTML editor") }}</a>
158 </div>
159 </div>
160 <div class="inline field">
161 </div>
162 </div>
163 </div>
164 </div>
165
166 <div class="ui basic center aligned segment">
167 <div class="ui wrapping spaced buttons">
168 <button type="submit" name="mailing_go" id="btnpreview" class="ui labeled icon button">
169 <i class="eye blue icon" aria-hidden="true"></i>
170 {{ _T("Preview") }}
171 </button>
172 <button type="submit" name="mailing_save" class="ui labeled icon button action">
173 <i class="save green icon" aria-hidden="true"></i>
174 {{ _T("Save") }}
175 </button>
176 <button type="submit" name="mailing_confirm" class="ui labeled icon button {% if callstatic('\\Galette\\Core\\Galette', 'isDemo') %} disabled" disabled="disabled{% endif %}">
177 <i class="rocket red icon" aria-hidden="true"></i>
178 {{ _T("Send") }}
179 </button>
180 <button type="submit" name="mailing_cancel" formnovalidate class="ui labeled icon button">
181 <i class="times icon" aria-hidden="true"></i>
182 {{ _T("Cancel mailing") }}
183 </button>
184 </div>
185 </div>
186 {% endif %}
187 {% if mailing.current_step == constant('Galette\\Core\\Mailing::STEP_PREVIEW') %}
188 <div class="ui basic fitted segment">
189 <div class="ui styled fluid accordion row">
190 <div class="active title">
191 <i class="jsonly hidden icon dropdown" aria-hidden="true"></i>
192 {{ _T("Preview your mailing") }}
193 </div>
194 <div class="active content field">
195 <table class="ui very basic striped unstackable table">
196 <tbody>
197 <tr>
198 <th class="two wide">{{ _T("Subject:") }}</th>
199 <td>{{ mailing.subject }}</td>
200 </tr>
201 <tr>
202 <th class="two wide">{{ _T("Message:") }}</th>
203 <td>
204 {% if mailing.html %}
205 {{ mailing.message }}
206 {% else %}
207 <pre>{{ mailing.wrapped_message }}</pre>
208 {% endif %}
209 </td>
210 </tr>
211 </tbody>
212 </table>
213
214 </div>
215 </div>
216 </div>
217
218 <div class="ui basic center aligned segment">
219 <div class="ui wrapped wrapping spaced buttons">
220 <button type="submit" name="mailing_reset" class="ui labeled icon button">
221 <i class="backward icon" aria-hidden="true"></i>
222 {{ _T("Modifiy mailing") }}
223 </button>
224 <button type="submit" name="mailing_confirm"{% if callstatic('\\Galette\\Core\\Galette', 'isDemo') %} class="ui labeled icon button disabled" disabled="disabled"{% else %} class="ui labeled icon button"{% endif %}>
225 <i class="rocket icon" aria-hidden="true"></i>
226 {{ _T("Send") }}
227 </button>
228 <button type="submit" name="mailing_cancel" formnovalidate class="ui labeled icon button">
229 <i class="trash red icon" aria-hidden="true"></i>
230 {{ _T("Cancel mailing") }}
231 </button>
232
233 <input type="hidden" name="mailing_objet" value="{{ mailing.subject }}"/>
234 <input type="hidden" name="mailing_corps" value="{% if mailing.message %}{{ mailing.message|escape }}{% endif %}"/>
235 </div>
236 </div>
237 {% endif %}
238 {% include "components/forms/csrf.html.twig" %}
239 </form>
240 {% endif %}
241 {% endblock %}
242
243 {% block javascripts %}
244 {% if (preferences.pref_mail_method != constant('Galette\\Core\\Mailing::METHOD_DISABLED') or not callstatic('\\Galette\\Core\\Galette', 'isDemo')) and mailing_saved is not defined %}
245 {% if mailing.current_step != constant('Galette\\Core\\Mailing::STEP_SENT') %}
246 <script type="text/javascript">
247 $(function() {
248 {# Preview popup #}
249 $('#btnpreview').click(function(){
250 var _sender = $('#sender').val();
251 var _sender_name = $('#sender_name').val();
252 var _sender_address = $('#sender_address').val();
253 var _subject = $('#mailing_objet').val();
254 var _body = $('#mailing_corps').val();
255 var _html = $('#mailing_html').is(':checked');
256 var _attachments = [];
257 $('#existing_attachments .item').each(function(){
258 _attachments[_attachments.length] = $(this).text();
259 });
260 $.ajax({
261 url: '{{ url_for('mailingPreview') }}',
262 type: "POST",
263 data: {
264 sender: _sender,
265 sender_name: _sender_name,
266 sender_address: _sender_address,
267 subject: _subject,
268 body: _body,
269 html: _html,
270 attachments: _attachments
271 },
272 {% include "elements/js/loader.js.twig" with {
273 selector: '#btnpreview',
274 loader: 'button'
275 } %},
276 success: function(res){
277 _preview_dialog(res);
278 },
279 error: function() {
280 {% include "elements/js/modal.js.twig" with {
281 modal_title_twig: _T("An error occurred displaying preview :(")|e("js"),
282 modal_without_content: true,
283 modal_class: "mini",
284 modal_deny_only: true,
285 modal_cancel_text: _T("Close")|e("js"),
286 modal_classname: "redalert",
287 } %}
288 }
289 });
290 return false;
291 });
292
293 var _preview_dialog = function(res){
294 {% include "elements/js/modal.js.twig" with {
295 modal_title_twig: _T("Mailing preview")|e("js"),
296 modal_content: "res",
297 modal_class: "scrolling",
298 modal_deny_only: true,
299 modal_cancel_text: _T("Close")|e("js")
300 } %}
301 }
302
303 {# Members popup #}
304 $('#btnusers').click(function(){
305 $.ajax({
306 url: '{{ url_for('ajaxMembers') }}',
307 type: "POST",
308 data: {
309 multiple: true
310 },
311 {% include "elements/js/loader.js.twig" with {
312 selector: '#btnusers',
313 loader: 'button'
314 } %},
315 success: function(res){
316 _members_dialog(res);
317 },
318 error: function() {
319 {% include "elements/js/modal.js.twig" with {
320 modal_title_twig: _T("An error occurred displaying members interface :(")|e("js"),
321 modal_without_content: true,
322 modal_class: "mini",
323 modal_deny_only: true,
324 modal_cancel_text: _T("Close")|e("js"),
325 modal_classname: "redalert",
326 } %}
327 }
328 });
329 return false;
330 });
331
332 var _members_dialog = function(res){
333 {% include "elements/js/modal.js.twig" with {
334 modal_title_twig: _T("Members selection")|e("js"),
335 modal_content: "res",
336 modal_class: "members-selection fullscreen",
337 modal_content_class: "scrolling",
338 modal_deny_only: true,
339 modal_cancel_text: _T("Close")|e("js")
340 } %}
341 _members_ajax_mapper(res);
342 }
343
344 var _members_ajax_mapper = function(res){
345 $('#btnvalid').click(function(){
346 //first, let's store new recipients in mailing object
347 var _recipients = new Array();
348 $('li[id^="member_"]').each(function(){
349 _recipients[_recipients.length] = this.id.substring(7, this.id.length);
350 });
351 $.ajax({
352 url: '{{ url_for('mailingRecipients') }}',
353 type: "POST",
354 data: {
355 recipients: _recipients
356 },
357 {% include "elements/js/loader.js.twig" with {
358 selector: '#btnvalid',
359 loader: 'button'
360 } %},
361 success: function(res){
362 $('#unreachables_count').remove();
363 $('#recipients_count').replaceWith(res);
364 $('.members-selection').modal('hide');
365 },
366 error: function() {
367 {% include "elements/js/modal.js.twig" with {
368 modal_title_twig: _T("An error occurred displaying members interface :(")|e("js"),
369 modal_without_content: true,
370 modal_class: "mini",
371 modal_deny_only: true,
372 modal_cancel_text: _T("Close")|e("js"),
373 modal_classname: "redalert",
374 } %}
375 }
376 });
377 });
378 //Remap links
379 var _none = $('#none_selected').clone();
380 $('li[id^="member_"]').click(function(){
381 $(this).remove();
382 if ( $('#selected_members ul li').length == 0 ) {
383 $('#selected_members ul').append(_none);
384 }
385 });
386 $('#listing tbody tr').click(function(event){
387 event.preventDefault();
388 var _mlink = $(this).find('.username_row a');
389 var _mid = _mlink[0].href.match(/.*\/(\d+)$/)[1];
390 var _mname = _mlink.text();
391 $('#none_selected').remove()
392 if ( $('#member_' + _mid).length == 0 ) {
393 var _li = '<li id="member_' + _mid + '" class="item"><i class="ui user minus icon" aria-hidden="true"></i><span class="ui content">' + _mname + '</span></li>';
394 $('#selected_members ul').append(_li);
395 $('#member_' + _mid).click(function(){
396 $(this).remove();
397 if ( $('#selected_members ul li').length == 0 ) {
398 $('#selected_members ul').append(_none);
399 }
400 });
401 }
402 return false;
403 }).css('cursor', 'pointer').attr('title', '{{ _T("Click on a row to select a member")|e('js') }}');
404
405 $('.members-selection .pagination a').click(function(){
406 var _members = new Array();
407 var _unreach = new Array();
408 $('li[id^="member_"]').each(function(){
409 var _mid = this.id.substring(7, this.id.length);
410 if ($(this).hasClass('unreachables')) {
411 _unreach[_unreach.length] = _mid;
412 } else {
413 _members[_members.length] = _mid;
414 }
415 });
416
417 $.ajax({
418 url: this.href,
419 type: "POST",
420 data: {
421 multiple: true,
422 members: _members,
423 unreachables: _unreach
424 },
425 {% include "elements/js/loader.js.twig" with {
426 loader: '#listing'
427 } %},
428 success: function(res){
429 $('#listing').remove();
430 var _listing = $($.parseHTML(res)).find('#listing');
431 $('.members-selection .eleven.wide.column').append(_listing);
432 _members_ajax_mapper(res);
433 },
434 error: function() {
435 {% include "elements/js/modal.js.twig" with {
436 modal_title_twig: _T("An error occurred displaying members interface :(")|e("js"),
437 modal_without_content: true,
438 modal_class: "mini",
439 modal_deny_only: true,
440 modal_cancel_text: _T("Close")|e("js"),
441 modal_classname: "redalert",
442 } %}
443 }
444 });
445 return false;
446 });
447 }
448
449 {% set modal_onapprove = "window.location.href = '" ~ url_for('mailing') ~ "' + _link.attr('href');" %}
450 $('.rm_attachement').click(function(event){
451 event.preventDefault();
452 var _link = $(this);
453 {% set modal_content = _T("Are you sure you want to remove this attachment?") ~ '<br/>' ~ _T("This will immediately remove attachment from disk and cannot be undone.") %}
454 {% include "elements/js/modal.js.twig" with {
455 modal_title_twig: _T("Remove attachment")|e("js"),
456 modal_content_twig: modal_content|e("js"),
457 modal_class: "tiny",
458 modal_onapprove: modal_onapprove,
459 modal_approve_text: _T("Remove")|e('js'),
460 modal_approve_icon: "trash",
461 modal_approve_color: "red",
462 modal_cancel_text: _T("Cancel")|e("js"),
463 modal_classname: "redalert",
464 } %}
465 });
466
467 $('#sender').on('change', function() {
468 var _this = $(this);
469 var _sender_name = $('#sender_name');
470 var _sender_address = $('#sender_address');
471 var _editable = false;
472 var _val = _this.val();
473 switch (_val) {
474 case '{{ constant('Galette\\Core\\GaletteMail::SENDER_PREFS') }}':
475 _sender_name.val('{{ preferences.pref_email_nom|e('js') }}');
476 _sender_address.val('{{ preferences.pref_email|e('js') }}');
477 break;
478
479 {% if not login.isSuperAdmin() %}
480 case '{{ constant('Galette\\Core\\GaletteMail::SENDER_CURRENT') }}':
481 _sender_name.val('{{ sender_current['name']|e('js') }}');
482 _sender_address.val('{{ sender_current['email']|e('js') }}');
483 break;
484 {% endif %}
485 case '{{ constant('Galette\\Core\\GaletteMail::SENDER_OTHER') }}':
486 _sender_name.val('');
487 _sender_address.val('');
488 _editable = true;
489 break;
490 }
491
492 if (_editable) {
493 _sender_name.removeAttr('disabled');
494 _sender_address.removeAttr('disabled');
495 $('#sender + span').removeClass('disabled');
496 } else {
497 _sender_name.attr('disabled', 'disabled');
498 _sender_address.attr('disabled', 'disabled');
499 $('#sender + span').addClass('disabled');
500 }
501 });
502 });
503 </script>
504 {% endif %}
505 {% endif %}
506 {% endblock %}