tracker-group.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. 'use strict'
  2. const TrackerBase = require('./tracker-base.js')
  3. const Tracker = require('./tracker.js')
  4. const TrackerStream = require('./tracker-stream.js')
  5. class TrackerGroup extends TrackerBase {
  6. parentGroup = null
  7. trackers = []
  8. completion = {}
  9. weight = {}
  10. totalWeight = 0
  11. finished = false
  12. bubbleChange = bubbleChange(this)
  13. nameInTree () {
  14. var names = []
  15. var from = this
  16. while (from) {
  17. names.unshift(from.name)
  18. from = from.parentGroup
  19. }
  20. return names.join('/')
  21. }
  22. addUnit (unit, weight) {
  23. if (unit.addUnit) {
  24. var toTest = this
  25. while (toTest) {
  26. if (unit === toTest) {
  27. throw new Error(
  28. 'Attempted to add tracker group ' +
  29. unit.name + ' to tree that already includes it ' +
  30. this.nameInTree(this))
  31. }
  32. toTest = toTest.parentGroup
  33. }
  34. unit.parentGroup = this
  35. }
  36. this.weight[unit.id] = weight || 1
  37. this.totalWeight += this.weight[unit.id]
  38. this.trackers.push(unit)
  39. this.completion[unit.id] = unit.completed()
  40. unit.on('change', this.bubbleChange)
  41. if (!this.finished) {
  42. this.emit('change', unit.name, this.completion[unit.id], unit)
  43. }
  44. return unit
  45. }
  46. completed () {
  47. if (this.trackers.length === 0) {
  48. return 0
  49. }
  50. var valPerWeight = 1 / this.totalWeight
  51. var completed = 0
  52. for (var ii = 0; ii < this.trackers.length; ii++) {
  53. var trackerId = this.trackers[ii].id
  54. completed +=
  55. valPerWeight * this.weight[trackerId] * this.completion[trackerId]
  56. }
  57. return completed
  58. }
  59. newGroup (name, weight) {
  60. return this.addUnit(new TrackerGroup(name), weight)
  61. }
  62. newItem (name, todo, weight) {
  63. return this.addUnit(new Tracker(name, todo), weight)
  64. }
  65. newStream (name, todo, weight) {
  66. return this.addUnit(new TrackerStream(name, todo), weight)
  67. }
  68. finish () {
  69. this.finished = true
  70. if (!this.trackers.length) {
  71. this.addUnit(new Tracker(), 1, true)
  72. }
  73. for (var ii = 0; ii < this.trackers.length; ii++) {
  74. var tracker = this.trackers[ii]
  75. tracker.finish()
  76. tracker.removeListener('change', this.bubbleChange)
  77. }
  78. this.emit('change', this.name, 1, this)
  79. }
  80. debug (depth = 0) {
  81. const indent = ' '.repeat(depth)
  82. let output = `${indent}${this.name || 'top'}: ${this.completed()}\n`
  83. this.trackers.forEach(function (tracker) {
  84. output += tracker instanceof TrackerGroup
  85. ? tracker.debug(depth + 1)
  86. : `${indent} ${tracker.name}: ${tracker.completed()}\n`
  87. })
  88. return output
  89. }
  90. }
  91. function bubbleChange (trackerGroup) {
  92. return function (name, completed, tracker) {
  93. trackerGroup.completion[tracker.id] = completed
  94. if (trackerGroup.finished) {
  95. return
  96. }
  97. trackerGroup.emit('change', name || trackerGroup.name, trackerGroup.completed(), trackerGroup)
  98. }
  99. }
  100. module.exports = TrackerGroup