Skip to content

iOS custom actions when text is selected in a TextArea #14382

Description

@alexlarocca

I have searched and made sure there are no existing issues for the issue I am filing

  • I have searched the existing issues

Description

In a recent project, I needed to add custom actions to the menu that appears when text is selected within a TextArea. To do this, I directly modified the SDK in a dirty way. This might be a feature that could be added in a more professional way.

const win = Ti.UI.createWindow();

const textArea = Ti.UI.createTextArea({
    left: 20, right: 20, height: 600, top: 80, borderWidth: 1, font: {fontSize: 16},
    value: 'Titanium lets you develop cross-platform native mobile applications and build great mobile experiences using JavaScript.',
    customActions: ['Action 1', 'Action 2']
});

textArea.addEventListener('customactions', function(e) {
    const start = e.range.location;
    const end = start + e.range.length;
    alert('action: ' + e.action + ', selected text: ' + textArea.value.substring(start, end));

})

win.add(textArea);
win.open(); 

Image

Solution

TiUITextArea.h

@interface TiUITextArea : TiUITextWidget <UITextViewDelegate> {
  @private
  BOOL returnActive;
  BOOL handleLinks;
  NSRange lastSelectedRange;

  // ***** ADD THIS *****
  NSArray<NSString *> *customActions;
}

TiUITextArea.m

#pragma mark Public APIs

// ***** ADD THIS *****
- (void)setCustomActions_:(id)value
{
	ENSURE_TYPE_OR_NIL(value, NSArray);

	if (value == nil) {
		customActions = nil;
	    return;
	}

	NSMutableArray<NSString *> *actions = [NSMutableArray array];

	for (id item in value) {
		if ([item isKindOfClass:[NSString class]]) {
			[actions addObject:item];
		}
	}

	customActions = [actions copy];
}


#pragma mark UITextViewDelegate

// ***** ADD THIS *****
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000
- (UIMenu *)textView:(UITextView *)tv
editMenuForTextInRange:(NSRange)range
suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions
{
    if (range.length == 0 || customActions.count == 0) {
        return [UIMenu menuWithChildren:suggestedActions];
    }

    NSMutableArray<UIMenuElement *> *finalActions = [NSMutableArray array];
    for (NSString *actionName in customActions) {
        UIAction *uiAction =
        [UIAction actionWithTitle:actionName
                            image:nil
                       identifier:nil
                          handler:^(__kindof UIAction * _Nonnull action) {

            NSDictionary *rangeDict = @{
                @"location": NUMUINTEGER(range.location),
                @"length":   NUMUINTEGER(range.length)
            };

            NSDictionary *event = @{
                @"action": actionName,
                @"range":  rangeDict
            };

			if ([self.proxy _hasListeners:@"customaction"]) {
				[self.proxy fireEvent:@"customaction" withObject:event];
			}

        }];

        [finalActions addObject:uiAction];
    }

    [finalActions addObjectsFromArray:suggestedActions];
    return [UIMenu menuWithTitle:@"" children:finalActions];
}
#endif

Alternatives

No response

Platforms

iOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureneeds triageThis issue hasn't been reviewed by maintainers

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions