active_frontend 14.0.81 → 14.0.82

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 89561af6ed088ed080187332c73c80be8cb12c91
4
- data.tar.gz: 73ae8b120387fee13410c469a07279a41cbbcfff
3
+ metadata.gz: 20013c44be81d37cbe7d143efa16e805360ad598
4
+ data.tar.gz: 4076e7c6bac0423fa158d0abda3a76a1e83b5ac3
5
5
  SHA512:
6
- metadata.gz: a8450019cbeb9a6033074ad449e989e8c0269942b4e58a00167392a84f6a63edda440e04563bef3f03b9eecf90b72752761e25f0c60218d9141444f691ddd3d2
7
- data.tar.gz: 629cb40ede38167b660b2db308205c98ed7215d0a8d6667bb206576750cf252aca7567604bb8094a18da97f231cdc6f9cfaa35c699fd5a394f9ebc2de367dcf0
6
+ metadata.gz: 1e986cf2dcd0f9c5254e9cdd36aba02fe9ec5aa8df655985c9032ddb04bbb0c4e7389d94b0b4c03cbdcb399b144fa14b71bd42c8d32b581049ea8d7774f13d13
7
+ data.tar.gz: 39214e183f7a88a3d5c0ea20fce94ebc3ff02cd61fd9a1d037860a0b69de3ef2e96b068e5435312ce7b44a0a8538fc16571751ac177a499d901df5ebe0f675a9
@@ -1,3 +1,3 @@
1
1
  module ActiveFrontend
2
- VERSION = '14.0.81'.freeze
2
+ VERSION = '14.0.82'.freeze
3
3
  end
@@ -40,6 +40,7 @@
40
40
  // ==================================================
41
41
  //= require extensions/_calendar
42
42
  //= require extensions/_chart
43
+ //= require extensions/_cohort
43
44
  //= require extensions/_copy
44
45
  //= require extensions/_map
45
46
  //= require extensions/_wysiwyg
@@ -57,6 +57,7 @@
57
57
  @import 'components/calendar';
58
58
  @import 'components/map';
59
59
  @import 'components/wysiwyg';
60
+ @import 'components/cohort';
60
61
  @import 'components/chart';
61
62
  @import 'blocks/common';
62
63
  @import 'blocks/typography';
@@ -40,6 +40,7 @@
40
40
  // ==================================================
41
41
  //= require extensions/_calendar
42
42
  //= require extensions/_chart
43
+ //= require extensions/_cohort
43
44
  //= require extensions/_copy
44
45
  //= require extensions/_map
45
46
  //= require extensions/_wysiwyg
