malkomalko
11/20/2009 - 1:21 AM

Cappuccino - Custom CPTextField

Cappuccino - Custom CPTextField

@import <AppKit/CPTextField.j>

Alphanumeric = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 ";
SearchFieldDidPressEnterNotification = @"SearchFieldDidPressEnterNotification";
SearchFieldDidPressDownArrowNotification = @"SearchFieldDidPressDownArrowNotification";
SearchFieldDidPressUpArrowNotification = @"SearchFieldDidPressUpArrowNotification";
SearchFieldDidPressRightArrowNotification = @"SearchFieldDidPressRightArrowNotification";
SearchFieldDidPressLeftArrowNotification = @"SearchFieldDidPressLeftArrowNotification";

@implementation SearchField : CPTextField
{
  BOOL _captureLeftAndRightArrows;
}

- (void)setCaptureLeftAndRightArrows:(BOOL)aValue
{
  _captureLeftAndRightArrows = aValue;
}

- (BOOL)captureLeftAndRightArrows
{
  return _captureLeftAndRightArrows;
}

- (void)keyUp:(CPEvent)anEvent
{
  var newChar = [anEvent characters][0],
    defaultCenter = [CPNotificationCenter defaultCenter];
  if (Alphanumeric.indexOf(newChar) != -1) {
    var cursorBegin = [self _inputElement].selectionStart,
      cursorEnd = [self _inputElement].selectionEnd,
      currentStringValue = [self stringValue],
      firstPart = currentStringValue.slice(0, cursorBegin),
      secondPart = currentStringValue.slice(cursorEnd);
    
    [self _setStringValue:firstPart + newChar + secondPart];
    [self _inputElement].value = [self stringValue];
    [self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
    [self _inputElement].selectionStart = cursorBegin + 1;
    [self _inputElement].selectionEnd = cursorBegin + 1;
    [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }
  else if ([anEvent keyCode] == CPDownArrowKeyCode) {
    [defaultCenter postNotificationName:SearchFieldDidPressDownArrowNotification
		   object:self];
    [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }
  else if ([anEvent keyCode] == CPUpArrowKeyCode) {
    [defaultCenter postNotificationName:SearchFieldDidPressUpArrowNotification
		   object:self];
    [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }
  else
    [super keyUp:anEvent];
}

- (void)keyDown:(CPEvent)anEvent
{
  var newChar = [anEvent characters][0],
    defaultCenter = [CPNotificationCenter defaultCenter];
  if ([anEvent keyCode] == CPReturnKeyCode) {
    [defaultCenter postNotificationName:SearchFieldDidPressEnterNotification
		   object:self];
    [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }   
  // I make up and down arrow key codes fire the event in key up because in firefox, 
  // hitting an up arrow at the beginning of the text or a down arrow at the end of the 
  // text doesn't fire key down
  else if ([anEvent keyCode] == CPDownArrowKeyCode) {
    [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }
  else if ([anEvent keyCode] == CPUpArrowKeyCode) {
    [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }
  else if ([anEvent keyCode] == CPRightArrowKeyCode && [self captureLeftAndRightArrows]) {
      [defaultCenter postNotificationName:SearchFieldDidPressRightArrowNotification
		     object:self];
      [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }

  else if ([anEvent keyCode] == CPLeftArrowKeyCode && [self captureLeftAndRightArrows]) {
      [defaultCenter postNotificationName:SearchFieldDidPressLeftArrowNotification
		     object:self];
      [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }
  else if (Alphanumeric.indexOf(newChar) != -1)  {
    [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
  }
  else 
    [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}

- (void)setDelegate:(id)aDelegate
{
  var defaultCenter = [CPNotificationCenter defaultCenter];
    
  //unsubscribe the existing delegate if it exists
  if (_delegate) {
    [defaultCenter removeObserver:_delegate name:SearchFieldDidPressEnterNotification object:self];
    [defaultCenter removeObserver:_delegate name:SearchFieldDidPressDownArrowNotification object:self];
    [defaultCenter removeObserver:_delegate name:SearchFiledDidPressUpArrowNotification object:self];
    [defaultCenter removeObserver:_delegate name:SearchFieldDidPressRightArrowNotification object:self];
    [defaultCenter removeObserver:_delegate name:SearchFieldDidPressLeftArrowNotification object:self];
  }
  [super setDelegate:aDelegate];
    

  if ([_delegate respondsToSelector:@selector(searchFieldDidPressEnter:)])
    [defaultCenter
      addObserver:_delegate
      selector:@selector(searchFieldDidPressEnter:)
      name:SearchFieldDidPressEnterNotification
      object:self];

  if ([_delegate respondsToSelector:@selector(searchFieldDidPressDownArrow:)])
    [defaultCenter
      addObserver:_delegate
      selector:@selector(searchFieldDidPressDownArrow:)
      name:SearchFieldDidPressDownArrowNotification
      object:self];

  if ([_delegate respondsToSelector:@selector(searchFieldDidPressUpArrow:)])
    [defaultCenter
      addObserver:_delegate
      selector:@selector(searchFieldDidPressUpArrow:)
      name:SearchFieldDidPressUpArrowNotification
      object:self];

  if ([_delegate respondsToSelector:@selector(searchFieldDidPressRightArrow:)])
    [defaultCenter
      addObserver:_delegate
      selector:@selector(searchFieldDidPressRightArrow:)
      name:SearchFieldDidPressRightArrowNotification
      object:self];
    
  if ([_delegate respondsToSelector:@selector(searchFieldDidPressLeftArrow:)])
    [defaultCenter
      addObserver:_delegate
      selector:@selector(searchFieldDidPressLeftArrow:)
      name:SearchFieldDidPressLeftArrowNotification
      object:self];
}

@end