cxa / MenuItemKit

UIMenuItem with image and closure(block) action

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Problem with MenuItemAction vs. Selectors

danfsd opened this issue · comments

I'm working on a fork of FolioReaderKit and your library is used there.

As a way of "filtering" which actions will be displayed on each scenario it was chosen to override the function canPerformAction of the UIWebView. There they verify each action (which is a Selector) and see if the item will end up displaying on the screen.

Like this:

open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    if action == #selector(highlight(_:))
        || action == #selector(createAnnotation(_:))
        || (action == #selector(define(_:)) && isOneWord)
        || (action == #selector(play(_:)) && (book.hasAudio() || readerConfig.enableTTS))
        || (action == #selector(share(_:)) && readerConfig.allowSharing)
        || action == #selector(copyText(_:)) {
        return true
    } else {
        return false
    }
}

The thing is that most of those actions are actually a Selector and were created using the default API like this:

let highlightItem = UIMenuItem(title: readerConfig.localizedHighlightMenu, action: #selector(highlight(_:)))

When using your API for creating items with images we end up sending MenuItemAction instead of Selectors:

let discussion = UIImage(readerImageNamed: "discussion-marker")
let discussionItem = UIMenuItem(title: "D", image: discussion!) { [weak self] _ in   
    self?.createHighlight()
}

Thus it's very hard to work combined with canPerformAction (which has a Selector as parameter)

Any suggestions of filtering which UIMenuItem(created with images, using MenuItemAction) will appear on a specific scenario?

We built an epub reader using WKWebView (uiwebview leaks memory), and we have a similar canPerformAction block as to what you described.

UIMenuKit creates actions with a fixed name, so you can filter them like this

    NSString *selectorName = NSStringFromSelector(action);
    if ([selectorName hasPrefix:@"_menuitemkit_block"]) {
        return YES;
    }

essentially I'm allowing all the menuitemkit actions through. You could possibly do custom naming of actions instead of random names

the constructor could be changed to inject an identifier - see here self.init(title: title, action: Selector(blockIdentifierPrefix + UUID.stripedString + ":"))

Now exposing this method from MenuItemKit, version 2.0.2.

I dont think this is quite what @danfsd was looking for :)

this only tells us if a selector is a menuitemkit selector - it doesnt tell us what the selector is. We need someway to identify a specific selector's functionality.

In his example he was checking if action == #selector(highlight(_:)), which tells us if the selector is the highlight selector.

In order to do this we would need to be able to identify UIMenuItemAction's with a specific identifier

Can you explain me how can we check if a selector is a menuitemkit selector in CanPerformAction ?

One temporary solution is to create a function which creates a MenuItemAction that accepts a selector instead of a function as a parameter.

We can argue whether comparing the action in the WKWebView.canPerformAction(_:) is the right way to selectively show or hide the action (based on a scenario), but this solution I give should fix the things for now.

Considering adding this way in future version.

Actully My problem is CanPerformAction method is not getting called for custom menuitem selectors using WebView.

Now you can use UIMenuController.installTo(responder:shouldShowForAction:) introduced in 3.1.0.