WIP async transformation of the library

async
Enrico Fasoli 2015-04-09 13:06:31 +02:00
parent 265f3bc7f8
commit 6c6843df49
6 changed files with 147 additions and 105 deletions

View File

@ -22,6 +22,7 @@
"bootstrap": "~3.3.4",
"sweetalert": "~0.5.0",
"angular": "~1.3.15",
"angular-ui-router": "~0.2.13"
"angular-ui-router": "~0.2.13",
"async": "~0.9.2"
}
}

View File

@ -35,6 +35,7 @@ gulp.task('js',function(){
jsFiles = ["src/*.js",
"bower_components/jquery/dist/jquery.js",
"bower_components/moment/moment.js",
"bower_components/async/lib/async.js",
"bower_components/bootstrap/dist/js/bootstrap.js",
"bower_components/bootstrap/js/collapse.js",
"bower_components/angular/angular.js",

View File

@ -1,6 +1,7 @@
class PBS
constructor: (@list, @verbose) ->
@days = []
@verbose = yes
@criticalPaths = []
log: (x...) ->
@ -25,68 +26,89 @@ class PBS
return item
# Compute the item's end day
calculateEndDay: (item) =>
if !item.startDay?
calculateEndDay: (item,cb) =>
if item.endDay? then cb null, item.endDay
else if !item.startDay?
@log "calculating start day of",item.id
item.startDay = @calculateStartDay item
@log "start day of",item.id,"is",item.startDay
item.endDay = item.startDay + item.duration
@log "end day of",item.id,"is",item.endDay
@insertDay item.endDay
return item.endDay
@calculateStartDay item, => @calculateEndDay item, cb
else
@log "start day of",item.id,"is",item.startDay
item.endDay = item.startDay + item.duration
@log "end day of",item.id,"is",item.endDay
@insertDay item.endDay
cb null, item.endDay
# Find out which day the activity starts
calculateStartDay: (item) =>
if !item.depends? or item.depends.length is 0
calculateStartDay: (item,cb) =>
if item.startDay? then cb null, item.startDay
else if !item.depends? or item.depends.length is 0
@insertDay 0
return item.startDay = 0
item.startDay = @maxa item.depends.map(@toActivity).map @calculateEndDay
@log "start day of",item.id,"is",item.startDay
# write max delay time to each depend
for j,x of item.depends
@log "checking permittedDelay to dependency", x, "of", item
i = @toActivity x
if !i.dependant? then i.dependant = [item.id]
else i.dependant.push item.id
if !i.permittedDelay?
i.permittedDelay = item.startDay - @calculateEndDay i
@log "written permittedDelay to dependency", x, "of", item, "as", i.permittedDelay
else @log "aborting permittedDelay: already calculated"
@log "permitted delay of",x,"is",i.permittedDelay
@insertDay item.startDay
return item.startDay
cb null, item.startDay = 0
else
async.map item.depends.map(@toActivity), @calculateEndDay.bind(@), (er, r) =>
item.startDay = @maxa r
@log "start day of",item.id,"is",item.startDay
# write max delay time to each depend
checkPermittedDelay = (x,c) =>
@log "checking permittedDelay to dependency", x, "of", item
i = @toActivity x
if !i.dependant? then i.dependant = [item.id]
else i.dependant.push item.id
if !i.permittedDelay?
@calculateEndDay i, (e,d) =>
i.permittedDelay = item.startDay - d
@log "written permittedDelay to dependency", x, "of", item, "as", i.permittedDelay
@log "permitted delay of",x,"is",i.permittedDelay
c()
else
@log "aborting permittedDelay: already calculated"
@log "permitted delay of",x,"is",i.permittedDelay
c()
async.each item.depends, checkPermittedDelay.bind(@), =>
@insertDay item.startDay
cb null, item.startDay
calculateDelays: (item) =>
if !item.dependant? or item.dependant.length is 0 then return no
lowestFDelay = 0; fDelay = no; cDelay = 0
for j,i of item.dependant
x = @toActivity i
if !isNaN(x.permittedDelay) or x.permittedDelay < lowestFDelay or fDelay is no
@log "activity", i, "dependant on", item.id, "has the lowest delay for now ("+(x.permittedDelay or 0)+")"
lowestFDelay = x.permittedDelay or 0
cDelay = x.chainedDelay or 0
fDelay = yes
olDelay = item.chainedDelay
item.chainedDelay = lowestFDelay + cDelay
@log "chained delay of", item.id, "is", item.chainedDelay
return item.chainedDelay isnt olDelay
calculateDelays: (item,cb) =>
if !item.dependant? or item.dependant.length is 0 then cb null, no
else
lowestFDelay = 0; fDelay = no; cDelay = 0
checkDependant = (i,c) =>
x = @toActivity i
if !isNaN(x.permittedDelay) or x.permittedDelay < lowestFDelay or fDelay is no
@log "activity", i, "dependant on", item.id, "has the lowest delay for now ("+(x.permittedDelay or 0)+")"
lowestFDelay = x.permittedDelay or 0
cDelay = x.chainedDelay or 0
fDelay = yes
c()
async.each item.dependant, checkDependant.bind(@), =>
olDelay = item.chainedDelay
item.chainedDelay = lowestFDelay + cDelay
@log "chained delay of", item.id, "is", item.chainedDelay
cb null, item.chainedDelay isnt olDelay
calculateCriticalPaths: (path) ->
calculateCriticalPaths: (path,cb) ->
@log "calculating path from",path
lastID = path[path.length - 1]
last = @toActivity lastID
if last.dependant? and last.dependant.length > 0
last.dependant.forEach (x) =>
checkDependant = (x,cb2) =>
ii = @toActivity x
delay = ii.permittedDelay or 0
if delay is 0
@calculateCriticalPaths path.concat x
cb2 null, yes
@calculateCriticalPaths path.concat(x), cb
else
@log "dead end at", lastID, "-->", x, "because delay is", delay
cb2 null, no
async.each last.dependant, checkDependant.bind(@), (a,b) -> return
else
path.forEach (x) => @toActivity(x).critical = yes
@log "calculated path", path
@criticalPaths.push path
setCritical = (x,c) =>
@toActivity(x).critical = yes
c null, yes
async.each path, setCritical.bind(@), =>
@log "calculated path", path
@criticalPaths.push path
cb null, path
# Find out which activity has the highest id
highestID: => return @maxa(@list.map (x) -> x.id)
@ -100,26 +122,41 @@ class PBS
setData: (data) ->
@list = data
return @
calculate: (options,cb) ->
h = @highestID()
for x,i in @list
@log '('+x.id+'/'+h+')'
@calculateEndDay x
finished = no; i = 0
while !finished
i++; finished = yes
for x,i in @list
if @calculateDelays x
finished = no
@log "Done calculating delays. Took", i, "iterations"
for x,i in @list
if !x.depends? or x.depends.length is 0
@calculateCriticalPaths [x.id]
results = activities: @list, days: @days, criticalPaths: @criticalPaths
if options?.json
if cb? then cb(JSON.stringify results)
JSON.stringify results
else
if cb? then cb(results)
results
@log "(Step 1) calculating startDay, endDay, freeDelay"
async.each @list, @calculateEndDay.bind(@), =>
@log "(Step 2) Starting chained delay calculations."
cont = yes; i = 0
notDone = ->
console.log cont
cont
chainedDelayChanged = (x,res) =>
i++
cont = no
@calculateDelays x, (e,r) =>
@log "cDelay calc result:",r
res null, r
calculateAllDelays = (cb2) =>
async.map @list, chainedDelayChanged, (err,r) ->
iterator = (acc,x,cb3) ->
if x
cb3 null, yes
else cb3 null, acc
async.reduce r, no, iterator, (err,res) ->
cont = res
cb2 null
#TODO: check WHILST
async.whilst notDone, calculateAllDelays, =>
@log "Done calculating delays. Took", i, "iterations"
#TODO: check THIS vvvvv
calculateCriticalPathIfApplicable = (x, c) =>
if !x.depends? or x.depends.length is 0
@calculateCriticalPaths [x.id], c
async.each @list, calculateCriticalPathIfApplicable.bind(@), =>
results = activities: @list, days: @days, criticalPaths: @criticalPaths
@log "DONE:", results
if options?.json
cb JSON.stringify results
else
cb results

View File

@ -46,13 +46,15 @@ pertController = ($scope) ->
localStorage.setItem 'ganttpert', sdata
unless options.silent
swal 'Ok', 'Data updated', 'success'
$scope.pbs = new PBS(data).calculate()
$scope.$broadcast 'dataChanged'
$scope.pbs = new PBS(data).calculate {}, ->
$scope.$broadcast 'dataChanged'
catch e
swal 'Error', e, 'error'
$scope.fromLocalStorage = (options) ->
$scope.fromLocalStorage = (options,cb) ->
options = options || {}
if options.call? then cb = options
else unless cb?.call? then return console.log "fromLocalStorage called without callback"
data = localStorage.getItem options.name || 'ganttpert'
if data is null then data = "[]"
try
@ -63,13 +65,15 @@ pertController = ($scope) ->
swal 'JSON Error', e, 'error'
if options.raw
#console.log 'Loading: []'
return []
cb []
else
#console.log 'Loading: {list: [], days: []}'
return list: [], days: []
cb list: [], days: []
if options.raw
#console.log 'Loading: '+jdata
return jdata
cb jdata
else
#console.log 'Loading: '+$scope.pbs
return $scope.pbs ?= new PBS(jdata).calculate()
new PBS(jdata).calculate (x) ->
$scope.pbs = x
cb x

View File

@ -1,9 +1,8 @@
pertApp.controller 'tableController', ($scope) ->
$scope.list = []
$scope.refreshTable = ->
ls = $scope.fromLocalStorage()
if ls?
$scope.list = ls.activities
$scope.fromLocalStorage (ls) ->
if ls? then $scope.list = ls.activities
$scope.$on 'dataChanged', $scope.refreshTable
$scope.refreshTable()
@ -32,7 +31,7 @@ pertApp.controller 'pertDiagController', ($scope) ->
network = new vis.Network (document.getElementById 'pertDiagram'), { nodes: nodes, edges: connections }, options
$scope.rebuild = ->
console.log 'rebuild'
$scope.buildGraph $scope.fromLocalStorage()
$scope.fromLocalStorage (r) -> $scope.buildGraph r
$scope.$on 'dataChanged', $scope.rebuild
$scope.rebuild()
@ -47,8 +46,8 @@ pertApp.controller 'ganttDiagController', ($scope) ->
if !data? then return
timeline = new vis.Timeline (document.getElementById 'timeline'), ($scope.toDates data.activities), {}
$scope.$on 'dataChanged', ->
$scope.buildTimeline $scope.fromLocalStorage()
$scope.buildTimeline $scope.fromLocalStorage()
$scope.fromLocalStorage (r) -> $scope.buildTimeline r
$scope.fromLocalStorage (r) -> $scope.buildTimeline r
pertApp.controller 'rawEditorController', ($scope) ->
$scope.reset = ->
@ -60,10 +59,9 @@ pertApp.controller 'rawEditorController', ($scope) ->
swal 'Invalid Data', e, 'error'
$scope.toLocalStorage data
$scope.reloadData = ->
$scope.taData = JSON.stringify $scope.fromLocalStorage silent: yes, raw: yes
$scope.$on 'dataChanged', ->
$scope.reloadData()
#$('#ta').val JSON.stringify $scope.fromLocalStorage silent: yes, raw: yes
$scope.fromLocalStorage { silent: yes, raw: yes }, (x) ->
$scope.taData = JSON.stringify x
$scope.$on 'dataChanged', -> $scope.reloadData()
$scope.reloadData()
pertApp.controller 'editorController', ($scope) ->
@ -77,18 +75,18 @@ pertApp.controller 'editorController', ($scope) ->
swal 'Ops', 'could not find '+id, 'warning'
$scope.delete = (index,id) ->
newdata = $scope.fromLocalStorage raw: yes
l = []
if id? then for i,j of newdata
if id isnt j.id
l.push j
else for i,j of newdata
if parseInt(i) isnt index
l.push j
diff = newdata.length - l.length
$scope.toLocalStorage l, silent: yes
if diff isnt 1
swal 'Done', diff+' item(s) deleted', 'warning'
$scope.fromLocalStorage { raw: yes }, (newdata) ->
l = []
if id? then for i,j of newdata
if id isnt j.id
l.push j
else for i,j of newdata
if parseInt(i) isnt index
l.push j
diff = newdata.length - l.length
$scope.toLocalStorage l, silent: yes
if diff isnt 1
swal 'Done', diff+' item(s) deleted', 'warning'
$scope.addNew = (id, dur, deps) ->
dur ?= $('#new-duration').val().trim()
@ -109,14 +107,14 @@ pertApp.controller 'editorController', ($scope) ->
unless isNaN dep
deps[i] = parseInt dep
catch e
newdata = $scope.fromLocalStorage silent: yes, raw: yes
if !newdata? or newdata is null or !newdata.push?
newdata = []
newdata.push { id: id, duration: dur, depends: deps }
$scope.toLocalStorage newdata, silent: yes
$scope.fromLocalStorage { silent: yes, raw: yes }, (newdata) ->
if !newdata? or newdata is null or !newdata.push?
newdata = []
newdata.push { id: id, duration: dur, depends: deps }
$scope.toLocalStorage newdata, silent: yes
$scope.refreshEditor = ->
data = $scope.fromLocalStorage { silent: yes, raw: yes }
$scope.list = data || []
$scope.fromLocalStorage { silent: yes, raw: yes }, (data) ->
$scope.list = data || []
$scope.$on 'dataChanged', $scope.refreshEditor
$scope.refreshEditor()

View File

@ -9,6 +9,7 @@
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="sweet-alert.css">
<script src="jquery.js"></script>
<script src="async.js"></script>
<script src="sweet-alert.js"></script>
<script src="angular.js"></script>
<script src="bootstrap.js"></script>