29 CPTextFieldSquareBezel = 0;
30 CPTextFieldRoundedBezel = 1;
32 CPTextFieldDidFocusNotification =
@"CPTextFieldDidFocusNotification";
33 CPTextFieldDidBlurNotification =
@"CPTextFieldDidBlurNotification";
35 var CPTextFieldDOMInputElement = nil,
36 CPTextFieldDOMPasswordInputElement = nil,
37 CPTextFieldDOMStandardInputElement = nil,
38 CPTextFieldInputOwner = nil,
39 CPTextFieldTextDidChangeValue = nil,
40 CPTextFieldInputResigning = NO,
41 CPTextFieldInputDidBlur = NO,
42 CPTextFieldInputIsActive = NO,
43 CPTextFieldCachedSelectStartFunction = nil,
44 CPTextFieldCachedDragFunction = nil,
45 CPTextFieldBlurHandler = nil,
46 CPTextFieldInputFunction = nil;
48 var CPSecureTextFieldCharacter =
"\u2022";
51 function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resigning, didBlurRef)
53 if (owner && domElement != inputElement.parentNode)
56 var ownerWindow = [owner window];
58 if (!resigning && [ownerWindow isKeyWindow])
65 if ([owner _isWithinUsablePlatformRect])
67 window.setTimeout(
function()
74 CPTextFieldHandleBlur(anEvent, @ref(owner));
75 @deref(didBlurRef) = YES;
80 function CPTextFieldHandleBlur(anEvent, ownerRef)
82 @deref(ownerRef) = nil;
88 @implementation CPString (CPTextFieldAdditions)
100 CPTextFieldStateRounded = CPThemeState(
"rounded");
101 CPTextFieldStatePlaceholder = CPThemeState(
"placeholder");
114 BOOL _willBecomeFirstResponderByClick;
116 BOOL _drawsBackground;
118 CPColor _textFieldBackgroundColor;
126 CPTextFieldBezelStyle _bezelStyle;
128 CPControlSize _controlSize;
131 + (Class)_binderClassForBinding:(
CPString)aBinding
133 if (aBinding === CPValueBinding)
134 return [_CPTextFieldValueBinder class];
135 else if ([aBinding hasPrefix:CPDisplayPatternValueBinding])
136 return [_CPTextFieldPatternValueBinder class];
137 else if ([aBinding hasPrefix:CPEditableBinding])
140 return [
super _binderClassForBinding:aBinding];
145 return [
self textFieldWithStringValue:aStringValue placeholder:aPlaceholder width:aWidth theme:[
CPTheme defaultTheme]];
150 var textField = [[
self alloc] initWithFrame:CGRectMake(0.0, 0.0, aWidth, 29.0)];
152 [textField setTheme:aTheme];
153 [textField setStringValue:aStringValue];
154 [textField setPlaceholderString:aPlaceholder];
155 [textField setBordered:YES];
156 [textField setBezeled:YES];
157 [textField setEditable:YES];
159 [textField sizeToFit];
166 return [
self roundedTextFieldWithStringValue:aStringValue placeholder:aPlaceholder width:aWidth theme:[
CPTheme defaultTheme]];
171 var textField = [[
CPTextField alloc] initWithFrame:CGRectMake(0.0, 0.0, aWidth, 29.0)];
173 [textField setTheme:aTheme];
174 [textField setStringValue:aStringValue];
175 [textField setPlaceholderString:aPlaceholder];
176 [textField setBezelStyle:CPTextFieldRoundedBezel];
177 [textField setBordered:YES];
178 [textField setBezeled:YES];
179 [textField setEditable:YES];
181 [textField sizeToFit];
188 return [
self labelWithTitle:aTitle theme:[
CPTheme defaultTheme]];
193 var textField = [[
self alloc] init];
195 [textField setStringValue:aTitle];
196 [textField sizeToFit];
209 @"bezel-inset": CGInsetMakeZero(),
210 @"content-inset": CGInsetMake(1.0, 0.0, 0.0, 0.0),
216 - (DOMElement)_inputElement
218 if (!CPTextFieldDOMInputElement)
220 CPTextFieldDOMInputElement = document.createElement(
"input");
221 CPTextFieldDOMInputElement.style.position =
"absolute";
222 CPTextFieldDOMInputElement.style.border =
"0px";
223 CPTextFieldDOMInputElement.style.padding =
"0px";
224 CPTextFieldDOMInputElement.style.margin =
"0px";
225 CPTextFieldDOMInputElement.style.whiteSpace =
"pre";
226 CPTextFieldDOMInputElement.style.background =
"transparent";
227 CPTextFieldDOMInputElement.style.outline =
"none";
229 CPTextFieldBlurHandler =
function(anEvent)
231 return CPTextFieldBlurFunction(
233 CPTextFieldInputOwner,
234 CPTextFieldInputOwner ? CPTextFieldInputOwner._DOMElement : nil,
235 CPTextFieldDOMInputElement,
236 CPTextFieldInputResigning,
237 @ref(CPTextFieldInputDidBlur));
242 CPTextFieldInputFunction =
function(anEvent)
244 if (!CPTextFieldInputOwner)
247 var cappEvent = [
CPEvent keyEventWithType:CPKeyUp
248 location:CGPointMakeZero()
250 timestamp:[
CPEvent currentTimestamp]
251 windowNumber:[[CPApp keyWindow] windowNumber]
254 charactersIgnoringModifiers:nil
258 [CPTextFieldInputOwner keyUp:cappEvent];
263 CPTextFieldDOMInputElement.oninput = CPTextFieldInputFunction;
267 CPTextFieldDOMInputElement.onblur = CPTextFieldBlurHandler;
269 CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
275 CPTextFieldDOMInputElement.type =
"password";
277 CPTextFieldDOMInputElement.type =
"text";
279 return CPTextFieldDOMInputElement;
284 if (!CPTextFieldDOMPasswordInputElement)
286 CPTextFieldDOMPasswordInputElement = document.createElement(
"input");
287 CPTextFieldDOMPasswordInputElement.style.position =
"absolute";
288 CPTextFieldDOMPasswordInputElement.style.border =
"0px";
289 CPTextFieldDOMPasswordInputElement.style.padding =
"0px";
290 CPTextFieldDOMPasswordInputElement.style.margin =
"0px";
291 CPTextFieldDOMPasswordInputElement.style.whiteSpace =
"pre";
292 CPTextFieldDOMPasswordInputElement.style.background =
"transparent";
293 CPTextFieldDOMPasswordInputElement.style.outline =
"none";
294 CPTextFieldDOMPasswordInputElement.type =
"password";
296 CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurHandler;
299 CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
303 CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
306 return CPTextFieldDOMInputElement;
310 - (id)initWithFrame:(CGRect)aFrame
312 self = [
super initWithFrame:aFrame];
316 [
self setStringValue:@""];
317 [
self setPlaceholderString:@""];
321 [
self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
327 #pragma mark Controlling Editability and Selectability
333 - (void)setEditable:(BOOL)shouldBeEditable
335 if (_isEditable === shouldBeEditable)
338 _isEditable = shouldBeEditable;
340 if (shouldBeEditable)
344 [
self setThemeState:CPThemeStateEditable];
346 [
self unsetThemeState:CPThemeStateEditable];
349 if (!(shouldBeEditable && ![
self isSelectable]) && [[
self window] firstResponder] ===
self)
350 [[
self window] makeFirstResponder:nil];
352 if (shouldBeEditable)
353 [
self setThemeState:CPThemeStateEditable];
355 [
self unsetThemeState:CPThemeStateEditable];
370 - (void)setEnabled:(BOOL)shouldBeEnabled
372 [
super setEnabled:shouldBeEnabled];
375 if (!shouldBeEnabled && [[
self window] firstResponder] ===
self)
376 [[
self window] makeFirstResponder:nil];
383 - (void)setSelectable:(BOOL)aFlag
385 _isSelectable = aFlag;
393 return _isSelectable;
400 - (void)setSecure:(BOOL)aFlag
418 - (void)setBezeled:(BOOL)shouldBeBezeled
421 [
self setThemeState:CPThemeStateBezeled];
423 [
self unsetThemeState:CPThemeStateBezeled];
431 return [
self hasThemeState:CPThemeStateBezeled];
438 - (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
440 var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
443 [
self setThemeState:CPTextFieldStateRounded];
445 [
self unsetThemeState:CPTextFieldStateRounded];
451 - (CPTextFieldBezelStyle)bezelStyle
453 if ([
self hasThemeState:CPTextFieldStateRounded])
454 return CPTextFieldRoundedBezel;
456 return CPTextFieldSquareBezel;
463 - (void)setBordered:(BOOL)shouldBeBordered
465 if (shouldBeBordered)
466 [
self setThemeState:CPThemeStateBordered];
468 [
self unsetThemeState:CPThemeStateBordered];
476 return [
self hasThemeState:CPThemeStateBordered];
483 - (void)setDrawsBackground:(BOOL)shouldDrawBackground
485 if (_drawsBackground == shouldDrawBackground)
488 _drawsBackground = shouldDrawBackground;
490 [
self setNeedsLayout];
491 [
self setNeedsDisplay:YES];
497 - (BOOL)drawsBackground
499 return _drawsBackground;
506 - (void)setTextFieldBackgroundColor:(
CPColor)aColor
508 if (_textFieldBackgroundColor == aColor)
511 _textFieldBackgroundColor = aColor;
513 [
self setNeedsLayout];
514 [
self setNeedsDisplay:YES];
520 - (
CPColor)textFieldBackgroundColor
522 return _textFieldBackgroundColor;
526 - (BOOL)acceptsFirstResponder
528 return [
self isEnabled] && ([
self isEditable] || [
self isSelectable]) && [
self _isWithinUsablePlatformRect];
532 - (BOOL)becomeFirstResponder
534 if (![
self isEnabled])
538 [
self _setObserveWindowKeyNotifications:YES];
542 if ([[
self window] isKeyWindow] && [
self isEditable])
543 return [
self _becomeFirstKeyResponder];
556 - (BOOL)_becomeFirstKeyResponder
560 if (![
self _isWithinUsablePlatformRect])
565 if (![
self isEditable])
568 [
self setThemeState:CPThemeStateEditing];
570 [
self _updatePlaceholderState];
572 [
self setNeedsLayout];
574 _stringValue = [
self stringValue];
578 var element = [
self _inputElement],
579 font = [
self currentValueForThemeAttribute:@"font"],
580 lineHeight = [font defaultLineHeightForFont];
582 element.value = _stringValue;
583 element.style.color = [[
self currentValueForThemeAttribute:@"text-color"] cssString];
586 element.style.font = [font cssString];
588 element.style.zIndex = 1000;
590 switch ([
self alignment])
593 element.style.textAlign =
"center";
597 element.style.textAlign =
"right";
601 element.style.textAlign =
"left";
604 var contentRect = [
self contentRectForBounds:[
self bounds]],
605 verticalAlign = [
self currentValueForThemeAttribute:"vertical-alignment"];
607 switch (verticalAlign)
610 var topPoint = CGRectGetMinY(contentRect) + "px";
614 var topPoint = (CGRectGetMidY(contentRect) - (lineHeight / 2)) + "px";
618 var topPoint = (CGRectGetMaxY(contentRect) - lineHeight) + "px";
622 var topPoint = CGRectGetMinY(contentRect) + "px";
626 element.style.top = topPoint;
628 var left = CGRectGetMinX(contentRect);
634 element.style.left = left + "px";
635 element.style.width = CGRectGetWidth(contentRect) + "px";
636 element.style.height = ROUND(lineHeight) + "px";
637 element.style.lineHeight = ROUND(lineHeight) + "px";
638 element.style.verticalAlign =
"top";
639 element.style.cursor =
"auto";
641 _DOMElement.appendChild(element);
645 element.style.font = [font cssString];
647 CPTextFieldInputIsActive = YES;
649 if (document.attachEvent)
651 CPTextFieldCachedSelectStartFunction = [[
self window] platformWindow]._DOMBodyElement.onselectstart;
652 CPTextFieldCachedDragFunction = [[
self window] platformWindow]._DOMBodyElement.ondrag;
654 [[
self window] platformWindow]._DOMBodyElement.ondrag =
function () {};
655 [[
self window] platformWindow]._DOMBodyElement.onselectstart =
function () {};
658 CPTextFieldInputOwner =
self;
660 window.setTimeout(
function()
665 if (CPTextFieldInputOwner !==
self)
671 if (!_willBecomeFirstResponderByClick)
672 [
self _selectText:self immediately:YES];
674 _willBecomeFirstResponderByClick = NO;
685 - (BOOL)resignFirstResponder
689 if (_isEditing && CPTextFieldInputOwner ===
self)
691 var element = [
self _inputElement],
692 newValue = element.value,
695 if (newValue !== _stringValue)
697 [
self _setStringValue:newValue];
702 if ([
self _valueIsValid:newValue] === NO)
711 [
self _setObserveWindowKeyNotifications:NO];
713 [
self _resignFirstKeyResponder];
716 if ([
self isEditable])
720 if ([
self sendsActionOnEndEditing])
721 [
self sendAction:[
self action] to:[
self target]];
729 - (void)_resignFirstKeyResponder
731 [
self unsetThemeState:CPThemeStateEditing];
734 _stringValue = [
self stringValue];
736 _willBecomeFirstResponderByClick = NO;
738 [
self _updatePlaceholderState];
739 [
self setNeedsLayout];
743 var element = [
self _inputElement];
745 CPTextFieldInputResigning = YES;
747 if (CPTextFieldInputIsActive)
750 if (!CPTextFieldInputDidBlur)
751 CPTextFieldBlurHandler();
753 CPTextFieldInputDidBlur = NO;
754 CPTextFieldInputResigning = NO;
756 if (element.parentNode == _DOMElement)
757 element.parentNode.removeChild(element);
759 CPTextFieldInputIsActive = NO;
761 if (document.attachEvent)
763 [[
self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
764 [[
self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
766 CPTextFieldCachedSelectStartFunction = nil;
767 CPTextFieldCachedDragFunction = nil;
773 - (void)_setObserveWindowKeyNotifications:(BOOL)shouldObserve
789 if (![[
self window] isKeyWindow])
790 [
self _resignFirstKeyResponder];
795 if (!([
self isEnabled] && [
self isEditable]))
798 var wind = [
self window];
800 if ([wind isKeyWindow] && [wind firstResponder] ===
self)
801 if (![
self _becomeFirstKeyResponder])
802 [wind makeFirstResponder:nil];
805 - (BOOL)_valueIsValid:(
CPString)aValue
811 if ([
self _setStringValue:aValue isNewValue:NO errorDescription:@ref(error)] === NO)
813 var acceptInvalidValue = NO;
815 if ([_delegate respondsToSelector:
@selector(control:didFailToFormatString:errorDescription:)])
816 acceptInvalidValue = [_delegate control:self didFailToFormatString:aValue errorDescription:error];
818 if (acceptInvalidValue === NO)
831 - (BOOL)needsPanelToBecomeKey
833 return [
self acceptsFirstResponder];
839 - (BOOL)acceptsFirstMouse:(
CPEvent)anEvent
841 return [
self acceptsFirstResponder];
855 - (void)mouseDown:(
CPEvent)anEvent
858 if ([
self isEditable] && [
self isEnabled])
860 _willBecomeFirstResponderByClick = YES;
861 [[
self window] makeFirstResponder:self];
863 else if ([
self isSelectable])
865 if (document.attachEvent)
867 CPTextFieldCachedSelectStartFunction = [[
self window] platformWindow]._DOMBodyElement.onselectstart;
868 CPTextFieldCachedDragFunction = [[
self window] platformWindow]._DOMBodyElement.ondrag;
870 [[
self window] platformWindow]._DOMBodyElement.ondrag =
function () {};
871 [[
self window] platformWindow]._DOMBodyElement.onselectstart =
function () {};
873 return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
876 return [[
self nextResponder] mouseDown:anEvent];
879 - (void)mouseUp:(
CPEvent)anEvent
881 if (![
self isEnabled] || !([
self isSelectable] || [
self isEditable]))
882 [[
self nextResponder] mouseUp:anEvent];
883 else if ([
self isSelectable])
885 if (document.attachEvent)
887 [[
self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
888 [[
self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
890 CPTextFieldCachedSelectStartFunction = nil
891 CPTextFieldCachedDragFunction = nil;
896 if ([[
CPApp currentEvent] clickCount] === 3)
898 [
self selectText:nil];
902 return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
906 - (void)mouseDragged:(
CPEvent)anEvent
908 if (![
self isEnabled] || !([
self isSelectable] || [
self isEditable]))
909 [[
self nextResponder] mouseDragged:anEvent];
910 else if ([
self isSelectable])
911 return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
916 if (!([
self isEnabled] && [
self isEditable]))
920 var newValue = [
self _inputElement].value;
922 if (newValue !== _stringValue)
924 [
self _setStringValue:newValue];
929 [[[
self window] platformWindow] _propagateCurrentDOMEvent:YES];
933 - (void)keyDown:(
CPEvent)anEvent
939 [[[
self window] platformWindow] _propagateCurrentDOMEvent:YES];
941 [
self interpretKeyEvents:[anEvent]];
955 - (void)doCommandBySelector:(
SEL)aSelector
957 if ([
self respondsToSelector:aSelector])
958 [
self performSelector:aSelector];
961 - (void)insertNewline:(
id)sender
963 if (!([
self isEnabled] && [
self isEditable]))
966 var newValue = [
self _inputElement].value;
968 if (newValue !== _stringValue)
970 [
self _setStringValue:newValue];
974 if ([
self _valueIsValid:_stringValue])
989 if (![
self action] || [
self sendAction:[
self action] to:[
self target]])
991 [
self selectAll:nil];
995 [[[
self window] platformWindow] _propagateCurrentDOMEvent:NO];
998 - (void)insertNewlineIgnoringFieldEditor:(
id)sender
1000 [
self _insertCharacterIgnoringFieldEditor:CPNewlineCharacter];
1003 - (void)insertTabIgnoringFieldEditor:(
id)sender
1005 [
self _insertCharacterIgnoringFieldEditor:CPTabCharacter];
1008 - (void)_insertCharacterIgnoringFieldEditor:(
CPString)aCharacter
1010 if (!([
self isEnabled] && [
self isEditable]))
1015 var oldValue = _stringValue,
1016 range = [
self selectedRange],
1017 element = [
self _inputElement];
1019 element.value = [element.value stringByReplacingCharactersInRange:[
self selectedRange] withString:aCharacter];
1020 [
self _setStringValue:element.value];
1023 if (oldValue !== _stringValue)
1034 if ([note
object] !=
self)
1043 if ([note
object] !=
self)
1051 if ([note
object] !==
self)
1054 [
self _continuouslyReverseSetBinding];
1056 [
super textDidChange:note];
1064 return [
super objectValue];
1071 - (BOOL)_setStringValue:(
CPString)aValue
1073 return [
self _setStringValue:aValue isNewValue:YES errorDescription:nil];
1080 - (BOOL)_setStringValue:(
CPString)aValue isNewValue:(BOOL)isNewValue errorDescription:(CPStringRef)anError
1082 _stringValue = aValue;
1084 var objectValue = aValue,
1085 formatter = [
self formatter],
1092 if ([formatter getObjectValue:@ref(
object) forString:aValue errorDescription:anError])
1093 objectValue =
object;
1096 objectValue = undefined;
1100 isNewValue |= objectValue !== [
super objectValue];
1105 [
self willChangeValueForKey:@"objectValue"];
1106 [
super setObjectValue:objectValue];
1107 [
self _updatePlaceholderState];
1108 [
self didChangeValueForKey:@"objectValue"];
1114 - (void)setObjectValue:(
id)aValue
1116 [
super setObjectValue:aValue];
1118 var formatter = [
self formatter];
1123 var formattedString = [
self hasThemeState:CPThemeStateEditing] ? [formatter editingStringForObjectValue:aValue] : [formatter stringForObjectValue:aValue];
1125 if (formattedString === nil)
1131 if ([formatter getObjectValue:@ref(value) forString:
@"" errorDescription:nil] === NO)
1134 [
super setObjectValue:value];
1135 _stringValue = (value === nil || value === undefined) ?
@"" : String(value);
1138 _stringValue = formattedString;
1141 _stringValue = [
self stringValue];
1145 if (CPTextFieldInputOwner ===
self || [[
self window] firstResponder] ===
self)
1146 [
self _inputElement].value = _stringValue;
1150 [
self _updatePlaceholderState];
1153 - (void)_updatePlaceholderState
1155 if ((!_stringValue || _stringValue.length === 0) && ![
self hasThemeState:CPThemeStateEditing])
1156 [
self setThemeState:CPTextFieldStatePlaceholder];
1158 [
self unsetThemeState:CPTextFieldStatePlaceholder];
1165 - (void)setPlaceholderString:(
CPString)aStringValue
1167 if (_placeholderString === aStringValue)
1170 _placeholderString = aStringValue;
1173 if ([
self hasThemeState:CPTextFieldStatePlaceholder])
1175 [
self setNeedsLayout];
1176 [
self setNeedsDisplay:YES];
1185 return _placeholderString;
1210 [
self setFrameSize:[
self _minimumFrameSize]];
1213 - (CGSize)_minimumFrameSize
1215 var frameSize = [
self frameSize],
1216 contentInset = [
self currentValueForThemeAttribute:@"content-inset"],
1217 minSize = [
self currentValueForThemeAttribute:@"min-size"],
1218 maxSize = [
self currentValueForThemeAttribute:@"max-size"],
1219 lineBreakMode = [
self lineBreakMode],
1220 text = (_stringValue ||
@" "),
1221 textSize = CGSizeMakeCopy(frameSize),
1222 font = [
self currentValueForThemeAttribute:@"font"];
1224 textSize.width -= contentInset.left + contentInset.right;
1225 textSize.height -= contentInset.top + contentInset.bottom;
1227 if (frameSize.width !== 0 &&
1228 ![
self isBezeled] &&
1231 textSize = [text sizeWithFont:font inWidth:textSize.width];
1235 textSize = [text sizeWithFont:font];
1238 textSize.width += 1;
1242 textSize.height += 1;
1244 frameSize.height = textSize.height + contentInset.top + contentInset.bottom;
1246 if ([
self isBezeled])
1248 frameSize.height = MAX(frameSize.height, minSize.height);
1250 if (maxSize.width > 0.0)
1251 frameSize.width = MIN(frameSize.width, maxSize.width);
1253 if (maxSize.height > 0.0)
1254 frameSize.height = MIN(frameSize.height, maxSize.height);
1257 frameSize.width = textSize.width + contentInset.left + contentInset.right;
1259 frameSize.width = MAX(frameSize.width, minSize.width);
1267 - (void)selectText:(
id)sender
1269 [
self _selectText:sender immediately:NO];
1272 - (void)_selectText:(
id)sender immediately:(BOOL)immediately
1275 if ([
self isEditable] || [
self isSelectable])
1277 var wind = [
self window];
1280 if ([
self isEditable])
1282 var element = [
self _inputElement];
1284 if ([wind firstResponder] ===
self)
1289 window.setTimeout(
function() { element.select(); }, 0);
1291 else if (wind !== nil && [wind makeFirstResponder:
self])
1292 [
self _selectText:sender immediately:immediately];
1296 [
self setSelectedRange:CPMakeRange(0, _stringValue.length)];
1301 if (wind !== nil && [wind firstResponder] !==
self)
1302 [wind makeFirstResponder:self];
1308 - (void)copy:(
id)sender
1311 var stringToCopy = nil;
1313 if ([
self isEditable])
1315 var selectedRange = [
self selectedRange];
1317 if (selectedRange.length < 1)
1320 stringToCopy = [_stringValue substringWithRange:selectedRange];
1327 stringToCopy = [[[
self window] platformWindow] _selectedText];
1333 [pasteboard declareTypes:[CPStringPboardType] owner:nil];
1334 [pasteboard setString:stringToCopy forType:CPStringPboardType];
1339 [[[
self window] platformWindow] _propagateCurrentDOMEvent:YES];
1343 - (void)cut:(
id)sender
1345 if (![
self isEnabled])
1350 if (![
self isEditable])
1353 if (![[
CPApp currentEvent] _platformIsEffectingCutOrPaste])
1355 [
self deleteBackward:sender];
1360 [[[
self window] platformWindow] _propagateCurrentDOMEvent:YES];
1364 [
CPTimer scheduledTimerWithTimeInterval:0.0 target:
self selector:
@selector(keyUp:) userInfo:nil repeats:NO];
1368 - (void)paste:(
id)sender
1370 if (!([
self isEnabled] && [
self isEditable]))
1373 if (![[
CPApp currentEvent] _platformIsEffectingCutOrPaste])
1380 [
self deleteBackward:sender];
1382 var selectedRange = [
self selectedRange],
1383 pasteString = [pasteboard stringForType:CPStringPboardType],
1384 newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
1386 [
self setStringValue:newValue];
1388 [
self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
1394 [[[
self window] platformWindow] _propagateCurrentDOMEvent:YES];
1397 [
CPTimer scheduledTimerWithTimeInterval:0.0 target:
self selector:
@selector(keyUp:) userInfo:nil repeats:NO];
1401 - (CPRange)selectedRange
1405 if ([[
self window] firstResponder] !==
self)
1413 var inputElement = [
self _inputElement],
1414 selectionStart = inputElement.selectionStart,
1415 selectionEnd = inputElement.selectionEnd;
1417 if ([selectionStart isKindOfClass:
CPNumber])
1418 return CPMakeRange(selectionStart, selectionEnd - selectionStart);
1421 var theDocument = inputElement.ownerDocument || inputElement.document,
1422 selectionRange = theDocument.selection.createRange(),
1423 range = inputElement.createTextRange();
1425 if (range.inRange(selectionRange))
1427 range.setEndPoint(
'EndToStart', selectionRange);
1428 return CPMakeRange(range.text.length, selectionRange.text.length);
1441 - (void)setSelectedRange:(CPRange)aRange
1443 if (![[
self window] firstResponder] ===
self)
1448 if (![
self isEditable])
1451 var contentView = [
self layoutEphemeralSubviewNamed:@"content-view"
1452 positioned:CPWindowAbove
1453 relativeToEphemeralSubviewNamed:@"bezel-view"];
1456 [contentView setSelectedRange:aRange];
1461 var inputElement = [
self _inputElement];
1465 if ([inputElement.selectionStart isKindOfClass:CPNumber])
1467 inputElement.selectionStart = aRange.location;
1468 inputElement.selectionEnd =
CPMaxRange(aRange);
1473 var theDocument = inputElement.ownerDocument || inputElement.document,
1474 existingRange = theDocument.selection.createRange(),
1475 range = inputElement.createTextRange();
1477 if (range.inRange(existingRange))
1479 range.collapse(
true);
1480 range.move(
'character', aRange.location);
1481 range.moveEnd(
'character', aRange.length);
1493 - (void)selectAll:(
id)sender
1495 [
self selectText:sender];
1498 - (void)deleteBackward:(
id)sender
1500 if (!([
self isEnabled] && [
self isEditable]))
1503 var selectedRange = [
self selectedRange];
1505 if (selectedRange.length < 1)
1507 if (selectedRange.location < 1)
1511 selectedRange.location -= 1;
1512 selectedRange.length += 1;
1515 var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
1517 [
self setStringValue:newValue];
1518 [
self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
1526 [[[
self window] platformWindow] _propagateCurrentDOMEvent:NO];
1530 - (void)delete:(
id)sender
1532 if (!([
self isEnabled] && [
self isEditable]))
1536 var selectedRange = [
self selectedRange];
1538 if (selectedRange.length < 1)
1541 var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
1543 [
self setStringValue:newValue];
1544 [
self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
1549 [[[
self window] platformWindow] _propagateCurrentDOMEvent:NO];
1553 - (void)deleteForward:(
id)sender
1555 if (!([
self isEnabled] && [
self isEditable]))
1558 var selectedRange = [
self selectedRange];
1560 if (selectedRange.length < 1)
1562 if (selectedRange.location + 1 >= _stringValue.length)
1565 selectedRange.length += 1;
1568 var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
1570 [
self setStringValue:newValue];
1571 [
self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
1576 [[[
self window] platformWindow] _propagateCurrentDOMEvent:NO];
1580 #pragma mark Setting the Delegate
1582 - (void)setDelegate:(
id)aDelegate
1589 [defaultCenter removeObserver:_delegate name:CPControlTextDidBeginEditingNotification object:self];
1590 [defaultCenter removeObserver:_delegate name:CPControlTextDidChangeNotification object:self];
1591 [defaultCenter removeObserver:_delegate name:CPControlTextDidEndEditingNotification object:self];
1592 [defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
1593 [defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
1596 _delegate = aDelegate;
1598 if ([_delegate respondsToSelector:
@selector(controlTextDidBeginEditing:)])
1600 addObserver:_delegate
1601 selector:@selector(controlTextDidBeginEditing:)
1602 name:CPControlTextDidBeginEditingNotification
1605 if ([_delegate respondsToSelector:
@selector(controlTextDidChange:)])
1607 addObserver:_delegate
1608 selector:@selector(controlTextDidChange:)
1609 name:CPControlTextDidChangeNotification
1613 if ([_delegate respondsToSelector:
@selector(controlTextDidEndEditing:)])
1615 addObserver:_delegate
1616 selector:@selector(controlTextDidEndEditing:)
1617 name:CPControlTextDidEndEditingNotification
1620 if ([_delegate respondsToSelector:
@selector(controlTextDidFocus:)])
1622 addObserver:_delegate
1623 selector:@selector(controlTextDidFocus:)
1624 name:CPTextFieldDidFocusNotification
1627 if ([_delegate respondsToSelector:
@selector(controlTextDidBlur:)])
1629 addObserver:_delegate
1630 selector:@selector(controlTextDidBlur:)
1631 name:CPTextFieldDidBlurNotification
1640 - (CGRect)contentRectForBounds:(CGRect)bounds
1642 var contentInset = [
self currentValueForThemeAttribute:@"content-inset"];
1644 return CGRectInsetByInset(bounds, contentInset);
1647 - (CGRect)bezelRectForBounds:(CGRect)bounds
1649 var bezelInset = [
self currentValueForThemeAttribute:@"bezel-inset"];
1651 return CGRectInsetByInset(bounds, bezelInset);
1654 - (CGRect)rectForEphemeralSubviewNamed:(
CPString)aName
1656 if (aName ===
"bezel-view")
1657 return [
self bezelRectForBounds:[
self bounds]];
1659 else if (aName ===
"content-view")
1660 return [
self contentRectForBounds:[
self bounds]];
1662 return [
super rectForEphemeralSubviewNamed:aName];
1667 if (aName ===
"bezel-view")
1669 var view = [[
CPView alloc] initWithFrame:CGRectMakeZero()];
1671 [view setHitTests:NO];
1677 var view = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
1679 [view setHitTests:NO];
1684 return [
super createEphemeralSubviewNamed:aName];
1687 - (void)layoutSubviews
1689 var bezelView = [
self layoutEphemeralSubviewNamed:@"bezel-view"
1690 positioned:CPWindowBelow
1691 relativeToEphemeralSubviewNamed:@"content-view"];
1694 [bezelView setBackgroundColor:[
self currentValueForThemeAttribute:@"bezel-color"]];
1696 var contentView = [
self layoutEphemeralSubviewNamed:@"content-view"
1697 positioned:CPWindowAbove
1698 relativeToEphemeralSubviewNamed:@"bezel-view"];
1702 [contentView setHidden:[
self hasThemeState:CPThemeStateEditing]];
1706 if ([
self hasThemeState:CPTextFieldStatePlaceholder])
1707 string = [
self placeholderString];
1710 string = _stringValue;
1712 if ([
self isSecure])
1713 string = secureStringForString(
string);
1716 [contentView setText:string];
1718 [contentView setTextColor:[
self currentValueForThemeAttribute:@"text-color"]];
1719 [contentView setFont:[
self currentValueForThemeAttribute:@"font"]];
1720 [contentView setAlignment:[
self currentValueForThemeAttribute:@"alignment"]];
1721 [contentView setVerticalAlignment:[
self currentValueForThemeAttribute:@"vertical-alignment"]];
1722 [contentView setLineBreakMode:[
self currentValueForThemeAttribute:@"line-break-mode"]];
1723 [contentView setTextShadowColor:[
self currentValueForThemeAttribute:@"text-shadow-color"]];
1724 [contentView setTextShadowOffset:[
self currentValueForThemeAttribute:@"text-shadow-offset"]];
1728 - (void)takeValueFromKeyPath:(
CPString)aKeyPath ofObjects:(CPArray)objects
1730 var count = objects.length,
1731 value = [objects[0] valueForKeyPath:aKeyPath];
1733 [
self setStringValue:value];
1734 [
self setPlaceholderString:@""];
1737 if (value !== [objects[count] valueForKeyPath:aKeyPath])
1739 [
self setPlaceholderString:@"Multiple Values"];
1740 [
self setStringValue:@""];
1744 #pragma mark Overrides
1748 [
super viewDidHide];
1750 if ([[
self window] firstResponder] ===
self)
1751 [
self _resignFirstKeyResponder];
1754 - (void)viewDidUnhide
1756 [
super viewDidUnhide];
1758 if ([
self isEditable] && [[
self window] firstResponder] ===
self)
1759 [
self _becomeFirstKeyResponder];
1762 - (BOOL)validateUserInterfaceItem:(
id )anItem
1764 var theAction = [anItem action];
1766 if (![
self isEditable] && (theAction ==
@selector(cut:) || theAction ==
@selector(paste:) || theAction ==
@selector(
delete:)))
1770 if (![
self isEditable])
1773 if (theAction ==
@selector(copy:) || theAction ==
@selector(cut:) || theAction ==
@selector(
delete:))
1774 return [
self selectedRange].length;
1779 #pragma mark Private
1781 - (BOOL)_isWithinUsablePlatformRect
1786 var wind = [
self window];
1792 var
frame = [
self convertRectToBase:[
self bounds]],
1793 usableRect = [[wind platformWindow] usableContentFrame];
1795 frame.origin = [wind convertBaseToGlobal:frame.origin];
1797 return (CGRectGetMinX(frame) >= CGRectGetMinX(usableRect) &&
1798 CGRectGetMaxX(frame) <= CGRectGetMaxX(usableRect) &&
1799 CGRectGetMinY(frame) >= CGRectGetMinY(usableRect) &&
1800 CGRectGetMaxY(frame) <= CGRectGetMaxY(usableRect));
1805 var secureStringForString =
function(aString)
1811 return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
1815 var CPTextFieldIsEditableKey =
"CPTextFieldIsEditableKey",
1816 CPTextFieldIsSelectableKey =
"CPTextFieldIsSelectableKey",
1817 CPTextFieldIsBorderedKey =
"CPTextFieldIsBorderedKey",
1818 CPTextFieldIsBezeledKey =
"CPTextFieldIsBezeledKey",
1819 CPTextFieldBezelStyleKey =
"CPTextFieldBezelStyleKey",
1820 CPTextFieldDrawsBackgroundKey =
"CPTextFieldDrawsBackgroundKey",
1821 CPTextFieldLineBreakModeKey =
"CPTextFieldLineBreakModeKey",
1822 CPTextFieldAlignmentKey =
"CPTextFieldAlignmentKey",
1823 CPTextFieldBackgroundColorKey =
"CPTextFieldBackgroundColorKey",
1824 CPTextFieldPlaceholderStringKey =
"CPTextFieldPlaceholderStringKey";
1826 @implementation CPTextField (CPCoding)
1833 - (id)initWithCoder:(
CPCoder)aCoder
1835 self = [
super initWithCoder:aCoder];
1839 [
self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
1840 [
self setSelectable:[aCoder decodeBoolForKey:CPTextFieldIsSelectableKey]];
1842 [
self setDrawsBackground:[aCoder decodeBoolForKey:CPTextFieldDrawsBackgroundKey]];
1844 [
self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
1846 [
self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
1847 [
self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
1849 [
self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
1859 - (void)encodeWithCoder:(
CPCoder)aCoder
1861 [
super encodeWithCoder:aCoder];
1863 [aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
1864 [aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
1866 [aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
1868 [aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
1870 [aCoder encodeInt:[
self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
1871 [aCoder encodeInt:[
self alignment] forKey:CPTextFieldAlignmentKey];
1873 [aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
1877 @implementation _CPTextFieldValueBinder :
CPBinder
1884 [
super _updatePlaceholdersWithOptions:options];
1886 [
self _setPlaceholder:@"Multiple Values" forMarker:CPMultipleValuesMarker isDefault:YES];
1887 [
self _setPlaceholder:@"No Selection" forMarker:CPNoSelectionMarker isDefault:YES];
1888 [
self _setPlaceholder:@"Not Applicable" forMarker:CPNotApplicableMarker isDefault:YES];
1889 [
self _setPlaceholder:@"" forMarker:CPNullMarker isDefault:YES];
1892 - (void)setPlaceholderValue:(
id)aValue withMarker:(
CPString)aMarker forBinding:(
CPString)aBinding
1894 [_source setPlaceholderString:aValue];
1895 [_source setObjectValue:nil];
1898 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
1900 if (!aValue || (aValue.isa && [aValue isMemberOfClass:
CPNull]))
1901 [_source setPlaceholderString:[
self _placeholderForMarker:CPNullMarker]];
1903 [_source setObjectValue:aValue];
1912 - (void)setPlaceholderValue:(
id)aValue withMarker:(
CPString)aMarker forBinding:(
CPString)aBinding
1914 [_source setPlaceholderString:aValue];
1915 [_source setObjectValue:nil];
1918 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
1920 if (!aValue || (aValue.isa && [aValue isMemberOfClass:
CPNull]))
1921 [_source setPlaceholderString:[
self _placeholderForMarker:CPNullMarker]];
1923 [_source setObjectValue:aValue];