Nuria has submitted this change and it was merged.
Change subject: Split up utils
......................................................................
Split up utils
The utils file was getting large and it sucked to have to include all
the dependencies just to do a simple thing.
Change-Id: Ie7d6f3b1305a291392f5acae387e3d65b4c69d36
---
M src/app/data-converters/simple-separated-values.js
M src/app/require.config.js
A src/app/utils/arrays.js
A src/app/utils/colors.js
A src/app/utils/datetime.js
A src/app/utils/elements.js
A src/app/utils/numbers.js
A src/app/utils/strings.js
M src/components/annotation-list/annotation-list.js
M src/components/compare-layout/compare-layout.js
M src/components/metric-selector/metric-selector.js
M src/components/project-selector/bindings.js
M src/components/project-selector/project-selector.js
M src/components/visualizers/rickshaw-timeseries/bindings.js
M src/components/visualizers/visualizer/visualizer.js
D src/lib/utils.js
A test/app/utils.js
17 files changed, 240 insertions(+), 109 deletions(-)
Approvals:
Nuria: Verified; Looks good to me, approved
diff --git a/src/app/data-converters/simple-separated-values.js
b/src/app/data-converters/simple-separated-values.js
index 7cce9bf..fb595f4 100644
--- a/src/app/data-converters/simple-separated-values.js
+++ b/src/app/data-converters/simple-separated-values.js
@@ -2,9 +2,10 @@
* This module returns a method that knows how to parse a file with values
* separated by arbitrary characters on lines separated by arbitrary
characters
*/
+'use strict';
define(function (require) {
- var util = require('utils');
+ var stringUtils = require('utils.strings');
/**
* Parses a CSV, TSV, or similar into an array of rows.
@@ -35,7 +36,7 @@
if (rows.length <= 1) { return []; }
// try to determine the type of each column
- var parsers = rows[1].map(util.parserFromSample);
+ var parsers = rows[1].map(stringUtils.parserFromSample);
var trimmer = function (s) { return s.trim(); };
// NOTE: will return the header but take care not to parse it
diff --git a/src/app/require.config.js b/src/app/require.config.js
index 196ff05..c8471ec 100644
--- a/src/app/require.config.js
+++ b/src/app/require.config.js
@@ -37,7 +37,6 @@
'dataConverterFactory' : 'app/data-converters/factory',
'typeahead' :
'bower_modules/typeahead.js/dist/typeahead.bundle',
'ajaxWrapper' : 'lib/ajax-wrapper',
- 'utils' : 'lib/utils',
'window' : 'lib/window',
'stateManager' : 'lib/state-manager',
'sitematrix' : 'app/sitematrix',
@@ -68,6 +67,14 @@
'converters.annotations' :
'app/data-converters/annotations-data',
'converters.pageview-api-response':
'app/data-converters/pageview-api-response',
+ // *** utils
+ 'utils.arrays' : 'app/utils/arrays',
+ 'utils.strings' : 'app/utils/strings',
+ 'utils.datetime' : 'app/utils/datetime',
+ 'utils.numbers' : 'app/utils/numbers',
+ 'utils.colors' : 'app/utils/colors',
+ 'utils.elements' : 'app/utils/elements',
+
// *** lib
'lib.polyfills' : 'lib/polyfills',
},
diff --git a/src/app/utils/arrays.js b/src/app/utils/arrays.js
new file mode 100644
index 0000000..a633291
--- /dev/null
+++ b/src/app/utils/arrays.js
@@ -0,0 +1,23 @@
+'use strict';
+define(function () {
+
+ return {
+ sortByName: function (a, b) {
+ // NOTE: this purposefully sorts uppercase before lowercase
+ return a.name === b.name ?
+ 0 : a.name > b.name ? 1 : -1;
+ },
+ sortByNameIgnoreCase: function (a, b) {
+ return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
+ },
+
+ /**
+ * Returns an array with "n" undefined values
+ */
+ filler: function (n) {
+ var empty = [];
+ empty.length = n;
+ return Array.apply(null, empty);
+ },
+ };
+});
diff --git a/src/app/utils/colors.js b/src/app/utils/colors.js
new file mode 100644
index 0000000..ac8160f
--- /dev/null
+++ b/src/app/utils/colors.js
@@ -0,0 +1,26 @@
+'use strict';
+define(function () {
+
+ return {
+ /**
+ * Poor man's category10 scale from d3, for when you don't want to
+ * import the whole library for a simple color scale
+ */
+ category10: function (domain, range) {
+ range = range || [
+ '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
+ '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'
+ ];
+ domain = domain || [];
+ return function (x) {
+
+ var index = domain.indexOf(x);
+ if (index < 0) {
+ index = domain.push(x) - 1;
+ }
+
+ return range[index % range.length];
+ };
+ },
+ };
+});
diff --git a/src/app/utils/datetime.js b/src/app/utils/datetime.js
new file mode 100644
index 0000000..a0df1a4
--- /dev/null
+++ b/src/app/utils/datetime.js
@@ -0,0 +1,17 @@
+'use strict';
+define(function (require) {
+
+ var moment = require('moment');
+
+ require('twix');
+
+ return {
+ timespan: function (a, b) {
+ return moment(a).twix(b, {allDay: true}).format();
+ },
+
+ formatDate: function (d) {
+ return d ? moment(d).format('YYYY-MM-DD') : '(invalid)';
+ },
+ };
+});
diff --git a/src/app/utils/elements.js b/src/app/utils/elements.js
new file mode 100644
index 0000000..85cea37
--- /dev/null
+++ b/src/app/utils/elements.js
@@ -0,0 +1,16 @@
+'use strict';
+define(function (require) {
+
+ require('jquery');
+
+ return {
+ getBounds: function (element, parentSelector) {
+ var container = $(element).parents(parentSelector);
+
+ return {
+ width: container.innerWidth() || 0,
+ height: container.innerHeight() || 0,
+ };
+ },
+ };
+});
diff --git a/src/app/utils/numbers.js b/src/app/utils/numbers.js
new file mode 100644
index 0000000..3ca6ba0
--- /dev/null
+++ b/src/app/utils/numbers.js
@@ -0,0 +1,24 @@
+'use strict';
+define(function (require) {
+
+ var numeral = require('numeral');
+
+ return {
+
+ /**
+ * Get a number formatting function from a numeral.js format
+ */
+ numberFormatter: function (numeralFormatter) {
+ var niceNames = {
+ 'percent': '0.0%',
+ 'kmb': '0.0a',
+ };
+
+ numeralFormatter = niceNames[numeralFormatter] || numeralFormatter;
+
+ return function (n) {
+ return numeral(n).format(numeralFormatter);
+ };
+ },
+ };
+});
diff --git a/src/app/utils/strings.js b/src/app/utils/strings.js
new file mode 100644
index 0000000..277d10e
--- /dev/null
+++ b/src/app/utils/strings.js
@@ -0,0 +1,32 @@
+'use strict';
+define(function (require) {
+
+ var moment = require('moment');
+
+ return {
+ /**
+ * Using a sample string, returns a function that can parse
+ * similar values. Falls back to the identity function.
+ */
+ parserFromSample: function (sample) {
+ // NOTE: Dates in YYYYMMDD format will parse incorrectly, please
use
+ // YYYY-MM-DD (with your choice of separator)
+ if (!isNaN(parseFloat(sample)) && isFinite(sample)) {
+ return function (x) {
+ return parseFloat(x);
+ };
+ }
+ if (moment(sample).isValid()) {
+ return function (x) {
+ return moment.utc(x).toDate();
+ };
+ }
+ // If the sample contains null values,
+ // the default parser tries to cast to float.
+ return function (x) {
+ return parseFloat(x) || x;
+ };
+ },
+
+ };
+});
\ No newline at end of file
diff --git a/src/components/annotation-list/annotation-list.js
b/src/components/annotation-list/annotation-list.js
index 81a5950..e560c4c 100644
--- a/src/components/annotation-list/annotation-list.js
+++ b/src/components/annotation-list/annotation-list.js
@@ -6,7 +6,7 @@
annotationsApi = require('apis.annotations'),
marked = require('marked'),
moment = require('moment'),
- utils = require('utils');
+ dateUtils = require('utils.datetime');
require('./bindings');
@@ -56,7 +56,7 @@
return formattedStart + ' - ' + formattedEnd;
}
- return utils.timespan(start, end);
+ return dateUtils.timespan(start, end);
};
this.annotations = ko.computed(function () {
diff --git a/src/components/compare-layout/compare-layout.js
b/src/components/compare-layout/compare-layout.js
index 9fed7b0..a1d6353 100644
--- a/src/components/compare-layout/compare-layout.js
+++ b/src/components/compare-layout/compare-layout.js
@@ -10,7 +10,8 @@
configApi = require('apis.config'),
marked = require('marked'),
moment = require('moment'),
- utils = require('utils'),
+ dateUtils = require('utils.datetime'),
+ colorUtils = require('utils.colors'),
asyncObs = require('observables.async'),
TimeseriesData = require('converters.timeseries');
@@ -33,7 +34,7 @@
this.fromDate = {
options: this.dates,
selected: ko.observable(),
- format: utils.formatDate,
+ format: dateUtils.formatDate,
};
this.toDate = {
options: ko.computed(function() {
@@ -42,7 +43,7 @@
}, this);
}, this),
selected: ko.observable(),
- format: utils.formatDate,
+ format: dateUtils.formatDate,
defaultToLast: true,
};
this.fromDate.selected.subscribe(function (newFromDate) {
@@ -51,7 +52,7 @@
}
}, this);
this.timespan = ko.computed(function() {
- return utils.timespan(this.fromDate.selected(),
this.toDate.selected());
+ return dateUtils.timespan(this.fromDate.selected(),
this.toDate.selected());
// rate limit for when fromDate forces a change on toDate
}, this).extend({ rateLimit: 0 });
@@ -182,14 +183,14 @@
}
// default to a 10-color scale, but use config if present
- var colorScale = utils.category10();
+ var colorScale = colorUtils.category10();
if (c.colors) {
var domain = [], range = [];
_.forEach(c.colors, function (val, key) {
range.push(val);
domain.push(key);
});
- colorScale = utils.category10(domain, range);
+ colorScale = colorUtils.category10(domain, range);
}
c.colors = colorScale;
diff --git a/src/components/metric-selector/metric-selector.js
b/src/components/metric-selector/metric-selector.js
index f27f0d6..7b6c1ce 100644
--- a/src/components/metric-selector/metric-selector.js
+++ b/src/components/metric-selector/metric-selector.js
@@ -23,7 +23,7 @@
var ko = require('knockout'),
templateMarkup = require('text!./metric-selector.html'),
- utils = require('utils');
+ arrayUtils = require('utils.arrays');
require('./bindings');
@@ -57,13 +57,13 @@
this.categories = ko.computed(function () {
var unwrap = ko.unwrap(this.metricsByCategory) || [],
copy = unwrap.slice(),
- categories = copy.sort(utils.sortByNameIgnoreCase);
+ categories = copy.sort(arrayUtils.sortByNameIgnoreCase);
categories.splice(0, 0, {
name: 'All metrics',
metrics: [].concat.apply([], categories.map(function (c) {
return c.metrics;
- })).sort(utils.sortByNameIgnoreCase)
+ })).sort(arrayUtils.sortByNameIgnoreCase)
});
// lots of different categories are sharing the same layout,
diff --git a/src/components/project-selector/bindings.js
b/src/components/project-selector/bindings.js
index 6adce64..cedbde5 100644
--- a/src/components/project-selector/bindings.js
+++ b/src/components/project-selector/bindings.js
@@ -2,7 +2,7 @@
define(function (require) {
var ko = require('knockout'),
- utils = require('utils');
+ arrayUtils = require('utils.arrays');
require('typeahead');
@@ -23,7 +23,7 @@
// an array that will be populated with substring matches
matches = unwrapped.filter(function (item) {
return substrRegex.test(item.name);
- }).sort(utils.sortByName);
+ }).sort(arrayUtils.sortByName);
callback(matches);
};
diff --git a/src/components/project-selector/project-selector.js
b/src/components/project-selector/project-selector.js
index a8f4f1b..625a42e 100644
--- a/src/components/project-selector/project-selector.js
+++ b/src/components/project-selector/project-selector.js
@@ -3,7 +3,7 @@
var ko = require('knockout'),
templateMarkup = require('text!./project-selector.html'),
- utils = require('utils');
+ arrayUtils = require('utils.arrays');
require('./bindings');
function ProjectSelector(params) {
@@ -117,7 +117,7 @@
this.addProject({project: selection.name});
return;
}
- options.sort(utils.sortByNameIgnoreCase);
+ options.sort(arrayUtils.sortByNameIgnoreCase);
this.suboptions(options);
};
diff --git a/src/components/visualizers/rickshaw-timeseries/bindings.js
b/src/components/visualizers/rickshaw-timeseries/bindings.js
index f3b5556..54a0cc1 100644
--- a/src/components/visualizers/rickshaw-timeseries/bindings.js
+++ b/src/components/visualizers/rickshaw-timeseries/bindings.js
@@ -1,9 +1,10 @@
+'use strict';
define(function(require) {
var Rickshaw = require('rickshaw'),
ko = require('knockout'),
d3 = require('d3'),
- getBounds = require('utils').getBounds;
+ getBounds = require('utils.elements').getBounds;
require('lib/polyfills');
@@ -22,8 +23,8 @@
graphEl.graph = new Rickshaw.Graph({
element: graphEl,
- width: opt.width || bounds.width * (opt.widthRatio || 13/16),
- height: opt.height || bounds.height * (opt.heightRatio || 5/6),
+ width: opt.width || bounds.width * (opt.widthRatio || 13 / 16),
+ height: opt.height || bounds.height * (opt.heightRatio || 5 /
6),
renderer: 'multi',
series: [],
});
diff --git a/src/components/visualizers/visualizer/visualizer.js
b/src/components/visualizers/visualizer/visualizer.js
index 2da0341..ec0e348 100644
--- a/src/components/visualizers/visualizer/visualizer.js
+++ b/src/components/visualizers/visualizer/visualizer.js
@@ -5,7 +5,7 @@
ko = require('knockout'),
_ = require('lodash'),
apiFinder = require('api-finder'),
- utils = require('utils'),
+ colorUtils = require('utils.colors'),
TimeseriesData = require('converters.timeseries');
require('datepicker-binding');
@@ -22,14 +22,14 @@
// like visualizers[this.type].showColumnToggle
this.columnToggle = this.type !== 'sunburst' && this.type !==
'hierarchy';
- var colorScale = utils.category10();
+ var colorScale = colorUtils.category10();
if (graph.colors) {
var domain = [], range = [];
_.forEach(graph.colors, function (val, key) {
range.push(val);
domain.push(key);
});
- colorScale = utils.category10(domain, range);
+ colorScale = colorUtils.category10(domain, range);
}
this.data = ko.observable(new TimeseriesData());
diff --git a/src/lib/utils.js b/src/lib/utils.js
deleted file mode 100644
index 8122583..0000000
--- a/src/lib/utils.js
+++ /dev/null
@@ -1,85 +0,0 @@
-'use strict';
-/**
- * Look into doing this with Lodash if we can make a slim enough build
- **/
-define(function (require) {
-
- var moment = require('moment');
-
- require('twix');
-
- var utils = {
- sortByName: function (a, b) {
- // NOTE: this purposefully sorts uppercase before lowercase
- return a.name === b.name ?
- 0 : a.name > b.name ? 1 : -1;
- },
- sortByNameIgnoreCase: function (a, b) {
- return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
- },
- getBounds: function (element, parentSelector) {
- var container = $(element).parents(parentSelector);
-
- return {
- width: container.innerWidth() || 0,
- height: container.innerHeight() || 0,
- };
- },
- /**
- * Using a sample string, returns a function that can parse
- * similar values. Falls back to the identity function.
- */
- parserFromSample: function (sample) {
- // NOTE: Dates in YYYYMMDD format will parse incorrectly, please
use
- // YYYY-MM-DD (with your choice of separator)
- if (!isNaN(parseFloat(sample)) && isFinite(sample)) {
- return function (x) { return parseFloat(x); };
- }
- if (moment(sample).isValid()) {
- return function (x) { return moment(x).toDate(); };
- }
- // If the sample contains null values,
- // the default parser tries to cast to float.
- return function (x) { return parseFloat(x) || x; };
- },
-
- timespan: function (a, b) {
- return moment(a).twix(b, {allDay: true}).format();
- },
-
- formatDate: function (d) {
- return d ? moment(d).format('YYYY-MM-DD') : '(invalid)';
- },
-
- /**
- * Returns an array with "n" undefined values
- */
- filler: function (n) {
- var empty = [];
- empty.length = n;
- return Array.apply(null, empty);
- },
-
- /**
- * Poor man's category10 scale from d3, for when you don't want to
- * import the whole library for a simple color scale
- */
- category10: function (domain, range) {
- range = range || [
- '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
- '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'
- ];
- domain = domain || [];
- return function (x) {
-
- var index = domain.indexOf(x);
- if (index < 0) {
- index = domain.push(x) - 1;
- }
-
- return range[index % range.length];
- };
- },
- };
- return utils;
-});
diff --git a/test/app/utils.js b/test/app/utils.js
new file mode 100644
index 0000000..9882d07
--- /dev/null
+++ b/test/app/utils.js
@@ -0,0 +1,68 @@
+'use strict';
+define(function (require) {
+
+ var arrays = require('utils.arrays'),
+ strings = require('utils.strings'),
+ datetime = require('utils.datetime'),
+ numbers = require('utils.numbers'),
+ colors = require('utils.colors'),
+ elements = require('utils.elements');
+
+ describe('Array Utilities', function () {
+
+ it('should make a zero-filled array', function () {
+ expect(arrays.filler(3)).toEqual([undefined, undefined,
undefined]);
+ });
+ });
+
+ describe('String Utilities', function () {
+ var dateString = '2015-01-02 00:00:10',
+ dateString2 = '2015-01-02 00:00:20',
+ floatString = '1234.40',
+ d = strings.parserFromSample(dateString),
+ f = strings.parserFromSample(floatString);
+
+ var timediff = d(dateString2).getTime() - d(dateString).getTime();
+
+ it('should parse dates or numbers properly', function () {
+ expect(timediff).toBe(10000);
+ expect(f(floatString)).toBe(1234.40);
+ });
+ });
+
+ describe('Datetime Utilities', function () {
+
+ it('should format a span of dates', function () {
+ expect(datetime.timespan('2015-01-30', '2015-02-01'))
+ .toBe('Jan 30 - Feb 1, 2015');
+ });
+ });
+
+ describe('Number Utilities', function () {
+
+ it('should format kmb', function () {
+ expect(numbers.numberFormatter('kmb')(1234567)).toBe('1.2m');
+ expect(numbers.numberFormatter('0.00a')(1234567)).toBe('1.23m');
+ expect(numbers.numberFormatter('percent')(0.123)).toBe('12.3%');
+ });
+ });
+
+ describe('Color Utilities', function () {
+ var scale = colors.category10();
+
+ scale('one');
+ scale('two');
+ scale('three');
+
+ it('should produce consistent colors', function () {
+ expect(scale('one')).toBe(scale('one'));
+ });
+ });
+
+ describe('Element Utilities', function () {
+ // needs DOM to test
+ it('should define something', function () {
+ expect(elements.getBounds).toBeDefined();
+ });
+ });
+});
\ No newline at end of file
--
To view, visit https://gerrit.wikimedia.org/r/282183
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ie7d6f3b1305a291392f5acae387e3d65b4c69d36
Gerrit-PatchSet: 2
Gerrit-Project: analytics/dashiki
Gerrit-Branch: master
Gerrit-Owner: Milimetric <[email protected]>
Gerrit-Reviewer: Mforns <[email protected]>
Gerrit-Reviewer: Nuria <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits