);
$result['crmMailingAB2'] = array(
'ext' => 'civicrm',
- 'js' => array('js/angular-crmMailingAB2.js', 'js/angular-crmMailingAB2-services.js'),
+ 'js' => array('js/angular-crmMailingAB2.js', 'js/angular-crmMailingAB2-services.js', 'js/angular-crmMailingAB2-directives.js'),
'css' => array('css/angular-crmMailingAB2.css'),
);
$result['crmMailingAB'] = array(
--- /dev/null
+(function (angular, $, _) {
+ var partialUrl = function (relPath) {
+ return CRM.resourceUrls['civicrm'] + '/partials/crmMailingAB2/' + relPath;
+ };
+
+ // example:
+ // scope.myAbtest = new CrmMailingAB();
+ // <crm-mailing-ab-block-mailing="{fromAddressA: 1, fromAddressB: 1}" crm-abtest="myAbtest" />
+ angular.module('crmMailingAB2').directive('crmMailingAbBlockMailing', function ($parse) {
+ return {
+ scope: {
+ crmMailingAbBlockMailing: '@',
+ crmAbtest: '@'
+ },
+ templateUrl: partialUrl('joint-mailing.html'),
+ link: function (scope, elm, attr) {
+ var model = $parse(attr.crmAbtest);
+ scope.abtest = model(scope.$parent);
+ scope.crmMailingConst = CRM.crmMailing;
+ scope.ts = CRM.ts('CiviMail');
+
+ var fieldsModel = $parse(attr.crmMailingAbBlockMailing);
+ scope.fields = fieldsModel(scope.$parent);
+ }
+ };
+ })
+})(angular, CRM.$, CRM._);
var crmMailingAB = this;
if (!crmMailingAB.id) {
crmMailingAB.ab = {
- name: '',
+ name: 'Example', // FIXME
mailing_id_a: null,
mailing_id_b: null,
mailing_id_c: null,
domain_id: null,
- testing_criteria_id: null,
+ testing_criteria_id: 1, // FIXME
winner_criteria_id: null,
specific_url: '',
declare_winning_time: null,
$scope.abtest = abtest;
$scope.ts = CRM.ts('CiviMail');
$scope.crmMailingABCriteria = crmMailingABCriteria;
+ $scope.crmMailingConst = CRM.crmMailing;;
+ $scope.partialUrl = partialUrl;
$scope.sync = function sync() {
abtest.mailings.a.name = ts('Test A (%1)', {1: abtest.ab.name});
$scope.delete = function () {
throw "Not implemented: EditCtrl.delete"
};
+ $scope.submit = function () {
+ throw "Not implemented: EditCtrl.submit"
+ };
+
+ function updateCriteriaName() {
+ $scope.criteriaName = crmMailingABCriteria.get($scope.abtest.ab.testing_criteria_id).name;
+ }
+ // initialize
+ updateCriteriaName();
$scope.sync();
+ $scope.$watch('abtest.ab.testing_criteria_id', updateCriteriaName);
});
})(angular, CRM.$, CRM._);
<!--
Controller: EditMailingCtrl
Required vars: mailing, crmMailingConst
+Note: Much of this file is duplicated in crmMailing and crmMailingAB with variations on placement/title/binding.
+It could perhaps be thinned by 30-60% by making more directives.
-->
<div class="crm-block" ng-form="subform" crm-ui-id-scope>
<div class="crm-group">
--- /dev/null
+Split screen!
<pre>{{abtest|json}}</pre>
</div>
-<form name="crmMailingAB2">
+<!--
+ An ABTest includes two mailings, but we don't require the user to enter two complete mailings. For
+ simplicity, the email composition UI generally displays A (unless we specifically decided to expose an
+ individual field from B). At the end of the composition process, the controller's "sync" operation will
+ merge shared settings from "A" into "B".
+-->
+
+<form name="crmMailingAB2" novalidate>
<div class="crm-block crm-form-block crmMailing2">
<div crm-ui-wizard>
- <div crm-ui-wizard-step crm-title="ts('Setup')">
+ <div crm-ui-wizard-step="10" crm-title="ts('Setup')">
<div ng-form="setupForm" crm-ui-id-scope>
<div>
<label crm-ui-for="setupForm.abName">{{ts('What would you like to name the test?')}}</label>
</div>
</div>
</div>
- <div crm-ui-wizard-step crm-title="ts('Content')">
- <div>
- Subject A: <input ng-model="abtest.mailings.a.subject"/>
+ <div crm-ui-wizard-step="20" crm-title="ts('Compose')" ng-if="criteriaName != 'Two different emails'">
+ <div crm-ui-tab-set>
+ <div crm-ui-tab id="tab-mailing" crm-title="ts('Mailing')">
+ <div
+ ng-if="criteriaName == 'From names'"
+ crm-mailing-ab-block-mailing="{
+ msg_template_id: 1,
+ fromAddressA: 1,
+ fromAddressB: 1,
+ replyTo: 1,
+ subject: 1
+ }"
+ crm-abtest="abtest"></div>
+ <div
+ ng-if="criteriaName == 'Subject lines'"
+ crm-mailing-ab-block-mailing="{
+ msg_template_id: 1,
+ fromAddress: 1,
+ replyTo: 1,
+ subjectA: 1,
+ subjectB: 1
+ }"
+ crm-abtest="abtest"></div>
+ <div crm-ui-accordion crm-title="ts('HTML')">
+ <div crm-mailing-body-html crm-mailing="abtest.mailings.a"/>
+ </div>
+ <div crm-ui-accordion crm-title="ts('Plain Text')" crm-collapsed='true'>
+ <div crm-mailing-body-text crm-mailing="abtest.mailings.a"/>
+ </div>
+ </div>
+ <!--
+ <div crm-ui-tab id="tab-attachment" crm-title="ts('Attachments')">
+ <div crm-attachments="attachments"/>
+ </div>
+ -->
+ <div crm-ui-tab id="tab-header" crm-title="ts('Header and Footer')">
+ <div crm-mailing-block-header-footer crm-mailing="abtest.mailings.a"/>
+ </div>
+ <div crm-ui-tab id="tab-pub" crm-title="ts('Publication')">
+ <div crm-mailing-block-publication crm-mailing="abtest.mailings.a"/>
+ </div>
+ <div crm-ui-tab id="tab-response" crm-title="ts('Responses')">
+ <div crm-mailing-block-responses crm-mailing="abtest.mailings.a"/>
+ </div>
+ </div>
+ <div crm-ui-accordion crm-title="ts('Preview (A)')">
+ <div crm-mailing-block-preview crm-mailing="abtest.mailings.a"/>
</div>
- <div>
- Subject B: <input ng-model="abtest.mailings.b.subject"/>
+ <div crm-ui-accordion crm-title="ts('Preview (B)')">
+ <div crm-mailing-block-preview crm-mailing="abtest.mailings.b"/>
</div>
</div>
- <span crm-ui-wizard-buttons style="float:right;">
- <button
- crm-confirm="{title:ts('Delete Draft?'), message:ts('Are you sure you want to delete the draft mailing?')}"
- on-yes="delete()">{{ts('Delete Draft')}}
- </button>
- <button ng-click="save()">{{ts('Save Draft')}}</button>
- </span>
+ <div crm-ui-wizard-step="30" crm-title="ts('Compose (A)')" ng-if="criteriaName == 'Two different emails'">
+ A
+ </div>
+ <div crm-ui-wizard-step="40" crm-title="ts('Compose (B)')" ng-if="criteriaName == 'Two different emails'">
+ B
+ </div>
+ <span crm-ui-wizard-buttons style="float:right;">
+ <button
+ crm-confirm="{title:ts('Delete Draft?'), message:ts('Are you sure you want to delete the draft mailing?')}"
+ on-yes="delete()">{{ts('Delete Draft')}}
+ </button>
+ <button ng-click="save()">{{ts('Save Draft')}}</button>
+ </span>
</div>
- </div>
</form>
--- /dev/null
+<!--
+Required vars: abtest
+Note: Much of this file is duplicated in crmMailing and crmMailingAB with variations on placement/title/binding.
+It could perhaps be thinned by 30-60% by making more directives.
+-->
+<div class="crm-block" ng-form="subform" crm-ui-id-scope>
+ <div class="crm-group">
+ <div crm-ui-field="subform.msg_template_id" crm-title="ts('Template')" style="background: #bbf; width:100%; padding: 0.1em;" ng-if="fields.msg_template_id">
+ <div ng-controller="MsgTemplateCtrl">
+ <select
+ crm-ui-id="subform.msg_template_id"
+ name="msg_template_id"
+ crm-ui-select="{dropdownAutoWidth : true, allowClear: true, placeholder: ts('Message Template')}"
+ ng-model="abtest.mailings.a.msg_template_id"
+ ng-change="loadTemplate(abtest.mailings.a, abtest.mailings.a.msg_template_id)"
+ >
+ <option value=""></option>
+ <option ng-repeat="frm in crmMsgTemplates.getAll() | orderBy:'msg_title'" ng-value="frm.id">{{frm.msg_title}}</option>
+ </select>
+ <a ng-click="saveTemplate(abtest.mailings.a)" class="crm-hover-button action-item" title="{{ts('Save As')}}"><span class="icon ui-icon-disk"></span></a>
+ </div>
+ </div>
+ <div crm-ui-field="subform.fromAddress" crm-title="ts('From')" ng-if="fields.fromAddress">
+ <span ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="abtest.mailings.a">
+ <select
+ crm-ui-id="subform.fromAddress"
+ name="fromAddress"
+ ui-jq="select2"
+ ui-options="{dropdownAutoWidth : true, allowClear: false, placeholder: ts('Email address')}"
+ ng-model="fromPlaceholder.label"
+ ng-options="frm.label as frm.label for frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'"
+ required>
+ <option value=""></option>
+ </select>
+ </span>
+ </div>
+ <div crm-ui-field="subform.fromAddressA" crm-title="ts('From (A)')" ng-if="fields.fromAddressA">
+ <span ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="abtest.mailings.a">
+ <select
+ crm-ui-id="subform.fromAddressA"
+ name="fromAddressA"
+ ui-jq="select2"
+ ui-options="{dropdownAutoWidth : true, allowClear: false, placeholder: ts('Email address')}"
+ ng-model="fromPlaceholder.label"
+ ng-options="frm.label as frm.label for frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'"
+ required>
+ <option value=""></option>
+ </select>
+ </span>
+ </div>
+ <div crm-ui-field="subform.fromAddressB" crm-title="ts('From (B)')" ng-if="fields.fromAddressB">
+ <span ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="abtest.mailings.b">
+ <select
+ crm-ui-id="subform.fromAddressB"
+ name="fromAddressB"
+ ui-jq="select2"
+ ui-options="{dropdownAutoWidth : true, allowClear: false, placeholder: ts('Email address')}"
+ ng-model="fromPlaceholder.label"
+ ng-options="frm.label as frm.label for frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'"
+ required>
+ <option value=""></option>
+ </select>
+ </span>
+ </div>
+ <div crm-ui-field="subform.replyTo" crm-title="ts('Reply-To')" ng-show="crmMailingConst.enableReplyTo" ng-if="fields.replyTo">
+ <span ng-controller="EmailAddrCtrl">
+ <select
+ crm-ui-id="subform.replyTo"
+ name="replyTo"
+ ui-jq="select2"
+ ui-options="{dropdownAutoWidth : true, allowClear: true, placeholder: ts('Email address')}"
+ ng-model="abtest.mailings.a.replyto_email"
+ ng-options="frm.label as frm.label for frm in crmFromAddresses.getAll() | filter:{is_active:1} | orderBy:'weight'"
+ >
+ <option value=""></option>
+ </select>
+ </span>
+ </div>
+ <!--
+ <div crm-ui-field="subform.recipients" crm-title="ts('Recipients')">
+ <div ng-controller="EditRecipCtrl">
+ <div style="float: right;">
+ <div class='crmMailing2-recip-est'>
+ <a href="" ng-click="previewRecipients()">{{getRecipientsEstimate()}}</a>
+ </div>
+ <div>
+ <input name='dedupe_email' type='checkbox' ng-model='abtest.mailings.a.dedupe_email' ng-true-value="1" ng-false-value="0" id="recipients-dedupe-email" />
+ <label for="recipients-dedupe-email">
+ {{ts('Dedupe')}}
+ </label>
+ </div>
+ </div>
+ <select crm-mailing-recipients
+ crm-mailing="mailing"
+ crm-avail-groups="crmMailingConst.groupNames | filter:{visibility:'Public pages'}"
+ crm-avail-mailings="crmMailingConst.civiMails | filter:{is_completed:1}"
+ name="recipients"
+ crm-ui-id="subform.recipients"
+ required
+ multiple>
+ </select>
+ </div>
+ </div>
+ -->
+ <div crm-ui-field="subform.subject" crm-title="ts('Subject')" ng-if="fields.subject">
+ <div style="float: right;">
+ <input crm-mailing-token crm-for="subject" />
+ </div>
+ <input
+ crm-ui-id="subform.subject"
+ type="text"
+ class="crm-form-text"
+ ng-model="abtest.mailings.a.subject"
+ required
+ placeholder="Subject"
+ name="subject" />
+ </div>
+ <div crm-ui-field="subform.subjectA" crm-title="ts('Subject (A)')" ng-if="fields.subjectA">
+ <div style="float: right;">
+ <input crm-mailing-token crm-for="subjectA" />
+ </div>
+ <input
+ crm-ui-id="subform.subjectA"
+ type="text"
+ class="crm-form-text"
+ ng-model="abtest.mailings.a.subject"
+ required
+ placeholder="Subject"
+ name="subjectA" />
+ </div>
+ <div crm-ui-field="subform.subjectB" crm-title="ts('Subject (B)')" ng-if="fields.subjectB">
+ <div style="float: right;">
+ <input crm-mailing-token crm-for="subjectB" />
+ </div>
+ <input
+ crm-ui-id="subform.subjectB"
+ type="text"
+ class="crm-form-text"
+ ng-model="abtest.mailings.b.subject"
+ required
+ placeholder="Subject"
+ name="subjectB" />
+ </div>
+ </div>
+</div>