Diff
Modified: trunk/LayoutTests/ChangeLog (272333 => 272334)
--- trunk/LayoutTests/ChangeLog 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/LayoutTests/ChangeLog 2021-02-03 20:27:31 UTC (rev 272334)
@@ -1,3 +1,18 @@
+2021-02-03 Aditya Keerthi <[email protected]>
+
+ [iOS][FCR] Add new picker for select elements
+ https://bugs.webkit.org/show_bug.cgi?id=221153
+ <rdar://problem/73770389>
+
+ Reviewed by Tim Horton.
+
+ * fast/forms/ios/form-control-refresh/select/choose-select-option-expected.txt: Added.
+ * fast/forms/ios/form-control-refresh/select/choose-select-option.html: Added.
+ * resources/ui-helper.js:
+ (window.UIHelper.waitForContextMenuToShow):
+
+ Added a new UIHelper method to wait until a context menu is displayed.
+
2021-02-03 Youenn Fablet <[email protected]>
Make sure GPUProcess MediaRecorder handles correctly muted tracks
Added: trunk/LayoutTests/fast/forms/ios/form-control-refresh/select/choose-select-option-expected.txt (0 => 272334)
--- trunk/LayoutTests/fast/forms/ios/form-control-refresh/select/choose-select-option-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/form-control-refresh/select/choose-select-option-expected.txt 2021-02-03 20:27:31 UTC (rev 272334)
@@ -0,0 +1,13 @@
+This test verifies that tapping on a select element and choosing an option via the presented context menu updates the element's value.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS select.value is "January"
+PASS select.value is "April"
+PASS grouped.value is "January"
+PASS grouped.value is "October"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/forms/ios/form-control-refresh/select/choose-select-option.html (0 => 272334)
--- trunk/LayoutTests/fast/forms/ios/form-control-refresh/select/choose-select-option.html (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/form-control-refresh/select/choose-select-option.html 2021-02-03 20:27:31 UTC (rev 272334)
@@ -0,0 +1,70 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true IOSFormControlRefreshEnabled=true ] -->
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+ <script src=""
+ <script src=""
+ </head>
+<body>
+<select id="select">
+ <option>January</option>
+ <option>February</option>
+ <option>March</option>
+ <option>April</option>
+ <option>May</option>
+ <option>June</option>
+ <option>July</option>
+ <option>August</option>
+ <option>September</option>
+ <option>October</option>
+ <option>November</option>
+ <option>December</option>
+</select>
+
+<select id="grouped">
+ <optgroup label="Winter">
+ <option>January</option>
+ <option>February</option>
+ <option>March</option>
+ </optgroup>
+ <optgroup label="Spring">
+ <option>April</option>
+ <option>May</option>
+ <option>June</option>
+ </optgroup>
+ <optgroup label="Summer">
+ <option>July</option>
+ <option>August</option>
+ <option>September</option>
+ </optgroup>
+ <optgroup label="Fall">
+ <option>October</option>
+ <option>November</option>
+ <option>December</option>
+ </optgroup>
+</select>
+</body>
+<script>
+jsTestIsAsync = true;
+
+addEventListener("load", async () => {
+ description("This test verifies that tapping on a select element and choosing an option via the presented context menu updates the element's value.");
+
+ shouldBeEqualToString("select.value", "January");
+ await UIHelper.activateElement(select);
+ await UIHelper.waitForContextMenuToShow();
+ await UIHelper.selectFormAccessoryPickerRow(3);
+ await UIHelper.waitForContextMenuToHide();
+ shouldBeEqualToString("select.value", "April");
+
+ shouldBeEqualToString("grouped.value", "January");
+ await UIHelper.activateElement(grouped);
+ await UIHelper.waitForContextMenuToShow();
+ await UIHelper.selectFormAccessoryPickerRow(9);
+ await UIHelper.waitForContextMenuToHide();
+ shouldBeEqualToString("grouped.value", "October");
+
+ finishJSTest();
+});
+</script>
+</html>
Modified: trunk/LayoutTests/resources/ui-helper.js (272333 => 272334)
--- trunk/LayoutTests/resources/ui-helper.js 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/LayoutTests/resources/ui-helper.js 2021-02-03 20:27:31 UTC (rev 272334)
@@ -668,6 +668,22 @@
});
}
+ static waitForContextMenuToShow()
+ {
+ if (!this.isWebKit2() || !this.isIOSFamily())
+ return Promise.resolve();
+
+ return new Promise(resolve => {
+ testRunner.runUIScript(`
+ (function() {
+ if (!uiController.isShowingContextMenu)
+ uiController.didShowContextMenuCallback = () => uiController.uiScriptComplete();
+ else
+ uiController.uiScriptComplete();
+ })()`, resolve);
+ });
+ }
+
static waitForContextMenuToHide()
{
if (!this.isWebKit2() || !this.isIOSFamily())
Modified: trunk/Source/WebKit/ChangeLog (272333 => 272334)
--- trunk/Source/WebKit/ChangeLog 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/Source/WebKit/ChangeLog 2021-02-03 20:27:31 UTC (rev 272334)
@@ -1,3 +1,72 @@
+2021-02-03 Aditya Keerthi <[email protected]>
+
+ [iOS][FCR] Add new picker for select elements
+ https://bugs.webkit.org/show_bug.cgi?id=221153
+ <rdar://problem/73770389>
+
+ Reviewed by Tim Horton.
+
+ Tapping on a select element should display an context menu that allows
+ users to choose one of the specified options. Rather than presenting a
+ UIPickerView, tapping on select elements now create UIContextMenuInteractions,
+ similar to date and file inputs.
+
+ Test: fast/forms/ios/form-control-refresh/select/choose-select-option.html
+
+ * UIProcess/ios/WKContentViewInteraction.h:
+ * UIProcess/ios/WKContentViewInteraction.mm:
+ (-[WKContentView _shouldShowAutomaticKeyboardUIIgnoringInputMode]):
+
+ The new picker does not bring up the keyboard view on all devices.
+
+ (-[WKContentView _elementTypeRequiresAccessoryView:]):
+
+ Changed from a static method to an instance method, as the returned
+ value depends on a flag which is only accessible through the instance.
+
+ (-[WKContentView requiresAccessoryView]):
+ (-[WKContentView _formControlRefreshEnabled]):
+ (-[WKContentView _shouldShowKeyboardForElement:]):
+ (-[WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:]):
+ (-[WKContentView _removeContextMenuViewIfPossible]):
+
+ Do not remove the context menu if an select element is actively being
+ interacted with.
+
+ (-[WKContentView selectControl]):
+ * UIProcess/ios/forms/WKFormSelectControl.mm:
+ (-[WKFormSelectControl initWithView:]):
+ * UIProcess/ios/forms/WKFormSelectPicker.h:
+ * UIProcess/ios/forms/WKFormSelectPicker.mm:
+ (-[WKSelectPicker initWithView:]):
+ (-[WKSelectPicker controlView]):
+ (-[WKSelectPicker controlBeginEditing]):
+
+ Ensure the position information is up-to-date prior to presenting the
+ context menu.
+
+ (-[WKSelectPicker controlEndEditing]):
+ (-[WKSelectPicker dealloc]):
+ (-[WKSelectPicker didSelectOptionIndex:]):
+ (-[WKSelectPicker createMenu]):
+
+ Build the menu using UIActions and UIMenus. Since optgroup elements
+ cannot be nested, only the root UIMenu can contain UIMenus. Submenus
+ can only contain UIActions.
+
+ (-[WKSelectPicker actionForOptionItem:withIndex:]):
+ (-[WKSelectPicker contextMenuInteraction:previewForHighlightingMenuWithConfiguration:]):
+ (-[WKSelectPicker _contextMenuInteraction:styleForMenuWithConfiguration:]):
+ (-[WKSelectPicker contextMenuInteraction:configurationForMenuAtLocation:]):
+ (-[WKSelectPicker contextMenuInteraction:willDisplayMenuForConfiguration:animator:]):
+ (-[WKSelectPicker contextMenuInteraction:willEndForConfiguration:animator:]):
+ (-[WKSelectPicker removeContextMenuInteraction]):
+ (-[WKSelectPicker ensureContextMenuInteraction]):
+ (-[WKSelectPicker showSelectPicker]):
+ (-[WKSelectPicker selectRow:inComponent:extendingSelection:]):
+
+ Implement method for testing select pickers.
+
2021-02-03 Per Arne Vollan <[email protected]>
[macOS] Remove access to graphics related user clients
Modified: trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h (272333 => 272334)
--- trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h 2021-02-03 20:27:31 UTC (rev 272334)
@@ -1258,7 +1258,14 @@
@end
#endif // ENABLE(DRAG_SUPPORT)
-#if HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
+#if USE(UICONTEXTMENU)
+
+@interface UIAction (IPI)
+- (void)_performActionWithSender:(id)sender;
+@end
+
+#if HAVE(LINK_PREVIEW)
+
@interface UIContextMenuConfiguration (IPI)
@property (nonatomic, copy) UIContextMenuContentPreviewProvider previewProvider;
@property (nonatomic, copy) UIContextMenuActionProvider actionProvider;
@@ -1281,8 +1288,10 @@
@property (nonatomic, strong) _UIClickPresentationInteraction *presentationInteraction;
@end
-#endif // HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
+#endif // HAVE(LINK_PREVIEW)
+#endif // USE(UICONTEXTMENU)
+
@interface UIPhysicalKeyboardEvent : UIPressesEvent
@end
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (272333 => 272334)
--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h 2021-02-03 20:27:31 UTC (rev 272334)
@@ -107,6 +107,7 @@
@class WKDateTimeInputControl;
@class WKFocusedFormControlView;
@class WKFormInputSession;
+@class WKFormSelectControl;
@class WKHighlightLongPressGestureRecognizer;
@class WKMouseGestureRecognizer;
@class WKInspectorNodeSearchGestureRecognizer;
@@ -671,6 +672,10 @@
- (void)_setMouseEventPolicy:(WebCore::MouseEventPolicy)policy;
#endif
+#if ENABLE(IOS_FORM_CONTROL_REFRESH)
+- (BOOL)_formControlRefreshEnabled;
+#endif
+
@end
@interface WKContentView (WKTesting)
@@ -692,6 +697,7 @@
@property (nonatomic, readonly) NSString *selectFormPopoverTitle;
@property (nonatomic, readonly) NSString *formInputLabel;
@property (nonatomic, readonly) WKDateTimeInputControl *dateTimeInputControl;
+@property (nonatomic, readonly) WKFormSelectControl *selectControl;
@end
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (272333 => 272334)
--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2021-02-03 20:27:31 UTC (rev 272334)
@@ -2025,7 +2025,13 @@
case WebKit::InputType::DateTimeLocal:
case WebKit::InputType::Time:
return NO;
- case WebKit::InputType::Select:
+ case WebKit::InputType::Select: {
+#if ENABLE(IOS_FORM_CONTROL_REFRESH)
+ if ([self _formControlRefreshEnabled])
+ return NO;
+#endif
+ return !WebKit::currentUserInterfaceIdiomIsPadOrMac();
+ }
#if ENABLE(INPUT_TYPE_COLOR)
case WebKit::InputType::Color:
#endif
@@ -3068,7 +3074,7 @@
#endif
}
-static bool elementTypeRequiresAccessoryView(WebKit::InputType type)
+- (bool)_elementTypeRequiresAccessoryView:(WebKit::InputType)type
{
switch (type) {
case WebKit::InputType::None:
@@ -3078,6 +3084,13 @@
case WebKit::InputType::Month:
case WebKit::InputType::Time:
return false;
+ case WebKit::InputType::Select: {
+#if ENABLE(IOS_FORM_CONTROL_REFRESH)
+ if ([self _formControlRefreshEnabled])
+ return NO;
+#endif
+ return !WebKit::currentUserInterfaceIdiomIsPadOrMac();
+ }
case WebKit::InputType::Text:
case WebKit::InputType::Password:
case WebKit::InputType::Search:
@@ -3088,7 +3101,6 @@
case WebKit::InputType::NumberPad:
case WebKit::InputType::ContentEditable:
case WebKit::InputType::TextArea:
- case WebKit::InputType::Select:
case WebKit::InputType::Week:
#if ENABLE(INPUT_TYPE_COLOR)
case WebKit::InputType::Color:
@@ -3105,7 +3117,7 @@
if ([_formInputSession customInputAccessoryView])
return YES;
- return elementTypeRequiresAccessoryView(_focusedElementInformation.elementType);
+ return [self _elementTypeRequiresAccessoryView:_focusedElementInformation.elementType];
}
- (UITextInputAssistantItem *)inputAssistantItem
@@ -5926,6 +5938,18 @@
[self _updateAccessory];
}
+#if ENABLE(IOS_FORM_CONTROL_REFRESH)
+
+- (BOOL)_formControlRefreshEnabled
+{
+ if (!_page)
+ return NO;
+
+ return _page->preferences().iOSFormControlRefreshEnabled();
+}
+
+#endif
+
- (const WebKit::FocusedElementInformation&)focusedElementInformation
{
return _focusedElementInformation;
@@ -5968,7 +5992,7 @@
}
}
-static bool shouldShowKeyboardForElement(const WebKit::FocusedElementInformation& information)
+- (bool)_shouldShowKeyboardForElement:(const WebKit::FocusedElementInformation&)information
{
if (information.inputMode == WebCore::InputMode::None)
return false;
@@ -5976,7 +6000,7 @@
if (mayContainSelectableText(information.elementType))
return true;
- return elementTypeRequiresAccessoryView(information.elementType);
+ return [self _elementTypeRequiresAccessoryView:information.elementType];
}
static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebKit::InputType type, WKContentView *view)
@@ -6007,7 +6031,7 @@
- (void)_elementDidFocus:(const WebKit::FocusedElementInformation&)information userIsInteracting:(BOOL)userIsInteracting blurPreviousNode:(BOOL)blurPreviousNode activityStateChanges:(OptionSet<WebCore::ActivityState::Flag>)activityStateChanges userObject:(NSObject <NSSecureCoding> *)userObject
{
SetForScope<BOOL> isChangingFocusForScope { _isChangingFocus, self._hasFocusedElement };
- SetForScope<BOOL> isFocusingElementWithKeyboardForScope { _isFocusingElementWithKeyboard, shouldShowKeyboardForElement(information) };
+ SetForScope<BOOL> isFocusingElementWithKeyboardForScope { _isFocusingElementWithKeyboard, [self _shouldShowKeyboardForElement:information] };
auto inputViewUpdateDeferrer = std::exchange(_inputViewUpdateDeferrer, nullptr);
@@ -8012,6 +8036,9 @@
// and for the date/time picker.
if ([self dateTimeInputControl])
return;
+
+ if ([self selectControl])
+ return;
[std::exchange(_contextMenuHintContainerView, nil) removeFromSuperview];
}
@@ -9191,6 +9218,13 @@
return nil;
}
+- (WKFormSelectControl *)selectControl
+{
+ if ([_inputPeripheral isKindOfClass:WKFormSelectControl.class])
+ return (WKFormSelectControl *)_inputPeripheral.get();
+ return nil;
+}
+
- (void)_simulateTextEntered:(NSString *)text
{
#if PLATFORM(WATCHOS)
Modified: trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectControl.mm (272333 => 272334)
--- trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectControl.mm 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectControl.mm 2021-02-03 20:27:31 UTC (rev 272334)
@@ -74,6 +74,15 @@
}
RetainPtr<NSObject <WKFormControl>> control;
+
+#if ENABLE(IOS_FORM_CONTROL_REFRESH)
+ if ([view _formControlRefreshEnabled]) {
+ // FIXME: Add implementation for multi-select picker.
+ control = adoptNS([[WKSelectPicker alloc] initWithView:view]);
+ return [super initWithView:view control:WTFMove(control)];
+ }
+#endif
+
if (currentUserInterfaceIdiomIsPadOrMac())
control = adoptNS([[WKSelectPopover alloc] initWithView:view hasGroups:hasGroups]);
else if (view.focusedElementInformation.isMultiSelect || hasGroups)
Modified: trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectPicker.h (272333 => 272334)
--- trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectPicker.h 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectPicker.h 2021-02-03 20:27:31 UTC (rev 272334)
@@ -38,4 +38,16 @@
- (instancetype)initWithView:(WKContentView *)view;
@end
+#if ENABLE(IOS_FORM_CONTROL_REFRESH)
+
+@interface WKSelectPicker : NSObject <WKFormControl
+#if USE(UICONTEXTMENU)
+, UIContextMenuInteractionDelegate
+#endif
+>
+- (instancetype)initWithView:(WKContentView *)view;
+@end
+
+#endif
+
#endif // PLATFORM(IOS_FAMILY)
Modified: trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectPicker.mm (272333 => 272334)
--- trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectPicker.mm 2021-02-03 20:16:38 UTC (rev 272333)
+++ trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectPicker.mm 2021-02-03 20:27:31 UTC (rev 272334)
@@ -33,7 +33,9 @@
#import "WKContentViewInteraction.h"
#import "WKFormPopover.h"
#import "WKFormSelectControl.h"
+#import "WKWebViewPrivateForTesting.h"
#import "WebPageProxy.h"
+#import <WebCore/LocalizedStrings.h>
using namespace WebKit;
@@ -464,4 +466,237 @@
@end
-#endif // PLATFORM(IOS_FAMILY)
+#pragma mark - Form Control Refresh
+
+@implementation WKSelectPicker {
+ __weak WKContentView *_view;
+ CGPoint _interactionPoint;
+
+#if USE(UICONTEXTMENU)
+ RetainPtr<UIMenu> _selectMenu;
+ RetainPtr<UIContextMenuInteraction> _selectContextMenuInteraction;
+#endif
+}
+
+- (instancetype)initWithView:(WKContentView *)view
+{
+ if (!(self = [super init]))
+ return nil;
+
+ _view = view;
+ _interactionPoint = [_view lastInteractionLocation];
+#if USE(UICONTEXTMENU)
+ _selectMenu = [self createMenu];
+#endif
+
+ return self;
+}
+
+- (UIView *)controlView
+{
+ return nil;
+}
+
+- (void)controlBeginEditing
+{
+ [_view startRelinquishingFirstResponderToFocusedElement];
+
+#if USE(UICONTEXTMENU)
+ WebKit::InteractionInformationRequest positionInformationRequest { WebCore::IntPoint(_view.focusedElementInformation.lastInteractionLocation) };
+ [_view doAfterPositionInformationUpdate:^(WebKit::InteractionInformationAtPosition interactionInformation) {
+ [self showSelectPicker];
+ } forRequest:positionInformationRequest];
+#endif
+}
+
+- (void)controlEndEditing
+{
+ [_view stopRelinquishingFirstResponderToFocusedElement];
+
+#if USE(UICONTEXTMENU)
+ [self removeContextMenuInteraction];
+#endif
+}
+
+- (void)dealloc
+{
+#if USE(UICONTEXTMENU)
+ [self removeContextMenuInteraction];
+#endif
+ [super dealloc];
+}
+
+- (void)didSelectOptionIndex:(NSInteger)index
+{
+ [_view page]->setFocusedElementSelectedIndex(index);
+}
+
+#if USE(UICONTEXTMENU)
+
+- (UIMenu *)createMenu
+{
+ if (!_view.focusedSelectElementOptions.size()) {
+ UIAction *emptyAction = [UIAction actionWithTitle:WEB_UI_STRING_KEY("No Options", "No Options Select Popover", "Empty select list") image:nil identifier:nil handler:^(__kindof UIAction *action) { }];
+ emptyAction.attributes = UIMenuElementAttributesDisabled;
+ return [UIMenu menuWithTitle:@"" children:@[emptyAction]];
+ }
+
+ NSMutableArray *items = [NSMutableArray array];
+ NSInteger optionIndex = 0;
+
+ size_t currentIndex = 0;
+ while (currentIndex < _view.focusedSelectElementOptions.size()) {
+ auto& optionItem = _view.focusedSelectElementOptions[currentIndex];
+ if (optionItem.isGroup) {
+ NSString *groupText = optionItem.text;
+ NSMutableArray *groupedItems = [NSMutableArray array];
+
+ currentIndex++;
+ while (currentIndex < _view.focusedSelectElementOptions.size()) {
+ optionItem = _view.focusedSelectElementOptions[currentIndex];
+ if (optionItem.isGroup)
+ break;
+
+ UIAction *action = "" actionForOptionItem:optionItem withIndex:optionIndex];
+ [groupedItems addObject:action];
+ optionIndex++;
+ currentIndex++;
+ }
+
+ UIMenu *groupMenu = [UIMenu menuWithTitle:groupText children:groupedItems];
+ [items addObject:groupMenu];
+ continue;
+ }
+
+ UIAction *action = "" actionForOptionItem:optionItem withIndex:optionIndex];
+ [items addObject:action];
+ optionIndex++;
+ currentIndex++;
+ }
+
+ return [UIMenu menuWithTitle:@"" children:items];
+}
+
+- (UIAction *)actionForOptionItem:(const OptionItem&)option withIndex:(NSInteger)optionIndex
+{
+ UIAction *optionAction = [UIAction actionWithTitle:option.text image:nil identifier:nil handler:^(__kindof UIAction *action) {
+ [self didSelectOptionIndex:optionIndex];
+ }];
+
+ if (option.disabled)
+ optionAction.attributes = UIMenuElementAttributesDisabled;
+
+ if (option.isSelected)
+ optionAction.state = UIMenuElementStateOn;
+
+ return optionAction;
+}
+
+- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction previewForHighlightingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
+{
+ return [_view _createTargetedContextMenuHintPreviewIfPossible];
+}
+
+- (_UIContextMenuStyle *)_contextMenuInteraction:(UIContextMenuInteraction *)interaction styleForMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
+{
+ _UIContextMenuStyle *style = [_UIContextMenuStyle defaultStyle];
+ style.preferredLayout = _UIContextMenuLayoutCompactMenu;
+ return style;
+}
+
+- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location
+{
+ UIContextMenuActionProvider actionMenuProvider = [weakSelf = WeakObjCPtr<WKSelectPicker>(self)] (NSArray<UIMenuElement *> *) -> UIMenu * {
+ auto strongSelf = weakSelf.get();
+ if (!strongSelf)
+ return nil;
+
+ return strongSelf->_selectMenu.get();
+ };
+
+ return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:actionMenuProvider];
+}
+
+- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willDisplayMenuForConfiguration:(UIContextMenuConfiguration *)configuration animator:(id <UIContextMenuInteractionAnimating>)animator
+{
+ [animator addCompletion:[weakSelf = WeakObjCPtr<WKSelectPicker>(self)] {
+ auto strongSelf = weakSelf.get();
+ if (strongSelf)
+ [strongSelf->_view.webView _didShowContextMenu];
+ }];
+}
+
+- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willEndForConfiguration:(UIContextMenuConfiguration *)configuration animator:(id <UIContextMenuInteractionAnimating>)animator
+{
+ [animator addCompletion:[weakSelf = WeakObjCPtr<WKSelectPicker>(self)] {
+ auto strongSelf = weakSelf.get();
+ if (strongSelf) {
+ [strongSelf->_view accessoryDone];
+ [strongSelf->_view.webView _didDismissContextMenu];
+ }
+ }];
+}
+
+- (void)removeContextMenuInteraction
+{
+ if (!_selectContextMenuInteraction)
+ return;
+
+ [_view removeInteraction:_selectContextMenuInteraction.get()];
+ _selectContextMenuInteraction = nil;
+ [_view _removeContextMenuViewIfPossible];
+ [_view.webView _didDismissContextMenu];
+}
+
+- (void)ensureContextMenuInteraction
+{
+ if (_selectContextMenuInteraction)
+ return;
+
+ _selectContextMenuInteraction = adoptNS([[UIContextMenuInteraction alloc] initWithDelegate:self]);
+ [_view addInteraction:_selectContextMenuInteraction.get()];
+}
+
+- (void)showSelectPicker
+{
+ [self ensureContextMenuInteraction];
+ [_selectContextMenuInteraction _presentMenuAtLocation:_interactionPoint];
+}
+
+#endif // USE(UICONTEXTMENU)
+
+// WKSelectTesting
+- (void)selectRow:(NSInteger)rowIndex inComponent:(NSInteger)componentIndex extendingSelection:(BOOL)extendingSelection
+{
+#if USE(UICONTEXTMENU)
+ NSInteger currentRow = 0;
+
+ NSArray<UIMenuElement *> *menuElements = [_selectMenu children];
+ for (UIMenuElement *menuElement in menuElements) {
+ if ([menuElement isKindOfClass:UIAction.class]) {
+ if (currentRow == rowIndex) {
+ [(UIAction *)menuElement _performActionWithSender:nil];
+ break;
+ }
+
+ currentRow++;
+ continue;
+ }
+
+ UIMenu *groupedMenu = (UIMenu *)menuElement;
+ if (currentRow + groupedMenu.children.count <= (NSUInteger)rowIndex)
+ currentRow += groupedMenu.children.count;
+ else {
+ UIAction *action = "" *)[groupedMenu.children objectAtIndex:rowIndex - currentRow];
+ [action _performActionWithSender:nil];
+ break;
+ }
+ }
+
+ [self removeContextMenuInteraction];
+#endif
+}
+
+@end
+
+#endif // PLATFORM(IOS_FAMILY)