Skip to content

Commit 2c857c0

Browse files
Fix navigation menu item opening in new tab
When Ctrl+click is applied to the navigation menu item on the details page, the appropriate panel (not the Basic one if it is not clicked specifically) is opened in new tab. Related to #11050
1 parent 9a216b7 commit 2c857c0

File tree

3 files changed

+86
-24
lines changed

3 files changed

+86
-24
lines changed

gui/admin-gui/src/frontend/js/midpoint-theme.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,4 +1944,14 @@ export default class MidPointTheme {
19441944
$(idInput).passwordFieldValidatorPopover(idInput, ".password-validator-popover");
19451945
});
19461946
};
1947+
1948+
handleCtrlClick(event) {
1949+
if (event.ctrlKey || event.which === 2) {
1950+
event.preventDefault(); // stop browser navigation
1951+
window.open(event.currentTarget.href, '_blank', 'noopener=true');
1952+
return false; // cancel AJAX
1953+
} else {
1954+
return true; // normal click → AJAX
1955+
}
1956+
}
19471957
}

gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/component/MainObjectListPanel.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,7 @@ protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
195195
attributes.getAjaxCallListeners().add(new AjaxCallListener() {
196196
@Override
197197
public CharSequence getPrecondition(Component component) {
198-
return "if(attrs.event.ctrlKey || attrs.event.which === 2) { " +
199-
"attrs.event.preventDefault(); " + // stop browser navigation
200-
"window.open(attrs.event.currentTarget.href, '_blank', 'noopener=true'); " +
201-
"return false; " + // cancel AJAX
202-
"} else { return true; }"; // normal click → AJAX
198+
return "return MidPointTheme.handleCtrlClick(attrs.event);";
203199
}
204200
});
205201
}

gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/menu/DetailsNavigationPanel.java

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@
99
import java.io.Serial;
1010
import java.util.List;
1111

12+
import com.evolveum.midpoint.gui.api.page.PageBase;
13+
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
14+
1215
import org.apache.commons.lang3.StringUtils;
1316
import org.apache.wicket.AttributeModifier;
1417
import org.apache.wicket.Component;
18+
import org.apache.wicket.ajax.AjaxEventBehavior;
1519
import org.apache.wicket.ajax.AjaxRequestTarget;
16-
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
20+
import org.apache.wicket.ajax.attributes.AjaxCallListener;
21+
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
22+
import org.apache.wicket.ajax.markup.html.AjaxLink;
1723
import org.apache.wicket.behavior.AttributeAppender;
1824
import org.apache.wicket.markup.head.IHeaderResponse;
1925
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
@@ -39,6 +45,10 @@
3945
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
4046
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationTypeType;
4147

