Skip to content

Instantly share code, notes, and snippets.

@swillits
Last active February 9, 2017 18:31
Show Gist options
  • Save swillits/949bf6cf812110c8db81a9caf9e936ea to your computer and use it in GitHub Desktop.
Save swillits/949bf6cf812110c8db81a9caf9e936ea to your computer and use it in GitHub Desktop.
@implementation NSWindow (Additions)
typedef NS_ENUM(NSUInteger, AGEndTextEditingOption) {
AGEndTextEditingAndClearFirstResponder = 0,
AGEndTextEditingAndMaintainFirstResponder,
};
//! Returns YES if the field editor voluntarily gives up first responder status. Also returns YES if nothing was being edited.
//! If the maintain option is used, the first responder is set to the field editor's text field.
//! Returns NO if the field didn't want to give up first responder, probably because of some validation issue. In this case, use ag_forcefullyEndTextEditing if needed.
- (BOOL)ag_endTextEditing:(AGEndTextEditingOption)option
{
// The goal of this method, is that IF the there is a field editor editing text,
// then we want to nicely end the text editing. In the past I simply just called
// [window endEditingFor:nil] but that actually doesn't work if the field editor
// is for a secure text field. (Interesting!) So instead we have to do it the
// correct way, which first tries makeFirstResponder.
// First we have to determine if there is a field editor. If there is, then it
// would be the first responder, so look for it there.
//
// We only want to call makeFirstResponder: if we're actually editing text
// otherwise we'd be moving the first responder "unexpectedly" to the user.
NSResponder * firstResponder = self.firstResponder;
if ([firstResponder isKindOfClass:[NSText class]]) {
NSText * text = (NSText *)firstResponder;
if (text.isFieldEditor) {
// Must get the text's delegate *before* changing first responder, otherwise it could go to nil.
if ([text.delegate isKindOfClass:[NSResponder class]]) {
firstResponder = (NSResponder *)text.delegate;
}
// Try to resign nicely. YES if it worked.
// (note we set the first responder to window not nil, because nil has some side effect I can't recall at the moment!)
if ([self makeFirstResponder:self]) {
// Reselect the field as first responder
if (option == AGEndTextEditingAndMaintainFirstResponder) {
[self makeFirstResponder:firstResponder];
}
return YES;
}
// Refused to give up first responder
return NO;
}
}
// No editing is being performed, so we ended it successfully.
return YES;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment