summaryrefslogtreecommitdiff
path: root/www/crm/wp-content/plugins/civicrm/civicrm/ang/crmMailing/Recipients.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/crm/wp-content/plugins/civicrm/civicrm/ang/crmMailing/Recipients.js')
-rw-r--r--www/crm/wp-content/plugins/civicrm/civicrm/ang/crmMailing/Recipients.js341
1 files changed, 341 insertions, 0 deletions
diff --git a/www/crm/wp-content/plugins/civicrm/civicrm/ang/crmMailing/Recipients.js b/www/crm/wp-content/plugins/civicrm/civicrm/ang/crmMailing/Recipients.js
new file mode 100644
index 00000000..4203d4a3
--- /dev/null
+++ b/www/crm/wp-content/plugins/civicrm/civicrm/ang/crmMailing/Recipients.js
@@ -0,0 +1,341 @@
+(function(angular, $, _) {
+ // example: <select multiple crm-mailing-recipients crm-mailing="mymailing" crm-avail-groups="myGroups" crm-avail-mailings="myMailings"></select>
+ // FIXME: participate in ngModel's validation cycle
+ angular.module('crmMailing').directive('crmMailingRecipients', function(crmUiAlert) {
+ return {
+ restrict: 'AE',
+ require: 'ngModel',
+ scope: {
+ ngRequired: '@'
+ },
+ link: function(scope, element, attrs, ngModel) {
+ scope.recips = ngModel.$viewValue;
+ scope.groups = scope.$parent.$eval(attrs.crmAvailGroups);
+ scope.mailings = scope.$parent.$eval(attrs.crmAvailMailings);
+ refreshMandatory();
+
+ var ts = scope.ts = CRM.ts(null);
+
+ /// Convert MySQL date ("yyyy-mm-dd hh:mm:ss") to JS date object
+ scope.parseDate = function(date) {
+ if (!angular.isString(date)) {
+ return date;
+ }
+ var p = date.split(/[\- :]/);
+ return new Date(parseInt(p[0]), parseInt(p[1]) - 1, parseInt(p[2]), parseInt(p[3]), parseInt(p[4]), parseInt(p[5]));
+ };
+
+ /// Remove {value} from {array}
+ function arrayRemove(array, value) {
+ var idx = array.indexOf(value);
+ if (idx >= 0) {
+ array.splice(idx, 1);
+ }
+ }
+
+ // @param string id an encoded string like "4 civicrm_mailing include"
+ // @return Object keys: entity_id, entity_type, mode
+ function convertValueToObj(id) {
+ var a = id.split(" ");
+ return {entity_id: parseInt(a[0]), entity_type: a[1], mode: a[2]};
+ }
+
+ // @param Object mailing
+ // @return array list of values like "4 civicrm_mailing include"
+ function convertMailingToValues(recipients) {
+ var r = [];
+ angular.forEach(recipients.groups.include, function(v) {
+ r.push(v + " civicrm_group include");
+ });
+ angular.forEach(recipients.groups.exclude, function(v) {
+ r.push(v + " civicrm_group exclude");
+ });
+ angular.forEach(recipients.mailings.include, function(v) {
+ r.push(v + " civicrm_mailing include");
+ });
+ angular.forEach(recipients.mailings.exclude, function(v) {
+ r.push(v + " civicrm_mailing exclude");
+ });
+ return r;
+ }
+
+ function refreshMandatory() {
+ if (ngModel.$viewValue && ngModel.$viewValue.groups) {
+ scope.mandatoryGroups = _.filter(scope.$parent.$eval(attrs.crmMandatoryGroups), function(grp) {
+ return _.contains(ngModel.$viewValue.groups.include, parseInt(grp.id));
+ });
+ scope.mandatoryIds = _.map(_.pluck(scope.$parent.$eval(attrs.crmMandatoryGroups), 'id'), function(n) {
+ return parseInt(n);
+ });
+ }
+ else {
+ scope.mandatoryGroups = [];
+ scope.mandatoryIds = [];
+ }
+ }
+
+ function isMandatory(grpId) {
+ return _.contains(scope.mandatoryIds, parseInt(grpId));
+ }
+
+ var refreshUI = ngModel.$render = function refresuhUI() {
+ scope.recips = ngModel.$viewValue;
+ if (ngModel.$viewValue) {
+ $(element).select2('val', convertMailingToValues(ngModel.$viewValue));
+ validate();
+ refreshMandatory();
+ }
+ };
+
+ // @return string HTML representing an option
+ function formatItem(item) {
+ if (!item.id) {
+ // return `text` for optgroup
+ return item.text;
+ }
+ var option = convertValueToObj(item.id);
+ var icon = (option.entity_type === 'civicrm_mailing') ? 'fa-envelope' : 'fa-users';
+ var spanClass = (option.mode == 'exclude') ? 'crmMailing-exclude' : 'crmMailing-include';
+ if (option.entity_type != 'civicrm_mailing' && isMandatory(option.entity_id)) {
+ spanClass = 'crmMailing-mandatory';
+ }
+ return '<i class="crm-i '+icon+'"></i> <span class="' + spanClass + '">' + item.text + '</span>';
+ }
+
+ function validate() {
+ if (scope.$parent.$eval(attrs.ngRequired)) {
+ var empty = (_.isEmpty(ngModel.$viewValue.groups.include) && _.isEmpty(ngModel.$viewValue.mailings.include));
+ ngModel.$setValidity('empty', !empty);
+ }
+ else {
+ ngModel.$setValidity('empty', true);
+ }
+ }
+
+ var rcpAjaxState = {
+ input: '',
+ entity: 'civicrm_group',
+ type: 'include',
+ page_n: 0,
+ page_i: 0,
+ };
+
+ $(element).select2({
+ width: '36em',
+ dropdownAutoWidth: true,
+ placeholder: "Groups or Past Recipients",
+ formatResult: formatItem,
+ formatSelection: formatItem,
+ escapeMarkup: function(m) {
+ return m;
+ },
+ multiple: true,
+ initSelection: function(el, cb) {
+ var values = el.val().split(',');
+
+ var gids = [];
+ var mids = [];
+
+ for (var i = 0; i < values.length; i++) {
+ var dv = convertValueToObj(values[i]);
+ if (dv.entity_type == 'civicrm_group') {
+ gids.push(dv.entity_id);
+ }
+ else if (dv.entity_type == 'civicrm_mailing') {
+ mids.push(dv.entity_id);
+ }
+ }
+ // push non existant 0 group/mailing id in order when no recipents group or prior mailing is selected
+ // this will allow to resuse the below code to handle datamap
+ if (gids.length === 0) {
+ gids.push(0);
+ }
+ if (mids.length === 0) {
+ mids.push(0);
+ }
+
+ CRM.api3('Group', 'getlist', { params: { id: { IN: gids }, options: { limit: 0 } }, extra: ["is_hidden"] } ).then(
+ function(glist) {
+ CRM.api3('Mailing', 'getlist', { params: { id: { IN: mids }, options: { limit: 0 } } }).then(
+ function(mlist) {
+ var datamap = [];
+
+ var groupNames = [];
+ var civiMails = [];
+
+ $(glist.values).each(function (idx, group) {
+ var key = group.id + ' civicrm_group include';
+ groupNames.push({id: parseInt(group.id), title: group.label, is_hidden: group.extra.is_hidden});
+
+ if (values.indexOf(key) >= 0) {
+ datamap.push({id: key, text: group.label});
+ }
+
+ key = group.id + ' civicrm_group exclude';
+ if (values.indexOf(key) >= 0) {
+ datamap.push({id: key, text: group.label});
+ }
+ });
+
+ $(mlist.values).each(function (idx, group) {
+ var key = group.id + ' civicrm_mailing include';
+ civiMails.push({id: parseInt(group.id), name: group.label});
+
+ if (values.indexOf(key) >= 0) {
+ datamap.push({id: key, text: group.label});
+ }
+
+ key = group.id + ' civicrm_mailing exclude';
+ if (values.indexOf(key) >= 0) {
+ datamap.push({id: key, text: group.label});
+ }
+ });
+
+ scope.$parent.crmMailingConst.groupNames = groupNames;
+ scope.$parent.crmMailingConst.civiMails = civiMails;
+
+ refreshMandatory();
+
+ cb(datamap);
+ });
+ });
+ },
+ ajax: {
+ url: CRM.url('civicrm/ajax/rest'),
+ quietMillis: 300,
+ data: function(input, page_num) {
+ if (page_num <= 1) {
+ rcpAjaxState = {
+ input: input,
+ entity: 'civicrm_group',
+ type: 'include',
+ page_n: 0,
+ };
+ }
+
+ rcpAjaxState.page_i = page_num - rcpAjaxState.page_n;
+ var filterParams = {};
+ switch(rcpAjaxState.entity) {
+ case 'civicrm_group':
+ filterParams = { is_hidden: 0, is_active: 1, group_type: {"LIKE": "%2%"} };
+ break;
+
+ case 'civicrm_mailing':
+ filterParams = { is_hidden: 0, is_active: 1 };
+ break;
+ }
+ var params = {
+ input: input,
+ page_num: rcpAjaxState.page_i,
+ params: filterParams,
+ };
+
+ if('civicrm_mailing' === rcpAjaxState.entity) {
+ params["api.MailingRecipients.getcount"] = {};
+ }
+
+ return params;
+ },
+ transport: function(params) {
+ switch(rcpAjaxState.entity) {
+ case 'civicrm_group':
+ CRM.api3('Group', 'getlist', params.data).then(params.success, params.error);
+ break;
+
+ case 'civicrm_mailing':
+ params.data.params.options = { sort: "is_archived asc, scheduled_date desc" };
+ CRM.api3('Mailing', 'getlist', params.data).then(params.success, params.error);
+ break;
+ }
+ },
+ results: function(data) {
+ results = {
+ children: $.map(data.values, function(obj) {
+ if('civicrm_mailing' === rcpAjaxState.entity) {
+ return obj["api.MailingRecipients.getcount"] > 0 ? { id: obj.id + ' ' + rcpAjaxState.entity + ' ' + rcpAjaxState.type,
+ text: obj.label } : '';
+ }
+ else {
+ return { id: obj.id + ' ' + rcpAjaxState.entity + ' ' + rcpAjaxState.type,
+ text: obj.label };
+ }
+ })
+ };
+
+ if (rcpAjaxState.page_i == 1 && data.count && results.children.length > 0) {
+ results.text = ts((rcpAjaxState.type == 'include'? 'Include ' : 'Exclude ') +
+ (rcpAjaxState.entity == 'civicrm_group'? 'Group' : 'Mailing'));
+ }
+
+ more = data.more_results || !(rcpAjaxState.entity == 'civicrm_mailing' && rcpAjaxState.type == 'exclude');
+
+ if (more && !data.more_results) {
+ if (rcpAjaxState.type == 'include') {
+ rcpAjaxState.type = 'exclude';
+ } else {
+ rcpAjaxState.type = 'include';
+ rcpAjaxState.entity = 'civicrm_mailing';
+ }
+ rcpAjaxState.page_n += rcpAjaxState.page_i;
+ }
+
+ return { more: more, results: [ results ] };
+ },
+ },
+ });
+
+ $(element).on('select2-selecting', function(e) {
+ var option = convertValueToObj(e.val);
+ var typeKey = option.entity_type == 'civicrm_mailing' ? 'mailings' : 'groups';
+ if (option.mode == 'exclude') {
+ ngModel.$viewValue[typeKey].exclude.push(option.entity_id);
+ arrayRemove(ngModel.$viewValue[typeKey].include, option.entity_id);
+ }
+ else {
+ ngModel.$viewValue[typeKey].include.push(option.entity_id);
+ arrayRemove(ngModel.$viewValue[typeKey].exclude, option.entity_id);
+ }
+ scope.$apply();
+ $(element).select2('close');
+ validate();
+ e.preventDefault();
+ });
+
+ $(element).on("select2-removing", function(e) {
+ var option = convertValueToObj(e.val);
+ var typeKey = option.entity_type == 'civicrm_mailing' ? 'mailings' : 'groups';
+ if (typeKey == 'groups' && isMandatory(option.entity_id)) {
+ crmUiAlert({
+ text: ts('This mailing was generated based on search results. The search results cannot be removed.'),
+ title: ts('Required')
+ });
+ e.preventDefault();
+ return;
+ }
+ scope.$parent.$apply(function() {
+ arrayRemove(ngModel.$viewValue[typeKey][option.mode], option.entity_id);
+ });
+ validate();
+ e.preventDefault();
+ });
+
+ scope.$watchCollection("recips.groups.include", refreshUI);
+ scope.$watchCollection("recips.groups.exclude", refreshUI);
+ scope.$watchCollection("recips.mailings.include", refreshUI);
+ scope.$watchCollection("recips.mailings.exclude", refreshUI);
+ setTimeout(refreshUI, 50);
+
+ scope.$watchCollection(attrs.crmAvailGroups, function() {
+ scope.groups = scope.$parent.$eval(attrs.crmAvailGroups);
+ });
+ scope.$watchCollection(attrs.crmAvailMailings, function() {
+ scope.mailings = scope.$parent.$eval(attrs.crmAvailMailings);
+ });
+ scope.$watchCollection(attrs.crmMandatoryGroups, function() {
+ refreshMandatory();
+ });
+ }
+ };
+ });
+
+})(angular, CRM.$, CRM._);