48+
import org.apache.wicket.request.cycle.RequestCycle;
49+
import org.apache.wicket.request.mapper.parameter.PageParameters;
50+
import org.jetbrains.annotations.NotNull;
51+
4252
public class DetailsNavigationPanel<O extends ObjectType> extends BasePanel<List<ContainerPanelConfigurationType>> {
4353

4454
@Serial private static final long serialVersionUID = 1L;
@@ -107,7 +117,7 @@ private void populateNavigationMenuItem(ListItem<ContainerPanelDto> item,
107117
WebMarkupContainer navigationDetails = createNavigationItemParentPanel(containerPanelDto);
108118
item.add(navigationDetails);
109119

110-
AjaxSubmitLink link = createNavigationLink(containerPanelDto, containerListModel);
120+
AjaxLink<?> link = createNavigationLink(containerPanelDto, containerListModel);
111121
navigationDetails.add(link);
112122

113123
addParentMenuItemDescription(link, panelConfig);
@@ -174,16 +184,52 @@ private boolean hasActiveSubmenu(ContainerPanelConfigurationType storageConfig,
174184
return false;
175185
}
176186

177-
private AjaxSubmitLink createNavigationLink(ContainerPanelDto panelConfigDto,
187+
private AjaxLink<?> createNavigationLink(ContainerPanelDto panelConfigDto,
178188
IModel<List<ContainerPanelDto>> containerListModel) {
179189
ContainerPanelConfigurationType panelConfig = panelConfigDto.getContainerPanelConfig();
180-
AjaxSubmitLink link = new AjaxSubmitLink(ID_NAV_ITEM_LINK) {
190+
var submenuExist = doesSubMenuExist(panelConfig);
191+
192+
AjaxLink<?> link = new AjaxLink<>(ID_NAV_ITEM_LINK) {
193+
@Serial private static final long serialVersionUID = 1L;
194+
195+
@Override
196+
public void onClick(AjaxRequestTarget target) {
197+
}
198+
199+
//todo fix
200+
// @Override
201+
// protected void onError(AjaxRequestTarget target) {
202+
// super.onError(target);
203+
//
204+
// target.add(getPageBase().getFeedbackPanel());
205+
// }
206+
};
207+
link.add(new AjaxEventBehavior("click") {
181208
@Serial private static final long serialVersionUID = 1L;
182209

183210
@Override
184-
public void onSubmit(AjaxRequestTarget target) {
185-
super.onSubmit(target);
211+
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
212+
super.updateAjaxAttributes(attributes);
213+
//CTRL+click should work only for the items without submenu
214+
//parent items (which have submenus) should only expand/collapse on click
215+
if (!submenuExist) {
216+
attributes.getDynamicExtraParameters().add(
217+
"return { ctrlKey: Wicket.Event.fix(attrs.event).ctrlKey };"
218+
);
219+
220+
attributes.getAjaxCallListeners().add(new AjaxCallListener() {
221+
@Serial private static final long serialVersionUID = 1L;
222+
223+
@Override
224+
public CharSequence getPrecondition(Component component) {
225+
return "return MidPointTheme.handleCtrlClick(attrs.event);";
226+
}
227+
});
228+
}
229+
}
186230

231+
@Override
232+
protected void onEvent(AjaxRequestTarget target) {
187233
target.add(DetailsNavigationPanel.this);
188234
onClickPerformed(panelConfig, target);
189235
clickedMenuItemName = createButtonLabel(panelConfig).getObject();
@@ -196,13 +242,8 @@ public void onSubmit(AjaxRequestTarget target) {
196242
panelConfigDto.setExpanded(!panelConfigDto.isExpanded());
197243
}
198244

199-
@Override
200-
protected void onError(AjaxRequestTarget target) {
201-
super.onError(target);
202-
203-
target.add(getPageBase().getFeedbackPanel());
204-
}
205-
};
245+
});
246+
link.add(AttributeModifier.replace("href", urlForNavItemLink(panelConfig)));
206247

207248
link.add(AttributeModifier.append(
208249
"aria-current",
@@ -223,7 +264,22 @@ protected void onError(AjaxRequestTarget target) {
223264
return link;
224265
}
225266

226-
private void addSrCurrentMessage(AjaxSubmitLink link, ContainerPanelDto panelConfigDto) {
267+
private String urlForNavItemLink(ContainerPanelConfigurationType panelConfig) {
268+
PageParameters parameters = new PageParameters();
269+
parameters.add(OnePageParameterEncoder.PARAMETER, objectDetailsModel.getObjectWrapper().getOid());
270+
271+
var panelId = panelConfig.getIdentifier();
272+
if (panelId != null) {
273+
parameters.add("panelId", panelId.toString());
274+
}
275+
276+
Class<? extends PageBase> detailsPageClass = getPageBase().getClass();
277+
var url = RequestCycle.get().urlFor(detailsPageClass, parameters);
278+
279+
return url != null ? url.toString() : "#";
280+
}
281+
282+
private void addSrCurrentMessage(@NotNull AjaxLink<?> link, ContainerPanelDto panelConfigDto) {
227283
ContainerPanelConfigurationType panelConfig = panelConfigDto.getContainerPanelConfig();
228284
Label srCurrentMessage = new Label(ID_NAV_ITEM_SR_CURRENT_MESSAGE, () -> {
229285
ContainerPanelConfigurationType storageConfig = getConfigurationFromStorage();
@@ -255,31 +311,31 @@ private void addSrCurrentMessage(AjaxSubmitLink link, ContainerPanelDto panelCon
255311
link.add(srCurrentMessage);
256312
}
257313

258-
private void addIcon(AjaxSubmitLink link, ContainerPanelConfigurationType panelConfig) {
314+
private void addIcon(@NotNull AjaxLink<?> link, ContainerPanelConfigurationType panelConfig) {
259315
WebMarkupContainer icon = new WebMarkupContainer(ID_NAV_ITEM_ICON);
260316
icon.setOutputMarkupId(true);
261317
icon.add(AttributeAppender.append("class", getMenuItemIconClass(panelConfig)));
262318
link.add(icon);
263319
}
264320

265-
private void addLabel(AjaxSubmitLink link, ContainerPanelConfigurationType panelConfig) {
321+
private void addLabel(@NotNull AjaxLink<?> link, ContainerPanelConfigurationType panelConfig) {
266322
Label buttonLabel = new Label(ID_NAV_ITEM, createButtonLabel(panelConfig));
267323
link.add(buttonLabel);
268324
}
269325

270-
private void addCount(AjaxSubmitLink link, ContainerPanelConfigurationType panelConfig) {
326+
private void addCount(@NotNull AjaxLink<?> link, ContainerPanelConfigurationType panelConfig) {
271327
Label label = new Label(ID_COUNT, createCountModel(panelConfig));
272328
label.add(new VisibleBehaviour(() -> getCounterProvider(panelConfig) != null));
273329
link.add(label);
274330
}
275331

276-
private void addSubmenuLink(AjaxSubmitLink link, ContainerPanelDto containerPanelDto) {
332+
private void addSubmenuLink(@NotNull AjaxLink<?> link, ContainerPanelDto containerPanelDto) {
277333
WebMarkupContainer submenuLink = new WebMarkupContainer(ID_SUBMENU_LINK);
278334
submenuLink.add(new VisibleBehaviour(() -> doesSubMenuExist(containerPanelDto.getContainerPanelConfig())));
279335
link.add(submenuLink);
280336
}
281337

282-
private void addParentMenuItemDescription(AjaxSubmitLink link, ContainerPanelConfigurationType panelConfig) {
338+
private void addParentMenuItemDescription(@NotNull AjaxLink<?> link, ContainerPanelConfigurationType panelConfig) {
283339
// in case there is parent menu item (e.g. Assignments is parent for Role menu item)
284340
// we want to add a description for a screen reader to describe this parent item
285341
DetailsNavigationPanel<?> parentPanel = link.findParent(DetailsNavigationPanel.class);

0 commit comments

Comments
 (0)