UNPKG

@danielkalen/simplybind

Version:

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

1,172 lines (1,169 loc) 37.4 kB
// Generated by CoffeeScript 1.10.0 (function() { var Binding, BindingInterface, BindingInterfacePrivate, BindingMulti, METHOD_bothWays, METHOD_chainTo, METHOD_condition, METHOD_conditionAll, METHOD_get, METHOD_of, METHOD_ofEvent, METHOD_pollEvery, METHOD_removeEvent, METHOD_set, METHOD_setOption, METHOD_stopPolling, METHOD_throttle, METHOD_transform, METHOD_transformAll, METHOD_transformSelf, METHOD_unBind, METHOD_updateSubsOnEvent, SimplyBind, applyPlaceholders, arrayIncludes, arrayMutatorMethods, boundInstances, cache, checkIf, dummyPropertyDescriptor, errors, escapeRegEx, extendState, genID, genObj, genProxiedEventInterface, genProxiedInterface, getErrSource, globalOptions, handleUpdateFromEvent, pholderRegEx, pholderRegExSplit, proto, setOptionsForBinding, setPholderRegEx, throwError, throwErrorBadArg, throwWarning; boundInstances = {}; globalOptions = { silent: false, liveProps: true, dispatchEvents: false, updateEvenIfSame: false, updateOnBind: true, mutateInherited: false, trackArrayChildren: false, simpleSelector: false, promiseTransforms: false, placeholder: ['{{', '}}'] }; arrayMutatorMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort']; dummyPropertyDescriptor = {}; genID = function() { return 'sb_' + (Math.floor((1 + Math.random()) * 1000000000000).toString(16)); }; genObj = function() { return Object.create(null); }; genProxiedInterface = function(publisher) { return function(subject, specificOptions) { return SimplyBind(subject, specificOptions, publisher); }; }; genProxiedEventInterface = function(publisher) { return function(eventName, customOutMethod, customInMethod) { return SimplyBind(0, null, publisher).ofEvent(eventName, customInMethod, customOutMethod); }; }; arrayIncludes = function(arr, item) { return arr.indexOf(item) !== -1; }; checkIf = { isDefined: function(subject) { return subject !== void 0; }, isArray: function(subject) { return subject instanceof Array; }, isObject: function(subject) { return typeof subject === 'object' && subject; }, isString: function(subject) { return typeof subject === 'string'; }, isNumber: function(subject) { return typeof subject === 'number'; }, isFunction: function(subject) { return typeof subject === 'function'; }, isBindingInterface: function(subject) { return subject instanceof BindingInterface; }, isSimpleObject: function(subject) { return checkIf.isFunction(subject) || checkIf.isArray(subject); } }; setOptionsForBinding = function(binding, newOptions) { var option, value; for (option in newOptions) { value = newOptions[option]; if (checkIf.isDefined(globalOptions[option])) { binding.options[option] = value; } } binding.makePropertyLive(); }; extendState = function(base, stateToInherit) { var i, key, len, stateMapping; stateMapping = Object.keys(stateToInherit); for (i = 0, len = stateMapping.length; i < len; i++) { key = stateMapping[i]; base[key] = stateToInherit[key]; } }; cache = { get: function(object, isSimpleObject, selector, isMultiChoice) { if (isSimpleObject) { return boundInstances[object._sb_ID]; } else { if (object._sb_map && object._sb_map[selector]) { return boundInstances[object._sb_map[selector]]; } } }, set: function(B, isSimpleObject) { var propsMap, selector; 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 }); } } } }; escapeRegEx = /[.*+?^${}()|[\]\\]/g; pholderRegEx = pholderRegExSplit = null; setPholderRegEx = function() { var end, middle, start; 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'); }; setPholderRegEx(); applyPlaceholders = function(contexts, values, indexMap) { var contextPart, i, index, len, output; output = ''; for (index = i = 0, len = contexts.length; i < len; index = ++i) { contextPart = contexts[index]; output += contextPart; if (indexMap[index]) { output += values[indexMap[index]]; } } return output; }; throwError = function(errorName) { throw new Error('SimplyBind: ' + (errors[errorName] || errorName)); }; throwWarning = function(warningName, depth) { var errSource, warn; if (!globalOptions.silent) { errSource = getErrSource(depth); warn = errors[warningName]; warn += "\n\n" + errSource; console.warn('SimplyBind: ' + warn); } }; throwErrorBadArg = function(arg) { throwError("Invalid argument/s (" + arg + ")", true); }; getErrSource = function(depth) { return ((new Error).stack || '').split('\n').slice(depth + 3).join('\n'); }; errors = { invalidParamName: "SimplyBind() and .to() only accept a function, an array, a bound object, a string, or a number.", fnOnly: "Only functions are allowed for .transform/.condition/All()", badEventArg: "Invalid argument number in .ofEvent()", emptyList: "Empty collection provided" }; SimplyBind = function(subject, options, publisher) { if ((!subject && subject !== 0) || (!checkIf.isString(subject) && !checkIf.isNumber(subject) && !checkIf.isFunction(subject) && !(subject instanceof Array))) { if (!checkIf.isBindingInterface(subject)) { throwError('invalidParamName'); } } if (checkIf.isObject(subject) && !(subject instanceof Array)) { return subject.selfClone(1); } else { return new BindingInterface(null, 0, null, subject, options, publisher); } }; Object.defineProperties(SimplyBind, { 'version': { value: '1.7.0' }, 'options': { get: function() { var clonedOptions, key, value; clonedOptions = {}; for (key in globalOptions) { value = globalOptions[key]; clonedOptions[key] = value; } return clonedOptions; } } }); SimplyBind.setOption = function(option, newValue) { if (checkIf.isDefined(globalOptions[option])) { globalOptions[option] = newValue; if (option === 'placeholder') { setPholderRegEx(); } } }; SimplyBind.setOptions = function(newOptions) { var option, value; for (option in newOptions) { value = newOptions[option]; SimplyBind.setOption(option, value); } }; SimplyBind.unBindAll = function(object, bothWays) { var boundID, prop, propMap; if (object && (checkIf.isObject(object) || checkIf.isFunction(object))) { propMap = object._sb_map; if (object._sb_ID) { boundInstances[object._sb_ID].removeAllSubs(bothWays); } if (propMap) { for (prop in propMap) { boundID = propMap[prop]; boundInstances[boundID].removeAllSubs(bothWays); } } } }; Binding = function(object, type, state) { var arrayBinding, subjectValue; extendState(this, state); this.type = type; this.object = object; this.ID = genID(); this.subs = []; this.subsOnce = genObj(); this.subsMap = genObj(); this.pubsMap = genObj(); this.subsPholders = genObj(); this.myPholders = genObj(); this.transforms = genObj(); this.conditions = genObj(); this.attachedEvents = []; /* ========================================================================== */ if (this.type === 'Event' || this.type === 'Func') { this.options.updateOnBind = false; this.options.updateEvenIfSame = true; } if (!(this.type === 'Event' || (this.type === 'Func' && this.publisherInterface))) { this.value = this.valueOriginal = subjectValue = this.fetchDirectValue(); if (this.type === 'ObjectProp' && !checkIf.isDefined(subjectValue)) { this.object[this.property] = subjectValue; } if (this.placeholder && !this.pholderValues) { this.scanForPholders(); } this.makePropertyLive(); } this.attachEvents(); if (this.object instanceof Array && this.type !== 'Array') { this.arrayBinding = arrayBinding = cache.get(this.object, true); if (arrayBinding && arrayBinding.options.trackArrayChildren && !arrayIncludes(arrayBinding.trackedChildren, this.property)) { arrayBinding.trackedChildren.push(this.property); SimplyBind(this.property).of(this.object).to(arrayBinding.updateSelf); } } return boundInstances[this.ID] = this; }; Binding.prototype = { makePropertyLive: function(force) { var _, opts, propertyDescriptor, shouldWriteLiveProp; if (this.options.liveProps) { _ = this; if (this.type === 'ObjectProp') { propertyDescriptor = Object.getOwnPropertyDescriptor(this.object, this.property) || dummyPropertyDescriptor; shouldWriteLiveProp = force || !this.isLiveProp && (propertyDescriptor.configurable || this.options.mutateInherited); if (shouldWriteLiveProp) { this.isLiveProp = true; Object.defineProperty(this.object, this.property, { configurable: true, enumerable: propertyDescriptor.enumerable, get: function() { return _.value; }, set: propertyDescriptor.set ? function(newValue) { propertyDescriptor.set(newValue); _.setValue(newValue); } : function(newValue) { _.setValue(newValue); } }); } } else if (this.type === 'Array') { if (!this.isLiveProp) { this.isLiveProp = true; arrayMutatorMethods.forEach(function(method) { return Object.defineProperty(_.value, method, { configurable: true, value: function() { var result; result = Array.prototype[method].apply(_.value, arguments); _.updateAllSubs(_); return result; } }); }); } if (this.options.trackArrayChildren && !this.trackedChildren) { this.trackedChildren = []; this.updateSelf = function() { return _.updateAllSubs(_); }; opts = { updateOnBind: false }; this.value.forEach(function(item, index) { _.trackedChildren.push('' + index); return SimplyBind(index, opts).of(_.value).to(_.updateSelf); }); } } } }, addSub: function(sub, updateOnce) { var i, len, ref, subItem; if (sub.isMulti) { ref = sub.bindings; for (i = 0, len = ref.length; i < len; i++) { subItem = ref[i]; this.addSub(subItem); } } else { if (!this.subsMap[sub.ID]) { this.subs.push(sub); this.subsMap[sub.ID] = sub; if (updateOnce) { this.subsOnce[sub.ID] = sub; } sub.pubsMap[this.ID] = this; } if (this.placeholder) { this.myPholders[sub.ID] = this.placeholder; } else if (this.myPholders[sub.ID]) { delete this.myPholders[sub.ID]; } if (sub.placeholder) { this.subsPholders[sub.ID] = sub.placeholder; } } return this; }, removeSub: function(sub, bothWays) { var i, len, ref, subItem; if (sub.isMulti) { ref = sub.bindings; for (i = 0, len = ref.length; i < len; i++) { subItem = ref[i]; this.removeSub(subItem, bothWays); } } else { if (this.subsMap[sub.ID]) { this.subs.splice(this.subs.indexOf(sub), 1); delete this.subsPholders[sub.ID]; delete this.subsMap[sub.ID]; delete sub.pubsMap[this.ID]; } if (bothWays) { sub.removeSub(this); delete this.pubsMap[sub.ID]; } } if (this.subs.length === 0 && Object.keys(this.pubsMap).length === 0) { this.destroy(); } }, removeAllSubs: function(bothWays) { var i, len, ref, sub; ref = this.subs.slice(); for (i = 0, len = ref.length; i < len; i++) { sub = ref[i]; this.removeSub(sub, bothWays); } }, destroy: function() { var event, i, j, len, len1, method, ref; delete boundInstances[this.ID]; this.removePollInterval(); if (this.type === 'Event') { ref = this.attachedEvents; for (i = 0, len = ref.length; i < len; i++) { event = ref[i]; this.unRegisterEvent(event, this.customEventMethod.remove); } delete this.object._sb_map; } else if (this.type === 'Array') { delete this.object._sb_ID; for (j = 0, len1 = arrayMutatorMethods.length; j < len1; j++) { method = arrayMutatorMethods[j]; delete this.object[method]; } } else if (this.type === 'Func') { delete this.object._sb_ID; } else { if (this.type === 'ObjectProp') { Object.defineProperty(this.object, this.property, { 'value': this.value, 'writable': true }); } delete this.object._sb_map; delete this.object._sb_ID; } }, fetchDirectValue: function() { var type; type = this.type; switch (false) { case type !== 'Func': return this.object(); case type !== 'Array': return this.object; default: return this.object[this.property]; } }, setValue: function(newValue, specificPlaceholder, publisher, fromSelf) { var isNewValue, prevValue; if (publisher == null) { publisher = this; } prevValue = specificPlaceholder ? this.pholderValues[specificPlaceholder] : this.value; if (this.selfTransform) { newValue = this.selfTransform(newValue); } isNewValue = newValue !== prevValue || this.options.updateEvenIfSame; if (isNewValue && this.type !== 'Array') { if (specificPlaceholder) { this.pholderValues[specificPlaceholder] = newValue; newValue = applyPlaceholders(this.pholderContexts, this.pholderValues, this.pholderIndexMap); } switch (this.type) { case 'ObjectProp': if (!this.isLiveProp) { this.object[this.property] = newValue; } break; case 'Func': prevValue = this.valuePassed; if (publisher.type === 'Array' && newValue === publisher.value) { newValue = newValue.slice(); } this.valuePassed = newValue; newValue = this.object(newValue, prevValue); break; case 'Event': if (!fromSelf) { this.isEmitter = true; this.emitEvent(newValue); this.isEmitter = false; } } this.value = newValue; this.updateAllSubs(publisher); } }, updateAllSubs: function(publisher) { var currentTime, i, len, ref, sub, timePassed; if (this.subs.length) { if (this.throttleRate) { currentTime = +(new Date); timePassed = currentTime - this.lastUpdate; if (timePassed < this.throttleRate) { clearTimeout(this.throttleTimeout); return this.throttleTimeout = setTimeout(((function(_this) { return function() { return _this.updateAllSubs(publisher); }; })(this)), this.throttleRate - timePassed); } else { this.lastUpdate = currentTime; } } ref = this.subs; for (i = 0, len = ref.length; i < len; i++) { sub = ref[i]; this.updateSub(sub, publisher); if (this.subsOnce[sub.ID]) { this.removeSub(sub, publisher); } } } }, updateSub: function(sub, publisher) { var currentValue, myPlaceholder, newValue, subPlaceholder, subValue; if ((publisher === sub) || (publisher !== this && publisher.subsMap[sub.ID])) { return; } myPlaceholder = this.myPholders[sub.ID]; subPlaceholder = this.subsPholders[sub.ID]; currentValue = myPlaceholder ? this.pholderValues[myPlaceholder] : this.value; subValue = subPlaceholder ? sub.pholderValues[subPlaceholder] : sub.value; newValue = !this.hasTransforms ? currentValue : this.applyTransform(sub, subPlaceholder, currentValue, subValue); if (this.hasConditions && !this.checkCondition(sub, subPlaceholder, currentValue, subValue)) { return; } if (this.options.promiseTransforms && newValue && checkIf.isFunction(newValue.then)) { newValue.then(function(newValue) { sub.setValue(newValue, subPlaceholder, publisher); }); } else { sub.setValue(newValue, subPlaceholder, publisher); } }, processTransform: function(transformFn, subjects) { var i, len, prox; if (!checkIf.isFunction(transformFn)) { return throwWarning('fnOnly', 2); } else { for (i = 0, len = subjects.length; i < len; i++) { prox = subjects[i]; prox = prox._ || prox; if (prox.isMulti) { this.processTransform(transformFn, prox.bindings); } else { this.addTransform(prox.ID, transformFn); if (this.pubsMap[prox.ID]) { prox.addTransform(this.ID, transformFn); } if (this.options.updateOnBind || this.type === 'Func') { this.updateSub(prox, this); } } } return true; } }, applyTransform: function(sub, placeholder, value, subValue) { if (this.transforms[sub.ID]) { return this.transforms[sub.ID](value, subValue); } else { return value; } }, addTransform: function(ID, transformFn) { this.hasTransforms = true; this.transforms[ID] = transformFn; }, processCondition: function(conditionFn, subjects) { var i, len, prox; if (!checkIf.isFunction(conditionFn)) { return throwWarning('fnOnly', 2); } else { for (i = 0, len = subjects.length; i < len; i++) { prox = subjects[i]; prox = prox._ || prox; if (prox.isMulti) { this.processCondition(conditionFn, prox.bindings); } else { this.addCondition(prox.ID, conditionFn); if (this.pubsMap[prox.ID]) { prox.addCondition(this.ID, conditionFn); } } } return true; } }, checkCondition: function(sub, placeholder, value, subValue) { if (this.conditions[sub.ID]) { return this.conditions[sub.ID](value, subValue); } else { return true; } }, addCondition: function(ID, conditionFn) { this.hasConditions = true; this.conditions[ID] = conditionFn; }, scanForPholders: function() { var index; this.pholderValues = genObj(); this.pholderIndexMap = genObj(); this.pholderContexts = []; if (checkIf.isString(this.valueOriginal)) { this.pholderContexts = this.valueOriginal.split(pholderRegExSplit); index = 0; this.value = this.valueOriginal.replace(pholderRegEx, (function(_this) { return function(e, pholder) { _this.pholderIndexMap[index++] = pholder; return _this.pholderValues[pholder] = pholder; }; })(this)); } }, addPollInterval: function(time) { this.removePollInterval(); return this.pollInterval = setInterval((function(_this) { return function() { var polledValue; polledValue = _this.fetchDirectValue(); return _this.setValue(polledValue); }; })(this), time); }, removePollInterval: function() { clearInterval(this.pollInterval); return this.pollInterval = null; }, attachEvents: function() { if (this.eventName) { this.registerEvent(this.eventName, this.customEventMethod["in"]); } }, registerEvent: function(eventName, customInMethod) { var attachmentMethod, defaultInMethod; if (!arrayIncludes(this.attachedEvents, eventName)) { defaultInMethod = 'on'; this.attachedEvents.push(eventName); attachmentMethod = customInMethod || defaultInMethod; this.invokeEventMethod(eventName, attachmentMethod, defaultInMethod); } }, unRegisterEvent: function(eventName, customMethod) { var defaultRemoveMethod, indexOfEvent, removalMethod; indexOfEvent = this.attachedEvents.indexOf(eventName); if (indexOfEvent === -1) { return; } defaultRemoveMethod = 'removeListener'; this.attachedEvents.splice(indexOfEvent, 1); removalMethod = customMethod || defaultRemoveMethod; this.invokeEventMethod(eventName, removalMethod, defaultRemoveMethod); }, invokeEventMethod: function(eventName, eventMethod, backupMethod) { var subject; subject = this.object; if (!subject[eventMethod]) { eventMethod = backupMethod; } if (!this.eventHandler) { this.eventHandler = handleUpdateFromEvent.bind(this); } if (typeof subject[eventMethod] === "function") { subject[eventMethod](eventName, this.eventHandler); } }, emitEvent: function(extraData) { var defaultOutMethod, emitMethod, subject; subject = this.object; defaultOutMethod = 'emit'; emitMethod = this.customEventMethod.out || defaultOutMethod; if (!subject[emitMethod]) { emitMethod = defaultOutMethod; } subject[emitMethod](this.eventName, extraData); } }; handleUpdateFromEvent = function() { var fetchedValue; if (!this.isEmitter) { fetchedValue = this.type === 'Event' ? arguments[this.property] : this.fetchDirectValue(); this.setValue(fetchedValue, null, null, true); } }; /** * Stage definitions: * * 0: Selection: Got selector, awaiting object. * 1: Indication: Got object, awaiting proxied property / function / Binding-object. * 2: Binding Complete: Complete, awaiting additional (optional) bindings/mutations. */ BindingInterface = function(binding, stage, inheritedState, subject, options, publisherInterface) { var key, newObjectType, split; if (inheritedState) { extendState(this, inheritedState); } this.stage = stage || 0; if (this.proxies == null) { this.proxies = []; } if (publisherInterface) { this.publisherInterface = publisherInterface; } switch (this.stage) { case 0: this.optionsPassed = options || (options = {}); this.options = {}; for (key in globalOptions) { this.options[key] = options[key] != null ? options[key] : globalOptions[key]; } if (checkIf.isSimpleObject(subject)) { this.isSimpleObject = true; return this.selfClone(1, subject); } else { if (checkIf.isNumber(subject)) { subject = subject.toString(); } this.selector = this.property = subject; if (!this.options.simpleSelector) { if (arrayIncludes(this.selector, ':')) { split = this.property.split(':'); this.descriptor = split[0]; this.property = split[1]; } if (arrayIncludes(this.selector, '.')) { split = this.property.split('.'); this.property = split[0]; this.placeholder = split.slice(1).join('.'); } this.selector = this.property; } } break; case 1: if (!binding) { switch (false) { case !this.hasEventName: newObjectType = 'Event'; break; case !this.isSimpleObject: newObjectType = checkIf.isFunction(subject) ? 'Func' : 'Array'; break; default: newObjectType = 'ObjectProp'; } if (this.descriptor === 'multi') { if (!subject.length) { throwError('emptyList'); } this.defineMainProps(new BindingMulti(subject, newObjectType, this)); } else { this.defineMainProps(this.createBinding(subject, newObjectType)); } if (publisherInterface = this.publisherInterface) { publisherInterface.proxies.push(this); publisherInterface._.addSub(this._, publisherInterface.updateOnce); publisherInterface.stage = 2; if (publisherInterface.updateOnce) { delete publisherInterface.updateOnce; } else if (publisherInterface._.options.updateOnBind || publisherInterface._.type === 'Func') { publisherInterface._.updateSub(this._, publisherInterface._); } return publisherInterface; } } } return this; }; BindingInterfacePrivate = { selfClone: function(newStage, subject) { return new BindingInterface(this._, newStage, this, subject); }, defineMainProps: function(binding) { this._ = binding; return Object.defineProperties(this, { 'ID': { get: function() { return binding.ID; } }, 'value': { get: function() { return binding.value; } }, 'original': { get: function() { return binding.objects || binding.object; } }, 'subscribers': { get: function() { return binding.subs.slice().map(function(sub) { return sub.object; }); } } }); }, createBinding: function(subject, newObjectType, bindingInterface) { var cachedBinding, newBinding; this.object = subject; cachedBinding = cache.get(subject, this.isSimpleObject, this.selector, this.isMultiChoice); if (cachedBinding) { return this.patchCachedBinding(cachedBinding); } else { newBinding = new Binding(subject, newObjectType, bindingInterface || this); cache.set(newBinding, this.isSimpleObject); return newBinding; } }, patchCachedBinding: function(cachedBinding) { cachedBinding.placeholder = this.placeholder; if (this.placeholder && !cachedBinding.pholderValues) { cachedBinding.valueOriginal = cachedBinding.fetchDirectValue(); cachedBinding.scanForPholders(); } if (cachedBinding.type === 'ObjectProp' && !(this.property in this.object)) { cachedBinding.makePropertyLive(true); } setOptionsForBinding(cachedBinding, this.optionsPassed); return cachedBinding; } }; BindingInterface.prototype = Object.create(BindingInterfacePrivate, { of: { get: function() { if (!this.stage) { return METHOD_of; } } }, ofEvent: { get: function() { if (!this.stage) { return METHOD_ofEvent; } } }, chainTo: { get: function() { if (this.stage) { return METHOD_chainTo; } } }, set: { get: function() { if (this.stage) { return METHOD_set; } } }, get: { get: function() { if (this.stage) { return METHOD_get; } } }, transformSelf: { get: function() { if (this.stage === 1 && this._.type !== 'Array') { return METHOD_transformSelf; } } }, transform: { get: function() { if (this.stage === 2) { return METHOD_transform; } } }, transformAll: { get: function() { if (this.stage === 2) { return METHOD_transformAll; } } }, condition: { get: function() { if (this.stage === 2) { return METHOD_condition; } } }, conditionAll: { get: function() { if (this.stage === 2) { return METHOD_conditionAll; } } }, bothWays: { get: function() { if (this.stage === 2) { return METHOD_bothWays; } } }, unBind: { get: function() { if (this.stage === 2) { return METHOD_unBind; } } }, pollEvery: { get: function() { if (this.stage === 2 && this._.type !== 'Event') { return METHOD_pollEvery; } } }, stopPolling: { get: function() { if (this.stage === 2) { return METHOD_stopPolling; } } }, updateSubsOnEvent: { get: function() { if (this.stage === 2) { return METHOD_updateSubsOnEvent; } } }, removeEvent: { get: function() { if (this.stage === 2) { return METHOD_removeEvent; } } }, throttle: { get: function() { if (this.stage) { return METHOD_throttle; } } }, setOption: { get: function() { return METHOD_setOption; } }, to: { get: function() { if (this.stage === 1) { return genProxiedInterface(this); } } }, toEvent: { get: function() { if (this.stage === 1) { return genProxiedEventInterface(this); } } }, and: { get: function() { if (this.stage === 2) { return this.selfClone(1); } } }, once: { get: function() { var interfaceToReturn; if (this.stage === 1) { interfaceToReturn = this.selfClone(1); interfaceToReturn.updateOnce = true; return interfaceToReturn; } } }, update: { get: function() { return this.set; } }, twoWay: { get: function() { return this.bothWays; } }, pipe: { get: function() { return this.chainTo; } } }); METHOD_of = function(object) { if (!(checkIf.isObject(object) || checkIf.isFunction(object))) { throwErrorBadArg(object); } if (checkIf.isBindingInterface(object)) { object = object.object; } return this.selfClone(1, object); }; METHOD_ofEvent = function(eventName, customInMethod, customOutMethod) { if (!eventName || !checkIf.isString(eventName)) { throwErrorBadArg(eventName); } else if (isNaN(parseInt(this.property))) { throwWarning('badEventArg', 1); } this.hasEventName = true; this.eventName = eventName; this.selector = this.property + '#' + this.eventName; this.customEventMethod = { 'in': customInMethod, 'out': customOutMethod }; return this; }; METHOD_chainTo = function(subject, specificOptions) { return SimplyBind(this.proxies[this.proxies.length - 1]).to(subject, specificOptions); }; METHOD_set = function(newValue) { this._.setValue(newValue, this.placeholder); return this; }; METHOD_get = function() { if (this.placeholder) { return this._.pholderValues[this.placeholder]; } else { return this._.value; } }; METHOD_transformSelf = function(transformFn) { var currentValue; if (!checkIf.isFunction(transformFn)) { throwWarning('fnOnly', 1); } else { this._.selfTransform = transformFn; if (this._.options.updateOnBind) { currentValue = this._.isMulti ? this.value[0] : this.value; this._.setValue(currentValue); } } return this; }; METHOD_transform = function(transformFn) { this._.processTransform(transformFn, this.proxies.slice(-1)); return this; }; METHOD_transformAll = function(transformFn) { this._.processTransform(transformFn, this.proxies); return this; }; METHOD_condition = function(conditionFn) { this._.processCondition(conditionFn, this.proxies.slice(-1)); return this; }; METHOD_conditionAll = function(conditionFn) { this._.processCondition(conditionFn, this.proxies); return this; }; METHOD_bothWays = function(dontOrAltTransform) { var originCondition, originTransform, proxied, proxiedBinding, transformToUse; proxied = this.proxies[this.proxies.length - 1]; proxiedBinding = proxied._.addSub(this._); originTransform = this._.transforms[proxied.ID]; originCondition = this._.conditions[proxied.ID]; if (originTransform || dontOrAltTransform) { transformToUse = checkIf.isFunction(dontOrAltTransform) ? dontOrAltTransform : originTransform; if (transformToUse && dontOrAltTransform !== false) { proxiedBinding.addTransform(this.ID, transformToUse); } } if (originCondition) { proxiedBinding.addCondition(this.ID, originCondition); } return this; }; METHOD_unBind = function(bothWays) { var i, len, proxied, ref; ref = this.proxies; for (i = 0, len = ref.length; i < len; i++) { proxied = ref[i]; this._.removeSub(proxied._, bothWays); } return this; }; METHOD_pollEvery = function(time) { this._.addPollInterval(time); return this; }; METHOD_stopPolling = function() { this._.removePollInterval(); return this; }; METHOD_updateSubsOnEvent = function(eventName, customMethod) { this._.registerEvent(eventName, customMethod); return this; }; METHOD_removeEvent = function(eventName, customMethod) { this._.unRegisterEvent(eventName, customMethod); return this; }; METHOD_throttle = function(delay) { if (delay && checkIf.isNumber(delay)) { this._.throttleRate = delay; } else if (delay === false) { delete this._.throttleRate; } return this; }; METHOD_setOption = function(optionName, newValue) { var i, len, newOptions, obj, proxied, ref; newOptions = ( obj = {}, obj["" + optionName] = newValue, obj ); setOptionsForBinding(this._, newOptions); ref = this.proxies; for (i = 0, len = ref.length; i < len; i++) { proxied = ref[i]; setOptionsForBinding(proxied._, newOptions); } return this; }; BindingMulti = function(objects, type, bindingInterface) { var bindings, i, len, object; extendState(this, bindingInterface); this.isMulti = true; this.type = type; this.bindings = bindings = []; for (i = 0, len = objects.length; i < len; i++) { object = objects[i]; bindings.push(this.createBinding(object, type, bindingInterface)); } return Object.defineProperties(this, { 'ID': { value: bindings[0].ID }, 'options': { value: bindings[0].options }, 'transforms': { value: bindings[0].transforms }, 'conditions': { value: bindings[0].conditions }, 'updateSub': { value: function(sub) { return bindings.forEach(function(binding) { return binding.updateSub(sub, binding); }); } }, 'pholderValues': { get: function() { return bindings[0].pholderValues; } }, 'value': { get: function() { return bindings.map(function(binding) { return binding.value; }); } }, 'throttleRate': { set: function(newRate) { return bindings.forEach(function(binding) { return binding.throttleRate = newRate; }); } }, 'selfTransform': { set: function(fn) { return bindings.forEach(function(binding) { return binding.selfTransform = fn; }); } } }); }; proto = BindingMulti.prototype = Object.create(BindingInterfacePrivate); Object.keys(Binding.prototype).forEach(function(methodName) { return proto[methodName] = function(a, b) { var binding, i, len, ref; ref = this.bindings; for (i = 0, len = ref.length; i < len; i++) { binding = ref[i]; binding[methodName](a, b); } }; }); return module.exports = SimplyBind; })();