35 - (BOOL)tokenField:(
CPTokenField)tokenField hasMenuForRepresentedObject:(
id)representedObject;
36 - (CPArray)tokenField:(
CPTokenField)tokenField completionsForSubstring:(
CPString)substring indexOfToken:(CPInteger)tokenIndex indexOfSelectedItem:(CPInteger)selectedIndex;
37 - (CPArray)tokenField:(
CPTokenField)tokenField shouldAddObjects:(CPArray)tokens atIndex:(CPUInteger)index;
38 - (
CPMenu)tokenField:(
CPTokenField)tokenField menuForRepresentedObject:(
id)representedObject;
39 - (
CPString )tokenField:(
CPTokenField)tokenField displayStringForRepresentedObject:(
id)representedObject;
40 - (id)tokenField:(
CPTokenField)tokenField representedObjectForEditingString:(
CPString)editingString;
54 var CPTokenFieldDOMInputElement = nil,
55 CPTokenFieldDOMPasswordInputElement = nil,
56 CPTokenFieldDOMStandardInputElement = nil,
57 CPTokenFieldInputOwner = nil,
58 CPTokenFieldTextDidChangeValue = nil,
59 CPTokenFieldInputResigning = NO,
60 CPTokenFieldInputDidBlur = NO,
61 CPTokenFieldInputIsActive = NO,
62 CPTokenFieldCachedSelectStartFunction = nil,
63 CPTokenFieldCachedDragFunction = nil,
64 CPTokenFieldFocusInput = NO,
66 CPTokenFieldBlurHandler = nil;
82 CPRange _selectedRange;
84 _CPAutocompleteMenu _autocompleteMenu;
87 CPTimeInterval _completionDelay;
93 BOOL _shouldNotifyTarget;
97 id <CPTokenFieldDelegate> _tokenFieldDelegate;
98 unsigned _implementedTokenFieldDelegateMethods;
106 + (CPTimeInterval)defaultCompletionDelay
118 return @{
@"editor-inset": CGInsetMakeZero() };
121 - (id)initWithFrame:(CGRect)frame
123 if (
self = [super initWithFrame:
frame])
125 _completionDelay = [[
self class] defaultCompletionDelay];
126 _tokenizingCharacterSet = [[
self class] defaultTokenizingCharacterSet];
144 var
frame = [
self frame];
146 _tokenScrollView = [[
CPScrollView alloc] initWithFrame:CGRectMakeZero()];
147 [_tokenScrollView setHasHorizontalScroller:NO];
148 [_tokenScrollView setHasVerticalScroller:NO];
149 [_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
151 var contentView = [[
CPView alloc] initWithFrame:CGRectMakeZero()];
152 [contentView setAutoresizingMask:CPViewWidthSizable];
153 [_tokenScrollView setDocumentView:contentView];
155 [
self addSubview:_tokenScrollView];
159 #pragma mark Delegate methods 164 - (void)setDelegate:(
id <CPTokenFieldDelegate>)aDelegate
166 if (_tokenFieldDelegate === aDelegate)
169 _tokenFieldDelegate = aDelegate;
170 _implementedTokenFieldDelegateMethods = 0;
172 if ([_tokenFieldDelegate respondsToSelector:
@selector(tokenField:hasMenuForRepresentedObject:)])
175 if ([_tokenFieldDelegate respondsToSelector:
@selector(tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem:)])
178 if ([_tokenFieldDelegate respondsToSelector:
@selector(tokenField:shouldAddObjects:atIndex:)])
181 if ([_tokenFieldDelegate respondsToSelector:
@selector(tokenField:menuForRepresentedObject:)])
184 if ([_tokenFieldDelegate respondsToSelector:
@selector(tokenField:displayStringForRepresentedObject:)])
187 if ([_tokenFieldDelegate respondsToSelector:
@selector(tokenField:representedObjectForEditingString:)])
193 - (_CPAutocompleteMenu)_autocompleteMenu
195 if (!_autocompleteMenu)
196 _autocompleteMenu = [[_CPAutocompleteMenu alloc] initWithTextField:self];
197 return _autocompleteMenu;
200 - (void)_complete:(_CPAutocompleteMenu)anAutocompleteMenu
202 [
self _autocompleteWithEvent:nil];
205 - (void)_autocompleteWithEvent:(
CPEvent)anEvent
210 [
self _hideCompletions];
212 var token = [_autocompleteMenu selectedItem],
213 shouldRemoveLastObject = token !==
@"" && [
self _editorValue] !==
@"";
216 token = [
self _editorValue];
221 if (!token || token ===
@"")
229 [[
self window] selectNextKeyView:self];
231 [[
self window] selectPreviousKeyView:self];
234 [[
self window] makeFirstResponder:nil];
238 var objectValue = [
self objectValue];
242 if (shouldRemoveLastObject)
243 [objectValue removeObjectAtIndex:_selectedRange.location];
246 token = [
self _representedObjectForEditingString:token];
249 var delegateApprovedObjects = [
self _shouldAddObjects:[CPArray arrayWithObject:token] atIndex:_selectedRange.location],
250 delegateApprovedObjectsCount = [delegateApprovedObjects count];
252 if (delegateApprovedObjects)
254 for (var i = 0; i < delegateApprovedObjectsCount; i++)
256 [objectValue insertObject:[delegateApprovedObjects objectAtIndex:i] atIndex:_selectedRange.location + i];
261 var location = _selectedRange.location;
263 [
self setObjectValue:objectValue];
265 if (delegateApprovedObjectsCount)
266 location += delegateApprovedObjectsCount;
269 [
self _inputElement].value =
@"";
270 [
self setNeedsLayout];
272 [
self _controlTextDidChange];
275 - (void)_autocomplete
277 [
self _autocompleteWithEvent:nil];
280 - (void)_selectToken:(_CPTokenFieldToken)token byExtendingSelection:(BOOL)extend
282 var indexOfToken = [[
self _tokens] indexOfObject:token];
287 _selectedRange =
CPMakeRange([[
self _tokens] count], 0);
294 [
self setNeedsLayout];
297 - (void)_deselectToken:(_CPTokenFieldToken)token
299 var indexOfToken = [[
self _tokens] indexOfObject:token];
302 _selectedRange =
CPMakeRange(MAX(indexOfToken, _selectedRange.location), MIN(_selectedRange.length, indexOfToken - _selectedRange.location));
304 [
self setNeedsLayout];
307 - (void)_deleteToken:(_CPTokenFieldToken)token
309 var indexOfToken = [[
self _tokens] indexOfObject:token],
310 objectValue = [
self objectValue];
314 if (indexOfToken < _selectedRange.location)
315 _selectedRange.location--;
317 [
self _deselectToken:token];
322 [objectValue removeObjectAtIndex:indexOfToken];
323 [
self setObjectValue:objectValue];
324 _selectedRange = selection;
326 [
self setNeedsLayout];
327 [
self _controlTextDidChange];
330 - (void)_controlTextDidChange
332 var binderClass = [[
self class] _binderClassForBinding:CPValueBinding],
333 theBinding = [binderClass getBinding:CPValueBinding forObject:self];
336 [theBinding reverseSetValueFor:@"objectValue"];
340 _shouldNotifyTarget = YES;
343 - (void)_removeSelectedTokens:(
id)sender
345 var tokens = [
self objectValue];
347 for (var i = _selectedRange.length - 1; i >= 0; i--)
348 [tokens removeObjectAtIndex:_selectedRange.location + i];
350 var collapsedSelection = _selectedRange.location;
352 [
self setObjectValue:tokens];
355 _selectedRange =
CPMakeRange(collapsedSelection, 0);
357 [
self _controlTextDidChange];
360 - (void)_updatePlaceholderState
363 [
self setThemeState:CPTextFieldStatePlaceholder];
365 [
self unsetThemeState:CPTextFieldStatePlaceholder];
372 - (BOOL)becomeFirstResponder
374 if (![super becomeFirstResponder])
378 if (CPTokenFieldInputOwner && [CPTokenFieldInputOwner window] !== [
self window])
379 [[CPTokenFieldInputOwner window] makeFirstResponder:nil];
383 [
self _setObserveWindowKeyNotifications:YES];
387 if ([[
self window] isKeyWindow])
388 return [
self _becomeFirstKeyResponder];
393 - (BOOL)_becomeFirstKeyResponder
397 if (![
self _isWithinUsablePlatformRect])
400 [
self setThemeState:CPThemeStateEditing];
402 [
self _updatePlaceholderState];
404 [
self setNeedsLayout];
408 var
string = [
self stringValue],
409 element = [
self _inputElement],
410 font = [
self currentValueForThemeAttribute:@"font"];
413 element.style.color = [[
self currentValueForThemeAttribute:@"text-color"] cssString];
414 element.style.font = [font cssString];
415 element.style.zIndex = 1000;
417 switch ([
self alignment])
420 element.style.textAlign =
"center";
424 element.style.textAlign =
"right";
428 element.style.textAlign =
"left";
431 var contentRect = [
self contentRectForBounds:[
self bounds]];
433 element.style.top = CGRectGetMinY(contentRect) + "px";
434 element.style.left = (CGRectGetMinX(contentRect) - 1) + "px";
435 element.style.width = CGRectGetWidth(contentRect) + "px";
436 element.style.height = [font defaultLineHeightForFont] + "px";
440 [_tokenScrollView documentView]._DOMElement.appendChild(element);
448 var previousScrollingOrigin = [
self _scrollToVisibleRectAndReturnPreviousOrigin];
452 [
self _restorePreviousScrollingOrigin:previousScrollingOrigin];
454 CPTokenFieldInputOwner = self;
460 [[[
self window] platformWindow] _propagateCurrentDOMEvent:YES];
462 CPTokenFieldInputIsActive = YES;
464 if (document.attachEvent)
466 CPTokenFieldCachedSelectStartFunction = document.body.onselectstart;
467 CPTokenFieldCachedDragFunction = document.body.ondrag;
469 document.body.ondrag =
function () {};
470 document.body.onselectstart =
function () {};
478 - (BOOL)resignFirstResponder
480 [
self _autocomplete];
483 [
self _setObserveWindowKeyNotifications:NO];
485 [
self _resignFirstKeyResponder];
487 if (_shouldNotifyTarget)
489 _shouldNotifyTarget = NO;
492 if ([
self sendsActionOnEndEditing])
501 - (void)_resignFirstKeyResponder
503 [
self unsetThemeState:CPThemeStateEditing];
505 [
self _updatePlaceholderState];
506 [
self setNeedsLayout];
510 var element = [
self _inputElement];
512 CPTokenFieldInputResigning = YES;
514 if (CPTokenFieldInputIsActive)
517 if (!CPTokenFieldInputDidBlur)
518 CPTokenFieldBlurHandler();
520 if (element.parentNode == [_tokenScrollView documentView]._DOMElement)
521 element.parentNode.removeChild(element);
529 CPTokenFieldInputDidBlur = NO;
530 CPTokenFieldInputResigning = NO;
532 CPTokenFieldInputIsActive = NO;
534 if (document.attachEvent)
536 CPTokenFieldCachedSelectStartFunction = nil;
537 CPTokenFieldCachedDragFunction = nil;
539 document.body.ondrag = CPTokenFieldCachedDragFunction;
540 document.body.onselectstart = CPTokenFieldCachedSelectStartFunction
548 _mouseDownEvent = anEvent;
550 [
self _selectToken:nil byExtendingSelection:NO];
557 _mouseDownEvent = nil;
560 - (void)_mouseDownOnToken:(_CPTokenFieldToken)aToken withEvent:(
CPEvent)anEvent
562 _mouseDownEvent = anEvent;
565 - (void)_mouseUpOnToken:(_CPTokenFieldToken)aToken withEvent:(
CPEvent)anEvent
567 if (_mouseDownEvent && CGPointEqualToPoint([_mouseDownEvent locationInWindow], [anEvent locationInWindow]))
569 [
self _selectToken:aToken byExtendingSelection:[anEvent
modifierFlags] & CPShiftKeyMask];
570 [[
self window] makeFirstResponder:self];
572 _shouldScrollTo = aToken;
583 return [
super objectValue];
588 return [[
self objectValue] componentsJoinedByString:@","];
593 var objectValue = [];
595 for (var i = 0, count = [[
self _tokens] count]; i < count; i++)
597 var token = [[
self _tokens] objectAtIndex:i];
599 if ([token isKindOfClass:[
CPString class]])
602 [objectValue addObject:[token representedObject]];
607 if ([
self _editorValue])
609 var token = [
self _representedObjectForEditingString:[
self _editorValue]];
610 [objectValue insertObject:token atIndex:_selectedRange.location];
618 - (void)setObjectValue:(
id)aValue
620 if (aValue !== nil && ![aValue isKindOfClass:[CPArray
class]])
627 if (aValue === superValue || [aValue isEqualToArray:superValue])
630 var contentView = [_tokenScrollView documentView],
631 oldTokens = [
self _tokens],
637 for (var i = 0, count = [aValue count]; i < count; i++)
640 var tokenObject = aValue[i],
641 tokenValue = [
self _displayStringForRepresentedObject:tokenObject],
644 for (var j = 0, oldCount = [oldTokens count]; j < oldCount; j++)
646 var oldToken = oldTokens[j];
647 if ([oldToken representedObject] == tokenObject)
650 [oldTokens removeObjectAtIndex:j];
656 if (newToken === nil)
658 newToken = [_CPTokenFieldToken new];
659 [newToken setTokenField:self];
660 [newToken setRepresentedObject:tokenObject];
661 [newToken setStringValue:tokenValue];
663 [contentView addSubview:newToken];
666 newTokens.push(newToken);
671 for (var j = 0, oldCount = [oldTokens count]; j < oldCount; j++)
672 [oldTokens[j] removeFromSuperview];
685 [
self _selectToken:nil byExtendingSelection:NO];
687 [
self _updatePlaceholderState];
694 - (void)setEnabled:(BOOL)shouldBeEnabled
699 for (var i = 0, count = [[
self _tokens] count]; i < count; i++)
701 var token = [[
self _tokens] objectAtIndex:i];
703 if ([token respondsToSelector:
@selector(setEnabled:)])
704 [token setEnabled:shouldBeEnabled];
708 - (void)setEditable:(BOOL)shouldBeEditable
712 [[
self _tokens] makeObjectsPerformSelector:@selector(setEditable:) withObject:shouldBeEditable];
715 - (BOOL)sendAction:(
SEL)anAction to:(
id)anObject
717 _shouldNotifyTarget = NO;
723 - (BOOL)_setStringValue:(
CPString)aValue
731 - (DOMElement)_inputElement
733 if (!CPTokenFieldDOMInputElement)
735 CPTokenFieldDOMInputElement = document.createElement(
"input");
736 CPTokenFieldDOMInputElement.style.position =
"absolute";
737 CPTokenFieldDOMInputElement.style.border =
"0px";
738 CPTokenFieldDOMInputElement.style.padding =
"0px";
739 CPTokenFieldDOMInputElement.style.margin =
"0px";
740 CPTokenFieldDOMInputElement.style.whiteSpace =
"pre";
741 CPTokenFieldDOMInputElement.style.background =
"transparent";
742 CPTokenFieldDOMInputElement.style.outline =
"none";
744 CPTokenFieldBlurHandler =
function(anEvent)
748 CPTokenFieldInputOwner,
749 CPTokenFieldInputOwner ? [CPTokenFieldInputOwner._tokenScrollView documentView]._DOMElement : nil,
750 CPTokenFieldDOMInputElement,
751 CPTokenFieldInputResigning,
752 @ref(CPTokenFieldInputDidBlur));
756 CPTokenFieldDOMInputElement.onblur = CPTokenFieldBlurHandler;
758 CPTokenFieldDOMStandardInputElement = CPTokenFieldDOMInputElement;
763 if ([CPTokenFieldInputOwner isSecure])
764 CPTokenFieldDOMInputElement.type =
"password";
766 CPTokenFieldDOMInputElement.type =
"text";
768 return CPTokenFieldDOMInputElement;
771 return CPTokenFieldDOMInputElement;
779 return [
self _inputElement].value;
782 - (void)moveUp:(
id)sender
784 [[
self _autocompleteMenu] selectPrevious];
788 - (void)moveDown:(
id)sender
790 [[
self _autocompleteMenu] selectNext];
794 - (void)insertNewline:(
id)sender
798 [
self _autocompleteWithEvent:[CPApp currentEvent]];
807 - (void)insertTab:(
id)sender
809 var anEvent = [CPApp currentEvent];
812 [
self _autocompleteWithEvent:anEvent];
829 if ([_tokenizingCharacterSet characterIsMember:[characters substringToIndex:1]])
831 [
self _autocompleteWithEvent:[CPApp currentEvent]];
836 if (_selectedRange.length)
838 [
self _removeSelectedTokens:self];
853 - (void)cancelOperation:(
id)sender
855 [
self _hideCompletions];
858 - (void)moveLeft:(
id)sender
861 if ((_selectedRange.location > 0 || _selectedRange.length) && [
self _editorValue] ==
"")
863 if (_selectedRange.length)
865 _selectedRange.length = 0;
867 _selectedRange.location--;
878 - (void)moveLeftAndModifySelection:(
id)sender
880 if (_selectedRange.location > 0 && [
self _editorValue] ==
"")
882 _selectedRange.location--;
884 _selectedRange.length++;
895 - (void)moveRight:(
id)sender
898 if ((_selectedRange.location < [[
self _tokens] count] || _selectedRange.length) && [
self _editorValue] ==
"")
900 if (_selectedRange.length)
903 _selectedRange.location =
CPMaxRange(_selectedRange);
904 _selectedRange.length = 0;
909 _selectedRange.location = MIN([[
self _tokens] count], _selectedRange.location + _selectedRange.length + 1);
922 - (void)moveRightAndModifySelection:(
id)sender
924 if (
CPMaxRange(_selectedRange) < [[
self _tokens] count] && [
self _editorValue] ==
"")
927 _selectedRange.length++;
938 - (void)deleteBackward:(
id)sender
942 if ([
self _editorValue] ==
@"")
944 [
self _hideCompletions];
948 if (_selectedRange.location > 0)
950 var tokenView = [[
self _tokens] objectAtIndex:(_selectedRange.location - 1)];
951 [
self _selectToken:tokenView byExtendingSelection:NO];
955 [
self _removeSelectedTokens:nil];
964 - (void)deleteForward:(
id)sender
968 if ([
self _editorValue] ==
@"")
971 [
self _hideCompletions];
975 if (_selectedRange.location < [[
self _tokens] count])
976 [
self _deleteToken:[[
self _tokens] objectAtIndex:[_selectedRange.location]]];
979 [
self _removeSelectedTokens:nil];
988 - (void)_selectText:(
id)sender immediately:(BOOL)immediately
997 if (([
self isEditable] || [
self isSelectable]))
999 [
super _selectText:sender immediately:immediately];
1002 [
self _autocomplete];
1003 _selectedRange =
CPMakeRange(0, [[
self _tokens] count]);
1005 [
self setNeedsLayout];
1012 CPTokenFieldTextDidChangeValue = [
self stringValue];
1020 [
self interpretKeyEvents:[anEvent]];
1028 if ([
self stringValue] !== CPTokenFieldTextDidChangeValue)
1054 if ([aNotification
object] !==
self)
1060 [
self _delayedShowCompletions];
1062 _selectedRange.length = 0;
1075 - (void)setCompletionDelay:(CPTimeInterval)delay
1077 _completionDelay = delay;
1080 - (CPTimeInterval)completionDelay
1082 return _completionDelay;
1088 - (void)layoutSubviews
1098 if (textFieldContentView)
1099 [textFieldContentView setHidden:[
self stringValue] !== @""];
1102 contentView = [_tokenScrollView documentView],
1103 tokens = [
self _tokens];
1106 if (![tokens isKindOfClass:[CPArray
class]])
1110 var contentRect = CGRectMakeCopy([contentView
bounds]),
1111 contentOrigin = contentRect.origin,
1112 contentSize = contentRect.size,
1113 offset = CGPointMake(contentOrigin.x, contentOrigin.y),
1114 spaceBetweenTokens = CGSizeMake(2.0, 2.0),
1116 tokenToken = [_CPTokenFieldToken new],
1117 font = [
self currentValueForThemeAttribute:@"font"],
1119 editorInset = [
self currentValueForThemeAttribute:@"editor-inset"];
1122 offset.y += CEIL(spaceBetweenTokens.height / 2.0);
1125 [tokenToken sizeToFit];
1127 var tokenHeight = CGRectGetHeight([tokenToken
bounds]);
1129 var fitAndFrame =
function(
width, height)
1131 var r = CGRectMake(0, 0,
width, height);
1133 if (offset.x +
width >= contentSize.width && offset.x > contentOrigin.x)
1135 offset.x = contentOrigin.x;
1136 offset.y += height + spaceBetweenTokens.height;
1139 r.origin.x = offset.x;
1140 r.origin.y = offset.y;
1143 var scrollHeight = offset.y + tokenHeight + CEIL(spaceBetweenTokens.height / 2.0);
1144 if (CGRectGetHeight([contentView
bounds]) < scrollHeight)
1145 [contentView setFrameSize:CGSizeMake(CGRectGetWidth([_tokenScrollView bounds]), scrollHeight)];
1147 offset.x +=
width + spaceBetweenTokens.width;
1152 var placeEditor =
function(useRemainingWidth)
1154 var element = [
self _inputElement],
1157 if (_selectedRange.length === 0)
1162 textWidth = [(element.value || @"") + "X" sizeWithFont:font].width;
1164 if (useRemainingWidth)
1165 textWidth = MAX(contentSize.width - offset.x - 1, textWidth);
1168 _inputFrame = fitAndFrame(textWidth, tokenHeight);
1170 _inputFrame.size.height = lineHeight;
1172 element.style.left = (_inputFrame.origin.x + editorInset.left) +
"px";
1173 element.style.top = (_inputFrame.origin.y + editorInset.top) +
"px";
1174 element.style.width = _inputFrame.size.width +
"px";
1175 element.style.height = _inputFrame.size.height +
"px";
1178 if (_selectedRange.length == 0)
1179 [[_tokenScrollView documentView] scrollPoint:CGPointMake(0, _inputFrame.origin.y)];
1182 for (var i = 0, count = [tokens count]; i < count; i++)
1184 if (isEditing && !_selectedRange.length && i ==
CPMaxRange(_selectedRange))
1187 var tokenView = [tokens objectAtIndex:i];
1190 if ([tokenView isKindOfClass:[
CPString class]])
1193 [tokenView setHighlighted:CPLocationInRange(i, _selectedRange)];
1194 [tokenView sizeToFit];
1196 var size = [contentView bounds].size,
1197 tokenViewSize = [tokenView bounds].size,
1198 tokenFrame = fitAndFrame(tokenViewSize.width, tokenViewSize.height);
1200 [tokenView setFrame:tokenFrame];
1202 [tokenView setButtonType:_buttonType];
1205 if (isEditing && !_selectedRange.length &&
CPMaxRange(_selectedRange) >= [tokens count])
1210 if (isEditing && _selectedRange.length)
1213 var inputElement = [
self _inputElement];
1214 inputElement.style.display =
"none";
1218 var inputElement = [
self _inputElement];
1219 inputElement.style.display =
"block";
1220 if (document.activeElement !== inputElement)
1221 inputElement.focus();
1225 var scrollHeight = offset.y + tokenHeight;
1226 if (CGRectGetHeight([contentView
bounds]) > scrollHeight)
1227 [contentView setFrameSize:CGSizeMake(CGRectGetWidth([_tokenScrollView bounds]), scrollHeight)];
1232 if (!(isEditing && _selectedRange.length == 0))
1234 var scrollToToken = _shouldScrollTo;
1237 scrollToToken = tokens[_selectedRange.location];
1239 scrollToToken = tokens[MAX(0, CPMaxRange(_selectedRange) - 1)];
1240 [
self _scrollTokenViewToVisible:scrollToToken];
1247 - (BOOL)_scrollTokenViewToVisible:(_CPTokenFieldToken)aToken
1252 return [[_tokenScrollView documentView] scrollPoint:CGPointMake(0, [aToken frameOrigin].y)];
1268 - (CPArray)_completionsForSubstring:(
CPString)substring indexOfToken:(
int)tokenIndex indexOfSelectedItem:(
int)selectedIndex
1273 return [_tokenFieldDelegate tokenField:self completionsForSubstring:substring indexOfToken:tokenIndex indexOfSelectedItem:selectedIndex];
1279 - (CGPoint)_completionOrigin:(_CPAutocompleteMenu)anAutocompleteMenu
1281 var relativeFrame = _inputFrame ? [[_tokenScrollView documentView] convertRect:_inputFrame toView:self ] : [
self bounds];
1283 return CGPointMake(CGRectGetMinX(relativeFrame), CGRectGetMaxY(relativeFrame));
1294 - (
CPString)_displayStringForRepresentedObject:(
id)representedObject
1298 var stringForRepresentedObject = [_tokenFieldDelegate tokenField:self displayStringForRepresentedObject:representedObject];
1300 if (stringForRepresentedObject !== nil)
1301 return stringForRepresentedObject;
1304 return representedObject;
1316 - (CPArray)_shouldAddObjects:(CPArray)tokens atIndex:(
int)index
1320 var approvedObjects = [_tokenFieldDelegate tokenField:self shouldAddObjects:tokens atIndex:index];
1322 if (approvedObjects !== nil)
1323 return approvedObjects;
1338 - (id)_representedObjectForEditingString:(
CPString)aString
1342 var token = [_tokenFieldDelegate tokenField:self representedObjectForEditingString:aString];
1344 if (token !== nil && token !== undefined)
1353 - (BOOL)_hasMenuForRepresentedObject:(
id)aRepresentedObject
1357 return [_tokenFieldDelegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
1362 - (
CPMenu)_menuForRepresentedObject:(
id)aRepresentedObject
1367 var hasMenu = [_tokenFieldDelegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
1370 return [_tokenFieldDelegate tokenField:self menuForRepresentedObject:aRepresentedObject] || nil;
1390 - (void)_delayedShowCompletions
1392 [[
self _autocompleteMenu] _delayedShowCompletions];
1395 - (void)_hideCompletions
1397 [_autocompleteMenu _hideCompletions];
1401 - (void)setButtonType:(
int)aButtonType
1403 if (_buttonType === aButtonType)
1406 _buttonType = aButtonType;
1414 _CPTokenFieldTokenCloseButton _deleteButton;
1415 _CPTokenFieldTokenDisclosureButton _disclosureButton;
1417 id _representedObject;
1423 return "tokenfield-token";
1426 - (BOOL)acceptsFirstResponder
1431 - (id)initWithFrame:(CGRect)frame
1433 if (
self = [super initWithFrame:
frame])
1435 [
self setEditable:NO];
1436 [
self setHighlighted:NO];
1437 [
self setBezeled:YES];
1438 [
self setButtonType:CPTokenFieldDisclosureButtonType];
1451 _tokenField = tokenField;
1454 - (id)representedObject
1456 return _representedObject;
1459 - (void)setRepresentedObject:(
id)representedObject
1461 _representedObject = representedObject;
1462 [
self setNeedsLayout];
1465 - (void)setEditable:(BOOL)shouldBeEditable
1467 [
super setEditable:shouldBeEditable];
1468 [
self setNeedsLayout];
1473 var r = [
super setThemeState:aState];
1478 [_disclosureButton setThemeState:CPThemeStateHovered];
1479 [_deleteButton setThemeState:CPThemeStateHovered];
1487 var r = [
super unsetThemeState:aState];
1492 [_disclosureButton unsetThemeState:CPThemeStateHovered];
1493 [_deleteButton unsetThemeState:CPThemeStateHovered];
1499 - (CGSize)_minimumFrameSize
1501 var size = CGSizeMakeZero(),
1502 minSize = [
self currentValueForThemeAttribute:@"min-size"],
1503 contentInset = [
self currentValueForThemeAttribute:@"content-inset"];
1506 size.height = minSize.height;
1507 size.width = MAX(minSize.width, [([
self stringValue] ||
@" ") sizeWithFont:[
self font]].width + contentInset.left + contentInset.right);
1512 - (void)setButtonType:(
int)aButtonType
1514 if (_buttonType === aButtonType)
1517 _buttonType = aButtonType;
1523 [_deleteButton removeFromSuperview];
1524 _deleteButton = nil;
1527 if (!_disclosureButton)
1529 _disclosureButton = [[_CPTokenFieldTokenDisclosureButton alloc] initWithFrame:CGRectMakeZero()];
1530 [
self addSubview:_disclosureButton];
1535 if (_disclosureButton)
1537 [_disclosureButton removeFromSuperview];
1538 _disclosureButton = nil;
1543 _deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CGRectMakeZero()];
1544 [
self addSubview:_deleteButton];
1545 [_deleteButton setTarget:self];
1546 [_deleteButton setAction:@selector(_delete:)];
1550 [
self setNeedsLayout];
1553 - (void)layoutSubviews
1555 [
super layoutSubviews];
1557 var bezelView = [
self layoutEphemeralSubviewNamed:@"bezel-view"
1558 positioned:CPWindowBelow
1559 relativeToEphemeralSubviewNamed:@"content-view"];
1561 if (bezelView && _tokenField)
1563 switch (_buttonType)
1566 var shouldBeEnabled = [
self hasMenu];
1567 [_disclosureButton setHidden:!shouldBeEnabled];
1569 if (shouldBeEnabled)
1570 [_disclosureButton setMenu:[
self menu]];
1572 var
frame = [bezelView frame],
1573 buttonOffset = [_disclosureButton currentValueForThemeAttribute:@"offset"],
1574 buttonSize = [_disclosureButton currentValueForThemeAttribute:@"min-size"];
1576 [_disclosureButton setFrame:CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
1579 [_deleteButton setEnabled:[
self isEditable] && [
self isEnabled]];
1581 var
frame = [bezelView frame],
1582 buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"],
1583 buttonSize = [_deleteButton currentValueForThemeAttribute:@"min-size"];
1585 [_deleteButton setFrame:CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
1591 - (void)mouseDown:(
CPEvent)anEvent
1593 [_tokenField _mouseDownOnToken:self withEvent:anEvent];
1596 - (void)mouseUp:(
CPEvent)anEvent
1598 [_tokenField _mouseUpOnToken:self withEvent:anEvent];
1601 - (void)_delete:(
id)sender
1603 if ([
self isEditable])
1604 [_tokenField _deleteToken:self];
1609 return [_tokenField _hasMenuForRepresentedObject:_representedObject];
1614 return [_tokenField _menuForRepresentedObject:_representedObject];
1618 @implementation _CPTokenFieldTokenCloseButton :
CPButton 1627 [attributes setObject:CGPointMake(15, 5) forKey:@"offset"];
1634 return "tokenfield-token-close-button";
1637 - (void)mouseEntered:(
CPEvent)anEvent
1642 - (void)mouseExited:(
CPEvent)anEvent
1648 @implementation _CPTokenFieldTokenDisclosureButton :
CPPopUpButton 1657 [attributes setObject:CGPointMake(15, 5) forKey:@"offset"];
1664 return "tokenfield-token-disclosure-button";
1667 - (id)initWithFrame:(CGRect)aFrame
1669 if (
self = [
self initWithFrame:aFrame pullsDown:YES])
1671 [
self setBordered:YES];
1672 [
super setTitle:@""];
1683 - (void)synchronizeTitleAndSelectedItem
1688 - (void)mouseEntered:(
CPEvent)anEvent
1693 - (void)mouseExited:(
CPEvent)anEvent
1713 _tokenizingCharacterSet = [aCoder decodeObjectForKey:CPTokenFieldTokenizingCharacterSetKey] || [[
self class] defaultTokenizingCharacterSet];
1714 _completionDelay = [aCoder decodeDoubleForKey:CPTokenFieldCompletionDelayKey] || [[
self class] defaultCompletionDelay];
1730 [aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
1731 [aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
1732 [aCoder encodeInt:_buttonType forKey:CPTokenFieldButtonTypeKey];
1744 return _tokenizingCharacterSet;
1752 _tokenizingCharacterSet = aValue;
1766 - (void)setButtonType:(
int)aValue
1768 _buttonType = aValue;
BOOL makeFirstResponder:(CPResponder aResponder)
function CPUnionRange(lhsRange, rhsRange)
void encodeWithCoder:(CPCoder aCoder)
float defaultLineHeightForFont()
void textDidChange:(CPNotification note)
var CPScrollDestinationRight
var CPTokenFieldDelegate_tokenField_menuForRepresentedObject_
The main run loop for the application.
CPThemeStateAutocompleting
CPResponder firstResponder()
var CPTokenFieldTokenizingCharacterSetKey
var CPTokenFieldDelegate_tokenField_displayStringForRepresentedObject_
CPTextFieldDidBlurNotification
CPString charactersIgnoringModifiers()
var CPTokenFieldDelegate_tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem_
var CPTokenFieldCompletionDelayKey
var CPTokenFieldDelegate_tokenField_representedObjectForEditingString_
A mutable key-value pair collection.
id characterSetWithCharactersInString:(CPString aString)
function ThemeState(stateNames)
void setEnabled:(BOOL shouldBeEnabled)
CPRunLoop currentRunLoop()
void setEditable:(BOOL shouldBeEditable)
void textDidBlur:(CPNotification note)
function CPEmptyRange(aRange)
function CPMaxRange(aRange)
An immutable string (collection of characters).
void keyDown:(CPEvent anEvent)
BOOL sendAction:to:(SEL anAction, [to] id anObject)
function CPFeatureIsCompatible(aFeature)
void setObjectValue:(id aValue)
void performBlock:argument:order:modes:(Function aBlock, [argument] id anArgument, [order] int anOrder, [modes] CPArray modes)
void selectNextKeyView:(id sender)
BOOL performKeyEquivalent:(CPEvent anEvent)
void setNeedsDisplay:(BOOL aFlag)
CGRect rectForEphemeralSubviewNamed:(CPString aName)
var CPTokenFieldButtonTypeKey
A notification that can be posted to a CPNotificationCenter.
CPDate limitDateForMode:(CPString aMode)
void setObjectValue:(id aValue)
CPTokenFieldDeleteButtonType
var CPTokenFieldDelegate_tokenField_hasMenuForRepresentedObject_
function CPMakeRangeCopy(aRange)
Defines methods for use when archiving & restoring (enc/decoding).
CPInputTypeCanBeChangedFeature
var CPScrollDestinationLeft
function CPLocationInRange(aLocation, aRange)
void selectPreviousKeyView:(id sender)
CPNotification notificationWithName:object:userInfo:(CPString aNotificationName, [object] id anObject, [userInfo] CPDictionary aUserInfo)
void mouseDown:(CPEvent anEvent)
void setBezeled:(BOOL shouldBeBezeled)
void textDidEndEditing:(CPNotification note)
CPCarriageReturnCharacter
BOOL sendAction:to:(SEL anAction, [to] id anObject)
var CPScrollDestinationNone
CPPlatformWindow platformWindow()
var CPTokenFieldDelegate_tokenField_shouldAddObjects_atIndex_
CPTokenFieldDisclosureButtonType
CPTextFieldDidFocusNotification
BOOL scrollRectToVisible:(CGRect aRect)
id initWithCoder:(CPCoder aCoder)
void setDelegate:(id< CPTextFieldDelegate > aDelegate)
CPRange function CPMakeRange(location, length)
function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resigning, didBlurRef)
CPView layoutEphemeralSubviewNamed:positioned:relativeToEphemeralSubviewNamed:(CPString aViewName, [positioned] CPWindowOrderingMode anOrderingMode, [relativeToEphemeralSubviewNamed] CPString relativeToViewName)
void textDidChange:(CPNotification aNotification)