edit-split.html - Remove unused file
[civicrm-core.git] / js / angular-crmMailing.js
CommitLineData
030dce01 1(function (angular, $, _) {
4dd19229 2 var partialUrl = function partialUrl(relPath) {
dcc7d5c9 3 return CRM.resourceUrls['civicrm'] + '/partials/crmMailing/' + relPath;
030dce01
TO
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 16 function ($routeProvider) {
96ac27bd 17 $routeProvider.when('/mailing', {
030dce01
TO
18 template: '<div></div>',
19 controller: 'ListMailingsCtrl'
20 });
96ac27bd 21 $routeProvider.when('/mailing/:id', {
030dce01
TO
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 });
96ac27bd 30 $routeProvider.when('/mailing/:id/unified', {
d4182dda
TO
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 });
96ac27bd 39 $routeProvider.when('/mailing/:id/unified2', {
d4182dda
TO
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 });
96ac27bd 48 $routeProvider.when('/mailing/:id/wizard', {
d4182dda
TO
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
58dfba8d 69 angular.module('crmMailing').controller('EditMailingCtrl', function EditMailingCtrl($scope, selectedMail, $location, crmMailingMgr, crmStatus, CrmAttachments, crmMailingPreviewMgr) {
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
86c3a327
TO
80 $scope.isSubmitted = function isSubmitted() {
81 return _.size($scope.mailing.jobs) > 0;
82 };
83
58dfba8d
TO
84 // @return Promise
85 $scope.previewMailing = function previewMailing(mailing, mode) {
86 return crmMailingPreviewMgr.preview(mailing, mode);
87 };
88
89 // @return Promise
90 $scope.sendTest = function sendTest(mailing, attachments, recipient) {
91 var savePromise = crmMailingMgr.save(mailing)
92 .then(function () {
93 return attachments.save();
86c3a327
TO
94 })
95 .then(updateUrl);
58dfba8d
TO
96 return crmStatus({start: ts('Saving...'), success: ''}, savePromise)
97 .then(function () {
98 crmMailingPreviewMgr.sendTest(mailing, recipient);
99 });
100 };
101
705c61e9
TO
102 // @return Promise
103 $scope.submit = function submit() {
db083bf0 104 var promise = crmMailingMgr.save($scope.mailing)
86c3a327
TO
105 .then(function () {
106 // pre-condition: the mailing exists *before* saving attachments to it
107 return $scope.attachments.save();
108 })
109 .then(function () {
110 return crmMailingMgr.submit($scope.mailing);
111 })
112 .then(function () {
113 updateUrl();
114 return $scope.mailing;
115 })
116 ;
db083bf0 117 return crmStatus({start: ts('Submitting...'), success: ts('Submitted')}, promise);
2d36e6bc 118 };
58dfba8d 119
705c61e9
TO
120 // @return Promise
121 $scope.save = function save() {
f286acec 122 return crmStatus(null,
db083bf0
TO
123 crmMailingMgr
124 .save($scope.mailing)
125 .then(function () {
126 // pre-condition: the mailing exists *before* saving attachments to it
127 return $scope.attachments.save();
128 })
86c3a327
TO
129 .then(function () {
130 updateUrl();
131 return $scope.mailing;
132 })
f286acec 133 );
2d36e6bc 134 };
58dfba8d 135
705c61e9
TO
136 // @return Promise
137 $scope.delete = function cancel() {
f286acec
TO
138 return crmStatus({start: ts('Deleting...'), success: ts('Deleted')},
139 crmMailingMgr.delete($scope.mailing)
140 );
2d36e6bc 141 };
58dfba8d 142
705c61e9 143 $scope.leave = function leave() {
2d36e6bc
TO
144 window.location = CRM.url('civicrm/mailing/browse/unscheduled', {
145 reset: 1,
146 scheduled: 'false'
147 });
148 };
c54afefa 149
86c3a327
TO
150 // Transition URL "/mailing/new" => "/mailing/123"
151 function updateUrl() {
152 var parts = $location.path().split('/'); // e.g. "/mailing/new" or "/mailing/123/wizard"
153 if (parts[2] != $scope.mailing.id) {
154 parts[2] = $scope.mailing.id;
c54afefa
TO
155 $location.path(parts.join('/'));
156 $location.replace();
157 // FIXME: Angular unnecessarily refreshes UI
86c3a327
TO
158 // WARNING: Changing the URL triggers a full reload. Any pending AJAX operations
159 // could be inconsistently applied. Run updateUrl() after other changes complete.
c54afefa 160 }
86c3a327 161 }
030dce01
TO
162 });
163
7801d9b5
TO
164 // Controller for the edit-recipients fields (
165 // WISHLIST: Move most of this to a (cache-enabled) service
166 // Scope members:
167 // - [input] mailing: object
168 // - [output] recipients: array of recipient records
88e9e883 169 angular.module('crmMailing').controller('EditRecipCtrl', function EditRecipCtrl($scope, dialogService, crmApi, crmMailingMgr) {
52f515c6 170 var ts = $scope.ts = CRM.ts('CiviMail');
7801d9b5
TO
171 $scope.recipients = null;
172 $scope.getRecipientsEstimate = function () {
173 var ts = $scope.ts;
f4f103fa 174 if ($scope.recipients == null) {
7801d9b5 175 return ts('(Estimating)');
f4f103fa
TO
176 }
177 if ($scope.recipients.length == 0) {
7801d9b5 178 return ts('No recipients');
f4f103fa
TO
179 }
180 if ($scope.recipients.length == 1) {
7801d9b5 181 return ts('~1 recipient');
f4f103fa
TO
182 }
183 if (RECIPIENTS_PREVIEW_LIMIT > 0 && $scope.recipients.length >= RECIPIENTS_PREVIEW_LIMIT) {
b73e0c53 184 return ts('>%1 recipients', {1: RECIPIENTS_PREVIEW_LIMIT});
f4f103fa 185 }
7801d9b5
TO
186 return ts('~%1 recipients', {1: $scope.recipients.length});
187 };
f4f103fa 188 $scope.getIncludesAsString = function () {
47bacc20
TO
189 var first = true;
190 var names = '';
f4f103fa
TO
191 _.each($scope.mailing.groups.include, function (id) {
192 if (!first) {
193 names = names + ', ';
194 }
195 var group = _.where(CRM.crmMailing.groupNames, {id: '' + id});
47bacc20
TO
196 names = names + group[0].title;
197 first = false;
198 });
f4f103fa
TO
199 _.each($scope.mailing.mailings.include, function (id) {
200 if (!first) {
201 names = names + ', ';
202 }
203 var oldMailing = _.where(CRM.crmMailing.civiMails, {id: '' + id});
47bacc20
TO
204 names = names + oldMailing[0].name;
205 first = false;
206 });
207 return names;
208 };
f4f103fa 209 $scope.getExcludesAsString = function () {
47bacc20
TO
210 var first = true;
211 var names = '';
f4f103fa
TO
212 _.each($scope.mailing.groups.exclude, function (id) {
213 if (!first) {
214 names = names + ', ';
215 }
216 var group = _.where(CRM.crmMailing.groupNames, {id: '' + id});
47bacc20
TO
217 names = names + group[0].title;
218 first = false;
219 });
f4f103fa
TO
220 _.each($scope.mailing.mailings.exclude, function (id) {
221 if (!first) {
222 names = names + ', ';
223 }
224 var oldMailing = _.where(CRM.crmMailing.civiMails, {id: '' + id});
47bacc20
TO
225 names = names + oldMailing[0].name;
226 first = false;
227 });
228 return names;
229 };
230
7801d9b5
TO
231 // We monitor four fields -- use debounce so that changes across the
232 // four fields can settle-down before AJAX.
233 var refreshRecipients = _.debounce(function () {
234 $scope.$apply(function () {
235 $scope.recipients = null;
8dfd5110
TO
236 crmMailingMgr.previewRecipients($scope.mailing, RECIPIENTS_PREVIEW_LIMIT).then(function (recipients) {
237 $scope.recipients = recipients;
b73e0c53 238 });
7801d9b5
TO
239 });
240 }, RECIPIENTS_DEBOUNCE_MS);
241 $scope.$watchCollection("mailing.groups.include", refreshRecipients);
242 $scope.$watchCollection("mailing.groups.exclude", refreshRecipients);
243 $scope.$watchCollection("mailing.mailings.include", refreshRecipients);
244 $scope.$watchCollection("mailing.mailings.exclude", refreshRecipients);
245
4dd19229 246 $scope.previewRecipients = function previewRecipients() {
7801d9b5
TO
247 var model = {
248 recipients: $scope.recipients
249 };
250 var options = {
251 autoOpen: false,
252 modal: true,
253 title: ts('Preview (%1)', {
254 1: $scope.getRecipientsEstimate()
52f515c6 255 })
7801d9b5 256 };
4dd19229 257 dialogService.open('recipDialog', partialUrl('dialog/recipients.html'), model, options);
7801d9b5
TO
258 };
259 });
260
261 // Controller for the "Preview Recipients" dialog
262 // Note: Expects $scope.model to be an object with properties:
263 // - recipients: array of contacts
88e9e883 264 angular.module('crmMailing').controller('PreviewRecipCtrl', function ($scope) {
7801d9b5
TO
265 $scope.ts = CRM.ts('CiviMail');
266 });
493eb47a 267
493eb47a
TO
268 // Controller for the "Preview Mailing" dialog
269 // Note: Expects $scope.model to be an object with properties:
270 // - "subject"
271 // - "body_html"
272 // - "body_text"
870cbdbb 273 angular.module('crmMailing').controller('PreviewMailingDialogCtrl', function PreviewMailingDialogCtrl($scope) {
493eb47a
TO
274 $scope.ts = CRM.ts('CiviMail');
275 });
276
47bacc20
TO
277 // Controller for the "Preview Mailing Component" segment
278 // which displays header/footer/auto-responder
88e9e883 279 angular.module('crmMailing').controller('PreviewComponentCtrl', function PreviewMailingDialogCtrl($scope, dialogService) {
52f515c6
TO
280 var ts = $scope.ts = CRM.ts('CiviMail');
281
47bacc20 282 $scope.previewComponent = function previewComponent(title, componentId) {
f4f103fa 283 var component = _.where(CRM.crmMailing.headerfooterList, {id: "" + componentId});
47bacc20
TO
284 if (!component || !component[0]) {
285 CRM.alert(ts('Invalid component ID (%1)', {
286 1: componentId
287 }));
288 return;
289 }
290 var options = {
291 autoOpen: false,
292 modal: true,
293 title: title // component[0].name
294 };
295 dialogService.open('previewComponentDialog', partialUrl('dialog/previewComponent.html'), component[0], options);
296 };
297 });
298
299 // Controller for the "Preview Mailing" dialog
300 // Note: Expects $scope.model to be an object with properties:
301 // - "name"
302 // - "subject"
303 // - "body_html"
304 // - "body_text"
88e9e883 305 angular.module('crmMailing').controller('PreviewComponentDialogCtrl', function PreviewMailingDialogCtrl($scope) {
47bacc20
TO
306 $scope.ts = CRM.ts('CiviMail');
307 });
308
744bebee 309 // Controller for the in-place msg-template management
870cbdbb 310 angular.module('crmMailing').controller('MsgTemplateCtrl', function MsgTemplateCtrl($scope, crmMsgTemplates, dialogService) {
744bebee
TO
311 var ts = $scope.ts = CRM.ts('CiviMail');
312 $scope.crmMsgTemplates = crmMsgTemplates;
313
314 // @return Promise MessageTemplate (per APIv3)
74263d6b 315 $scope.saveTemplate = function saveTemplate(mailing) {
744bebee 316 var model = {
74263d6b 317 selected_id: mailing.msg_template_id,
744bebee
TO
318 tpl: {
319 msg_title: '',
74263d6b
TO
320 msg_subject: mailing.subject,
321 msg_text: mailing.body_text,
322 msg_html: mailing.body_html
744bebee
TO
323 }
324 };
325 var options = {
326 autoOpen: false,
327 modal: true,
328 title: ts('Save Template')
329 };
330 return dialogService.open('saveTemplateDialog', partialUrl('dialog/saveTemplate.html'), model, options)
f4f103fa 331 .then(function (item) {
74263d6b 332 mailing.msg_template_id = item.id;
744bebee
TO
333 return item;
334 });
335 };
336
337 // @param int id
338 // @return Promise
74263d6b 339 $scope.loadTemplate = function loadTemplate(mailing, id) {
744bebee 340 return crmMsgTemplates.get(id).then(function (tpl) {
74263d6b
TO
341 mailing.subject = tpl.msg_subject;
342 mailing.body_text = tpl.msg_text;
343 mailing.body_html = tpl.msg_html;
744bebee
TO
344 });
345 };
346 });
347
348 // Controller for the "Save Message Template" dialog
349 // Scope members:
350 // - [input] "model": Object
351 // - "selected_id": int
352 // - "tpl": Object
353 // - "msg_subject": string
354 // - "msg_text": string
355 // - "msg_html": string
88e9e883 356 angular.module('crmMailing').controller('SaveMsgTemplateDialogCtrl', function SaveMsgTemplateDialogCtrl($scope, crmMsgTemplates, dialogService) {
744bebee
TO
357 var ts = $scope.ts = CRM.ts('CiviMail');
358 $scope.saveOpt = {mode: '', newTitle: ''};
359 $scope.selected = null;
360
361 $scope.save = function save() {
362 var tpl = _.extend({}, $scope.model.tpl);
363 switch ($scope.saveOpt.mode) {
364 case 'add':
365 tpl.msg_title = $scope.saveOpt.newTitle;
366 break;
367 case 'update':
368 tpl.id = $scope.selected.id;
369 tpl.msg_title = $scope.selected.msg_title;
370 break;
371 default:
372 throw 'SaveMsgTemplateDialogCtrl: Unrecognized mode: ' + $scope.saveOpt.mode;
373 }
374 return crmMsgTemplates.save(tpl)
375 .then(function (item) {
376 CRM.status(ts('Saved'));
377 return item;
378 });
379 };
380
381 function scopeApply(f) {
382 return function () {
383 var args = arguments;
384 $scope.$apply(function () {
385 f.apply(args);
386 });
387 };
388 }
389
390 function init() {
391 crmMsgTemplates.get($scope.model.selected_id).then(
392 function (tpl) {
393 $scope.saveOpt.mode = 'update';
394 $scope.selected = tpl;
395 },
396 function () {
397 $scope.saveOpt.mode = 'add';
398 $scope.selected = null;
399 }
400 );
401 // When using dialogService with a button bar, the major button actions
402 // need to be registered with the dialog widget (and not embedded in
403 // the body of the dialog).
404 var buttons = {};
405 buttons[ts('Save')] = function () {
406 $scope.save().then(function (item) {
407 dialogService.close('saveTemplateDialog', item);
408 });
409 };
410 buttons[ts('Cancel')] = function () {
411 dialogService.cancel('saveTemplateDialog');
412 };
413 dialogService.setButtons('saveTemplateDialog', buttons);
414 }
f4f103fa 415
744bebee
TO
416 setTimeout(scopeApply(init), 0);
417 });
2d06b3b6 418
58dfba8d 419 angular.module('crmMailing').controller('EmailAddrCtrl', function EmailAddrCtrl($scope, crmFromAddresses) {
0a993c89
TO
420 $scope.crmFromAddresses = crmFromAddresses;
421 });
030dce01 422})(angular, CRM.$, CRM._);