1 (function (angular
, $, _
) {
3 angular
.module('crmMailingAB', ['ngRoute', 'ui.utils', 'crmUi', 'crmAttachment', 'crmMailing', 'crmD3']);
4 angular
.module('crmMailingAB').config([
6 function ($routeProvider
) {
7 $routeProvider
.when('/abtest', {
8 templateUrl
: '~/crmMailingAB/list.html',
9 controller
: 'CrmMailingABListCtrl',
11 mailingABList: function ($route
, crmApi
) {
12 return crmApi('MailingAB', 'get', {rowCount
: 0});
14 fields: function(crmMetadata
){
15 return crmMetadata
.getFields('MailingAB');
19 $routeProvider
.when('/abtest/new', {
20 template
: '<p>' + ts('Initializing...') + '</p>',
21 controller
: 'CrmMailingABNewCtrl',
23 abtest: function ($route
, CrmMailingAB
) {
24 var abtest
= new CrmMailingAB(null);
25 return abtest
.load().then(function(){
31 $routeProvider
.when('/abtest/:id', {
32 templateUrl
: '~/crmMailingAB/main.html',
33 controller
: 'CrmMailingABEditCtrl',
35 abtest: function ($route
, CrmMailingAB
) {
36 var abtest
= new CrmMailingAB($route
.current
.params
.id
== 'new' ? null : $route
.current
.params
.id
);
44 angular
.module('crmMailingAB').controller('CrmMailingABListCtrl', function($scope
, mailingABList
, crmMailingABCriteria
, crmMailingABStatus
, fields
) {
45 var ts
= $scope
.ts
= CRM
.ts(null);
46 $scope
.mailingABList
= _
.values(mailingABList
.values
);
47 $scope
.crmMailingABCriteria
= crmMailingABCriteria
;
48 $scope
.crmMailingABStatus
= crmMailingABStatus
;
49 $scope
.fields
= fields
;
53 angular
.module('crmMailingAB').controller('CrmMailingABNewCtrl', function ($scope
, abtest
, $location
) {
54 // Transition URL "/abtest/new/foo" => "/abtest/123/foo"
55 var parts
= $location
.path().split('/'); // e.g. "/mailing/new" or "/mailing/123/wizard"
57 $location
.path(parts
.join('/'));
61 angular
.module('crmMailingAB').controller('CrmMailingABEditCtrl', function ($scope
, abtest
, crmMailingABCriteria
, crmMailingMgr
, crmMailingPreviewMgr
, crmStatus
, $q
, $location
, crmBlocker
, $interval
, $timeout
, CrmAutosaveCtrl
, dialogService
) {
62 $scope
.abtest
= abtest
;
63 var ts
= $scope
.ts
= CRM
.ts(null);
64 var block
= $scope
.block
= crmBlocker();
65 $scope
.crmUrl
= CRM
.url
;
66 var myAutosave
= null;
67 $scope
.crmMailingABCriteria
= crmMailingABCriteria
;
68 $scope
.crmMailingConst
= CRM
.crmMailing
;
69 $scope
.checkPerm
= CRM
.checkPerm
;
71 $scope
.isSubmitted
= function isSubmitted() {
72 return _
.size(abtest
.mailings
.a
.jobs
) > 0 || _
.size(abtest
.mailings
.b
.jobs
) > 0;
75 $scope
.sync
= function sync() {
76 abtest
.mailings
.a
.name
= ts('Test A (%1)', {1: abtest
.ab
.name
});
77 abtest
.mailings
.b
.name
= ts('Test B (%1)', {1: abtest
.ab
.name
});
78 abtest
.mailings
.c
.name
= ts('Final (%1)', {1: abtest
.ab
.name
});
80 if (abtest
.ab
.testing_criteria
) {
81 // TODO review fields exposed in UI and make sure the sync rules match
82 switch (abtest
.ab
.testing_criteria
) {
84 crmMailingMgr
.mergeInto(abtest
.mailings
.b
, abtest
.mailings
.a
, [
91 crmMailingMgr
.mergeInto(abtest
.mailings
.b
, abtest
.mailings
.a
, [
99 crmMailingMgr
.mergeInto(abtest
.mailings
.b
, abtest
.mailings
.a
, [
106 'override_verp', // keep override_verp and replyto_Email linked
112 throw "Unrecognized testing_criteria";
115 crmMailingMgr
.mergeInto(abtest
.mailings
.c
, abtest
.mailings
.a
, ['name']);
120 $scope
.save
= function save() {
121 return block(crmStatus({start
: ts('Saving...'), success
: ts('Saved')}, abtest
.save()));
125 $scope
.previewMailing
= function previewMailing(mailingName
, mode
) {
126 return crmMailingPreviewMgr
.preview(abtest
.mailings
[mailingName
], mode
);
130 $scope
.sendTest
= function sendTest(mailingName
, recipient
) {
131 return block(crmStatus({start
: ts('Saving...'), success
: ''}, abtest
.save())
133 crmMailingPreviewMgr
.sendTest(abtest
.mailings
[mailingName
], recipient
);
138 $scope
.delete = function () {
139 return block(crmStatus({start
: ts('Deleting...'), success
: ts('Deleted')}, abtest
.delete().then($scope
.leave
)));
143 $scope
.submit
= function submit() {
144 if (block
.check() || $scope
.crmMailingAB
.$invalid
) {
147 return block(crmStatus({start
: ts('Saving...'), success
: ''}, abtest
.save())
149 return crmStatus({start
: ts('Submitting...'), success
: ts('Submitted')}, myAutosave
.suspend(abtest
.submitTest()));
150 // Note: We're going to leave, so we don't care that submit() modifies several server-side records.
151 // If we stayed on this page, then we'd care about updating and call: abtest.submitTest().then(...abtest.load()...)
156 $scope
.leave
= function leave() {
157 $location
.path('abtest');
161 $scope
.selectWinner
= function selectWinner(mailingName
) {
163 abtest
: $scope
.abtest
,
164 mailingName
: mailingName
166 var options
= CRM
.utils
.adjustDialogDefaults({
168 title
: ts('Select Final Mailing (Test %1)', {
169 1: mailingName
.toUpperCase()
172 return myAutosave
.suspend(dialogService
.open('selectWinnerDialog', '~/crmMailingAB/selectWinner.html', model
, options
));
176 var syncJob
= $interval($scope
.sync
, 333);
177 $scope
.$on('$destroy', function(){
178 $interval
.cancel(syncJob
);
181 myAutosave
= new CrmAutosaveCtrl({
184 return abtest
.ab
.status
== 'Draft' && $scope
.sync();
187 return abtest
.getAutosaveSignature();
190 return $scope
.crmMailingAB
;
193 $timeout(myAutosave
.start
);
194 $scope
.$on('$destroy', myAutosave
.stop
);
197 angular
.module('crmMailingAB').controller('CrmMailingABReportCtrl', function ($scope
, crmApi
, crmMailingStats
) {
198 var ts
= $scope
.ts
= CRM
.ts(null);
200 var CrmMailingABReportCnt
= 1, activeMailings
= null;
201 $scope
.getActiveMailings = function() {
202 if ($scope
.abtest
.$CrmMailingABReportCnt
!= CrmMailingABReportCnt
) {
203 $scope
.abtest
.$CrmMailingABReportCnt
= ++CrmMailingABReportCnt
;
205 {name
: 'a', title
: ts('Mailing A'), mailing
: $scope
.abtest
.mailings
.a
, attachments
: $scope
.abtest
.attachments
.a
},
206 {name
: 'b', title
: ts('Mailing B'), mailing
: $scope
.abtest
.mailings
.b
, attachments
: $scope
.abtest
.attachments
.b
}
208 if ($scope
.abtest
.ab
.status
== 'Final') {
209 activeMailings
.push({name
: 'c', title
: ts('Final'), mailing
: $scope
.abtest
.mailings
.c
, attachments
: $scope
.abtest
.attachments
.c
});
212 return activeMailings
;
215 crmMailingStats
.getStats({
216 a
: $scope
.abtest
.ab
.mailing_id_a
,
217 b
: $scope
.abtest
.ab
.mailing_id_b
,
218 c
: $scope
.abtest
.ab
.mailing_id_c
219 }).then(function(stats
) {
220 $scope
.stats
= stats
;
223 $scope
.statTypes
= crmMailingStats
.getStatTypes();
224 $scope
.statUrl
= function statUrl(mailing
, statType
, view
) {
225 return crmMailingStats
.getUrl(mailing
, statType
, view
, 'abtest/' + $scope
.abtest
.ab
.id
);
228 $scope
.checkPerm
= CRM
.checkPerm
;
231 angular
.module('crmMailingAB').controller('CrmMailingABWinnerDialogCtrl', function ($scope
, $timeout
, dialogService
, crmMailingMgr
, crmStatus
) {
232 var ts
= $scope
.ts
= CRM
.ts(null);
233 var abtest
= $scope
.abtest
= $scope
.model
.abtest
;
234 var mailingName
= $scope
.model
.mailingName
;
236 var titles
= {a
: ts('Mailing A'), b
: ts('Mailing B')};
237 $scope
.mailingTitle
= titles
[mailingName
];
240 // When using dialogService with a button bar, the major button actions
241 // need to be registered with the dialog widget (and not embedded in
242 // the body of the dialog).
244 buttons
[ts('Submit final mailing')] = function () {
245 crmMailingMgr
.mergeInto(abtest
.mailings
.c
, abtest
.mailings
[mailingName
], [
250 crmStatus({start
: ts('Saving...'), success
: ''}, abtest
.save())
252 return crmStatus({start
: ts('Submitting...'), success
: ts('Submitted')},
253 abtest
.submitFinal().then(function(r
){
254 delete abtest
.$CrmMailingABReportCnt
;
259 dialogService
.close('selectWinnerDialog', abtest
);
262 buttons
[ts('Cancel')] = function () {
263 dialogService
.cancel('selectWinnerDialog');
265 dialogService
.setButtons('selectWinnerDialog', buttons
);
271 })(angular
, CRM
.$, CRM
._
);