API  0.9.9
CPTextField.j
Go to the documentation of this file.
1 /*
2  * CPTextField.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 @global CPApp
26 @global CPStringPboardType
27 @global CPCursor
28 
30 
31 @end
32 
39 
40 
41 @typedef CPTextFieldBezelStyle
45 CPTextFieldDidFocusNotification = @"CPTextFieldDidFocusNotification";
46 CPTextFieldDidBlurNotification = @"CPTextFieldDidBlurNotification";
47 
62 
64 
65 function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resigning, didBlurRef)
66 {
67  if (owner && domElement != inputElement.parentNode)
68  return;
69 
70  var ownerWindow = [owner window];
71 
72  if (!resigning && [ownerWindow isKeyWindow])
73  {
74  /*
75  Browsers blur text fields when a click occurs anywhere outside the text field. That is normal for browsers, but in Cocoa the key view retains focus unless the click target accepts first responder. So if we lost focus but were not told to resign and our window is still key, restore focus,
76  but only if the text field is completely within the browser window. If we restore focus when it
77  is off screen, the entire body scrolls out of our control.
78  */
79  if ([owner _isWithinUsablePlatformRect])
80  {
81  // This will prevent to jump to the focused element[[CPRunLoop mainRunLoop] performBlock:function()
82  {
83 
84  var previousScrollingOrigin = [owner _scrollToVisibleRectAndReturnPreviousOrigin];
85 
86  inputElement.focus();
87 
88  [owner _restorePreviousScrollingOrigin:previousScrollingOrigin];
89  }
90  argument:nil order:0 modes:[CPDefaultRunLoopMode]];
91  }
92  }
93 
94  CPTextFieldHandleBlur(anEvent, @ref(owner));
95  @deref(didBlurRef) = YES;
96 
97  return true;
98 }
99 
100 function CPTextFieldHandleBlur(anEvent, ownerRef)
101 {
102  @deref(ownerRef) = nil;
103 
104  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
105 }
106 
107 
109 
113 - (CPString)string
114 {
115  return self;
116 }
117 
118 @end
119 
120 CPTextFieldStateRounded = CPThemeState("rounded");
121 CPTextFieldStatePlaceholder = CPThemeState("placeholder");
122 
127 @implementation CPTextField : CPControl
128 {
129  BOOL _isEditing;
130 
131  BOOL _isEditable;
132  BOOL _isSelectable;
133  BOOL _isSecure;
134  BOOL _willBecomeFirstResponderByClick;
135  BOOL _invokedByUserEvent;
136 
137  BOOL _drawsBackground;
138 
139  CPColor _textFieldBackgroundColor;
140 
141  CPString _placeholderString;
142  CPString _stringValue;
143 
144  id <CPTextFieldDelegate> _delegate;
145  unsigned _implementedDelegateMethods;
146 
147  // NS-style Display Properties
148  CPTextFieldBezelStyle _bezelStyle;
149  BOOL _isBordered;
150  BOOL _usesSingleLineMode;
151  BOOL _wraps;
152  BOOL _scrolls;
153 }
154 
155 + (Class)_binderClassForBinding:(CPString)aBinding
156 {
157  if (aBinding === CPValueBinding)
158  return [_CPTextFieldValueBinder class];
159  else if ([aBinding hasPrefix:CPDisplayPatternValueBinding])
160  return [_CPTextFieldPatternValueBinder class];
161  else if ([aBinding hasPrefix:CPEditableBinding])
162  return [CPMultipleValueAndBinding class];
163 
164  return [super _binderClassForBinding:aBinding];
165 }
166 
167 + (CPTextField)textFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth
168 {
169  return [self textFieldWithStringValue:aStringValue placeholder:aPlaceholder width:aWidth theme:[CPTheme defaultTheme]];
170 }
171 
172 + (CPTextField)textFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth theme:(CPTheme)aTheme
173 {
174  var textField = [[self alloc] initWithFrame:CGRectMake(0.0, 0.0, aWidth, 29.0)];
175 
176  [textField setTheme:aTheme];
177  [textField setStringValue:aStringValue];
178  [textField setPlaceholderString:aPlaceholder];
179  [textField setBordered:YES];
180  [textField setBezeled:YES];
181  [textField setEditable:YES];
182 
183  [textField sizeToFit];
184 
185  return textField;
186 }
187 
188 + (CPTextField)roundedTextFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth
189 {
190  return [self roundedTextFieldWithStringValue:aStringValue placeholder:aPlaceholder width:aWidth theme:[CPTheme defaultTheme]];
191 }
192 
193 + (CPTextField)roundedTextFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth theme:(CPTheme)aTheme
194 {
195  var textField = [[CPTextField alloc] initWithFrame:CGRectMake(0.0, 0.0, aWidth, 29.0)];
196 
197  [textField setTheme:aTheme];
198  [textField setStringValue:aStringValue];
199  [textField setPlaceholderString:aPlaceholder];
200  [textField setBezelStyle:CPTextFieldRoundedBezel];
201  [textField setBordered:YES];
202  [textField setBezeled:YES];
203  [textField setEditable:YES];
204 
205  [textField sizeToFit];
206 
207  return textField;
208 }
209 
210 + (CPTextField)labelWithTitle:(CPString)aTitle
211 {
212  return [self labelWithTitle:aTitle theme:[CPTheme defaultTheme]];
213 }
214 
215 + (CPTextField)labelWithTitle:(CPString)aTitle theme:(CPTheme)aTheme
216 {
217  var textField = [[self alloc] init];
218 
219  [textField setStringValue:aTitle];
220  [textField sizeToFit];
221 
222  return textField;
223 }
224 
225 + (CPString)defaultThemeClass
226 {
227  return "textfield";
228 }
229 
230 + (CPDictionary)themeAttributes
231 {
232  return @{
233  @"bezel-inset": CGInsetMakeZero(),
234  @"content-inset": CGInsetMake(1.0, 0.0, 0.0, 0.0),
235  @"bezel-color": [CPNull null],
236  };
237 }
238 
239 
240 #pragma mark -
241 #pragma mark Control Size
242 
243 - (void)setControlSize:(CPControlSize)aControlSize
244 {
245  [super setControlSize:aControlSize];
246 
247  if ([self isBezeled])
248  [self _sizeToControlSize];
249 }
250 
251 
252 #pragma mark -
253 
254 #if PLATFORM(DOM)
255 - (DOMElement)_inputElement
256 {
258  {
259  CPTextFieldDOMTextAreaElement = document.createElement("textarea");
260  CPTextFieldDOMTextAreaElement.style.position = "absolute";
261  CPTextFieldDOMTextAreaElement.style.border = "0px";
262  CPTextFieldDOMTextAreaElement.style.padding = "0px";
263  CPTextFieldDOMTextAreaElement.style.margin = "0px";
264  CPTextFieldDOMTextAreaElement.style.background = "transparent";
265  CPTextFieldDOMTextAreaElement.style.outline = "none";
266  CPTextFieldDOMTextAreaElement.style.resize = "none";
267  CPTextFieldDOMTextAreaElement.style.overflow = "hidden";
268  CPTextFieldDOMTextAreaElement.spellcheck = NO;
269  }
270 
272  {
273  CPTextFieldDOMStandardInputElement = document.createElement("input");
274  CPTextFieldDOMStandardInputElement.style.position = "absolute";
275  CPTextFieldDOMStandardInputElement.style.border = "0px";
276  CPTextFieldDOMStandardInputElement.style.padding = "0px";
277  CPTextFieldDOMStandardInputElement.style.margin = "0px";
278  CPTextFieldDOMStandardInputElement.style.whiteSpace = "pre";
279  CPTextFieldDOMStandardInputElement.style.background = "transparent";
280  CPTextFieldDOMStandardInputElement.style.outline = "none";
281  CPTextFieldDOMStandardInputElement.spellcheck = NO;
282  }
283 
285  {
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";
295  CPTextFieldDOMPasswordInputElement.spellcheck = NO;
296  }
297 
299  {
300  CPTextFieldBlurHandler = function(anEvent)
301  {
303  anEvent,
305  CPTextFieldInputOwner ? CPTextFieldInputOwner._DOMElement : nil,
309  };
310  }
311 
313  {
315  return;
316 
317  CPTextFieldInputFunction = function(anEvent)
318  {
320  return;
321 
322  var cappEvent = [CPEvent keyEventWithType:CPKeyUp
323  location:CGPointMakeZero()
324  modifierFlags:0
326  windowNumber:[[CPApp keyWindow] windowNumber]
327  context:nil
328  characters:nil
330  isARepeat:NO
331  keyCode:nil];
332 
333  [CPTextFieldInputOwner keyUp:cappEvent];
334 
335  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
336  }
337 
340 
343 
346  }
347 
348 
349  if ([self isSecure])
351  else if (_usesSingleLineMode)
353  else
355 
357 }
358 #endif
359 
360 - (id)initWithFrame:(CGRect)aFrame
361 {
362  self = [super initWithFrame:aFrame];
363 
364  if (self)
365  {
366  [self setStringValue:@""];
367  [self setPlaceholderString:@""];
368 
369  _sendActionOn = CPKeyUpMask | CPKeyDownMask;
370 
371  [self setValue:CPNaturalTextAlignment forThemeAttribute:@"alignment"];
372  }
373 
374  return self;
375 }
376 
377 #pragma mark Controlling Editability and Selectability
378 
383 - (void)setEditable:(BOOL)shouldBeEditable
384 {
385  if (_isEditable === shouldBeEditable)
386  return;
387 
388  _isEditable = shouldBeEditable;
389 
390  if (shouldBeEditable)
391  _isSelectable = YES;
392 
393  if (_isEditable)
394  [self setThemeState:CPThemeStateEditable];
395  else
396  [self unsetThemeState:CPThemeStateEditable];
397 
398  // We only allow first responder status if the field is enable, and editable or selectable.
399  if (!(shouldBeEditable && ![self isSelectable]) && [[self window] firstResponder] === self)
400  [[self window] makeFirstResponder:nil];
401 
402  if (shouldBeEditable)
403  [self setThemeState:CPThemeStateEditable];
404  else
405  [self unsetThemeState:CPThemeStateEditable];
406 }
407 
411 - (BOOL)isEditable
412 {
413  return _isEditable;
414 }
415 
420 - (void)setEnabled:(BOOL)shouldBeEnabled
421 {
422  [super setEnabled:shouldBeEnabled];
423 
424  // We only allow first responder status if the field is enabled.
425  if (!shouldBeEnabled && [[self window] firstResponder] === self)
426  [[self window] makeFirstResponder:nil];
427 }
428 
433 - (void)setSelectable:(BOOL)aFlag
434 {
435  _isSelectable = aFlag;
436 }
437 
441 - (BOOL)isSelectable
442 {
443  return _isSelectable;
444 }
445 
450 - (void)setSecure:(BOOL)aFlag
451 {
452  _isSecure = aFlag;
453 }
454 
458 - (BOOL)isSecure
459 {
460  return _isSecure;
461 }
462 
463 // Setting the Bezel Style
468 - (void)setBezeled:(BOOL)shouldBeBezeled
469 {
470  if (shouldBeBezeled)
471  [self setThemeState:CPThemeStateBezeled];
472  else
473  [self unsetThemeState:CPThemeStateBezeled];
474 }
475 
479 - (BOOL)isBezeled
480 {
481  return [self hasThemeState:CPThemeStateBezeled];
482 }
483 
488 - (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
489 {
490  var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
491 
492  if (shouldBeRounded)
493  [self setThemeState:CPTextFieldStateRounded];
494  else
495  [self unsetThemeState:CPTextFieldStateRounded];
496 }
497 
501 - (CPTextFieldBezelStyle)bezelStyle
502 {
503  if ([self hasThemeState:CPTextFieldStateRounded])
505 
506  return CPTextFieldSquareBezel;
507 }
508 
513 - (void)setBordered:(BOOL)shouldBeBordered
514 {
515  if (shouldBeBordered)
516  [self setThemeState:CPThemeStateBordered];
517  else
518  [self unsetThemeState:CPThemeStateBordered];
519 }
520 
524 - (BOOL)isBordered
525 {
526  return [self hasThemeState:CPThemeStateBordered];
527 }
528 
533 - (void)setDrawsBackground:(BOOL)shouldDrawBackground
534 {
535  if (_drawsBackground == shouldDrawBackground)
536  return;
537 
538  _drawsBackground = shouldDrawBackground;
539 
540  [self setNeedsLayout];
541  [self setNeedsDisplay:YES];
542 }
543 
547 - (BOOL)drawsBackground
548 {
549  return _drawsBackground;
550 }
551 
556 - (void)setTextFieldBackgroundColor:(CPColor)aColor
557 {
558  if (_textFieldBackgroundColor == aColor)
559  return;
560 
561  _textFieldBackgroundColor = aColor;
562 
563  [self setNeedsLayout];
564  [self setNeedsDisplay:YES];
565 }
566 
570 - (CPColor)textFieldBackgroundColor
571 {
572  return _textFieldBackgroundColor;
573 }
574 
576 - (void)_setUsesSingleLineMode:(BOOL)aFlag
577 {
578  _usesSingleLineMode = aFlag;
579 }
580 
582 - (void)_setWraps:(BOOL)aFlag
583 {
584  _wraps = aFlag;
585 }
586 
588 - (void)_setScrolls:(BOOL)aFlag
589 {
590  _scrolls = aFlag;
591 }
592 
594 - (BOOL)acceptsFirstResponder
595 {
596  return [self isEnabled] && ([self isEditable] || [self isSelectable]) && [self _isWithinUsablePlatformRect];
597 }
598 
600 - (BOOL)becomeFirstResponder
601 {
602  if (![self isEnabled] || ![super becomeFirstResponder])
603  return NO;
604 
605  // As long as we are the first responder we need to monitor the key status of our window.
606  [self _setObserveWindowKeyNotifications:YES];
607 
608  _isEditing = NO;
609 
610  if ([[self window] isKeyWindow] && [self isEditable])
611  return [self _becomeFirstKeyResponder];
612 
613  return YES;
614 }
615 
616 /*
617  A text field can be the first responder without necessarily being the focus of keyboard input. For example, it might be the first responder of window A but window B is the main and key window. It's important we don't put a focused input field into a text field in a non-key window, even if that field is the first responder, because the key window might also have a first responder text field which the user will expect to receive keyboard input.
618 
619  Since a first responder but non-key window text field can't receive input it should not even look like an active text field (Cocoa has a "slightly active" text field look it uses when another window is the key window, but Cappuccino doesn't today.)
620 
621  It's also possible for a text field to be non-editable but selectable in which case it can also become the first responder -
622  this is what allows text to be copied from it.
623 */
624 - (BOOL)_becomeFirstKeyResponder
625 {
626  // If the text field is still not completely on screen, refuse to become
627  // first responder, because the browser will scroll it into view out of our control.
628  if (![self _isWithinUsablePlatformRect])
629  return NO;
630 
631  // A selectable but non-editable text field may be the first responder, but never the
632  // first key responder (first key responder indicating editability.)
633  if (![self isEditable])
634  return NO;
635 
636  [self setThemeState:CPThemeStateEditing];
637 
638  [self _updatePlaceholderState];
639 
640  [self setNeedsLayout];
641 
642  _stringValue = [self stringValue];
643 
644 
645 #if PLATFORM(DOM)
646 
647  [self _setCSSStyleForInputElement];
648 
649  var element = [self _inputElement];
650  element.value = _stringValue;
651  _DOMElement.appendChild(element);
652 
654 
655  if (document.attachEvent)
656  {
657  CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
658  CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
659 
660  [[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
661  [[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
662  }
663 
664  CPTextFieldInputOwner = self;
665 
666  // This will prevent to jump to the focused element// Select the text if the textfield became first responder through keyboard interaction[[CPRunLoop mainRunLoop] performBlock:function()
667  {
668  if (CPTextFieldInputOwner !== self)
669  return;
670 
671 
672  var previousScrollingOrigin = [self _scrollToVisibleRectAndReturnPreviousOrigin];
673 
674  element.focus();
675 
676  [self _restorePreviousScrollingOrigin:previousScrollingOrigin];
677 
678 
679  if (!_willBecomeFirstResponderByClick)
680  {
681  [self _selectText:self immediately:YES];
682  }
683  else
684  {
685  var point = CGPointMake([self convertPointFromBase:[[CPApp currentEvent] locationInWindow]].x - [self currentValueForThemeAttribute:@"content-inset"].left, 0),
686  position = [CPPlatformString charPositionOfString:[self stringValue] withFont:[self font] forPoint:point];
687 
688  [self setSelectedRange:CPMakeRange(position, 0)];
689  }
690 
691  _willBecomeFirstResponderByClick = NO;
692 
693  [self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
694  } argument:nil order:0 modes:[CPDefaultRunLoopMode]];
695 
696 #endif
697 
698  return YES;
699 }
700 
705 - (void)_setEnableCSSSelection:(BOOL)shouldEnable
706 {
707 #if PLATFORM (DOM)
709  CPTexFieldCurrentCSSSelectableField._DOMElement.style[CPBrowserStyleProperty(@"user-select")] = @"none";
710 
712  _DOMElement.style[CPBrowserStyleProperty(@"user-select")] = shouldEnable ? @"text" : @"none";
713 #endif
714 }
715 
720 - (void)_setCSSStyleForInputElement
721 {
722 #if PLATFORM(DOM)
723 
724  var element = [self _inputElement],
725  font = [self currentValueForThemeAttribute:@"font"],
726  lineHeight = [font defaultLineHeightForFont],
727  contentRect = [self contentRectForBounds:[self bounds]],
728  verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"],
729  left = CGRectGetMinX(contentRect);
730 
731  // If the browser has a built in left padding, compensate for it. We need the input text to be exactly on top of the original text.
733  left -= 1;
734 
735  switch (verticalAlign)
736  {
738  var topPoint = CGRectGetMinY(contentRect) + "px";
739  break;
740 
742  var topPoint = (CGRectGetMidY(contentRect) - (lineHeight / 2)) + "px";
743  break;
744 
746  var topPoint = (CGRectGetMaxY(contentRect) - lineHeight) + "px";
747  break;
748 
749  default:
750  var topPoint = CGRectGetMinY(contentRect) + "px";
751  break;
752  }
753 
754  if ([self hasThemeState:CPTextFieldStatePlaceholder])
755  element.style.color = [[self valueForThemeAttribute:@"text-color" inState:CPTextFieldStatePlaceholder] cssString];
756  else
757  element.style.color = [[self valueForThemeAttribute:@"text-color" inState:CPThemeStateEditing] cssString];
758 
759  switch ([self alignment])
760  {
762  element.style.textAlign = "center";
763  break;
764 
766  element.style.textAlign = "right";
767  break;
768 
770  element.style.textAlign = "";
771  break;
772 
773  default:
774  element.style.textAlign = "left";
775  }
776 
777  var isTextArea = element.nodeName.toUpperCase() == "TEXTAREA";
778 
779  element.style.zIndex = 1000;
780  element.style.top = topPoint;
781  element.style.lineHeight = ROUND(lineHeight) + "px";
782  element.style.height = isTextArea ? CGRectGetHeight(contentRect) + "px" : ROUND(lineHeight) + "px";;
783  element.style.width = CGRectGetWidth(contentRect) + "px";
784  element.style.left = left + "px";
785  element.style.verticalAlign = "top";
786  element.style.cursor = "auto";
787  element.style.font = [font cssString];
788 
789  if (isTextArea)
790  element.style.whiteSpace = _wraps ? "pre" : "nowrap";
791 
792 #endif
793 }
794 
796 - (BOOL)resignFirstResponder
797 {
798 #if PLATFORM(DOM)
799  // We might have been the first responder without actually editing.
800  if (_isEditing && CPTextFieldInputOwner === self)
801  {
802  var element = [self _inputElement],
803  newValue = element.value,
804  error = @"";
805 
806  if (newValue !== _stringValue)
807  {
808  [self _setStringValue:newValue];
809  }
810 
811  // If there is a formatter, always give it a chance to reject the resignation,
812  // even if the value has not changed.
813  if ([self _valueIsValid:newValue] === NO)
814  {
815  // This will prevent to jump to the focused element
816  var previousScrollingOrigin = [self _scrollToVisibleRectAndReturnPreviousOrigin];
817 
818  element.focus();
819 
820  [self _restorePreviousScrollingOrigin:previousScrollingOrigin];
821 
822  return NO;
823  }
824  }
825 #endif
826 
827  // When we are no longer the first responder we don't worry about the key status of our window anymore.
828  [self _setObserveWindowKeyNotifications:NO];
829 
830  if ([[self window] isKeyWindow])
831  [self _resignFirstKeyResponder];
832 
833  _isEditing = NO;
834 
835  if ([self isEditable])
836  {
837  [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:@{"CPTextMovement": [self _currentTextMovement]}]];
838 
839  if ([self sendsActionOnEndEditing])
840  [self sendAction:[self action] to:[self target]];
841  }
842 
843  [self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
844 
845  return YES;
846 }
847 
848 - (void)_resignFirstKeyResponder
849 {
850  [self unsetThemeState:CPThemeStateEditing];
851 
852  // Cache the formatted string
853  _stringValue = [self stringValue];
854 
855  _willBecomeFirstResponderByClick = NO;
856 
857  [self _updatePlaceholderState];
858  [self setNeedsLayout];
859 
860 #if PLATFORM(DOM)
861 
862  var element = [self _inputElement];
863 
865 
867  element.blur();
868 
871 
874 
875  if (element.parentNode == _DOMElement)
876  element.parentNode.removeChild(element);
877 
879 
880  if (document.attachEvent)
881  {
882  [[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
883  [[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
884 
887  }
888 
889 #endif
890 }
891 
892 - (void)_setObserveWindowKeyNotifications:(BOOL)shouldObserve
893 {
894  if (shouldObserve)
895  {
896  [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:) name:CPWindowDidResignKeyNotification object:[self window]];
897  [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:) name:CPWindowDidBecomeKeyNotification object:[self window]];
898  }
899  else
900  {
901  [[CPNotificationCenter defaultCenter] removeObserver:self name:CPWindowDidResignKeyNotification object:[self window]];
902  [[CPNotificationCenter defaultCenter] removeObserver:self name:CPWindowDidBecomeKeyNotification object:[self window]];
903  }
904 }
905 
906 - (void)_removeObservers
907 {
908  if (!_isObserving)
909  return;
910 
911  [super _removeObservers];
912  [self _setObserveWindowKeyNotifications:NO];
913 }
914 
915 - (void)_addObservers
916 {
917  if (_isObserving)
918  return;
919 
920  [super _addObservers];
921 
922  if ([[self window] firstResponder] === self)
923  [self _setObserveWindowKeyNotifications:YES];
924 }
925 
926 - (void)_windowDidResignKey:(CPNotification)aNotification
927 {
928  if (![[self window] isKeyWindow])
929  [self _resignFirstKeyResponder];
930 }
931 
932 - (void)_windowDidBecomeKey:(CPNotification)aNotification
933 {
934  if (!([self isEnabled] && [self isEditable]))
935  return;
936 
937  var wind = [self window];
938 
939  if ([wind isKeyWindow] && [wind firstResponder] === self)
940  if (![self _becomeFirstKeyResponder])
941  [wind makeFirstResponder:nil];
942 }
943 
944 - (BOOL)_valueIsValid:(CPString)aValue
945 {
946 #if PLATFORM(DOM)
947 
948  var error = @"";
949 
950  if ([self _setStringValue:aValue isNewValue:NO errorDescription:@ref(error)] === NO)
951  {
952  var acceptInvalidValue = NO;
953 
955  acceptInvalidValue = [_delegate control:self didFailToFormatString:aValue errorDescription:error];
956 
957  if (acceptInvalidValue === NO)
958  return NO;
959  }
960 
961 #endif
962 
963  return YES;
964 }
965 
970 - (BOOL)needsPanelToBecomeKey
971 {
972  return [self acceptsFirstResponder];
973 }
974 
978 - (BOOL)acceptsFirstMouse:(CPEvent)anEvent
979 {
980  return [self acceptsFirstResponder];
981 }
982 
983 - (void)_didEdit
984 {
985  if (!_isEditing)
986  {
987  _isEditing = YES;
988  [self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
989  }
990 
991  [self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
992 }
993 
994 - (void)mouseMoved:(CPEvent)anEvent
995 {
996  [super mouseMoved:anEvent];
997  [self _updateCursorForEvent:anEvent];
998 }
999 
1000 - (void)mouseDown:(CPEvent)anEvent
1001 {
1002  // Don't track! (ever?)
1003  if ([self isEditable] && [self isEnabled])
1004  {
1005  _willBecomeFirstResponderByClick = YES;
1006  [[self window] makeFirstResponder:self];
1007  }
1008  else if ([self isSelectable])
1009  {
1010  [self _setEnableCSSSelection:YES];
1011  if (document.attachEvent)
1012  {
1013  CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
1014  CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
1015 
1016  [[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
1017  [[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
1018  }
1019  return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
1020  }
1021  else
1022  return [[self nextResponder] mouseDown:anEvent];
1023 }
1024 
1025 - (void)mouseUp:(CPEvent)anEvent
1026 {
1027  if (![self isEnabled] || !([self isSelectable] || [self isEditable]))
1028  [[self nextResponder] mouseUp:anEvent];
1029  else if ([self isSelectable])
1030  {
1031  if (document.attachEvent)
1032  {
1033  [[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
1034  [[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
1035 
1038  }
1039 
1040  // TODO clickCount === 2 should select the clicked word.
1041 
1042  if ([[CPApp currentEvent] clickCount] === 3)
1043  {
1044  [self selectText:nil];
1045  return;
1046  }
1047 
1048  return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
1049  }
1050 }
1051 
1052 - (void)rightMouseDown:(CPEvent)anEvent
1053 {
1054  if ([self menuForEvent:anEvent] || [[self nextResponder] isKindOfClass:CPView])
1055  [super rightMouseDown:anEvent];
1056  else
1057  [[[anEvent window] platformWindow] _propagateContextMenuDOMEvent:YES];
1058 }
1059 
1060 - (void)mouseDragged:(CPEvent)anEvent
1061 {
1062  if (![self isEnabled] || !([self isSelectable] || [self isEditable]))
1063  [[self nextResponder] mouseDragged:anEvent];
1064  else if ([self isSelectable])
1065  return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
1066 }
1067 
1068 - (void)keyUp:(CPEvent)anEvent
1069 {
1070  if (!([self isEnabled] && [self isEditable]))
1071  return;
1072 
1073 #if PLATFORM(DOM)
1074  var newValue = [self _inputElement].value;
1075 
1076  if (newValue !== _stringValue)
1077  {
1078  [self _setStringValue:newValue];
1079  [self _didEdit];
1080  }
1081 
1082  [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
1083 #endif
1084 }
1085 
1086 - (void)keyDown:(CPEvent)anEvent
1087 {
1088  if (!([self isEnabled] && [self isEditable]))
1089  return;
1090 
1091  // CPTextField uses an HTML input element to take the input so we need to
1092  // propagate the dom event so the element is updated. This has to be done
1093  // before interpretKeyEvents: though so individual commands have a chance
1094  // to override this (escape to clear the text in a search field for example).
1095  [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
1096 
1097  // Set a flag so that key handling methods (such as deleteBackward:)
1098  // know they were invoked from a user event.
1099  _invokedByUserEvent = !!anEvent._DOMEvent;
1100  [self interpretKeyEvents:[anEvent]];
1101  _invokedByUserEvent = NO;
1102 
1103  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
1104 }
1105 
1115 - (void)doCommandBySelector:(SEL)aSelector
1116 {
1117  if ([self respondsToSelector:aSelector])
1118  [self performSelector:aSelector];
1119 }
1120 
1121 - (void)insertNewline:(id)sender
1122 {
1123  if (!([self isEnabled] && [self isEditable]))
1124  return;
1125 
1126  var newValue = [self _inputElement].value;
1127 
1128  if (newValue !== _stringValue)
1129  {
1130  [self _setStringValue:newValue];
1131  [self _didEdit];
1132  }
1133 
1134  if ([self _valueIsValid:_stringValue])
1135  {
1136  // If _isEditing == YES then the target action can also be called via
1137  // resignFirstResponder, and it is possible that the target action
1138  // itself will change this textfield's responder status, so start by
1139  // setting the _isEditing flag to NO to prevent the target action being
1140  // called twice (once below and once from resignFirstResponder).
1141  if (_isEditing)
1142  {
1143  _isEditing = NO;
1144  [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:@{"CPTextMovement": [self _currentTextMovement]}]];
1145  }
1146 
1147  // If there is no target action, or the sendAction call returns
1148  // success.
1149  if (![self action] || [self sendAction:[self action] to:[self target]])
1150  {
1151  [self selectAll:nil];
1152  }
1153  }
1154 
1155  [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
1156 }
1157 
1158 - (void)insertNewlineIgnoringFieldEditor:(id)sender
1159 {
1160  [self _insertCharacterIgnoringFieldEditor:CPNewlineCharacter];
1161 }
1162 
1163 - (void)insertTabIgnoringFieldEditor:(id)sender
1164 {
1165  [self _insertCharacterIgnoringFieldEditor:CPTabCharacter];
1166 }
1167 
1168 - (void)_insertCharacterIgnoringFieldEditor:(CPString)aCharacter
1169 {
1170  if (!([self isEnabled] && [self isEditable]))
1171  return;
1172 
1173 #if PLATFORM(DOM)
1174 
1175  var oldValue = _stringValue,
1176  range = [self selectedRange],
1177  element = [self _inputElement];
1178 
1179  // we don't need to do this in case of textarea
1180  // or we will end up with 2 carriage returns
1181  if (aCharacter != CPNewlineCharacter || element.nodeName.toUpperCase() != "TEXTAREA" || !CPFeatureIsCompatible(CPAltEnterTextAreaFeature))
1182  element.value = [element.value stringByReplacingCharactersInRange:[self selectedRange] withString:aCharacter];
1183 
1184  [self _setStringValue:element.value];
1185 
1186  // NOTE: _stringValue is now the current input element value
1187  if (oldValue !== _stringValue)
1188  {
1189  [self _didEdit];
1190  }
1191 
1192 #endif
1193 }
1194 
1195 - (void)textDidBlur:(CPNotification)note
1196 {
1197  // this looks to prevent false propagation of notifications for other objects
1198  if ([note object] != self)
1199  return;
1200 
1201  if (_implementedDelegateMethods & CPTextFieldDelegate_controlTextDidBlur_)
1202  [_delegate controlTextDidBlur:note];
1203 
1205 }
1206 
1207 - (void)textDidFocus:(CPNotification)note
1208 {
1209  // this looks to prevent false propagation of notifications for other objects
1210  if ([note object] !== self)
1211  return;
1212 
1213  if (_implementedDelegateMethods & CPTextFieldDelegate_controlTextDidFocus_)
1214  [_delegate controlTextDidFocus:note];
1215 
1217 }
1218 
1219 - (void)textDidChange:(CPNotification)note
1220 {
1221  if ([note object] !== self)
1222  return;
1223 
1224  [self _continuouslyReverseSetBinding];
1225 
1226  if (_implementedDelegateMethods & CPTextFieldDelegate_controlTextDidChange_)
1227  [_delegate controlTextDidChange:note];
1228 
1229  [super textDidChange:note];
1230 }
1231 
1232 - (void)textDidBeginEditing:(CPNotification)note
1233 {
1234  //this looks to prevent false propagation of notifications for other objects
1235  if ([note object] != self)
1236  return;
1237 
1238  if (_implementedDelegateMethods & CPTextFieldDelegate_controlTextDidBeginEditing_)
1239  [_delegate controlTextDidBeginEditing:[[CPNotification alloc] initWithName:CPControlTextDidBeginEditingNotification object:self userInfo:@{"CPFieldEditor": [note object]}]]
1240 
1241  [super textDidBeginEditing:note];
1242 }
1243 
1244 - (void)textDidEndEditing:(CPNotification)note
1245 {
1246  //this looks to prevent false propagation of notifications for other objects
1247  if ([note object] != self)
1248  return;
1249 
1250  [super textDidEndEditing:note];
1251 
1252  if (_implementedDelegateMethods & CPTextFieldDelegate_controlTextDidEndEditing_)
1253  [_delegate controlTextDidEndEditing:note];
1254 }
1255 
1256 - (void)_updateCursorForEvent:(CPEvent)anEvent
1257 {
1258  var frame = CGRectMakeCopy([self frame]),
1259  contentInset = [self currentValueForThemeAttribute:@"content-inset"];
1260 
1261  frame = [[self superview] convertRectToBase:CGRectInsetByInset(frame, contentInset)];
1262 
1263  if ([self isEnabled] && ([self isSelectable] || [self isEditable]) && CGRectContainsPoint(frame, [anEvent locationInWindow]))
1264  {
1265 #if PLATFORM(DOM)
1266  self._DOMElement.style.cursor = "text";
1267 #endif
1268  }
1269  else
1270  {
1271 #if PLATFORM(DOM)
1272  self._DOMElement.style.cursor = "default";
1273 #endif
1274  }
1275 }
1276 
1280 - (id)objectValue
1281 {
1282  return [super objectValue];
1283 }
1284 
1285 /*
1286  Sets the internal string value without updating the value in the input element.
1287  This should only be invoked when the underlying text element's value has changed.
1288 */
1289 - (BOOL)_setStringValue:(CPString)aValue
1290 {
1291  return [self _setStringValue:aValue isNewValue:YES errorDescription:nil];
1292 }
1293 
1298 - (BOOL)_setStringValue:(CPString)aValue isNewValue:(BOOL)isNewValue errorDescription:(CPStringRef)anError
1299 {
1300  _stringValue = aValue;
1301 
1302  var objectValue = aValue,
1303  formatter = [self formatter],
1304  result = YES;
1305 
1306  if (formatter)
1307  {
1308  var object = nil;
1309 
1310  if ([formatter getObjectValue:@ref(object) forString:aValue errorDescription:anError])
1311  objectValue = object;
1312  else
1313  {
1314  objectValue = undefined; // Mark the value as invalid
1315  result = NO;
1316  }
1317 
1318  isNewValue |= objectValue !== [super objectValue];
1319  }
1320 
1321  if (isNewValue)
1322  {
1323  [self willChangeValueForKey:@"objectValue"];
1324  [super setObjectValue:objectValue];
1325  [self _updatePlaceholderState];
1326  [self didChangeValueForKey:@"objectValue"];
1327  }
1328 
1329  return result;
1330 }
1331 
1332 - (void)setObjectValue:(id)aValue
1333 {
1334  [self _setObjectValue:aValue useFormatter:YES];
1335 }
1336 
1337 - (void)_setObjectValue:(id)aValue useFormatter:(BOOL)useFormatter
1338 {
1339  [super setObjectValue:aValue];
1340 
1341  var formatter = [self formatter];
1342 
1343  if (useFormatter && formatter)
1344  {
1345  // If there is a formatter, make sure the object value can be formatted successfully
1346  var formattedString = [self hasThemeState:CPThemeStateEditing] ? [formatter editingStringForObjectValue:aValue] : [formatter stringForObjectValue:aValue];
1347 
1348  if (formattedString === nil)
1349  {
1350  var value = nil;
1351 
1352  // Formatting failed, get an "empty" object by formatting an empty string.
1353  // If that fails, the value is undefined.
1354  if ([formatter getObjectValue:@ref(value) forString:@"" errorDescription:nil] === NO)
1355  value = undefined;
1356 
1357  [super setObjectValue:value];
1358  _stringValue = (value === nil || value === undefined) ? @"" : String(value);
1359  }
1360  else
1361  _stringValue = formattedString;
1362  }
1363  else
1364  _stringValue = [self stringValue];
1365 
1366 #if PLATFORM(DOM)
1367 
1368  if ((CPTextFieldInputOwner === self || [[self window] firstResponder] === self) && [[self window] isKeyWindow])
1369  [self _inputElement].value = _stringValue;
1370 
1371 #endif
1372 
1373  [self _updatePlaceholderState];
1374 }
1375 
1376 - (void)_updatePlaceholderState
1377 {
1378  if (!_stringValue || _stringValue.length === 0)
1379  [self setThemeState:CPTextFieldStatePlaceholder];
1380  else
1381  [self unsetThemeState:CPTextFieldStatePlaceholder];
1382 }
1383 
1388 - (void)setPlaceholderString:(CPString)aStringValue
1389 {
1390  if (_placeholderString === aStringValue)
1391  return;
1392 
1393  _placeholderString = aStringValue;
1394 
1395  // Only update things if we need to show the placeholder
1396  if ([self hasThemeState:CPTextFieldStatePlaceholder])
1397  {
1398  [self setNeedsLayout];
1399  [self setNeedsDisplay:YES];
1400  }
1401 }
1402 
1406 - (CPString)placeholderString
1407 {
1408  return _placeholderString;
1409 }
1410 
1431 - (void)sizeToFit
1432 {
1433  [self setFrameSize:[self _minimumFrameSize]];
1434 }
1435 
1436 - (CGSize)_minimumFrameSize
1437 {
1438  var frameSize = [self frameSize],
1439  contentInset = [self currentValueForThemeAttribute:@"content-inset"],
1440  minSize = [self currentValueForThemeAttribute:@"min-size"],
1441  maxSize = [self currentValueForThemeAttribute:@"max-size"],
1442  lineBreakMode = [self lineBreakMode],
1443  text = (_stringValue || @" "),
1444  textSize = CGSizeMakeCopy(frameSize),
1445  font = [self currentValueForThemeAttribute:@"font"];
1446 
1447  textSize.width -= contentInset.left + contentInset.right;
1448  textSize.height -= contentInset.top + contentInset.bottom;
1449 
1450  if (frameSize.width !== 0 &&
1451  ![self isBezeled] &&
1452  (lineBreakMode === CPLineBreakByWordWrapping || lineBreakMode === CPLineBreakByCharWrapping))
1453  {
1454  textSize = [text sizeWithFont:font inWidth:textSize.width];
1455  }
1456  else
1457  {
1458  textSize = [text sizeWithFont:font];
1459 
1460  // Account for possible fractional pixels at right edge
1461  textSize.width += 1;
1462  }
1463 
1464  // Account for possible fractional pixels at bottom edge
1465  textSize.height += 1;
1466 
1467  frameSize.height = textSize.height + contentInset.top + contentInset.bottom;
1468 
1469  if ([self isBezeled])
1470  {
1471  frameSize.height = MAX(frameSize.height, minSize.height);
1472 
1473  if (maxSize.width > 0.0)
1474  frameSize.width = MIN(frameSize.width, maxSize.width);
1475 
1476  if (maxSize.height > 0.0)
1477  frameSize.height = MIN(frameSize.height, maxSize.height);
1478  }
1479  else
1480  frameSize.width = textSize.width + contentInset.left + contentInset.right;
1481 
1482  frameSize.width = MAX(frameSize.width, minSize.width);
1483 
1484  return frameSize;
1485 }
1486 
1490 - (void)selectText:(id)sender
1491 {
1492  [self _selectText:sender immediately:NO];
1493 }
1494 
1495 - (void)_selectText:(id)sender immediately:(BOOL)immediately
1496 {
1497  // Selecting the text in a field makes it the first responder
1498  if ([self isEditable] || [self isSelectable])
1499  {
1500  var wind = [self window];
1501 
1502 #if PLATFORM(DOM)
1503  if ([self isEditable])
1504  {
1505  var element = [self _inputElement];
1506 
1507  if ([wind firstResponder] === self)
1508  {
1509  if (immediately)
1510  element.select();
1511  else
1512  [[CPRunLoop mainRunLoop] performBlock:function(){ element.select(); } argument:nil order:0 modes:[CPDefaultRunLoopMode]];
1513  }
1514  else if (wind !== nil && [wind makeFirstResponder:self])
1515  [self _selectText:sender immediately:immediately];
1516  }
1517  else
1518  {
1519  [self setSelectedRange:CPMakeRange(0, _stringValue.length)];
1520  }
1521 #else
1522  // Even if we can't actually select the text we need to preserve the first
1523  // responder side effect.
1524  if (wind !== nil && [wind firstResponder] !== self)
1525  [wind makeFirstResponder:self];
1526 #endif
1527  }
1528 
1529 }
1530 
1531 - (void)copy:(id)sender
1532 {
1533  // First write to the Cappuccino clipboard.
1534  var stringToCopy = nil;
1535 
1536  if ([self isEditable])
1537  {
1538  var selectedRange = [self selectedRange];
1539 
1540  if (selectedRange.length < 1)
1541  return;
1542 
1543  stringToCopy = [_stringValue substringWithRange:selectedRange];
1544  }
1545  else
1546  {
1547  // selectedRange won't work if we're displaying our text using a <div>. Instead we have to ask the browser
1548  // what's selected and hope it's right in a Cappuccino context as well.
1549 #if PLATFORM(DOM)
1550  stringToCopy = [[[self window] platformWindow] _selectedText];
1551 #endif
1552  }
1553 
1554  var pasteboard = [CPPasteboard generalPasteboard];
1555 
1556  [pasteboard declareTypes:[CPStringPboardType] owner:nil];
1557  [pasteboard setString:stringToCopy forType:CPStringPboardType];
1558 
1559  if ([CPPlatform isBrowser])
1560  {
1561  // Then also allow the browser to capture the copied text into the system clipboard.
1562  [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
1563  }
1564 }
1565 
1566 - (void)cut:(id)sender
1567 {
1568  if (![self isEnabled])
1569  return;
1570 
1571  [self copy:sender];
1572 
1573  if (![self isEditable])
1574  return;
1575 
1576  if (![[CPApp currentEvent] _platformIsEffectingCutOrPaste])
1577  {
1578  [self deleteBackward:sender];
1579  }
1580  else
1581  {
1582  // Allow the browser's standard cut handling. This should also result in the deleteBackward: happening.
1583  [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
1584 
1585  // If we don't have an oninput listener, we won't detect the change made by the cut and need to fake a key up "soon".
1588  }
1589 }
1590 
1591 - (void)paste:(id)sender
1592 {
1593  if (!([self isEnabled] && [self isEditable]))
1594  return;
1595 
1596  if (![[CPApp currentEvent] _platformIsEffectingCutOrPaste])
1597  {
1598  var pasteboard = [CPPasteboard generalPasteboard];
1599 
1600  if (![[pasteboard types] containsObject:CPStringPboardType])
1601  return;
1602 
1603  [self deleteBackward:sender];
1604 
1605  var selectedRange = [self selectedRange],
1606  pasteString = [pasteboard stringForType:CPStringPboardType],
1607  newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
1608 
1609  [self setStringValue:newValue];
1610  [self _didEdit];
1611  [self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
1612  }
1613  // If we don't have an oninput listener, we won't detect the change made by the cut and need to fake a key up "soon".
1614  else
1615  {
1616  // Allow the browser's standard paste handling.
1617  [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
1618 
1621  }
1622 }
1623 
1624 - (CPRange)selectedRange
1625 {
1626  // TODO Need a way to figure out the selected range if we're not using an input. Need
1627  // to get whole document selection and somehow see which part is inside of this text field.
1628  if ([[self window] firstResponder] !== self)
1629  return CPMakeRange(0, 0);
1630 
1631 #if PLATFORM(DOM)
1632 
1633  // we wrap this in try catch because firefox will throw an exception in certain instances
1634  try
1635  {
1636  var inputElement = [self _inputElement],
1637  selectionStart = inputElement.selectionStart,
1638  selectionEnd = inputElement.selectionEnd;
1639 
1640  if ([selectionStart isKindOfClass:CPNumber])
1641  return CPMakeRange(selectionStart, selectionEnd - selectionStart);
1642 
1643  // browsers which don't support selectionStart/selectionEnd (aka IE).
1644  var theDocument = inputElement.ownerDocument || inputElement.document,
1645  selectionRange = theDocument.selection.createRange(),
1646  range = inputElement.createTextRange();
1647 
1648  if (range.inRange(selectionRange))
1649  {
1650  range.setEndPoint('EndToStart', selectionRange);
1651  return CPMakeRange(range.text.length, selectionRange.text.length);
1652  }
1653  }
1654  catch (e)
1655  {
1656  // fall through to the return
1657  }
1658 
1659 #endif
1660 
1661  return CPMakeRange(0, 0);
1662 }
1663 
1664 - (void)setSelectedRange:(CPRange)aRange
1665 {
1666  if (![[self window] firstResponder] === self)
1667  return;
1668 
1669 #if PLATFORM(DOM)
1670 
1671  if (![self isEditable])
1672  {
1673  // No input element - selectable text field only.
1674  var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
1675  positioned:CPWindowAbove
1676  relativeToEphemeralSubviewNamed:@"bezel-view"];
1677 
1678  if (contentView)
1679  [contentView setSelectedRange:aRange];
1680  }
1681  else
1682  {
1683  // Input element
1684  var inputElement = [self _inputElement];
1685 
1686  try
1687  {
1688  if ([inputElement.selectionStart isKindOfClass:CPNumber])
1689  {
1690  inputElement.selectionStart = aRange.location;
1691  inputElement.selectionEnd = CPMaxRange(aRange);
1692  }
1693  else
1694  {
1695  // browsers which don't support selectionStart/selectionEnd (aka IE).
1696  var theDocument = inputElement.ownerDocument || inputElement.document,
1697  existingRange = theDocument.selection.createRange(),
1698  range = inputElement.createTextRange();
1699 
1700  if (range.inRange(existingRange))
1701  {
1702  range.collapse(true);
1703  range.move('character', aRange.location);
1704  range.moveEnd('character', aRange.length);
1705  range.select();
1706  }
1707  }
1708  }
1709  catch (e)
1710  {
1711  }
1712  }
1713 #endif
1714 }
1715 
1716 - (void)selectAll:(id)sender
1717 {
1718  [self selectText:sender];
1719 }
1720 
1721 - (void)deleteBackward:(id)sender
1722 {
1723  if (!([self isEnabled] && [self isEditable]))
1724  return;
1725 
1726  var selectedRange = [self selectedRange];
1727 
1728  if (selectedRange.length === 0)
1729  {
1730  if (selectedRange.location < 1)
1731  return;
1732 
1733  // Delete a single element backward from the insertion point if there's no selection.
1734  selectedRange.location -= 1;
1735  selectedRange.length += 1;
1736  }
1737 
1738  [self _replaceCharactersInRange:selectedRange withCharacters:@""];
1739 }
1740 
1741 - (void)delete:(id)sender
1742 {
1743  if (!([self isEnabled] && [self isEditable]))
1744  return;
1745 
1746  // delete: only works when there's a selection (as opposed to deleteForward: and deleteBackward:).
1747  var selectedRange = [self selectedRange];
1748 
1749  if (selectedRange.length < 1)
1750  return;
1751 
1752  [self _replaceCharactersInRange:selectedRange withCharacters:@""];
1753 }
1754 
1755 - (void)deleteForward:(id)sender
1756 {
1757  if (!([self isEnabled] && [self isEditable]))
1758  return;
1759 
1760  var selectedRange = [self selectedRange];
1761 
1762  if (selectedRange.length === 0)
1763  {
1764  if (selectedRange.location >= _stringValue.length)
1765  return;
1766 
1767  // Delete a single element forward from the insertion point if there's no selection.
1768  selectedRange.length += 1;
1769  }
1770 
1771  [self _replaceCharactersInRange:selectedRange withCharacters:@""];
1772 }
1773 
1774 - (void)_replaceCharactersInRange:(CPRange)range withCharacters:(CPString)characters
1775 {
1776  var newValue = [_stringValue stringByReplacingCharactersInRange:range withString:characters];
1777 
1778  if (_invokedByUserEvent)
1779  {
1780  [self _setStringValue:newValue];
1781  }
1782  else
1783  {
1784  [self _setObjectValue:newValue useFormatter:NO];
1785  [self setSelectedRange:CPMakeRange(range.location, 0)];
1786 
1787 #if PLATFORM(DOM)
1788  // Since we just performed the deletion manually, we don't need the browser to do anything else.
1789  [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
1790 #endif
1791  }
1792 
1793  [self _didEdit];
1794 }
1795 
1796 #pragma mark Setting the Delegate
1797 
1798 - (void)setDelegate:(id <CPTextFieldDelegate>)aDelegate
1799 {
1800  if (_delegate === aDelegate)
1801  return;
1802 
1803  _delegate = aDelegate;
1804  _implementedDelegateMethods = 0;
1805 
1806  if ([_delegate respondsToSelector:@selector(control:didFailToFormatString:errorDescription:)])
1808 
1809  if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
1810  _implementedDelegateMethods |= CPTextFieldDelegate_controlTextDidBeginEditing_;
1811 
1812  if ([_delegate respondsToSelector:@selector(controlTextDidChange:)])
1813  _implementedDelegateMethods |= CPTextFieldDelegate_controlTextDidChange_;
1814 
1815  if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)])
1816  _implementedDelegateMethods |= CPTextFieldDelegate_controlTextDidEndEditing_;
1817 
1818  if ([_delegate respondsToSelector:@selector(controlTextDidFocus:)])
1819  _implementedDelegateMethods |= CPTextFieldDelegate_controlTextDidFocus_;
1820 
1821  if ([_delegate respondsToSelector:@selector(controlTextDidBlur:)])
1822  _implementedDelegateMethods |= CPTextFieldDelegate_controlTextDidBlur_;
1823 }
1824 
1826 {
1827  return _delegate;
1828 }
1829 
1830 - (CGRect)contentRectForBounds:(CGRect)bounds
1831 {
1832  var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
1833 
1834  return CGRectInsetByInset(bounds, contentInset);
1835 }
1836 
1837 - (CGRect)bezelRectForBounds:(CGRect)bounds
1838 {
1839  var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
1840 
1841  return CGRectInsetByInset(bounds, bezelInset);
1842 }
1843 
1844 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
1845 {
1846  if (aName === "bezel-view")
1847  return [self bezelRectForBounds:[self bounds]];
1848 
1849  else if (aName === "content-view")
1850  return [self contentRectForBounds:[self bounds]];
1851 
1852  return [super rectForEphemeralSubviewNamed:aName];
1853 }
1854 
1855 - (CPView)createEphemeralSubviewNamed:(CPString)aName
1856 {
1857  if (aName === "bezel-view")
1858  {
1859  var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
1860 
1861  [view setHitTests:NO];
1862 
1863  return view;
1864  }
1865  else
1866  {
1867  var view = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
1868 
1869  [view setHitTests:NO];
1870 
1871  return view;
1872  }
1873 
1874  return [super createEphemeralSubviewNamed:aName];
1875 }
1876 
1877 - (void)layoutSubviews
1878 {
1879  var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
1880  positioned:CPWindowBelow
1881  relativeToEphemeralSubviewNamed:@"content-view"];
1882 
1883  if (bezelView)
1884  [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
1885 
1886  var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
1887  positioned:CPWindowAbove
1888  relativeToEphemeralSubviewNamed:@"bezel-view"];
1889 
1890  if (contentView)
1891  {
1892  [contentView setHidden:(_stringValue && _stringValue.length > 0) && [self hasThemeState:CPThemeStateEditing]];
1893 
1894  var string = "";
1895 
1896  if ([self hasThemeState:CPTextFieldStatePlaceholder])
1897  string = [self placeholderString];
1898  else
1899  {
1900  string = _stringValue;
1901 
1902  if ([self isSecure])
1903  string = secureStringForString(string);
1904  }
1905 
1906  [contentView setText:string];
1907 
1908  [contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
1909  [contentView setFont:[self currentValueForThemeAttribute:@"font"]];
1910  [contentView setAlignment:[self currentValueForThemeAttribute:@"alignment"]];
1911  [contentView setVerticalAlignment:[self currentValueForThemeAttribute:@"vertical-alignment"]];
1912  [contentView setLineBreakMode:[self currentValueForThemeAttribute:@"line-break-mode"]];
1913  [contentView setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
1914  [contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
1915  }
1916 
1917  if (_isEditing)
1918  [self _setCSSStyleForInputElement];
1919 }
1920 
1921 - (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
1922 {
1923  var count = objects.length,
1924  value = [objects[0] valueForKeyPath:aKeyPath];
1925 
1926  [self setStringValue:value];
1927  [self setPlaceholderString:@""];
1928 
1929  while (count-- > 1)
1930  if (value !== [objects[count] valueForKeyPath:aKeyPath])
1931  {
1932  [self setPlaceholderString:@"Multiple Values"];
1933  [self setStringValue:@""];
1934  }
1935 }
1936 
1937 #pragma mark Overrides
1938 
1944 - (void)setTextColor:(CPColor)aColor
1945 {
1946  // We don't want to change the text-color of the placeHolder of the textField
1947  var placeholderColor = [self valueForThemeAttribute:@"text-color" inState:CPTextFieldStatePlaceholder];
1948 
1949  [super setTextColor:aColor];
1950  [self setValue:placeholderColor forThemeAttribute:@"text-color" inState:CPTextFieldStatePlaceholder];
1951 }
1952 
1953 - (void)viewDidHide
1954 {
1955  [super viewDidHide];
1956 
1957  if ([[self window] firstResponder] === self)
1958  [self _resignFirstKeyResponder];
1959 }
1960 
1961 - (void)viewDidUnhide
1962 {
1963  [super viewDidUnhide];
1964 
1965  if ([self isEditable] && [[self window] firstResponder] === self)
1966  [self _becomeFirstKeyResponder];
1967 }
1968 
1969 - (BOOL)validateUserInterfaceItem:(id /*<CPValidatedUserInterfaceItem>*/)anItem
1970 {
1971  var theAction = [anItem action];
1972 
1973  if (![self isEditable] && (theAction == @selector(cut:) || theAction == @selector(paste:) || theAction == @selector(delete:)))
1974  return NO;
1975 
1976  // FIXME - [self selectedRange] is always empty if we're not an editable field, so we must assume yes here.
1977  if (![self isEditable])
1978  return YES;
1979 
1980  if (theAction == @selector(copy:) || theAction == @selector(cut:) || theAction == @selector(delete:))
1981  return [self selectedRange].length;
1982 
1983  return YES;
1984 }
1985 
1986 #pragma mark Private
1987 
1988 - (BOOL)_isWithinUsablePlatformRect
1989 {
1990  // Make sure the text field is completely within the platform window
1991  // so the browser will not scroll it into view.
1992 
1993  var wind = [self window];
1994 
1995  // If the field is not yet within a window, it can't be first responder
1996  if (!wind)
1997  return NO;
1998 
1999  var scrollView = [self enclosingScrollView],
2000  previousContentViewBoundsOrigin;
2001 
2002  // Here we scroll to the textField, otherwise the textField could not be in the usable platformRect
2003  var previousScrollingOrigin = [self _scrollToVisibleRectAndReturnPreviousOrigin];
2004 
2005  var frame = [self convertRectToBase:[self contentRectForBounds:[self bounds]]],
2006  usableRect = [[wind platformWindow] usableContentFrame];
2007 
2008  frame.origin = [wind convertBaseToGlobal:frame.origin];
2009 
2010  // Here we restore the the previous scrolling posiition
2011  [self _restorePreviousScrollingOrigin:previousScrollingOrigin];
2012 
2013  return (CGRectGetMinX(frame) >= CGRectGetMinX(usableRect) &&
2014  CGRectGetMaxX(frame) <= CGRectGetMaxX(usableRect) &&
2015  CGRectGetMinY(frame) >= CGRectGetMinY(usableRect) &&
2016  CGRectGetMaxY(frame) <= CGRectGetMaxY(usableRect));
2017 }
2018 
2022 - (CGPoint)_scrollToVisibleRectAndReturnPreviousOrigin
2023 {
2024  var scrollView = [self enclosingScrollView],
2025  previousContentViewBoundsOrigin;
2026 
2027  // Here we scroll to the textField, otherwise the textField could not be in the usable platformRect
2028  if ([scrollView isKindOfClass:[CPScrollView class]])
2029  {
2030  previousContentViewBoundsOrigin = CGPointMakeCopy([[scrollView contentView] boundsOrigin]);
2031 
2032  if (![[self superview] scrollRectToVisible:[self frame]])
2033  previousContentViewBoundsOrigin = nil;
2034  }
2035 
2036  return previousContentViewBoundsOrigin;
2037 }
2038 
2042 - (void)_restorePreviousScrollingOrigin:(CGPoint)scrollingOrigin
2043 {
2044  if (scrollingOrigin)
2045  [[[self enclosingScrollView] contentView] setBoundsOrigin:scrollingOrigin];
2046 }
2047 
2048 @end
2049 
2050 var secureStringForString = function(aString)
2051 {
2052  // This is true for when aString === "" and null/undefined.
2053  if (!aString)
2054  return "";
2055 
2056  return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
2057 };
2058 
2059 
2060 var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
2061  CPTextFieldIsSelectableKey = "CPTextFieldIsSelectableKey",
2062  CPTextFieldIsBorderedKey = "CPTextFieldIsBorderedKey",
2063  CPTextFieldIsBezeledKey = "CPTextFieldIsBezeledKey",
2064  CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
2065  CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
2066  CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
2067  CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
2068  CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
2069  CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey",
2070  CPTextFieldUsesSingleLineMode = "CPTextFieldUsesSingleLineMode",
2071  CPTextFieldWraps = "CPTextFieldWraps",
2072  CPTextFieldScrolls = "CPTextFieldScrolls";
2073 
2074 
2075 @implementation CPTextField (CPCoding)
2076 
2082 - (id)initWithCoder:(CPCoder)aCoder
2083 {
2084  self = [super initWithCoder:aCoder];
2085 
2086  if (self)
2087  {
2088  [self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
2089  [self setSelectable:[aCoder decodeBoolForKey:CPTextFieldIsSelectableKey]];
2090 
2091  [self setDrawsBackground:[aCoder decodeBoolForKey:CPTextFieldDrawsBackgroundKey]];
2092 
2093  [self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
2094 
2095  [self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
2096  [self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
2097 
2098  [self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
2099 
2100  [self _setUsesSingleLineMode:[aCoder decodeBoolForKey:CPTextFieldUsesSingleLineMode]];
2101  [self _setWraps:[aCoder decodeBoolForKey:CPTextFieldWraps]];
2102  [self _setScrolls:[aCoder decodeBoolForKey:CPTextFieldScrolls]];
2103  }
2104 
2105  return self;
2106 }
2107 
2112 - (void)encodeWithCoder:(CPCoder)aCoder
2113 {
2114  [super encodeWithCoder:aCoder];
2115 
2116  [aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
2117  [aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
2118 
2119  [aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
2120 
2121  [aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
2122 
2123  [aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
2124  [aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey];
2125 
2126  [aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
2127 
2128  [aCoder encodeBool:_usesSingleLineMode forKey:CPTextFieldUsesSingleLineMode];
2129  [aCoder encodeBool:_wraps forKey:CPTextFieldWraps];
2130  [aCoder encodeBool:_scrolls forKey:CPTextFieldScrolls];
2131 }
2132 
2133 @end
2134 @implementation _CPTextFieldValueBinder : CPBinder
2135 {
2136  id __doxygen__;
2137 }
2138 
2139 - (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
2140 {
2141  [super _updatePlaceholdersWithOptions:options];
2142 
2143  [self _setPlaceholder:@"Multiple Values" forMarker:CPMultipleValuesMarker isDefault:YES];
2144  [self _setPlaceholder:@"No Selection" forMarker:CPNoSelectionMarker isDefault:YES];
2145  [self _setPlaceholder:@"Not Applicable" forMarker:CPNotApplicableMarker isDefault:YES];
2146  [self _setPlaceholder:@"" forMarker:CPNullMarker isDefault:YES];
2147 }
2148 
2149 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
2150 {
2151  [_source setPlaceholderString:aValue];
2152  [_source setObjectValue:nil];
2153 }
2154 
2155 - (void)setValue:(id)aValue forBinding:(CPString)aBinding
2156 {
2157  if (!aValue || (aValue.isa && [aValue isMemberOfClass:CPNull]))
2158  [_source setPlaceholderString:[self _placeholderForMarker:CPNullMarker]];
2159 
2160  [_source setObjectValue:aValue];
2161 }
2162 
2163 - (void)reverseSetValueFor:(CPString)aBinding
2164 {
2165  var destination = [_info objectForKey:CPObservedObjectKey],
2166  keyPath = [_info objectForKey:CPObservedKeyPathKey],
2167  options = [_info objectForKey:CPOptionsKey],
2168  newValue = [self valueForBinding:aBinding],
2169  value = [destination valueForKeyPath:keyPath];
2170 
2171  if (CPIsControllerMarker(value) && newValue === nil)
2172  return;
2173 
2174  newValue = [self reverseTransformValue:newValue withOptions:options];
2175 
2176  [self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
2177  [destination setValue:newValue forKeyPath:keyPath];
2178  [self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
2179 }
2180 
2181 @end
2182 @implementation _CPTextFieldPatternValueBinder : CPValueWithPatternBinding
2183 {
2184  id __doxygen__;
2185 }
2186 
2187 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
2188 {
2189  [_source setPlaceholderString:aValue];
2190  [_source setObjectValue:nil];
2191 }
2192 
2193 - (void)setValue:(id)aValue forBinding:(CPString)aBinding
2194 {
2195  if (!aValue || (aValue.isa && [aValue isMemberOfClass:CPNull]))
2196  [_source setPlaceholderString:[self _placeholderForMarker:CPNullMarker]];
2197 
2198  [_source setObjectValue:aValue];
2199 }
2200 
2201 @end
CPEvent keyEventWithType:location:modifierFlags:timestamp:windowNumber:context:characters:charactersIgnoringModifiers:isARepeat:keyCode:(CPEventType anEventType, [location] CGPoint aPoint, [modifierFlags] unsigned int modifierFlags, [timestamp] CPTimeInterval aTimestamp, [windowNumber] int aWindowNumber, [context] CPGraphicsContext aGraphicsContext, [characters] CPString characters, [charactersIgnoringModifiers] CPString unmodCharacters, [isARepeat] BOOL repeatKey, [keyCode] unsigned short code)
Definition: CPEvent.j:103
BOOL makeFirstResponder:(CPResponder aResponder)
Definition: CPWindow.j:1618
void setDrawsBackground:(BOOL shouldDrawBackground)
Definition: CPTextField.j:533
var CPTextFieldDOMStandardInputElement
Definition: CPTextField.j:50
CGRect convertRectToBase:(CGRect aRect)
Definition: CPView.j:2256
void postNotification:(CPNotification aNotification)
var CPTextFieldIsBorderedKey
Definition: CPTextField.j:2062
var CPTextFieldIsBezeledKey
Definition: CPTextField.j:2063
float defaultLineHeightForFont()
Definition: CPFont.j:362
var CPTextFieldAlignmentKey
Definition: CPTextField.j:2067
BOOL isEnabled()
Definition: CPControl.j:970
void textDidChange:(CPNotification note)
Definition: CPTextField.j:1219
BOOL setThemeState:(ThemeState aState)
Definition: CPView.j:3148
CGRect frame
var CPTextFieldTextDidChangeValue
Definition: CPTextField.j:53
void selectText:(id sender)
Definition: CPTextField.j:1490
void setValue:forThemeAttribute:inState:(id aValue, [forThemeAttribute] CPString aName, [inState] ThemeState aState)
Definition: CPView.j:3264
An object representation of nil.
Definition: CPNull.h:2
CPStringPboardType
Definition: CPPasteboard.j:37
var CPTextFieldCachedSelectStartFunction
Definition: CPTextField.j:57
void setSelectedRange:(CPRange aRange)
Definition: CPTextField.j:1664
var CPTextFieldDelegate_controlTextDidBeginEditing_
Definition: CPTextField.j:34
The main run loop for the application.
Definition: CPRunLoop.h:2
CPRightTextAlignment
Definition: CPText.j:50
id generalPasteboard()
Definition: CPPasteboard.j:87
var CPTextFieldDelegate_controlTextDidEndEditing_
Definition: CPTextField.j:36
CPTextField labelWithTitle:theme:(CPString aTitle, [theme] CPTheme aTheme)
Definition: CPTextField.j:215
void addObserver:selector:name:object:(id anObserver, [selector] SEL aSelector, [name] CPString aNotificationName, [object] id anObject)
void setLineBreakMode:(CPLineBreakMode mode)
Definition: CPControl.j:823
var CPTextFieldInputOwner
Definition: CPTextField.j:52
CPResponder firstResponder()
Definition: CPWindow.j:1643
void textDidChange:(CPNotification note)
Definition: CPControl.j:703
var CPTextFieldDelegate_controlTextDidBlur_
Definition: CPTextField.j:38
var CPTextFieldInputFunction
Definition: CPTextField.j:60
function CPTextFieldHandleBlur(anEvent, ownerRef)
Definition: CPTextField.j:100
CPFont font()
Definition: CPControl.j:899
void viewDidHide()
Definition: CPView.j:1717
CPInputOnInputEventFeature
void selectAll:(id sender)
Definition: CPTextField.j:1716
CPLineBreakByCharWrapping
Definition: CPControl.j:46
CPTextField textFieldWithStringValue:placeholder:width:theme:(CPString aStringValue, [placeholder] CPString aPlaceholder, [width] float aWidth, [theme] CPTheme aTheme)
Definition: CPTextField.j:172
CPIsControllerMarker
id delegate()
Definition: CALayer.j:965
void textDidBeginEditing:(CPNotification note)
Definition: CPControl.j:694
void textDidEndEditing:(CPNotification note)
Definition: CPControl.j:712
id initWithFrame:(CGRect aFrame)
Definition: CPControl.j:183
CGRect bounds()
Definition: CPView.j:1287
CPTextFieldDidBlurNotification
Definition: CPTextField.j:46
void deleteBackward:(id sender)
Definition: CPTextField.j:1721
void copy:(id sender)
Definition: CPTextField.j:1531
void setControlSize:(CPControlSize aControlSize)
Definition: CPControl.j:211
void setEnabled:(BOOL isEnabled)
Definition: CPControl.j:959
CPFormatter formatter()
Definition: CPControl.j:1216
CPKeyUpMask
void setValue:forThemeAttribute:(id aValue, [forThemeAttribute] CPString aName)
Definition: CPView.j:3277
CPTextFieldBezelStyle CPTextFieldSquareBezel
Definition: CPTextField.j:42
CPNotificationCenter defaultCenter()
A mutable key-value pair collection.
Definition: CPDictionary.h:2
CPScrollView enclosingScrollView()
Definition: CPView.j:2862
void rightMouseDown:(CPEvent anEvent)
Definition: CPView.j:1838
var CPTextFieldIsSelectableKey
Definition: CPTextField.j:2061
CPRunLoop currentRunLoop()
Definition: CPRunLoop.j:230
var CPTextFieldWraps
Definition: CPTextField.j:2071
void setEditable:(BOOL shouldBeEditable)
Definition: CPTextField.j:383
void textDidBlur:(CPNotification note)
Definition: CPTextField.j:1195
CGRect bounds()
Definition: CALayer.j:203
CPWindow window()
Definition: CPView.j:486
CGSize frameSize()
Definition: CPView.j:1021
CPRange selectedRange()
Definition: CPTextField.j:1624
CGPoint convertPointFromBase:(CGPoint aPoint)
Definition: CPView.j:2155
CPEditableBinding
var CPTextFieldCachedDragFunction
Definition: CPTextField.j:58
CPView createEphemeralSubviewNamed:(CPString aViewName)
Definition: CPView.j:3290
CPNaturalTextAlignment
Definition: CPText.j:53
id initWithName:object:userInfo:(CPString aNotificationName, [object] id anObject, [userInfo] CPDictionary aUserInfo)
void setPlaceholderString:(CPString aStringValue)
Definition: CPTextField.j:1388
function CPMaxRange(aRange)
Definition: CPRange.j:70
An immutable string (collection of characters).
Definition: CPString.h:2
CPNull null()
Definition: CPNull.j:51
CPAltEnterTextAreaFeature
if(CPFeatureIsCompatible(CPHTMLCanvasFeature))
CPRunLoop mainRunLoop()
Definition: CPRunLoop.j:238
var CPTextFieldInputIsActive
Definition: CPTextField.j:56
CPClipView contentView()
Definition: CPScrollView.j:377
BOOL sendAction:to:(SEL anAction, [to] id anObject)
Definition: CPControl.j:319
function CPFeatureIsCompatible(aFeature)
SEL action()
Definition: CPControl.j:290
id initWithCoder:(CPCoder aCoder)
Definition: CPControl.j:1085
var CPTextFieldBezelStyleKey
Definition: CPTextField.j:2064
void performBlock:argument:order:modes:(Function aBlock, [argument] id anArgument, [order] int anOrder, [modes] CPArray modes)
Definition: CPRunLoop.j:268
BOOL acceptsFirstResponder()
Definition: CPTextField.j:594
void textDidBeginEditing:(CPNotification note)
Definition: CPTextField.j:1232
void setTextColor:(CPColor aColor)
Definition: CPControl.j:841
var CPTextFieldDOMPasswordInputElement
Definition: CPTextField.j:51
CGRect contentRectForBounds:(CGRect bounds)
Definition: CPTextField.j:1830
BOOL isEditable()
Definition: CPTextField.j:411
void setNeedsDisplay:(BOOL aFlag)
Definition: CPView.j:2490
var CPTextFieldPlaceholderStringKey
Definition: CPTextField.j:2069
void setObjectValue:(id anObject)
Definition: CPControl.j:534
var CPTextFieldDelegate_controlTextDidChange_
Definition: CPTextField.j:35
CPTextFieldStateRounded
Definition: CPTextField.j:120
CPTextAlignment alignment()
Definition: CPControl.j:784
var CPSecureTextFieldCharacter
Definition: CPTextField.j:63
CGRect bezelRectForBounds:(CGRect bounds)
Definition: CPTextField.j:1837
CPWindow window()
Definition: CPEvent.j:330
int length()
Definition: CPString.j:186
CPVerticalTextAlignment CPTopVerticalTextAlignment
Definition: CPControl.j:53
var secureStringForString
Definition: CPTextField.j:2050
void setStringValue:(CPString aString)
Definition: CPControl.j:629
A notification that can be posted to a CPNotificationCenter.
Definition: CPNotification.h:2
CPTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:(CPTimeInterval seconds, [target] id aTarget, [selector] SEL aSelector, [userInfo] id userInfo, [repeats] BOOL shouldRepeat)
Definition: CPTimer.j:58
CPDate limitDateForMode:(CPString aMode)
Definition: CPRunLoop.j:340
CPTextFieldRoundedBezel
Definition: CPTextField.j:43
var CPTextFieldIsEditableKey
Definition: CPTextField.j:2060
CPTheme defaultTheme()
Definition: CPTheme.j:44
void setNeedsLayout()
Definition: CPView.j:2641
id target()
Definition: CPControl.j:308
CPString stringValue()
Definition: CPControl.j:613
CPBottomVerticalTextAlignment
Definition: CPControl.j:55
var CPTextFieldDOMCurrentElement
Definition: CPTextField.j:48
BOOL isKeyWindow()
Definition: CPWindow.j:2052
A timer object that can send a message after the given time interval.
Definition: CPTimer.h:2
void setBoundsOrigin:(CGPoint aPoint)
Definition: CPClipView.j:81
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
BOOL isSelectable()
Definition: CPTextField.j:441
CPString cssString()
Definition: CPFont.j:383
void setAlignment:(CPTextAlignment alignment)
Definition: CPControl.j:776
BOOL unsetThemeState:(ThemeState aState)
Definition: CPView.j:3161
Sends messages (CPNotification) between objects.
CPNotification notificationWithName:object:userInfo:(CPString aNotificationName, [object] id anObject, [userInfo] CPDictionary aUserInfo)
CPString placeholderString()
Definition: CPTextField.j:1406
Definition: CPTheme.h:2
void setSelectable:(BOOL aFlag)
Definition: CPTextField.j:433
CPNewlineCharacter
Definition: CPText.j:26
CPLineBreakMode lineBreakMode()
Definition: CPControl.j:831
CPTimeInterval currentTimestamp()
Definition: CPEvent.j:81
var CPTextFieldDelegate_controlTextDidFocus_
Definition: CPTextField.j:37
var CPTextFieldLineBreakModeKey
Definition: CPTextField.j:2066
var CPTextFieldBlurHandler
Definition: CPTextField.j:59
void textDidEndEditing:(CPNotification note)
Definition: CPTextField.j:1244
CPTextField roundedTextFieldWithStringValue:placeholder:width:theme:(CPString aStringValue, [placeholder] CPString aPlaceholder, [width] float aWidth, [theme] CPTheme aTheme)
Definition: CPTextField.j:193
var CPTextFieldInputDidBlur
Definition: CPTextField.j:55
CPLineBreakMode CPLineBreakByWordWrapping
Definition: CPControl.j:45
void setFrameSize:(CGSize aSize)
Definition: CPView.j:1086
var CPTextFieldUsesSingleLineMode
Definition: CPTextField.j:2070
var CPTextFieldDOMTextAreaElement
Definition: CPTextField.j:49
CPDisplayPatternValueBinding
CPTextFieldStatePlaceholder
Definition: CPTextField.j:121
void removeObserver:name:object:(id anObserver, [name] CPString aNotificationName, [object] id anObject)
var CPTexFieldCurrentCSSSelectableField
Definition: CPTextField.j:61
var CPTextFieldDrawsBackgroundKey
Definition: CPTextField.j:2065
Definition: CPEvent.h:2
void setTextFieldBackgroundColor:(CPColor aColor)
Definition: CPTextField.j:556
var CPTextFieldBackgroundColorKey
Definition: CPTextField.j:2068
CPKeyDownMask
CPView superview()
Definition: CPView.j:469
CPCenterTextAlignment
Definition: CPText.j:51
CPPlatformWindow platformWindow()
Definition: CPWindow.j:384
CPTextFieldDidFocusNotification
Definition: CPTextField.j:45
CPValueBinding
var CPTextFieldInputResigning
Definition: CPTextField.j:54
A bridged object to native Javascript numbers.
Definition: CPNumber.h:2
void viewDidUnhide()
Definition: CPView.j:1731
void encodeWithCoder:(CPCoder aCoder)
Definition: CPControl.j:1114
void textDidFocus:(CPNotification note)
Definition: CPTextField.j:1207
var CPTextFieldScrolls
Definition: CPTextField.j:2072
CPRange function CPMakeRange(location, length)
Definition: CPRange.j:37
function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resigning, didBlurRef)
Definition: CPTextField.j:65
id objectValue()
Definition: CPControl.j:526
var CPTextFieldDelegate_control_didFailToFormatString_errorDescription_
Definition: CPTextField.j:33
CPNullMarker
CPView layoutEphemeralSubviewNamed:positioned:relativeToEphemeralSubviewNamed:(CPString aViewName, [positioned] CPWindowOrderingMode anOrderingMode, [relativeToEphemeralSubviewNamed] CPString relativeToViewName)
Definition: CPView.j:3300
CPCenterVerticalTextAlignment
Definition: CPControl.j:54
id alloc()
Definition: CPObject.j:130
CGRect rectForEphemeralSubviewNamed:(CPString aViewName)
Definition: CPView.j:3295
Definition: CPView.j:131
CPInput1PxLeftPadding