Merge pull request #21744 from civicrm/5.42
[civicrm-core.git] / ang / crmMailing / services.js
CommitLineData
8dfd5110 1(function (angular, $, _) {
8dfd5110 2
a0214785
TO
3 // The representation of from/reply-to addresses is inconsistent in the mailing data-model,
4 // so the UI must do some adaptation. The crmFromAddresses provides a richer way to slice/dice
5 // the available "From:" addrs. Records are like the underlying OptionValues -- but add "email"
6 // and "author".
88e9e883 7 angular.module('crmMailing').factory('crmFromAddresses', function ($q, crmApi) {
c65ce897 8 var emailRegex = /^"(.*)" *<([^@>]*@[^@>]*)>$/;
f4f103fa 9 var addrs = _.map(CRM.crmMailing.fromAddress, function (addr) {
a0214785 10 var match = emailRegex.exec(addr.label);
86c3a327 11 return angular.extend({}, addr, {
a0214785
TO
12 email: match ? match[2] : '(INVALID)',
13 author: match ? match[1] : '(INVALID)'
14 });
15 });
f4f103fa 16
a0214785 17 function first(array) {
6bcb856f 18 return (array.length === 0) ? null : array[0];
52f515c6 19 }
a0214785
TO
20
21 return {
22 getAll: function getAll() {
23 return addrs;
24 },
25 getByAuthorEmail: function getByAuthorEmail(author, email, autocreate) {
26 var result = null;
f4f103fa 27 _.each(addrs, function (addr) {
a0214785
TO
28 if (addr.author == author && addr.email == email) {
29 result = addr;
30 }
31 });
32 if (!result && autocreate) {
33 result = {
34 label: '(INVALID) "' + author + '" <' + email + '>',
35 author: author,
36 email: email
37 };
38 addrs.push(result);
39 }
40 return result;
41 },
42 getByEmail: function getByEmail(email) {
43 return first(_.where(addrs, {email: email}));
44 },
f4f103fa 45 getByLabel: function (label) {
a0214785
TO
46 return first(_.where(addrs, {label: label}));
47 },
48 getDefault: function getDefault() {
49 return first(_.where(addrs, {is_default: "1"}));
50 }
51 };
52 });
53
88e9e883 54 angular.module('crmMailing').factory('crmMsgTemplates', function ($q, crmApi) {
f4f103fa 55 var tpls = _.map(CRM.crmMailing.mesTemplate, function (tpl) {
86c3a327 56 return angular.extend({}, tpl, {
744bebee
TO
57 //id: tpl parseInt(tpl.id)
58 });
59 });
60 window.tpls = tpls;
61 var lastModifiedTpl = null;
62 return {
3637550f
SL
63 // Get a template
64 // @param id MessageTemplate id (per APIv3)
744bebee
TO
65 // @return Promise MessageTemplate (per APIv3)
66 get: function get(id) {
ad51ce06 67 return crmApi('MessageTemplate', 'getsingle', {
3637550f
SL
68 "return": "id,msg_subject,msg_html,msg_title,msg_text",
69 "id": id
3637550f 70 });
744bebee
TO
71 },
72 // Save a template
73 // @param tpl MessageTemplate (per APIv3) For new templates, omit "id"
74 // @return Promise MessageTemplate (per APIv3)
f4f103fa
TO
75 save: function (tpl) {
76 return crmApi('MessageTemplate', 'create', tpl).then(function (response) {
744bebee 77 if (!tpl.id) {
f4f103fa 78 tpl.id = '' + response.id; //parseInt(response.id);
744bebee
TO
79 tpls.push(tpl);
80 }
f2bad133 81 lastModifiedTpl = tpl;
744bebee
TO
82 return tpl;
83 });
84 },
85 // @return Object MessageTemplate (per APIv3)
f4f103fa 86 getLastModifiedTpl: function () {
744bebee
TO
87 return lastModifiedTpl;
88 },
89 getAll: function getAll() {
90 return tpls;
91 }
92 };
93 });
94
a0214785 95 // The crmMailingMgr service provides business logic for loading, saving, previewing, etc
36768f7e
TO
96 angular.module('crmMailing').factory('crmMailingMgr', function ($q, crmApi, crmFromAddresses, crmQueue) {
97 var qApi = crmQueue(crmApi);
4dd19229 98 var pickDefaultMailComponent = function pickDefaultMailComponent(type) {
8dfd5110 99 var mcs = _.where(CRM.crmMailing.headerfooterList, {
f4f103fa 100 component_type: type,
8dfd5110
TO
101 is_default: "1"
102 });
103 return (mcs.length >= 1) ? mcs[0].id : null;
104 };
105
106 return {
107 // @param scalar idExpr a number or the literal string 'new'
108 // @return Promise|Object Mailing (per APIv3)
4dd19229 109 getOrCreate: function getOrCreate(idExpr) {
8dfd5110
TO
110 return (idExpr == 'new') ? this.create() : this.get(idExpr);
111 },
112 // @return Promise Mailing (per APIv3)
4dd19229 113 get: function get(id) {
86c3a327
TO
114 var crmMailingMgr = this;
115 var mailing;
36768f7e 116 return qApi('Mailing', 'getsingle', {id: id})
86c3a327
TO
117 .then(function (getResult) {
118 mailing = getResult;
119 return $q.all([
120 crmMailingMgr._loadGroups(mailing),
121 crmMailingMgr._loadJobs(mailing)
122 ]);
123 })
124 .then(function () {
125 return mailing;
126 });
127 },
128 // Call MailingGroup.get and merge results into "mailing"
129 _loadGroups: function (mailing) {
dd75b22c 130 return crmApi('MailingGroup', 'get', {mailing_id: mailing.id, 'options': {'limit':0}})
86c3a327 131 .then(function (groupResult) {
9cd4f489 132 mailing.recipients = {};
720c658b 133 mailing.recipients.groups = {include: [], exclude: [], base: []};
9cd4f489 134 mailing.recipients.mailings = {include: [], exclude: []};
f4f103fa 135 _.each(groupResult.values, function (mailingGroup) {
f78abdbe 136 var bucket = (/^civicrm_group/.test(mailingGroup.entity_table)) ? 'groups' : 'mailings';
89a50c67 137 var entityId = parseInt(mailingGroup.entity_id);
9cd4f489 138 mailing.recipients[bucket][mailingGroup.group_type.toLowerCase()].push(entityId);
8dfd5110 139 });
8dfd5110 140 });
86c3a327
TO
141 },
142 // Call MailingJob.get and merge results into "mailing"
143 _loadJobs: function (mailing) {
144 return crmApi('MailingJob', 'get', {mailing_id: mailing.id, is_test: 0})
145 .then(function (jobResult) {
146 mailing.jobs = mailing.jobs || {};
147 angular.extend(mailing.jobs, jobResult.values);
148 });
8dfd5110
TO
149 },
150 // @return Object Mailing (per APIv3)
657b8692
TO
151 create: function create(params) {
152 var defaults = {
86c3a327 153 jobs: {}, // {jobId: JobRecord}
9cd4f489 154 recipients: {
720c658b
TO
155 groups: {include: [], exclude: [], base: []},
156 mailings: {include: [], exclude: []}
9cd4f489 157 },
3ac6e107
TO
158 template_type: "traditional",
159 // Workaround CRM-19756 w/template_options.nonce
160 template_options: {nonce: 1},
d78cc635 161 name: "",
8dfd5110 162 campaign_id: null,
8dfd5110 163 replyto_email: "",
d78cc635 164 subject: "",
13782061 165 body_html: "",
657b8692 166 body_text: ""
8dfd5110 167 };
657b8692 168 return angular.extend({}, defaults, params);
8dfd5110
TO
169 },
170
705c61e9
TO
171 // @param mailing Object (per APIv3)
172 // @return Promise
f4f103fa 173 'delete': function (mailing) {
705c61e9 174 if (mailing.id) {
36768f7e 175 return qApi('Mailing', 'delete', {id: mailing.id});
f4f103fa
TO
176 }
177 else {
705c61e9
TO
178 var d = $q.defer();
179 d.resolve();
180 return d.promise;
181 }
182 },
183
21fb26b8
TO
184 // Search the body, header, and footer for required tokens.
185 // ex: var msgs = findMissingTokens(mailing, 'body_html');
186 findMissingTokens: function(mailing, field) {
187 var missing = {};
d124a91f 188 if (!_.isEmpty(mailing[field]) && !CRM.crmMailing.disableMandatoryTokensCheck) {
21fb26b8
TO
189 var body = '';
190 if (mailing.footer_id) {
191 var footer = _.where(CRM.crmMailing.headerfooterList, {id: mailing.footer_id});
192 body = body + footer[0][field];
193
194 }
195 body = body + mailing[field];
196 if (mailing.header_id) {
197 var header = _.where(CRM.crmMailing.headerfooterList, {id: mailing.header_id});
198 body = body + header[0][field];
199 }
200
201 angular.forEach(CRM.crmMailing.requiredTokens, function(value, token) {
202 if (!_.isObject(value)) {
203 if (body.indexOf('{' + token + '}') < 0) {
204 missing[token] = value;
205 }
206 }
207 else {
208 var count = 0;
209 angular.forEach(value, function(nestedValue, nestedToken) {
210 if (body.indexOf('{' + nestedToken + '}') >= 0) {
211 count++;
212 }
213 });
d03e0d13 214 if (count === 0) {
21fb26b8
TO
215 angular.extend(missing, value);
216 }
217 }
218 });
219 }
220 return missing;
221 },
222
07fa6426
TO
223 // Copy all data fields in (mailingFrom) to (mailingTgt) -- except for (excludes)
224 // ex: crmMailingMgr.mergeInto(newMailing, mailingTemplate, ['subject']);
225 mergeInto: function mergeInto(mailingTgt, mailingFrom, excludes) {
226 var MAILING_FIELDS = [
70980d8e 227 // always exclude: 'id'
07fa6426
TO
228 'name',
229 'campaign_id',
230 'from_name',
231 'from_email',
232 'replyto_email',
233 'subject',
234 'dedupe_email',
9cd4f489 235 'recipients',
07fa6426
TO
236 'body_html',
237 'body_text',
238 'footer_id',
239 'header_id',
240 'visibility',
241 'url_tracking',
242 'dedupe_email',
243 'forward_replies',
244 'auto_responder',
245 'open_tracking',
246 'override_verp',
247 'optout_id',
248 'reply_id',
249 'resubscribe_id',
250 'unsubscribe_id'
251 ];
252 if (!excludes) {
253 excludes = [];
254 }
255 _.each(MAILING_FIELDS, function (field) {
256 if (!_.contains(excludes, field)) {
257 mailingTgt[field] = mailingFrom[field];
258 }
f2bad133 259 });
07fa6426
TO
260 },
261
493eb47a
TO
262 // @param mailing Object (per APIv3)
263 // @return Promise an object with "subject", "body_text", "body_html"
264 preview: function preview(mailing) {
0075b0cb 265 return this.getPreviewContent(qApi, mailing);
24689c79 266 },
267
268 // @param backend
269 // @param mailing Object (per APIv3)
270 // @return preview content
271 getPreviewContent: function getPreviewContent(backend, mailing) {
360d6097 272 if (CRM.crmMailing.workflowEnabled && !CRM.checkPerm('create mailings') && !CRM.checkPerm('access CiviMail')) {
24689c79 273 return backend('Mailing', 'preview', {id: mailing.id}).then(function(result) {
3efe22a0
TO
274 return result.values;
275 });
276 }
277 else {
0075b0cb 278 var params = angular.extend({}, mailing);
279 delete params.id;
280 return backend('Mailing', 'preview', params).then(function(result) {
3efe22a0 281 // changes rolled back, so we don't care about updating mailing
0075b0cb 282 return result.values;
3efe22a0
TO
283 });
284 }
493eb47a
TO
285 },
286
8dfd5110
TO
287 // @param mailing Object (per APIv3)
288 // @param int previewLimit
289 // @return Promise for a list of recipients (mailing_id, contact_id, api.contact.getvalue, api.email.getvalue)
4dd19229 290 previewRecipients: function previewRecipients(mailing, previewLimit) {
8dfd5110
TO
291 // To get list of recipients, we tentatively save the mailing and
292 // get the resulting recipients -- then rollback any changes.
6dd717a6 293 var params = angular.extend({}, mailing.recipients, {
294 id: mailing.id,
8dfd5110
TO
295 'api.MailingRecipients.get': {
296 mailing_id: '$value.id',
58dfba8d 297 options: {limit: previewLimit},
8dfd5110
TO
298 'api.contact.getvalue': {'return': 'display_name'},
299 'api.email.getvalue': {'return': 'email'}
300 }
301 });
80955669 302 delete params.scheduled_date;
9cd4f489 303 delete params.recipients; // the content was merged in
36768f7e 304 return qApi('Mailing', 'create', params).then(function (recipResult) {
beab9d1b 305 // changes rolled back, so we don't care about updating mailing
2fc6d711 306 mailing.modified_date = recipResult.values[recipResult.id].modified_date;
8dfd5110
TO
307 return recipResult.values[recipResult.id]['api.MailingRecipients.get'].values;
308 });
beab9d1b
TO
309 },
310
7a646a01 311 previewRecipientCount: function previewRecipientCount(mailing, crmMailingCache, rebuild) {
312 var cachekey = 'mailing-' + mailing.id + '-recipient-count';
313 var recipientCount = crmMailingCache.get(cachekey);
314 if (rebuild || _.isEmpty(recipientCount)) {
315 // To get list of recipients, we tentatively save the mailing and
316 // get the resulting recipients -- then rollback any changes.
317 var params = angular.extend({}, mailing, mailing.recipients, {
6dd717a6 318 id: mailing.id,
7a646a01 319 'api.MailingRecipients.getcount': {
320 mailing_id: '$value.id'
321 }
322 });
323 // if this service is executed on rebuild then also fetch the recipients list
324 if (rebuild) {
325 params = angular.extend(params, {
326 'api.MailingRecipients.get': {
327 mailing_id: '$value.id',
328 options: {limit: 50},
329 'api.contact.getvalue': {'return': 'display_name'},
330 'api.email.getvalue': {'return': 'email'}
331 }
332 });
333 crmMailingCache.put('mailing-' + mailing.id + '-recipient-params', params.recipients);
79d21cce 334 }
80955669 335 delete params.scheduled_date;
7a646a01 336 delete params.recipients; // the content was merged in
337 recipientCount = qApi('Mailing', 'create', params).then(function (recipResult) {
338 // changes rolled back, so we don't care about updating mailing
339 mailing.modified_date = recipResult.values[recipResult.id].modified_date;
340 if (rebuild) {
341 crmMailingCache.put('mailing-' + mailing.id + '-recipient-list', recipResult.values[recipResult.id]['api.MailingRecipients.get'].values);
342 }
343 return recipResult.values[recipResult.id]['api.MailingRecipients.getcount'];
344 });
345 crmMailingCache.put(cachekey, recipientCount);
346 }
347
348 return recipientCount;
79d21cce
TO
349 },
350
43102e47 351 // Save a (draft) mailing
705c61e9
TO
352 // @param mailing Object (per APIv3)
353 // @return Promise
d78cc635 354 save: function(mailing) {
9cd4f489 355 var params = angular.extend({}, mailing, mailing.recipients);
43102e47 356
d78cc635
TO
357 // Angular ngModel sometimes treats blank fields as undefined.
358 angular.forEach(mailing, function(value, key) {
e72949ef 359 if (value === undefined || value === null) {
d78cc635
TO
360 mailing[key] = '';
361 }
362 });
363
43102e47
TO
364 // WORKAROUND: Mailing.create (aka CRM_Mailing_BAO_Mailing::create()) interprets scheduled_date
365 // as an *intent* to schedule and creates tertiary records. Saving a draft with a scheduled_date
366 // is therefore not allowed. Remove this after fixing Mailing.create's contract.
367 delete params.scheduled_date;
368
86c3a327
TO
369 delete params.jobs;
370
9cd4f489 371 delete params.recipients; // the content was merged in
d0d7fea5 372 params._skip_evil_bao_auto_recipients_ = 1; // skip recipient rebuild on simple save
36768f7e 373 return qApi('Mailing', 'create', params).then(function(result) {
f4f103fa
TO
374 if (result.id && !mailing.id) {
375 mailing.id = result.id;
376 } // no rollback, so update mailing.id
43102e47 377 // Perhaps we should reload mailing based on result?
2fc6d711 378 mailing.modified_date = result.values[result.id].modified_date;
86c3a327 379 return mailing;
705c61e9
TO
380 });
381 },
382
383 // Schedule/send the mailing
384 // @param mailing Object (per APIv3)
385 // @return Promise
43102e47 386 submit: function (mailing) {
86c3a327 387 var crmMailingMgr = this;
6818346a
TO
388 var params = {
389 id: mailing.id,
d3312ed5 390 approval_date: 'now',
391 scheduled_date: mailing.scheduled_date ? mailing.scheduled_date : 'now'
43102e47 392 };
36768f7e 393 return qApi('Mailing', 'submit', params)
86c3a327
TO
394 .then(function (result) {
395 angular.extend(mailing, result.values[result.id]); // Perhaps we should reload mailing based on result?
396 return crmMailingMgr._loadJobs(mailing);
397 })
398 .then(function () {
399 return mailing;
400 });
705c61e9
TO
401 },
402
403 // Immediately send a test message
beab9d1b 404 // @param mailing Object (per APIv3)
58dfba8d 405 // @param to Object with either key "email" (string) or "gid" (int)
beab9d1b 406 // @return Promise for a list of delivery reports
58dfba8d 407 sendTest: function (mailing, recipient) {
9cd4f489 408 var params = angular.extend({}, mailing, mailing.recipients, {
43102e47 409 // options: {force_rollback: 1}, // Test mailings include tracking features, so the mailing must be persistent
beab9d1b
TO
410 'api.Mailing.send_test': {
411 mailing_id: '$value.id',
58dfba8d
TO
412 test_email: recipient.email,
413 test_group: recipient.gid
beab9d1b
TO
414 }
415 });
43102e47
TO
416
417 // WORKAROUND: Mailing.create (aka CRM_Mailing_BAO_Mailing::create()) interprets scheduled_date
418 // as an *intent* to schedule and creates tertiary records. Saving a draft with a scheduled_date
419 // is therefore not allowed. Remove this after fixing Mailing.create's contract.
420 delete params.scheduled_date;
421
86c3a327
TO
422 delete params.jobs;
423
9cd4f489
TO
424 delete params.recipients; // the content was merged in
425
d0d7fea5 426 params._skip_evil_bao_auto_recipients_ = 1; // skip recipient rebuild while sending test mail
427
36768f7e 428 return qApi('Mailing', 'create', params).then(function (result) {
f4f103fa
TO
429 if (result.id && !mailing.id) {
430 mailing.id = result.id;
431 } // no rollback, so update mailing.id
2fc6d711 432 mailing.modified_date = result.values[result.id].modified_date;
beab9d1b
TO
433 return result.values[result.id]['api.Mailing.send_test'].values;
434 });
8dfd5110
TO
435 }
436 };
437 });
58dfba8d
TO
438
439 // The preview manager performs preview actions while putting up a visible UI (e.g. dialogs & status alerts)
440 angular.module('crmMailing').factory('crmMailingPreviewMgr', function (dialogService, crmMailingMgr, crmStatus) {
441 return {
442 // @param mode string one of 'html', 'text', or 'full'
443 // @return Promise
444 preview: function preview(mailing, mode) {
445 var templates = {
fd9c35ce
TO
446 html: '~/crmMailing/PreviewMgr/html.html',
447 text: '~/crmMailing/PreviewMgr/text.html',
448 full: '~/crmMailing/PreviewMgr/full.html'
58dfba8d
TO
449 };
450 var result = null;
451 var p = crmMailingMgr
24689c79 452 .getPreviewContent(CRM.api3, mailing)
58dfba8d 453 .then(function (content) {
b1fc510d 454 var options = CRM.utils.adjustDialogDefaults({
58dfba8d 455 autoOpen: false,
58dfba8d
TO
456 title: ts('Subject: %1', {
457 1: content.subject
458 })
b1fc510d 459 });
58dfba8d
TO
460 result = dialogService.open('previewDialog', templates[mode], content, options);
461 });
46233df6 462 crmStatus({start: ts('Previewing...'), success: ''}, p);
58dfba8d
TO
463 return result;
464 },
465
466 // @param to Object with either key "email" (string) or "gid" (int)
467 // @return Promise
468 sendTest: function sendTest(mailing, recipient) {
469 var promise = crmMailingMgr.sendTest(mailing, recipient)
470 .then(function (deliveryInfos) {
471 var count = Object.keys(deliveryInfos).length;
472 if (count === 0) {
302e4e03 473 CRM.alert(ts('Could not identify any recipients. Perhaps your test group is empty, or you tried sending to contacts that do not exist and you have no permission to add contacts.'));
58dfba8d
TO
474 }
475 })
476 ;
477 return crmStatus({start: ts('Sending...'), success: ts('Sent')}, promise);
478 }
479 };
480 });
481
7173e315
TO
482 angular.module('crmMailing').factory('crmMailingStats', function (crmApi, crmLegacy) {
483 var statTypes = [
78414681
SL
484 // {name: 'Recipients', title: ts('Intended Recipients'), searchFilter: '', eventsFilter: '&event=queue', reportType: 'detail', reportFilter: ''},
485 {name: 'Delivered', title: ts('Successful Deliveries'), searchFilter: '&mailing_delivery_status=Y', eventsFilter: '&event=delivered', reportType: 'detail', reportFilter: '&delivery_status_value=successful'},
486 {name: 'Opened', title: ts('Tracked Opens'), searchFilter: '&mailing_open_status=Y', eventsFilter: '&event=opened', reportType: 'opened', reportFilter: ''},
487 {name: 'Unique Clicks', title: ts('Click-throughs'), searchFilter: '&mailing_click_status=Y', eventsFilter: '&event=click&distinct=1', reportType: 'clicks', reportFilter: ''},
488 // {name: 'Forward', title: ts('Forwards'), searchFilter: '&mailing_forward=1', eventsFilter: '&event=forward', reportType: 'detail', reportFilter: '&is_forwarded_value=1'},
489 // {name: 'Replies', title: ts('Replies'), searchFilter: '&mailing_reply_status=Y', eventsFilter: '&event=reply', reportType: 'detail', reportFilter: '&is_replied_value=1'},
490 {name: 'Bounces', title: ts('Bounces'), searchFilter: '&mailing_delivery_status=N', eventsFilter: '&event=bounce', reportType: 'bounce', reportFilter: ''},
491 {name: 'Unsubscribers', title: ts('Unsubscribes'), searchFilter: '&mailing_unsubscribe=1', eventsFilter: '&event=unsubscribe', reportType: 'detail', reportFilter: '&is_unsubscribed_value=1'},
492 // {name: 'OptOuts', title: ts('Opt-Outs'), searchFilter: '&mailing_optout=1', eventsFilter: '&event=optout', reportType: 'detail', reportFilter: ''}
7173e315
TO
493 ];
494
495 return {
496 getStatTypes: function() {
497 return statTypes;
498 },
499
500 /**
501 * @param mailingIds object
502 * List of mailing IDs ({a: 123, b: 456})
503 * @return Promise
504 * List of stats for each mailing
505 * ({a: ...object..., b: ...object...})
506 */
507 getStats: function(mailingIds) {
508 var params = {};
509 angular.forEach(mailingIds, function(mailingId, name) {
b4486604 510 params[name] = ['Mailing', 'stats', {mailing_id: mailingId, is_distinct: 0}];
7173e315
TO
511 });
512 return crmApi(params).then(function(result) {
513 var stats = {};
514 angular.forEach(mailingIds, function(mailingId, name) {
515 stats[name] = result[name].values[mailingId];
516 });
517 return stats;
518 });
519 },
520
521 /**
522 * Determine the legacy URL for a report about a given mailing and stat.
523 *
524 * @param mailing object
525 * @param statType object (see statTypes above)
526 * @param view string ('search', 'event', 'report')
05381a97 527 * @param returnPath string|null Return path (relative to Angular base)
7173e315
TO
528 * @return string|null
529 */
05381a97 530 getUrl: function getUrl(mailing, statType, view, returnPath) {
7173e315
TO
531 switch (view) {
532 case 'events':
05381a97 533 var retParams = returnPath ? '&context=angPage&angPage=' + returnPath : '';
7173e315 534 return crmLegacy.url('civicrm/mailing/report/event',
05381a97 535 'reset=1&mid=' + mailing.id + statType.eventsFilter + retParams);
7173e315
TO
536 case 'search':
537 return crmLegacy.url('civicrm/contact/search/advanced',
538 'force=1&mailing_id=' + mailing.id + statType.searchFilter);
78414681 539 case 'report':
b4fdf77a 540 var reportIds = CRM.crmMailing.reportIds;
78414681
SL
541 return crmLegacy.url('civicrm/report/instance/' + reportIds[statType.reportType],
542 'reset=1&mailing_id_value=' + mailing.id + statType.reportFilter);
7173e315
TO
543 default:
544 return null;
545 }
546 }
547 };
548 });
549
e908a393
TO
550 // crmMailingSimpleDirective is a template/factory-function for constructing very basic
551 // directives that accept a "mailing" argument. Please don't overload it. If one continues building
552 // this, it risks becoming a second system that violates Angular architecture (and prevents one
553 // from using standard Angular docs+plugins). So this really shouldn't do much -- it is really
554 // only for simple directives. For something complex, suck it up and write 10 lines of boilerplate.
555 angular.module('crmMailing').factory('crmMailingSimpleDirective', function ($q, crmMetadata, crmUiHelp) {
556 return function crmMailingSimpleDirective(directiveName, templateUrl) {
557 return {
558 scope: {
559 crmMailing: '@'
560 },
561 templateUrl: templateUrl,
562 link: function (scope, elm, attr) {
563 scope.$parent.$watch(attr.crmMailing, function(newValue){
564 scope.mailing = newValue;
565 });
566 scope.crmMailingConst = CRM.crmMailing;
567 scope.ts = CRM.ts(null);
568 scope.hs = crmUiHelp({file: 'CRM/Mailing/MailingUI'});
569 scope[directiveName] = attr[directiveName] ? scope.$parent.$eval(attr[directiveName]) : {};
570 $q.when(crmMetadata.getFields('Mailing'), function(fields) {
571 scope.mailingFields = fields;
572 });
573 }
574 };
575 };
576 });
577
7a646a01 578 angular.module('crmMailing').factory('crmMailingCache', ['$cacheFactory', function($cacheFactory) {
579 return $cacheFactory('crmMailingCache');
580 }]);
581
8dfd5110 582})(angular, CRM.$, CRM._);