31 @
typedef CPBindingOperationKind
40 JSObject _suppressedNotifications;
41 JSObject _placeholderForMarker;
44 + (void)exposeBinding:(
CPString)aBinding forClass:(Class)aClass
46 var bindings = [exposedBindingsMap objectForKey:[aClass UID]];
51 [exposedBindingsMap setObject:bindings forKey:[aClass UID]];
54 bindings.push(aBinding);
57 + (CPArray)exposedBindingsForClass:(Class)aClass
59 return [[exposedBindingsMap objectForKey:[aClass UID]] copy];
64 return [[bindingsMap objectForKey:[anObject UID]] objectForKey:aBinding];
67 + (void)_reverseSetValueFromExclusiveBinderForObject:(
id)anObject
69 var bindersByBindingName = [bindingsMap objectForKey:[anObject UID]];
71 [bindersByBindingName enumerateKeysAndObjectsUsingBlock:function(binding, binder, stop)
73 if ([binder isKindOfClass:[
self class]])
75 [binder reverseSetValueFor:binding];
86 return theBinding._info;
93 return [bindingsMap objectForKey:[anObject UID]];
96 + (void)unbind:(
CPString)aBinding forObject:(
id)anObject
98 var bindings = [bindingsMap objectForKey:[anObject UID]];
103 var theBinding = [bindings objectForKey:aBinding];
108 var info = theBinding._info,
109 observedObject = [info objectForKey:CPObservedObjectKey],
110 keyPath = [info objectForKey:CPObservedKeyPathKey];
112 [observedObject removeObserver:theBinding forKeyPath:keyPath];
113 [bindings removeObjectForKey:aBinding];
116 + (void)unbindAllForObject:(
id)anObject
118 var bindings = [bindingsMap objectForKey:[anObject UID]];
123 var allKeys = [bindings allKeys],
127 [anObject unbind:allKeys[count]];
129 [bindingsMap removeObjectForKey:[anObject UID]];
145 _suppressedNotifications = {};
146 _placeholderForMarker = {};
149 [_info setObject:options forKey:CPOptionsKey];
151 [
self _updatePlaceholdersWithOptions:options forBinding:aName];
153 [aDestination addObserver:self forKeyPath:aKeyPath options:0 context:aBinding];
155 var bindings = [bindingsMap objectForKey:[_source UID]];
160 [bindingsMap setObject:bindings forKey:[_source UID]];
163 [bindings setObject:self forKey:aName];
170 + (BOOL)isBindingAllowed:(
CPString)aBinding forObject:(
id)anObject
172 if ([[anObject
class] isBindingExclusive:aBinding])
174 var bindingsForObject = [bindingsMap objectForKey:[anObject UID]],
175 allBindings = [bindingsForObject allKeys],
176 count = [allBindings count];
180 if ([[anObject
class] isBindingExclusive:allBindings[count]])
190 if (aValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
193 reason:@"Cannot transform non-applicable key on: " + _source + " key path: " + keyPath + " value: " + aValue];
199 var destination = [_info objectForKey:CPObservedObjectKey],
200 keyPath = [_info objectForKey:CPObservedKeyPathKey],
201 options = [_info objectForKey:CPOptionsKey],
202 newValue = [destination valueForKeyPath:keyPath];
204 if (CPIsControllerMarker(newValue))
208 var value = [
self _placeholderForMarker:newValue];
218 - (void)setPlaceholderValue:(
id)aValue withMarker:(
CPString)aMarker forBinding:(
CPString)aBinding
220 [_source setValue:aValue forKey:aBinding];
223 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
225 [_source setValue:aValue forKey:aBinding];
230 var destination = [_info objectForKey:CPObservedObjectKey],
231 keyPath = [_info objectForKey:CPObservedKeyPathKey],
232 options = [_info objectForKey:CPOptionsKey],
238 [destination setValue:newValue forKeyPath:keyPath];
244 return [_source valueForKeyPath:aBinding];
247 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)changes context:(
id)context
252 var objectSuppressions = _suppressedNotifications[[anObject UID]];
254 if (objectSuppressions && objectSuppressions[aKeyPath])
262 var valueTransformerName = [options
objectForKey:CPValueTransformerNameBindingOption],
265 if (valueTransformerName)
269 if (!valueTransformer)
273 if (valueTransformerClass)
275 valueTransformer = [[valueTransformerClass alloc] init];
276 [valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName];
281 valueTransformer = [options
objectForKey:CPValueTransformerBindingOption];
283 if (valueTransformer)
284 aValue = [valueTransformer transformedValue:aValue];
289 if ((aValue === undefined || aValue === nil || aValue === [
CPNull null])
290 && ![_source respondsToSelector:
@selector(setPlaceholderString:)])
291 aValue = [options
objectForKey:CPNullPlaceholderBindingOption] || nil;
296 - (id)reverseTransformValue:(
id)aValue withOptions:(
CPDictionary)options
298 var valueTransformerName = [options
objectForKey:CPValueTransformerNameBindingOption],
301 if (valueTransformerName)
304 valueTransformer = [options
objectForKey:CPValueTransformerBindingOption];
306 if (valueTransformer && [[valueTransformer
class] allowsReverseTransformation])
307 aValue = [valueTransformer reverseTransformedValue:aValue];
312 - (BOOL)continuouslyUpdatesValue
314 var options = [_info objectForKey:CPOptionsKey];
315 return [[options
objectForKey:CPContinuouslyUpdatesValueBindingOption] boolValue];
318 - (BOOL)handlesContentAsCompoundValue
320 var options = [_info objectForKey:CPOptionsKey];
321 return [[options
objectForKey:CPHandlesContentAsCompoundValueBindingOption] boolValue];
327 - (void)suppressSpecificNotificationFromObject:(
id)anObject keyPath:(
CPString)aKeyPath
332 var uid = [anObject UID],
333 objectSuppressions = _suppressedNotifications[uid];
335 if (!objectSuppressions)
336 _suppressedNotifications[uid] = objectSuppressions = {};
338 objectSuppressions[aKeyPath] = YES;
344 - (void)unsuppressSpecificNotificationFromObject:(
id)anObject keyPath:(
CPString)aKeyPath
349 var uid = [anObject UID],
350 objectSuppressions = _suppressedNotifications[uid];
352 if (!objectSuppressions)
355 delete objectSuppressions[aKeyPath];
358 - (void)_updatePlaceholdersWithOptions:(
CPDictionary)options
360 var count = [CPBinderPlaceholderMarkers count];
364 var marker = CPBinderPlaceholderMarkers[count],
365 optionName = CPBinderPlaceholderOptions[count],
367 placeholder = isExplicit ? [options
objectForKey:optionName] : nil;
369 [
self _setPlaceholder:placeholder forMarker:marker isDefault:!isExplicit];
375 [
self _updatePlaceholdersWithOptions:options];
378 - (JSObject)_placeholderForMarker:(
id)aMarker
380 var placeholder = _placeholderForMarker[[aMarker
UID]];
383 return placeholder.value;
388 - (void)_setPlaceholder:(
id)aPlaceholder forMarker:(
id)aMarker isDefault:(BOOL)isDefault
392 var existingPlaceholder = _placeholderForMarker[[aMarker
UID]];
395 if (existingPlaceholder && !existingPlaceholder.isDefault)
399 _placeholderForMarker[[aMarker
UID]] = {
'isDefault': isDefault,
'value': aPlaceholder };
411 + (Class)_binderClassForBinding:(
CPString)aBinding
421 - (CPArray)exposedBindings
423 var exposedBindings = [],
424 theClass = [
self class];
433 theClass = [theClass superclass];
436 return exposedBindings;
446 if (!anObject || !aKeyPath)
447 return CPLog.error(
"Invalid object or path on " +
self +
" for " + aBinding);
449 if (![
CPBinder isBindingAllowed:aBinding forObject:
self])
451 CPLog.warn([
self description] +
" : cannot bind " + aBinding +
" because another binding with the same functionality is already in use.");
457 var binderClass = [[
self class] _binderClassForBinding:aBinding];
460 [[binderClass alloc] initWithBinding:[
self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
470 var binderClass = [[
self class] _binderClassForBinding:aBinding];
471 [binderClass unbind:aBinding forObject:self];
489 @implementation _CPValueBinder :
CPBinder 494 - (void)setValueFor:(
CPString)theBinding
496 [
super setValueFor:@"objectValue"];
499 - (void)reverseSetValueFor:(
CPString)theBinding
501 [
super reverseSetValueFor:@"objectValue"];
506 @implementation _CPMultipleValueBooleanBinding :
CPBinder 508 CPBindingOperationKind _operation;
511 - (void)setValueFor:(
CPString)aBinding
513 var bindings = [bindingsMap valueForKey:[_source UID]];
518 var baseBinding = aBinding.replace(/\d$/,
"");
520 [_source setValue:[
self resolveMultipleValuesForBinding:baseBinding bindings:bindings booleanOperation:_operation] forKey:baseBinding];
523 - (void)reverseSetValueFor:(
CPString)theBinding
528 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)changes context:(
id)context
530 [
self setValueFor:context];
533 - (BOOL)resolveMultipleValuesForBinding:(
CPString)aBinding bindings:(
CPDictionary)bindings booleanOperation:(CPBindingOperationKind)operation
535 var bindingName = aBinding,
539 while (theBinding = [bindings objectForKey:bindingName])
541 var info = theBinding._info,
542 object = [info objectForKey:CPObservedObjectKey],
543 keyPath = [info objectForKey:CPObservedKeyPathKey],
544 options = [info objectForKey:CPOptionsKey],
545 value = [object valueForKeyPath:keyPath];
547 if (CPIsControllerMarker(value))
549 [
self raiseIfNotApplicable:value forKeyPath:keyPath options:options];
550 value = [theBinding _placeholderForMarker:value];
553 value = [theBinding transformValue:value withOptions:options];
566 bindingName = aBinding + (count++);
581 if (
self = [super
init])
595 if (
self = [super
init])
603 @implementation _CPMultipleValueActionBinding :
CPBinder 609 - (void)setValueFor:(
CPString)theBinding
612 [
self checkForNullBinding:theBinding initializing:YES];
615 - (void)reverseSetValueFor:(
CPString)theBinding
620 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)changes context:(
id)context
623 [
self checkForNullBinding:context initializing:NO];
634 - (void)checkForNullBinding:(
CPString)theBinding initializing:(BOOL)isInitializing
637 if (![_source isKindOfClass:
CPButton])
642 if (isInitializing && theBinding === CPArgumentBinding)
643 [_source setEnabled:YES];
645 var bindings = [bindingsMap valueForKey:[_source UID]],
646 binding = [bindings objectForKey:theBinding],
647 info = binding._info,
648 options = [info objectForKey:CPOptionsKey];
650 if (![options valueForKey:CPAllowsNullArgumentBindingOption])
652 var
object = [info objectForKey:CPObservedObjectKey],
653 keyPath = [info objectForKey:CPObservedKeyPathKey],
654 value = [object valueForKeyPath:keyPath];
656 if (value === nil || value === undefined)
658 [_source setEnabled:NO];
665 [_source setEnabled:YES];
670 var bindings = [bindingsMap valueForKey:[_source UID]],
671 theBinding = [bindings objectForKey:CPTargetBinding],
673 info = theBinding._info,
674 object = [info objectForKey:CPObservedObjectKey],
675 keyPath = [info objectForKey:CPObservedKeyPathKey],
676 options = [info objectForKey:CPOptionsKey],
678 target = [object valueForKeyPath:keyPath],
679 selector = [options
objectForKey:CPSelectorNameBindingOption];
681 if (!target || !selector)
685 bindingName = CPArgumentBinding,
688 while (theBinding = [bindings objectForKey:bindingName])
690 info = theBinding._info;
691 object = [info objectForKey:CPObservedObjectKey];
692 keyPath = [info objectForKey:CPObservedKeyPathKey];
694 [invocation setArgument:[object valueForKeyPath:keyPath] atIndex:++count];
696 bindingName = CPArgumentBinding + count;
699 [invocation setSelector:selector];
700 [invocation invokeWithTarget:target];
711 if (
self = [super
init])
713 _argumentBinding = CPArgumentBinding;
714 _targetBinding = CPTargetBinding;
728 if (
self = [super
init])
730 _argumentBinding = CPArgumentBinding;
731 _targetBinding = CPTargetBinding;
742 @implementation _CPPatternBinding :
CPBinder 748 - (void)setValueFor:(
CPString)aBinding
750 var bindings = [bindingsMap valueForKey:[_source UID]];
756 var baseBinding = aBinding.replace(/\d$/,
""),
757 result = [
self resolveMultipleValuesForBindings:bindings];
759 if (result.isPlaceholder)
760 [
self setPlaceholderValue:result.value withMarker:result.marker forBinding:baseBinding];
762 [
self setValue:result.value forBinding:baseBinding];
765 - (void)reverseSetValueFor:(
CPString)theBinding
770 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)changes context:(
id)context
772 [
self setValueFor:context];
775 - (JSObject)resolveMultipleValuesForBindings:(
CPDictionary)bindings
778 result = { value:
@"", isPlaceholder:NO, marker:nil };
780 for (var count = 1; theBinding = [bindings
objectForKey:_bindingKey + count]; ++count)
782 var info = theBinding._info,
783 object = [info objectForKey:CPObservedObjectKey],
784 keyPath = [info objectForKey:CPObservedKeyPathKey],
785 options = [info objectForKey:CPOptionsKey],
786 value = [object valueForKeyPath:keyPath];
789 result.value = [options objectForKey:CPDisplayPatternBindingOption];
791 if (CPIsControllerMarker(value))
793 [
self raiseIfNotApplicable:value forKeyPath:keyPath options:options];
795 result.isPlaceholder = YES;
796 result.marker = value;
798 value = [theBinding _placeholderForMarker:value];
801 value = [theBinding transformValue:value withOptions:options];
803 if (value === nil || value === undefined)
806 result.value = result.value.replace(
"%{" + _patternPlaceholder + count +
"}@", [value
description]);
827 if (
self = [super
init])
829 _bindingKey = CPDisplayPatternValueBinding;
830 _patternPlaceholder =
@"value";
851 if (
self = [super
init])
853 _bindingKey = CPDisplayPatternTitleBinding;
854 _patternPlaceholder =
@"title";
862 @implementation _CPStateMarker :
CPObject 869 if (
self = [super
init])
877 return "<" + _name + ">";
891 CPNoSelectionMarker = [[_CPStateMarker alloc] initWithName:@"NO SELECTION MARKER"];
892 CPMultipleValuesMarker = [[_CPStateMarker alloc] initWithName:@"MULTIPLE VALUES MARKER"];
893 CPNotApplicableMarker = [[_CPStateMarker alloc] initWithName:@"NOT APPLICABLE MARKER"];
894 CPNullMarker = [[_CPStateMarker alloc] initWithName:@"NULL MARKER"];
897 CPAlignmentBinding =
@"alignment";
898 CPArgumentBinding =
@"argument";
899 CPContentArrayBinding =
@"contentArray";
900 CPContentBinding =
@"content";
901 CPContentObjectBinding =
@"contentObject";
902 CPContentObjectsBinding =
@"contentObjects";
903 CPContentValuesBinding =
@"contentValues";
904 CPDisplayPatternTitleBinding =
@"displayPatternTitle";
905 CPDisplayPatternValueBinding =
@"displayPatternValue";
906 CPDoubleClickArgumentBinding =
@"doubleClickArgument";
907 CPDoubleClickTargetBinding =
@"doubleClickTarget";
908 CPEditableBinding =
@"editable";
909 CPEnabledBinding =
@"enabled";
910 CPFontBinding =
@"font";
911 CPFontNameBinding =
@"fontName";
912 CPFontBoldBinding =
@"fontBold";
913 CPHiddenBinding =
@"hidden";
914 CPFilterPredicateBinding =
@"filterPredicate";
915 CPMaxValueBinding =
@"maxValue";
916 CPMinValueBinding =
@"minValue";
917 CPPredicateBinding =
@"predicate";
918 CPSelectedIndexBinding =
@"selectedIndex";
919 CPSelectedLabelBinding =
@"selectedLabel";
920 CPSelectedObjectBinding =
@"selectedObject";
921 CPSelectedObjectsBinding =
@"selectedObjects";
922 CPSelectedTagBinding =
@"selectedTag";
923 CPSelectedValueBinding =
@"selectedValue";
924 CPSelectedValuesBinding =
@"selectedValues";
925 CPSelectionIndexesBinding =
@"selectionIndexes";
926 CPTargetBinding =
@"target";
927 CPTextColorBinding =
@"textColor";
928 CPTitleBinding =
@"title";
929 CPToolTipBinding =
@"toolTip";
930 CPValueBinding =
@"value";
931 CPAttributedStringBinding =
@"attributedString";
932 CPValueURLBinding =
@"valueURL";
933 CPValuePathBinding =
@"valuePath";
934 CPDataBinding =
@"data";
937 CPAllowsEditingMultipleValuesSelectionBindingOption =
@"CPAllowsEditingMultipleValuesSelection";
938 CPAllowsNullArgumentBindingOption =
@"CPAllowsNullArgument";
939 CPConditionallySetsEditableBindingOption =
@"CPConditionallySetsEditable";
940 CPConditionallySetsEnabledBindingOption =
@"CPConditionallySetsEnabled";
941 CPConditionallySetsHiddenBindingOption =
@"CPConditionallySetsHidden";
942 CPContinuouslyUpdatesValueBindingOption =
@"CPContinuouslyUpdatesValue";
943 CPCreatesSortDescriptorBindingOption =
@"CPCreatesSortDescriptor";
944 CPDeletesObjectsOnRemoveBindingsOption =
@"CPDeletesObjectsOnRemove";
945 CPDisplayNameBindingOption =
@"CPDisplayName";
946 CPDisplayPatternBindingOption =
@"CPDisplayPattern";
947 CPHandlesContentAsCompoundValueBindingOption =
@"CPHandlesContentAsCompoundValue";
948 CPInsertsNullPlaceholderBindingOption =
@"CPInsertsNullPlaceholder";
949 CPInvokesSeparatelyWithArrayObjectsBindingOption =
@"CPInvokesSeparatelyWithArrayObjects";
950 CPMultipleValuesPlaceholderBindingOption =
@"CPMultipleValuesPlaceholder";
951 CPNoSelectionPlaceholderBindingOption =
@"CPNoSelectionPlaceholder";
952 CPNotApplicablePlaceholderBindingOption =
@"CPNotApplicablePlaceholder";
953 CPNullPlaceholderBindingOption =
@"CPNullPlaceholder";
954 CPPredicateFormatBindingOption =
@"CPPredicateFormat";
955 CPRaisesForNotApplicableKeysBindingOption =
@"CPRaisesForNotApplicableKeys";
956 CPSelectorNameBindingOption =
@"CPSelectorName";
957 CPSelectsAllWhenSettingContentBindingOption =
@"CPSelectsAllWhenSettingContent";
958 CPValidatesImmediatelyBindingOption =
@"CPValidatesImmediately";
959 CPValueTransformerNameBindingOption =
@"CPValueTransformerName";
960 CPValueTransformerBindingOption =
@"CPValueTransformer";
962 CPIsControllerMarker =
function(anObject)
964 return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
967 var CPBinderPlaceholderMarkers = [CPMultipleValuesMarker, CPNoSelectionMarker, CPNotApplicableMarker, CPNullMarker],
968 CPBinderPlaceholderOptions = [CPMultipleValuesPlaceholderBindingOption, CPNoSelectionPlaceholderBindingOption, CPNotApplicablePlaceholderBindingOption, CPNullPlaceholderBindingOption];
971 @implementation CPBinder (CPSynthesizedAccessors)
Used to implement exception handling (creating & raising).
CPArray exposedBindings()
void setPlaceholderValue:withMarker:forBinding:(id aValue, [withMarker] CPString aMarker, [forBinding] CPString aBinding)
BOOL containsKey:(id aKey)
CPDictionary infoForBinding:forObject:(CPString aBinding, [forObject] id anObject)
id invocationWithMethodSignature:(CPMethodSignature aMethodSignature)
An object representation of nil.
void setValue:forBinding:(id aValue, [forBinding] CPString aBinding)
void suppressSpecificNotificationFromObject:keyPath:(id anObject, [keyPath] CPString aKeyPath)
void raiseIfNotApplicable:forKeyPath:options:(id aValue, [forKeyPath] CPString keyPath, [options] CPDictionary options)
CPBindingOperationKind var CPBindingOperationAnd
id valueForBinding:(CPString aBinding)
void raise:reason:(CPString aName, [reason] CPString aReason)
A mutable key-value pair collection.
An object representation of a message.
id reverseTransformValue:withOptions:(id aValue, [withOptions] CPDictionary options)
An immutable string (collection of characters).
id objectForKey:(id aKey)
if(CPFeatureIsCompatible(CPHTMLCanvasFeature))
void unbind:(CPString aBinding)
void exposeBinding:forClass:(CPString aBinding, [forClass] Class aClass)
CPBinder getBinding:forObject:(CPString aBinding, [forObject] id anObject)
void setValueFor:(CPString theBinding)
CPBindingOperationKind var CPBindingOperationOr
id transformValue:withOptions:(id aValue, [withOptions] CPDictionary options)
CPArray exposedBindingsForClass:(Class aClass)
void unsuppressSpecificNotificationFromObject:keyPath:(id anObject, [keyPath] CPString aKeyPath)
function CPClassFromString(aClassName)
FrameUpdater prototype description