@@ -0,0 +1,342 @@
1
+ ;(function(globals) {
2
+ var TYPE_PERCENTAGE = 'percentage';
3
+ var TYPE_ABSOLUTE = 'absolute';
4
+
5
+ var cohortDefaults = {
6
+ monthNames: [
7
+ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
8
+ 'October', 'November', 'December'
9
+ ],
10
+ shortMonthNames: [
11
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
12
+ ],
13
+ repeatLevels: {
14
+ 'low': [0, 10],
15
+ 'medium-low': [10, 20],
16
+ 'medium': [20, 30],
17
+ 'medium-high': [30, 40],
18
+ 'high': [40, 60],
19
+ 'hot': [60, 70],
20
+ 'extra-hot': [70, 100]
21
+ },
22
+ labels: {
23
+ time: 'Time',
24
+ total: 'Total',
25
+ weekOf: 'Week of'
26
+ },
27
+ emptyPlaceholder: '---',
28
+ timeInterval: 'monthly',
29
+ drawEmptyCells: true,
30
+ rawNumberOnHover: true,
31
+ initialIntervalNumber: 1,
32
+ percentagePercision: 1,
33
+ classPrefix: 'cohort-',
34
+
35
+ formatHeaderLabel: function(i) {
36
+ return (this.initialIntervalNumber - 1 + i).toString();
37
+ },
38
+ formatDailyLabel: function(date, i) {
39
+ date.setDate(date.getDate() + i);
40
+ return this.monthNames[date.getMonth()] + ' ' + date.getDate() + ', ' + getYear(date);
41
+ },
42
+ formatWeeklyLabel: function(date, i) {
43
+ date.setDate(date.getDate() + i * 7);
44
+ return this.labels.weekOf + ' ' + this.shortMonthNames[date.getMonth()] + ' ' +
45
+ date.getDate() + ', ' + getYear(date);
46
+ },
47
+ formatMonthlyLabel: function(date, i) {
48
+ date.setMonth(date.getMonth() + i);
49
+ return this.monthNames[date.getMonth()] + ' ' + getYear(date);
50
+ },
51
+ formatYearlyLabel: function(date, i) {
52
+ return date.getYear() + 1900 + i;
53
+ }
54
+ },
55
+
56
+ defaults = cohortDefaults;
57
+
58
+ function extend() {
59
+ var target = arguments[0];
60
+
61
+ if (arguments.length === 1) return target;
62
+
63
+ for (var i = 1; i < arguments.length; i++) {
64
+ var source = arguments[i];
65
+ for (var prop in source) target[prop] = source[prop];
66
+ }
67
+
68
+ return target;
69
+ }
70
+
71
+ function isNumber(val) {
72
+ return Object.prototype.toString.call(val) === '[object Number]';
73
+ }
74
+
75
+ function isEmpty(val) {
76
+ return val === null || val === undefined || val === '';
77
+ }
78
+
79
+ function getYear(date) {
80
+ return date.getFullYear ? date.getFullYear() : date.getYear() + 1900;
81
+ }
82
+
83
+ function formatValue(value, base, valueType) {
84
+ if (valueType === TYPE_ABSOLUTE) {
85
+ return value;
86
+ } else if (isNumber(value) && base > 0) {
87
+ return (value / base * 100).toFixed(cohortDefaults.percentagePercision);
88
+ } else if (isNumber(value)) {
89
+ return '0.00';
90
+ }
91
+ }
92
+
93
+ function setText(element, text) {
94
+ if (document.all) {
95
+ element.innerText = text;
96
+ } else {
97
+ element.textContent = text;
98
+ }
99
+ }
100
+
101
+ function setTitle(element, text, type) {
102
+ if (type === TYPE_ABSOLUTE) {
103
+ element.dataset.originalTitle = text;
104
+ } else {
105
+ element.dataset.originalTitle = text + '%';
106
+ }
107
+ }
108
+
109
+ function addClass(element, className) {
110
+ if (!new RegExp(className).test(element.className)) {
111
+ element.className += ' ' + className;
112
+ }
113
+ }
114
+
115
+ function removeClass(element, className) {
116
+ element.className = element.className.replace(className, '');
117
+ }
118
+
119
+ function prefixClass(className, classPrefix) {
120
+ var prefixedClass = [],
121
+ classes = className.split(/\s+/);
122
+
123
+ for (var i in classes) {
124
+ prefixedClass.push(classPrefix + classes[i]);
125
+ }
126
+
127
+ return prefixedClass.join(' ');
128
+ }
129
+
130
+ var draw = function(cohort, values, container) {
131
+ if (!values) throw new Error ('Please provide the values data');
132
+ if (!container) throw new Error ('Please provide the values container');
133
+
134
+ var config = cohort.config,
135
+ initialDate = cohort.initialDate;
136
+
137
+ function create(el, options) {
138
+ options = options || {};
139
+
140
+ el = document.createElement(el);
141
+
142
+ if ((className = options.className)) {
143
+ delete options.className;
144
+ el.className = prefixClass(className, config.classPrefix);
145
+ }
146
+
147
+ if (!isEmpty(options.text)) {
148
+ var text = options.text.toString();
149
+ setText(el, text);
150
+ delete options.text;
151
+ }
152
+
153
+ if (options.tooltip) {
154
+ el.dataset.hover = 'tooltip';
155
+ el.dataset.container = 'body';
156
+ delete options.tooltip;
157
+ }
158
+
159
+ for (var option in options) {
160
+ if ((opt = options[option])) el[option] = opt;
161
+ }
162
+
163
+ return el;
164
+ }
165
+
166
+ function drawHeader(data) {
167
+ var th = create('tr'),
168
+ monthLength = data[0].length;
169
+
170
+ th.appendChild(create('th', { text: config.labels.time, className: 'time' }));
171
+
172
+ for (var i = 0; i < monthLength; i++) {
173
+ if (i > config.maxColumns) break;
174
+ var text = i === 0 ? config.labels.total : config.formatHeaderLabel(i);
175
+ th.appendChild(create('th', { text: text, className: 'total' }));
176
+ }
177
+
178
+ return th;
179
+ }
180
+
181
+ function formatTimeLabel(initial, timeInterval, i) {
182
+ var date = new Date(initial.getTime()),
183
+ formatFn = null;
184
+
185
+ if (timeInterval === 'daily') {
186
+ formatFn = 'formatDailyLabel';
187
+ } else if (timeInterval === 'weekly') {
188
+ formatFn = 'formatWeeklyLabel';
189
+ } else if (timeInterval === 'monthly') {
190
+ formatFn = 'formatMonthlyLabel';
191
+ } else if (timeInterval === 'yearly') {
192
+ formatFn = 'formatYearlyLabel';
193
+ } else {
194
+ throw new Error('Interval not supported');
195
+ }
196
+
197
+ return config[formatFn].call(config, date, i);
198
+ }
199
+
200
+ function drawCells(data) {
201
+ var fragment = document.createDocumentFragment(),
202
+ startMonth = config.maxRows ? data.length - config.maxRows : 0,
203
+ classNameFor = function(value) {
204
+ var levels = config.repeatLevels,
205
+ floatValue = value && parseFloat(value),
206
+ highestLevel = null,
207
+ classNames = ['percentage'];
208
+
209
+ for (var level in levels) {
210
+ if (floatValue >= levels[level][0] && floatValue < levels[level][1]) {
211
+ classNames.push(level);
212
+ return classNames.join(' ');
213
+ }
214
+
215
+ highestLevel = level;
216
+ }
217
+
218
+ classNames.push(highestLevel);
219
+ return classNames.join(' ');
220
+ };
221
+
222
+ for (var i = startMonth; i < data.length; i++) {
223
+ var tr = create('tr'),
224
+ row = data[i],
225
+ baseValue = row[0];
226
+
227
+ tr.appendChild(create('td', {
228
+ className: 'label',
229
+ text: formatTimeLabel(initialDate, config.timeInterval, i)
230
+ }));
231
+
232
+ for (var j = 0; j < data[0].length; j++) {
233
+ if (j > config.maxColumns) break;
234
+
235
+ var value = row[j],
236
+ cellValue = j === 0 ? value : formatValue(value, baseValue, TYPE_PERCENTAGE),
237
+ opts = {};
238
+
239
+ if (!isEmpty(cellValue)) {
240
+ var title = j > 0 && config.rawNumberOnHover ? value : null;
241
+
242
+ opts = {
243
+ text: cellValue,
244
+ title: title,
245
+ className: j === 0 ? 'total' : classNameFor(cellValue),
246
+ tooltip: title !== null
247
+ };
248
+ } else if (config.drawEmptyCells) {
249
+ opts = { text: config.emptyPlaceholder, className: 'empty' };
250
+ }
251
+
252
+ tr.appendChild(create('td', opts));
253
+ }
254
+
255
+ fragment.appendChild(tr);
256
+ }
257
+
258
+ return fragment;
259
+ }
260
+
261
+ var mainContainer = create('div', { className: 'container' }),
262
+ table = create('table', { className: 'table' });
263
+
264
+ table.appendChild(drawHeader(values));
265
+ table.appendChild(drawCells(values));
266
+
267
+ if ((title = config.title)) {
268
+ mainContainer.appendChild(create('div', { text: title, className: 'title' }));
269
+ }
270
+
271
+ mainContainer.appendChild(table);
272
+
273
+ container.innerHTML = '';
274
+ container.appendChild(mainContainer);
275
+ };
276
+
277
+ var Cohort = function(opts) {
278
+ if (!(initialDate = opts.initialDate)) throw new Error('The initialDate is a required argument');
279
+ delete opts.initialDate;
280
+
281
+ this.initialDate = initialDate;
282
+ this.valueType = TYPE_PERCENTAGE;
283
+ this.config = extend({}, Cohort.getDefaults(), opts || {});
284
+
285
+ this.toggleValues = function() {
286
+ this.valueType = this.valueType === TYPE_PERCENTAGE ? TYPE_ABSOLUTE : TYPE_PERCENTAGE;
287
+ var table = opts.container.getElementsByTagName('table')[0];
288
+
289
+ for (var rowIndex = 0; rowIndex < opts.values.length; rowIndex++) {
290
+ var tr = table.children[rowIndex + 1];
291
+
292
+ for (var cellIndex = 1; cellIndex < opts.values[rowIndex].length; cellIndex++) {
293
+ var td = tr.children[cellIndex + 1];
294
+ var absValue = formatValue(opts.values[rowIndex][cellIndex], opts.values[rowIndex][0], TYPE_ABSOLUTE);
295
+ var perValue = formatValue(opts.values[rowIndex][cellIndex], opts.values[rowIndex][0], TYPE_PERCENTAGE);
296
+
297
+ if (this.valueType === TYPE_ABSOLUTE) {
298
+ setText(td, absValue);
299
+ setTitle(td, perValue, TYPE_PERCENTAGE);
300
+ removeClass(td, prefixClass('percentage', this.config.classPrefix));
301
+ } else {
302
+ setText(td, perValue);
303
+ setTitle(td, absValue, TYPE_ABSOLUTE);
304
+ addClass(td, prefixClass('percentage', this.config.classPrefix));
305
+ }
306
+ }
307
+ }
308
+ };
309
+ };
310
+
311
+ extend(Cohort, {
312
+ getDefaults: function() {
313
+ return defaults;
314
+ },
315
+ setDefaults: function(def) {
316
+ defaults = extend({}, cohortDefaults, def);
317
+ },
318
+ resetDefaults: function() {
319
+ defaults = cohortDefaults;
320
+ },
321
+ draw: function(options) {
322
+ var cohort = new Cohort(options);
323
+ draw(cohort, options.values, options.container);
324
+ return cohort;
325
+ }
326
+ });
327
+
328
+ if (typeof jQuery !== 'undefined' && jQuery !== null) {
329
+ jQuery.fn.cohort = function(options) {
330
+ return this.each(function() {
331
+ options.container = this;
332
+ return Cohort.draw(options);
333
+ });
334
+ };
335
+ }
336
+
337
+ if (globals.exports) {
338
+ globals.exports = Cohort;
339
+ } else {
340
+ globals.Cohort = Cohort;
341
+ }
342
+ })(typeof module === 'function' ? module : window);
@@ -57,6 +57,7 @@
57
57
  @import 'components/calendar';
