UNPKG

@danielkalen/simplybind

Version:

Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.

81 lines (59 loc) 5.12 kB
Binding = (object, type, state)-> extendState(@, state) @optionsDefault = if @saveOptions then @options else defaultOptions @type = type # ObjectProp | Array | Func | Proxy | Event | DOMAttr | DOMValue | DOMCheckbox | DOMRadio @object = object # The subject object of this binding, i.e. function, array, {}, DOM el, etc. @ID = genID() # Assigned only after passing a valid object to .of() @subs = [] # Subscribers array listing all of the objects that will be updated upon value update @subOpts = genObj() # Map subscribers' options by their ID @pubsMap = genObj() # Map publishers (bindings that update this binding) by their ID @subsPholders = genObj() # SubscriberID:sub-placeholder mapping @myPholders = genObj() # SubscriberID:self-placeholder mapping indicating which subs will receive a value of a specific placeholder from this binding (if applicable) @attachedEvents = [] # Array listing all of the events currently listened on @object @setValue = noop if @type is 'Array' or @type is 'Proxy' # ==== Properties declared later or inherited from binding interface ================================================================================= # @options = options # @transforms = genObj() # SubscriberID:transformFn mapping # @conditions = genObj() # SubscriberID:coniditionFn mapping # @valueOriginal = undefined # Value on init # @value = undefined # Will represent the actual current value of the binding/object # @property = property # The property name or array index or event callback argument # @selector = selector # The property name or array index or event callback argument # @customEventMethod = {} # Names of the event emitter/trigger methods (if applicable) # @pholderValues = {} # Placeholder value mapping # @pholderContexts = {} # Placeholder surroundings (original binding value split by the placeholder regEx) # @pholderIndexMap = {} # Placeholder occurence mapping, i.e. the placeholder name for each placeholder occurence # @placeholder = "" # The last specified placeholder to bind the value to # @descriptor = "" # Describes the type of property, i.e. 'attr:data-name' to indicate a DOMAttr type binding # @isLiveProp = Boolean # Indicates whether or not the Object/Object's propety have been modified to be a live property # @isDom = Boolean # Indicates whether or not the binding's object is a DOM object # @pollInterval = ID # The interval ID of the timer that manually polls the object's value at a set interval # @arrayBinding = Binding # Reference to the parent array binding (if exists) for an index-of-array binding (i.e. SimplyBind(array)) # @trackedChildren = [] # For Array type bindings - indicates which indicies of the array are tracked for changes (applicable when @options.trackArrayChildren) is true # @eventName = "" # The name of the event this binding is listening to (for Event type bindings) # @isEmitter = Boolean # Tracker to let us know we shouldn't handle the event update we received as it is the event this binding just emitted # @eventHandler = Function # The callback that gets triggered upon an event emittance (for Even type bindings) # @eventObject = Event # The dispatched event object (for Event type bindings) # @selfTransform = Function # The transform function that new values being set to this binding are being passed through during @setValue (if applicable) # @throttleRate = milliseconds # The rate in which the binding's subscribers will be updated only once in # @throttleTimeout = ID # The timeout ID of the delay timer to update a throttled binding # @lastUpdate = epoch timestamp # Last time the subs have been updated; used for throttle functions # @isAsync = Boolean # Indicates if this is an async binding (currently only used for Event bindings) ### ========================================================================== ### import [browserOnly] -DOMChoice_group.coffee unless @type is 'Event' or (@type is 'Func' and @parentInterface) # the second condition will prevent function subscribers from being invoked on this binding creation @value = @valueOriginal = subjectValue = @fetchDirectValue() if @type is 'ObjectProp' and not checkIf.isDefined(subjectValue) @object[@property] = subjectValue # Define the prop on the object if it non-existent if @placeholder and not @pholderValues @scanForPholders() @convertToLive() @attachEvents() # IF this is a binding to a specific index of an array then we must make this binding update the array on change if the array binding is tracking its children if @object instanceof Array and @type isnt 'Array' @arrayBinding = arrayBinding = cache.get(@object, true) if arrayBinding and arrayBinding.trackedChildren and not targetIncludes(arrayBinding.trackedChildren, @property) arrayBinding.trackedChildren.push(@property) SimplyBind(@property).of(@object).to arrayBinding.updateSelf return boundInstances[@ID] = @ import prototype.coffee