crmMailing,crmMailingAB - Rename scope.help() to scope.hs()
[civicrm-core.git] / js / angular-crmMailingAB / directives.js
CommitLineData
22bc3e48 1(function (angular, $, _) {
22bc3e48
TO
2
3 // example:
4 // scope.myAbtest = new CrmMailingAB();
5 // <crm-mailing-ab-block-mailing="{fromAddressA: 1, fromAddressB: 1}" crm-abtest="myAbtest" />
1d4d0279 6 var simpleDirectives = {
ef5d18a1
TO
7 crmMailingAbBlockMailing: '~/crmMailingAB/joint-mailing.html',
8 crmMailingAbBlockSetup: '~/crmMailingAB/setup.html'
1d4d0279
TO
9 };
10 _.each(simpleDirectives, function (templateUrl, directiveName) {
dfc2a868 11 angular.module('crmMailingAB').directive(directiveName, function ($parse, crmMailingABCriteria, crmUiHelp) {
1d4d0279
TO
12 var scopeDesc = {crmAbtest: '@'};
13 scopeDesc[directiveName] = '@';
14
15 return {
16 scope: scopeDesc,
17 templateUrl: templateUrl,
18 link: function (scope, elm, attr) {
19 var model = $parse(attr.crmAbtest);
20 scope.abtest = model(scope.$parent);
21 scope.crmMailingConst = CRM.crmMailing;
22 scope.crmMailingABCriteria = crmMailingABCriteria;
5d8901af 23 scope.ts = CRM.ts(null);
1ce7f3e4 24 scope.hs = crmUiHelp({file: 'CRM/Mailing/MailingUI'});
22bc3e48 25
1d4d0279
TO
26 var fieldsModel = $parse(attr[directiveName]);
27 scope.fields = fieldsModel(scope.$parent);
28 }
29 };
30 });
cdb373b4
TO
31 });
32
33 // example: <div crm-mailing-ab-slider ng-model="abtest.ab.group_percentage"></div>
efd95528 34 angular.module('crmMailingAB').directive('crmMailingAbSlider', function () {
cdb373b4
TO
35 return {
36 require: '?ngModel',
37 scope: {},
ef5d18a1 38 templateUrl: '~/crmMailingAB/slider.html',
cdb373b4
TO
39 link: function (scope, element, attrs, ngModel) {
40 var TEST_MIN = 1, TEST_MAX = 50;
41 var sliders = $('.slider-test,.slider-win', element);
42 var sliderTests = $('.slider-test', element);
43 var sliderWin = $('.slider-win', element);
44
5d8901af 45 scope.ts = CRM.ts(null);
cdb373b4
TO
46 scope.testValue = 0;
47 scope.winValue = 100;
48
49 // set the base value (following a GUI event)
50 function setValue(value) {
51 value = Math.min(TEST_MAX, Math.max(TEST_MIN, value));
52 scope.$apply(function () {
53 ngModel.$setViewValue(value);
54 scope.testValue = value;
55 scope.winValue = 100 - (2 * scope.testValue);
56 sliderTests.slider('value', scope.testValue);
57 sliderWin.slider('value', scope.winValue);
58 });
59 }
60
61 sliders.slider({
62 min: 0,
63 max: 100,
64 range: 'min',
65 step: 1
66 });
67 sliderTests.slider({
68 slide: function slideTest(event, ui) {
69 event.preventDefault();
70 setValue(ui.value);
71 }
72 });
73 sliderWin.slider({
74 slide: function slideWinner(event, ui) {
75 event.preventDefault();
76 setValue(Math.round((100 - ui.value) / 2));
77 }
78 });
79
80 ngModel.$render = function () {
81 scope.testValue = ngModel.$viewValue;
82 scope.winValue = 100 - (2 * scope.testValue);
83 sliderTests.slider('value', scope.testValue);
84 sliderWin.slider('value', scope.winValue);
85 };
86 }
87 };
88 });
360aaa75
TO
89
90 // FIXME: This code is long and hasn't been fully working for me, but I've moved it into a spot
91 // where it at least fits in a bit better.
92
93 // example: <div crm-mailing-ab-stats="{split_count: 6, criteria:'Open'}" crm-abtest="myabtest" />
94 // options (see also: Mailing.graph_stats API)
95 // - split_count: int
96 // - criteria: string
97 // - target_date: string, date
98 // - target_url: string
99 angular.module('crmMailingAB').directive('crmMailingAbStats', function (crmApi, $parse, crmNow) {
100 return {
101 scope: {
102 crmMailingAbStats: '@',
103 crmAbtest: '@'
104 },
105 template: '<div class="crm-mailing-ab-stats"></div>',
106 link: function (scope, element, attrs) {
107 var abtestModel = $parse(attrs.crmAbtest);
108 var optionModel = $parse(attrs.crmMailingAbStats);
109 var options = angular.extend({}, optionModel(scope.$parent), {
110 criteria: 'Open', // e.g. 'Open', 'Total Unique Clicks'
111 split_count: 5
112 });
113
114 scope.$watch(attrs.crmAbtest, refresh);
115 function refresh() {
116 var now = crmNow();
117 var abtest = abtestModel(scope.$parent);
118 if (!abtest) {
119 console.log('failed to draw stats - missing abtest');
120 return;
121 }
122
123 scope.graph_data = [
124 {},
125 {},
126 {},
127 {},
128 {}
129 ];
130 var keep_cnt = 0;
131
132 for (var i = 1; i <= options.split_count; i++) {
133 var result = crmApi('MailingAB', 'graph_stats', {
134 id: abtest.ab.id,
135 target_date: abtest.ab.declare_winning_time ? abtest.ab.declare_winning_time : now,
136 target_url: null, // FIXME
137 criteria: options.criteria,
138 split_count: options.split_count,
139 split_count_select: i
140 });
175762a3 141 /*jshint -W083 */
360aaa75
TO
142 result.then(function (data) {
143 var temp = 0;
144 keep_cnt++;
145 for (var key in data.values.A) {
146 temp = key;
147 }
148 var t = data.values.A[temp].time.split(" ");
149 var m = t[0];
150 var year = t[2];
151 var day = t[1].substr(0, t[1].length - 3);
f2bad133 152 var t1, hur, hour, min;
175762a3 153 if (_.isEmpty(t[3])) {
f2bad133
TO
154 t1 = t[4].split(":");
155 hur = t1[0];
360aaa75
TO
156 if (t[5] == "AM") {
157 hour = hur;
158 if (hour == 12) {
159 hour = 0;
160 }
161 }
162 if (t[5] == "PM") {
163 hour = parseInt(hur) + 12;
164 }
f2bad133 165 min = t1[1];
360aaa75
TO
166 }
167 else {
f2bad133
TO
168 t1 = t[3].split(":");
169 hur = t1[0];
360aaa75
TO
170 if (t[4] == "AM") {
171 hour = hur;
172 if (hour == 12) {
173 hour = 0;
174 }
175 }
176 if (t[4] == "PM") {
177 hour = parseInt(hur) + 12;
178 }
f2bad133 179 min = t1[1];
360aaa75
TO
180 }
181 var month = 0;
182 switch (m) {
183 case "January":
184 month = 0;
185 break;
186 case "February":
187 month = 1;
188 break;
189 case "March":
190 month = 2;
191 break;
192 case "April":
193 month = 3;
194 break;
195 case "May":
196 month = 4;
197 break;
198 case "June":
199 month = 5;
200 break;
201 case "July":
202 month = 6;
203 break;
204 case "August":
205 month = 7;
206 break;
207 case "September":
208 month = 8;
209 break;
210 case "October":
211 month = 9;
212 break;
213 case "November":
214 month = 10;
215 break;
216 case "December":
217 month = 11;
218 break;
219
220 }
221 var tp = new Date(year, month, day, hour, min, 0, 0);
222 scope.graph_data[temp - 1] = {
223 time: tp,
224 x: data.values.A[temp].count,
225 y: data.values.B[temp].count
226 };
227
228 if (keep_cnt == options.split_count) {
229 scope.graphload = true;
f2bad133 230 data = scope.graph_data;
360aaa75
TO
231
232 // set up a colour variable
233 var color = d3.scale.category10();
234
235 // map one colour each to x, y and z
236 // keys grabs the key value or heading of each key value pair in the json
237 // but not time
238 color.domain(d3.keys(data[0]).filter(function (key) {
239 return key !== "time";
240 }));
241
242 // create a nested series for passing to the line generator
243 // it's best understood by console logging the data
244 var series = color.domain().map(function (name) {
245 return {
246 name: name,
247 values: data.map(function (d) {
248 return {
249 time: d.time,
250 score: +d[name]
251 };
252 })
253 };
254 });
255
256 // Set the dimensions of the canvas / graph
257 var margin = {
258 top: 30,
259 right: 20,
260 bottom: 40,
261 left: 75
262 },
263 width = 550 - margin.left - margin.right,
264 height = 350 - margin.top - margin.bottom;
265
266 // Set the ranges
267 //var x = d3.time.scale().range([0, width]).domain([0,10]);
268 var x = d3.time.scale().range([0, width]);
269 var y = d3.scale.linear().range([height, 0]);
270
271 // Define the axes
272 var xAxis = d3.svg.axis().scale(x)
273 .orient("bottom").ticks(10);
274
275 var yAxis = d3.svg.axis().scale(y)
276 .orient("left").ticks(5);
277
278 // Define the line
279 // Note you plot the time / score pair from each key you created ealier
280 var valueline = d3.svg.line()
281 .x(function (d) {
282 return x(d.time);
283 })
284 .y(function (d) {
285 return y(d.score);
286 });
287
288 // Adds the svg canvas
289 var svg = d3.select($('.crm-mailing-ab-stats', element)[0])
290 .append("svg")
291 .attr("width", width + margin.left + margin.right)
292 .attr("height", height + margin.top + margin.bottom)
293 .append("g")
294 .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
295
296 // Scale the range of the data
297 x.domain(d3.extent(data, function (d) {
298 return d.time;
299 }));
300
301 // note the nested nature of this you need to dig an additional level
302 y.domain([
303 d3.min(series, function (c) {
304 return d3.min(c.values, function (v) {
305 return v.score;
306 });
307 }),
308 d3.max(series, function (c) {
309 return d3.max(c.values, function (v) {
310 return v.score;
311 });
312 })
313 ]);
314 svg.append("text") // text label for the x axis
315 .attr("x", width / 2)
316 .attr("y", height + margin.bottom)
317 .style("text-anchor", "middle")
318 .text("Time");
319
320 svg.append("text") // text label for the x axis
321 .style("text-anchor", "middle")
322 .text(scope.winnercriteria).attr("transform",function (d) {
f2bad133 323 return "rotate(-90)";
360aaa75
TO
324 }).attr("x", -height / 2)
325 .attr("y", -30);
326
327 // create a variable called series and bind the date
328 // for each series append a g element and class it as series for css styling
f2bad133 329 series = svg.selectAll(".series")
360aaa75
TO
330 .data(series)
331 .enter().append("g")
332 .attr("class", "series");
333
334 // create the path for each series in the variable series i.e. x, y and z
335 // pass each object called x, y nad z to the lne generator
336 series.append("path")
337 .attr("class", "line")
338 .attr("d", function (d) {
339 // console.log(d); // to see how d3 iterates through series
340 return valueline(d.values);
341 })
342 .style("stroke", function (d) {
343 return color(d.name);
344 });
345
346 // Add the X Axis
347 svg.append("g") // Add the X Axis
348 .attr("class", "x axis")
349 .attr("transform", "translate(0," + height + ")")
350 .call(xAxis)
351 .selectAll("text")
352 .attr("transform", function (d) {
353 return "rotate(-30)";
354 });
355
356 // Add the Y Axis
357 svg.append("g") // Add the Y Axis
358 .attr("class", "y axis")
359 .call(yAxis);
360 }
361 });
362 }
363 }
364 } // link()
365 };
366 });
22bc3e48 367})(angular, CRM.$, CRM._);