58
58
  @import 'components/map';
59
59
  @import 'components/wysiwyg';
60
+ @import 'components/cohort';
60
61
  @import 'components/chart';
61
62
  @import 'blocks/common';
62
63
  @import 'blocks/typography';
@@ -0,0 +1,87 @@
1
+ // Table of Contents
2
+ // ==================================================
3
+ // Cohort
4
+
5
+ // scss-lint:disable ImportantRule
6
+ // scss-lint:disable NestingDepth
7
+
8
+ // Cohort
9
+ // ==================================================
10
+ .cohort-title {
11
+ font-size: text-size(b);
12
+ font-weight: text-weight(semibold);
13
+ padding-bottom: 20px;
14
+ text-align: center;
15
+ }
16
+ .cohort-table {
17
+ background: light-color(light-haze);
18
+ border: 1px solid color(dark-haze);
19
+ border-spacing: 0;
20
+ border-collapse: collapse;
21
+ font-size: text-size(b);
22
+ margin: auto;
23
+ max-width: 100%;
24
+ width: 100%;
25
+
26
+ tr:first-child {
27
+ th {
28
+ border-bottom-width: 3px;
29
+
30
+ &:last-child { border-right: 0; }
31
+ }
32
+ }
33
+
34
+ td,
35
+ th {
36
+ text-align: center;
37
+ padding: 8px;
38
+ }
39
+
40
+ th {
41
+ border-bottom: 1px solid color(dark-haze);
42
+ border-right: 1px solid color(dark-haze);
43
+ font-weight: text-weight(semibold);
44
+ }
45
+ }
46
+ .cohort-percentage {
47
+ &::after {
48
+ content: '%';
49
+ margin-left: 2px;
50
+ }
51
+ }
52
+ .cohort-label,
53
+ .cohort-total {
54
+ border-bottom: 1px solid color(dark-haze);
55
+ border-right: 1px solid color(dark-haze);
56
+ font-weight: text-weight(semibold);
57
+ }
58
+ .cohort-label {
59
+ text-align: left !important;
60
+ width: 140px;
61
+ }
62
+ .cohort-total {
63
+ border-right-width: 3px;
64
+ font-weight: text-weight(normal);
65
+ width: 80px;
66
+ }
67
+ .cohort-empty {
68
+ background: color(white);
69
+ border-bottom: 1px solid color(dark-haze);
70
+ border-right: 1px solid color(dark-haze);
71
+ }
72
+ .cohort-low,
73
+ .cohort-medium-low,
74
+ .cohort-medium,
75
+ .cohort-medium-high,
76
+ .cohort-high,
77
+ .cohort-hot,
78
+ .cohort-extra-hot { color: color(white); }
79
+ @each $name, $multiplier in (low: 3, medium-low: 2, medium: 1) {
80
+ .cohort-#{$name} { background: lighten(color(primary), percentage((7.5 * $multiplier) / 100)); }
81
+ }
82
+ .cohort-medium-high {
83
+ background: color(primary);
84
+ }
85
+ @each $name, $multiplier in (high: 1, hot: 2, extra-hot: 3) {
86
+ .cohort-#{$name} { background: darken(color(primary), percentage((7.5 * $multiplier) / 100)); }
87
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_frontend
3
3
  version: !ruby/object:Gem::Version
4
- version: 14.0.81
4
+ version: 14.0.82
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-07 00:00:00.000000000 Z
11
+ date: 2017-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -247,6 +247,7 @@ files:
247
247
  - vendor/assets/javascripts/base/_typeahead.js
248
248
  - vendor/assets/javascripts/extensions/_calendar.js
249
249
  - vendor/assets/javascripts/extensions/_chart.js
250
+ - vendor/assets/javascripts/extensions/_cohort.js
250
251
  - vendor/assets/javascripts/extensions/_copy.js
251
252
  - vendor/assets/javascripts/extensions/_map.js
252
253
  - vendor/assets/javascripts/extensions/_wysiwyg.js
@@ -277,6 +278,7 @@ files:
277
278
  - vendor/assets/stylesheets/components/_carousel.scss
278
279
  - vendor/assets/stylesheets/components/_chart.scss
279
280
  - vendor/assets/stylesheets/components/_choicepicker.scss
281
+ - vendor/assets/stylesheets/components/_cohort.scss
280
282
  - vendor/assets/stylesheets/components/_collapse.scss
281
283
  - vendor/assets/stylesheets/components/_colorpicker.scss
282
284
  - vendor/assets/stylesheets/components/_datepicker.scss