UNPKG

@danielkalen/simplybind

Version:

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

1,168 lines (1,164 loc) 38.8 kB
// Generated by CoffeeScript 1.10.0 (function() { var Binding, BindingInterface, BindingInterfacePrivate, GroupBinding, METHOD_bothWays, METHOD_chainTo, METHOD_condition, METHOD_conditionAll, METHOD_of, METHOD_pollEvery, METHOD_set, METHOD_setOption, METHOD_stopPolling, METHOD_transform, METHOD_transformAll, METHOD_transformSelf, METHOD_unBind, SimplyBind, applyPlaceholders, arrayMutatorMethods, boundInstances, cache, checkIf, cloneObject, convertToLive, convertToReg, currentID, defaultOptions, defineProperty, dummyPropertyDescriptor, errors, escapeRegEx, eventUpdateHandler, extendState, fetchDescriptor, genID, genObj, genProxiedInterface, genSelfUpdater, getDescriptor, getErrSource, pholderRegEx, pholderRegExSplit, placeholder, proto, setPholderRegEx, setValueNoop, settings, targetIncludes, throwError, throwErrorBadArg, throwWarning; currentID = 0; arrayMutatorMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort']; dummyPropertyDescriptor = {}; boundInstances = {}; placeholder = ['{{', '}}']; settings = Object.create({ silent: false }, { placeholder: { get: function() { return placeholder; }, set: function(newPlaceholder) { if (checkIf.isArray(newPlaceholder) && newPlaceholder.length === 2) { placeholder = newPlaceholder; setPholderRegEx(); } } } }); defaultOptions = { delay: false, throttle: false, simpleSelector: false, promiseTransforms: false, dispatchEvents: false, sendArrayCopies: false, updateEvenIfSame: false, updateOnBind: true }; defineProperty = Object.defineProperty; getDescriptor = Object.getOwnPropertyDescriptor; setValueNoop = function(v, publisher) { return this.updateAllSubs(publisher || this); }; genID = function() { return '' + (++currentID); }; genObj = function() { return Object.create(null); }; genProxiedInterface = function(isSub, completeCallback) { return function(subject, customOptions, saveOptions) { return SimplyBind(subject, customOptions, saveOptions, isSub, completeCallback); }; }; genSelfUpdater = function(binding, fetchValue) { return binding.selfUpdater || (binding.selfUpdater = new Binding(function() { if (fetchValue) { return binding.setValue(binding.fetchDirectValue(), binding, true); } else { return binding.updateAllSubs(binding); } }, 'Func', {})); }; targetIncludes = function(target, item) { return target && target.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; } }; fetchDescriptor = function(object, property, isProto) { var descriptor, objectProto; descriptor = getDescriptor(object, property); if (descriptor) { if (isProto) { descriptor.configurable = true; } return descriptor; } else if (objectProto = Object.getPrototypeOf(object)) { return fetchDescriptor(objectProto, property, true); } }; convertToLive = function(bindingInstance, object, onlyArrayMethods) { var _, context, getterValue, origFn, propertyDescriptor, proxyFn, shouldIndicateUpdateIsFromSelf, shouldWriteLiveProp, slice, typeIsArray; _ = bindingInstance; if (!_.origDescriptor) { _.origDescriptor = fetchDescriptor(object, _.property); } if (onlyArrayMethods) { arrayMutatorMethods.forEach(function(method) { return defineProperty(object, method, { configurable: true, value: function() { var result; result = Array.prototype[method].apply(object, arguments); _.updateAllSubs(_); return result; } }); }); } else { if (_.type === 'Proxy') { origFn = _.origFn = _.value; context = object; _.value = { result: null, args: null }; if (checkIf.isFunction(origFn)) { slice = [].slice; getterValue = proxyFn = function() { var args, result; args = slice.call(arguments); _.value.args = args = _.selfTransform ? _.selfTransform(args) : args; _.value.result = result = origFn.apply(context, args); _.updateAllSubs(_); return result; }; defineProperty(object, _.property, { configurable: _.isLiveProp = true, get: function() { return getterValue; }, set: function(newValue) { if (!checkIf.isFunction(newValue)) { getterValue = newValue; } else if (newValue !== origFn) { if (newValue !== proxyFn) { origFn = _.origFn = newValue; } if (getterValue !== proxyFn) { getterValue = proxyFn; } } } }); } } else { propertyDescriptor = _.origDescriptor || dummyPropertyDescriptor; if (propertyDescriptor.get) { _.origGetter = propertyDescriptor.get.bind(object); } if (propertyDescriptor.set) { _.origSetter = propertyDescriptor.set.bind(object); } shouldWriteLiveProp = propertyDescriptor.configurable; if (shouldWriteLiveProp) { typeIsArray = _.type === 'Array'; shouldIndicateUpdateIsFromSelf = !_.origSetter && !typeIsArray; defineProperty(object, _.property, { configurable: _.isLiveProp = true, enumerable: propertyDescriptor.enumerable, get: _.origGetter || function() { return _.value; }, set: function(newValue) { _.setValue(newValue, _, shouldIndicateUpdateIsFromSelf); } }); if (typeIsArray) { convertToLive(_, object[_.property], true); } } } } }; convertToReg = function(bindingInstance, object, onlyArrayMethods) { var _, j, len, method, newDescriptor, results; if (onlyArrayMethods) { results = []; for (j = 0, len = arrayMutatorMethods.length; j < len; j++) { method = arrayMutatorMethods[j]; results.push(delete object[method]); } return results; } else { _ = bindingInstance; newDescriptor = _.origDescriptor; if (!(newDescriptor.set || newDescriptor.get)) { newDescriptor.value = _.origFn || _.value; } return defineProperty(object, _.property, newDescriptor); } }; cloneObject = function(object) { var clone, key; clone = genObj(); for (key in object) { clone[key] = object[key]; } return clone; }; extendState = function(base, stateToInherit) { var j, key, len, stateMapping; stateMapping = Object.keys(stateToInherit); for (j = 0, len = stateMapping.length; j < len; j++) { key = stateMapping[j]; base[key] = stateToInherit[key]; } }; cache = { get: function(object, isFunction, selector, isMultiChoice) { if (isFunction) { return boundInstances[object._sb_ID]; } else { if (object._sb_map && object._sb_map[selector]) { return boundInstances[object._sb_map[selector]]; } } }, set: function(B, isFunction) { var propsMap, selector; if (isFunction) { 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; defineProperty(B.object, '_sb_map', { 'configurable': true, 'value': propsMap }); } } } }; escapeRegEx = /[.*+?^${}()|[\]\\]/g; pholderRegEx = pholderRegExSplit = null; setPholderRegEx = function() { var end, middle, start; start = settings.placeholder[0].replace(escapeRegEx, '\\$&'); end = settings.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, index, j, len, output; output = ''; for (index = j = 0, len = contexts.length; j < len; index = ++j) { 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 (!settings.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, saveOptions, isSub, completeCallback) { var interfaceToReturn, newInterface; 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)) { interfaceToReturn = completeCallback ? completeCallback(subject) : subject.selfClone(); } else { newInterface = new BindingInterface(options); newInterface.saveOptions = saveOptions; newInterface.isSub = isSub; newInterface.completeCallback = completeCallback; if (checkIf.isFunction(subject)) { interfaceToReturn = newInterface.setObject(subject, true); } else { interfaceToReturn = newInterface.setProperty(subject); } } return interfaceToReturn; }; SimplyBind.version = '1.14.2'; SimplyBind.settings = settings; SimplyBind.defaultOptions = defaultOptions; 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 parentBinding, parentProperty, subjectValue; extendState(this, state); this.optionsDefault = this.saveOptions ? this.options : defaultOptions; this.type = type; this.object = object; this.ID = genID(); this.subs = []; this.subsMeta = genObj(); this.pubsMap = genObj(); this.attachedEvents = []; if (this.type === 'Proxy') { this.setValue = setValueNoop; } /* ========================================================================== */ if (!(this.type === 'Event' || (this.type === 'Func' && this.isSub))) { if (this.type === 'Pholder') { parentProperty = this.property; parentBinding = this.parentBinding = SimplyBind(parentProperty).of(object)._; parentBinding.scanForPholders(); this.value = parentBinding.pholderValues[this.pholder]; } else { this.value = subjectValue = this.fetchDirectValue(); if (this.type === 'ObjectProp' && !checkIf.isDefined(subjectValue)) { this.object[this.property] = subjectValue; } convertToLive(this, this.object); } } this.attachEvents(); return boundInstances[this.ID] = this; }; Binding.prototype = { addSub: function(sub, options, updateOnce, updateEvenIfSame) { var alreadyHadSub, j, len, metaData, ref, subItem; if (sub.isMulti) { ref = sub.bindings; for (j = 0, len = ref.length; j < len; j++) { subItem = ref[j]; this.addSub(subItem, options, updateOnce, updateEvenIfSame); } } else { if (metaData = this.subsMeta[sub.ID]) { alreadyHadSub = true; } else { sub.pubsMap[this.ID] = this; this.subs.unshift(sub); metaData = this.subsMeta[sub.ID] = genObj(); metaData.updateOnce = updateOnce; metaData.opts = cloneObject(options); if (updateEvenIfSame || this.type === 'Event' || this.type === 'Proxy' || this.type === 'Array') { metaData.opts.updateEvenIfSame = true; } metaData.valueRef = sub.type === 'Func' ? 'valuePassed' : 'value'; } } return alreadyHadSub; }, removeSub: function(sub, bothWays) { var j, len, ref, subItem; if (sub.isMulti) { ref = sub.bindings; for (j = 0, len = ref.length; j < len; j++) { subItem = ref[j]; this.removeSub(subItem, bothWays); } } else { if (this.subsMeta[sub.ID]) { this.subs.splice(this.subs.indexOf(sub), 1); delete this.subsMeta[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 j, len, ref, sub; ref = this.subs.slice(); for (j = 0, len = ref.length; j < len; j++) { sub = ref[j]; this.removeSub(sub, bothWays); } }, destroy: function() { var event, j, len, ref; delete boundInstances[this.ID]; this.removePollInterval(); if (this.type === 'Event') { ref = this.attachedEvents; for (j = 0, len = ref.length; j < len; j++) { event = ref[j]; this.unRegisterEvent(event, this.customEventMethod.listen); } } else if (this.type === 'Func') { delete this.object._sb_ID; } /* istanbul ignore next */ if (this.isLiveProp && this.origDescriptor) { convertToReg(this, this.object); } if (this.type === 'Array') { convertToReg(this, this.value, true); } if (this.object._sb_map) { delete this.object._sb_map[this.selector]; if (Object.keys(this.object._sb_map).length === 0) { delete this.object._sb_map; } } }, fetchDirectValue: function() { var type; type = this.type; switch (false) { case type !== 'Func': return this.object(); default: return this.object[this.property]; } }, setValue: function(newValue, publisher, fromSelf, fromChangeEvent) { var entireValue, parent, prevValue; publisher || (publisher = this); if (this.selfTransform) { newValue = this.selfTransform(newValue); } if (!fromSelf) { switch (this.type) { case 'ObjectProp': if (!this.isLiveProp) { if (newValue !== this.value) { this.object[this.property] = newValue; } } else if (this.origSetter) { this.origSetter(newValue); } break; case 'Pholder': parent = this.parentBinding; parent.pholderValues[this.pholder] = newValue; entireValue = applyPlaceholders(parent.pholderContexts, parent.pholderValues, parent.pholderIndexMap); parent.setValue(entireValue, publisher); break; case 'Array': if (newValue !== this.value) { if (!checkIf.isArray(newValue)) { newValue = Array.prototype.concat(newValue); } convertToReg(this, this.value, true); convertToLive(this, newValue = newValue.slice(), true); } break; case 'Func': prevValue = this.valuePassed; this.valuePassed = newValue; newValue = this.object(newValue, prevValue); break; case 'Event': this.isEmitter = true; this.emitEvent(newValue); this.isEmitter = false; } } this.value = newValue; this.updateAllSubs(publisher); }, updateAllSubs: function(publisher) { var arr, i; if (i = (arr = this.subs).length) { while (i--) { this.updateSub(arr[i], publisher); } } }, updateSub: function(sub, publisher, isDelayedUpdate) { var currentTime, meta, newValue, subValue, timePassed, transform; if ((publisher === sub) || (publisher !== this && publisher.subsMeta[sub.ID])) { return; } meta = this.subsMeta[sub.ID]; if (meta.opts.throttle) { currentTime = +(new Date); timePassed = currentTime - meta.lastUpdate; if (timePassed < meta.opts.throttle) { clearTimeout(meta.updateTimer); return meta.updateTimer = setTimeout(((function(_this) { return function() { return _this.updateSub(sub, publisher); }; })(this)), meta.opts.throttle - timePassed); } else { meta.lastUpdate = currentTime; } } else if (meta.opts.delay && !isDelayedUpdate) { return setTimeout(((function(_this) { return function() { return _this.updateSub(sub, publisher, true); }; })(this)), meta.opts.delay); } newValue = this.type === 'Array' && meta.opts.sendArrayCopies ? this.value.slice() : this.value; subValue = sub[meta.valueRef]; newValue = (transform = meta.transformFn) ? transform(newValue, subValue, sub.object) : newValue; if (newValue === subValue && !meta.opts.updateEvenIfSame || meta.conditionFn && !meta.conditionFn(newValue, subValue, sub.object)) { return; } if (meta.opts.promiseTransforms && newValue && checkIf.isFunction(newValue.then)) { newValue.then(function(newValue) { sub.setValue(newValue, publisher); }); } else { sub.setValue(newValue, publisher); } if (meta.updateOnce) { this.removeSub(sub); } }, addModifierFn: function(target, subInterfaces, subjectFn, updateOnBind) { var j, len, subInterface, subMetaData, subscriber; if (!checkIf.isFunction(subjectFn)) { return throwWarning('fnOnly', 2); } else { for (j = 0, len = subInterfaces.length; j < len; j++) { subInterface = subInterfaces[j]; subscriber = subInterface._ || subInterface; if (subscriber.isMulti) { this.addModifierFn(target, subscriber.bindings, subjectFn, updateOnBind); } else { subMetaData = this.subsMeta[subscriber.ID]; subMetaData[target] = subjectFn; updateOnBind = updateOnBind && !subMetaData.updateOnce; if (this.pubsMap[subscriber.ID]) { subscriber.subsMeta[this.ID][target] = subjectFn; } if ((updateOnBind || this.type === 'Func') && target === 'transformFn') { this.updateSub(subscriber, this); } } } return true; } }, setSelfTransform: function(transformFn, updateOnBind) { this.selfTransform = transformFn; if (updateOnBind) { this.setValue(this.value); } }, scanForPholders: function() { var index; if (!this.pholderValues) { this.pholderValues = genObj(); this.pholderIndexMap = genObj(); this.pholderContexts = []; if (checkIf.isString(this.value)) { this.pholderContexts = this.value.split(pholderRegExSplit); index = 0; this.value = this.value.replace(pholderRegEx, (function(_this) { return function(e, pholder) { _this.pholderIndexMap[index++] = pholder; return _this.pholderValues[pholder] = pholder; }; })(this)); } } }, addPollInterval: function(time) { if (this.type !== 'Event') { 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.listen); } }, registerEvent: function(eventName, customListenMethod) { var attachmentMethod, defaultInMethod; defaultInMethod = 'on'; this.attachedEvents.push(eventName); attachmentMethod = customListenMethod || defaultInMethod; this.invokeEventMethod(eventName, attachmentMethod, defaultInMethod); }, unRegisterEvent: function(eventName, customEmitMethod) { var defaultRemoveMethod, removalMethod; defaultRemoveMethod = 'removeListener'; this.attachedEvents.splice(this.attachedEvents.indexOf(eventName), 1); removalMethod = customEmitMethod || 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 = eventUpdateHandler.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.emit || defaultOutMethod; if (!subject[emitMethod]) { emitMethod = defaultOutMethod; } subject[emitMethod](this.eventName, extraData); } }; eventUpdateHandler = function() { if (!this.isEmitter) { this.setValue(arguments[this.property], 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(options, inheritedState) { var key; if (inheritedState) { extendState(this, inheritedState); this.stage = 1; } else { this.stage = 0; this.subs = []; this.optionsPassed = options || (options = {}); this.options = {}; for (key in defaultOptions) { this.options[key] = options[key] != null ? options[key] : defaultOptions[key]; } } return this; }; BindingInterfacePrivate = { selfClone: function() { return new BindingInterface(null, this); }, defineMainProps: function(binding) { this._ = binding; return Object.defineProperties(this, { '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, isFunction) { var cachedBinding, newBinding; this.object = subject; cachedBinding = cache.get(subject, isFunction, this.selector, this.isMultiChoice); if (cachedBinding) { return this.patchCachedBinding(cachedBinding); } else { newBinding = new Binding(subject, newObjectType, bindingInterface); cache.set(newBinding, isFunction); return newBinding; } }, patchCachedBinding: function(cachedBinding) { var key, option, ref, ref1, value; if (cachedBinding.type === 'ObjectProp' && !(this.property in this.object)) { convertToLive(cachedBinding, this.object); } if (this.saveOptions) { ref = this.optionsPassed; for (option in ref) { value = ref[option]; cachedBinding.optionsDefault[option] = value; } } ref1 = cachedBinding.optionsDefault; for (key in ref1) { value = ref1[key]; this.options[key] = checkIf.isDefined(this.optionsPassed[key]) ? this.optionsPassed[key] : value; } return cachedBinding; }, setProperty: function(subject) { var split; if (checkIf.isNumber(subject)) { subject = subject.toString(); } this.selector = this.property = subject; if (!this.options.simpleSelector) { if (targetIncludes(subject, ':')) { split = subject.split(':'); this.descriptor = split.slice(0, -1).join(':'); this.property = split[split.length - 1]; } if (targetIncludes(subject, '.')) { split = this.property.split('.'); this.property = split[0]; this.pholder = split.slice(1).join('.'); } if (targetIncludes(this.descriptor, 'event')) { if (targetIncludes(subject, '#')) { split = this.property.split('#'); this.eventName = split[0]; this.property = split[1]; } else { this.eventName = this.property; this.property = 0; } if (isNaN(parseInt(this.property))) { throwWarning('badEventArg', 1); } this.customEventMethod = { listen: this.optionsPassed.listenMethod, emit: this.optionsPassed.emitMethod }; } } return this; }, setObject: function(subject, isFunction) { var newObjectType; this.stage = 1; switch (false) { case !isFunction: newObjectType = 'Func'; break; case !this.pholder: newObjectType = 'Pholder'; break; case !targetIncludes(this.descriptor, 'array'): newObjectType = 'Array'; break; case !targetIncludes(this.descriptor, 'event'): newObjectType = 'Event'; break; case !targetIncludes(this.descriptor, 'func'): newObjectType = 'Proxy'; break; default: newObjectType = 'ObjectProp'; } if (targetIncludes(this.descriptor, 'multi')) { if (!subject.length) { throwError('emptyList'); } this.defineMainProps(new GroupBinding(this, subject, newObjectType)); } else { this.defineMainProps(this.createBinding(subject, newObjectType, this, isFunction)); } if (targetIncludes(this._.type, 'Event') || targetIncludes(this._.type, 'Proxy')) { this.options.updateOnBind = false; } else if (targetIncludes(this._.type, 'Func')) { this.options.updateOnBind = true; } if (this.completeCallback) { return this.completeCallback(this); } else { return this; } }, addToPublisher: function(publisherInterface) { var alreadyHadSub, binding, j, len, ref; publisherInterface.stage = 2; publisherInterface.subs.push(this); alreadyHadSub = publisherInterface._.addSub(this._, publisherInterface.options, publisherInterface.updateOnce); if (publisherInterface.updateOnce) { delete publisherInterface.updateOnce; } else if (publisherInterface.options.updateOnBind && !alreadyHadSub) { if (this._.isMulti) { ref = this._.bindings; for (j = 0, len = ref.length; j < len; j++) { binding = ref[j]; publisherInterface._.updateSub(binding, publisherInterface._); } } else { publisherInterface._.updateSub(this._, publisherInterface._); } } } }; BindingInterface.prototype = Object.create(BindingInterfacePrivate, { of: { get: function() { if (!this.stage) { return METHOD_of; } } }, set: { get: function() { if (this.stage) { return METHOD_set; } } }, chainTo: { get: function() { if (this.stage === 2) { return METHOD_chainTo; } } }, transformSelf: { get: function() { if (this.stage === 1) { 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) { return METHOD_pollEvery; } } }, stopPolling: { get: function() { if (this.stage) { return METHOD_stopPolling; } } }, setOption: { get: function() { if (this.stage === 2) { return METHOD_setOption; } } }, updateOn: { get: function() { var thisInterface; if (this.stage && (thisInterface = this)) { return genProxiedInterface(false, function(subInterface) { if (subInterface._ !== thisInterface._) { thisInterface._.pubsMap[subInterface._.ID] = subInterface._; subInterface._.addSub(genSelfUpdater(thisInterface._, true), subInterface.options, false, true); } return thisInterface; }); } } }, removeUpdater: { get: function() { var selfUpdater, thisInterface; if (this.stage && (thisInterface = this) && (selfUpdater = this._.selfUpdater)) { return genProxiedInterface(false, function(subInterface) { if (subInterface._.subsMeta[selfUpdater.ID]) { delete thisInterface._.pubsMap[subInterface._.ID]; subInterface._.removeSub(selfUpdater); } }); } } }, to: { get: function() { var thisInterface; if (this.stage === 1 && (thisInterface = this)) { return genProxiedInterface(true, function(subInterface) { if (subInterface._ !== thisInterface._) { subInterface.addToPublisher(thisInterface); } return thisInterface; }); } } }, and: { get: function() { var cloneBinding, cloneInterface; cloneInterface = this.selfClone(); if (this.stage === 2) { return cloneInterface; } else if (this.stage === 1) { if (!cloneInterface._.isMulti) { cloneBinding = cloneInterface._; cloneInterface._ = cloneInterface._ = new GroupBinding(cloneInterface); cloneInterface._.addBinding(cloneBinding); } return genProxiedInterface(false, function(siblingInterface) { cloneInterface._.addBinding(siblingInterface._); return cloneInterface; }); } } }, once: { get: function() { var interfaceToReturn; if (this.stage === 1) { interfaceToReturn = this.selfClone(); 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; } this.stage = 1; return this.setObject(object); }; METHOD_chainTo = function(subject, specificOptions, saveOptions) { return SimplyBind(this.subs[this.subs.length - 1]).to(subject, specificOptions, saveOptions); }; METHOD_set = function(newValue) { this._.setValue(newValue); return this; }; METHOD_transformSelf = function(transformFn) { if (!checkIf.isFunction(transformFn)) { throwWarning('fnOnly', 1); } else { this._.setSelfTransform(transformFn, this.options.updateOnBind); } return this; }; METHOD_transform = function(transformFn) { this._.addModifierFn('transformFn', this.subs.slice(-1), transformFn, this.options.updateOnBind); return this; }; METHOD_transformAll = function(transformFn) { this._.addModifierFn('transformFn', this.subs, transformFn, this.options.updateOnBind); return this; }; METHOD_condition = function(conditionFn) { this._.addModifierFn('conditionFn', this.subs.slice(-1), conditionFn); return this; }; METHOD_conditionAll = function(conditionFn) { this._.addModifierFn('conditionFn', this.subs, conditionFn); return this; }; METHOD_bothWays = function(altTransform) { var binding, bindings, j, len, originCondition, originTransform, sub, subBinding, transformToUse; sub = this.subs[this.subs.length - 1]; subBinding = sub._; bindings = this._.isMulti ? this._.bindings : [this._]; subBinding.addSub(this._, sub.options); for (j = 0, len = bindings.length; j < len; j++) { binding = bindings[j]; originTransform = binding.subsMeta[subBinding.ID].transformFn; originCondition = binding.subsMeta[subBinding.ID].conditionFn; if (originTransform || altTransform) { transformToUse = checkIf.isFunction(altTransform) ? altTransform : originTransform; if (transformToUse && altTransform !== false) { subBinding.subsMeta[this._.ID].transformFn = transformToUse; } } if (originCondition) { subBinding.subsMeta[this._.ID].conditionFn = originCondition; } } return this; }; METHOD_unBind = function(bothWays) { var j, len, ref, sub; ref = this.subs; for (j = 0, len = ref.length; j < len; j++) { sub = ref[j]; this._.removeSub(sub._, bothWays); } return this; }; METHOD_pollEvery = function(time) { this._.addPollInterval(time); return this; }; METHOD_stopPolling = function() { this._.removePollInterval(); return this; }; METHOD_setOption = function(optionName, newValue) { this._.subsMeta[this.subs[this.subs.length - 1]._.ID].opts[optionName] = newValue; return this; }; GroupBinding = function(bindingInterface, objects, objectType) { var bindings, j, len, object; bindingInterface.selector = bindingInterface.selector.slice(6); extendState(this, this["interface"] = bindingInterface); this.isMulti = true; this.bindings = bindings = []; if (objects) { for (j = 0, len = objects.length; j < len; j++) { object = objects[j]; this.addBinding(object, objectType); } } return Object.defineProperties(this, { 'type': { get: function() { return bindings.map(function(binding) { return binding.type; }); } }, 'value': { get: function() { return bindings.map(function(binding) { return binding.value; }); } } }); }; proto = GroupBinding.prototype = Object.create(BindingInterfacePrivate); Object.keys(Binding.prototype).forEach(function(methodName) { return proto[methodName] = function(a, b, c, d) { var binding, j, len, ref; ref = this.bindings; for (j = 0, len = ref.length; j < len; j++) { binding = ref[j]; if (methodName === 'updateSub') { b = binding; } binding[methodName](a, b, c, d); } }; }); proto.addBinding = function(object, objectType) { this.bindings.push(!objectType ? object : this.createBinding(object, objectType, this["interface"])); }; if ((typeof module !== "undefined" && module !== null ? module.exports : void 0) != null) { return module.exports = SimplyBind; } else if (typeof define === 'function' && define.amd) { return define(['simplybind'], function() { return SimplyBind; }); } else { return this.SimplyBind = SimplyBind; } })();