core-state
Version:
127 lines (123 loc) • 4.43 kB
text/coffeescript
if typeof EventEmitter is "undefined"
EventEmitter = Leaf?.EventEmitter or require("eventex").EventEmitter
class ObservePortal extends EventEmitter
constructor:( )->
super()
= {}
= {}
.listenBy this,"change", .bind(this)
.listenBy this,"init", .bind(this)
.listenBy this,"delete", .bind(this)
observeBy:(who,path,callback)->
path =
[path] ?= []
watch = [path]
exists = watch.some (item)->
return item.owner is who and callback is callback
if not exists
watch.push {
owner:who
callback:callback
}
path,callback
stopObserveBy:(who,path)->
if path
watch = [path]
watches = [watch]
else
watches = ( [prop] for prop of )
for watch,index in watches
for item in watch
if item.owner is who
watch.splice(index,1)
break
for path of
if [path].length is 0
path
_observe:(path,callback = ()->)->
.observe path,(err,results)=>
# I do not emit change event here, no matter the property change
# or not.
# If every thing goes right,
# 1. the first observe will not need a event since nobody is listen.
# 2. if not first observe then change event will already be sent before
#
# so no bother to fire even here.
if results and results not instanceof Array
results = [results]
else if not results
results = []
for result in results
result.path,result
callback err,results
_stopObserve:(path,callback = ()->)->
.stopObserve path,callback
normalize:(path)->
path = path.split(".")
group = path.shift()
if not group
return
name = path.shift()
if not name or name is "*"
name = ""
path = "#{group}.#{name}"
return path
handleChange:(change)->
if change.type is "delete"
change.path
else if change.type in ["init","change"]
change.path,change.property
"#{change.type}/#{change.path}"
change.type,change
get:(path)->
detail =
if detail instanceof Array
return detail.map (item)->item.data
else if detail
return detail.data
return null
getProperty:(path)->
routes = path.split(".")
groupName = routes.shift()
propertyName = routes.shift()
if not groupName
return null
group = [groupName] or {}
if not propertyName or propertyName is "*"
return (group[prop] for prop of group)
property = group[propertyName]
if not property
return null
return property
setBufferProperty:(path,property)->
[group,name] = path.split(".")
if not group or not name
return
[group] ?= {}
[group][name] = property
deleteBufferProperty:(path)->
[group,name] = path.split(".")
delete [group]?[name]
class Adapter extends EventEmitter
constructor:()->
super()
observe:(path,callback)->
stopObserve:(path,callback)->
class ExampleAdapter extends Adapter
constructor:( )->
super()
.on "delete",(path)=>
"delete",{type:"delete",path}
.on "init",(prop)=>
prop.type = "init"
"init",prop
.on "change",(prop)=>
prop.type = "change"
"change",prop
observe:(path,callback)->
callback null, .observe path
stopObserve:(path,callback)->
callback null, .stopObserve path
module.exports.ObservePortal = ObservePortal
module.exports.Adapter = Adapter
module.exports.ExampleAdapter = ExampleAdapter