@danielkalen/simplybind
Version:
Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.
103 lines (75 loc) • 3.16 kB
text/coffeescript
fetchDescriptor = (object, property, isProto)->
descriptor = getDescriptor(object, property)
if descriptor
descriptor.configurable = true if isProto
return descriptor
else if objectProto=Object.getPrototypeOf(object)
return fetchDescriptor(objectProto, property, true)
convertToLive = (bindingInstance, object, onlyArrayMethods)->
_ = bindingInstance
_.origDescriptor = fetchDescriptor(object, _.property) if not _.origDescriptor
if onlyArrayMethods
arrayMutatorMethods.forEach (method)-> # Using forEach because we need a closure here
defineProperty object, method,
configurable: true
value: ()->
result = Array::[method].apply object, arguments
_.updateAllSubs(_)
return result
else
if _.type is 'Proxy'
origFn = _.origFn = _.value
context = object
_.value = result:null, args:null
if checkIf.isFunction(origFn)
slice = [].slice
getterValue = proxyFn = ()->
args = slice.call(arguments)
_.value.args = args = if _.selfTransform then _.selfTransform(args) else args
_.value.result = result = origFn.apply(context, args)
_.updateAllSubs(_)
return result
defineProperty object, _.property,
configurable: _.isLiveProp = true
get: ()-> getterValue
set: (newValue)->
if not checkIf.isFunction(newValue)
getterValue = newValue
else if newValue isnt origFn
origFn = _.origFn = newValue if newValue isnt proxyFn
getterValue = proxyFn if getterValue isnt proxyFn
return
# simplyimport:if BUNDLE_TARGET = 'browser'
else if not targetIncludes(_.type, 'DOM') and not (_.object is window and targetIncludes(windowPropsToIgnore, _.property))
# simplyimport:end
# simplyimport:if BUNDLE_TARGET = 'node'
else
# simplyimport:end
# 'ObjectProp' or 'Array' type bindings
propertyDescriptor = _.origDescriptor or dummyPropertyDescriptor
_.origGetter = propertyDescriptor.get.bind(object) if propertyDescriptor.get
_.origSetter = propertyDescriptor.set.bind(object) if propertyDescriptor.set
shouldWriteLiveProp = propertyDescriptor.configurable
# simplyimport:if BUNDLE_TARGET = 'browser'
shouldWriteLiveProp = shouldWriteLiveProp and object.constructor isnt CSSStyleDeclaration
import './webkitDomDescriptorFix'
# simplyimport:end
if shouldWriteLiveProp
typeIsArray = _.type is 'Array'
shouldIndicateUpdateIsFromSelf = not _.origSetter and not typeIsArray
defineProperty object, _.property,
configurable: _.isLiveProp = true
enumerable: propertyDescriptor.enumerable
get: _.origGetter or ()-> _.value
set: (newValue)-> _.setValue(newValue, _, shouldIndicateUpdateIsFromSelf); return
if typeIsArray
convertToLive(_, object[_.property], true)
return
convertToReg = (bindingInstance, object, onlyArrayMethods)->
if onlyArrayMethods
delete object[method] for method in arrayMutatorMethods
else
_ = bindingInstance
newDescriptor = _.origDescriptor
newDescriptor.value = (_.origFn or _.value) unless newDescriptor.set or newDescriptor.get
defineProperty object, _.property, newDescriptor