CRM-15578 - MsgTemplateCtrl - Don't hardcode dependence on upstream "scope.mailing"
[civicrm-core.git] / js / angular-crmMailing2-directives.js
CommitLineData
5d72b4e2
TO
1(function (angular, $, _) {
2 var partialUrl = function (relPath) {
3 return CRM.resourceUrls['civicrm'] + '/partials/crmMailing2/' + relPath;
4 };
5
6 var crmMailing2 = angular.module('crmMailing2');
7
18da0e87
TO
8 // The following directives have the same simple implementation -- load
9 // a template and export a "mailing" object into scope.
10 var simpleBlocks = {
11 crmMailingBlockHeaderFooter: partialUrl('headerFooter.html'),
12 crmMailingBlockMailing: partialUrl('mailing.html'),
13 crmMailingBlockPreview: partialUrl('preview.html'),
14 crmMailingBlockPublication: partialUrl('publication.html'),
15 crmMailingBlockResponses: partialUrl('responses.html'),
16 crmMailingBlockReview: partialUrl('review.html'),
17 crmMailingBlockSchedule: partialUrl('schedule.html'),
18 crmMailingBlockSummary: partialUrl('summary.html'),
19 crmMailingBlockTracking: partialUrl('tracking.html'),
20 crmMailingBodyHtml: partialUrl('body_html.html'),
21 crmMailingBodyText: partialUrl('body_text.html')
22 };
23 _.each(simpleBlocks, function(templateUrl, directiveName){
24 crmMailing2.directive(directiveName, function ($parse) {
25 return {
26 scope: {
27 crmMailing: '@'
28 },
29 templateUrl: templateUrl,
30 link: function (scope, elm, attr) {
31 var model = $parse(attr.crmMailing);
32 scope.mailing = model(scope.$parent);
33 scope.crmMailingConst = CRM.crmMailing;
34 scope.ts = CRM.ts('CiviMail');
35 }
36 };
37 });
f8601d61
TO
38 });
39
f4f103fa 40 crmMailing2.directive('crmMailingReviewBool', function () {
47bacc20
TO
41 return {
42 scope: {
43 crmOn: '@',
44 crmTitle: '@'
45 },
46 template: '<span ng-class="spanClasses"><span class="icon" ng-class="iconClasses"></span>{{crmTitle}} </span>',
f4f103fa 47 link: function (scope, element, attrs) {
47bacc20
TO
48 function refresh() {
49 if (scope.$parent.$eval(attrs.crmOn)) {
50 scope.spanClasses = {'crmMailing2-active': true};
51 scope.iconClasses = {'ui-icon-check': true};
f4f103fa
TO
52 }
53 else {
47bacc20
TO
54 scope.spanClasses = {'crmMailing2-inactive': true};
55 scope.iconClasses = {'ui-icon-close': true};
56 }
57 scope.crmTitle = scope.$parent.$eval(attrs.crmTitle);
58 }
f4f103fa 59
47bacc20
TO
60 refresh();
61 scope.$parent.$watch(attrs.crmOn, refresh);
62 scope.$parent.$watch(attrs.crmTitle, refresh);
63 }
64 };
65 });
66
5d72b4e2
TO
67 // example: <input name="subject" /> <input crm-mailing-token crm-for="subject"/>
68 // WISHLIST: Instead of global CRM.crmMailing.mailTokens, accept token list as an input
38737af8 69 crmMailing2.directive('crmMailingToken', function (crmUiId) {
5d72b4e2
TO
70 return {
71 scope: {
72 crmFor: '@'
73 },
74 template: '<input type="text" class="crmMailingToken" />',
75 link: function (scope, element, attrs) {
76 // 1. Find the corresponding input element (crmFor)
77
78 var form = $(element).closest('form');
79 var crmForEl = $('input[name="' + attrs.crmFor + '"],textarea[name="' + attrs.crmFor + '"]', form);
80 if (form.length != 1 || crmForEl.length != 1) {
38737af8 81 if (console.log) {
5d72b4e2 82 console.log('crmMailingToken cannot be matched to input element. Expected to find one form and one input.', form.length, crmForEl.length);
38737af8 83 }
5d72b4e2
TO
84 return;
85 }
86
87 // 2. Setup the token selector
38737af8
TO
88 $(element).select2({
89 width: "10em",
5d72b4e2
TO
90 dropdownAutoWidth: true,
91 data: CRM.crmMailing.mailTokens,
92 placeholder: ts('Insert')
93 });
94 $(element).on('select2-selecting', function (e) {
38737af8
TO
95 var id = crmUiId(crmForEl);
96 if (CKEDITOR.instances[id]) {
97 CKEDITOR.instances[id].insertText(e.val);
98 $(element).select2('close').select2('val', '');
99 CKEDITOR.instances[id].focus();
100 }
101 else {
102 var origVal = crmForEl.val();
103 var origPos = crmForEl[0].selectionStart;
104 var newVal = origVal.substring(0, origPos) + e.val + origVal.substring(origPos, origVal.length);
105 crmForEl.val(newVal);
106 var newPos = (origPos + e.val.length);
107 crmForEl[0].selectionStart = newPos;
108 crmForEl[0].selectionEnd = newPos;
5d72b4e2 109
38737af8
TO
110 $(element).select2('close').select2('val', '');
111 crmForEl.triggerHandler('change');
112 crmForEl.focus();
113 }
5d72b4e2
TO
114
115 e.preventDefault();
116 });
117 }
118 };
119 });
120
b0461279 121 // example: <select multiple crm-mailing-recipients crm-mailing="mymailing" crm-avail-groups="myGroups" crm-avail-mailings="myMailings"></select>
f8601d61 122 // FIXME: participate in ngModel's validation cycle
b0461279
TO
123 crmMailing2.directive('crmMailingRecipients', function () {
124 return {
125 restrict: 'AE',
126 scope: {
127 crmAvailGroups: '@', // available groups
128 crmAvailMailings: '@', // available mailings
129 crmMailing: '@' // the mailing for which we are choosing recipients
130 },
131 templateUrl: partialUrl('directive/recipients.html'),
132 link: function (scope, element, attrs) {
133 scope.mailing = scope.$parent.$eval(attrs.crmMailing);
134 scope.groups = scope.$parent.$eval(attrs.crmAvailGroups);
135 scope.mailings = scope.$parent.$eval(attrs.crmAvailMailings);
136
137 scope.ts = CRM.ts('CiviMail');
138
139 /// Convert MySQL date ("yyyy-mm-dd hh:mm:ss") to JS date object
140 scope.parseDate = function (date) {
f4f103fa 141 if (!angular.isString(date)) {
b0461279 142 return date;
f4f103fa 143 }
b0461279
TO
144 var p = date.split(/[\- :]/);
145 return new Date(p[0], p[1], p[2], p[3], p[4], p[5]);
146 };
147
148 /// Remove {value} from {array}
149 function arrayRemove(array, value) {
150 var idx = array.indexOf(value);
151 if (idx >= 0) {
152 array.splice(idx, 1);
153 }
154 }
155
156 // @param string id an encoded string like "4 civicrm_mailing include"
157 // @return Object keys: entity_id, entity_type, mode
158 function convertValueToObj(id) {
159 var a = id.split(" ");
160 return {entity_id: parseInt(a[0]), entity_type: a[1], mode: a[2]};
161 }
162
163 // @param Object mailing
164 // @return array list of values like "4 civicrm_mailing include"
165 function convertMailingToValues(mailing) {
166 var r = [];
167 angular.forEach(mailing.groups.include, function (v) {
168 r.push(v + " civicrm_group include");
169 });
170 angular.forEach(mailing.groups.exclude, function (v) {
171 r.push(v + " civicrm_group exclude");
172 });
173 angular.forEach(mailing.mailings.include, function (v) {
174 r.push(v + " civicrm_mailing include");
175 });
176 angular.forEach(mailing.mailings.exclude, function (v) {
177 r.push(v + " civicrm_mailing exclude");
178 });
179 return r;
180 }
181
182 // Update $(element) view based on latest data
183 function refreshUI() {
184 $(element).select2('val', convertMailingToValues(scope.mailing));
185 }
186
187 /// @return string HTML representingn an option
188 function formatItem(item) {
189 if (!item.id) {
190 // return `text` for optgroup
191 return item.text;
192 }
193 var option = convertValueToObj(item.id);
194 var icon = (option.entity_type === 'civicrm_mailing') ? 'EnvelopeIn.gif' : 'group.png';
195 var spanClass = (option.mode == 'exclude') ? 'crmMailing2-exclude' : 'crmMailing2-include';
196 return "<img src='../../sites/all/modules/civicrm/i/" + icon + "' height=12 width=12 /> <span class='" + spanClass + "'>" + item.text + "</span>";
197 }
198
199 $(element).select2({
200 dropdownAutoWidth: true,
201 placeholder: "Groups or Past Recipients",
202 formatResult: formatItem,
203 formatSelection: formatItem,
204 escapeMarkup: function (m) {
205 return m;
206 },
207 });
208
209 $(element).on('select2-selecting', function (e) {
210 var option = convertValueToObj(e.val);
211 var typeKey = option.entity_type == 'civicrm_mailing' ? 'mailings' : 'groups';
212 if (option.mode == 'exclude') {
213 scope.mailing[typeKey].exclude.push(option.entity_id);
214 arrayRemove(scope.mailing[typeKey].include, option.entity_id);
f4f103fa
TO
215 }
216 else {
b0461279
TO
217 scope.mailing[typeKey].include.push(option.entity_id);
218 arrayRemove(scope.mailing[typeKey].exclude, option.entity_id);
219 }
220 scope.$apply();
221 $(element).select2('close');
222 e.preventDefault();
223 });
224
225 $(element).on("select2-removing", function (e) {
226 var option = convertValueToObj(e.val);
227 var typeKey = option.entity_type == 'civicrm_mailing' ? 'mailings' : 'groups';
f4f103fa 228 scope.$parent.$apply(function () {
89a50c67
TO
229 arrayRemove(scope.mailing[typeKey][option.mode], option.entity_id);
230 });
b0461279
TO
231 e.preventDefault();
232 });
233
234 scope.$watchCollection(attrs.crmMailing + ".groups.include", refreshUI);
235 scope.$watchCollection(attrs.crmMailing + ".groups.exclude", refreshUI);
236 scope.$watchCollection(attrs.crmMailing + ".mailings.include", refreshUI);
237 scope.$watchCollection(attrs.crmMailing + ".mailings.exclude", refreshUI);
238 setTimeout(refreshUI, 50);
239 }
240 };
241 });
242
5d72b4e2 243})(angular, CRM.$, CRM._);