From: Tim Otten Date: Wed, 8 Apr 2015 04:46:25 +0000 (-0700) Subject: CRM-16145 - crmMailing - Split controllers into separate files X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=6b8bd380dbdbdd67065de77fb1b8b458c4cbf572;p=civicrm-core.git CRM-16145 - crmMailing - Split controllers into separate files --- diff --git a/ang/crmMailing.js b/ang/crmMailing.js index dd0b5c06a8..bc3938f2ac 100644 --- a/ang/crmMailing.js +++ b/ang/crmMailing.js @@ -4,12 +4,6 @@ 'crmUtil', 'crmAttachment', 'crmAutosave', 'ngRoute', 'ui.utils', 'crmUi', 'dialogService' ]); - // Time to wait before triggering AJAX update to recipients list - var RECIPIENTS_DEBOUNCE_MS = 100; - var RECIPIENTS_PREVIEW_LIMIT = 10000; - - var APPROVAL_STATUSES = {'Approved': 1, 'Rejected': 2, 'None': 3}; - angular.module('crmMailing').config([ '$routeProvider', function ($routeProvider) { @@ -57,531 +51,4 @@ } ]); - angular.module('crmMailing').controller('ListMailingsCtrl', ['crmLegacy', 'crmNavigator', function ListMailingsCtrl(crmLegacy, crmNavigator) { - // We haven't implemented this in Angular, but some users may get clever - // about typing URLs, so we'll provide a redirect. - var new_url = crmLegacy.url('civicrm/mailing/browse/unscheduled', {reset: 1, scheduled: 'false'}); - crmNavigator.redirect(new_url); - }]); - - angular.module('crmMailing').controller('CreateMailingCtrl', function EditMailingCtrl($scope, selectedMail, $location) { - // Transition URL "/mailing/new/foo" => "/mailing/123/foo" - var parts = $location.path().split('/'); // e.g. "/mailing/new" or "/mailing/123/wizard" - parts[2] = selectedMail.id; - $location.path(parts.join('/')); - $location.replace(); - }); - - angular.module('crmMailing').controller('EditMailingCtrl', function EditMailingCtrl($scope, selectedMail, $location, crmMailingMgr, crmStatus, attachments, crmMailingPreviewMgr, crmBlocker, CrmAutosaveCtrl, $timeout, crmUiHelp) { - $scope.mailing = selectedMail; - $scope.attachments = attachments; - $scope.crmMailingConst = CRM.crmMailing; - $scope.checkPerm = CRM.checkPerm; - - var ts = $scope.ts = CRM.ts(null); - $scope.hs = crmUiHelp({file: 'CRM/Mailing/MailingUI'}); - var block = $scope.block = crmBlocker(); - var myAutosave = null; - - $scope.isSubmitted = function isSubmitted() { - return _.size($scope.mailing.jobs) > 0; - }; - - // usage: approve('Approved') - $scope.approve = function approve(status, options) { - $scope.mailing.approval_status_id = APPROVAL_STATUSES[status]; - return myAutosave.suspend($scope.submit(options)); - }; - - // @return Promise - $scope.previewMailing = function previewMailing(mailing, mode) { - return crmMailingPreviewMgr.preview(mailing, mode); - }; - - // @return Promise - $scope.sendTest = function sendTest(mailing, attachments, recipient) { - var savePromise = crmMailingMgr.save(mailing) - .then(function () { - return attachments.save(); - }); - return block(crmStatus({start: ts('Saving...'), success: ''}, savePromise) - .then(function () { - crmMailingPreviewMgr.sendTest(mailing, recipient); - })); - }; - - // @return Promise - $scope.submit = function submit(options) { - options = options || {}; - if (block.check() || $scope.crmMailing.$invalid) { - return; - } - - var promise = crmMailingMgr.save($scope.mailing) - .then(function () { - // pre-condition: the mailing exists *before* saving attachments to it - return $scope.attachments.save(); - }) - .then(function () { - return crmMailingMgr.submit($scope.mailing); - }) - .then(function () { - if (!options.stay) { - $scope.leave('scheduled'); - } - }) - ; - return block(crmStatus({start: ts('Submitting...'), success: ts('Submitted')}, promise)); - }; - - // @return Promise - $scope.save = function save() { - return block(crmStatus(null, - crmMailingMgr - .save($scope.mailing) - .then(function () { - // pre-condition: the mailing exists *before* saving attachments to it - return $scope.attachments.save(); - }) - )); - }; - - // @return Promise - $scope.delete = function cancel() { - return block(crmStatus({start: ts('Deleting...'), success: ts('Deleted')}, - crmMailingMgr.delete($scope.mailing) - .then(function () { - $scope.leave('unscheduled'); - }) - )); - }; - - // @param string listingScreen 'archive', 'scheduled', 'unscheduled' - $scope.leave = function leave(listingScreen) { - switch (listingScreen) { - case 'archive': - window.location = CRM.url('civicrm/mailing/browse/archived', { - reset: 1 - }); - break; - case 'scheduled': - window.location = CRM.url('civicrm/mailing/browse/scheduled', { - reset: 1, - scheduled: 'true' - }); - break; - case 'unscheduled': - /* falls through */ - default: - window.location = CRM.url('civicrm/mailing/browse/unscheduled', { - reset: 1, - scheduled: 'false' - }); - } - }; - - myAutosave = new CrmAutosaveCtrl({ - save: $scope.save, - saveIf: function() { - return true; - }, - model: function() { - return [$scope.mailing, $scope.attachments.getAutosaveSignature()]; - }, - form: function() { - return $scope.crmMailing; - } - }); - $timeout(myAutosave.start); - $scope.$on('$destroy', myAutosave.stop); - }); - - angular.module('crmMailing').controller('ViewRecipCtrl', function EditRecipCtrl($scope) { - $scope.getIncludesAsString = function(mailing) { - var first = true; - var names = ''; - _.each(mailing.recipients.groups.include, function (id) { - if (!first) { - names = names + ', '; - } - var group = _.where(CRM.crmMailing.groupNames, {id: '' + id}); - names = names + group[0].title; - first = false; - }); - _.each(mailing.recipients.mailings.include, function (id) { - if (!first) { - names = names + ', '; - } - var oldMailing = _.where(CRM.crmMailing.civiMails, {id: '' + id}); - names = names + oldMailing[0].name; - first = false; - }); - return names; - }; - $scope.getExcludesAsString = function (mailing) { - var first = true; - var names = ''; - _.each(mailing.recipients.groups.exclude, function (id) { - if (!first) { - names = names + ', '; - } - var group = _.where(CRM.crmMailing.groupNames, {id: '' + id}); - names = names + group[0].title; - first = false; - }); - _.each(mailing.recipients.mailings.exclude, function (id) { - if (!first) { - names = names + ', '; - } - var oldMailing = _.where(CRM.crmMailing.civiMails, {id: '' + id}); - names = names + oldMailing[0].name; - first = false; - }); - return names; - }; - }); - - // Controller for the edit-recipients fields ( - // WISHLIST: Move most of this to a (cache-enabled) service - // Scope members: - // - [input] mailing: object - // - [output] recipients: array of recipient records - angular.module('crmMailing').controller('EditRecipCtrl', function EditRecipCtrl($scope, dialogService, crmApi, crmMailingMgr, $q, crmMetadata) { - var ts = $scope.ts = CRM.ts(null); - - $scope.isMailingList = function isMailingList(group) { - var GROUP_TYPE_MAILING_LIST = '2'; - return _.contains(group.group_type, GROUP_TYPE_MAILING_LIST); - }; - - $scope.recipients = null; - $scope.getRecipientsEstimate = function () { - var ts = $scope.ts; - if ($scope.recipients === null) { - return ts('(Estimating)'); - } - if ($scope.recipients.length === 0) { - return ts('No recipients'); - } - if ($scope.recipients.length === 1) { - return ts('~1 recipient'); - } - if (RECIPIENTS_PREVIEW_LIMIT > 0 && $scope.recipients.length >= RECIPIENTS_PREVIEW_LIMIT) { - return ts('>%1 recipients', {1: RECIPIENTS_PREVIEW_LIMIT}); - } - return ts('~%1 recipients', {1: $scope.recipients.length}); - }; - - // We monitor four fields -- use debounce so that changes across the - // four fields can settle-down before AJAX. - var refreshRecipients = _.debounce(function () { - $scope.$apply(function () { - $scope.recipients = null; - if (!$scope.mailing) return; - crmMailingMgr.previewRecipients($scope.mailing, RECIPIENTS_PREVIEW_LIMIT).then(function (recipients) { - $scope.recipients = recipients; - }); - }); - }, RECIPIENTS_DEBOUNCE_MS); - $scope.$watchCollection("mailing.recipients.groups.include", refreshRecipients); - $scope.$watchCollection("mailing.recipients.groups.exclude", refreshRecipients); - $scope.$watchCollection("mailing.recipients.mailings.include", refreshRecipients); - $scope.$watchCollection("mailing.recipients.mailings.exclude", refreshRecipients); - - $scope.previewRecipients = function previewRecipients() { - var model = { - recipients: $scope.recipients - }; - var options = CRM.utils.adjustDialogDefaults({ - width: '40%', - autoOpen: false, - title: ts('Preview (%1)', { - 1: $scope.getRecipientsEstimate() - }) - }); - dialogService.open('recipDialog', '~/crmMailing/dialog/recipients.html', model, options); - }; - - // Open a dialog for editing the advanced recipient options. - $scope.editOptions = function editOptions(mailing) { - var options = CRM.utils.adjustDialogDefaults({ - autoOpen: false, - width: '40%', - height: 'auto', - title: ts('Edit Options') - }); - $q.when(crmMetadata.getFields('Mailing')).then(function(fields) { - var model = { - fields: fields, - mailing: mailing - }; - dialogService.open('previewComponentDialog', '~/crmMailing/dialog/recipientOptions.html', model, options); - }); - }; - }); - - // Controller for the "Preview Recipients" dialog - // Note: Expects $scope.model to be an object with properties: - // - recipients: array of contacts - angular.module('crmMailing').controller('PreviewRecipCtrl', function ($scope) { - $scope.ts = CRM.ts(null); - }); - - // Controller for the "Preview Mailing" dialog - // Note: Expects $scope.model to be an object with properties: - // - "subject" - // - "body_html" - // - "body_text" - angular.module('crmMailing').controller('PreviewMailingDialogCtrl', function PreviewMailingDialogCtrl($scope) { - $scope.ts = CRM.ts(null); - }); - - // Controller for the "Recipients: Edit Options" dialog - // Note: Expects $scope.model to be an object with properties: - // - "mailing" (APIv3 mailing object) - // - "fields" (list of fields) - angular.module('crmMailing').controller('EditRecipOptionsDialogCtrl', function EditRecipOptionsDialogCtrl($scope, crmUiHelp) { - $scope.ts = CRM.ts(null); - $scope.hs = crmUiHelp({file: 'CRM/Mailing/MailingUI'}); - }); - - // Controller for the "Preview Mailing Component" segment - // which displays header/footer/auto-responder - angular.module('crmMailing').controller('PreviewComponentCtrl', function PreviewComponentCtrl($scope, dialogService) { - var ts = $scope.ts = CRM.ts(null); - - $scope.previewComponent = function previewComponent(title, componentId) { - var component = _.where(CRM.crmMailing.headerfooterList, {id: "" + componentId}); - if (!component || !component[0]) { - CRM.alert(ts('Invalid component ID (%1)', { - 1: componentId - })); - return; - } - var options = CRM.utils.adjustDialogDefaults({ - autoOpen: false, - title: title // component[0].name - }); - dialogService.open('previewComponentDialog', '~/crmMailing/dialog/previewComponent.html', component[0], options); - }; - }); - - // Controller for the "Preview Mailing Component" dialog - // Note: Expects $scope.model to be an object with properties: - // - "name" - // - "subject" - // - "body_html" - // - "body_text" - angular.module('crmMailing').controller('PreviewComponentDialogCtrl', function PreviewComponentDialogCtrl($scope) { - $scope.ts = CRM.ts(null); - }); - - // Controller for the in-place msg-template management - angular.module('crmMailing').controller('MsgTemplateCtrl', function MsgTemplateCtrl($scope, crmMsgTemplates, dialogService) { - var ts = $scope.ts = CRM.ts(null); - $scope.crmMsgTemplates = crmMsgTemplates; - - // @return Promise MessageTemplate (per APIv3) - $scope.saveTemplate = function saveTemplate(mailing) { - var model = { - selected_id: mailing.msg_template_id, - tpl: { - msg_title: '', - msg_subject: mailing.subject, - msg_text: mailing.body_text, - msg_html: mailing.body_html - } - }; - var options = CRM.utils.adjustDialogDefaults({ - autoOpen: false, - height: 'auto', - width: '40%', - title: ts('Save Template') - }); - return dialogService.open('saveTemplateDialog', '~/crmMailing/dialog/saveTemplate.html', model, options) - .then(function (item) { - mailing.msg_template_id = item.id; - return item; - }); - }; - - // @param int id - // @return Promise - $scope.loadTemplate = function loadTemplate(mailing, id) { - return crmMsgTemplates.get(id).then(function (tpl) { - mailing.subject = tpl.msg_subject; - mailing.body_text = tpl.msg_text; - mailing.body_html = tpl.msg_html; - }); - }; - }); - - // Controller for the "Save Message Template" dialog - // Scope members: - // - [input] "model": Object - // - "selected_id": int - // - "tpl": Object - // - "msg_subject": string - // - "msg_text": string - // - "msg_html": string - angular.module('crmMailing').controller('SaveMsgTemplateDialogCtrl', function SaveMsgTemplateDialogCtrl($scope, crmMsgTemplates, dialogService) { - var ts = $scope.ts = CRM.ts(null); - $scope.saveOpt = {mode: '', newTitle: ''}; - $scope.selected = null; - - $scope.save = function save() { - var tpl = _.extend({}, $scope.model.tpl); - switch ($scope.saveOpt.mode) { - case 'add': - tpl.msg_title = $scope.saveOpt.newTitle; - break; - case 'update': - tpl.id = $scope.selected.id; - tpl.msg_title = $scope.selected.msg_title; - break; - default: - throw 'SaveMsgTemplateDialogCtrl: Unrecognized mode: ' + $scope.saveOpt.mode; - } - return crmMsgTemplates.save(tpl) - .then(function (item) { - CRM.status(ts('Saved')); - return item; - }); - }; - - function scopeApply(f) { - return function () { - var args = arguments; - $scope.$apply(function () { - f.apply(args); - }); - }; - } - - function init() { - crmMsgTemplates.get($scope.model.selected_id).then( - function (tpl) { - $scope.saveOpt.mode = 'update'; - $scope.selected = tpl; - }, - function () { - $scope.saveOpt.mode = 'add'; - $scope.selected = null; - } - ); - // When using dialogService with a button bar, the major button actions - // need to be registered with the dialog widget (and not embedded in - // the body of the dialog). - var buttons = [ - { - text: ts('Save'), - icons: {primary: 'ui-icon-check'}, - click: function () { - $scope.save().then(function (item) { - dialogService.close('saveTemplateDialog', item); - }); - } - }, - { - text: ts('Cancel'), - icons: {primary: 'ui-icon-close'}, - click: function () { - dialogService.cancel('saveTemplateDialog'); - } - } - ]; - dialogService.setButtons('saveTemplateDialog', buttons); - } - - setTimeout(scopeApply(init), 0); - }); - - angular.module('crmMailing').controller('EmailAddrCtrl', function EmailAddrCtrl($scope, crmFromAddresses, crmUiAlert) { - var ts = CRM.ts(null); - function changeAlert(winnerField, loserField) { - crmUiAlert({ - title: ts('Conflict'), - text: ts('The "%1" option conflicts with the "%2" option. The "%2" option has been disabled.', { - 1: winnerField, - 2: loserField - }) - }); - } - - $scope.crmFromAddresses = crmFromAddresses; - $scope.checkReplyToChange = function checkReplyToChange(mailing) { - if (!_.isEmpty(mailing.replyto_email) && mailing.override_verp == '0') { - mailing.override_verp = '1'; - changeAlert(ts('Reply-To'), ts('Track Replies')); - } - }; - $scope.checkVerpChange = function checkVerpChange(mailing) { - if (!_.isEmpty(mailing.replyto_email) && mailing.override_verp == '0') { - mailing.replyto_email = ''; - changeAlert(ts('Track Replies'), ts('Reply-To')); - } - }; - }); - - var lastEmailTokenAlert = null; - angular.module('crmMailing').controller('EmailBodyCtrl', function EmailBodyCtrl($scope, crmMailingMgr, crmUiAlert, $timeout) { - var ts = CRM.ts(null); - - // ex: if (!hasAllTokens(myMailing, 'body_text)) alert('Oh noes!'); - $scope.hasAllTokens = function hasAllTokens(mailing, field) { - return _.isEmpty(crmMailingMgr.findMissingTokens(mailing, field)); - }; - - // ex: checkTokens(myMailing, 'body_text', 'insert:body_text') - // ex: checkTokens(myMailing, '*') - $scope.checkTokens = function checkTokens(mailing, field, insertEvent) { - if (lastEmailTokenAlert) { - lastEmailTokenAlert.close(); - } - var missing, insertable; - if (field == '*') { - insertable = false; - missing = angular.extend({}, - crmMailingMgr.findMissingTokens(mailing, 'body_html'), - crmMailingMgr.findMissingTokens(mailing, 'body_text') - ); - } else { - insertable = !_.isEmpty(insertEvent); - missing = crmMailingMgr.findMissingTokens(mailing, field); - } - if (!_.isEmpty(missing)) { - lastEmailTokenAlert = crmUiAlert({ - type: 'error', - title: ts('Required tokens'), - templateUrl: '~/crmMailing/dialog/tokenAlert.html', - scope: angular.extend($scope.$new(), { - insertable: insertable, - insertToken: function(token) { - $timeout(function(){ - $scope.$broadcast(insertEvent, '{' + token + '}'); - $timeout(function(){ - checkTokens(mailing, field, insertEvent); - }); - }); - }, - missing: missing - }) - }); - } - }; - }); - - angular.module('crmMailing').controller('EditUnsubGroupCtrl', function EditUnsubGroupCtrl($scope) { - // CRM.crmMailing.groupNames is a global constant - since it doesn't change, we can digest & cache. - var mandatoryIds = []; - _.each(CRM.crmMailing.groupNames, function(grp){ - if (grp.is_hidden == "1") { - mandatoryIds.push(parseInt(grp.id)); - } - }); - - $scope.isUnsubGroupRequired = function isUnsubGroupRequired(mailing) { - return _.intersection(mandatoryIds, mailing.recipients.groups.include).length > 0; - }; - }); })(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/CreateMailingCtrl.js b/ang/crmMailing/CreateMailingCtrl.js new file mode 100644 index 0000000000..9baecadbf2 --- /dev/null +++ b/ang/crmMailing/CreateMailingCtrl.js @@ -0,0 +1,11 @@ +(function(angular, $, _) { + + angular.module('crmMailing').controller('CreateMailingCtrl', function EditMailingCtrl($scope, selectedMail, $location) { + // Transition URL "/mailing/new/foo" => "/mailing/123/foo" + var parts = $location.path().split('/'); // e.g. "/mailing/new" or "/mailing/123/wizard" + parts[2] = selectedMail.id; + $location.path(parts.join('/')); + $location.replace(); + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/EditMailingCtrl.js b/ang/crmMailing/EditMailingCtrl.js new file mode 100644 index 0000000000..2620497550 --- /dev/null +++ b/ang/crmMailing/EditMailingCtrl.js @@ -0,0 +1,129 @@ +(function(angular, $, _) { + + angular.module('crmMailing').controller('EditMailingCtrl', function EditMailingCtrl($scope, selectedMail, $location, crmMailingMgr, crmStatus, attachments, crmMailingPreviewMgr, crmBlocker, CrmAutosaveCtrl, $timeout, crmUiHelp) { + var APPROVAL_STATUSES = {'Approved': 1, 'Rejected': 2, 'None': 3}; + + $scope.mailing = selectedMail; + $scope.attachments = attachments; + $scope.crmMailingConst = CRM.crmMailing; + $scope.checkPerm = CRM.checkPerm; + + var ts = $scope.ts = CRM.ts(null); + $scope.hs = crmUiHelp({file: 'CRM/Mailing/MailingUI'}); + var block = $scope.block = crmBlocker(); + var myAutosave = null; + + $scope.isSubmitted = function isSubmitted() { + return _.size($scope.mailing.jobs) > 0; + }; + + // usage: approve('Approved') + $scope.approve = function approve(status, options) { + $scope.mailing.approval_status_id = APPROVAL_STATUSES[status]; + return myAutosave.suspend($scope.submit(options)); + }; + + // @return Promise + $scope.previewMailing = function previewMailing(mailing, mode) { + return crmMailingPreviewMgr.preview(mailing, mode); + }; + + // @return Promise + $scope.sendTest = function sendTest(mailing, attachments, recipient) { + var savePromise = crmMailingMgr.save(mailing) + .then(function() { + return attachments.save(); + }); + return block(crmStatus({start: ts('Saving...'), success: ''}, savePromise) + .then(function() { + crmMailingPreviewMgr.sendTest(mailing, recipient); + })); + }; + + // @return Promise + $scope.submit = function submit(options) { + options = options || {}; + if (block.check() || $scope.crmMailing.$invalid) { + return; + } + + var promise = crmMailingMgr.save($scope.mailing) + .then(function() { + // pre-condition: the mailing exists *before* saving attachments to it + return $scope.attachments.save(); + }) + .then(function() { + return crmMailingMgr.submit($scope.mailing); + }) + .then(function() { + if (!options.stay) { + $scope.leave('scheduled'); + } + }) + ; + return block(crmStatus({start: ts('Submitting...'), success: ts('Submitted')}, promise)); + }; + + // @return Promise + $scope.save = function save() { + return block(crmStatus(null, + crmMailingMgr + .save($scope.mailing) + .then(function() { + // pre-condition: the mailing exists *before* saving attachments to it + return $scope.attachments.save(); + }) + )); + }; + + // @return Promise + $scope.delete = function cancel() { + return block(crmStatus({start: ts('Deleting...'), success: ts('Deleted')}, + crmMailingMgr.delete($scope.mailing) + .then(function() { + $scope.leave('unscheduled'); + }) + )); + }; + + // @param string listingScreen 'archive', 'scheduled', 'unscheduled' + $scope.leave = function leave(listingScreen) { + switch (listingScreen) { + case 'archive': + window.location = CRM.url('civicrm/mailing/browse/archived', { + reset: 1 + }); + break; + case 'scheduled': + window.location = CRM.url('civicrm/mailing/browse/scheduled', { + reset: 1, + scheduled: 'true' + }); + break; + case 'unscheduled': + /* falls through */ + default: + window.location = CRM.url('civicrm/mailing/browse/unscheduled', { + reset: 1, + scheduled: 'false' + }); + } + }; + + myAutosave = new CrmAutosaveCtrl({ + save: $scope.save, + saveIf: function() { + return true; + }, + model: function() { + return [$scope.mailing, $scope.attachments.getAutosaveSignature()]; + }, + form: function() { + return $scope.crmMailing; + } + }); + $timeout(myAutosave.start); + $scope.$on('$destroy', myAutosave.stop); + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/EditRecipCtrl.js b/ang/crmMailing/EditRecipCtrl.js new file mode 100644 index 0000000000..5e59ddd47d --- /dev/null +++ b/ang/crmMailing/EditRecipCtrl.js @@ -0,0 +1,88 @@ +(function(angular, $, _) { + + // Controller for the edit-recipients fields ( + // WISHLIST: Move most of this to a (cache-enabled) service + // Scope members: + // - [input] mailing: object + // - [output] recipients: array of recipient records + angular.module('crmMailing').controller('EditRecipCtrl', function EditRecipCtrl($scope, dialogService, crmApi, crmMailingMgr, $q, crmMetadata) { + // Time to wait before triggering AJAX update to recipients list + var RECIPIENTS_DEBOUNCE_MS = 100; + var RECIPIENTS_PREVIEW_LIMIT = 10000; + + var ts = $scope.ts = CRM.ts(null); + + $scope.isMailingList = function isMailingList(group) { + var GROUP_TYPE_MAILING_LIST = '2'; + return _.contains(group.group_type, GROUP_TYPE_MAILING_LIST); + }; + + $scope.recipients = null; + $scope.getRecipientsEstimate = function() { + var ts = $scope.ts; + if ($scope.recipients === null) { + return ts('(Estimating)'); + } + if ($scope.recipients.length === 0) { + return ts('No recipients'); + } + if ($scope.recipients.length === 1) { + return ts('~1 recipient'); + } + if (RECIPIENTS_PREVIEW_LIMIT > 0 && $scope.recipients.length >= RECIPIENTS_PREVIEW_LIMIT) { + return ts('>%1 recipients', {1: RECIPIENTS_PREVIEW_LIMIT}); + } + return ts('~%1 recipients', {1: $scope.recipients.length}); + }; + + // We monitor four fields -- use debounce so that changes across the + // four fields can settle-down before AJAX. + var refreshRecipients = _.debounce(function() { + $scope.$apply(function() { + $scope.recipients = null; + if (!$scope.mailing) { + return; + } + crmMailingMgr.previewRecipients($scope.mailing, RECIPIENTS_PREVIEW_LIMIT).then(function(recipients) { + $scope.recipients = recipients; + }); + }); + }, RECIPIENTS_DEBOUNCE_MS); + $scope.$watchCollection("mailing.recipients.groups.include", refreshRecipients); + $scope.$watchCollection("mailing.recipients.groups.exclude", refreshRecipients); + $scope.$watchCollection("mailing.recipients.mailings.include", refreshRecipients); + $scope.$watchCollection("mailing.recipients.mailings.exclude", refreshRecipients); + + $scope.previewRecipients = function previewRecipients() { + var model = { + recipients: $scope.recipients + }; + var options = CRM.utils.adjustDialogDefaults({ + width: '40%', + autoOpen: false, + title: ts('Preview (%1)', { + 1: $scope.getRecipientsEstimate() + }) + }); + dialogService.open('recipDialog', '~/crmMailing/dialog/recipients.html', model, options); + }; + + // Open a dialog for editing the advanced recipient options. + $scope.editOptions = function editOptions(mailing) { + var options = CRM.utils.adjustDialogDefaults({ + autoOpen: false, + width: '40%', + height: 'auto', + title: ts('Edit Options') + }); + $q.when(crmMetadata.getFields('Mailing')).then(function(fields) { + var model = { + fields: fields, + mailing: mailing + }; + dialogService.open('previewComponentDialog', '~/crmMailing/dialog/recipientOptions.html', model, options); + }); + }; + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/EditRecipOptionsDialogCtrl.js b/ang/crmMailing/EditRecipOptionsDialogCtrl.js new file mode 100644 index 0000000000..43734e34b9 --- /dev/null +++ b/ang/crmMailing/EditRecipOptionsDialogCtrl.js @@ -0,0 +1,12 @@ +(function(angular, $, _) { + + // Controller for the "Recipients: Edit Options" dialog + // Note: Expects $scope.model to be an object with properties: + // - "mailing" (APIv3 mailing object) + // - "fields" (list of fields) + angular.module('crmMailing').controller('EditRecipOptionsDialogCtrl', function EditRecipOptionsDialogCtrl($scope, crmUiHelp) { + $scope.ts = CRM.ts(null); + $scope.hs = crmUiHelp({file: 'CRM/Mailing/MailingUI'}); + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/EditUnsubGroupCtrl.js b/ang/crmMailing/EditUnsubGroupCtrl.js new file mode 100644 index 0000000000..c0e7d3e71f --- /dev/null +++ b/ang/crmMailing/EditUnsubGroupCtrl.js @@ -0,0 +1,17 @@ +(function(angular, $, _) { + + angular.module('crmMailing').controller('EditUnsubGroupCtrl', function EditUnsubGroupCtrl($scope) { + // CRM.crmMailing.groupNames is a global constant - since it doesn't change, we can digest & cache. + var mandatoryIds = []; + _.each(CRM.crmMailing.groupNames, function(grp) { + if (grp.is_hidden == "1") { + mandatoryIds.push(parseInt(grp.id)); + } + }); + + $scope.isUnsubGroupRequired = function isUnsubGroupRequired(mailing) { + return _.intersection(mandatoryIds, mailing.recipients.groups.include).length > 0; + }; + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/EmailAddrCtrl.js b/ang/crmMailing/EmailAddrCtrl.js new file mode 100644 index 0000000000..942bcfe123 --- /dev/null +++ b/ang/crmMailing/EmailAddrCtrl.js @@ -0,0 +1,31 @@ +(function(angular, $, _) { + + angular.module('crmMailing').controller('EmailAddrCtrl', function EmailAddrCtrl($scope, crmFromAddresses, crmUiAlert) { + var ts = CRM.ts(null); + + function changeAlert(winnerField, loserField) { + crmUiAlert({ + title: ts('Conflict'), + text: ts('The "%1" option conflicts with the "%2" option. The "%2" option has been disabled.', { + 1: winnerField, + 2: loserField + }) + }); + } + + $scope.crmFromAddresses = crmFromAddresses; + $scope.checkReplyToChange = function checkReplyToChange(mailing) { + if (!_.isEmpty(mailing.replyto_email) && mailing.override_verp == '0') { + mailing.override_verp = '1'; + changeAlert(ts('Reply-To'), ts('Track Replies')); + } + }; + $scope.checkVerpChange = function checkVerpChange(mailing) { + if (!_.isEmpty(mailing.replyto_email) && mailing.override_verp == '0') { + mailing.replyto_email = ''; + changeAlert(ts('Track Replies'), ts('Reply-To')); + } + }; + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/EmailBodyCtrl.js b/ang/crmMailing/EmailBodyCtrl.js new file mode 100644 index 0000000000..08ce2d8bc0 --- /dev/null +++ b/ang/crmMailing/EmailBodyCtrl.js @@ -0,0 +1,52 @@ +(function(angular, $, _) { + + var lastEmailTokenAlert = null; + angular.module('crmMailing').controller('EmailBodyCtrl', function EmailBodyCtrl($scope, crmMailingMgr, crmUiAlert, $timeout) { + var ts = CRM.ts(null); + + // ex: if (!hasAllTokens(myMailing, 'body_text)) alert('Oh noes!'); + $scope.hasAllTokens = function hasAllTokens(mailing, field) { + return _.isEmpty(crmMailingMgr.findMissingTokens(mailing, field)); + }; + + // ex: checkTokens(myMailing, 'body_text', 'insert:body_text') + // ex: checkTokens(myMailing, '*') + $scope.checkTokens = function checkTokens(mailing, field, insertEvent) { + if (lastEmailTokenAlert) { + lastEmailTokenAlert.close(); + } + var missing, insertable; + if (field == '*') { + insertable = false; + missing = angular.extend({}, + crmMailingMgr.findMissingTokens(mailing, 'body_html'), + crmMailingMgr.findMissingTokens(mailing, 'body_text') + ); + } + else { + insertable = !_.isEmpty(insertEvent); + missing = crmMailingMgr.findMissingTokens(mailing, field); + } + if (!_.isEmpty(missing)) { + lastEmailTokenAlert = crmUiAlert({ + type: 'error', + title: ts('Required tokens'), + templateUrl: '~/crmMailing/dialog/tokenAlert.html', + scope: angular.extend($scope.$new(), { + insertable: insertable, + insertToken: function(token) { + $timeout(function() { + $scope.$broadcast(insertEvent, '{' + token + '}'); + $timeout(function() { + checkTokens(mailing, field, insertEvent); + }); + }); + }, + missing: missing + }) + }); + } + }; + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/ListMailingsCtrl.js b/ang/crmMailing/ListMailingsCtrl.js new file mode 100644 index 0000000000..e60ffe5474 --- /dev/null +++ b/ang/crmMailing/ListMailingsCtrl.js @@ -0,0 +1,10 @@ +(function(angular, $, _) { + + angular.module('crmMailing').controller('ListMailingsCtrl', ['crmLegacy', 'crmNavigator', function ListMailingsCtrl(crmLegacy, crmNavigator) { + // We haven't implemented this in Angular, but some users may get clever + // about typing URLs, so we'll provide a redirect. + var new_url = crmLegacy.url('civicrm/mailing/browse/unscheduled', {reset: 1, scheduled: 'false'}); + crmNavigator.redirect(new_url); + }]); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/MsgTemplateCtrl.js b/ang/crmMailing/MsgTemplateCtrl.js new file mode 100644 index 0000000000..ebcd52e82f --- /dev/null +++ b/ang/crmMailing/MsgTemplateCtrl.js @@ -0,0 +1,43 @@ +(function(angular, $, _) { + + // Controller for the in-place msg-template management + angular.module('crmMailing').controller('MsgTemplateCtrl', function MsgTemplateCtrl($scope, crmMsgTemplates, dialogService) { + var ts = $scope.ts = CRM.ts(null); + $scope.crmMsgTemplates = crmMsgTemplates; + + // @return Promise MessageTemplate (per APIv3) + $scope.saveTemplate = function saveTemplate(mailing) { + var model = { + selected_id: mailing.msg_template_id, + tpl: { + msg_title: '', + msg_subject: mailing.subject, + msg_text: mailing.body_text, + msg_html: mailing.body_html + } + }; + var options = CRM.utils.adjustDialogDefaults({ + autoOpen: false, + height: 'auto', + width: '40%', + title: ts('Save Template') + }); + return dialogService.open('saveTemplateDialog', '~/crmMailing/dialog/saveTemplate.html', model, options) + .then(function(item) { + mailing.msg_template_id = item.id; + return item; + }); + }; + + // @param int id + // @return Promise + $scope.loadTemplate = function loadTemplate(mailing, id) { + return crmMsgTemplates.get(id).then(function(tpl) { + mailing.subject = tpl.msg_subject; + mailing.body_text = tpl.msg_text; + mailing.body_html = tpl.msg_html; + }); + }; + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/PreviewComponentCtrl.js b/ang/crmMailing/PreviewComponentCtrl.js new file mode 100644 index 0000000000..4b99532539 --- /dev/null +++ b/ang/crmMailing/PreviewComponentCtrl.js @@ -0,0 +1,24 @@ +(function(angular, $, _) { + + // Controller for the "Preview Mailing Component" segment + // which displays header/footer/auto-responder + angular.module('crmMailing').controller('PreviewComponentCtrl', function PreviewComponentCtrl($scope, dialogService) { + var ts = $scope.ts = CRM.ts(null); + + $scope.previewComponent = function previewComponent(title, componentId) { + var component = _.where(CRM.crmMailing.headerfooterList, {id: "" + componentId}); + if (!component || !component[0]) { + CRM.alert(ts('Invalid component ID (%1)', { + 1: componentId + })); + return; + } + var options = CRM.utils.adjustDialogDefaults({ + autoOpen: false, + title: title // component[0].name + }); + dialogService.open('previewComponentDialog', '~/crmMailing/dialog/previewComponent.html', component[0], options); + }; + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/PreviewComponentDialogCtrl.js b/ang/crmMailing/PreviewComponentDialogCtrl.js new file mode 100644 index 0000000000..2b1d9f2c63 --- /dev/null +++ b/ang/crmMailing/PreviewComponentDialogCtrl.js @@ -0,0 +1,13 @@ +(function(angular, $, _) { + + // Controller for the "Preview Mailing Component" dialog + // Note: Expects $scope.model to be an object with properties: + // - "name" + // - "subject" + // - "body_html" + // - "body_text" + angular.module('crmMailing').controller('PreviewComponentDialogCtrl', function PreviewComponentDialogCtrl($scope) { + $scope.ts = CRM.ts(null); + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/PreviewMailingDialogCtrl.js b/ang/crmMailing/PreviewMailingDialogCtrl.js new file mode 100644 index 0000000000..9e339b5305 --- /dev/null +++ b/ang/crmMailing/PreviewMailingDialogCtrl.js @@ -0,0 +1,12 @@ +(function(angular, $, _) { + + // Controller for the "Preview Mailing" dialog + // Note: Expects $scope.model to be an object with properties: + // - "subject" + // - "body_html" + // - "body_text" + angular.module('crmMailing').controller('PreviewMailingDialogCtrl', function PreviewMailingDialogCtrl($scope) { + $scope.ts = CRM.ts(null); + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/PreviewRecipCtrl.js b/ang/crmMailing/PreviewRecipCtrl.js new file mode 100644 index 0000000000..371fb8efdd --- /dev/null +++ b/ang/crmMailing/PreviewRecipCtrl.js @@ -0,0 +1,10 @@ +(function(angular, $, _) { + + // Controller for the "Preview Recipients" dialog + // Note: Expects $scope.model to be an object with properties: + // - recipients: array of contacts + angular.module('crmMailing').controller('PreviewRecipCtrl', function($scope) { + $scope.ts = CRM.ts(null); + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/SaveMsgTemplateDialogCtrl.js b/ang/crmMailing/SaveMsgTemplateDialogCtrl.js new file mode 100644 index 0000000000..31ca602452 --- /dev/null +++ b/ang/crmMailing/SaveMsgTemplateDialogCtrl.js @@ -0,0 +1,83 @@ +(function(angular, $, _) { + + // Controller for the "Save Message Template" dialog + // Scope members: + // - [input] "model": Object + // - "selected_id": int + // - "tpl": Object + // - "msg_subject": string + // - "msg_text": string + // - "msg_html": string + angular.module('crmMailing').controller('SaveMsgTemplateDialogCtrl', function SaveMsgTemplateDialogCtrl($scope, crmMsgTemplates, dialogService) { + var ts = $scope.ts = CRM.ts(null); + $scope.saveOpt = {mode: '', newTitle: ''}; + $scope.selected = null; + + $scope.save = function save() { + var tpl = _.extend({}, $scope.model.tpl); + switch ($scope.saveOpt.mode) { + case 'add': + tpl.msg_title = $scope.saveOpt.newTitle; + break; + case 'update': + tpl.id = $scope.selected.id; + tpl.msg_title = $scope.selected.msg_title; + break; + default: + throw 'SaveMsgTemplateDialogCtrl: Unrecognized mode: ' + $scope.saveOpt.mode; + } + return crmMsgTemplates.save(tpl) + .then(function (item) { + CRM.status(ts('Saved')); + return item; + }); + }; + + function scopeApply(f) { + return function () { + var args = arguments; + $scope.$apply(function () { + f.apply(args); + }); + }; + } + + function init() { + crmMsgTemplates.get($scope.model.selected_id).then( + function (tpl) { + $scope.saveOpt.mode = 'update'; + $scope.selected = tpl; + }, + function () { + $scope.saveOpt.mode = 'add'; + $scope.selected = null; + } + ); + // When using dialogService with a button bar, the major button actions + // need to be registered with the dialog widget (and not embedded in + // the body of the dialog). + var buttons = [ + { + text: ts('Save'), + icons: {primary: 'ui-icon-check'}, + click: function () { + $scope.save().then(function (item) { + dialogService.close('saveTemplateDialog', item); + }); + } + }, + { + text: ts('Cancel'), + icons: {primary: 'ui-icon-close'}, + click: function () { + dialogService.cancel('saveTemplateDialog'); + } + } + ]; + dialogService.setButtons('saveTemplateDialog', buttons); + } + + setTimeout(scopeApply(init), 0); + }); + +})(angular, CRM.$, CRM._); diff --git a/ang/crmMailing/ViewRecipCtrl.js b/ang/crmMailing/ViewRecipCtrl.js new file mode 100644 index 0000000000..bc5507d4d2 --- /dev/null +++ b/ang/crmMailing/ViewRecipCtrl.js @@ -0,0 +1,48 @@ +(function(angular, $, _) { + + angular.module('crmMailing').controller('ViewRecipCtrl', function EditRecipCtrl($scope) { + $scope.getIncludesAsString = function(mailing) { + var first = true; + var names = ''; + _.each(mailing.recipients.groups.include, function(id) { + if (!first) { + names = names + ', '; + } + var group = _.where(CRM.crmMailing.groupNames, {id: '' + id}); + names = names + group[0].title; + first = false; + }); + _.each(mailing.recipients.mailings.include, function(id) { + if (!first) { + names = names + ', '; + } + var oldMailing = _.where(CRM.crmMailing.civiMails, {id: '' + id}); + names = names + oldMailing[0].name; + first = false; + }); + return names; + }; + $scope.getExcludesAsString = function(mailing) { + var first = true; + var names = ''; + _.each(mailing.recipients.groups.exclude, function(id) { + if (!first) { + names = names + ', '; + } + var group = _.where(CRM.crmMailing.groupNames, {id: '' + id}); + names = names + group[0].title; + first = false; + }); + _.each(mailing.recipients.mailings.exclude, function(id) { + if (!first) { + names = names + ', '; + } + var oldMailing = _.where(CRM.crmMailing.civiMails, {id: '' + id}); + names = names + oldMailing[0].name; + first = false; + }); + return names; + }; + }); + +})(angular, CRM.$, CRM._);