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];
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
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";
438 window.setTimeout(
function()
440 [_tokenScrollView documentView]._DOMElement.appendChild(element);
445 window.setTimeout(
function()
448 CPTokenFieldInputOwner =
self;
454 [[[
self window] platformWindow] _propagateCurrentDOMEvent:YES];
456 CPTokenFieldInputIsActive = YES;
458 if (document.attachEvent)
460 CPTokenFieldCachedSelectStartFunction = document.body.onselectstart;
461 CPTokenFieldCachedDragFunction = document.body.ondrag;
463 document.body.ondrag =
function () {};
464 document.body.onselectstart =
function () {};
472 - (BOOL)resignFirstResponder
474 [
self _autocomplete];
477 [
self _setObserveWindowKeyNotifications:NO];
479 [
self _resignFirstKeyResponder];
481 if (_shouldNotifyTarget)
483 _shouldNotifyTarget = NO;
486 if ([
self sendsActionOnEndEditing])
495 - (void)_resignFirstKeyResponder
497 [
self unsetThemeState:CPThemeStateEditing];
499 [
self _updatePlaceholderState];
500 [
self setNeedsLayout];
504 var element = [
self _inputElement];
506 CPTokenFieldInputResigning = YES;
509 if (!CPTokenFieldInputDidBlur)
510 CPTokenFieldBlurHandler();
512 CPTokenFieldInputDidBlur = NO;
513 CPTokenFieldInputResigning = NO;
515 if (element.parentNode == [_tokenScrollView documentView]._DOMElement)
516 element.parentNode.removeChild(element);
518 CPTokenFieldInputIsActive = NO;
520 if (document.attachEvent)
522 CPTokenFieldCachedSelectStartFunction = nil;
523 CPTokenFieldCachedDragFunction = nil;
525 document.body.ondrag = CPTokenFieldCachedDragFunction
526 document.body.onselectstart = CPTokenFieldCachedSelectStartFunction
534 _mouseDownEvent = anEvent;
536 [
self _selectToken:nil byExtendingSelection:NO];
543 _mouseDownEvent = nil;
546 - (void)_mouseDownOnToken:(_CPTokenFieldToken)aToken withEvent:(
CPEvent)anEvent
548 _mouseDownEvent = anEvent;
551 - (void)_mouseUpOnToken:(_CPTokenFieldToken)aToken withEvent:(
CPEvent)anEvent
553 if (_mouseDownEvent && CGPointEqualToPoint([_mouseDownEvent locationInWindow], [anEvent locationInWindow]))
555 [
self _selectToken:aToken byExtendingSelection:[anEvent
modifierFlags] & CPShiftKeyMask];
556 [[
self window] makeFirstResponder:self];
558 _shouldScrollTo = aToken;
569 return [
super objectValue];
574 return [[
self objectValue] componentsJoinedByString:@","];
579 var objectValue = [];
581 for (var i = 0, count = [[
self _tokens] count]; i < count; i++)
583 var token = [[
self _tokens] objectAtIndex:i];
585 if ([token isKindOfClass:[
CPString class]])
588 [objectValue addObject:[token representedObject]];
593 if ([
self _editorValue])
595 var token = [
self _representedObjectForEditingString:[
self _editorValue]];
596 [objectValue insertObject:token atIndex:_selectedRange.location];
604 - (void)setObjectValue:(
id)aValue
606 if (aValue !== nil && ![aValue isKindOfClass:[CPArray
class]])
613 if (aValue === superValue || [aValue isEqualToArray:superValue])
616 var contentView = [_tokenScrollView documentView],
617 oldTokens = [
self _tokens],
623 for (var i = 0, count = [aValue count]; i < count; i++)
626 var tokenObject = aValue[i],
627 tokenValue = [
self _displayStringForRepresentedObject:tokenObject],
630 for (var j = 0, oldCount = [oldTokens count]; j < oldCount; j++)
632 var oldToken = oldTokens[j];
633 if ([oldToken representedObject] == tokenObject)
636 [oldTokens removeObjectAtIndex:j];
642 if (newToken === nil)
644 newToken = [_CPTokenFieldToken new];
645 [newToken setTokenField:self];
646 [newToken setRepresentedObject:tokenObject];
647 [newToken setStringValue:tokenValue];
649 [contentView addSubview:newToken];
652 newTokens.push(newToken);
657 for (var j = 0, oldCount = [oldTokens count]; j < oldCount; j++)
658 [oldTokens[j] removeFromSuperview];
671 [
self _selectToken:nil byExtendingSelection:NO];
673 [
self _updatePlaceholderState];
680 - (void)setEnabled:(BOOL)shouldBeEnabled
685 for (var i = 0, count = [[
self _tokens] count]; i < count; i++)
687 var token = [[
self _tokens] objectAtIndex:i];
689 if ([token respondsToSelector:
@selector(setEnabled:)])
690 [token setEnabled:shouldBeEnabled];
694 - (void)setEditable:(BOOL)shouldBeEditable
698 [[
self _tokens] makeObjectsPerformSelector:@selector(setEditable:) withObject:shouldBeEditable];
701 - (BOOL)sendAction:(
SEL)anAction to:(
id)anObject
703 _shouldNotifyTarget = NO;
709 - (BOOL)_setStringValue:(
CPString)aValue
717 - (DOMElement)_inputElement
719 if (!CPTokenFieldDOMInputElement)
721 CPTokenFieldDOMInputElement = document.createElement(
"input");
722 CPTokenFieldDOMInputElement.style.position =
"absolute";
723 CPTokenFieldDOMInputElement.style.border =
"0px";
724 CPTokenFieldDOMInputElement.style.padding =
"0px";
725 CPTokenFieldDOMInputElement.style.margin =
"0px";
726 CPTokenFieldDOMInputElement.style.whiteSpace =
"pre";
727 CPTokenFieldDOMInputElement.style.background =
"transparent";
728 CPTokenFieldDOMInputElement.style.outline =
"none";
730 CPTokenFieldBlurHandler =
function(anEvent)
734 CPTokenFieldInputOwner,
735 CPTokenFieldInputOwner ? [CPTokenFieldInputOwner._tokenScrollView documentView]._DOMElement : nil,
736 CPTokenFieldDOMInputElement,
737 CPTokenFieldInputResigning,
738 @ref(CPTokenFieldInputDidBlur));
742 CPTokenFieldDOMInputElement.onblur = CPTokenFieldBlurHandler;
744 CPTokenFieldDOMStandardInputElement = CPTokenFieldDOMInputElement;
749 if ([CPTokenFieldInputOwner isSecure])
750 CPTokenFieldDOMInputElement.type =
"password";
752 CPTokenFieldDOMInputElement.type =
"text";
754 return CPTokenFieldDOMInputElement;
757 return CPTokenFieldDOMInputElement;
765 return [
self _inputElement].value;
768 - (void)moveUp:(
id)sender
770 [[
self _autocompleteMenu] selectPrevious];
774 - (void)moveDown:(
id)sender
776 [[
self _autocompleteMenu] selectNext];
780 - (void)insertNewline:(
id)sender
782 if ([
self hasThemeState:CPThemeStateAutocompleting])
784 [
self _autocompleteWithEvent:[CPApp currentEvent]];
793 - (void)insertTab:(
id)sender
795 var anEvent = [CPApp currentEvent];
796 if ([
self hasThemeState:CPThemeStateAutocompleting])
798 [
self _autocompleteWithEvent:anEvent];
815 if ([_tokenizingCharacterSet characterIsMember:[characters substringToIndex:1]])
817 [
self _autocompleteWithEvent:[CPApp currentEvent]];
822 if (_selectedRange.length)
824 [
self _removeSelectedTokens:self];
839 - (void)cancelOperation:(
id)sender
841 [
self _hideCompletions];
844 - (void)moveLeft:(
id)sender
847 if ((_selectedRange.location > 0 || _selectedRange.length) && [
self _editorValue] ==
"")
849 if (_selectedRange.length)
851 _selectedRange.length = 0;
853 _selectedRange.location--;
864 - (void)moveLeftAndModifySelection:(
id)sender
866 if (_selectedRange.location > 0 && [
self _editorValue] ==
"")
868 _selectedRange.location--;
870 _selectedRange.length++;
881 - (void)moveRight:(
id)sender
884 if ((_selectedRange.location < [[
self _tokens] count] || _selectedRange.length) && [
self _editorValue] ==
"")
886 if (_selectedRange.length)
889 _selectedRange.location =
CPMaxRange(_selectedRange);
890 _selectedRange.length = 0;
895 _selectedRange.location = MIN([[
self _tokens] count], _selectedRange.location + _selectedRange.length + 1);
908 - (void)moveRightAndModifySelection:(
id)sender
910 if (
CPMaxRange(_selectedRange) < [[
self _tokens] count] && [
self _editorValue] ==
"")
913 _selectedRange.length++;
924 - (void)deleteBackward:(
id)sender
928 if ([
self _editorValue] ==
@"")
930 [
self _hideCompletions];
934 if (_selectedRange.location > 0)
936 var tokenView = [[
self _tokens] objectAtIndex:(_selectedRange.location - 1)];
937 [
self _selectToken:tokenView byExtendingSelection:NO];
941 [
self _removeSelectedTokens:nil];
950 - (void)deleteForward:(
id)sender
954 if ([
self _editorValue] ==
@"")
957 [
self _hideCompletions];
961 if (_selectedRange.location < [[
self _tokens] count])
962 [
self _deleteToken:[[
self _tokens] objectAtIndex:[_selectedRange.location]]];
965 [
self _removeSelectedTokens:nil];
974 - (void)_selectText:(
id)sender immediately:(BOOL)immediately
983 if (([
self isEditable] || [
self isSelectable]))
985 [
super _selectText:sender immediately:immediately];
988 [
self _autocomplete];
989 _selectedRange =
CPMakeRange(0, [[
self _tokens] count]);
991 [
self setNeedsLayout];
998 CPTokenFieldTextDidChangeValue = [
self stringValue];
1014 if ([
self stringValue] !== CPTokenFieldTextDidChangeValue)
1040 if ([aNotification
object] !==
self)
1046 [
self _delayedShowCompletions];
1048 _selectedRange.length = 0;
1061 - (void)setCompletionDelay:(CPTimeInterval)delay
1063 _completionDelay = delay;
1066 - (CPTimeInterval)completionDelay
1068 return _completionDelay;
1074 - (void)layoutSubviews
1084 if (textFieldContentView)
1085 [textFieldContentView setHidden:[
self stringValue] !== @""];
1088 contentView = [_tokenScrollView documentView],
1089 tokens = [
self _tokens];
1092 if (![tokens isKindOfClass:[CPArray
class]])
1096 var contentRect = CGRectMakeCopy([contentView
bounds]),
1097 contentOrigin = contentRect.origin,
1098 contentSize = contentRect.size,
1099 offset = CGPointMake(contentOrigin.x, contentOrigin.y),
1100 spaceBetweenTokens = CGSizeMake(2.0, 2.0),
1102 tokenToken = [_CPTokenFieldToken new],
1108 offset.y += CEIL(spaceBetweenTokens.height / 2.0);
1111 [tokenToken sizeToFit];
1113 var tokenHeight = CGRectGetHeight([tokenToken bounds]);
1115 var fitAndFrame =
function(
width, height)
1117 var r = CGRectMake(0, 0,
width, height);
1119 if (offset.x +
width >= contentSize.width && offset.x > contentOrigin.x)
1121 offset.x = contentOrigin.x;
1122 offset.y += height + spaceBetweenTokens.height;
1125 r.origin.x = offset.x;
1126 r.origin.y = offset.y;
1129 var scrollHeight = offset.y + tokenHeight + CEIL(spaceBetweenTokens.height / 2.0);
1130 if (CGRectGetHeight([contentView bounds]) < scrollHeight)
1131 [contentView setFrameSize:CGSizeMake(CGRectGetWidth([_tokenScrollView bounds]), scrollHeight)];
1133 offset.x +=
width + spaceBetweenTokens.width;
1138 var placeEditor =
function(useRemainingWidth)
1140 var element = [
self _inputElement],
1143 if (_selectedRange.length === 0)
1148 textWidth = [(element.value || @"") + "X" sizeWithFont:font].width;
1150 if (useRemainingWidth)
1151 textWidth = MAX(contentSize.width - offset.x - 1, textWidth);
1154 _inputFrame = fitAndFrame(textWidth, tokenHeight);
1156 _inputFrame.size.height = lineHeight;
1158 element.style.left = (_inputFrame.origin.x + editorInset.left) +
"px";
1159 element.style.top = (_inputFrame.origin.y + editorInset.top) +
"px";
1160 element.style.width = _inputFrame.size.width +
"px";
1161 element.style.height = _inputFrame.size.height +
"px";
1164 if (_selectedRange.length == 0)
1165 [[_tokenScrollView documentView] scrollPoint:CGPointMake(0, _inputFrame.origin.y)];
1168 for (var i = 0, count = [tokens count]; i < count; i++)
1170 if (isEditing && !_selectedRange.length && i ==
CPMaxRange(_selectedRange))
1173 var tokenView = [tokens objectAtIndex:i];
1176 if ([tokenView isKindOfClass:[
CPString class]])
1179 [tokenView setHighlighted:CPLocationInRange(i, _selectedRange)];
1180 [tokenView sizeToFit];
1182 var size = [contentView bounds].size,
1183 tokenViewSize = [tokenView bounds].size,
1184 tokenFrame = fitAndFrame(tokenViewSize.width, tokenViewSize.height);
1186 [tokenView setFrame:tokenFrame];
1188 [tokenView setButtonType:_buttonType];
1191 if (isEditing && !_selectedRange.length &&
CPMaxRange(_selectedRange) >= [tokens count])
1196 if (isEditing && _selectedRange.length)
1199 var inputElement = [
self _inputElement];
1200 inputElement.style.display =
"none";
1204 var inputElement = [
self _inputElement];
1205 inputElement.style.display =
"block";
1206 if (document.activeElement !== inputElement)
1207 inputElement.focus();
1211 var scrollHeight = offset.y + tokenHeight;
1212 if (CGRectGetHeight([contentView bounds]) > scrollHeight)
1213 [contentView setFrameSize:CGSizeMake(CGRectGetWidth([_tokenScrollView bounds]), scrollHeight)];
1218 if (!(isEditing && _selectedRange.length == 0))
1220 var scrollToToken = _shouldScrollTo;
1223 scrollToToken = tokens[_selectedRange.location]
1225 scrollToToken = tokens[MAX(0, CPMaxRange(_selectedRange) - 1)];
1226 [
self _scrollTokenViewToVisible:scrollToToken];
1233 - (BOOL)_scrollTokenViewToVisible:(_CPTokenFieldToken)aToken
1238 return [[_tokenScrollView documentView] scrollPoint:CGPointMake(0, [aToken frameOrigin].y)];
1254 - (CPArray)_completionsForSubstring:(
CPString)substring indexOfToken:(
int)tokenIndex indexOfSelectedItem:(
int)selectedIndex
1259 return [_tokenFieldDelegate tokenField:self completionsForSubstring:substring indexOfToken:tokenIndex indexOfSelectedItem:selectedIndex];
1265 - (CGPoint)_completionOrigin:(_CPAutocompleteMenu)anAutocompleteMenu
1267 var relativeFrame = _inputFrame ? [[_tokenScrollView documentView] convertRect:_inputFrame toView:self ] : [
self bounds];
1269 return CGPointMake(CGRectGetMinX(relativeFrame), CGRectGetMaxY(relativeFrame));
1280 - (
CPString)_displayStringForRepresentedObject:(
id)representedObject
1284 var stringForRepresentedObject = [_tokenFieldDelegate tokenField:self displayStringForRepresentedObject:representedObject];
1286 if (stringForRepresentedObject !== nil)
1287 return stringForRepresentedObject;
1290 return representedObject;
1302 - (CPArray)_shouldAddObjects:(CPArray)tokens atIndex:(
int)index
1306 var approvedObjects = [_tokenFieldDelegate tokenField:self shouldAddObjects:tokens atIndex:index];
1308 if (approvedObjects !== nil)
1309 return approvedObjects;
1324 - (id)_representedObjectForEditingString:(
CPString)aString
1328 var token = [_tokenFieldDelegate tokenField:self representedObjectForEditingString:aString];
1330 if (token !== nil && token !== undefined)
1339 - (BOOL)_hasMenuForRepresentedObject:(
id)aRepresentedObject
1343 return [_tokenFieldDelegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
1348 - (
CPMenu)_menuForRepresentedObject:(
id)aRepresentedObject
1350 if ((_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_hasMenuForRepresentedObject_) &&
1353 var hasMenu = [_tokenFieldDelegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
1356 return [_tokenFieldDelegate tokenField:self menuForRepresentedObject:aRepresentedObject] || nil;
1376 - (void)_delayedShowCompletions
1378 [[
self _autocompleteMenu] _delayedShowCompletions];
1381 - (void)_hideCompletions
1383 [_autocompleteMenu _hideCompletions];
1387 - (void)setButtonType:(
int)aButtonType
1389 if (_buttonType === aButtonType)
1392 _buttonType = aButtonType;
1400 _CPTokenFieldTokenCloseButton _deleteButton;
1401 _CPTokenFieldTokenDisclosureButton _disclosureButton;
1403 id _representedObject;
1409 return "tokenfield-token";
1412 - (BOOL)acceptsFirstResponder
1417 - (id)initWithFrame:(CGRect)frame
1419 if (
self = [super initWithFrame:frame])
1421 [
self setEditable:NO];
1422 [
self setHighlighted:NO];
1423 [
self setBezeled:YES];
1424 [
self setButtonType:CPTokenFieldDisclosureButtonType];
1437 _tokenField = tokenField;
1440 - (id)representedObject
1442 return _representedObject;
1445 - (void)setRepresentedObject:(
id)representedObject
1447 _representedObject = representedObject;
1448 [
self setNeedsLayout];
1451 - (void)setEditable:(BOOL)shouldBeEditable
1453 [
super setEditable:shouldBeEditable];
1454 [
self setNeedsLayout];
1459 if (aState.isa && [aState isKindOfClass:CPArray])
1460 aState = CPThemeState.apply(null, aState);
1462 var r = [
super setThemeState:aState];
1467 [_disclosureButton setThemeState:CPThemeStateHovered];
1468 [_deleteButton setThemeState:CPThemeStateHovered];
1476 if (aState.isa && [aState isKindOfClass:CPArray])
1477 aState = CPThemeState.apply(null, aState);
1479 var r = [
super unsetThemeState:aState];
1484 [_disclosureButton unsetThemeState:CPThemeStateHovered];
1485 [_deleteButton unsetThemeState:CPThemeStateHovered];
1491 - (CGSize)_minimumFrameSize
1493 var size = CGSizeMakeZero(),
1494 minSize = [
self currentValueForThemeAttribute:@"min-size"],
1495 contentInset = [
self currentValueForThemeAttribute:@"content-inset"];
1498 size.height = minSize.height;
1499 size.width = MAX(minSize.width, [([
self stringValue] ||
@" ") sizeWithFont:[
self font]].width + contentInset.left + contentInset.right);
1504 - (void)setButtonType:(
int)aButtonType
1506 if (_buttonType === aButtonType)
1509 _buttonType = aButtonType;
1515 [_deleteButton removeFromSuperview];
1516 _deleteButton = nil;
1519 if (!_disclosureButton)
1521 _disclosureButton = [[_CPTokenFieldTokenDisclosureButton alloc] initWithFrame:CGRectMakeZero()];
1522 [
self addSubview:_disclosureButton];
1527 if (_disclosureButton)
1529 [_disclosureButton removeFromSuperview];
1530 _disclosureButton = nil;
1535 _deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CGRectMakeZero()];
1536 [
self addSubview:_deleteButton];
1537 [_deleteButton setTarget:self];
1538 [_deleteButton setAction:@selector(_delete:)];
1542 [
self setNeedsLayout];
1545 - (void)layoutSubviews
1547 [
super layoutSubviews];
1549 var bezelView = [
self layoutEphemeralSubviewNamed:@"bezel-view"
1550 positioned:CPWindowBelow
1551 relativeToEphemeralSubviewNamed:@"content-view"];
1553 if (bezelView && _tokenField)
1555 switch (_buttonType)
1558 var shouldBeEnabled = [
self hasMenu];
1559 [_disclosureButton setHidden:!shouldBeEnabled];
1561 if (shouldBeEnabled)
1562 [_disclosureButton setMenu:[
self menu]];
1564 var
frame = [bezelView frame],
1565 buttonOffset = [_disclosureButton currentValueForThemeAttribute:@"offset"],
1566 buttonSize = [_disclosureButton currentValueForThemeAttribute:@"min-size"];
1568 [_disclosureButton setFrame:CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
1571 [_deleteButton setEnabled:[
self isEditable] && [
self isEnabled]];
1573 var frame = [bezelView frame],
1574 buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"],
1575 buttonSize = [_deleteButton currentValueForThemeAttribute:@"min-size"];
1577 [_deleteButton setFrame:CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
1583 - (void)mouseDown:(
CPEvent)anEvent
1585 [_tokenField _mouseDownOnToken:self withEvent:anEvent];
1588 - (void)mouseUp:(
CPEvent)anEvent
1590 [_tokenField _mouseUpOnToken:self withEvent:anEvent];
1593 - (void)_delete:(
id)sender
1595 if ([
self isEditable])
1596 [_tokenField _deleteToken:self];
1601 return [_tokenField _hasMenuForRepresentedObject:_representedObject];
1606 return [_tokenField _menuForRepresentedObject:_representedObject];
1610 @implementation _CPTokenFieldTokenCloseButton :
CPButton
1619 [attributes setObject:CGPointMake(15, 5) forKey:@"offset"];
1626 return "tokenfield-token-close-button";
1629 - (void)mouseEntered:(
CPEvent)anEvent
1634 - (void)mouseExited:(
CPEvent)anEvent
1640 @implementation _CPTokenFieldTokenDisclosureButton :
CPPopUpButton
1649 [attributes setObject:CGPointMake(15, 5) forKey:@"offset"];
1656 return "tokenfield-token-disclosure-button";
1659 - (id)initWithFrame:(CGRect)aFrame
1661 if (
self = [
self initWithFrame:aFrame pullsDown:YES])
1663 [
self setBordered:YES];
1664 [
super setTitle:@""];
1675 - (void)synchronizeTitleAndSelectedItem
1680 - (void)mouseEntered:(
CPEvent)anEvent
1685 - (void)mouseExited:(
CPEvent)anEvent
1705 _tokenizingCharacterSet = [aCoder decodeObjectForKey:CPTokenFieldTokenizingCharacterSetKey] || [[
self class] defaultTokenizingCharacterSet];
1706 _completionDelay = [aCoder decodeDoubleForKey:CPTokenFieldCompletionDelayKey] || [[
self class] defaultCompletionDelay];
1722 [aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
1723 [aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
1724 [aCoder encodeInt:_buttonType forKey:CPTokenFieldButtonTypeKey];
1736 return _tokenizingCharacterSet;
1744 _tokenizingCharacterSet = aValue;
1758 - (void)setButtonType:(
int)aValue
1760 _buttonType = aValue;