@danielkalen/simplybind
Version:
Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.
157 lines (83 loc) • 3.69 kB
text/coffeescript
import [browserOnly] closure-helpers-changeEvent.coffee
arrayMutatorMethods = ['push','pop','shift','unshift','splice','reverse','sort']
dummyPropertyDescriptor = {}
genID = ()-> 'sb_'+(Math.floor((1+Math.random()) * 1000000000000).toString(16))
genObj = ()-> Object.create(null)
# ==== Checks =================================================================================
arrayIncludes = (arr, item)-> arr.indexOf(item) isnt -1
checkIf =
isDefined: (subject)-> subject isnt undefined
isObject: (subject)-> typeof subject is 'object' and subject # 2nd check is to test against 'null' values
isString: (subject)-> typeof subject is 'string'
isNumber: (subject)-> typeof subject is 'number'
isFunction: (subject)-> typeof subject is 'function'
isBindingInterface: (subject)-> subject instanceof BindingInterface
import [browserOnly] closure-helpers-checkIf.DOM.coffee
# ==== Options =================================================================================
setOptionsForBinding = (binding, newOptions)->
for option,value of newOptions
binding.options[option] = value if checkIf.isDefined(globalOptions[option])
binding.makePropertyLive()
return
extendState = (base, stateToInherit)->
stateMapping = Object.keys(stateToInherit)
base[key] = stateToInherit[key] for key in stateMapping
return
# ==== Binding Cache =================================================================================
cache =
get: (object, isSimpleObject, selector, isMultiChoice)->
if isSimpleObject
return boundInstances[object._sb_ID]
else
import [browserOnly] closure-helpers-cache.get.DOMChoice_group.coffee
if object._sb_map and object._sb_map[selector]
return boundInstances[ object._sb_map[selector] ]
set: (B, isSimpleObject)-> # B ==== Binding Object
if isSimpleObject
Object.defineProperty B.object, '_sb_ID', {'configurable':true, 'value':B.ID}
else
selector = B.selector
if B.object._sb_map
B.object._sb_map[selector] = B.ID
else
propsMap = {}
propsMap[selector] = B.ID
Object.defineProperty B.object, '_sb_map', {'configurable':true, 'value':propsMap}
return
# ==== Placeholders =================================================================================
escapeRegEx = /[.*+?^${}()|[\]\\]/g
pholderRegEx = pholderRegExSplit = null
setPholderRegEx = ()->
start = globalOptions.placeholder[0].replace(escapeRegEx, '\\$&')
end = globalOptions.placeholder[1].replace(escapeRegEx, '\\$&')
middle = "[^#{end}]+"
pholderRegEx = new RegExp("#{start}(#{middle})#{end}", 'g')
pholderRegExSplit = new RegExp("#{start}#{middle}#{end}", 'g')
return
applyPlaceholders = (contexts, values, indexMap)->
output = ''
for contextPart,index in contexts
output += contextPart
output += values[indexMap[index]] if indexMap[index]
return output
import [browserOnly] closure-helpers-scanTextNodesPlaceholders.coffee
# ==== Errors + Warnings =================================================================================
throwError = (errorName)->
throw new Error 'SimplyBind: '+(errors[errorName] or errorName)
throwWarning = (warningName, depth)-> unless globalOptions.silent
errSource = getErrSource(depth)
warn = errors[warningName]
warn += "\n\n"+errSource
console.warn('SimplyBind: '+warn)
return
throwErrorUnavail = (methodName)->
throwError "You can't use/invoke .#{methodName}() at this stage", true
return
throwErrorBadArg = (methodName, arg)->
throwError "Invalid argument/s (#{arg}) passed to .#{methodName}()", true
return
getErrSource = (depth)->
((new Error).stack or '')
.split('\n')
.slice(depth+3)
.join('\n')