UNPKG

@danielkalen/simplybind

Version:

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

1,048 lines (1,045 loc) 36.3 kB
// Generated by CoffeeScript 1.10.0 (function() { var Binding, BindingInterface, SimplyBind, applyPlaceholders, arrayMutatorMethods, boundInstances, cache, computeProxied, errRegEx, errors, escapeRegEx, genID, genObj, getErrSource, globalOptions, handleUpdateFromEvent, isBindingInterface, maybeUpdateDep, methodNames, pholderRegEx, pholderRegExSplit, setOptionsForBinding, setPholderRegEx, throwError, throwErrorBadArg, throwErrorUnavail, throwWarning; arrayMutatorMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort']; genID = function() { return 'sb_' + (Math.floor((1 + Math.random()) * 1000000000000).toString(16)); }; genObj = function() { return Object.create(null); }; isBindingInterface = function(subject) { return subject instanceof BindingInterface; }; setOptionsForBinding = function(binding, newOptions, makeLive) { var option, value; for (option in newOptions) { value = newOptions[option]; if (globalOptions[option] != null) { binding.options[option] = value; } } if (makeLive) { return binding.makePropertyLive(); } }; cache = { textNodes: {}, object: { set: function(B) { var propsMap, selector; selector = B.selector || B.property; 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, selector) { if (object._sb_map && object._sb_map[selector]) { return boundInstances[object._sb_map[selector]]; } } }, simpleObject: { set: function(B) { return Object.defineProperty(B.object, '_sb_ID', { 'configurable': true, 'value': B.ID }); }, get: function(object) { return boundInstances[object._sb_ID]; } } }; escapeRegEx = /[.*+?^${}()|[\]\\]/g; pholderRegEx = null; pholderRegExSplit = null; setPholderRegEx = function() { var end, middle, start; start = globalOptions.placeholderStart.replace(escapeRegEx, '\\$&'); end = globalOptions.placeholderEnd.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, nonTemplate) { var err, errSource; errSource = getErrSource(); err = nonTemplate ? errorName : errors[errorName]; err += "\n\nCall Source:\n" + errSource; throw new Error('SimplyBind: ' + err); }; throwWarning = function(warningName) { var errSource, warn; if (!globalOptions.silent) { errSource = getErrSource(); warn = errors[warningName]; warn += "\n\nCall Source:\n" + errSource; return console.log('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() { return (new Error).stack.split('\n').slice(3, 10).map(function(line) { return line.replace(errRegEx, function(all, extras, source) { return "@ " + source; }); }).join('\n'); }; errRegEx = /[@(?:\wat\s)](.*)\/(.+)$/; Error.prototype.stack = '\n\n\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, updateEvenIfUndefined: false, updateEvenIfSame: false, updateOnBind: true, mutateInherited: false, trackArrayChildren: false, simpleSelector: false, promiseTransforms: false, placeholderStart: '{{', placeholderEnd: '}}' }; setPholderRegEx(); SimplyBind = function(subject, options, isBeingProxied) { if ((!subject && subject !== 0) || (typeof subject !== 'string' && typeof subject !== 'number' && typeof subject !== 'function' && !(subject instanceof Array))) { if (!isBindingInterface(subject)) { throwError('invalidParamName'); } } if (typeof subject === 'object' && !(subject instanceof Array)) { return new BindingInterface(subject._, 1); } else { return new BindingInterface(null, 0, null, subject, isBeingProxied, options); } }; Binding = function(type, selector, property, object, objects, options, extraState, isBeingProxied) { var arrayBinding, key, subjectValue, value; for (key in extraState) { value = extraState[key]; this[key] = value; } this.options = options; this.type = type; this.ID = genID(); this.property = property; this.selector = selector; this.object = object; this.objects = objects; this.valueOriginal = null; this.value = null; 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') { subjectValue = this.fetchDirectValue(null, isBeingProxied); if (typeof subjectValue === 'undefined' && this.type === 'ObjectProp') { this.object[this.property] = subjectValue = null; } this.value = this.valueOriginal = subjectValue; if (this.placeholder && !this.pholderValues) { this.scanForPholders(); } } this.makePropertyLive(); this.attachEvents(); if (this.object instanceof Array && this.type !== 'Array') { this.arrayBinding = arrayBinding = cache.simpleObject.get(this.object); if (arrayBinding && arrayBinding.options.trackArrayChildren && arrayBinding.trackedChildren.indexOf(this.property) === -1) { 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(Private, stage, inheritedState, subject, isBeingProxied, options) { var key, newObjectType, object, ref, split, value; ref = inheritedState || {}; for (key in ref) { value = ref[key]; this[key] = value; } 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 (typeof subject === 'function') { Private = this.setObject(subject, 'Func', true, isBeingProxied); this.stage = 1; } else if (subject instanceof Array) { Private = this.setObject(subject, 'Array', true); this.stage = 1; } else { if (typeof subject === 'number') { subject = subject.toString(); } this.selector = this.property = subject; if (!this.options.simpleSelector) { if (this.selector.indexOf(':') !== -1) { split = this.property.split(':'); this.descriptor = split[0]; this.property = split[1]; } if (this.selector.indexOf('.') !== -1) { split = this.property.split('.'); this.property = split[0]; this.placeholder = split.slice(1).join('.'); } this.selector = this.property; } } break; case 1: if (Private) { break; } object = subject; newObjectType = (function() { switch (false) { case !this.state.hasEventName: return 'Event'; default: return 'ObjectProp'; } }).call(this); Private = this.setObject(object, newObjectType); } Object.defineProperties(this, { '_': { value: Private }, 'ID': { get: function() { return Private.ID; } }, 'value': { get: function() { return Private.value; } }, 'original': { get: function() { return Private.objects || Private.object; } }, 'dependents': { get: function() { return Private.deps.slice().map(function(dep) { return dep.object; }); } }, 'lastProxied': { get: function() { return this.proxies[this.proxies.length - 1]; } }, 'new': { value: function(stage, object) { return new BindingInterface(Private, stage, this.getState(), object, isBeingProxied); } } }); return this; }; Binding.prototype = { makePropertyLive: function(force) { var _this, opts, origGetFn, origSetFn, propertyDescriptor, ref, ref1, shouldWriteLiveProp; if (this.options.liveProps) { _this = this; if (this.type === 'ObjectProp') { propertyDescriptor = Object.getOwnPropertyDescriptor(this.object, this.property); shouldWriteLiveProp = this.options.mutateInherited || (propertyDescriptor && propertyDescriptor.configurable); if ((shouldWriteLiveProp && !this.isLiveProp) || force) { this.isLiveProp = true; origGetFn = (propertyDescriptor != null ? (ref = propertyDescriptor.get) != null ? ref.bind(this.object) : void 0 : void 0) || function() { return _this.value; }; origSetFn = (propertyDescriptor != null ? (ref1 = propertyDescriptor.set) != null ? ref1.bind(this.object) : void 0 : void 0) || function() {}; return Object.defineProperty(this.object, this.property, { configurable: true, enumerable: propertyDescriptor != null ? propertyDescriptor.enumerable : void 0, get: function() { return origGetFn(); }, set: function(newValue) { _this.setValue(newValue); return origSetFn(newValue); } }); } } else if (this.type === 'Array') { if (!this.isLiveProp) { this.isLiveProp = true; arrayMutatorMethods.forEach(function(method) { return Object.defineProperty(_this.value, method, { configurable: true, value: function() { var result; result = Array.prototype[method].apply(_this.value, arguments); _this.updateAllDeps(); return result; } }); }); } if (this.options.trackArrayChildren && !this.trackedChildren) { this.trackedChildren = []; this.updateSelf = function() { return _this.updateAllDeps(); }; opts = { updateOnBind: false }; return this.value.forEach(function(item, index) { _this.trackedChildren.push('' + index); return SimplyBind(index, opts).of(_this.value).to(_this.updateSelf); }); } } } }, addDep: function(dep, bothWays) { 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) { 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); return 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' || this.type === 'DOMText') { 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(type, isBeingProxied) { if (type == null) { type = this.type; } switch (type) { case 'Func': if (!isBeingProxied) { return this.object(); } break; case 'Array': return this.object; default: return this.object[this.property]; } }, setValue: function(newValue, specificPlaceholder, updater, fromSelf) { var currentValue, isNewValue, isValidValue, placeholderValue, prevValue; if (updater == null) { updater = this; } currentValue = specificPlaceholder ? this.pholderValues[specificPlaceholder] : this.value; if (this.selfTransform) { newValue = this.selfTransform(newValue); } isNewValue = newValue !== currentValue || this.options.updateEvenIfSame; isValidValue = typeof newValue !== 'undefined' || this.options.updateEvenIfUndefined; if ((isNewValue && isValidValue || this.isEvent) && this.type !== 'Array') { prevValue = this.value; if (specificPlaceholder) { this.pholderValues[specificPlaceholder] = placeholderValue = newValue; this.value = newValue = applyPlaceholders(this.pholderContexts, this.pholderValues, this.pholderIndexMap); } else { this.value = newValue; } switch (this.type) { case 'ObjectProp': if (!this.isLiveProp) { this.object[this.property] = newValue; } break; case 'Func': prevValue = this.valuePassed; this.valuePassed = newValue; this.value = this.object(newValue, prevValue); break; case 'Event': if (!fromSelf) { this.emitCauser = updater; this.emitEvent(newValue); this.emitCauser = null; } } if (!(fromSelf && this.emitCauser)) { this.updateAllDeps(updater); } } }, updateAllDeps: function(updater) { var dep, i, len, ref; if (this.deps.length) { if (this.throttleRate) { if (+(new Date) - this.lastUpdate < this.throttleRate) { clearTimeout(this.throttleTimeout); return this.throttleTimeout = setTimeout(((function(_this) { return function() { return _this.updateAllDeps(updater); }; })(this)), this.throttleRate); } else { this.lastUpdate = +(new Date); } } 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, isInfiniteLoop, isNewEventBinding, myPlaceholder, newValue; isNewEventBinding = this.value === null && this.type === 'Event'; isInfiniteLoop = updater && ((updater === dep) || (updater !== this && updater.depsMap[1][dep.ID])); if (isInfiniteLoop || isNewEventBinding) { return; } updater || (updater = this); myPlaceholder = this.myPholders[dep.ID]; currentValue = myPlaceholder ? this.pholderValues[myPlaceholder] : this.value; depPlaceholder = this.depsPholders[dep.ID]; depValue = depPlaceholder ? dep.pholderValues[depPlaceholder] : dep.value; newValue = currentValue; newValue = this.applyTransform(dep, depPlaceholder, currentValue, depValue); if (!this.checkCondition(dep, depPlaceholder, currentValue, depValue)) { return; } if (this.options.promiseTransforms && (newValue != null) && typeof newValue.then === 'function') { return newValue.then((function(_this) { return function(newValue) { return dep.setValue(newValue, depPlaceholder, updater); }; })(this)); } else { return dep.setValue(newValue, depPlaceholder, updater); } }, processTransform: function(transformFn, subjects) { var i, len, prox, proxID; if (typeof transformFn !== 'function') { return throwWarning('fnOnly'); } else { for (i = 0, len = subjects.length; i < len; i++) { prox = subjects[i]; proxID = prox.ID; proxID += prox.placeholder ? '.' + prox.placeholder : ''; this.addTransform(proxID, transformFn); prox = prox._; if (this.depsMap[2][prox.ID]) { prox.addTransform(this.ID, transformFn); } if (this.options.updateOnBind || this.type === 'Func') { this.updateDep(prox); } } return true; } }, applyTransform: function(dep, placeholder, value, depValue) { var depID; if (!this.hasTransforms) { return value; } else { 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 (typeof conditionFn !== 'function') { return throwWarning('fnOnly'); } else { for (i = 0, len = subjects.length; i < len; i++) { prox = subjects[i]; proxID = prox.ID; proxID += prox.placeholder ? '.' + prox.placeholder : ''; this.addCondition(proxID, conditionFn); prox = prox._; if (this.depsMap[2][prox.ID]) { prox.addCondition(this.ID, conditionFn); } } return true; } }, checkCondition: function(dep, placeholder, value, depValue) { var depID; if (!this.hasConditions) { return true; } else { 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 (typeof this.valueOriginal === 'string') { 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.type === 'Event') { return this.registerEvent(this.eventName, this.customEventMethod["in"]); } }, registerEvent: function(eventName, customInMethod) { var attachmentMethod, defaultInMethod; if (this.attachedEvents.indexOf(eventName) !== -1) { 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; fetchedValue = this.type === 'Event' ? arguments[this.property] : this.fetchDirectValue(); return this.setValue(fetchedValue, null, this.emitCauser, true); }; BindingInterface.prototype = { of: function(object) { var proxied; if (this.stage !== 0 && this.stage !== 2) { throwErrorUnavail(methodNames[0]); } if (!((typeof object === 'object') || (typeof object === 'function'))) { throwErrorBadArg(methodNames[0], object); } if (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 || typeof eventName !== 'string') { throwErrorBadArg(methodNames[1], eventName); } else if (isNaN(parseInt(this.property))) { throwWarning('badEventArg'); } 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) { if (this.stage !== 1 || this.stage === 1 && this._.type === 'Array') { throwErrorUnavail(methodNames[8]); } if (typeof transformFn !== 'function') { throwWarning('fnOnly'); } else { this._.selfTransform = transformFn; if (this._.options.updateOnBind) { this.set(this.value); } } 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 boundProxied, originCondition, originTransform, proxied, transformToUse; if (this.stage !== 3 || this.state.hasMultiTransform) { throwErrorUnavail(methodNames[13]); } proxied = this.lastProxied; boundProxied = proxied._.addDep(this._, true); originTransform = this._.transforms[proxied.ID]; originCondition = this._.conditions[proxied.ID]; if (originTransform || dontOrAltTransform) { transformToUse = typeof dontOrAltTransform === 'function' ? dontOrAltTransform : originTransform; if (transformToUse && dontOrAltTransform !== false) { boundProxied.addTransform(this.ID, transformToUse); } } if (originCondition) { boundProxied.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 (typeof delay === 'number' && 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, true); ref = this.proxies; for (i = 0, len = ref.length; i < len; i++) { proxied = ref[i]; setOptionsForBinding(proxied._, newOptions, true); } return this; } }; BindingInterface.prototype.update = BindingInterface.prototype.set; BindingInterface.prototype.twoWay = BindingInterface.prototype.bothWays; BindingInterface.prototype.pipe = BindingInterface.prototype.chainTo; methodNames = Object.keys(BindingInterface.prototype); 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); } }; Object.defineProperties(BindingInterface.prototype, { setObject: { value: function(object, newObjectType, isSimpleObject, isBeingProxied) { var cacheObjectType, extraState, fromCache, newPrivate; this.object = object; cacheObjectType = isSimpleObject ? 'simpleObject' : 'object'; fromCache = cache[cacheObjectType].get(object, this.selector); if (fromCache) { fromCache.placeholder = this.placeholder; if (this.placeholder && !fromCache.pholderValues) { fromCache.valueOriginal = fromCache.fetchDirectValue(); fromCache.scanForPholders(); } if (fromCache.type === 'ObjectProp' && !(this.property in object)) { fromCache.makePropertyLive(true); } setOptionsForBinding(fromCache, this.options, true); return fromCache; } else { extraState = { isDom: this.isDom, isDomInput: this.isDomInput, placeholder: this.placeholder, eventName: this.eventName, customEventMethod: this.customEventMethod, isEvent: this.state.hasEventName }; newPrivate = new Binding(newObjectType, this.selector, this.property, this.object, this.objects, this.options, extraState, isBeingProxied); cache[cacheObjectType].set(newPrivate); return newPrivate; } } }, getState: { value: function() { return { options: this.options, selector: this.selector, object: this.object, property: this.property, descriptor: this.descriptor, placeholder: this.placeholder, eventName: this.eventName, customEventMethod: this.customEventMethod, proxied: this.proxied, proxies: this.proxies, state: this.state }; } } }); Object.defineProperties(SimplyBind, { 'version': { value: '1.2.1' }, '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 (globalOptions[option] != null) { globalOptions[option] = newValue; if (option.indexOf('place') !== -1) { 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 && ((typeof object === 'object') || (typeof object === 'function'))) { 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; })();