UNPKG

@danielkalen/simplybind

Version:

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

1,109 lines (1,106 loc) 38 kB
// Generated by CoffeeScript 1.10.0 (function() { var Binding, BindingInterface, BindingInterfacePrivate, BindingInterfacePublic, BindingMulti, SimplyBind, applyPlaceholders, arrayIncludes, arrayMutatorMethods, boundInstances, cache, checkIf, computeProxied, dummyPropertyDescriptor, errors, escapeRegEx, extendState, genID, genObj, getErrSource, globalOptions, handleUpdateFromEvent, i, len, maybeUpdateDep, methodName, methodNames, pholderRegEx, pholderRegExSplit, proto, setOptionsForBinding, setPholderRegEx, throwError, throwErrorBadArg, throwErrorUnavail, throwWarning; 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); }; arrayIncludes = function(arr, item) { return arr.indexOf(item) !== -1; }; checkIf = { isDefined: function(subject) { return subject !== void 0; }, 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; } }; setOptionsForBinding = function(binding, newOptions) { var option, value; for (option in newOptions) { value = newOptions[option]; if (checkIf.isDefined(globalOptions[option])) { binding.options[option] = value; } } return 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 = { set: function(B, isSimpleObject) { var propsMap, selector; if (isSimpleObject) { return Object.defineProperty(B.object, '_sb_ID', { 'configurable': true, 'value': B.ID }); } else { selector = B.selector; if (B.object._sb_map) { return B.object._sb_map[selector] = B.ID; } else { propsMap = {}; propsMap[selector] = B.ID; return Object.defineProperty(B.object, '_sb_map', { 'configurable': true, 'value': propsMap }); } } }, 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]]; } } } }; 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'); return pholderRegExSplit = new RegExp("" + start + middle + end, 'g'); }; 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; return console.warn('SimplyBind: ' + warn); } }; throwErrorUnavail = function(methodName) { return throwError("You can't use/invoke ." + methodName + "() at this stage", true); }; throwErrorBadArg = function(methodName, arg) { return throwError("Invalid argument/s (" + arg + ") passed to ." + methodName + "()", 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()" }; boundInstances = {}; globalOptions = { silent: false, liveProps: true, dispatchEvents: false, updateEvenIfSame: false, updateOnBind: true, mutateInherited: false, trackArrayChildren: false, simpleSelector: false, promiseTransforms: false, placeholder: ['{{', '}}'] }; setPholderRegEx(); SimplyBind = function(subject, options, isProxiedFunc) { 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 new BindingInterface(subject._, 1); } else { return new BindingInterface(null, 0, null, subject, isProxiedFunc, options); } }; Binding = function(object, type, state, isProxiedFunc) { var arrayBinding, subjectValue; extendState(this, state); this.type = type; this.object = object; this.ID = genID(); this.deps = []; this.depsMap = { 1: genObj(), 2: genObj() }; this.depsPholders = 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' || isProxiedFunc)) { 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; }; /** * Stage definitions: * * 0: Selection: Got selector, awaiting object. * 1: Indication: Got object, awaiting proxied property / function / Binding-object. * 2: Binding Selection: Got proxied selector, awaiting proxied object. * 3: Binding Complete: Complete, awaiting additional (optional) bindings/mutations. */ BindingInterface = function(binding, stage, inheritedState, subject, isProxiedFunc, options) { var key, newObjectType, split; if (inheritedState) { extendState(this, inheritedState); } this.stage = stage || 0; if (this.proxies == null) { this.proxies = []; } if (this.state == null) { this.state = {}; } 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.isFunction(subject)) { this.stage = 1; binding = this.createBinding(subject, 'Func', true, isProxiedFunc); } else if (subject instanceof Array) { this.stage = 1; binding = this.createBinding(subject, 'Array', true); } 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) { newObjectType = (function() { switch (false) { case !this.state.hasEventName: return 'Event'; default: return 'ObjectProp'; } }).call(this); if (this.descriptor === 'multi') { binding = new BindingMulti(subject, newObjectType, this); } else { binding = this.createBinding(subject, newObjectType); } } } return this.defineMainProps(binding); }; 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; return Object.defineProperty(this.object, this.property, { configurable: true, enumerable: propertyDescriptor.enumerable, get: propertyDescriptor.get || function() { return _.value; }, set: propertyDescriptor.set ? function(newValue) { _.setValue(newValue); propertyDescriptor.set(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); _.updateAllDeps(_); return result; } }); }); } if (this.options.trackArrayChildren && !this.trackedChildren) { this.trackedChildren = []; this.updateSelf = function() { return _.updateAllDeps(_); }; opts = { updateOnBind: false }; return this.value.forEach(function(item, index) { _.trackedChildren.push('' + index); return SimplyBind(index, opts).of(_.value).to(_.updateSelf); }); } } } }, addDep: function(dep, bothWays) { var depItem, i, len, ref; if (dep.isMulti) { ref = dep.bindings; for (i = 0, len = ref.length; i < len; i++) { depItem = ref[i]; this.addDep(depItem); } } else { if (!this.depsMap[1][dep.ID]) { this.depsMap[1][dep.ID] = dep; this.deps.push(dep); } if (this.placeholder) { this.myPholders[dep.ID] = this.placeholder; } else if (this.myPholders[dep.ID]) { delete this.myPholders[dep.ID]; } if (dep.placeholder) { this.depsPholders[dep.ID] = dep.placeholder; } if (bothWays) { this.depsMap[2][dep.ID] = dep; } else if (dep.depsMap[1][this.ID]) { dep.addDep(this, true); this.addDep(dep, true); } } return this; }, removeDep: function(dep, bothWays) { var depItem, i, len, ref; if (dep.isMulti) { ref = dep.bindings; for (i = 0, len = ref.length; i < len; i++) { depItem = ref[i]; this.removeDep(depItem, bothWays); } } else { if (this.depsMap[1][dep.ID]) { this.deps.splice(this.deps.indexOf(dep), 1); delete this.depsMap[1][dep.ID]; delete this.depsPholders[dep.ID]; } if (bothWays) { dep.removeDep(this); delete this.depsMap[2][dep.ID]; } } }, removeAllDeps: function(bothWays) { var dep, i, len, ref; ref = this.deps.slice(); for (i = 0, len = ref.length; i < len; i++) { dep = ref[i]; this.removeDep(dep, bothWays); } if (bothWays || Object.keys(this.depsMap[2]).length === 0) { return this.destroy(); } }, destroy: function() { var event, i, j, len, len1, method, ref; delete boundInstances[this.ID]; 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; } else 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; } }, 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, updater, fromSelf) { var isNewValue, prevValue; if (updater == null) { updater = 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; 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.updateAllDeps(updater); } }, updateAllDeps: function(updater) { var currentTime, dep, i, len, ref, timePassed; if (this.deps.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.updateAllDeps(updater); }; })(this)), this.throttleRate - timePassed); } else { this.lastUpdate = currentTime; } } ref = this.deps; for (i = 0, len = ref.length; i < len; i++) { dep = ref[i]; this.updateDep(dep, updater); } } }, updateDep: function(dep, updater) { var currentValue, depPlaceholder, depValue, myPlaceholder, newValue; if ((updater === dep) || (updater !== this && updater.depsMap[1][dep.ID])) { return; } myPlaceholder = this.myPholders[dep.ID]; depPlaceholder = this.depsPholders[dep.ID]; currentValue = myPlaceholder ? this.pholderValues[myPlaceholder] : this.value; depValue = depPlaceholder ? dep.pholderValues[depPlaceholder] : dep.value; newValue = !this.hasTransforms ? currentValue : this.applyTransform(dep, depPlaceholder, currentValue, depValue); if (this.hasConditions && !this.checkCondition(dep, depPlaceholder, currentValue, depValue)) { return; } if (this.options.promiseTransforms && newValue && checkIf.isFunction(newValue.then)) { newValue.then((function(_this) { return function(newValue) { return dep.setValue(newValue, depPlaceholder, updater); }; })(this)); } else { dep.setValue(newValue, depPlaceholder, updater); } }, processTransform: function(transformFn, subjects) { var i, len, prox, proxID; 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 { proxID = prox.ID; proxID += prox.placeholder ? '.' + prox.placeholder : ''; this.addTransform(proxID, transformFn); if (this.depsMap[2][prox.ID]) { prox.addTransform(this.ID, transformFn); } if (this.options.updateOnBind || this.type === 'Func') { this.updateDep(prox, this); } } } return true; } }, applyTransform: function(dep, placeholder, value, depValue) { var depID; depID = dep.ID; if (placeholder) { depID += '.' + placeholder; } if (this.transforms[depID]) { return this.transforms[depID](value, depValue); } else { return value; } }, addTransform: function(ID, transformFn) { this.hasTransforms = true; return this.transforms[ID] = transformFn; }, processCondition: function(conditionFn, subjects) { var i, len, prox, proxID; 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 { proxID = prox.ID; proxID += prox.placeholder ? '.' + prox.placeholder : ''; this.addCondition(proxID, conditionFn); if (this.depsMap[2][prox.ID]) { prox.addCondition(this.ID, conditionFn); } } } return true; } }, checkCondition: function(dep, placeholder, value, depValue) { var depID; depID = dep.ID; if (placeholder) { depID += '.' + placeholder; } if (this.conditions[depID]) { return this.conditions[depID](value, depValue); } else { return true; } }, addCondition: function(ID, conditionFn) { this.hasConditions = true; return 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; return 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) { return this.registerEvent(this.eventName, this.customEventMethod["in"]); } }, registerEvent: function(eventName, customInMethod) { var attachmentMethod, defaultInMethod; if (arrayIncludes(this.attachedEvents, eventName)) { return; } defaultInMethod = 'on'; this.attachedEvents.push(eventName); attachmentMethod = customInMethod || defaultInMethod; return 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; return 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); } return typeof subject[eventMethod] === "function" ? subject[eventMethod](eventName, this.eventHandler) : void 0; }, emitEvent: function(extraData) { var defaultOutMethod, emitMethod, subject; subject = this.object; defaultOutMethod = 'emit'; emitMethod = this.customEventMethod.out || defaultOutMethod; if (!subject[emitMethod]) { emitMethod = defaultOutMethod; } return subject[emitMethod](this.eventName, extraData); } }; handleUpdateFromEvent = function() { var fetchedValue; if (!this.isEmitter) { fetchedValue = this.type === 'Event' ? arguments[this.property] : this.fetchDirectValue(); return this.setValue(fetchedValue, null, null, true); } }; BindingInterfacePrivate = { "new": function(stage, object) { return new BindingInterface(this._, stage, this, object); }, 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; } }, 'dependents': { get: function() { return binding.deps.slice().map(function(dep) { return dep.object; }); } }, 'lastProxied': { get: function() { return this.proxies[this.proxies.length - 1]; } } }); }, createBinding: function(subject, newObjectType, isSimpleObject, isProxiedFunc, bindingInterface) { var cachedBinding, newBinding; this.object = subject; cachedBinding = cache.get(subject, isSimpleObject, this.selector, this.isMultiChoice); if (cachedBinding) { return this.patchCachedBinding(cachedBinding); } else { newBinding = new Binding(subject, newObjectType, bindingInterface || this, isProxiedFunc); cache.set(newBinding, 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); BindingInterfacePublic = { of: function(object) { var proxied; if (this.stage !== 0 && this.stage !== 2) { throwErrorUnavail(methodNames[0]); } if (!(checkIf.isObject(object) || checkIf.isFunction(object))) { throwErrorBadArg(methodNames[0], object); } if (checkIf.isBindingInterface(object)) { object = object.object; } if (this.stage === 2) { this.proxies[this.proxies.length - 1] = proxied = this.lastProxied.of(object); this.state.hasInitialBinding = true; this.state.hasTransform = false; this._.addDep(proxied._); maybeUpdateDep(this._, proxied._); } return this["new"](this.stage + 1, object); }, ofEvent: function(eventName, customInMethod, customOutMethod) { if (this.stage !== 0 || this.state.hasEventName) { throwErrorUnavail(methodNames[1]); } else if (!eventName || !checkIf.isString(eventName)) { throwErrorBadArg(methodNames[1], eventName); } else if (isNaN(parseInt(this.property))) { throwWarning('badEventArg', 1); } this.state.hasEventName = true; this.eventName = eventName; this.selector = this.property + '#' + this.eventName; this.customEventMethod = { 'in': customInMethod, 'out': customOutMethod }; return this; }, to: function(subject, specificOptions) { var newStage, proxied; if (this.stage !== 1 || this.state.hasInitialBinding) { throwErrorUnavail(methodNames[2]); } this.proxies.push(proxied = computeProxied(this, subject, specificOptions)); if (proxied.stage === 0) { newStage = 2; } else { newStage = 3; this.state.hasInitialBinding = true; } return this["new"](newStage); }, and: function(subject, specificOptions) { var newStage, proxied; if (this.stage !== 3 || !this.state.hasInitialBinding || this.state.hasMultiTransform) { throwErrorUnavail(methodNames[3]); } this.proxies.push(proxied = computeProxied(this, subject, specificOptions)); if (proxied.stage === 0) { newStage = 2; } else { newStage = 3; this.state.hasTransform = false; } return this["new"](newStage); }, toEvent: function(eventName, customOutMethod, customInMethod, specificOptions) { if (this.stage !== 1) { throwErrorUnavail(methodNames[4]); } this.proxies.push(SimplyBind(0, specificOptions).ofEvent(eventName, customInMethod, customOutMethod)); return this["new"](2); }, chainTo: function(subject, specificOptions) { if (this.stage !== 3) { throwErrorUnavail(methodNames[5]); } return SimplyBind(this.lastProxied).to(subject, specificOptions); }, set: function(newValue) { if (this.stage === 0 || this.stage === 2) { throwErrorUnavail(methodNames[6]); } this._.setValue(newValue, this.placeholder); return this; }, get: function() { if (this.stage === 0 || this.stage === 2) { throwErrorUnavail(methodNames[7]); } if (this.placeholder) { return this._.pholderValues[this.placeholder]; } else { return this._.value; } }, transformSelf: function(transformFn) { var currentValue; if (this.stage !== 1 || this.stage === 1 && this._.type === 'Array') { throwErrorUnavail(methodNames[8]); } 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; }, transform: function(transformFn) { if (this.stage !== 3 || this.state.hasTransform || this.state.hasMultiTransform) { throwErrorUnavail(methodNames[9]); } this.state.hasTransform = this._.processTransform(transformFn, this.proxies.slice(-1)) || false; return this["new"](3); }, transformAll: function(transformFn) { if (this.stage !== 3 || this.state.hasTransform || this.state.hasMultiTransform) { throwErrorUnavail(methodNames[10]); } this.state.hasMultiTransform = this._.processTransform(transformFn, this.proxies) || false; return this["new"](3); }, condition: function(conditionFn) { if (this.stage !== 3) { throwErrorUnavail(methodNames[11]); } this._.processCondition(conditionFn, this.proxies.slice(-1)); return this["new"](3); }, conditionAll: function(conditionFn) { if (this.stage !== 3) { throwErrorUnavail(methodNames[12]); } this._.processCondition(conditionFn, this.proxies); return this["new"](3); }, bothWays: function(dontOrAltTransform) { var originCondition, originTransform, proxied, proxiedBinding, transformToUse; if (this.stage !== 3 || this.state.hasMultiTransform) { throwErrorUnavail(methodNames[13]); } proxied = this.lastProxied; proxiedBinding = proxied._.addDep(this._, true); 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); } this._.addDep(proxied._, true); return this; }, unBind: function(bothWays) { var i, len, proxied, ref; if (this.stage !== 3) { throwErrorUnavail(methodNames[14]); } ref = this.proxies; for (i = 0, len = ref.length; i < len; i++) { proxied = ref[i]; this._.removeDep(proxied._, bothWays); } return this; }, pollEvery: function(time) { if (this.stage !== 3 || this._.type === 'Event') { throwErrorUnavail(methodNames[15]); } this._.addPollInterval(time); return this; }, stopPolling: function() { if (this.stage !== 3) { throwErrorUnavail(methodNames[16]); } this._.removePollInterval(); return this; }, updateDepsOnEvent: function(eventName, customMethod) { if (this.stage !== 3) { throwErrorUnavail(methodNames[17]); } this._.registerEvent(eventName, customMethod); return this; }, removeEvent: function(eventName, customMethod) { if (this.stage !== 3) { throwErrorUnavail(methodNames[18]); } this._.unRegisterEvent(eventName, customMethod); return this; }, throttle: function(delay) { if (this.stage !== 1 && this.stage !== 3) { throwErrorUnavail(methodNames[19]); } if (delay && checkIf.isNumber(delay)) { this._.throttleRate = delay; } else if (delay === false) { delete this._.throttleRate; } return this; }, 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; } }; BindingInterfacePublic.update = BindingInterfacePublic.set; BindingInterfacePublic.twoWay = BindingInterfacePublic.bothWays; BindingInterfacePublic.pipe = BindingInterfacePublic.chainTo; methodNames = Object.keys(BindingInterfacePublic); for (i = 0, len = methodNames.length; i < len; i++) { methodName = methodNames[i]; BindingInterface.prototype[methodName] = BindingInterfacePublic[methodName]; } computeProxied = function(instance, subject, specificOptions) { var proxied; if (specificOptions == null) { specificOptions = {}; } proxied = SimplyBind(subject, specificOptions, true); if (proxied.stage !== 0) { instance._.addDep(proxied._, instance); maybeUpdateDep(instance._, proxied._); } return proxied; }; maybeUpdateDep = function(instance, proxied) { if (instance.options.updateOnBind || instance.type === 'Func') { return instance.updateDep(proxied, instance); } }; BindingMulti = function(objects, type, bindingInterface) { var bindings, j, len1, object; extendState(this, bindingInterface); this.isMulti = true; this.type = type; this.bindings = bindings = []; for (j = 0, len1 = objects.length; j < len1; j++) { object = objects[j]; bindings.push(this.createBinding(object, type, null, null, 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 }, 'updateDep': { value: function(dep) { return bindings.forEach(function(binding) { return binding.updateDep(dep, 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, j, len1, ref; ref = this.bindings; for (j = 0, len1 = ref.length; j < len1; j++) { binding = ref[j]; binding[methodName](a, b); } }; }); Object.defineProperties(SimplyBind, { 'version': { value: '1.5.3' }, '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') { return 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].removeAllDeps(bothWays); } if (propMap) { for (prop in propMap) { boundID = propMap[prop]; boundInstances[boundID].removeAllDeps(bothWays); } } } }; return module.exports = SimplyBind; })();