mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-12 05:31:29 +00:00
Merge branch 'master' of github.com:280north/cappuccino
This commit is contained in:
+17
-15
@@ -111,7 +111,7 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)prepareContent
|
||||
- (void)prepareContent
|
||||
{
|
||||
[self _setContentArray:[[self newObject]]];
|
||||
}
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
- (void)setContent:(id)value
|
||||
{
|
||||
if(![value isKindOfClass:[CPArray class]])
|
||||
if (![value isKindOfClass:[CPArray class]])
|
||||
value = [value];
|
||||
|
||||
var oldSelectedObjects = nil,
|
||||
@@ -178,7 +178,7 @@
|
||||
// We need to be in control of when notifications fire.
|
||||
_contentObject = value;
|
||||
|
||||
if(_clearsFilterPredicateOnInsertion)
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
|
||||
else
|
||||
[self _rearrangeObjects];
|
||||
@@ -342,7 +342,9 @@
|
||||
|
||||
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
[self _selectionWillChange]
|
||||
[self __setSelectionIndexes:indexes];
|
||||
[self _selectionDidChange];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -365,17 +367,17 @@
|
||||
|
||||
if (![indexes count])
|
||||
{
|
||||
if(_avoidsEmptySelection && [[self arrangedObjects] count])
|
||||
if (_avoidsEmptySelection && [[self arrangedObjects] count])
|
||||
indexes = [CPIndexSet indexSetWithIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
var objectsCount = [[self arrangedObjects] count];
|
||||
// Remove out of bounds indexes.
|
||||
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex]+1)];
|
||||
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
|
||||
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
|
||||
if(![indexes count] && _avoidsEmptySelection && objectsCount)
|
||||
indexes = [CPIndexSet indexSetWithIndex:objectsCount-1];
|
||||
if (![indexes count] && _avoidsEmptySelection && objectsCount)
|
||||
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
}
|
||||
|
||||
if ([_selectionIndexes isEqualToIndexSet:indexes])
|
||||
@@ -418,7 +420,7 @@
|
||||
count = [objects count],
|
||||
arrangedObjects = [self arrangedObjects];
|
||||
|
||||
for (var i=0; i<count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var index = [arrangedObjects indexOfObject:[objects objectAtIndex:i]];
|
||||
|
||||
@@ -437,7 +439,7 @@
|
||||
return [[self selectionIndexes] firstIndex] > 0
|
||||
}
|
||||
|
||||
-(void)selectPrevious:(id)sender
|
||||
- (void)selectPrevious:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex] - 1;
|
||||
|
||||
@@ -545,9 +547,9 @@
|
||||
[self didChangeValueForKey:@"content"];
|
||||
}
|
||||
|
||||
-(void)add:(id)sender
|
||||
- (void)add:(id)sender
|
||||
{
|
||||
if(![self canAdd])
|
||||
if (![self canAdd])
|
||||
return;
|
||||
|
||||
[self insert:sender];
|
||||
@@ -555,7 +557,7 @@
|
||||
|
||||
- (void)insert:(id)sender
|
||||
{
|
||||
if(![self canInsert])
|
||||
if (![self canInsert])
|
||||
return;
|
||||
|
||||
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
|
||||
@@ -576,13 +578,13 @@
|
||||
|
||||
- (void)addObjects:(CPArray)objects
|
||||
{
|
||||
if(![self canAdd])
|
||||
if (![self canAdd])
|
||||
return;
|
||||
|
||||
var contentArray = [self contentArray],
|
||||
count = [objects count];
|
||||
|
||||
for (var i=0; i<count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
[contentArray addObject:[objects objectAtIndex:i]];
|
||||
|
||||
[self setContent:contentArray];
|
||||
@@ -590,7 +592,7 @@
|
||||
|
||||
- (void)removeObjects:(CPArray)objects
|
||||
{
|
||||
if(![self canRemove])
|
||||
if (![self canRemove])
|
||||
return;
|
||||
|
||||
[self _removeObjects:objects];
|
||||
|
||||
+39
-17
@@ -146,10 +146,39 @@ var CPBindingOperationAnd = 0,
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
newValue = [destination valueForKeyPath:keyPath];
|
||||
newValue = [destination valueForKeyPath:keyPath],
|
||||
isPlaceholder = CPIsControllerMarker(newValue);
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
switch (newValue)
|
||||
{
|
||||
case CPMultipleValuesMarker:
|
||||
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
|
||||
break;
|
||||
|
||||
case CPNoSelectionMarker:
|
||||
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
|
||||
break;
|
||||
|
||||
case CPNotApplicableMarker:
|
||||
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
|
||||
|
||||
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only transform the value if the current value is not a placeholder
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
}
|
||||
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
[_source setValue:newValue forKey:aBinding];
|
||||
|
||||
if ([_source respondsToSelector:@selector(_setCurrentValueIsPlaceholder:)])
|
||||
[_source _setCurrentValueIsPlaceholder:isPlaceholder];
|
||||
}
|
||||
|
||||
- (void)reverseSetValueFor:(CPString)aBinding
|
||||
@@ -200,20 +229,9 @@ var CPBindingOperationAnd = 0,
|
||||
if (valueTransformer)
|
||||
aValue = [valueTransformer transformedValue:aValue];
|
||||
|
||||
switch (aValue)
|
||||
{
|
||||
case CPMultipleValuesMarker: return [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
|
||||
|
||||
case CPNoSelectionMarker: return [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
|
||||
|
||||
case CPNotApplicableMarker: if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+aValue];
|
||||
|
||||
return [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
|
||||
|
||||
case nil:
|
||||
case undefined: return [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||
}
|
||||
if (aValue === undefined || aValue === nil)
|
||||
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||
|
||||
return aValue;
|
||||
}
|
||||
@@ -248,7 +266,7 @@ var CPBindingOperationAnd = 0,
|
||||
var exposedBindings = [],
|
||||
theClass = [self class];
|
||||
|
||||
while(theClass)
|
||||
while (theClass)
|
||||
{
|
||||
var temp = [CPKeyValueBinding exposedBindingsForClass:theClass];
|
||||
|
||||
@@ -379,7 +397,7 @@ var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argu
|
||||
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
|
||||
[invocation setSelector:selector];
|
||||
|
||||
var bindingName = argumentKey
|
||||
var bindingName = argumentKey,
|
||||
count = 1;
|
||||
|
||||
while (theBinding = [bindings objectForKey:bindingName])
|
||||
@@ -447,3 +465,7 @@ CPValidatesImmediatelyBindingOption = @"CPValidatesImmediatelyBi
|
||||
CPValueTransformerNameBindingOption = @"CPValueTransformerNameBindingOption";
|
||||
CPValueTransformerBindingOption = @"CPValueTransformerBindingOption";
|
||||
|
||||
CPIsControllerMarker = function(/*id*/anObject)
|
||||
{
|
||||
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
|
||||
}
|
||||
+45
-9
@@ -86,6 +86,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPColor _textFieldBackgroundColor;
|
||||
|
||||
id _placeholderString;
|
||||
id _originalPlaceholderString;
|
||||
BOOL _currentValueIsPlaceholder;
|
||||
|
||||
id _delegate;
|
||||
|
||||
@@ -279,7 +281,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
_isEditable = shouldBeEditable;
|
||||
|
||||
if(shouldBeEditable)
|
||||
if (shouldBeEditable)
|
||||
_isSelectable = YES;
|
||||
|
||||
// We only allow first responder status if the field is editable and enabled.
|
||||
@@ -543,7 +545,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
var element = [self _inputElement];
|
||||
|
||||
[self setObjectValue:element.value];
|
||||
if ([self stringValue] !== element.value)
|
||||
[self _setStringValue:element.value];
|
||||
|
||||
CPTextFieldInputResigning = YES;
|
||||
element.blur();
|
||||
@@ -695,8 +698,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)textDidBlur:(CPNotification)note
|
||||
{
|
||||
//this looks to prevent false propagation of notifications for other objects
|
||||
if([note object] != self)
|
||||
// this looks to prevent false propagation of notifications for other objects
|
||||
if ([note object] != self)
|
||||
return;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||
@@ -704,13 +707,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)textDidFocus:(CPNotification)note
|
||||
{
|
||||
//this looks to prevent false propagation of notifications for other objects
|
||||
if([note object] != self)
|
||||
// this looks to prevent false propagation of notifications for other objects
|
||||
if ([note object] != self)
|
||||
return;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
// Don't reverse set our empty value
|
||||
if (!_currentValueIsPlaceholder)
|
||||
[self _reverseSetBinding];
|
||||
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the string the text field.
|
||||
*/
|
||||
@@ -757,7 +769,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
Sets a placeholder string for the receiver. The placeholder is displayed until editing begins,
|
||||
and after editing ends, if the text field has an empty string value
|
||||
*/
|
||||
-(void)setPlaceholderString:(CPString)aStringValue
|
||||
- (void)setPlaceholderString:(CPString)aStringValue
|
||||
{
|
||||
if (_placeholderString === aStringValue)
|
||||
return;
|
||||
@@ -780,6 +792,30 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return _placeholderString;
|
||||
}
|
||||
|
||||
- (void)_setCurrentValueIsPlaceholder:(BOOL)isPlaceholder
|
||||
{
|
||||
if (isPlaceholder)
|
||||
{
|
||||
// Save the original placeholder value so we can restore it later
|
||||
// Only do this if the placeholder is not already overridden because the bindings logic might call this method
|
||||
// several times and we don't want the bindings placeholder to ever become the original placeholder
|
||||
if (!_currentValueIsPlaceholder)
|
||||
_originalPlaceholderString = [self placeholderString];
|
||||
|
||||
// Set the current string value as the current placeholder and clear the string value
|
||||
[self setPlaceholderString:[self stringValue]];
|
||||
[self setStringValue:@""];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore the original placeholder, the actual textfield value is already correct
|
||||
// because it was set using setValue:forKey:
|
||||
[self setPlaceholderString:_originalPlaceholderString];
|
||||
}
|
||||
|
||||
_currentValueIsPlaceholder = isPlaceholder;
|
||||
}
|
||||
|
||||
/*!
|
||||
Size to fit has two behavior, depending on if the receiver is an editable text field or not.
|
||||
|
||||
@@ -881,7 +917,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1158,7 +1194,7 @@ var secureStringForString = function(aString)
|
||||
if (!aString)
|
||||
return "";
|
||||
|
||||
return Array(aString.length+1).join(CPSecureTextFieldCharacter);
|
||||
return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -245,6 +245,19 @@
|
||||
[self assert:[CPIndexSet indexSetWithIndex:0] equals:observation.newValue message:"new selected index should be 0"];
|
||||
}
|
||||
|
||||
- (void)testObservationDuringSetSelectionIndexes
|
||||
{
|
||||
var arrayController = [self arrayController],
|
||||
newContent = [self setupObservationFixture];
|
||||
|
||||
var newSelection = [CPIndexSet indexSetWithIndex:2];
|
||||
[arrayController setSelectionIndexes:newSelection];
|
||||
|
||||
[self assertNotNull:[arrayController selection] message:@"a selection was made, selection proxy should be defined"];
|
||||
[self assert:2 equals:[observations count] message:@"exactly 2 change notifications should be sent for new selection indexes"];
|
||||
[self assert:newSelection equals:[arrayController selectionIndexes] message:@"selection was not set properly"];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:keyPath
|
||||
ofObject:anActivity
|
||||
change:change
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
[binder setCheese:@"banana"];
|
||||
|
||||
[self assertTrue:[self valueForKey:@"FOO"]==="banana" message:"Bound value should have been updated to banana, was "+FOO];
|
||||
[self assertTrue:[self valueForKey:@"FOO"] === "banana" message:"Bound value should have been updated to banana, was " + FOO];
|
||||
}
|
||||
|
||||
- (void)testBindOptions
|
||||
@@ -164,7 +164,7 @@
|
||||
[tableColumn bind:@"value" toObject:arrayController withKeyPath:@"arrangedObjects.valueA" options:nil];
|
||||
|
||||
// Reset these if they were read during initialization.
|
||||
for(var i=0; i<[content count];i++)
|
||||
for (var i = 0; i < [content count]; i++)
|
||||
[content[i] setAccesses:0];
|
||||
var testView = [DataViewTester new];
|
||||
[tableColumn prepareDataView:testView forRow:0];
|
||||
@@ -190,6 +190,29 @@
|
||||
[self assert:'value' equals:testView.lastKey];
|
||||
}
|
||||
|
||||
- (void)testTextField
|
||||
{
|
||||
var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
[textField setPlaceholderString:@"cheese"];
|
||||
|
||||
|
||||
content = [
|
||||
[BindingTester testerWithCheese:@"yellow"],
|
||||
[BindingTester testerWithCheese:@"green"]
|
||||
];
|
||||
arrayController = [[CPArrayController alloc] initWithContent:content];
|
||||
|
||||
[arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, 2)]];
|
||||
|
||||
var options = [CPDictionary dictionaryWithJSObject:{CPMultipleValuesPlaceholderBindingOption:@"Multiple Values"}];
|
||||
[textField bind:@"value" toObject:arrayController withKeyPath:@"selection.cheese" options:options];
|
||||
|
||||
[self assert:@"Multiple Values" equals:[textField placeholderString]];
|
||||
|
||||
[arrayController setSelectionIndex:0];
|
||||
[self assert:@"cheese" equals:[textField placeholderString]];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext
|
||||
{
|
||||
CPLog(@"here: "+aKeyPath+" value: "+[anObject valueForKey:aKeyPath]);
|
||||
@@ -202,6 +225,13 @@
|
||||
id cheese;
|
||||
}
|
||||
|
||||
+ (id)testerWithCheese:(id)aCheese
|
||||
{
|
||||
var tester = [[self alloc] init];
|
||||
[tester setCheese:aCheese];
|
||||
return tester;
|
||||
}
|
||||
|
||||
- (void)setCheese:(id)aCheese
|
||||
{
|
||||
cheese = aCheese;
|
||||
@@ -242,7 +272,7 @@
|
||||
CPNumber accesses @accessors;
|
||||
}
|
||||
|
||||
+ (AccessCounter) counterWithValueA:aValue valueB:anotherValue
|
||||
+ (AccessCounter)counterWithValueA:aValue valueB:anotherValue
|
||||
{
|
||||
r = [self new];
|
||||
[r setValueA:aValue];
|
||||
|
||||
Reference in New Issue
Block a user