diff --git a/.bowerrc b/.bowerrc
new file mode 100644
index 0000000..25c9a0f
--- /dev/null
+++ b/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory": "vendor"
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0113f0c..38f11f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@ node_modules/
.idea/
*.log
src/components/
-config.json
\ No newline at end of file
+config.json
+vendor/
+.build_cache~
\ No newline at end of file
diff --git a/Gruntfile.coffee b/Gruntfile.coffee
new file mode 100644
index 0000000..cead607
--- /dev/null
+++ b/Gruntfile.coffee
@@ -0,0 +1,73 @@
+module.exports = (grunt) ->
+ grunt.initConfig
+ pkg: grunt.file.readJSON("package.json")
+
+ apps_c:
+ commonjs:
+ src: [ 'src/**/*.{coffee,js,eco}' ]
+ dest: 'build/app.js'
+ options:
+ main: 'src/app.coffee'
+ name: [ 'ghbc', 'ghb', 'github-burndown-chart' ]
+
+ stylus:
+ compile:
+ options:
+ paths: [ 'src/styles/app.styl' ]
+ files:
+ 'build/app.css': 'src/styles/app.styl'
+
+ concat:
+ scripts:
+ src: [
+ # Vendor dependencies.
+ 'vendor/async/lib/async.js'
+ 'vendor/d3/d3.js'
+ 'vendor/d3-tip/index.js'
+ 'vendor/lodash/dist/lodash.js'
+ 'vendor/marked/lib/marked.js'
+ 'vendor/superagent/superagent.js'
+ # Our app.
+ 'build/app.js'
+ ]
+ dest: 'build/app.bundle.js'
+ options:
+ separator: ';' # for minification purposes
+
+ styles:
+ src: [
+ # Vendor dependencies.
+ 'vendor/normalize-css/normalize.css'
+ # Our style.
+ 'build/app.css'
+ ]
+ dest: 'build/app.bundle.css'
+
+ uglify:
+ scripts:
+ files:
+ 'build/app.min.js': 'build/app.js'
+ 'build/app.bundle.min.js': 'build/app.bundle.js'
+
+ cssmin:
+ combine:
+ files:
+ 'build/app.min.css': 'build/app.css'
+ 'build/app.bundle.min.css': 'build/app.bundle.css'
+
+ grunt.loadNpmTasks('grunt-apps-c')
+ grunt.loadNpmTasks('grunt-contrib-stylus')
+ grunt.loadNpmTasks('grunt-contrib-concat')
+ grunt.loadNpmTasks('grunt-contrib-uglify')
+ grunt.loadNpmTasks('grunt-contrib-cssmin')
+
+ grunt.registerTask('default', [
+ 'apps_c'
+ 'stylus'
+ 'concat'
+ ])
+
+ grunt.registerTask('minify', [
+ 'uglify'
+ 'cssmin'
+ ])
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 8c5e059..a778d26 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,22 @@
-test:
- ./node_modules/.bin/mocha --compilers coffee:coffee-script --reporter spec --ui exports --bail
+install:
+ npm install
+ bower install
build:
- ./node_modules/.bin/apps-b ./src/ ./build/
+ grunt
+
+minify:
+ grunt minify
+
+watch:
+ watch --color -n 1 make build
publish:
+ build
+ minify
git checkout gh-pages
- git show master:build/build.js > build.js
- git show master:build/build.css > build.css
+ git show master:build/app.bundle.min.js > app.bundle.min.js
+ git show master:build/app.bundle.min.css > app.bundle.min.css
git add .
@status=$$(git status --porcelain); \
if ! test "x$${status}" = x; then \
@@ -16,4 +25,7 @@ publish:
fi
git checkout master
+test:
+ ./node_modules/.bin/mocha --compilers coffee:coffee-script --reporter spec --ui exports --bail
+
.PHONY: build test
\ No newline at end of file
diff --git a/README.md b/README.md
index 6bcb929..c2436dc 100644
--- a/README.md
+++ b/README.md
@@ -90,15 +90,15 @@ Visit the port in question in the browser and continue as before.
##Build It
-If you would like to run your own build for a custom version of the app, use the [Apps/B Builder](https://github.com/intermine/apps-b-builder).
-
-In short:
+If you would like to build a custom version of your app, edit the `Gruntfile.coffee` and run the following:
```bash
-$ npm install -d
-$ make build
+$ make install
+$ make build
```
+We are using the [Bower](http://bower.io/) package manager and [Grunt](http://gruntjs.com/) task runner.
+
##Publish It
If you would like to track changes to build files in `gh-pages` branch, execute the following command:
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..a5b9f3f
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,13 @@
+{
+ "name": "github-burndown-chart",
+ "version": "1.0.0-alpha",
+ "dependencies": {
+ "lodash": null,
+ "async": null,
+ "d3": null,
+ "d3-tip": null,
+ "superagent": null,
+ "normalize-css": null,
+ "marked": null
+ }
+}
\ No newline at end of file
diff --git a/build/build.css b/build/app.bundle.css
similarity index 57%
rename from build/build.css
rename to build/app.bundle.css
index b399fae..3f8b43c 100644
--- a/build/build.css
+++ b/build/app.bundle.css
@@ -1,8 +1,3 @@
-
-
-
-
-
/*! normalize.css v2.1.3 | MIT License | git.io/normalize */
/* ==========================================================================
@@ -410,294 +405,42 @@ table {
border-spacing: 0;
}
-
-.tip {
- position: absolute;
- padding: 5px;
- z-index: 1000;
- /* default offset for edge-cases: https://github.com/component/tip/pull/12 */
- top: 0;
- left: 0;
-}
-
-/* effects */
-
-.tip.fade {
- transition: opacity 100ms;
- -moz-transition: opacity 100ms;
- -webkit-transition: opacity 100ms;
-}
-
-.tip-hide {
- opacity: 0;
-}
-
-.tip {
- font-size: 11px;
-}
-
-.tip-inner {
- background-color: rgba(0,0,0,.75);
- color: #fff;
- padding: 8px 10px 7px 10px;
- text-align: center;
-}
-
-.tip-inner {
- border-radius: 3px;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
-}
-
-.tip-arrow {
- position: absolute;
- width: 0;
- height: 0;
- line-height: 0;
- border: 5px dashed rgba(0,0,0,.75);
-}
-
-.tip-arrow-north { border-bottom-color: rgba(0,0,0,.75) }
-.tip-arrow-south { border-top-color: rgba(0,0,0,.75) }
-.tip-arrow-east { border-left-color: rgba(0,0,0,.75) }
-.tip-arrow-west { border-right-color: rgba(0,0,0,.75) }
-
-.tip-north .tip-arrow,
-.tip-north-east .tip-arrow,
-.tip-north-west .tip-arrow {
- top: 0px;
- left: 50%;
- margin-left: -5px;
- border-bottom-style: solid;
- border-top: none;
- border-left-color: transparent;
- border-right-color: transparent
-}
-
-.tip-south .tip-arrow,
-.tip-south-east .tip-arrow,
-.tip-south-west .tip-arrow {
- bottom: 0;
- left: 50%;
- margin-left: -5px;
- border-top-style: solid;
- border-bottom: none;
- border-left-color: transparent;
- border-right-color: transparent
-}
-
-.tip-east .tip-arrow {
- right: 0;
- top: 50%;
- margin-top: -5px;
- border-left-style: solid;
- border-right: none;
- border-top-color: transparent;
- border-bottom-color: transparent
-}
-
-.tip-west .tip-arrow {
- left: 0;
- top: 50%;
- margin-top: -5px;
- border-right-style: solid;
- border-left: none;
- border-top-color: transparent;
- border-bottom-color: transparent
-}
-
-.tip-north-west .tip-arrow,
-.tip-south-west .tip-arrow {
- left: 15px;
-}
-
-.tip-north-east .tip-arrow,
-.tip-south-east .tip-arrow {
- left: 85%;
-}
-
-
-@font-face {
- font-family: 'Source Sans Pro';
- font-style: normal;
- font-weight: 400;
- src: local('Source Sans Pro'), local('SourceSansPro-Regular'),
- url("app/styles/../../fonts/SourceSansPro-Regular.woff") format('woff');
-}
-@font-face {
- font-family: 'Source Sans Pro';
- font-style: normal;
- font-weight: 600;
- src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'),
- url("app/styles/../../fonts/SourceSansPro-Semibold.woff") format('woff');
-}
-@font-face {
- font-family: 'Source Sans Pro';
- font-style: normal;
- font-weight: 700;
- src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'),
- url("app/styles/../../fonts/SourceSansPro-Bold.woff") format('woff');
-}
-body {
- height: 100%;
- background: #d7bcab;
- background: -moz-linear-gradient(-45deg, #d7bcab 0%, #cc9485 100%);
- background: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #d7bcab), color-stop(100%, #cc9485));
- background: -webkit-linear-gradient(-45deg, #d7bcab 0%, #cc9485 100%);
- background: -o-linear-gradient(-45deg, #d7bcab 0%, #cc9485 100%);
- background: -ms-linear-gradient(-45deg, #d7bcab 0%, #cc9485 100%);
- background: linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);
- background-repeat: no-repeat;
- background-attachment: fixed;
- font-family: 'Source Sans Pro', sans-serif;
- padding: 100px;
- color: #64584c;
-}
-ul {
- list-style-type: none;
- padding: 0;
-}
-ul li {
- padding: 0;
-}
-h2 {
- font-size: 16px;
- text-transform: uppercase;
-}
-.box {
- background: #fff;
- box-shadow: 2px 4px 6px rgba(0,0,0,0.2);
-}
-.box.generic,
-.box.info,
-.box.error,
-.box.success {
- padding: 20px 0;
- border-top: 4px solid #eac85d;
- width: 50%;
- margin: 0 auto;
-}
-.box.info {
- border-top-color: #5f90b0;
-}
-.box.error {
- border-top-color: #e45e39;
-}
-.box.success {
- border-top-color: #4db07a;
-}
-.box a {
- color: #64584c;
-}
-.box h1 {
- margin: 0;
- padding: 20px;
- color: #64584c;
- font-size: 20px;
- text-transform: uppercase;
-}
-.box h2 {
- margin: 0;
- padding: 0 20px 20px;
-}
-.box p {
- margin: 5px 0;
- padding: 0 20px;
-}
-.box p.description {
- margin: -10px 0 0 0;
-}
-#graph {
- height: 200px;
- position: relative;
-}
-#graph #tooltip {
- position: absolute;
- top: 0;
- left: 0;
-}
-#graph svg path.line {
- fill: none;
- stroke-width: 1px;
- clip-path: url("app/styles/#clip");
-}
-#graph svg path.line.actual {
- stroke: #64584c;
- stroke-width: 3px;
-}
-#graph svg path.line.ideal {
- stroke: #cacaca;
- stroke-width: 3px;
-}
-#graph svg path.line.trendline {
- stroke: #64584c;
- stroke-width: 1.5px;
- stroke-dasharray: 5, 5;
-}
-#graph svg line.today {
- stroke: #cacaca;
- stroke-width: 1px;
- shape-rendering: crispEdges;
- stroke-dasharray: 5, 5;
-}
-#graph svg circle {
- fill: #64584c;
- stroke: transparent;
- stroke-width: 15px;
- cursor: pointer;
-}
-#graph svg .axis {
- shape-rendering: crispEdges;
-}
-#graph svg .axis line {
- stroke: rgba(202,202,202,0.25);
- shape-rendering: crispEdges;
-}
-#graph svg .axis text {
- font-weight: bold;
- fill: #cacaca;
-}
-#graph svg .axis path {
- display: none;
-}
-#progress {
- padding: 20px;
- border-radius: 0 0 6px 6px;
-}
-#progress:after {
- clear: both;
- display: block;
- content: "";
-}
-#progress .bars {
- position: relative;
-}
-#progress .bars div {
- border-radius: 6px;
- height: 12px;
-}
-#progress .bars div.closed {
- position: absolute;
- top: 0;
- left: 0;
- background: #4daf7c;
-}
-#progress .bars div.closed:not(.done) {
- border-radius: 6px 0 0 6px;
-}
-#progress .bars div.opened {
- width: 100%;
- background: #e55f3a;
-}
-#progress h2 {
- margin: 10px 0 0 0;
- padding: 0;
-}
-#progress h2.closed {
- float: left;
- color: #4daf7c;
-}
-#progress h2.opened {
- float: right;
- color: #e55f3a;
-}
+body{height:100%;background:#d7bcab;background:-moz--webkit-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-moz--moz-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-moz--o-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-moz--ms-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-moz-linear-gradient(-45deg, #d7bcab 0%, #cc9485 100%);background:-webkit-gradient(linear, left top, right bottom, color-stop(0%, #d7bcab), color-stop(100%, #cc9485));background:-webkit-gradient(linear, left top, right bottom, color-stop(0%, #d7bcab), color-stop(100%, #cc9485));background:-webkit-gradient(linear, left top, right bottom, color-stop(0%, #d7bcab), color-stop(100%, #cc9485));background:-webkit-gradient(linear, left top, right bottom, color-stop(0%, #d7bcab), color-stop(100%, #cc9485));background:-webkit-gradient(linear, left top, right bottom, color-stop(0%, #d7bcab), color-stop(100%, #cc9485));background:-webkit--webkit-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-webkit--moz-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-webkit--o-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-webkit--ms-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-webkit-linear-gradient(-45deg, #d7bcab 0%, #cc9485 100%);background:-o--webkit-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-o--moz-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-o--o-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-o--ms-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-o-linear-gradient(-45deg, #d7bcab 0%, #cc9485 100%);background:-ms--webkit-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-ms--moz-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-ms--o-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-ms--ms-linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background:-ms-linear-gradient(-45deg, #d7bcab 0%, #cc9485 100%);background:-webkit-linear-gradient(315deg, #d7bcab 0%, #cc9485 100%);background:-moz-linear-gradient(315deg, #d7bcab 0%, #cc9485 100%);background:-o-linear-gradient(315deg, #d7bcab 0%, #cc9485 100%);background:-ms-linear-gradient(315deg, #d7bcab 0%, #cc9485 100%);background:linear-gradient(135deg, #d7bcab 0%, #cc9485 100%);background-repeat:no-repeat;background-attachment:fixed;font-family:'Source Sans Pro',sans-serif;padding:100px;color:#64584c}
+ul{list-style-type:none;padding:0;}
+ul li{padding:0}
+h2{font-size:16px;text-transform:uppercase}
+.box{background:#fff;-webkit-box-shadow:2px 4px 6px rgba(0,0,0,0.2);box-shadow:2px 4px 6px rgba(0,0,0,0.2);}
+.box.generic,.box.info,.box.error,.box.success{padding:20px 0;border-top:4px solid #eac85d;width:50%;margin:0 auto}
+.box.info{border-top-color:#5f90b0}
+.box.error{border-top-color:#e45e39}
+.box.success{border-top-color:#4db07a}
+.box a{color:#64584c}
+.box h1{margin:0;padding:20px;color:#64584c;font-size:20px;text-transform:uppercase}
+.box h2{margin:0;padding:0 20px 20px}
+.box p{margin:5px 0;padding:0 20px;}
+.box p.description{margin:-10px 0 0 0}
+#graph{height:200px;position:relative;}
+#graph #tooltip{position:absolute;top:0;left:0}
+#graph svg path.line{fill:none;stroke-width:1px;clip-path:url("#clip");}
+#graph svg path.line.actual{stroke:#64584c;stroke-width:3px}
+#graph svg path.line.ideal{stroke:#cacaca;stroke-width:3px}
+#graph svg path.line.trendline{stroke:#64584c;stroke-width:1.5px;stroke-dasharray:5,5}
+#graph svg line.today{stroke:#cacaca;stroke-width:1px;shape-rendering:crispEdges;stroke-dasharray:5,5}
+#graph svg circle{fill:#64584c;stroke:transparent;stroke-width:15px;cursor:pointer}
+#graph svg .axis{shape-rendering:crispEdges;}
+#graph svg .axis line{stroke:rgba(202,202,202,0.25);shape-rendering:crispEdges}
+#graph svg .axis text{font-weight:bold;fill:#cacaca}
+#graph svg .axis path{display:none}
+.d3-tip{margin-top:-10px;font-size:11px;padding:8px 10px 7px 10px;text-align:center;background:rgba(0,0,0,0.75);color:#fff;-webkit-border-radius:3px;border-radius:3px;}
+.d3-tip:after{width:100%;color:rgba(0,0,0,0.8);content:"\25BC";position:absolute}
+.d3-tip.n:after{margin:-3px 0 0 0;top:100%;left:0}
+#progress{padding:20px;-webkit-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
+#progress:after{clear:both;display:block;content:""}
+#progress .bars{position:relative;}
+#progress .bars div{-webkit-border-radius:6px;border-radius:6px;height:12px;}
+#progress .bars div.closed{position:absolute;top:0;left:0;background:#4daf7c;}
+#progress .bars div.closed:not(.done){-webkit-border-radius:6px 0 0 6px;border-radius:6px 0 0 6px}
+#progress .bars div.opened{width:100%;background:#e55f3a}
+#progress h2{margin:10px 0 0 0;padding:0;}
+#progress h2.closed{float:left;color:#4daf7c}
+#progress h2.opened{float:right;color:#e55f3a}
diff --git a/build/build.js b/build/app.bundle.js
similarity index 62%
rename from build/build.js
rename to build/app.bundle.js
index cb6d08a..0a9cfbf 100644
--- a/build/build.js
+++ b/build/app.bundle.js
@@ -1,212 +1,10511 @@
+/*global setImmediate: false, setTimeout: false, console: false */
+(function () {
-/**
- * Require the given path.
- *
- * @param {String} path
- * @return {Object} exports
- * @api public
- */
+ var async = {};
-function require(path, parent, orig) {
- var resolved = require.resolve(path);
+ // global on the server, window in the browser
+ var root, previous_async;
- // lookup failed
- if (null == resolved) {
- orig = orig || path;
- parent = parent || 'root';
- var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
- err.path = orig;
- err.parent = parent;
- err.require = true;
- throw err;
+ root = this;
+ if (root != null) {
+ previous_async = root.async;
+ }
+
+ async.noConflict = function () {
+ root.async = previous_async;
+ return async;
+ };
+
+ function only_once(fn) {
+ var called = false;
+ return function() {
+ if (called) throw new Error("Callback was already called.");
+ called = true;
+ fn.apply(root, arguments);
+ }
+ }
+
+ //// cross-browser compatiblity functions ////
+
+ var _each = function (arr, iterator) {
+ if (arr.forEach) {
+ return arr.forEach(iterator);
+ }
+ for (var i = 0; i < arr.length; i += 1) {
+ iterator(arr[i], i, arr);
+ }
+ };
+
+ var _map = function (arr, iterator) {
+ if (arr.map) {
+ return arr.map(iterator);
+ }
+ var results = [];
+ _each(arr, function (x, i, a) {
+ results.push(iterator(x, i, a));
+ });
+ return results;
+ };
+
+ var _reduce = function (arr, iterator, memo) {
+ if (arr.reduce) {
+ return arr.reduce(iterator, memo);
+ }
+ _each(arr, function (x, i, a) {
+ memo = iterator(memo, x, i, a);
+ });
+ return memo;
+ };
+
+ var _keys = function (obj) {
+ if (Object.keys) {
+ return Object.keys(obj);
+ }
+ var keys = [];
+ for (var k in obj) {
+ if (obj.hasOwnProperty(k)) {
+ keys.push(k);
+ }
+ }
+ return keys;
+ };
+
+ //// exported async module functions ////
+
+ //// nextTick implementation with browser-compatible fallback ////
+ if (typeof process === 'undefined' || !(process.nextTick)) {
+ if (typeof setImmediate === 'function') {
+ async.nextTick = function (fn) {
+ setImmediate(fn);
+ };
+ }
+ else {
+ async.nextTick = function (fn) {
+ setTimeout(fn, 0);
+ };
+ }
+ }
+ else {
+ async.nextTick = process.nextTick;
+ }
+
+ async.each = function (arr, iterator, callback) {
+ callback = callback || function () {};
+ if (!arr.length) {
+ return callback();
+ }
+ var completed = 0;
+ _each(arr, function (x) {
+ iterator(x, only_once(function (err) {
+ if (err) {
+ callback(err);
+ callback = function () {};
+ }
+ else {
+ completed += 1;
+ if (completed >= arr.length) {
+ callback(null);
+ }
+ }
+ }));
+ });
+ };
+ async.forEach = async.each;
+
+ async.eachSeries = function (arr, iterator, callback) {
+ callback = callback || function () {};
+ if (!arr.length) {
+ return callback();
+ }
+ var completed = 0;
+ var iterate = function () {
+ var sync = true;
+ iterator(arr[completed], function (err) {
+ if (err) {
+ callback(err);
+ callback = function () {};
+ }
+ else {
+ completed += 1;
+ if (completed >= arr.length) {
+ callback(null);
+ }
+ else {
+ if (sync) {
+ async.nextTick(iterate);
+ }
+ else {
+ iterate();
+ }
+ }
+ }
+ });
+ sync = false;
+ };
+ iterate();
+ };
+ async.forEachSeries = async.eachSeries;
+
+ async.eachLimit = function (arr, limit, iterator, callback) {
+ var fn = _eachLimit(limit);
+ fn.apply(null, [arr, iterator, callback]);
+ };
+ async.forEachLimit = async.eachLimit;
+
+ var _eachLimit = function (limit) {
+
+ return function (arr, iterator, callback) {
+ callback = callback || function () {};
+ if (!arr.length || limit <= 0) {
+ return callback();
+ }
+ var completed = 0;
+ var started = 0;
+ var running = 0;
+
+ (function replenish () {
+ if (completed >= arr.length) {
+ return callback();
+ }
+
+ while (running < limit && started < arr.length) {
+ started += 1;
+ running += 1;
+ iterator(arr[started - 1], function (err) {
+ if (err) {
+ callback(err);
+ callback = function () {};
+ }
+ else {
+ completed += 1;
+ running -= 1;
+ if (completed >= arr.length) {
+ callback();
+ }
+ else {
+ replenish();
+ }
+ }
+ });
+ }
+ })();
+ };
+ };
+
+
+ var doParallel = function (fn) {
+ return function () {
+ var args = Array.prototype.slice.call(arguments);
+ return fn.apply(null, [async.each].concat(args));
+ };
+ };
+ var doParallelLimit = function(limit, fn) {
+ return function () {
+ var args = Array.prototype.slice.call(arguments);
+ return fn.apply(null, [_eachLimit(limit)].concat(args));
+ };
+ };
+ var doSeries = function (fn) {
+ return function () {
+ var args = Array.prototype.slice.call(arguments);
+ return fn.apply(null, [async.eachSeries].concat(args));
+ };
+ };
+
+
+ var _asyncMap = function (eachfn, arr, iterator, callback) {
+ var results = [];
+ arr = _map(arr, function (x, i) {
+ return {index: i, value: x};
+ });
+ eachfn(arr, function (x, callback) {
+ iterator(x.value, function (err, v) {
+ results[x.index] = v;
+ callback(err);
+ });
+ }, function (err) {
+ callback(err, results);
+ });
+ };
+ async.map = doParallel(_asyncMap);
+ async.mapSeries = doSeries(_asyncMap);
+ async.mapLimit = function (arr, limit, iterator, callback) {
+ return _mapLimit(limit)(arr, iterator, callback);
+ };
+
+ var _mapLimit = function(limit) {
+ return doParallelLimit(limit, _asyncMap);
+ };
+
+ // reduce only has a series version, as doing reduce in parallel won't
+ // work in many situations.
+ async.reduce = function (arr, memo, iterator, callback) {
+ async.eachSeries(arr, function (x, callback) {
+ iterator(memo, x, function (err, v) {
+ memo = v;
+ callback(err);
+ });
+ }, function (err) {
+ callback(err, memo);
+ });
+ };
+ // inject alias
+ async.inject = async.reduce;
+ // foldl alias
+ async.foldl = async.reduce;
+
+ async.reduceRight = function (arr, memo, iterator, callback) {
+ var reversed = _map(arr, function (x) {
+ return x;
+ }).reverse();
+ async.reduce(reversed, memo, iterator, callback);
+ };
+ // foldr alias
+ async.foldr = async.reduceRight;
+
+ var _filter = function (eachfn, arr, iterator, callback) {
+ var results = [];
+ arr = _map(arr, function (x, i) {
+ return {index: i, value: x};
+ });
+ eachfn(arr, function (x, callback) {
+ iterator(x.value, function (v) {
+ if (v) {
+ results.push(x);
+ }
+ callback();
+ });
+ }, function (err) {
+ callback(_map(results.sort(function (a, b) {
+ return a.index - b.index;
+ }), function (x) {
+ return x.value;
+ }));
+ });
+ };
+ async.filter = doParallel(_filter);
+ async.filterSeries = doSeries(_filter);
+ // select alias
+ async.select = async.filter;
+ async.selectSeries = async.filterSeries;
+
+ var _reject = function (eachfn, arr, iterator, callback) {
+ var results = [];
+ arr = _map(arr, function (x, i) {
+ return {index: i, value: x};
+ });
+ eachfn(arr, function (x, callback) {
+ iterator(x.value, function (v) {
+ if (!v) {
+ results.push(x);
+ }
+ callback();
+ });
+ }, function (err) {
+ callback(_map(results.sort(function (a, b) {
+ return a.index - b.index;
+ }), function (x) {
+ return x.value;
+ }));
+ });
+ };
+ async.reject = doParallel(_reject);
+ async.rejectSeries = doSeries(_reject);
+
+ var _detect = function (eachfn, arr, iterator, main_callback) {
+ eachfn(arr, function (x, callback) {
+ iterator(x, function (result) {
+ if (result) {
+ main_callback(x);
+ main_callback = function () {};
+ }
+ else {
+ callback();
+ }
+ });
+ }, function (err) {
+ main_callback();
+ });
+ };
+ async.detect = doParallel(_detect);
+ async.detectSeries = doSeries(_detect);
+
+ async.some = function (arr, iterator, main_callback) {
+ async.each(arr, function (x, callback) {
+ iterator(x, function (v) {
+ if (v) {
+ main_callback(true);
+ main_callback = function () {};
+ }
+ callback();
+ });
+ }, function (err) {
+ main_callback(false);
+ });
+ };
+ // any alias
+ async.any = async.some;
+
+ async.every = function (arr, iterator, main_callback) {
+ async.each(arr, function (x, callback) {
+ iterator(x, function (v) {
+ if (!v) {
+ main_callback(false);
+ main_callback = function () {};
+ }
+ callback();
+ });
+ }, function (err) {
+ main_callback(true);
+ });
+ };
+ // all alias
+ async.all = async.every;
+
+ async.sortBy = function (arr, iterator, callback) {
+ async.map(arr, function (x, callback) {
+ iterator(x, function (err, criteria) {
+ if (err) {
+ callback(err);
+ }
+ else {
+ callback(null, {value: x, criteria: criteria});
+ }
+ });
+ }, function (err, results) {
+ if (err) {
+ return callback(err);
+ }
+ else {
+ var fn = function (left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ };
+ callback(null, _map(results.sort(fn), function (x) {
+ return x.value;
+ }));
+ }
+ });
+ };
+
+ async.auto = function (tasks, callback) {
+ callback = callback || function () {};
+ var keys = _keys(tasks);
+ if (!keys.length) {
+ return callback(null);
+ }
+
+ var results = {};
+
+ var listeners = [];
+ var addListener = function (fn) {
+ listeners.unshift(fn);
+ };
+ var removeListener = function (fn) {
+ for (var i = 0; i < listeners.length; i += 1) {
+ if (listeners[i] === fn) {
+ listeners.splice(i, 1);
+ return;
+ }
+ }
+ };
+ var taskComplete = function () {
+ _each(listeners.slice(0), function (fn) {
+ fn();
+ });
+ };
+
+ addListener(function () {
+ if (_keys(results).length === keys.length) {
+ callback(null, results);
+ callback = function () {};
+ }
+ });
+
+ _each(keys, function (k) {
+ var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
+ var taskCallback = function (err) {
+ if (err) {
+ callback(err);
+ // stop subsequent errors hitting callback multiple times
+ callback = function () {};
+ }
+ else {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ results[k] = args;
+ async.nextTick(taskComplete);
+ }
+ };
+ var requires = task.slice(0, Math.abs(task.length - 1)) || [];
+ var ready = function () {
+ return _reduce(requires, function (a, x) {
+ return (a && results.hasOwnProperty(x));
+ }, true) && !results.hasOwnProperty(k);
+ };
+ if (ready()) {
+ task[task.length - 1](taskCallback, results);
+ }
+ else {
+ var listener = function () {
+ if (ready()) {
+ removeListener(listener);
+ task[task.length - 1](taskCallback, results);
+ }
+ };
+ addListener(listener);
+ }
+ });
+ };
+
+ async.waterfall = function (tasks, callback) {
+ callback = callback || function () {};
+ if (!tasks.length) {
+ return callback();
+ }
+ var wrapIterator = function (iterator) {
+ return function (err) {
+ if (err) {
+ callback.apply(null, arguments);
+ callback = function () {};
+ }
+ else {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var next = iterator.next();
+ if (next) {
+ args.push(wrapIterator(next));
+ }
+ else {
+ args.push(callback);
+ }
+ async.nextTick(function () {
+ iterator.apply(null, args);
+ });
+ }
+ };
+ };
+ wrapIterator(async.iterator(tasks))();
+ };
+
+ var _parallel = function(eachfn, tasks, callback) {
+ callback = callback || function () {};
+ if (tasks.constructor === Array) {
+ eachfn.map(tasks, function (fn, callback) {
+ if (fn) {
+ fn(function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ callback.call(null, err, args);
+ });
+ }
+ }, callback);
+ }
+ else {
+ var results = {};
+ eachfn.each(_keys(tasks), function (k, callback) {
+ tasks[k](function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ results[k] = args;
+ callback(err);
+ });
+ }, function (err) {
+ callback(err, results);
+ });
+ }
+ };
+
+ async.parallel = function (tasks, callback) {
+ _parallel({ map: async.map, each: async.each }, tasks, callback);
+ };
+
+ async.parallelLimit = function(tasks, limit, callback) {
+ _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
+ };
+
+ async.series = function (tasks, callback) {
+ callback = callback || function () {};
+ if (tasks.constructor === Array) {
+ async.mapSeries(tasks, function (fn, callback) {
+ if (fn) {
+ fn(function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ callback.call(null, err, args);
+ });
+ }
+ }, callback);
+ }
+ else {
+ var results = {};
+ async.eachSeries(_keys(tasks), function (k, callback) {
+ tasks[k](function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (args.length <= 1) {
+ args = args[0];
+ }
+ results[k] = args;
+ callback(err);
+ });
+ }, function (err) {
+ callback(err, results);
+ });
+ }
+ };
+
+ async.iterator = function (tasks) {
+ var makeCallback = function (index) {
+ var fn = function () {
+ if (tasks.length) {
+ tasks[index].apply(null, arguments);
+ }
+ return fn.next();
+ };
+ fn.next = function () {
+ return (index < tasks.length - 1) ? makeCallback(index + 1): null;
+ };
+ return fn;
+ };
+ return makeCallback(0);
+ };
+
+ async.apply = function (fn) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return function () {
+ return fn.apply(
+ null, args.concat(Array.prototype.slice.call(arguments))
+ );
+ };
+ };
+
+ var _concat = function (eachfn, arr, fn, callback) {
+ var r = [];
+ eachfn(arr, function (x, cb) {
+ fn(x, function (err, y) {
+ r = r.concat(y || []);
+ cb(err);
+ });
+ }, function (err) {
+ callback(err, r);
+ });
+ };
+ async.concat = doParallel(_concat);
+ async.concatSeries = doSeries(_concat);
+
+ async.whilst = function (test, iterator, callback) {
+ if (test()) {
+ var sync = true;
+ iterator(function (err) {
+ if (err) {
+ return callback(err);
+ }
+ if (sync) {
+ async.nextTick(function () {
+ async.whilst(test, iterator, callback);
+ });
+ }
+ else {
+ async.whilst(test, iterator, callback);
+ }
+ });
+ sync = false;
+ }
+ else {
+ callback();
+ }
+ };
+
+ async.doWhilst = function (iterator, test, callback) {
+ var sync = true;
+ iterator(function (err) {
+ if (err) {
+ return callback(err);
+ }
+ if (test()) {
+ if (sync) {
+ async.nextTick(function () {
+ async.doWhilst(iterator, test, callback);
+ });
+ }
+ else {
+ async.doWhilst(iterator, test, callback);
+ }
+ }
+ else {
+ callback();
+ }
+ });
+ sync = false;
+ };
+
+ async.until = function (test, iterator, callback) {
+ if (!test()) {
+ var sync = true;
+ iterator(function (err) {
+ if (err) {
+ return callback(err);
+ }
+ if (sync) {
+ async.nextTick(function () {
+ async.until(test, iterator, callback);
+ });
+ }
+ else {
+ async.until(test, iterator, callback);
+ }
+ });
+ sync = false;
+ }
+ else {
+ callback();
+ }
+ };
+
+ async.doUntil = function (iterator, test, callback) {
+ var sync = true;
+ iterator(function (err) {
+ if (err) {
+ return callback(err);
+ }
+ if (!test()) {
+ if (sync) {
+ async.nextTick(function () {
+ async.doUntil(iterator, test, callback);
+ });
+ }
+ else {
+ async.doUntil(iterator, test, callback);
+ }
+ }
+ else {
+ callback();
+ }
+ });
+ sync = false;
+ };
+
+ async.queue = function (worker, concurrency) {
+ function _insert(q, data, pos, callback) {
+ if(data.constructor !== Array) {
+ data = [data];
+ }
+ _each(data, function(task) {
+ var item = {
+ data: task,
+ callback: typeof callback === 'function' ? callback : null
+ };
+
+ if (pos) {
+ q.tasks.unshift(item);
+ } else {
+ q.tasks.push(item);
+ }
+
+ if (q.saturated && q.tasks.length === concurrency) {
+ q.saturated();
+ }
+ async.nextTick(q.process);
+ });
+ }
+
+ var workers = 0;
+ var q = {
+ tasks: [],
+ concurrency: concurrency,
+ saturated: null,
+ empty: null,
+ drain: null,
+ push: function (data, callback) {
+ _insert(q, data, false, callback);
+ },
+ unshift: function (data, callback) {
+ _insert(q, data, true, callback);
+ },
+ process: function () {
+ if (workers < q.concurrency && q.tasks.length) {
+ var task = q.tasks.shift();
+ if (q.empty && q.tasks.length === 0) {
+ q.empty();
+ }
+ workers += 1;
+ var sync = true;
+ var next = function () {
+ workers -= 1;
+ if (task.callback) {
+ task.callback.apply(task, arguments);
+ }
+ if (q.drain && q.tasks.length + workers === 0) {
+ q.drain();
+ }
+ q.process();
+ };
+ var cb = only_once(function () {
+ var cbArgs = arguments;
+
+ if (sync) {
+ async.nextTick(function () {
+ next.apply(null, cbArgs);
+ });
+ } else {
+ next.apply(null, arguments);
+ }
+ });
+ worker(task.data, cb);
+ sync = false;
+ }
+ },
+ length: function () {
+ return q.tasks.length;
+ },
+ running: function () {
+ return workers;
+ }
+ };
+ return q;
+ };
+
+ async.cargo = function (worker, payload) {
+ var working = false,
+ tasks = [];
+
+ var cargo = {
+ tasks: tasks,
+ payload: payload,
+ saturated: null,
+ empty: null,
+ drain: null,
+ push: function (data, callback) {
+ if(data.constructor !== Array) {
+ data = [data];
+ }
+ _each(data, function(task) {
+ tasks.push({
+ data: task,
+ callback: typeof callback === 'function' ? callback : null
+ });
+ if (cargo.saturated && tasks.length === payload) {
+ cargo.saturated();
+ }
+ });
+ async.nextTick(cargo.process);
+ },
+ process: function process() {
+ if (working) return;
+ if (tasks.length === 0) {
+ if(cargo.drain) cargo.drain();
+ return;
+ }
+
+ var ts = typeof payload === 'number'
+ ? tasks.splice(0, payload)
+ : tasks.splice(0);
+
+ var ds = _map(ts, function (task) {
+ return task.data;
+ });
+
+ if(cargo.empty) cargo.empty();
+ working = true;
+ worker(ds, function () {
+ working = false;
+
+ var args = arguments;
+ _each(ts, function (data) {
+ if (data.callback) {
+ data.callback.apply(null, args);
+ }
+ });
+
+ process();
+ });
+ },
+ length: function () {
+ return tasks.length;
+ },
+ running: function () {
+ return working;
+ }
+ };
+ return cargo;
+ };
+
+ var _console_fn = function (name) {
+ return function (fn) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ fn.apply(null, args.concat([function (err) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (typeof console !== 'undefined') {
+ if (err) {
+ if (console.error) {
+ console.error(err);
+ }
+ }
+ else if (console[name]) {
+ _each(args, function (x) {
+ console[name](x);
+ });
+ }
+ }
+ }]));
+ };
+ };
+ async.log = _console_fn('log');
+ async.dir = _console_fn('dir');
+ /*async.info = _console_fn('info');
+ async.warn = _console_fn('warn');
+ async.error = _console_fn('error');*/
+
+ async.memoize = function (fn, hasher) {
+ var memo = {};
+ var queues = {};
+ hasher = hasher || function (x) {
+ return x;
+ };
+ var memoized = function () {
+ var args = Array.prototype.slice.call(arguments);
+ var callback = args.pop();
+ var key = hasher.apply(null, args);
+ if (key in memo) {
+ callback.apply(null, memo[key]);
+ }
+ else if (key in queues) {
+ queues[key].push(callback);
+ }
+ else {
+ queues[key] = [callback];
+ fn.apply(null, args.concat([function () {
+ memo[key] = arguments;
+ var q = queues[key];
+ delete queues[key];
+ for (var i = 0, l = q.length; i < l; i++) {
+ q[i].apply(null, arguments);
+ }
+ }]));
+ }
+ };
+ memoized.memo = memo;
+ memoized.unmemoized = fn;
+ return memoized;
+ };
+
+ async.unmemoize = function (fn) {
+ return function () {
+ return (fn.unmemoized || fn).apply(null, arguments);
+ };
+ };
+
+ async.times = function (count, iterator, callback) {
+ var counter = [];
+ for (var i = 0; i < count; i++) {
+ counter.push(i);
+ }
+ return async.map(counter, iterator, callback);
+ };
+
+ async.timesSeries = function (count, iterator, callback) {
+ var counter = [];
+ for (var i = 0; i < count; i++) {
+ counter.push(i);
+ }
+ return async.mapSeries(counter, iterator, callback);
+ };
+
+ async.compose = function (/* functions... */) {
+ var fns = Array.prototype.reverse.call(arguments);
+ return function () {
+ var that = this;
+ var args = Array.prototype.slice.call(arguments);
+ var callback = args.pop();
+ async.reduce(fns, args, function (newargs, fn, cb) {
+ fn.apply(that, newargs.concat([function () {
+ var err = arguments[0];
+ var nextargs = Array.prototype.slice.call(arguments, 1);
+ cb(err, nextargs);
+ }]))
+ },
+ function (err, results) {
+ callback.apply(that, [err].concat(results));
+ });
+ };
+ };
+
+ // AMD / RequireJS
+ if (typeof define !== 'undefined' && define.amd) {
+ define([], function () {
+ return async;
+ });
+ }
+ // Node.js
+ else if (typeof module !== 'undefined' && module.exports) {
+ module.exports = async;
+ }
+ // included directly via
+
+
diff --git a/src/app.coffee b/src/app.coffee
index 409e9d8..fef7c3b 100644
--- a/src/app.coffee
+++ b/src/app.coffee
@@ -1,7 +1,4 @@
#!/usr/bin/env coffee
-async = require 'async'
-{ _ } = require 'lodash'
-
config = require './modules/config'
regex = require './modules/regex'
render = require './modules/render'
diff --git a/src/component.json b/src/component.json
deleted file mode 100644
index eee5de9..0000000
--- a/src/component.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "name": "app",
- "main": "app.js",
- "version": "1.0.0-alpha",
- "dependencies": {
- "lodash/lodash": "*",
- "caolan/async": "*",
- "mbostock/d3": "*",
- "visionmedia/superagent": "*",
- "necolas/normalize.css": "*",
- "component/tip": "*",
- "component/aurora-tip": "*",
- "component/marked": "*"
- },
- "styles": [
- "styles/fonts.css"
- ],
- "apps-b": [
- "app.coffee",
-
- "modules/config.coffee",
- "modules/graph.coffee",
- "modules/issues.coffee",
- "modules/milestones.coffee",
- "modules/regex.coffee",
- "modules/request.coffee",
- "modules/render.coffee",
- "modules/repo.coffee",
-
- "templates/error.eco",
- "templates/graph.eco",
- "templates/info.eco",
- "templates/label.eco",
- "templates/loading.eco",
- "templates/progress.eco",
-
- "styles/app.styl"
- ]
-}
\ No newline at end of file
diff --git a/src/modules/config.coffee b/src/modules/config.coffee
index 38a40fa..5f415f9 100644
--- a/src/modules/config.coffee
+++ b/src/modules/config.coffee
@@ -1,5 +1,5 @@
#!/usr/bin/env coffee
-{ _ } = require 'lodash'
+{ _ } = require './require'
request = require './request'
regex = require './regex'
diff --git a/src/modules/graph.coffee b/src/modules/graph.coffee
index d0d481d..9b07939 100644
--- a/src/modules/graph.coffee
+++ b/src/modules/graph.coffee
@@ -1,9 +1,7 @@
#!/usr/bin/env coffee
-{ _ } = require 'lodash'
-d3 = require 'd3'
-Tip = require 'tip'
+{ _, d3 } = require './require'
-reg = require './regex'
+reg = require './regex'
module.exports =
@@ -219,7 +217,10 @@ module.exports =
.attr("d", line.interpolate("linear").y( (d) -> y(d.points) )(actual))
# Collect the tooltip here.
- tooltip = null
+ tooltip = d3.tip().attr('class', 'd3-tip').html ({ number, title }) ->
+ "##{number}: #{title}"
+
+ svg.call(tooltip)
# Show when we closed an issue.
svg.selectAll("a.issue")
@@ -234,19 +235,7 @@ module.exports =
.attr("cx", ({ date }) -> x date )
.attr("cy", ({ points }) -> y points )
.attr("r", ({ radius }) -> 5 ) # fixed for now
- .on('mouseover', ({ date, points, title, number }) ->
- # Pass a title string.
- tooltip = new Tip "##{number}: #{title}"
- # Absolutely position the div.
- div = document.querySelector '#tooltip'
- div.style.left = x(date) + margin.left + 'px'
- div.style.top = -10 + y(points) + margin.top + 'px'
- # And now show us on the div.
- tooltip.show '#tooltip'
- )
- .on('mouseout', (d) ->
- # Hide after a time has passed if exists.
- tooltip?.hide(200)
- )
+ .on('mouseover', tooltip.show)
+ .on('mouseout', tooltip.hide)
cb null
\ No newline at end of file
diff --git a/src/modules/issues.coffee b/src/modules/issues.coffee
index 512b5cf..70b0938 100644
--- a/src/modules/issues.coffee
+++ b/src/modules/issues.coffee
@@ -1,9 +1,8 @@
#!/usr/bin/env coffee
-{ _ } = require 'lodash'
-async = require 'async'
+{ _, async } = require './require'
-req = require './request'
-reg = require './regex'
+req = require './request'
+reg = require './regex'
module.exports =
diff --git a/src/modules/milestones.coffee b/src/modules/milestones.coffee
index 76855d2..e1c4889 100644
--- a/src/modules/milestones.coffee
+++ b/src/modules/milestones.coffee
@@ -1,6 +1,5 @@
#!/usr/bin/env coffee
-{ _ } = require 'lodash'
-marked = require 'marked'
+{ _, marked } = require './require'
request = require './request'
diff --git a/src/modules/repo.coffee b/src/modules/repo.coffee
index 08ab8d0..c76ef93 100644
--- a/src/modules/repo.coffee
+++ b/src/modules/repo.coffee
@@ -1,6 +1,5 @@
#!/usr/bin/env coffee
-{ _ } = require 'lodash'
-async = require 'async'
+{ _, async } = require './require'
milestones = require './milestones'
issues = require './issues'
diff --git a/src/modules/request.coffee b/src/modules/request.coffee
index f96d7a2..ae367b3 100644
--- a/src/modules/request.coffee
+++ b/src/modules/request.coffee
@@ -1,9 +1,8 @@
#!/usr/bin/env coffee
-sa = require 'superagent'
-{ _ } = require 'lodash'
+{ superagent, _ } = require './require'
# Custom JSON parser.
-sa.parse =
+superagent.parse =
'application/json': (res) ->
try
JSON.parse res
@@ -29,7 +28,7 @@ module.exports =
# Get config from our host always.
'config': (cb) ->
- sa
+ superagent
.get("http://#{window.location.host + window.location.pathname}config.json")
.set('Content-Type', 'application/json')
.end _.partialRight respond, cb
@@ -39,7 +38,7 @@ request = ({ protocol, host, token, path }, query, noun, cb) ->
# Make the query params.
q = ( "#{k}=#{v}" for k, v of query ).join('&')
- req = sa
+ req = superagent
# The URI.
.get("#{protocol}://#{host}/repos/#{path}/#{noun}?#{q}")
# The content type.
diff --git a/src/modules/require.coffee b/src/modules/require.coffee
new file mode 100644
index 0000000..9c921d3
--- /dev/null
+++ b/src/modules/require.coffee
@@ -0,0 +1,5 @@
+#!/usr/bin/env coffee
+# So we can easily stub these.
+module.exports = {
+ _, superagent, d3, async, marked
+}
\ No newline at end of file
diff --git a/src/styles/app.styl b/src/styles/app.styl
index e876587..3a65a77 100644
--- a/src/styles/app.styl
+++ b/src/styles/app.styl
@@ -1,3 +1,5 @@
+@import 'nib'
+
// color definitions
$closed = #4DAF7C
$opened = #E55F3A
@@ -138,6 +140,27 @@ h2
path
display: none
+// tooltips
+.d3-tip
+ margin-top: -10px
+ font-size: 11px
+ padding: 8px 10px 7px 10px
+ text-align: center
+ background: rgba(0,0,0,0.75)
+ color: #fff
+ border-radius: 3px
+
+ &:after
+ width: 100%
+ color: rgba(0,0,0,0.8)
+ content: "\25BC"
+ position: absolute
+
+ &.n:after
+ margin: -3px 0 0 0
+ top: 100%
+ left: 0
+
// progression graph
#progress
padding: 20px
diff --git a/test/config.coffee b/test/config.coffee
index b79df89..2cd4c19 100644
--- a/test/config.coffee
+++ b/test/config.coffee
@@ -7,6 +7,12 @@ req = {}
config = proxy path.resolve(__dirname, '../src/modules/config.coffee'),
'./request': req
+ './require':
+ '_': require 'lodash'
+ 'superagent': null
+ 'd3': null
+ 'async': null
+ 'marked': null
{ size_label } = require path.resolve __dirname, '../src/modules/regex.coffee'
diff --git a/test/issues.coffee b/test/issues.coffee
index da2636b..aeabe8a 100644
--- a/test/issues.coffee
+++ b/test/issues.coffee
@@ -9,6 +9,12 @@ regex = require path.resolve(__dirname, '../src/modules/regex.coffee')
issues = proxy path.resolve(__dirname, '../src/modules/issues.coffee'),
'./request': req
+ './require':
+ '_': require 'lodash'
+ 'superagent': null
+ 'd3': null
+ 'async': require 'async'
+ 'marked': null
repo = { 'milestone': { 'number': no } }
diff --git a/test/milestones.coffee b/test/milestones.coffee
index f28c7a5..368d566 100644
--- a/test/milestones.coffee
+++ b/test/milestones.coffee
@@ -7,6 +7,12 @@ req = {}
milestones = proxy path.resolve(__dirname, '../src/modules/milestones.coffee'),
'./request': req
+ './require':
+ '_': require 'lodash'
+ 'superagent': null
+ 'd3': null
+ 'async': null
+ 'marked': require 'marked'
module.exports =
@@ -166,8 +172,6 @@ module.exports =
do done
'milestones - has description': (done) ->
- marked = require 'marked'
-
req.all_milestones = (opts, cb) ->
cb null, [
{
diff --git a/test/request.coffee b/test/request.coffee
index 51386ca..e8daee8 100644
--- a/test/request.coffee
+++ b/test/request.coffee
@@ -10,7 +10,12 @@ class Superagent
end: (cb) -> cb @response
request = proxy path.resolve(__dirname, '../src/modules/request.coffee'),
- 'superagent': sa = new Superagent()
+ './require':
+ '_': require 'lodash'
+ 'superagent': sa = new Superagent()
+ 'd3': null
+ 'async': null
+ 'marked': null
module.exports =