39 JSObject _suppressedNotifications;
40 JSObject _placeholderForMarker;
43 + (void)exposeBinding:(
CPString)aBinding forClass:(Class)aClass
45 var bindings = [exposedBindingsMap objectForKey:[aClass UID]];
50 [exposedBindingsMap setObject:bindings forKey:[aClass UID]];
53 bindings.push(aBinding);
56 + (
CPArray)exposedBindingsForClass:(Class)aClass
58 return [[exposedBindingsMap objectForKey:[aClass UID]] copy];
63 return [[bindingsMap objectForKey:[anObject UID]] objectForKey:aBinding];
71 return theBinding._info;
78 return [bindingsMap objectForKey:[anObject UID]];
81 + (void)unbind:(
CPString)aBinding forObject:(
id)anObject
83 var bindings = [bindingsMap objectForKey:[anObject UID]];
88 var theBinding = [bindings objectForKey:aBinding];
93 var infoDictionary = theBinding._info,
94 observedObject = [infoDictionary objectForKey:CPObservedObjectKey],
95 keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey];
97 [observedObject removeObserver:theBinding forKeyPath:keyPath];
98 [bindings removeObjectForKey:aBinding];
101 + (void)unbindAllForObject:(
id)anObject
103 var bindings = [bindingsMap objectForKey:[anObject UID]];
107 var allKeys = [bindings allKeys],
111 [anObject unbind:[bindings objectForKey:allKeys[count]]];
113 [bindingsMap removeObjectForKey:[anObject UID]];
124 _suppressedNotifications = {};
125 _placeholderForMarker = {};
128 [_info setObject:options forKey:CPOptionsKey];
130 [
self _updatePlaceholdersWithOptions:options forBinding:aName];
132 [aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
134 var bindings = [bindingsMap objectForKey:[_source UID]];
138 [bindingsMap setObject:bindings forKey:[_source UID]];
141 [bindings setObject:self forKey:aName];
150 var destination = [_info objectForKey:CPObservedObjectKey],
151 keyPath = [_info objectForKey:CPObservedKeyPathKey],
152 options = [_info objectForKey:CPOptionsKey],
153 newValue = [destination valueForKeyPath:keyPath],
161 reason:@"Cannot transform non-applicable key on: " + _source + " key path: " + keyPath + " value: " + newValue];
164 var value = [
self _placeholderForMarker:newValue];
174 - (void)setPlaceholderValue:(
id)aValue withMarker:(
CPString)aMarker forBinding:(
CPString)aBinding
176 [_source setValue:aValue forKey:aBinding];
179 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
181 [_source setValue:aValue forKey:aBinding];
186 var destination = [_info objectForKey:CPObservedObjectKey],
187 keyPath = [_info objectForKey:CPObservedKeyPathKey],
188 options = [_info objectForKey:CPOptionsKey],
194 [destination setValue:newValue forKeyPath:keyPath];
200 return [_source valueForKeyPath:aBinding];
203 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)changes context:(
id)context
208 var objectSuppressions = _suppressedNotifications[[anObject UID]];
209 if (objectSuppressions && objectSuppressions[aKeyPath])
217 var valueTransformerName = [options
objectForKey:CPValueTransformerNameBindingOption],
220 if (valueTransformerName)
224 if (!valueTransformer)
227 if (valueTransformerClass)
229 valueTransformer = [[valueTransformerClass alloc] init];
230 [valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName];
235 valueTransformer = [options
objectForKey:CPValueTransformerBindingOption];
237 if (valueTransformer)
238 aValue = [valueTransformer transformedValue:aValue];
240 if (aValue === undefined || aValue === nil || aValue === [
CPNull null])
241 aValue = [options
objectForKey:CPNullPlaceholderBindingOption] || nil;
246 - (id)reverseTransformValue:(
id)aValue withOptions:(
CPDictionary)options
248 var valueTransformerName = [options
objectForKey:CPValueTransformerNameBindingOption],
251 if (valueTransformerName)
254 valueTransformer = [options
objectForKey:CPValueTransformerBindingOption];
256 if (valueTransformer && [[valueTransformer
class] allowsReverseTransformation])
257 aValue = [valueTransformer reverseTransformedValue:aValue];
262 - (BOOL)continuouslyUpdatesValue
264 var options = [_info objectForKey:CPOptionsKey];
265 return [[options
objectForKey:CPContinuouslyUpdatesValueBindingOption] boolValue];
268 - (BOOL)handlesContentAsCompoundValue
270 var options = [_info objectForKey:CPOptionsKey];
271 return [[options
objectForKey:CPHandlesContentAsCompoundValueBindingOption] boolValue];
277 - (void)suppressSpecificNotificationFromObject:(
id)anObject keyPath:(
CPString)aKeyPath
282 var uid = [anObject UID],
283 objectSuppressions = _suppressedNotifications[uid];
284 if (!objectSuppressions)
285 _suppressedNotifications[uid] = objectSuppressions = {};
287 objectSuppressions[aKeyPath] = YES;
293 - (void)unsuppressSpecificNotificationFromObject:(
id)anObject keyPath:(
CPString)aKeyPath
298 var uid = [anObject UID],
299 objectSuppressions = _suppressedNotifications[uid];
300 if (!objectSuppressions)
303 delete objectSuppressions[aKeyPath];
306 - (void)_updatePlaceholdersWithOptions:(
CPDictionary)options
308 var count = [CPBinderPlaceholderMarkers count];
315 placeholder = isExplicit ? [options
objectForKey:optionName] : nil;
316 [
self _setPlaceholder:placeholder forMarker:marker isDefault:!isExplicit];
322 [
self _updatePlaceholdersWithOptions:options];
325 - (void)_placeholderForMarker:aMarker
327 var placeholder = _placeholderForMarker[aMarker];
329 return placeholder['value'];
333 - (void)_setPlaceholder:(
id)aPlaceholder forMarker:(
id)aMarker isDefault:(BOOL)isDefault
337 var existingPlaceholder = _placeholderForMarker[aMarker];
340 if (existingPlaceholder && !existingPlaceholder[
'isDefault'])
344 _placeholderForMarker[aMarker] = {
'isDefault': isDefault,
'value': aPlaceholder };
356 + (Class)_binderClassForBinding:(
CPString)theBinding
363 var exposedBindings = [],
364 theClass = [
self class];
373 theClass = [theClass superclass];
376 return exposedBindings;
386 if (!anObject || !aKeyPath)
387 return CPLog.error(
"Invalid object or path on " +
self +
" for " + aBinding);
392 var binderClass = [[
self class] _binderClassForBinding:aBinding];
395 [[binderClass alloc] initWithBinding:[
self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
405 var binderClass = [[
self class] _binderClassForBinding:aBinding];
406 [binderClass unbind:aBinding forObject:self];
409 - (id)_replacementKeyPathForBinding:(
CPString)binding
422 @implementation _CPValueBinder :
CPBinder
427 - (void)setValueFor:(
CPString)theBinding
429 [
super setValueFor:@"objectValue"];
432 - (void)reverseSetValueFor:(
CPString)theBinding
434 [
super reverseSetValueFor:@"objectValue"];
438 @implementation _CPKeyValueOrBinding :
CPBinder
443 - (void)setValueFor:(
CPString)aBinding
445 var bindings = [bindingsMap valueForKey:[_source UID]];
450 [_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationOr) forKey:aBinding];
453 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)changes context:(
id)context
455 [
self setValueFor:context];
459 @implementation _CPKeyValueAndBinding :
CPBinder
464 - (void)setValueFor:(
CPString)aBinding
466 var bindings = [bindingsMap objectForKey:[_source UID]];
471 [_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationAnd) forKey:aBinding];
474 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObejct change:(
CPDictionary)changes context:(
id)context
476 [
self setValueFor:context];
483 var bindingName = key,
487 while (theBinding = [bindings objectForKey:bindingName])
489 var infoDictionary = theBinding._info,
490 object = [infoDictionary objectForKey:CPObservedObjectKey],
491 keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
492 options = [infoDictionary objectForKey:CPOptionsKey];
494 var value = [theBinding transformValue:[object valueForKeyPath:keyPath] withOptions:options];
496 if (value == operation)
507 var theBinding = [bindings objectForKey:targetKey],
508 infoDictionary = theBinding._info,
510 object = [infoDictionary objectForKey:CPObservedObjectKey],
511 keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
512 options = [infoDictionary objectForKey:CPOptionsKey],
514 target = [object valueForKeyPath:keyPath],
515 selector = [options
objectForKey:CPSelectorNameBindingOption];
517 if (!target || !selector)
521 [invocation setSelector:selector];
523 var bindingName = argumentKey,
526 while (theBinding = [bindings objectForKey:bindingName])
528 infoDictionary = theBinding._info;
530 keyPath = [infoDictionary objectForKey:CPObserverKeyPathKey];
531 object = [[infoDictionary objectForKey:CPObservedObjectKey] valueForKeyPath:keyPath];
534 [invocation setArgument:object atIndex:++count];
620 CPBinderPlaceholderOptions = [CPMultipleValuesPlaceholderBindingOption, CPNoSelectionPlaceholderBindingOption, CPNotApplicablePlaceholderBindingOption, CPNullPlaceholderBindingOption];