1 (function (angular
, $, _
) {
3 var partialUrl = function (relPath
, module
) {
5 module
= 'crmMailingAB';
7 return CRM
.resourceUrls
.civicrm
+ '/partials/' + module
+ '/' + relPath
;
10 angular
.module('crmMailingAB', ['ngRoute', 'ui.utils', 'ngSanitize', 'crmUi', 'crmAttachment', 'crmMailing', 'crmD3']);
11 angular
.module('crmMailingAB').config([
13 function ($routeProvider
) {
14 $routeProvider
.when('/abtest', {
15 templateUrl
: partialUrl('list.html'),
16 controller
: 'CrmMailingABListCtrl',
18 mailingABList: function ($route
, crmApi
) {
19 return crmApi('MailingAB', 'get', {rowCount
: 0});
23 $routeProvider
.when('/abtest/:id', {
24 templateUrl
: partialUrl('edit.html'),
25 controller
: 'CrmMailingABEditCtrl',
27 abtest: function ($route
, CrmMailingAB
) {
28 var abtest
= new CrmMailingAB($route
.current
.params
.id
== 'new' ? null : $route
.current
.params
.id
);
33 $routeProvider
.when('/abtest/:id/report', {
34 templateUrl
: partialUrl('report.html'),
35 controller
: 'CrmMailingABReportCtrl',
37 abtest: function ($route
, CrmMailingAB
) {
38 var abtest
= new CrmMailingAB($route
.current
.params
.id
);
46 angular
.module('crmMailingAB').controller('CrmMailingABListCtrl', function ($scope
, mailingABList
, crmMailingABCriteria
, crmMailingABStatus
) {
47 var ts
= $scope
.ts
= CRM
.ts('CiviMail');
48 $scope
.mailingABList
= mailingABList
.values
;
49 $scope
.crmMailingABCriteria
= crmMailingABCriteria
;
50 $scope
.crmMailingABStatus
= crmMailingABStatus
;
53 angular
.module('crmMailingAB').controller('CrmMailingABEditCtrl', function ($scope
, abtest
, crmMailingABCriteria
, crmMailingMgr
, crmMailingPreviewMgr
, crmStatus
, $q
, $location
) {
54 $scope
.abtest
= abtest
;
55 var ts
= $scope
.ts
= CRM
.ts('CiviMail');
56 $scope
.crmMailingABCriteria
= crmMailingABCriteria
;
57 $scope
.crmMailingConst
= CRM
.crmMailing
;
58 $scope
.partialUrl
= partialUrl
;
60 $scope
.isSubmitted
= function isSubmitted() {
61 return _
.size(abtest
.mailings
.a
.jobs
) > 0 || _
.size(abtest
.mailings
.b
.jobs
) > 0;
64 $scope
.sync
= function sync() {
65 abtest
.mailings
.a
.name
= ts('Test A (%1)', {1: abtest
.ab
.name
});
66 abtest
.mailings
.b
.name
= ts('Test B (%1)', {1: abtest
.ab
.name
});
67 abtest
.mailings
.c
.name
= ts('Winner (%1)', {1: abtest
.ab
.name
});
69 var criteria
= crmMailingABCriteria
.get(abtest
.ab
.testing_criteria_id
);
71 // TODO review fields exposed in UI and make sure the sync rules match
72 switch (criteria
.name
) {
74 crmMailingMgr
.mergeInto(abtest
.mailings
.b
, abtest
.mailings
.a
, [
82 crmMailingMgr
.mergeInto(abtest
.mailings
.b
, abtest
.mailings
.a
, [
90 case 'Two different emails':
91 crmMailingMgr
.mergeInto(abtest
.mailings
.b
, abtest
.mailings
.a
, [
103 throw "Unrecognized testing_criteria";
106 crmMailingMgr
.mergeInto(abtest
.mailings
.c
, abtest
.mailings
.a
, ['name']);
107 return $q
.when(true);
111 $scope
.save
= function save() {
113 return crmStatus({start
: ts('Saving...'), success
: ts('Saved')}, abtest
.save().then(updateUrl
));
117 $scope
.previewMailing
= function previewMailing(mailingName
, mode
) {
119 return crmMailingPreviewMgr
.preview(abtest
.mailings
[mailingName
], mode
);
123 $scope
.sendTest
= function sendTest(mailingName
, recipient
) {
125 return crmStatus({start
: ts('Saving...'), success
: ''}, abtest
.save().then(updateUrl
))
127 crmMailingPreviewMgr
.sendTest(abtest
.mailings
[mailingName
], recipient
);
132 $scope
.delete = function () {
133 return crmStatus({start
: ts('Deleting...'), success
: ts('Deleted')}, abtest
.delete().then(leave
));
137 $scope
.submit
= function submit() {
139 return crmStatus({start
: ts('Saving...'), success
: ''}, abtest
.save())
141 return crmStatus({start
: ts('Submitting...'), success
: ts('Submitted')}, abtest
.submitTest());
142 // Note: We're going to leave, so we don't care that submit() modifies several server-side records.
143 // If we stayed on this page, then we'd care about updating and call: abtest.submitTest().then(...abtest.load()...)
149 $location
.path('abtest');
153 function updateCriteriaName() {
154 var criteria
= crmMailingABCriteria
.get($scope
.abtest
.ab
.testing_criteria_id
);
155 $scope
.criteriaName
= criteria
? criteria
.name
: null;
158 // Transition URL "/abtest/new" => "/abtest/123"
159 function updateUrl() {
160 var parts
= $location
.path().split('/'); // e.g. "/abtest/new" or "/abtest/123/wizard"
161 if (parts
[2] != $scope
.abtest
.ab
.id
) {
162 parts
[2] = $scope
.abtest
.ab
.id
;
163 $location
.path(parts
.join('/'));
165 // FIXME: Angular unnecessarily refreshes UI
166 // WARNING: Changing the URL triggers a full reload. Any pending AJAX operations
167 // could be inconsistently applied. Run updateUrl() after other changes complete.
172 updateCriteriaName();
174 $scope
.$watch('abtest.ab.testing_criteria_id', updateCriteriaName
);
177 angular
.module('crmMailingAB').controller('CrmMailingABReportCtrl', function ($scope
, abtest
, crmApi
, crmMailingPreviewMgr
, dialogService
) {
178 var ts
= $scope
.ts
= CRM
.ts('CiviMail');
180 $scope
.abtest
= abtest
;
183 crmApi('Mailing', 'stats', {mailing_id
: abtest
.ab
.mailing_id_a
}).then(function(data
){
184 $scope
.stats
.a
= data
.values
[abtest
.ab
.mailing_id_a
];
186 crmApi('Mailing', 'stats', {mailing_id
: abtest
.ab
.mailing_id_b
}).then(function(data
){
187 $scope
.stats
.b
= data
.values
[abtest
.ab
.mailing_id_b
];
189 crmApi('Mailing', 'stats', {mailing_id
: abtest
.ab
.mailing_id_c
}).then(function(data
){
190 $scope
.stats
.c
= data
.values
[abtest
.ab
.mailing_id_c
];
193 $scope
.previewMailing
= function previewMailing(mailingName
, mode
) {
194 return crmMailingPreviewMgr
.preview(abtest
.mailings
[mailingName
], mode
);
196 $scope
.selectWinner
= function selectWinner(mailingName
) {
199 mailingName
: mailingName
204 title
: ts('Select Winner (%1)', {
205 1: mailingName
.toUpperCase()
208 return dialogService
.open('selectWinnerDialog', partialUrl('selectWinner.html'), model
, options
);
213 angular
.module('crmMailingAB').controller('CrmMailingABWinnerDialogCtrl', function ($scope
, $timeout
, dialogService
, crmMailingMgr
, crmStatus
) {
214 var ts
= $scope
.ts
= CRM
.ts('CiviMail');
215 var abtest
= $scope
.abtest
= $scope
.model
.abtest
;
216 var mailingName
= $scope
.model
.mailingName
;
218 var titles
= {a
: ts('Mailing A'), b
: ts('Mailing B')};
219 $scope
.mailingTitle
= titles
[mailingName
];
222 // When using dialogService with a button bar, the major button actions
223 // need to be registered with the dialog widget (and not embedded in
224 // the body of the dialog).
226 buttons
[ts('Select Winner')] = function () {
227 crmMailingMgr
.mergeInto(abtest
.mailings
.c
, abtest
.mailings
[mailingName
], [
233 crmStatus({start
: ts('Saving...'), success
: ''}, abtest
.save())
235 return crmStatus({start
: ts('Submitting...'), success
: ts('Submitted')},
236 abtest
.submitFinal().then(function(){
237 return abtest
.load();
241 dialogService
.close('selectWinnerDialog', abtest
);
244 buttons
[ts('Cancel')] = function () {
245 dialogService
.cancel('selectWinnerDialog');
247 dialogService
.setButtons('selectWinnerDialog', buttons
);
253 })(angular
, CRM
.$, CRM
._
);