CRM-15578 - Rename crmMailing2 to crmMailing
[civicrm-core.git] / js / angular-crmMailing2.js
CommitLineData
030dce01 1(function (angular, $, _) {
4dd19229 2 var partialUrl = function partialUrl(relPath) {
030dce01
TO
3 return CRM.resourceUrls['civicrm'] + '/partials/crmMailing2/' + relPath;
4 };
5
88e9e883 6 angular.module('crmMailing', [
f4f103fa
TO
7 'crmUtil', 'crmAttachment', 'ngRoute', 'ui.utils', 'crmUi', 'dialogService'
8 ]); // TODO ngSanitize, unsavedChanges
030dce01 9
7801d9b5
TO
10 // Time to wait before triggering AJAX update to recipients list
11 var RECIPIENTS_DEBOUNCE_MS = 100;
b73e0c53 12 var RECIPIENTS_PREVIEW_LIMIT = 10000;
7801d9b5 13
88e9e883 14 angular.module('crmMailing').config([
f4f103fa 15 '$routeProvider',
030dce01
TO
16 function ($routeProvider) {
17 $routeProvider.when('/mailing2', {
18 template: '<div></div>',
19 controller: 'ListMailingsCtrl'
20 });
030dce01
TO
21 $routeProvider.when('/mailing2/:id', {
22 templateUrl: partialUrl('edit.html'),
23 controller: 'EditMailingCtrl',
24 resolve: {
f4f103fa
TO
25 selectedMail: function selectedMail($route, crmMailingMgr) {
26 return crmMailingMgr.getOrCreate($route.current.params.id);
27 }
d4182dda
TO
28 }
29 });
30 $routeProvider.when('/mailing2/:id/unified', {
31 templateUrl: partialUrl('edit-unified.html'),
32 controller: 'EditMailingCtrl',
33 resolve: {
f4f103fa
TO
34 selectedMail: function selectedMail($route, crmMailingMgr) {
35 return crmMailingMgr.getOrCreate($route.current.params.id);
36 }
d4182dda
TO
37 }
38 });
39 $routeProvider.when('/mailing2/:id/unified2', {
40 templateUrl: partialUrl('edit-unified2.html'),
41 controller: 'EditMailingCtrl',
42 resolve: {
f4f103fa
TO
43 selectedMail: function selectedMail($route, crmMailingMgr) {
44 return crmMailingMgr.getOrCreate($route.current.params.id);
45 }
d4182dda
TO
46 }
47 });
48 $routeProvider.when('/mailing2/:id/wizard', {
49 templateUrl: partialUrl('edit-wizard.html'),
50 controller: 'EditMailingCtrl',
51 resolve: {
f4f103fa
TO
52 selectedMail: function selectedMail($route, crmMailingMgr) {
53 return crmMailingMgr.getOrCreate($route.current.params.id);
54 }
030dce01
TO
55 }
56 });
57 }
58 ]);
59
88e9e883 60 angular.module('crmMailing').controller('ListMailingsCtrl', function ListMailingsCtrl() {
030dce01
TO
61 // We haven't implemented this in Angular, but some users may get clever
62 // about typing URLs, so we'll provide a redirect.
63 window.location = CRM.url('civicrm/mailing/browse/unscheduled', {
64 reset: 1,
65 scheduled: 'false'
66 });
67 });
68
88e9e883 69 angular.module('crmMailing').controller('EditMailingCtrl', function EditMailingCtrl($scope, selectedMail, $location, crmMailingMgr, crmStatus, CrmAttachments) {
27e690c2 70 $scope.mailing = selectedMail;
f4f103fa 71 $scope.attachments = new CrmAttachments(function () {
db083bf0
TO
72 return {entity_table: 'civicrm_mailing', entity_id: $scope.mailing.id};
73 });
ab0a4aec 74 $scope.attachments.load();
27e690c2
TO
75 $scope.crmMailingConst = CRM.crmMailing;
76
030dce01 77 $scope.partialUrl = partialUrl;
52f515c6 78 var ts = $scope.ts = CRM.ts('CiviMail');
27e690c2 79
705c61e9
TO
80 // @return Promise
81 $scope.submit = function submit() {
db083bf0
TO
82 var promise = crmMailingMgr.save($scope.mailing)
83 .then(function () {
84 // pre-condition: the mailing exists *before* saving attachments to it
85 return $scope.attachments.save();
86 })
87 .then(function () {
88 return crmMailingMgr.submit($scope.mailing);
89 });
90 return crmStatus({start: ts('Submitting...'), success: ts('Submitted')}, promise);
2d36e6bc 91 };
705c61e9
TO
92 // @return Promise
93 $scope.save = function save() {
f286acec 94 return crmStatus(null,
db083bf0
TO
95 crmMailingMgr
96 .save($scope.mailing)
97 .then(function () {
98 // pre-condition: the mailing exists *before* saving attachments to it
99 return $scope.attachments.save();
100 })
f286acec 101 );
2d36e6bc 102 };
705c61e9
TO
103 // @return Promise
104 $scope.delete = function cancel() {
f286acec
TO
105 return crmStatus({start: ts('Deleting...'), success: ts('Deleted')},
106 crmMailingMgr.delete($scope.mailing)
107 );
2d36e6bc 108 };
705c61e9 109 $scope.leave = function leave() {
2d36e6bc
TO
110 window.location = CRM.url('civicrm/mailing/browse/unscheduled', {
111 reset: 1,
112 scheduled: 'false'
113 });
114 };
c54afefa
TO
115
116 // Transition URL "/mailing2/new" => "/mailing2/123" as soon as ID is known
f4f103fa 117 $scope.$watch('mailing.id', function (newValue, oldValue) {
c54afefa
TO
118 if (newValue && newValue != oldValue) {
119 var parts = $location.path().split('/'); // e.g. "/mailing2/new" or "/mailing2/123/wizard"
120 parts[2] = newValue;
121 $location.path(parts.join('/'));
122 $location.replace();
123 // FIXME: Angular unnecessarily refreshes UI
124 }
125 });
030dce01
TO
126 });
127
7801d9b5
TO
128 // Controller for the edit-recipients fields (
129 // WISHLIST: Move most of this to a (cache-enabled) service
130 // Scope members:
131 // - [input] mailing: object
132 // - [output] recipients: array of recipient records
88e9e883 133 angular.module('crmMailing').controller('EditRecipCtrl', function EditRecipCtrl($scope, dialogService, crmApi, crmMailingMgr) {
52f515c6 134 var ts = $scope.ts = CRM.ts('CiviMail');
7801d9b5
TO
135 $scope.recipients = null;
136 $scope.getRecipientsEstimate = function () {
137 var ts = $scope.ts;
f4f103fa 138 if ($scope.recipients == null) {
7801d9b5 139 return ts('(Estimating)');
f4f103fa
TO
140 }
141 if ($scope.recipients.length == 0) {
7801d9b5 142 return ts('No recipients');
f4f103fa
TO
143 }
144 if ($scope.recipients.length == 1) {
7801d9b5 145 return ts('~1 recipient');
f4f103fa
TO
146 }
147 if (RECIPIENTS_PREVIEW_LIMIT > 0 && $scope.recipients.length >= RECIPIENTS_PREVIEW_LIMIT) {
b73e0c53 148 return ts('>%1 recipients', {1: RECIPIENTS_PREVIEW_LIMIT});
f4f103fa 149 }
7801d9b5
TO
150 return ts('~%1 recipients', {1: $scope.recipients.length});
151 };
f4f103fa 152 $scope.getIncludesAsString = function () {
47bacc20
TO
153 var first = true;
154 var names = '';
f4f103fa
TO
155 _.each($scope.mailing.groups.include, function (id) {
156 if (!first) {
157 names = names + ', ';
158 }
159 var group = _.where(CRM.crmMailing.groupNames, {id: '' + id});
47bacc20
TO
160 names = names + group[0].title;
161 first = false;
162 });
f4f103fa
TO
163 _.each($scope.mailing.mailings.include, function (id) {
164 if (!first) {
165 names = names + ', ';
166 }
167 var oldMailing = _.where(CRM.crmMailing.civiMails, {id: '' + id});
47bacc20
TO
168 names = names + oldMailing[0].name;
169 first = false;
170 });
171 return names;
172 };
f4f103fa 173 $scope.getExcludesAsString = function () {
47bacc20
TO
174 var first = true;
175 var names = '';
f4f103fa
TO
176 _.each($scope.mailing.groups.exclude, function (id) {
177 if (!first) {
178 names = names + ', ';
179 }
180 var group = _.where(CRM.crmMailing.groupNames, {id: '' + id});
47bacc20
TO
181 names = names + group[0].title;
182 first = false;
183 });
f4f103fa
TO
184 _.each($scope.mailing.mailings.exclude, function (id) {
185 if (!first) {
186 names = names + ', ';
187 }
188 var oldMailing = _.where(CRM.crmMailing.civiMails, {id: '' + id});
47bacc20
TO
189 names = names + oldMailing[0].name;
190 first = false;
191 });
192 return names;
193 };
194
7801d9b5
TO
195 // We monitor four fields -- use debounce so that changes across the
196 // four fields can settle-down before AJAX.
197 var refreshRecipients = _.debounce(function () {
198 $scope.$apply(function () {
199 $scope.recipients = null;
8dfd5110
TO
200 crmMailingMgr.previewRecipients($scope.mailing, RECIPIENTS_PREVIEW_LIMIT).then(function (recipients) {
201 $scope.recipients = recipients;
b73e0c53 202 });
7801d9b5
TO
203 });
204 }, RECIPIENTS_DEBOUNCE_MS);
205 $scope.$watchCollection("mailing.groups.include", refreshRecipients);
206 $scope.$watchCollection("mailing.groups.exclude", refreshRecipients);
207 $scope.$watchCollection("mailing.mailings.include", refreshRecipients);
208 $scope.$watchCollection("mailing.mailings.exclude", refreshRecipients);
209
4dd19229 210 $scope.previewRecipients = function previewRecipients() {
7801d9b5
TO
211 var model = {
212 recipients: $scope.recipients
213 };
214 var options = {
215 autoOpen: false,
216 modal: true,
217 title: ts('Preview (%1)', {
218 1: $scope.getRecipientsEstimate()
52f515c6 219 })
7801d9b5 220 };
4dd19229 221 dialogService.open('recipDialog', partialUrl('dialog/recipients.html'), model, options);
7801d9b5
TO
222 };
223 });
224
225 // Controller for the "Preview Recipients" dialog
226 // Note: Expects $scope.model to be an object with properties:
227 // - recipients: array of contacts
88e9e883 228 angular.module('crmMailing').controller('PreviewRecipCtrl', function ($scope) {
7801d9b5
TO
229 $scope.ts = CRM.ts('CiviMail');
230 });
493eb47a
TO
231
232 // Controller for the "Preview Mailing" segment
233 // Note: Expects $scope.model to be an object with properties:
234 // - mailing: object
db083bf0 235 // - attachments: object
88e9e883 236 angular.module('crmMailing').controller('PreviewMailingCtrl', function ($scope, dialogService, crmMailingMgr, crmStatus) {
52f515c6
TO
237 var ts = $scope.ts = CRM.ts('CiviMail');
238
13cb08ff 239 $scope.testContact = {email: CRM.crmMailing.defaultTestEmail};
493eb47a
TO
240 $scope.testGroup = {gid: null};
241
4dd19229 242 $scope.previewHtml = function previewHtml() {
493eb47a
TO
243 $scope.previewDialog(partialUrl('dialog/previewHtml.html'));
244 };
4dd19229 245 $scope.previewText = function previewText() {
493eb47a
TO
246 $scope.previewDialog(partialUrl('dialog/previewText.html'));
247 };
4dd19229 248 $scope.previewFull = function previewFull() {
493eb47a
TO
249 $scope.previewDialog(partialUrl('dialog/previewFull.html'));
250 };
251 // Open a dialog with a preview of the current mailing
252 // @param template string URL of the template to use in the preview dialog
4dd19229 253 $scope.previewDialog = function previewDialog(template) {
978e94d7 254 var p = crmMailingMgr
493eb47a 255 .preview($scope.mailing)
f4f103fa 256 .then(function (content) {
493eb47a
TO
257 var options = {
258 autoOpen: false,
259 modal: true,
260 title: ts('Subject: %1', {
261 1: content.subject
7e830b29 262 })
493eb47a
TO
263 };
264 dialogService.open('previewDialog', template, content, options);
265 });
f4f103fa 266 CRM.status({start: ts('Previewing'), success: ''}, CRM.toJqPromise(p));
493eb47a 267 };
4dd19229 268 $scope.sendTestToContact = function sendTestToContact() {
db083bf0 269 $scope.sendTest($scope.mailing, $scope.attachments, $scope.testContact.email, null);
493eb47a 270 };
4dd19229 271 $scope.sendTestToGroup = function sendTestToGroup() {
db083bf0 272 $scope.sendTest($scope.mailing, $scope.attachments, null, $scope.testGroup.gid);
beab9d1b 273 };
db083bf0
TO
274 $scope.sendTest = function sendTest(mailing, attachments, testEmail, testGroup) {
275 var promise = crmMailingMgr.save(mailing)
276 .then(function () {
277 return attachments.save();
278 })
279 .then(function () {
280 return crmMailingMgr.sendTest(mailing, testEmail, testGroup);
281 })
282 .then(function (deliveryInfos) {
283 var count = Object.keys(deliveryInfos).length;
284 if (count === 0) {
285 CRM.alert(ts('Could not identify any recipients. Perhaps the group is empty?'));
286 }
287 })
288 ;
289 return crmStatus({start: ts('Sending...'), success: ts('Sent')}, promise);
493eb47a
TO
290 };
291 });
292
293 // Controller for the "Preview Mailing" dialog
294 // Note: Expects $scope.model to be an object with properties:
295 // - "subject"
296 // - "body_html"
297 // - "body_text"
88e9e883 298 angular.module('crmMailing').controller('PreviewMailingDialogCtrl', function PreviewMailingDialogCtrl($scope, crmMailingMgr) {
493eb47a
TO
299 $scope.ts = CRM.ts('CiviMail');
300 });
301
47bacc20
TO
302 // Controller for the "Preview Mailing Component" segment
303 // which displays header/footer/auto-responder
88e9e883 304 angular.module('crmMailing').controller('PreviewComponentCtrl', function PreviewMailingDialogCtrl($scope, dialogService) {
52f515c6
TO
305 var ts = $scope.ts = CRM.ts('CiviMail');
306
47bacc20 307 $scope.previewComponent = function previewComponent(title, componentId) {
f4f103fa 308 var component = _.where(CRM.crmMailing.headerfooterList, {id: "" + componentId});
47bacc20
TO
309 if (!component || !component[0]) {
310 CRM.alert(ts('Invalid component ID (%1)', {
311 1: componentId
312 }));
313 return;
314 }
315 var options = {
316 autoOpen: false,
317 modal: true,
318 title: title // component[0].name
319 };
320 dialogService.open('previewComponentDialog', partialUrl('dialog/previewComponent.html'), component[0], options);
321 };
322 });
323
324 // Controller for the "Preview Mailing" dialog
325 // Note: Expects $scope.model to be an object with properties:
326 // - "name"
327 // - "subject"
328 // - "body_html"
329 // - "body_text"
88e9e883 330 angular.module('crmMailing').controller('PreviewComponentDialogCtrl', function PreviewMailingDialogCtrl($scope) {
47bacc20
TO
331 $scope.ts = CRM.ts('CiviMail');
332 });
333
744bebee 334 // Controller for the in-place msg-template management
88e9e883 335 angular.module('crmMailing').controller('MsgTemplateCtrl', function MsgTemplateCtrl($scope, crmMsgTemplates, dialogService, $parse) {
744bebee
TO
336 var ts = $scope.ts = CRM.ts('CiviMail');
337 $scope.crmMsgTemplates = crmMsgTemplates;
338
339 // @return Promise MessageTemplate (per APIv3)
74263d6b 340 $scope.saveTemplate = function saveTemplate(mailing) {
744bebee 341 var model = {
74263d6b 342 selected_id: mailing.msg_template_id,
744bebee
TO
343 tpl: {
344 msg_title: '',
74263d6b
TO
345 msg_subject: mailing.subject,
346 msg_text: mailing.body_text,
347 msg_html: mailing.body_html
744bebee
TO
348 }
349 };
350 var options = {
351 autoOpen: false,
352 modal: true,
353 title: ts('Save Template')
354 };
355 return dialogService.open('saveTemplateDialog', partialUrl('dialog/saveTemplate.html'), model, options)
f4f103fa 356 .then(function (item) {
74263d6b 357 mailing.msg_template_id = item.id;
744bebee
TO
358 return item;
359 });
360 };
361
362 // @param int id
363 // @return Promise
74263d6b 364 $scope.loadTemplate = function loadTemplate(mailing, id) {
744bebee 365 return crmMsgTemplates.get(id).then(function (tpl) {
74263d6b
TO
366 mailing.subject = tpl.msg_subject;
367 mailing.body_text = tpl.msg_text;
368 mailing.body_html = tpl.msg_html;
744bebee
TO
369 });
370 };
371 });
372
373 // Controller for the "Save Message Template" dialog
374 // Scope members:
375 // - [input] "model": Object
376 // - "selected_id": int
377 // - "tpl": Object
378 // - "msg_subject": string
379 // - "msg_text": string
380 // - "msg_html": string
88e9e883 381 angular.module('crmMailing').controller('SaveMsgTemplateDialogCtrl', function SaveMsgTemplateDialogCtrl($scope, crmMsgTemplates, dialogService) {
744bebee
TO
382 var ts = $scope.ts = CRM.ts('CiviMail');
383 $scope.saveOpt = {mode: '', newTitle: ''};
384 $scope.selected = null;
385
386 $scope.save = function save() {
387 var tpl = _.extend({}, $scope.model.tpl);
388 switch ($scope.saveOpt.mode) {
389 case 'add':
390 tpl.msg_title = $scope.saveOpt.newTitle;
391 break;
392 case 'update':
393 tpl.id = $scope.selected.id;
394 tpl.msg_title = $scope.selected.msg_title;
395 break;
396 default:
397 throw 'SaveMsgTemplateDialogCtrl: Unrecognized mode: ' + $scope.saveOpt.mode;
398 }
399 return crmMsgTemplates.save(tpl)
400 .then(function (item) {
401 CRM.status(ts('Saved'));
402 return item;
403 });
404 };
405
406 function scopeApply(f) {
407 return function () {
408 var args = arguments;
409 $scope.$apply(function () {
410 f.apply(args);
411 });
412 };
413 }
414
415 function init() {
416 crmMsgTemplates.get($scope.model.selected_id).then(
417 function (tpl) {
418 $scope.saveOpt.mode = 'update';
419 $scope.selected = tpl;
420 },
421 function () {
422 $scope.saveOpt.mode = 'add';
423 $scope.selected = null;
424 }
425 );
426 // When using dialogService with a button bar, the major button actions
427 // need to be registered with the dialog widget (and not embedded in
428 // the body of the dialog).
429 var buttons = {};
430 buttons[ts('Save')] = function () {
431 $scope.save().then(function (item) {
432 dialogService.close('saveTemplateDialog', item);
433 });
434 };
435 buttons[ts('Cancel')] = function () {
436 dialogService.cancel('saveTemplateDialog');
437 };
438 dialogService.setButtons('saveTemplateDialog', buttons);
439 }
f4f103fa 440
744bebee
TO
441 setTimeout(scopeApply(init), 0);
442 });
2d06b3b6 443
88e9e883 444 angular.module('crmMailing').controller('EmailAddrCtrl', function EmailAddrCtrl($scope, crmFromAddresses){
0a993c89
TO
445 $scope.crmFromAddresses = crmFromAddresses;
446 });
030dce01 447})(angular, CRM.$, CRM._);