@conduction/nextcloud-vue 2.56.0-beta.4 → 2.56.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
  6. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
  7. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
  8. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  11. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
  12. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  13. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
  14. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  15. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
  16. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  17. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  18. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
  19. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
  20. package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
  21. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
  22. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  25. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
  26. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
  28. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
  30. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  31. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  32. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  33. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
  34. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  35. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
  36. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  37. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
  38. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  39. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
  40. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
  42. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
  43. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  44. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
  45. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  46. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
  48. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
  49. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
  50. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  51. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
  52. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  53. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
  54. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
  55. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
  56. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
  57. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
  58. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
  60. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
  62. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
  63. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
  64. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
  65. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
  67. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
  69. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  70. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
  71. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  72. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
  73. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
  74. package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
  75. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
  76. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  77. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  78. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  79. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
  80. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
  81. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
  82. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
  83. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  84. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
  85. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  86. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  87. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
  88. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  89. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  90. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  91. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  92. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  93. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  94. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  95. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  96. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  97. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  98. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  99. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  100. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  101. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  102. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  103. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  104. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  105. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  106. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  107. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  108. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  109. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  110. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  111. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  112. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  113. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  114. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  115. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  116. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  117. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  118. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  119. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  120. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  121. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  122. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  123. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  124. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  125. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  126. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  127. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  128. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  129. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  130. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  131. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  132. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  133. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  134. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  135. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  136. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  137. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  138. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  139. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  140. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  141. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  142. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  143. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  144. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  145. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  146. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  147. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  148. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  149. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  150. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  151. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  152. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  153. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  154. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  155. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  156. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  157. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  158. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  159. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  160. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  161. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  162. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  163. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  164. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  165. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  166. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  167. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  168. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  169. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  170. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  171. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  172. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  173. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  174. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  175. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  176. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  177. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  178. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  179. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  180. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  181. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  182. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  183. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  184. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  185. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  186. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  187. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  188. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  189. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  190. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  191. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  192. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  193. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  194. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  195. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  196. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  197. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  198. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  199. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  200. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  201. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  202. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  203. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  204. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  205. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  206. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  207. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  208. package/dist/esm/l10n/en.json.js +1 -0
  209. package/dist/esm/l10n/en.json.js.map +1 -1
  210. package/dist/esm/l10n/nl.json.js +1 -0
  211. package/dist/esm/l10n/nl.json.js.map +1 -1
  212. package/dist/esm/nextcloud-vue.css +71 -7
  213. package/dist/esm/utils/actionLink.js +5 -0
  214. package/dist/esm/utils/actionLink.js.map +1 -1
  215. package/dist/esm/utils/actionsDispatcher.js +16 -1
  216. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  217. package/dist/esm/utils/linkNavigation.js +6 -3
  218. package/dist/esm/utils/linkNavigation.js.map +1 -1
  219. package/dist/esm/utils/rowAuxClick.js +30 -5
  220. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  221. package/dist/esm/utils/safeHref.js +18 -3
  222. package/dist/esm/utils/safeHref.js.map +1 -1
  223. package/dist/nextcloud-vue.cjs.js +809 -383
  224. package/dist/nextcloud-vue.cjs.js.map +2 -2
  225. package/dist/nextcloud-vue.css +71 -7
  226. package/l10n/en.json +1 -0
  227. package/l10n/nl.json +1 -0
  228. package/package.json +1 -1
  229. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  230. package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
  231. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  232. package/src/components/CnBoardView/CnBoardView.vue +13 -5
  233. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  234. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  235. package/src/components/CnDataTable/CnDataTable.md +1 -1
  236. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  237. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  238. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  239. package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
  240. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  241. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  242. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  243. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  244. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  245. package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
  246. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  247. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  248. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  249. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  250. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  251. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  252. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  253. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  254. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  255. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  256. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  257. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  258. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  259. package/src/components/CnTabs/CnTabs.vue +7 -3
  260. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  261. package/src/css/table.css +26 -0
  262. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  263. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  264. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  265. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  266. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  267. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  268. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  269. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  270. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  271. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  272. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  273. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  274. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  275. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  276. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  277. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  278. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  279. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  280. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  281. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  282. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  283. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  284. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  285. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  286. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  287. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  288. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  289. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  290. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  291. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  292. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  293. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  294. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  295. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  296. package/src/utils/actionLink.js +5 -0
  297. package/src/utils/actionsDispatcher.js +15 -0
  298. package/src/utils/linkNavigation.js +6 -3
  299. package/src/utils/rowAuxClick.js +29 -4
  300. package/src/utils/safeHref.js +18 -3
@@ -5757,13 +5757,17 @@ async function runSelfImportRequest({ register, schema, file }) {
5757
5757
  * also fire `auxclick` for the right button, so a row that listens to it must
5758
5758
  * filter both out itself.
5759
5759
  *
5760
- * Whoever opens a row in a new tab calls `preventDefault()` on the event, so a
5761
- * second listener for the same click (a host behind a library default) can
5760
+ * Whoever opens a row in a new tab marks the event with `markNewTabHandled`, so
5761
+ * a second listener for the same click (a host behind a library default) can
5762
5762
  * check `isNewTabHandled` and not open a second tab.
5763
5763
  *
5764
5764
  * @module utils/rowAuxClick
5765
5765
  */
5766
5766
 
5767
+ // Events that opened a new tab. Not `defaultPrevented`, which any unrelated
5768
+ // handler can set on a modified or middle click.
5769
+ const newTabHandled = new WeakSet();
5770
+
5767
5771
  const NESTED_CONTROL = 'a, button, input, select, textarea, label, summary, [role="button"], [role="checkbox"], [role="link"], [contenteditable="true"]';
5768
5772
 
5769
5773
  /**
@@ -5797,6 +5801,21 @@ function isRowMiddleClick(event) {
5797
5801
  return Boolean(event && event.button === 1 && !isFromNestedControl(event))
5798
5802
  }
5799
5803
 
5804
+ /**
5805
+ * Cancel a middle-button press on a clickable row or card body, so the
5806
+ * browser does not start autoscroll (Chrome/Edge on Windows) instead of the
5807
+ * middle click opening the row. A press on a nested control, a link
5808
+ * included, keeps its default.
5809
+ *
5810
+ * @param {MouseEvent} event The mousedown event.
5811
+ * @return {void}
5812
+ */
5813
+ function preventMiddleClickAutoscroll(event) {
5814
+ if (event && event.button === 1 && !isFromNestedControl(event) && typeof event.preventDefault === 'function') {
5815
+ event.preventDefault();
5816
+ }
5817
+ }
5818
+
5800
5819
  /**
5801
5820
  * Whether `openRowTarget` would open this click in a new tab.
5802
5821
  *
@@ -5814,18 +5833,24 @@ function isNewTabClick(event) {
5814
5833
  * @return {boolean}
5815
5834
  */
5816
5835
  function isNewTabHandled(event) {
5817
- return Boolean(isNewTabClick(event) && event.defaultPrevented)
5836
+ return Boolean(isNewTabClick(event) && newTabHandled.has(event))
5818
5837
  }
5819
5838
 
5820
5839
  /**
5821
5840
  * Mark a new-tab click as handled after opening it, see `isNewTabHandled`.
5841
+ * Also prevents the event's default, so the browser does not act on the
5842
+ * click as well.
5822
5843
  *
5823
5844
  * @param {MouseEvent|KeyboardEvent|null|undefined} event The click event.
5824
5845
  * @param {boolean} opened Whether the target was opened.
5825
5846
  * @return {void}
5826
5847
  */
5827
5848
  function markNewTabHandled(event, opened) {
5828
- if (opened && isNewTabClick(event) && typeof event.preventDefault === 'function') {
5849
+ if (!opened || !isNewTabClick(event)) {
5850
+ return
5851
+ }
5852
+ newTabHandled.add(event);
5853
+ if (typeof event.preventDefault === 'function') {
5829
5854
  event.preventDefault();
5830
5855
  }
5831
5856
  }
@@ -5900,8 +5925,11 @@ function resolveHref(target, router) {
5900
5925
  * click is routed through the router; a modified click, or one a handler
5901
5926
  * already prevented, is left to the browser.
5902
5927
  *
5928
+ * Unlike `resolveHref`, a string target is a router path, so pair the two
5929
+ * with a location object (or `{ path }`) for the href and click to agree.
5930
+ *
5903
5931
  * @param {MouseEvent} event The click event.
5904
- * @param {string|object} target The router location the link points at.
5932
+ * @param {string|object} target The router location the link points at; a string is a router path.
5905
5933
  * @param {object} [router] The app's router.
5906
5934
  * @return {boolean} True when the app navigated.
5907
5935
  */
@@ -5927,8 +5955,8 @@ function followLinkClick(event, target, router) {
5927
5955
  *
5928
5956
  * A click that came from a control inside the surface (a button, a link, a
5929
5957
  * checkbox) is left to that control. Opening a new tab marks the event with
5930
- * `preventDefault()`, and an event already marked that way is skipped, so
5931
- * two listeners on the same click never open two tabs.
5958
+ * `markNewTabHandled`, and an event already marked is skipped, so two
5959
+ * listeners on the same click never open two tabs.
5932
5960
  *
5933
5961
  * @param {MouseEvent|KeyboardEvent|null|undefined} event The click event.
5934
5962
  * @param {string|object} target A URL, or a vue-router location.
@@ -6026,6 +6054,11 @@ function resolveItemActionLink(action, item, router) {
6026
6054
  * on an in-app link that opens in place goes through the router; a URL, a
6027
6055
  * new-tab target or a modified click is left to the browser.
6028
6056
  *
6057
+ * Hand-rolled rather than `NcActionRouter` / `NcButton :to`: the menus and
6058
+ * bars using it must still emit their own events on click, and without an
6059
+ * installed router `NcButton :to` falls back to a button that goes nowhere,
6060
+ * while an `<a href>` still navigates.
6061
+ *
6029
6062
  * @param {MouseEvent} event The click event.
6030
6063
  * @param {{to: (string|object|null), target: (string|undefined)}} link The resolved link.
6031
6064
  * @param {object} [router] The app's router.
@@ -6447,6 +6480,21 @@ function interpolateActionTarget(target, ctx) {
6447
6480
  return interpolateActionString(target || '', ctx || {})
6448
6481
  }
6449
6482
 
6483
+ // The tokens interpolateActionString resolves; a bare `@` or `{` is not one.
6484
+ const ACTION_TARGET_TOKEN = /@(?:objectId|object\.|page\.|workspace\.|config\.|range\.)|\{objectId\}/;
6485
+
6486
+ /**
6487
+ * Whether an action target carries a token that interpolation would resolve,
6488
+ * so it can only be known once the page context is. A `mailto:` address or a
6489
+ * URL with an `@handle` in it has none.
6490
+ *
6491
+ * @param {string} target The action's raw `target`.
6492
+ * @return {boolean}
6493
+ */
6494
+ function hasActionTargetTokens(target) {
6495
+ return typeof target === 'string' && ACTION_TARGET_TOKEN.test(target)
6496
+ }
6497
+
6450
6498
  /**
6451
6499
  * The link an action renders as when its only job is to navigate to a target
6452
6500
  * known at render time: `navigate` (token-interpolated like the dispatcher)
@@ -15200,6 +15248,20 @@ const __sfc_main$5Y = script$62;
15200
15248
  * @module utils/safeHref
15201
15249
  */
15202
15250
 
15251
+ /**
15252
+ * Whether a URL is protocol-relative the way a browser reads it: leading
15253
+ * control characters and spaces are dropped, tabs and newlines are ignored
15254
+ * anywhere, and a backslash counts as `/`.
15255
+ *
15256
+ * @param {string} url The URL.
15257
+ * @return {boolean}
15258
+ */
15259
+ function isProtocolRelative(url) {
15260
+ // eslint-disable-next-line no-control-regex
15261
+ const normalized = url.replace(/[\t\n\r]/g, '').replace(/^[\u0000-\u0020]+/, '');
15262
+ return /^[/\\]{2}/.test(normalized)
15263
+ }
15264
+
15203
15265
  /**
15204
15266
  * Validate a URL and return it only if the scheme is safe for `:href`.
15205
15267
  *
@@ -15212,7 +15274,8 @@ const __sfc_main$5Y = script$62;
15212
15274
  * - `javascript:...`
15213
15275
  * - `data:...`
15214
15276
  * - `vbscript:...`
15215
- * - Protocol-relative `//attacker.com/...` (ambiguous origin)
15277
+ * - Protocol-relative `//attacker.com/...` (ambiguous origin), also as
15278
+ * `/\attacker.com` or with leading whitespace
15216
15279
  * - Any other unrecognised scheme
15217
15280
  * - `null`, `undefined`, empty string
15218
15281
  *
@@ -15234,7 +15297,7 @@ function safeHref(url) {
15234
15297
  }
15235
15298
  // Reject protocol-relative URLs — `//attacker.com/x` looks like a relative
15236
15299
  // path but resolves to an arbitrary origin, bypassing same-origin intent.
15237
- if (url.startsWith('//')) {
15300
+ if (isProtocolRelative(url)) {
15238
15301
  return '#'
15239
15302
  }
15240
15303
  // Allow root-relative paths (same-origin navigation)
@@ -15279,7 +15342,7 @@ function safeImageSrc(url) {
15279
15342
  return url
15280
15343
  }
15281
15344
  // Reject protocol-relative
15282
- if (url.startsWith('//')) {
15345
+ if (isProtocolRelative(url)) {
15283
15346
  return ''
15284
15347
  }
15285
15348
  try {
@@ -16929,9 +16992,11 @@ var script$5_ = {
16929
16992
 
16930
16993
  /**
16931
16994
  * Convenience navigation (folded from CnTableWidget): a function that
16932
- * receives the clicked row and returns a vue-router route to push. When
16933
- * set, a row click navigates there (the `row-click` event still fires);
16934
- * a ctrl/cmd/shift or middle click opens it in a new tab.
16995
+ * receives a row and returns the vue-router route it opens. When set,
16996
+ * each row renders as a real link to that route, stretched over the
16997
+ * row: a click navigates there (the `row-click` event still fires), and
16998
+ * a ctrl/cmd/shift or middle click opens it in a new tab. A table whose
16999
+ * row click selects (`selectable` without `rowClickToView`) gets no link.
16935
17000
  *
16936
17001
  * @type {((row: object) => object)|null}
16937
17002
  */
@@ -16954,7 +17019,7 @@ var script$5_ = {
16954
17019
  },
16955
17020
  },
16956
17021
 
16957
- emits: ['row-click', 'row-context-menu', 'select', 'select-all', 'sort', 'view-all'],
17022
+ emits: ['row-click', 'row-aux-click', 'row-context-menu', 'select', 'select-all', 'sort', 'view-all'],
16958
17023
 
16959
17024
  setup() {
16960
17025
  // Tell a deliberate row click apart from a text-selection drag.
@@ -17104,6 +17169,32 @@ var script$5_ = {
17104
17169
  *
17105
17170
  * @return {Array<{key: string, order: 'asc'|'desc'}>}
17106
17171
  */
17172
+ /**
17173
+ * The link each row opens, keyed by row key: the `rowClickRoute`
17174
+ * location and its href. Empty when rows have no route, or when a row
17175
+ * click selects instead of navigating.
17176
+ *
17177
+ * @return {{[key: string]: {target: object, href: string}}}
17178
+ */
17179
+ rowLinks() {
17180
+ const links = {};
17181
+ if (!this.rowClickRoute || !this.$router || (this.selectable && !this.rowClickToView)) {
17182
+ return links
17183
+ }
17184
+ for (const row of this.effectiveRows) {
17185
+ const route = this.rowClickRoute(row);
17186
+ if (!route) {
17187
+ continue
17188
+ }
17189
+ const target = typeof route === 'string' ? { path: route } : route;
17190
+ const href = resolveHref(target, this.$router);
17191
+ if (href) {
17192
+ links[String(row[this.rowKey])] = { target, href };
17193
+ }
17194
+ }
17195
+ return links
17196
+ },
17197
+
17107
17198
  effectiveSortKeys() {
17108
17199
  if (this.sortKeys && this.sortKeys.length > 0) {
17109
17200
  return this.sortKeys
@@ -17580,9 +17671,23 @@ var script$5_ = {
17580
17671
  },
17581
17672
 
17582
17673
  /**
17583
- * Row-body middle click: emits `row-click` like a click, so the host
17584
- * (or `rowClickRoute`) can open the row in a new tab. Ignored for other
17585
- * buttons, nested controls, drags and select-on-click tables.
17674
+ * Row mousedown: record the press for the drag guard, and on a row a
17675
+ * middle click opens, keep the browser from starting autoscroll.
17676
+ *
17677
+ * @param {MouseEvent} event The mousedown event.
17678
+ */
17679
+ onRowMouseDown(event) {
17680
+ this.onPointerDown(event);
17681
+ if (!this.selectable || this.rowClickToView) {
17682
+ preventMiddleClickAutoscroll(event);
17683
+ }
17684
+ },
17685
+
17686
+ /**
17687
+ * Row-body middle click: emits `row-aux-click`, not `row-click`, so an
17688
+ * existing `row-click` listener that navigates never moves the current
17689
+ * tab away; `rowClickRoute` still opens the row in a new tab. Ignored
17690
+ * for other buttons, nested controls, drags and select-on-click tables.
17586
17691
  *
17587
17692
  * @param {object} row The clicked row object
17588
17693
  * @param {MouseEvent} event The originating auxclick event.
@@ -17594,23 +17699,39 @@ var script$5_ = {
17594
17699
  if (this.selectable && !this.rowClickToView) {
17595
17700
  return
17596
17701
  }
17597
- this.emitRowClick(row, event);
17702
+ /**
17703
+ * @event row-aux-click Emitted on a row-body middle click, under the same conditions as `row-click`, so a host can open the row in a new tab (see `openRowTarget`). Payload: `(row, event)` — the clicked row object and the native auxclick event.
17704
+ * @type {object} The clicked row object.
17705
+ */
17706
+ this.$emit('row-aux-click', row, event);
17707
+ this.followRowClickRoute(row, event);
17598
17708
  },
17599
17709
 
17600
17710
  /**
17601
17711
  * Emit `row-click` and follow `rowClickRoute` when set.
17602
17712
  *
17603
17713
  * @param {object} row The clicked row object
17604
- * @param {MouseEvent} [event] The originating click or auxclick event.
17714
+ * @param {MouseEvent} [event] The originating click event.
17605
17715
  */
17606
17716
  emitRowClick(row, event) {
17607
17717
  /**
17608
- * @event row-click Emitted on a row-body click for navigation, and on a middle click (auxclick). Fires when `selectable` is false, OR when `rowClickToView` is set (selection then happens via the checkbox column). Payload: `(row, event)` — the clicked row object and the native click/auxclick event, so a host can open the row in a new tab on a ctrl/cmd/shift or middle click (see `openRowTarget`).
17718
+ * @event row-click Emitted on a row-body click for navigation. Fires when `selectable` is false, OR when `rowClickToView` is set (selection then happens via the checkbox column). Payload: `(row, event)` — the clicked row object and the native click event, so a host can open the row in a new tab on a ctrl/cmd/shift click (see `openRowTarget`). A middle click emits `row-aux-click` instead.
17609
17719
  * @type {object} The clicked row object.
17610
17720
  */
17611
17721
  this.$emit('row-click', row, event);
17612
- // A ctrl/cmd/shift or middle click opens the route in a new tab,
17613
- // unless a row-click listener already did.
17722
+ this.followRowClickRoute(row, event);
17723
+ },
17724
+
17725
+ /**
17726
+ * Follow `rowClickRoute` for a row click: in place, or in a new tab on
17727
+ * a ctrl/cmd/shift or middle click.
17728
+ *
17729
+ * @param {object} row The clicked row object
17730
+ * @param {MouseEvent} [event] The originating click or auxclick event.
17731
+ */
17732
+ followRowClickRoute(row, event) {
17733
+ // A new-tab click opens the route in a new tab, unless a listener
17734
+ // already did.
17614
17735
  if (this.rowClickRoute && this.$router && !isNewTabHandled(event)) {
17615
17736
  const route = this.rowClickRoute(row);
17616
17737
  if (route) {
@@ -17619,14 +17740,57 @@ var script$5_ = {
17619
17740
  }
17620
17741
  },
17621
17742
 
17743
+ /**
17744
+ * A plain or alt click on a row link routes in place; a new-tab click
17745
+ * is left to the browser, which opens the href itself.
17746
+ *
17747
+ * @param {object} row The row the link belongs to.
17748
+ * @param {MouseEvent} event The click event.
17749
+ */
17750
+ onRowLinkClick(row, event) {
17751
+ const link = this.rowLinks[String(row[this.rowKey])];
17752
+ if (!link) {
17753
+ return
17754
+ }
17755
+ // Alt-click on a link downloads it; a row opens like a plain click.
17756
+ if (event.altKey && !isNewTabClick(event) && !event.defaultPrevented) {
17757
+ event.preventDefault();
17758
+ this.$router.push(link.target).catch(() => {});
17759
+ return
17760
+ }
17761
+ followLinkClick(event, link.target, this.$router);
17762
+ },
17763
+
17764
+ /**
17765
+ * The row link's accessible name: the row's first cell when it holds
17766
+ * plain text, else a generic name.
17767
+ *
17768
+ * @param {object} row The row.
17769
+ * @param {object} col The first data column.
17770
+ * @return {string}
17771
+ */
17772
+ rowLinkLabel(row, col) {
17773
+ const value = this.cellValue(row, col);
17774
+ if (['string', 'number'].includes(typeof value) && String(value).trim() !== '') {
17775
+ return String(value)
17776
+ }
17777
+ return l10n.translate('nextcloud-vue', 'Open row')
17778
+ },
17779
+
17622
17780
  /**
17623
17781
  * Row right-click: forward the row + originating event so a host can
17624
- * open a context menu (the browser default is prevented).
17782
+ * open a context menu. The browser menu is prevented, except on a row
17783
+ * link when no host listens, so its link actions stay available.
17625
17784
  *
17626
17785
  * @param {object} row The right-clicked row object.
17627
17786
  * @param {MouseEvent} event The originating contextmenu event.
17628
17787
  */
17629
17788
  onRowContextMenu(row, event) {
17789
+ const fromRowLink = event.target?.closest?.('.cn-table-row__link');
17790
+ // `$.vnode.props`, not `$attrs`: a declared emit is stripped from `$attrs`.
17791
+ if (!fromRowLink || this.$.vnode.props?.onRowContextMenu) {
17792
+ event.preventDefault();
17793
+ }
17630
17794
  /**
17631
17795
  * @event row-context-menu Emitted on a row right-click (contextmenu) for hosts that render a context menu.
17632
17796
  * @type {{ row: object, event: MouseEvent }}
@@ -17788,18 +17952,19 @@ const _hoisted_16$1b = {
17788
17952
  key: 1,
17789
17953
  class: "cn-table-col--icon"
17790
17954
  };
17791
- const _hoisted_17$12 = {
17792
- key: 1,
17955
+ const _hoisted_17$12 = ["href", "aria-label", "onClick"];
17956
+ const _hoisted_18$T = {
17957
+ key: 2,
17793
17958
  class: "cn-table-row-indicators",
17794
17959
  "data-testid": "cn-row-indicators"
17795
17960
  };
17796
- const _hoisted_18$T = ["title", "data-testid"];
17797
- const _hoisted_19$L = { class: "hidden-visually" };
17798
- const _hoisted_20$E = {
17961
+ const _hoisted_19$L = ["title", "data-testid"];
17962
+ const _hoisted_20$E = { class: "hidden-visually" };
17963
+ const _hoisted_21$C = {
17799
17964
  key: 3,
17800
17965
  class: "cn-data-table__footer"
17801
17966
  };
17802
- const _hoisted_21$C = ["href"];
17967
+ const _hoisted_22$z = ["href"];
17803
17968
 
17804
17969
  function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
17805
17970
  const _component_NcLoadingIcon = vue$1.resolveComponent("NcLoadingIcon");
@@ -17907,14 +18072,15 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
17907
18072
  key: row[$props.rowKey],
17908
18073
  class: vue$1.normalizeClass(["cn-table-row", [
17909
18074
  $options.isSelected(row) ? 'cn-table-row--selected' : '',
18075
+ $options.rowLinks[String(row[$props.rowKey])] ? 'cn-table-row--linked' : '',
17910
18076
  $props.rowClass ? $props.rowClass(row) : '',
17911
18077
  ]]),
17912
18078
  "data-testid": "cn-object-row",
17913
18079
  "data-testid-row-id": row[$props.rowKey],
17914
- onMousedown: _cache[5] || (_cache[5] = (...args) => (_ctx.onPointerDown && _ctx.onPointerDown(...args))),
18080
+ onMousedown: _cache[5] || (_cache[5] = (...args) => ($options.onRowMouseDown && $options.onRowMouseDown(...args))),
17915
18081
  onClick: $event => ($options.onRowClick(row, $event)),
17916
18082
  onAuxclick: $event => ($options.onRowAuxClick(row, $event)),
17917
- onContextmenu: vue$1.withModifiers($event => ($options.onRowContextMenu(row, $event)), ["prevent"])
18083
+ onContextmenu: $event => ($options.onRowContextMenu(row, $event))
17918
18084
  }, [
17919
18085
  ($props.selectable)
17920
18086
  ? (vue$1.openBlock(), vue$1.createElementBlock("td", {
@@ -17945,15 +18111,26 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
17945
18111
  style: vue$1.normalizeStyle(col.width ? { maxWidth: col.width } : {}),
17946
18112
  onMouseenter: _cache[2] || (_cache[2] = (...args) => ($options.titleWhenClipped && $options.titleWhenClipped(...args)))
17947
18113
  }, [
18114
+ (colIndex === 0 && $options.rowLinks[String(row[$props.rowKey])])
18115
+ ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
18116
+ key: 0,
18117
+ class: "cn-table-row__link",
18118
+ href: $options.rowLinks[String(row[$props.rowKey])].href,
18119
+ "aria-label": $options.rowLinkLabel(row, col),
18120
+ draggable: "false",
18121
+ "data-testid": "cn-row-link",
18122
+ onClick: $event => ($options.onRowLinkClick(row, $event))
18123
+ }, null, 8 /* PROPS */, _hoisted_17$12))
18124
+ : vue$1.createCommentVNode("v-if", true),
17948
18125
  (colIndex === 0)
17949
18126
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnLockIndicator, {
17950
- key: 0,
18127
+ key: 1,
17951
18128
  object: row,
17952
18129
  size: 16
17953
18130
  }, null, 8 /* PROPS */, ["object"]))
17954
18131
  : vue$1.createCommentVNode("v-if", true),
17955
18132
  (colIndex === 0 && $options.indicatorsFor(row).shown.length > 0)
17956
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_17$12, [
18133
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_18$T, [
17957
18134
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.indicatorsFor(row).shown, (indicator) => {
17958
18135
  return (vue$1.openBlock(), vue$1.createElementBlock("span", {
17959
18136
  key: indicator.id || indicator.field,
@@ -17965,8 +18142,8 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
17965
18142
  name: indicator.icon || 'InformationOutline',
17966
18143
  size: 16
17967
18144
  }, null, 8 /* PROPS */, ["name"]),
17968
- vue$1.createElementVNode("span", _hoisted_19$L, vue$1.toDisplayString(indicator.text), 1 /* TEXT */)
17969
- ], 8 /* PROPS */, _hoisted_18$T))
18145
+ vue$1.createElementVNode("span", _hoisted_20$E, vue$1.toDisplayString(indicator.text), 1 /* TEXT */)
18146
+ ], 8 /* PROPS */, _hoisted_19$L))
17970
18147
  }), 128 /* KEYED_FRAGMENT */))
17971
18148
  ]))
17972
18149
  : vue$1.createCommentVNode("v-if", true),
@@ -18004,7 +18181,7 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
18004
18181
  ], 2 /* CLASS */)
18005
18182
  ], 8 /* PROPS */, _hoisted_5$3W)),
18006
18183
  (_ctx.$slots.footer || ($props.viewAllRoute && $options.totalRowCount > $options.effectiveRows.length))
18007
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_20$E, [
18184
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_21$C, [
18008
18185
  vue$1.renderSlot(_ctx.$slots, "footer", {
18009
18186
  total: $options.totalRowCount,
18010
18187
  shown: $options.effectiveRows.length
@@ -18015,7 +18192,7 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
18015
18192
  class: "cn-data-table__view-all",
18016
18193
  href: $options.viewAllHref,
18017
18194
  onClick: _cache[6] || (_cache[6] = (...args) => ($options.onViewAll && $options.onViewAll(...args)))
18018
- }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_21$C))
18195
+ }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_22$z))
18019
18196
  : (vue$1.openBlock(), vue$1.createElementBlock("button", {
18020
18197
  key: 1,
18021
18198
  type: "button",
@@ -51199,12 +51376,12 @@ const _hoisted_22$y = {
51199
51376
  class: "cn-icon-browser-panel__error",
51200
51377
  role: "alert"
51201
51378
  };
51202
- const _hoisted_23$o = ["placeholder", "aria-label"];
51203
- const _hoisted_24$m = {
51379
+ const _hoisted_23$p = ["placeholder", "aria-label"];
51380
+ const _hoisted_24$n = {
51204
51381
  key: 3,
51205
51382
  class: "cn-icon-browser-panel__grid"
51206
51383
  };
51207
- const _hoisted_25$i = ["title", "aria-label", "onClick"];
51384
+ const _hoisted_25$j = ["title", "aria-label", "onClick"];
51208
51385
  const _hoisted_26$f = ["src", "alt"];
51209
51386
  const _hoisted_27$b = {
51210
51387
  key: 0,
@@ -51395,12 +51572,12 @@ function render$5X(_ctx, _cache, $props, $setup, $data, $options) {
51395
51572
  class: "cn-icon-browser-panel__search",
51396
51573
  placeholder: $options.t('nextcloud-vue', 'Search icons…'),
51397
51574
  "aria-label": $options.t('nextcloud-vue', 'Search icons')
51398
- }, null, 8 /* PROPS */, _hoisted_23$o)), [
51575
+ }, null, 8 /* PROPS */, _hoisted_23$p)), [
51399
51576
  [vue$1.vModelText, $data.customQuery]
51400
51577
  ])
51401
51578
  : vue$1.createCommentVNode("v-if", true),
51402
51579
  ($options.customVisibleIcons.length > 0)
51403
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_24$m, [
51580
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_24$n, [
51404
51581
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.customVisibleIcons, (icon) => {
51405
51582
  return (vue$1.openBlock(), vue$1.createElementBlock("button", {
51406
51583
  key: icon.id || icon.url,
@@ -51419,7 +51596,7 @@ function render$5X(_ctx, _cache, $props, $setup, $data, $options) {
51419
51596
  ($props.showLabels)
51420
51597
  ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_27$b, vue$1.toDisplayString(icon.label), 1 /* TEXT */))
51421
51598
  : vue$1.createCommentVNode("v-if", true)
51422
- ], 10 /* CLASS, PROPS */, _hoisted_25$i))
51599
+ ], 10 /* CLASS, PROPS */, _hoisted_25$j))
51423
51600
  }), 128 /* KEYED_FRAGMENT */))
51424
51601
  ]))
51425
51602
  : vue$1.createCommentVNode("v-if", true),
@@ -61199,9 +61376,9 @@ const _hoisted_19$I = { class: "cn-activity-tab__day-label" };
61199
61376
  const _hoisted_20$B = { class: "cn-activity-tab__day-count" };
61200
61377
  const _hoisted_21$z = { class: "cn-activity-tab__list" };
61201
61378
  const _hoisted_22$w = { class: "cn-activity-tab__subject" };
61202
- const _hoisted_23$n = { class: "cn-activity-tab__avatar-wrap" };
61203
- const _hoisted_24$l = { class: "cn-activity-tab__subname" };
61204
- const _hoisted_25$h = { class: "cn-activity-tab__actor" };
61379
+ const _hoisted_23$o = { class: "cn-activity-tab__avatar-wrap" };
61380
+ const _hoisted_24$m = { class: "cn-activity-tab__subname" };
61381
+ const _hoisted_25$i = { class: "cn-activity-tab__actor" };
61205
61382
  const _hoisted_26$e = { class: "cn-activity-tab__time" };
61206
61383
  const _hoisted_27$a = {
61207
61384
  key: 0,
@@ -61318,7 +61495,7 @@ function render$5S(_ctx, _cache, $props, $setup, $data, $options) {
61318
61495
  vue$1.createElementVNode("span", _hoisted_22$w, vue$1.toDisplayString($options.subjectFor(entry)), 1 /* TEXT */)
61319
61496
  ]),
61320
61497
  icon: vue$1.withCtx(() => [
61321
- vue$1.createElementVNode("span", _hoisted_23$n, [
61498
+ vue$1.createElementVNode("span", _hoisted_23$o, [
61322
61499
  vue$1.createVNode(_component_NcAvatar, {
61323
61500
  user: $options.avatarUser(entry),
61324
61501
  displayName: $options.actorFor(entry),
@@ -61335,8 +61512,8 @@ function render$5S(_ctx, _cache, $props, $setup, $data, $options) {
61335
61512
  ])
61336
61513
  ]),
61337
61514
  subname: vue$1.withCtx(() => [
61338
- vue$1.createElementVNode("span", _hoisted_24$l, [
61339
- vue$1.createElementVNode("span", _hoisted_25$h, vue$1.toDisplayString($options.actorFor(entry)), 1 /* TEXT */)
61515
+ vue$1.createElementVNode("span", _hoisted_24$m, [
61516
+ vue$1.createElementVNode("span", _hoisted_25$i, vue$1.toDisplayString($options.actorFor(entry)), 1 /* TEXT */)
61340
61517
  ])
61341
61518
  ]),
61342
61519
  _: 2 /* DYNAMIC */
@@ -61615,8 +61792,9 @@ var script$5R = {
61615
61792
  return `cn-analytics-card__badge--type-${type ?? 'unknown'}`
61616
61793
  },
61617
61794
 
61795
+ // A provider URL is used only when it is a safe scheme; else the app link.
61618
61796
  reportUrl(report) {
61619
- if (report && report.url) {
61797
+ if (report && report.url && safeHref(report.url) !== '#') {
61620
61798
  return report.url
61621
61799
  }
61622
61800
  const id = this.reportKey(report);
@@ -62507,8 +62685,9 @@ var script$5O = {
62507
62685
  return l10n.translate('nextcloud-vue', 'Latest value')
62508
62686
  },
62509
62687
 
62688
+ // A provider URL is used only when it is a safe scheme; else the app link.
62510
62689
  reportUrl(report) {
62511
- if (report && report.url) {
62690
+ if (report && report.url && safeHref(report.url) !== '#') {
62512
62691
  return report.url
62513
62692
  }
62514
62693
  const id = this.reportKey(report);
@@ -62740,8 +62919,7 @@ function render$5O(_ctx, _cache, $props, $setup, $data, $options) {
62740
62919
  vue$1.createVNode(_component_NcButton, {
62741
62920
  variant: "primary",
62742
62921
  href: $props.analyticsAppUrl,
62743
- target: "_blank",
62744
- rel: "noopener noreferrer"
62922
+ target: "_blank"
62745
62923
  }, {
62746
62924
  icon: vue$1.withCtx(() => [
62747
62925
  vue$1.createVNode(_component_ChartBar, { size: 20 })
@@ -62788,8 +62966,7 @@ function render$5O(_ctx, _cache, $props, $setup, $data, $options) {
62788
62966
  vue$1.createVNode(_component_NcActionLink, {
62789
62967
  closeAfterClick: true,
62790
62968
  href: $options.reportUrl(report),
62791
- target: "_blank",
62792
- rel: "noopener noreferrer"
62969
+ target: "_blank"
62793
62970
  }, {
62794
62971
  icon: vue$1.withCtx(() => [
62795
62972
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -63673,6 +63850,11 @@ var script$5L = {
63673
63850
  return bookmark.title || bookmark.url || ''
63674
63851
  },
63675
63852
 
63853
+ // Bookmark URLs are user-entered (bookmarklets are `javascript:`), so only a safe one is a link.
63854
+ hasSafeUrl(bookmark) {
63855
+ return safeHref(bookmark.url) !== '#'
63856
+ },
63857
+
63676
63858
  chipSubtitle(bookmark) {
63677
63859
  return bookmark.description || bookmark.url || this.bookmarkTitle(bookmark)
63678
63860
  },
@@ -63758,55 +63940,61 @@ var script$5L = {
63758
63940
  const _hoisted_1$5w = ["title"];
63759
63941
  const _hoisted_2$5h = ["src"];
63760
63942
  const _hoisted_3$4J = ["href"];
63761
- const _hoisted_4$4h = {
63943
+ const _hoisted_4$4h = { key: 3 };
63944
+ const _hoisted_5$3L = {
63762
63945
  key: 1,
63763
63946
  class: "cn-bookmarks-card__empty"
63764
63947
  };
63765
- const _hoisted_5$3L = {
63948
+ const _hoisted_6$3t = {
63766
63949
  key: 0,
63767
63950
  class: "cn-bookmarks-card__empty"
63768
63951
  };
63769
- const _hoisted_6$3t = {
63952
+ const _hoisted_7$34 = {
63770
63953
  key: 1,
63771
63954
  class: "cn-bookmarks-card__empty"
63772
63955
  };
63773
- const _hoisted_7$34 = {
63956
+ const _hoisted_8$2J = {
63774
63957
  key: 2,
63775
63958
  class: "cn-bookmarks-card__headline"
63776
63959
  };
63777
- const _hoisted_8$2J = { class: "cn-bookmarks-card__headline-line" };
63778
- const _hoisted_9$2v = {
63960
+ const _hoisted_9$2v = { class: "cn-bookmarks-card__headline-line" };
63961
+ const _hoisted_10$2c = {
63779
63962
  key: 0,
63780
63963
  class: "cn-bookmarks-card__headline-recent"
63781
63964
  };
63782
- const _hoisted_10$2c = ["src"];
63783
- const _hoisted_11$1T = ["href"];
63784
- const _hoisted_12$1I = {
63965
+ const _hoisted_11$1T = ["src"];
63966
+ const _hoisted_12$1I = ["href"];
63967
+ const _hoisted_13$1A = { key: 3 };
63968
+ const _hoisted_14$1r = {
63785
63969
  key: 1,
63786
63970
  class: "cn-bookmarks-card__view-all"
63787
63971
  };
63788
- const _hoisted_13$1A = ["href"];
63789
- const _hoisted_14$1r = {
63972
+ const _hoisted_15$1g = ["href"];
63973
+ const _hoisted_16$15 = {
63790
63974
  key: 0,
63791
63975
  class: "cn-bookmarks-card__empty"
63792
63976
  };
63793
- const _hoisted_15$1g = {
63977
+ const _hoisted_17$Y = {
63794
63978
  key: 1,
63795
63979
  class: "cn-bookmarks-card__empty"
63796
63980
  };
63797
- const _hoisted_16$15 = {
63981
+ const _hoisted_18$N = {
63798
63982
  key: 2,
63799
63983
  class: "cn-bookmarks-card__list"
63800
63984
  };
63801
- const _hoisted_17$Y = { class: "cn-bookmarks-card__row-icon" };
63802
- const _hoisted_18$N = ["src", "onError"];
63803
- const _hoisted_19$F = { class: "cn-bookmarks-card__row-main" };
63804
- const _hoisted_20$z = ["href"];
63805
- const _hoisted_21$x = {
63985
+ const _hoisted_19$F = { class: "cn-bookmarks-card__row-icon" };
63986
+ const _hoisted_20$z = ["src", "onError"];
63987
+ const _hoisted_21$x = { class: "cn-bookmarks-card__row-main" };
63988
+ const _hoisted_22$v = ["href"];
63989
+ const _hoisted_23$n = {
63990
+ key: 1,
63991
+ class: "cn-bookmarks-card__title"
63992
+ };
63993
+ const _hoisted_24$l = {
63806
63994
  key: 3,
63807
63995
  class: "cn-bookmarks-card__view-all"
63808
63996
  };
63809
- const _hoisted_22$v = ["href"];
63997
+ const _hoisted_25$h = ["href"];
63810
63998
 
63811
63999
  function render$5L(_ctx, _cache, $props, $setup, $data, $options) {
63812
64000
  const _component_NcLoadingIcon = vue$1.resolveComponent("NcLoadingIcon");
@@ -63841,26 +64029,29 @@ function render$5L(_ctx, _cache, $props, $setup, $data, $options) {
63841
64029
  key: 1,
63842
64030
  size: 14
63843
64031
  })),
63844
- vue$1.createElementVNode("a", {
63845
- href: $data.entity.url,
63846
- target: "_blank",
63847
- rel: "noopener noreferrer"
63848
- }, vue$1.toDisplayString($options.bookmarkTitle($data.entity)), 9 /* TEXT, PROPS */, _hoisted_3$4J)
64032
+ ($options.hasSafeUrl($data.entity))
64033
+ ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
64034
+ key: 2,
64035
+ href: $data.entity.url,
64036
+ target: "_blank",
64037
+ rel: "noopener noreferrer"
64038
+ }, vue$1.toDisplayString($options.bookmarkTitle($data.entity)), 9 /* TEXT, PROPS */, _hoisted_3$4J))
64039
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_4$4h, vue$1.toDisplayString($options.bookmarkTitle($data.entity)), 1 /* TEXT */))
63849
64040
  ], 8 /* PROPS */, _hoisted_1$5w))
63850
- : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_4$4h, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
64041
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_5$3L, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
63851
64042
  ], 64 /* STABLE_FRAGMENT */))
63852
64043
  : ($props.surface === 'user-dashboard' || $props.surface === 'app-dashboard')
63853
64044
  ? (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 2 }, [
63854
64045
  ($data.degraded)
63855
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_5$3L, vue$1.toDisplayString($data.degraded), 1 /* TEXT */))
64046
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$3t, vue$1.toDisplayString($data.degraded), 1 /* TEXT */))
63856
64047
  : ($data.bookmarks.length === 0)
63857
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$3t, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
63858
- : (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_7$34, [
63859
- vue$1.createElementVNode("div", _hoisted_8$2J, [
64048
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_7$34, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
64049
+ : (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$2J, [
64050
+ vue$1.createElementVNode("div", _hoisted_9$2v, [
63860
64051
  vue$1.createElementVNode("strong", null, vue$1.toDisplayString($options.countHeadline), 1 /* TEXT */)
63861
64052
  ]),
63862
64053
  ($options.mostRecent)
63863
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_9$2v, [
64054
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_10$2c, [
63864
64055
  ($options.faviconUrl($options.mostRecent))
63865
64056
  ? (vue$1.openBlock(), vue$1.createElementBlock("img", {
63866
64057
  key: 0,
@@ -63868,41 +64059,44 @@ function render$5L(_ctx, _cache, $props, $setup, $data, $options) {
63868
64059
  alt: "",
63869
64060
  class: "cn-bookmarks-card__favicon",
63870
64061
  onError: _cache[1] || (_cache[1] = $event => ($options.onFaviconError($options.mostRecent)))
63871
- }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_10$2c))
64062
+ }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_11$1T))
63872
64063
  : (vue$1.openBlock(), vue$1.createBlock(_component_Bookmark, {
63873
64064
  key: 1,
63874
64065
  size: 14
63875
64066
  })),
63876
- vue$1.createElementVNode("a", {
63877
- href: $options.mostRecent.url,
63878
- target: "_blank",
63879
- rel: "noopener noreferrer"
63880
- }, vue$1.toDisplayString($options.bookmarkTitle($options.mostRecent)), 9 /* TEXT, PROPS */, _hoisted_11$1T)
64067
+ ($options.hasSafeUrl($options.mostRecent))
64068
+ ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
64069
+ key: 2,
64070
+ href: $options.mostRecent.url,
64071
+ target: "_blank",
64072
+ rel: "noopener noreferrer"
64073
+ }, vue$1.toDisplayString($options.bookmarkTitle($options.mostRecent)), 9 /* TEXT, PROPS */, _hoisted_12$1I))
64074
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_13$1A, vue$1.toDisplayString($options.bookmarkTitle($options.mostRecent)), 1 /* TEXT */))
63881
64075
  ]))
63882
64076
  : vue$1.createCommentVNode("v-if", true),
63883
64077
  ($data.bookmarks.length > 1)
63884
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_12$1I, [
64078
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_14$1r, [
63885
64079
  vue$1.createElementVNode("a", {
63886
64080
  href: $props.bookmarksAppUrl,
63887
64081
  target: "_blank",
63888
64082
  rel: "noopener noreferrer"
63889
- }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_13$1A)
64083
+ }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_15$1g)
63890
64084
  ]))
63891
64085
  : vue$1.createCommentVNode("v-if", true)
63892
64086
  ]))
63893
64087
  ], 64 /* STABLE_FRAGMENT */))
63894
64088
  : (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 3 }, [
63895
64089
  ($data.degraded)
63896
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_14$1r, vue$1.toDisplayString($data.degraded), 1 /* TEXT */))
64090
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_16$15, vue$1.toDisplayString($data.degraded), 1 /* TEXT */))
63897
64091
  : ($data.bookmarks.length === 0)
63898
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_15$1g, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
63899
- : (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_16$15, [
64092
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_17$Y, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
64093
+ : (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_18$N, [
63900
64094
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.displayedBookmarks, (bookmark) => {
63901
64095
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
63902
64096
  key: $options.bookmarkKey(bookmark),
63903
64097
  class: "cn-bookmarks-card__row"
63904
64098
  }, [
63905
- vue$1.createElementVNode("div", _hoisted_17$Y, [
64099
+ vue$1.createElementVNode("div", _hoisted_19$F, [
63906
64100
  ($options.faviconUrl(bookmark))
63907
64101
  ? (vue$1.openBlock(), vue$1.createElementBlock("img", {
63908
64102
  key: 0,
@@ -63910,30 +64104,33 @@ function render$5L(_ctx, _cache, $props, $setup, $data, $options) {
63910
64104
  alt: "",
63911
64105
  class: "cn-bookmarks-card__favicon",
63912
64106
  onError: $event => ($options.onFaviconError(bookmark))
63913
- }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_18$N))
64107
+ }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_20$z))
63914
64108
  : (vue$1.openBlock(), vue$1.createBlock(_component_Bookmark, {
63915
64109
  key: 1,
63916
64110
  size: 14
63917
64111
  }))
63918
64112
  ]),
63919
- vue$1.createElementVNode("div", _hoisted_19$F, [
63920
- vue$1.createElementVNode("a", {
63921
- href: bookmark.url,
63922
- target: "_blank",
63923
- rel: "noopener noreferrer",
63924
- class: "cn-bookmarks-card__title"
63925
- }, vue$1.toDisplayString($options.bookmarkTitle(bookmark)), 9 /* TEXT, PROPS */, _hoisted_20$z)
64113
+ vue$1.createElementVNode("div", _hoisted_21$x, [
64114
+ ($options.hasSafeUrl(bookmark))
64115
+ ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
64116
+ key: 0,
64117
+ href: bookmark.url,
64118
+ target: "_blank",
64119
+ rel: "noopener noreferrer",
64120
+ class: "cn-bookmarks-card__title"
64121
+ }, vue$1.toDisplayString($options.bookmarkTitle(bookmark)), 9 /* TEXT, PROPS */, _hoisted_22$v))
64122
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_23$n, vue$1.toDisplayString($options.bookmarkTitle(bookmark)), 1 /* TEXT */))
63926
64123
  ])
63927
64124
  ]))
63928
64125
  }), 128 /* KEYED_FRAGMENT */))
63929
64126
  ])),
63930
64127
  ($data.bookmarks.length > $data.COMPACT_LIMIT)
63931
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_21$x, [
64128
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_24$l, [
63932
64129
  vue$1.createElementVNode("a", {
63933
64130
  href: $props.bookmarksAppUrl,
63934
64131
  target: "_blank",
63935
64132
  rel: "noopener noreferrer"
63936
- }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_22$v)
64133
+ }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_25$h)
63937
64134
  ]))
63938
64135
  : vue$1.createCommentVNode("v-if", true)
63939
64136
  ], 64 /* STABLE_FRAGMENT */))
@@ -64643,6 +64840,23 @@ var script$5I = {
64643
64840
  return safeHref(bookmark.url)
64644
64841
  },
64645
64842
 
64843
+ /**
64844
+ * Whether the bookmark's URL passed `safeHref`, so its row is a link.
64845
+ *
64846
+ * @param {object} bookmark The bookmark row.
64847
+ * @return {boolean}
64848
+ */
64849
+ hasSafeUrl(bookmark) {
64850
+ return this.bookmarkHref(bookmark) !== '#'
64851
+ },
64852
+
64853
+ // NcListItem always renders an anchor; one without a safe URL must not follow `#`.
64854
+ onBookmarkClick(bookmark, event) {
64855
+ if (!this.hasSafeUrl(bookmark)) {
64856
+ event?.preventDefault?.();
64857
+ }
64858
+ },
64859
+
64646
64860
  bookmarkTags(bookmark) {
64647
64861
  const tags = bookmark.tags;
64648
64862
  if (!Array.isArray(tags)) {
@@ -64785,8 +64999,7 @@ function render$5I(_ctx, _cache, $props, $setup, $data, $options) {
64785
64999
  vue$1.createVNode(_component_NcButton, {
64786
65000
  variant: "primary",
64787
65001
  href: $props.bookmarksAppUrl,
64788
- target: "_blank",
64789
- rel: "noopener noreferrer"
65002
+ target: "_blank"
64790
65003
  }, {
64791
65004
  icon: vue$1.withCtx(() => [
64792
65005
  vue$1.createVNode(_component_Bookmark, { size: 20 })
@@ -64826,8 +65039,9 @@ function render$5I(_ctx, _cache, $props, $setup, $data, $options) {
64826
65039
  name: $options.bookmarkTitle(bookmark),
64827
65040
  bold: true,
64828
65041
  href: $options.bookmarkHref(bookmark),
64829
- target: "_blank",
64830
- forceDisplayActions: true
65042
+ target: $options.hasSafeUrl(bookmark) ? '_blank' : undefined,
65043
+ forceDisplayActions: true,
65044
+ onClick: $event => ($options.onBookmarkClick(bookmark, $event))
64831
65045
  }, {
64832
65046
  icon: vue$1.withCtx(() => [
64833
65047
  vue$1.createElementVNode("span", _hoisted_10$2a, [
@@ -64865,20 +65079,22 @@ function render$5I(_ctx, _cache, $props, $setup, $data, $options) {
64865
65079
  : vue$1.createCommentVNode("v-if", true)
64866
65080
  ]),
64867
65081
  actions: vue$1.withCtx(() => [
64868
- vue$1.createVNode(_component_NcActionLink, {
64869
- closeAfterClick: true,
64870
- href: $options.bookmarkHref(bookmark),
64871
- target: "_blank",
64872
- rel: "noopener noreferrer"
64873
- }, {
64874
- icon: vue$1.withCtx(() => [
64875
- vue$1.createVNode(_component_OpenInNew, { size: 20 })
64876
- ]),
64877
- default: vue$1.withCtx(() => [
64878
- vue$1.createTextVNode(" " + vue$1.toDisplayString($options.t('nextcloud-vue', 'Open bookmark')), 1 /* TEXT */)
64879
- ]),
64880
- _: 1 /* STABLE */
64881
- }, 8 /* PROPS */, ["href"]),
65082
+ ($options.hasSafeUrl(bookmark))
65083
+ ? (vue$1.openBlock(), vue$1.createBlock(_component_NcActionLink, {
65084
+ key: 0,
65085
+ closeAfterClick: true,
65086
+ href: $options.bookmarkHref(bookmark),
65087
+ target: "_blank"
65088
+ }, {
65089
+ icon: vue$1.withCtx(() => [
65090
+ vue$1.createVNode(_component_OpenInNew, { size: 20 })
65091
+ ]),
65092
+ default: vue$1.withCtx(() => [
65093
+ vue$1.createTextVNode(" " + vue$1.toDisplayString($options.t('nextcloud-vue', 'Open bookmark')), 1 /* TEXT */)
65094
+ ]),
65095
+ _: 1 /* STABLE */
65096
+ }, 8 /* PROPS */, ["href"]))
65097
+ : vue$1.createCommentVNode("v-if", true),
64882
65098
  vue$1.createVNode(_component_NcActionButton, {
64883
65099
  closeAfterClick: true,
64884
65100
  onClick: $event => ($options.unlinkBookmark(bookmark))
@@ -64893,7 +65109,7 @@ function render$5I(_ctx, _cache, $props, $setup, $data, $options) {
64893
65109
  }, 8 /* PROPS */, ["onClick"])
64894
65110
  ]),
64895
65111
  _: 2 /* DYNAMIC */
64896
- }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["name", "href"]))
65112
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["name", "href", "target", "onClick"]))
64897
65113
  }), 128 /* KEYED_FRAGMENT */))
64898
65114
  ])
64899
65115
  ])),
@@ -66968,8 +67184,9 @@ var script$5D = {
66968
67184
  return typeof emoji === 'string' ? emoji.trim() : ''
66969
67185
  },
66970
67186
 
67187
+ // A provider URL is used only when it is a safe scheme; else the app link.
66971
67188
  pageUrl(page) {
66972
- if (typeof page.url === 'string' && page.url !== '') {
67189
+ if (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {
66973
67190
  return page.url
66974
67191
  }
66975
67192
  const d = this.dataOf(page);
@@ -67922,8 +68139,9 @@ var script$5A = {
67922
68139
  return text
67923
68140
  },
67924
68141
 
68142
+ // A provider URL is used only when it is a safe scheme; else the app link.
67925
68143
  pageUrl(page) {
67926
- if (typeof page.url === 'string' && page.url !== '') {
68144
+ if (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {
67927
68145
  return page.url
67928
68146
  }
67929
68147
  const d = this.dataOf(page);
@@ -68205,8 +68423,7 @@ function render$5A(_ctx, _cache, $props, $setup, $data, $options) {
68205
68423
  vue$1.createVNode(_component_NcButton, {
68206
68424
  variant: "primary",
68207
68425
  href: $props.collectivesAppUrl,
68208
- target: "_blank",
68209
- rel: "noopener noreferrer"
68426
+ target: "_blank"
68210
68427
  }, {
68211
68428
  icon: vue$1.withCtx(() => [
68212
68429
  vue$1.createVNode(_component_BookOpenPageVariant, { size: 20 })
@@ -68267,8 +68484,7 @@ function render$5A(_ctx, _cache, $props, $setup, $data, $options) {
68267
68484
  vue$1.createVNode(_component_NcActionLink, {
68268
68485
  closeAfterClick: true,
68269
68486
  href: $options.pageUrl(page),
68270
- target: "_blank",
68271
- rel: "noopener noreferrer"
68487
+ target: "_blank"
68272
68488
  }, {
68273
68489
  icon: vue$1.withCtx(() => [
68274
68490
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -70733,7 +70949,7 @@ var script$5t = {
70733
70949
  },
70734
70950
 
70735
70951
  rowUrl(row) {
70736
- if (row.url) {
70952
+ if (row.url && safeHref(row.url) !== '#') {
70737
70953
  return row.url
70738
70954
  }
70739
70955
  const projectId = row.projectId ?? row.project_id ?? row.data?.projectid ?? row.data?.project_id ?? null;
@@ -71606,7 +71822,7 @@ var script$5q = {
71606
71822
  },
71607
71823
 
71608
71824
  rowUrl(row) {
71609
- if (row.url) {
71825
+ if (row.url && safeHref(row.url) !== '#') {
71610
71826
  return row.url
71611
71827
  }
71612
71828
  const projectId = row.projectId ?? row.project_id ?? row.data?.projectid ?? row.data?.project_id ?? null;
@@ -71880,8 +72096,7 @@ function render$5q(_ctx, _cache, $props, $setup, $data, $options) {
71880
72096
  vue$1.createVNode(_component_NcButton, {
71881
72097
  variant: "primary",
71882
72098
  href: $props.cospendAppUrl,
71883
- target: "_blank",
71884
- rel: "noopener noreferrer"
72099
+ target: "_blank"
71885
72100
  }, {
71886
72101
  icon: vue$1.withCtx(() => [
71887
72102
  vue$1.createVNode(_component_CurrencyEur, { size: 20 })
@@ -72219,7 +72434,7 @@ var script$5p = {
72219
72434
  },
72220
72435
 
72221
72436
  cardUrl(card) {
72222
- if (card.url) {
72437
+ if (card.url && safeHref(card.url) !== '#') {
72223
72438
  return card.url
72224
72439
  }
72225
72440
  const boardId = card.boardId ?? card.board?.id ?? '';
@@ -73282,7 +73497,7 @@ var script$5m = {
73282
73497
  },
73283
73498
 
73284
73499
  cardUrl(card) {
73285
- if (card.url) {
73500
+ if (card.url && safeHref(card.url) !== '#') {
73286
73501
  return card.url
73287
73502
  }
73288
73503
  const boardId = card.boardId ?? card.board?.id ?? '';
@@ -73601,8 +73816,7 @@ function render$5m(_ctx, _cache, $props, $setup, $data, $options) {
73601
73816
  vue$1.createVNode(_component_NcButton, {
73602
73817
  variant: "primary",
73603
73818
  href: $props.deckAppUrl,
73604
- target: "_blank",
73605
- rel: "noopener noreferrer"
73819
+ target: "_blank"
73606
73820
  }, {
73607
73821
  icon: vue$1.withCtx(() => [
73608
73822
  vue$1.createVNode(_component_ViewColumnOutline, { size: 20 })
@@ -74988,8 +75202,7 @@ function render$5j(_ctx, _cache, $props, $setup, $data, $options) {
74988
75202
  vue$1.createVNode(_component_NcButton, {
74989
75203
  variant: "primary",
74990
75204
  href: $options.composeUrl,
74991
- target: "_blank",
74992
- rel: "noopener noreferrer"
75205
+ target: "_blank"
74993
75206
  }, {
74994
75207
  icon: vue$1.withCtx(() => [
74995
75208
  vue$1.createVNode(_component_EmailEditOutline, { size: 18 })
@@ -79140,6 +79353,8 @@ var script$5e = {
79140
79353
  methods: {
79141
79354
  t: l10n.translate,
79142
79355
 
79356
+ preventMiddleClickAutoscroll,
79357
+
79143
79358
  /**
79144
79359
  * Hold the file input element from its function ref.
79145
79360
  *
@@ -79984,10 +80199,10 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
79984
80199
  return (vue$1.openBlock(), vue$1.createElementBlock("div", {
79985
80200
  class: vue$1.normalizeClass(["cn-files-browser", { 'cn-files-browser--dragging': $data.dragging }]),
79986
80201
  "data-testid": "cn-files-browser",
79987
- onDragenter: _cache[14] || (_cache[14] = vue$1.withModifiers($event => ($data.dragging = true), ["prevent"])),
79988
- onDragover: _cache[15] || (_cache[15] = vue$1.withModifiers($event => ($data.dragging = true), ["prevent"])),
79989
- onDragleave: _cache[16] || (_cache[16] = vue$1.withModifiers($event => ($data.dragging = false), ["prevent"])),
79990
- onDrop: _cache[17] || (_cache[17] = vue$1.withModifiers((...args) => ($options.onDrop && $options.onDrop(...args)), ["prevent"]))
80202
+ onDragenter: _cache[16] || (_cache[16] = vue$1.withModifiers($event => ($data.dragging = true), ["prevent"])),
80203
+ onDragover: _cache[17] || (_cache[17] = vue$1.withModifiers($event => ($data.dragging = true), ["prevent"])),
80204
+ onDragleave: _cache[18] || (_cache[18] = vue$1.withModifiers($event => ($data.dragging = false), ["prevent"])),
80205
+ onDrop: _cache[19] || (_cache[19] = vue$1.withModifiers((...args) => ($options.onDrop && $options.onDrop(...args)), ["prevent"]))
79991
80206
  }, [
79992
80207
  vue$1.createElementVNode("div", _hoisted_1$53, [
79993
80208
  vue$1.createVNode(_component_NcBreadcrumbs, { class: "cn-files-browser__crumbs" }, {
@@ -80221,6 +80436,7 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80221
80436
  "data-testid": "cn-files-browser-row",
80222
80437
  "data-name": node.basename,
80223
80438
  onClick: $event => ($options.onRowClick(node, $event)),
80439
+ onMousedown: _cache[3] || (_cache[3] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
80224
80440
  onAuxclick: $event => ($options.onRowAuxClick(node, $event))
80225
80441
  }, [
80226
80442
  vue$1.createElementVNode("td", _hoisted_14$1b, [
@@ -80348,7 +80564,6 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80348
80564
  key: 2,
80349
80565
  href: $options.permalink(node),
80350
80566
  target: "_blank",
80351
- rel: "noopener noreferrer",
80352
80567
  closeAfterClick: true
80353
80568
  }, {
80354
80569
  icon: vue$1.withCtx(() => [
@@ -80373,6 +80588,7 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80373
80588
  "data-testid": "cn-files-browser-linked-row",
80374
80589
  "data-name": item.name,
80375
80590
  onClick: $event => ($options.openLinked(item)),
80591
+ onMousedown: _cache[7] || (_cache[7] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
80376
80592
  onAuxclick: $event => ($options.onLinkedAuxClick(item, $event))
80377
80593
  }, [
80378
80594
  vue$1.createElementVNode("td", _hoisted_20$t, [
@@ -80403,7 +80619,7 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80403
80619
  key: 0,
80404
80620
  href: item.noteHref,
80405
80621
  class: "cn-files-browser__note-link",
80406
- onClick: _cache[3] || (_cache[3] = vue$1.withModifiers(() => {}, ["stop"]))
80622
+ onClick: _cache[4] || (_cache[4] = vue$1.withModifiers(() => {}, ["stop"]))
80407
80623
  }, vue$1.toDisplayString(item.note), 9 /* TEXT, PROPS */, _hoisted_24$i))
80408
80624
  : (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 1 }, [
80409
80625
  vue$1.createTextVNode(vue$1.toDisplayString(item.note), 1 /* TEXT */)
@@ -80426,8 +80642,8 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80426
80642
  }), 128 /* KEYED_FRAGMENT */)),
80427
80643
  vue$1.createElementVNode("td", {
80428
80644
  class: "cn-files-browser__col-actions",
80429
- onClick: _cache[4] || (_cache[4] = vue$1.withModifiers(() => {}, ["stop"])),
80430
- onAuxclick: _cache[5] || (_cache[5] = vue$1.withModifiers(() => {}, ["stop"]))
80645
+ onClick: _cache[5] || (_cache[5] = vue$1.withModifiers(() => {}, ["stop"])),
80646
+ onAuxclick: _cache[6] || (_cache[6] = vue$1.withModifiers(() => {}, ["stop"]))
80431
80647
  }, [
80432
80648
  vue$1.createVNode(_component_NcActions, {
80433
80649
  forceMenu: true,
@@ -80439,7 +80655,6 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80439
80655
  key: 0,
80440
80656
  href: item.href,
80441
80657
  target: "_blank",
80442
- rel: "noopener noreferrer",
80443
80658
  closeAfterClick: true,
80444
80659
  "data-testid": "cn-files-browser-linked-open"
80445
80660
  }, {
@@ -80483,11 +80698,11 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80483
80698
  name: $props.renameLabel,
80484
80699
  size: "small",
80485
80700
  "data-testid": "cn-files-browser-rename",
80486
- onClosing: _cache[9] || (_cache[9] = $event => ($data.renaming = null))
80701
+ onClosing: _cache[11] || (_cache[11] = $event => ($data.renaming = null))
80487
80702
  }, {
80488
80703
  actions: vue$1.withCtx(() => [
80489
80704
  vue$1.createVNode(_component_NcButton, {
80490
- onClick: _cache[8] || (_cache[8] = $event => ($data.renaming = null))
80705
+ onClick: _cache[10] || (_cache[10] = $event => ($data.renaming = null))
80491
80706
  }, {
80492
80707
  default: vue$1.withCtx(() => [
80493
80708
  vue$1.createTextVNode(vue$1.toDisplayString($options.t('nextcloud-vue', 'Cancel')), 1 /* TEXT */)
@@ -80509,11 +80724,11 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80509
80724
  default: vue$1.withCtx(() => [
80510
80725
  vue$1.createElementVNode("form", {
80511
80726
  class: "cn-files-browser__new-folder",
80512
- onSubmit: _cache[7] || (_cache[7] = vue$1.withModifiers((...args) => ($options.rename && $options.rename(...args)), ["prevent"]))
80727
+ onSubmit: _cache[9] || (_cache[9] = vue$1.withModifiers((...args) => ($options.rename && $options.rename(...args)), ["prevent"]))
80513
80728
  }, [
80514
80729
  vue$1.createVNode(_component_NcTextField, {
80515
80730
  modelValue: $data.renameName,
80516
- "onUpdate:modelValue": _cache[6] || (_cache[6] = $event => (($data.renameName) = $event)),
80731
+ "onUpdate:modelValue": _cache[8] || (_cache[8] = $event => (($data.renameName) = $event)),
80517
80732
  label: $options.t('nextcloud-vue', 'New name'),
80518
80733
  error: $data.renameError !== '',
80519
80734
  helperText: $data.renameError,
@@ -80530,11 +80745,11 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80530
80745
  name: $props.newFolderLabel,
80531
80746
  size: "small",
80532
80747
  "data-testid": "cn-files-browser-new-folder",
80533
- onClosing: _cache[13] || (_cache[13] = $event => ($data.newFolderOpen = false))
80748
+ onClosing: _cache[15] || (_cache[15] = $event => ($data.newFolderOpen = false))
80534
80749
  }, {
80535
80750
  actions: vue$1.withCtx(() => [
80536
80751
  vue$1.createVNode(_component_NcButton, {
80537
- onClick: _cache[12] || (_cache[12] = $event => ($data.newFolderOpen = false))
80752
+ onClick: _cache[14] || (_cache[14] = $event => ($data.newFolderOpen = false))
80538
80753
  }, {
80539
80754
  default: vue$1.withCtx(() => [
80540
80755
  vue$1.createTextVNode(vue$1.toDisplayString($options.t('nextcloud-vue', 'Cancel')), 1 /* TEXT */)
@@ -80556,11 +80771,11 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80556
80771
  default: vue$1.withCtx(() => [
80557
80772
  vue$1.createElementVNode("form", {
80558
80773
  class: "cn-files-browser__new-folder",
80559
- onSubmit: _cache[11] || (_cache[11] = vue$1.withModifiers((...args) => ($options.createFolder && $options.createFolder(...args)), ["prevent"]))
80774
+ onSubmit: _cache[13] || (_cache[13] = vue$1.withModifiers((...args) => ($options.createFolder && $options.createFolder(...args)), ["prevent"]))
80560
80775
  }, [
80561
80776
  vue$1.createVNode(_component_NcTextField, {
80562
80777
  modelValue: $data.newFolderName,
80563
- "onUpdate:modelValue": _cache[10] || (_cache[10] = $event => (($data.newFolderName) = $event)),
80778
+ "onUpdate:modelValue": _cache[12] || (_cache[12] = $event => (($data.newFolderName) = $event)),
80564
80779
  label: $options.t('nextcloud-vue', 'Folder name'),
80565
80780
  error: $data.newFolderError !== '',
80566
80781
  helperText: $data.newFolderError,
@@ -81378,7 +81593,6 @@ function render$5d(_ctx, _cache, $props, $setup, $data, $options) {
81378
81593
  key: 2,
81379
81594
  href: $options.showInFilesUrl(file),
81380
81595
  target: "_blank",
81381
- rel: "noopener noreferrer",
81382
81596
  closeAfterClick: true
81383
81597
  }, {
81384
81598
  icon: vue$1.withCtx(() => [
@@ -81623,7 +81837,7 @@ var script$5c = {
81623
81837
  },
81624
81838
 
81625
81839
  opUrl(op) {
81626
- return op.url || this.flowSettingsUrl
81840
+ return op.url && safeHref(op.url) !== '#' ? op.url : this.flowSettingsUrl
81627
81841
  },
81628
81842
 
81629
81843
  shortClass(className) {
@@ -82290,7 +82504,7 @@ var script$5a = {
82290
82504
  },
82291
82505
 
82292
82506
  opUrl(op) {
82293
- return op.url || this.flowSettingsUrl
82507
+ return op.url && safeHref(op.url) !== '#' ? op.url : this.flowSettingsUrl
82294
82508
  },
82295
82509
 
82296
82510
  shortClass(className) {
@@ -82576,8 +82790,7 @@ function render$5a(_ctx, _cache, $props, $setup, $data, $options) {
82576
82790
  vue$1.createVNode(_component_NcButton, {
82577
82791
  variant: "primary",
82578
82792
  href: $props.flowSettingsUrl,
82579
- target: "_blank",
82580
- rel: "noopener noreferrer"
82793
+ target: "_blank"
82581
82794
  }, {
82582
82795
  icon: vue$1.withCtx(() => [
82583
82796
  vue$1.createVNode(_component_SitemapOutline, { size: 20 })
@@ -82929,8 +83142,9 @@ var script$59 = {
82929
83142
  return form.title || form.id || l10n.translate('nextcloud-vue', 'Untitled form')
82930
83143
  },
82931
83144
 
83145
+ // A provider URL is used only when it is a safe scheme; else the app link.
82932
83146
  formUrl(form) {
82933
- if (form.url) {
83147
+ if (form.url && safeHref(form.url) !== '#') {
82934
83148
  return form.url
82935
83149
  }
82936
83150
  if (form.hash) {
@@ -83970,8 +84184,9 @@ var script$56 = {
83970
84184
  return form.description || ''
83971
84185
  },
83972
84186
 
84187
+ // A provider URL is used only when it is a safe scheme; else the app link.
83973
84188
  formUrl(form) {
83974
- if (form.url) {
84189
+ if (form.url && safeHref(form.url) !== '#') {
83975
84190
  return form.url
83976
84191
  }
83977
84192
  if (form.hash) {
@@ -84280,8 +84495,7 @@ function render$56(_ctx, _cache, $props, $setup, $data, $options) {
84280
84495
  vue$1.createVNode(_component_NcButton, {
84281
84496
  variant: "primary",
84282
84497
  href: $props.formsAppUrl,
84283
- target: "_blank",
84284
- rel: "noopener noreferrer"
84498
+ target: "_blank"
84285
84499
  }, {
84286
84500
  icon: vue$1.withCtx(() => [
84287
84501
  vue$1.createVNode(_component_ClipboardText, { size: 20 })
@@ -84331,8 +84545,7 @@ function render$56(_ctx, _cache, $props, $setup, $data, $options) {
84331
84545
  vue$1.createVNode(_component_NcActionLink, {
84332
84546
  closeAfterClick: true,
84333
84547
  href: $options.formUrl(form),
84334
- target: "_blank",
84335
- rel: "noopener noreferrer"
84548
+ target: "_blank"
84336
84549
  }, {
84337
84550
  icon: vue$1.withCtx(() => [
84338
84551
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -84632,8 +84845,9 @@ var script$55 = {
84632
84845
  return `${lat.toFixed(5)}, ${lng.toFixed(5)}`
84633
84846
  },
84634
84847
 
84848
+ // A provider URL is used only when it is a safe scheme; else the app link.
84635
84849
  pointUrl(point) {
84636
- if (typeof point.url === 'string' && point.url !== '') {
84850
+ if (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {
84637
84851
  return point.url
84638
84852
  }
84639
84853
  const lat = this.pointLat(point);
@@ -85549,8 +85763,9 @@ var script$52 = {
85549
85763
  return `${lat.toFixed(5)}, ${lng.toFixed(5)}`
85550
85764
  },
85551
85765
 
85766
+ // A provider URL is used only when it is a safe scheme; else the app link.
85552
85767
  pointUrl(point) {
85553
- if (typeof point.url === 'string' && point.url !== '') {
85768
+ if (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {
85554
85769
  return point.url
85555
85770
  }
85556
85771
  if (this.pointHasCoords(point)) {
@@ -85781,8 +85996,7 @@ function render$52(_ctx, _cache, $props, $setup, $data, $options) {
85781
85996
  vue$1.createVNode(_component_NcButton, {
85782
85997
  variant: "primary",
85783
85998
  href: $props.mapsAppUrl,
85784
- target: "_blank",
85785
- rel: "noopener noreferrer"
85999
+ target: "_blank"
85786
86000
  }, {
85787
86001
  icon: vue$1.withCtx(() => [
85788
86002
  vue$1.createVNode(_component_MapMarker, { size: 20 })
@@ -85851,8 +86065,7 @@ function render$52(_ctx, _cache, $props, $setup, $data, $options) {
85851
86065
  vue$1.createVNode(_component_NcActionLink, {
85852
86066
  closeAfterClick: true,
85853
86067
  href: $options.pointUrl(point),
85854
- target: "_blank",
85855
- rel: "noopener noreferrer"
86068
+ target: "_blank"
85856
86069
  }, {
85857
86070
  icon: vue$1.withCtx(() => [
85858
86071
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -88020,7 +88233,8 @@ var script$4Z = {
88020
88233
  },
88021
88234
 
88022
88235
  wpUrl(wp) {
88023
- return wp.url ?? wp._links?.self?.href ?? this.openprojectAppUrl
88236
+ const url = wp.url ?? wp._links?.self?.href;
88237
+ return url && safeHref(url) !== '#' ? url : this.openprojectAppUrl
88024
88238
  },
88025
88239
 
88026
88240
  wpStatus(wp) {
@@ -89250,7 +89464,8 @@ var script$4W = {
89250
89464
  },
89251
89465
 
89252
89466
  wpUrl(wp) {
89253
- return wp.url ?? wp._links?.self?.href ?? this.openprojectAppUrl
89467
+ const url = wp.url ?? wp._links?.self?.href;
89468
+ return url && safeHref(url) !== '#' ? url : this.openprojectAppUrl
89254
89469
  },
89255
89470
 
89256
89471
  wpStatus(wp) {
@@ -89516,8 +89731,7 @@ function render$4W(_ctx, _cache, $props, $setup, $data, $options) {
89516
89731
  vue$1.createVNode(_component_NcButton, {
89517
89732
  variant: "primary",
89518
89733
  href: $props.openconnectorUrl,
89519
- target: "_blank",
89520
- rel: "noopener noreferrer"
89734
+ target: "_blank"
89521
89735
  }, {
89522
89736
  icon: vue$1.withCtx(() => [
89523
89737
  vue$1.createVNode(_component_CogOutline, { size: 20 })
@@ -89540,8 +89754,7 @@ function render$4W(_ctx, _cache, $props, $setup, $data, $options) {
89540
89754
  vue$1.createVNode(_component_NcButton, {
89541
89755
  variant: "secondary",
89542
89756
  href: $props.openprojectAppUrl,
89543
- target: "_blank",
89544
- rel: "noopener noreferrer"
89757
+ target: "_blank"
89545
89758
  }, {
89546
89759
  icon: vue$1.withCtx(() => [
89547
89760
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -89897,7 +90110,7 @@ var script$4V = {
89897
90110
  },
89898
90111
 
89899
90112
  albumUrl(album) {
89900
- if (album && album.url) {
90113
+ if (album && album.url && safeHref(album.url) !== '#') {
89901
90114
  return album.url
89902
90115
  }
89903
90116
  const name = this.albumName(album);
@@ -90680,7 +90893,7 @@ var script$4S = {
90680
90893
  },
90681
90894
 
90682
90895
  albumUrl(album) {
90683
- if (album && album.url) {
90896
+ if (album && album.url && safeHref(album.url) !== '#') {
90684
90897
  return album.url
90685
90898
  }
90686
90899
  const id = this.albumKey(album);
@@ -90943,8 +91156,7 @@ function render$4S(_ctx, _cache, $props, $setup, $data, $options) {
90943
91156
  vue$1.createVNode(_component_NcButton, {
90944
91157
  variant: "primary",
90945
91158
  href: $props.photosAppUrl,
90946
- target: "_blank",
90947
- rel: "noopener noreferrer"
91159
+ target: "_blank"
90948
91160
  }, {
90949
91161
  icon: vue$1.withCtx(() => [
90950
91162
  vue$1.createVNode(_component_ImageIcon, { size: 20 })
@@ -91213,7 +91425,7 @@ var script$4R = {
91213
91425
  },
91214
91426
 
91215
91427
  pollUrl(poll) {
91216
- if (poll.url) {
91428
+ if (poll.url && safeHref(poll.url) !== '#') {
91217
91429
  return poll.url
91218
91430
  }
91219
91431
  const id = poll.id ?? '';
@@ -92289,7 +92501,7 @@ var script$4O = {
92289
92501
  },
92290
92502
 
92291
92503
  pollUrl(poll) {
92292
- if (poll.url) {
92504
+ if (poll.url && safeHref(poll.url) !== '#') {
92293
92505
  return poll.url
92294
92506
  }
92295
92507
  const id = this.pollKey(poll);
@@ -92535,8 +92747,7 @@ function render$4O(_ctx, _cache, $props, $setup, $data, $options) {
92535
92747
  vue$1.createVNode(_component_NcButton, {
92536
92748
  variant: "primary",
92537
92749
  href: $props.pollsAppUrl,
92538
- target: "_blank",
92539
- rel: "noopener noreferrer"
92750
+ target: "_blank"
92540
92751
  }, {
92541
92752
  icon: vue$1.withCtx(() => [
92542
92753
  vue$1.createVNode(_component_Poll, { size: 20 })
@@ -93979,8 +94190,7 @@ function render$4L(_ctx, _cache, $props, $setup, $data, $options) {
93979
94190
  vue$1.createVNode(_component_NcButton, {
93980
94191
  variant: "primary",
93981
94192
  href: $props.filesAppUrl,
93982
- target: "_blank",
93983
- rel: "noopener noreferrer"
94193
+ target: "_blank"
93984
94194
  }, {
93985
94195
  icon: vue$1.withCtx(() => [
93986
94196
  vue$1.createVNode(_component_FolderOutline, { size: 20 })
@@ -94066,8 +94276,7 @@ function render$4L(_ctx, _cache, $props, $setup, $data, $options) {
94066
94276
  vue$1.createVNode(_component_NcActionLink, {
94067
94277
  closeAfterClick: true,
94068
94278
  href: $props.filesAppUrl,
94069
- target: "_blank",
94070
- rel: "noopener noreferrer"
94279
+ target: "_blank"
94071
94280
  }, {
94072
94281
  icon: vue$1.withCtx(() => [
94073
94282
  vue$1.createVNode(_component_FolderOutline, { size: 20 })
@@ -94107,8 +94316,7 @@ function render$4L(_ctx, _cache, $props, $setup, $data, $options) {
94107
94316
  vue$1.createVNode(_component_NcButton, {
94108
94317
  variant: "tertiary",
94109
94318
  href: $props.filesAppUrl,
94110
- target: "_blank",
94111
- rel: "noopener noreferrer"
94319
+ target: "_blank"
94112
94320
  }, {
94113
94321
  icon: vue$1.withCtx(() => [
94114
94322
  vue$1.createVNode(_component_FolderOutline, { size: 18 })
@@ -94745,8 +94953,9 @@ var script$4I = {
94745
94953
  return stripMarker(raw) || String(this.roomKey(room))
94746
94954
  },
94747
94955
 
94956
+ // A provider URL is used only when it is a safe scheme; else the app link.
94748
94957
  roomUrl(room) {
94749
- if (room.url) {
94958
+ if (room.url && safeHref(room.url) !== '#') {
94750
94959
  return room.url
94751
94960
  }
94752
94961
  const token = room.token ?? room.id ?? '';
@@ -95478,8 +95687,9 @@ var script$4F = {
95478
95687
  return stripMarker(raw) || String(this.roomKey(room))
95479
95688
  },
95480
95689
 
95690
+ // A provider URL is used only when it is a safe scheme; else the app link.
95481
95691
  roomUrl(room) {
95482
- if (room.url) {
95692
+ if (room.url && safeHref(room.url) !== '#') {
95483
95693
  return room.url
95484
95694
  }
95485
95695
  const token = room.roomToken ?? room.token ?? room.id ?? '';
@@ -95816,8 +96026,7 @@ function render$4F(_ctx, _cache, $props, $setup, $data, $options) {
95816
96026
  vue$1.createVNode(_component_NcButton, {
95817
96027
  variant: "primary",
95818
96028
  href: $props.talkAppUrl,
95819
- target: "_blank",
95820
- rel: "noopener noreferrer"
96029
+ target: "_blank"
95821
96030
  }, {
95822
96031
  icon: vue$1.withCtx(() => [
95823
96032
  vue$1.createVNode(_component_ChatOutline, { size: 20 })
@@ -95854,8 +96063,7 @@ function render$4F(_ctx, _cache, $props, $setup, $data, $options) {
95854
96063
  vue$1.createVNode(_component_NcActionLink, {
95855
96064
  closeAfterClick: true,
95856
96065
  href: $options.roomUrl(room),
95857
- target: "_blank",
95858
- rel: "noopener noreferrer"
96066
+ target: "_blank"
95859
96067
  }, {
95860
96068
  icon: vue$1.withCtx(() => [
95861
96069
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -97099,7 +97307,7 @@ var script$4C = {
97099
97307
  },
97100
97308
 
97101
97309
  rowUrl(row) {
97102
- if (row.url) {
97310
+ if (row.url && safeHref(row.url) !== '#') {
97103
97311
  return row.url
97104
97312
  }
97105
97313
  const kind = this.rowKind(row);
@@ -97967,7 +98175,7 @@ var script$4z = {
97967
98175
  },
97968
98176
 
97969
98177
  rowUrl(row) {
97970
- if (row.url) {
98178
+ if (row.url && safeHref(row.url) !== '#') {
97971
98179
  return row.url
97972
98180
  }
97973
98181
  const kind = this.rowKind(row);
@@ -98285,8 +98493,7 @@ function render$4z(_ctx, _cache, $props, $setup, $data, $options) {
98285
98493
  vue$1.createVNode(_component_NcButton, {
98286
98494
  variant: "primary",
98287
98495
  href: $props.timeTrackerAppUrl,
98288
- target: "_blank",
98289
- rel: "noopener noreferrer"
98496
+ target: "_blank"
98290
98497
  }, {
98291
98498
  icon: vue$1.withCtx(() => [
98292
98499
  vue$1.createVNode(_component_Clock, { size: 20 })
@@ -99214,8 +99421,10 @@ var script$4x = {
99214
99421
  return String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))
99215
99422
  },
99216
99423
 
99424
+ // An unsafe scheme is treated like a missing URL.
99217
99425
  pageUrl(page) {
99218
- return page.url ?? ''
99426
+ const url = page.url ?? '';
99427
+ return url && safeHref(url) !== '#' ? url : ''
99219
99428
  },
99220
99429
 
99221
99430
  breadcrumbLabel(page) {
@@ -100290,15 +100499,17 @@ var script$4u = {
100290
100499
 
100291
100500
  /**
100292
100501
  * External XWiki deep-link for the page. Empty string when the
100293
- * provider didn't surface a `url`, so the row renders as a plain
100294
- * (non-anchored) NcListItem rather than a dead link.
100502
+ * provider didn't surface a `url`, or surfaced an unsafe scheme, so
100503
+ * the row renders as a plain (non-anchored) NcListItem rather than a
100504
+ * dead link.
100295
100505
  *
100296
100506
  * @param {object} page Provider row.
100297
100507
  *
100298
100508
  * @return {string} Absolute XWiki URL or ''.
100299
100509
  */
100300
100510
  pageHref(page) {
100301
- return String(page.url ?? '')
100511
+ const url = String(page.url ?? '');
100512
+ return url && safeHref(url) !== '#' ? url : ''
100302
100513
  },
100303
100514
 
100304
100515
  breadcrumbLabel(page) {
@@ -100481,14 +100692,13 @@ function render$4u(_ctx, _cache, $props, $setup, $data, $options) {
100481
100692
  class: "cn-xwiki-tab__banner-cta",
100482
100693
  href: $options.banner.ctaHref || undefined,
100483
100694
  target: $options.banner.ctaHref ? '_blank' : undefined,
100484
- rel: $options.banner.ctaHref ? 'noopener noreferrer' : undefined,
100485
100695
  onClick: $options.banner.ctaHandler
100486
100696
  }, {
100487
100697
  default: vue$1.withCtx(() => [
100488
100698
  vue$1.createTextVNode(vue$1.toDisplayString($options.banner.ctaLabel), 1 /* TEXT */)
100489
100699
  ]),
100490
100700
  _: 1 /* STABLE */
100491
- }, 8 /* PROPS */, ["href", "target", "rel", "onClick"]))
100701
+ }, 8 /* PROPS */, ["href", "target", "onClick"]))
100492
100702
  : vue$1.createCommentVNode("v-if", true)
100493
100703
  ], 2 /* CLASS */))
100494
100704
  : vue$1.createCommentVNode("v-if", true),
@@ -100571,8 +100781,7 @@ function render$4u(_ctx, _cache, $props, $setup, $data, $options) {
100571
100781
  class: "cn-xwiki-tab__open",
100572
100782
  closeAfterClick: true,
100573
100783
  href: $options.pageHref(page),
100574
- target: "_blank",
100575
- rel: "noopener noreferrer"
100784
+ target: "_blank"
100576
100785
  }, {
100577
100786
  icon: vue$1.withCtx(() => [
100578
100787
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -105493,16 +105702,20 @@ var script$4q = {
105493
105702
  /**
105494
105703
  * A link entry was clicked: route a plain in-app click, leave the rest to
105495
105704
  * the browser, and emit `action` as a button would. The `handler` is not
105496
- * called, since navigating is what the link already does.
105705
+ * called, since navigating is what the link already does. A modified
105706
+ * click opens a new tab, so nothing is emitted in this one.
105497
105707
  *
105498
105708
  * @param {object} action The action definition.
105499
105709
  * @param {object} link The resolved link.
105500
105710
  * @param {MouseEvent} event The click event.
105501
105711
  */
105502
105712
  onLinkAction(action, link, event) {
105713
+ if (isModifiedClick(event)) {
105714
+ return
105715
+ }
105503
105716
  followItemActionLink(event, link, this.$router);
105504
105717
  /**
105505
- * @event action User picked an entry. Payload: the action's label and the row. A button entry has already run its `handler`; a link entry navigates instead.
105718
+ * @event action User picked an entry. Payload: the action's label and the row. A button entry has already run its `handler`; a link entry navigates instead, and a modified (new-tab) click on a link emits nothing.
105506
105719
  * @type {{ action: string, row: object|null }}
105507
105720
  */
105508
105721
  this.$emit('action', { action: action.label, row: this.row });
@@ -105751,7 +105964,7 @@ var script$4p = {
105751
105964
  },
105752
105965
  },
105753
105966
 
105754
- emits: ['created', 'row-click', 'view-all', 'files-dropped'],
105967
+ emits: ['created', 'row-click', 'row-aux-click', 'view-all', 'files-dropped'],
105755
105968
 
105756
105969
  data() {
105757
105970
  return {
@@ -106744,29 +106957,60 @@ var script$4p = {
106744
106957
 
106745
106958
  /**
106746
106959
  * Navigate to a configured detail route on row click (when `rowRoute`
106747
- * is set and a router is available); a ctrl/cmd/shift or middle click
106748
- * opens it in a new tab.
106960
+ * is set and a router is available); a ctrl/cmd/shift click opens it
106961
+ * in a new tab.
106749
106962
  *
106750
106963
  * @param {object} row The clicked object row.
106751
- * @param {MouseEvent} [event] The originating click/auxclick event.
106964
+ * @param {MouseEvent} [event] The originating click event.
106752
106965
  * @return {void}
106753
106966
  */
106754
106967
  onRowClick(row, event) {
106755
- const route = this.content.rowRoute;
106756
- const id = row && (row.id || (row['@self'] && row['@self'].id));
106757
- if (route && id && this.$router) {
106758
- markNewTabHandled(event, openRowTarget(event, { name: route, params: { id } }, this.$router));
106759
- }
106968
+ this.openRowRoute(row, event);
106760
106969
  /**
106761
106970
  * @event row-click Emitted with the clicked object (for hosts that
106762
- * want to handle navigation themselves), on a click or middle click.
106763
- * Payload: `(row, event)`, the second being the native click/auxclick
106764
- * event.
106971
+ * want to handle navigation themselves). Payload: `(row, event)`, the
106972
+ * second being the native click event. A middle click emits
106973
+ * `row-aux-click` instead.
106765
106974
  * @type {object}
106766
106975
  */
106767
106976
  this.$emit('row-click', row, event);
106768
106977
  },
106769
106978
 
106979
+ /**
106980
+ * A row middle click: opens the configured detail route in a new tab
106981
+ * and emits `row-aux-click`, not `row-click`.
106982
+ *
106983
+ * @param {object} row The clicked object row.
106984
+ * @param {MouseEvent} event The originating auxclick event.
106985
+ * @return {void}
106986
+ */
106987
+ onRowAuxClick(row, event) {
106988
+ this.openRowRoute(row, event);
106989
+ /**
106990
+ * @event row-aux-click Emitted with the middle-clicked object, for
106991
+ * opening it in a new tab. Payload: `(row, event)`, the second being
106992
+ * the native auxclick event.
106993
+ * @type {object}
106994
+ */
106995
+ this.$emit('row-aux-click', row, event);
106996
+ },
106997
+
106998
+ /**
106999
+ * Open `content.rowRoute` for a row: in place, or in a new tab on a
107000
+ * ctrl/cmd/shift or middle click.
107001
+ *
107002
+ * @param {object} row The clicked object row.
107003
+ * @param {MouseEvent} [event] The originating event.
107004
+ * @return {void}
107005
+ */
107006
+ openRowRoute(row, event) {
107007
+ const route = this.content.rowRoute;
107008
+ const id = row && (row.id || (row['@self'] && row['@self'].id));
107009
+ if (route && id && this.$router) {
107010
+ markNewTabHandled(event, openRowTarget(event, { name: route, params: { id } }, this.$router));
107011
+ }
107012
+ },
107013
+
106770
107014
  /**
106771
107015
  * Dispatch one declared row action. A `handler` action gets the row
106772
107016
  * appended as its last argument, the same convention CnWidgetObjectTable
@@ -106795,8 +107039,7 @@ var script$4p = {
106795
107039
  * @return {object} `{ href, linkTarget }`, `{ to }`, or `{}`.
106796
107040
  */
106797
107041
  rowActionLink(action) {
106798
- const target = typeof action.target === 'string' ? action.target : '';
106799
- if (/[@{]/.test(target)) {
107042
+ if (hasActionTargetTokens(action.target)) {
106800
107043
  return {}
106801
107044
  }
106802
107045
  const link = actionLink(action, { router: this.$router || null });
@@ -107219,6 +107462,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
107219
107462
  sortOrder: $data.localSort.dir || 'asc',
107220
107463
  borderless: "",
107221
107464
  onRowClick: $options.onRowClick,
107465
+ onRowAuxClick: $options.onRowAuxClick,
107222
107466
  onSelect: $options.onSelect,
107223
107467
  onSort: $options.onSort
107224
107468
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
@@ -107234,7 +107478,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
107234
107478
  key: "0"
107235
107479
  }
107236
107480
  : undefined
107237
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["columns", "rows", "loading", "emptyText", "selectable", "selectedIds", "sortKey", "sortOrder", "onRowClick", "onSelect", "onSort"])
107481
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["columns", "rows", "loading", "emptyText", "selectable", "selectedIds", "sortKey", "sortOrder", "onRowClick", "onRowAuxClick", "onSelect", "onSort"])
107238
107482
  ]))
107239
107483
  }), 128 /* KEYED_FRAGMENT */))
107240
107484
  ]))
@@ -107250,6 +107494,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
107250
107494
  sortOrder: $data.localSort.dir || 'asc',
107251
107495
  borderless: "",
107252
107496
  onRowClick: $options.onRowClick,
107497
+ onRowAuxClick: $options.onRowAuxClick,
107253
107498
  onSelect: $options.onSelect,
107254
107499
  onSort: $options.onSort
107255
107500
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
@@ -107265,7 +107510,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
107265
107510
  key: "0"
107266
107511
  }
107267
107512
  : undefined
107268
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["columns", "rows", "loading", "emptyText", "selectable", "selectedIds", "sortKey", "sortOrder", "onRowClick", "onSelect", "onSort"])
107513
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["columns", "rows", "loading", "emptyText", "selectable", "selectedIds", "sortKey", "sortOrder", "onRowClick", "onRowAuxClick", "onSelect", "onSort"])
107269
107514
  ])),
107270
107515
  ($options.showPager)
107271
107516
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnPagination, {
@@ -108772,7 +109017,6 @@ function render$4n(_ctx, _cache, $props, $setup, $data, $options) {
108772
109017
  key: 1,
108773
109018
  href: $options.resolvedRequestFeatureUrl,
108774
109019
  target: "_blank",
108775
- rel: "noopener noreferrer",
108776
109020
  "data-testid": `${$props.testidBase}-action-request-feature`,
108777
109021
  closeAfterClick: true,
108778
109022
  onClick: $options.onRequestFeatureClick
@@ -108806,7 +109050,6 @@ function render$4n(_ctx, _cache, $props, $setup, $data, $options) {
108806
109050
  key: 3,
108807
109051
  href: $options.resolvedReportBugUrl,
108808
109052
  target: "_blank",
108809
- rel: "noopener noreferrer",
108810
109053
  "data-testid": `${$props.testidBase}-action-report-bug`,
108811
109054
  closeAfterClick: true
108812
109055
  }, {
@@ -108824,7 +109067,6 @@ function render$4n(_ctx, _cache, $props, $setup, $data, $options) {
108824
109067
  key: 4,
108825
109068
  href: $options.resolvedDocumentationUrl,
108826
109069
  target: "_blank",
108827
- rel: "noopener noreferrer",
108828
109070
  "data-testid": `${$props.testidBase}-action-documentation`,
108829
109071
  closeAfterClick: true
108830
109072
  }, {
@@ -121958,8 +122200,7 @@ function render$41(_ctx, _cache, $props, $setup, $data, $options) {
121958
122200
  vue$1.createVNode(_component_NcButton, {
121959
122201
  variant: "primary",
121960
122202
  href: $options.docsUrl,
121961
- target: "_blank",
121962
- rel: "noopener"
122203
+ target: "_blank"
121963
122204
  }, {
121964
122205
  icon: vue$1.withCtx(() => [
121965
122206
  vue$1.createVNode(_component_OpenInNew, { size: 18 })
@@ -123842,7 +124083,7 @@ var script$3Z = {
123842
124083
  },
123843
124084
  },
123844
124085
 
123845
- emits: ['click', 'select'],
124086
+ emits: ['click', 'select', 'aux-click'],
123846
124087
 
123847
124088
  setup() {
123848
124089
  // Tell a deliberate card click apart from a text-selection drag.
@@ -123968,14 +124209,28 @@ var script$3Z = {
123968
124209
  return
123969
124210
  }
123970
124211
  /**
123971
- * @event click Emitted when a non-selectable (or `clickToView`) card is clicked or middle-clicked. Payload: `(object, event)` — the card's object and the native click/auxclick event, for opening it in a new tab on a ctrl/cmd/shift or middle click. Selectable cards emit `select`; they also emit `click` (deprecated) when a `click` listener is present, so migrate selectable consumers to `@select`.
124212
+ * @event click Emitted when a non-selectable (or `clickToView`) card is clicked. Payload: `(object, event)` — the card's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead. Selectable cards emit `select`; they also emit `click` (deprecated) when a `click` listener is present, so migrate selectable consumers to `@select`.
123972
124213
  * @type {object} The card's object.
123973
124214
  */
123974
124215
  this.$emit('click', this.object, event);
123975
124216
  },
123976
124217
 
123977
124218
  /**
123978
- * Card-body middle click: emits `click` like a navigating click.
124219
+ * Card mousedown: record the press for the drag guard, and on a card a
124220
+ * middle click opens, keep the browser from starting autoscroll.
124221
+ *
124222
+ * @param {MouseEvent} event The mousedown event.
124223
+ */
124224
+ onCardMouseDown(event) {
124225
+ this.onPointerDown(event);
124226
+ if (!this.selectable || this.clickToView) {
124227
+ preventMiddleClickAutoscroll(event);
124228
+ }
124229
+ },
124230
+
124231
+ /**
124232
+ * Card-body middle click: emits `aux-click`, not `click`, so an existing
124233
+ * `click` listener that navigates never moves the current tab away.
123979
124234
  * Ignored on a select-on-click card, on nested controls and on drags.
123980
124235
  *
123981
124236
  * @param {MouseEvent} event The auxclick event.
@@ -123987,7 +124242,11 @@ var script$3Z = {
123987
124242
  if (this.selectable && !this.clickToView) {
123988
124243
  return
123989
124244
  }
123990
- this.$emit('click', this.object, event);
124245
+ /**
124246
+ * @event aux-click Emitted when a non-selectable (or `clickToView`) card is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the card's object and the native auxclick event.
124247
+ * @type {object} The card's object.
124248
+ */
124249
+ this.$emit('aux-click', this.object, event);
123991
124250
  },
123992
124251
  },
123993
124252
  };
@@ -124018,7 +124277,7 @@ function render$3Z(_ctx, _cache, $props, $setup, $data, $options) {
124018
124277
 
124019
124278
  return (vue$1.openBlock(), vue$1.createElementBlock("div", {
124020
124279
  class: vue$1.normalizeClass(["cn-object-card", { 'cn-object-card--selected': $props.selected }]),
124021
- onMousedown: _cache[5] || (_cache[5] = (...args) => (_ctx.onPointerDown && _ctx.onPointerDown(...args))),
124280
+ onMousedown: _cache[5] || (_cache[5] = (...args) => ($options.onCardMouseDown && $options.onCardMouseDown(...args))),
124022
124281
  onClick: _cache[6] || (_cache[6] = $event => ($options.onCardClick($event))),
124023
124282
  onAuxclick: _cache[7] || (_cache[7] = $event => ($options.onCardAuxClick($event)))
124024
124283
  }, [
@@ -136734,10 +136993,9 @@ var script$3w = {
136734
136993
  * @return {void}
136735
136994
  */
136736
136995
  dispatchAction({ actionType, url, value }) {
136996
+ // An `external` entry with a URL is a real link (see linkAttrsFor);
136997
+ // one without a URL has nothing to open.
136737
136998
  switch (actionType) {
136738
- case ACTION_TYPES$1.EXTERNAL:
136739
- this.handleExternal(url);
136740
- break
136741
136999
  case ACTION_TYPES$1.INTERNAL:
136742
137000
  this.$emit('internal-action', url);
136743
137001
  break
@@ -136748,20 +137006,6 @@ var script$3w = {
136748
137006
  break
136749
137007
  }
136750
137008
  },
136751
-
136752
- /**
136753
- * Open an external URL in a new tab; `noopener,noreferrer` prevents
136754
- * the opened page reaching back via `window.opener`.
136755
- *
136756
- * @param {string} url the URL to open.
136757
- * @return {void}
136758
- */
136759
- handleExternal(url) {
136760
- if (typeof url !== 'string' || url === '') {
136761
- return
136762
- }
136763
- window.open(url, '_blank', 'noopener,noreferrer');
136764
- },
136765
137009
  },
136766
137010
  };
136767
137011
 
@@ -146317,18 +146561,14 @@ var script$3b = {
146317
146561
  },
146318
146562
 
146319
146563
  /**
146320
- * Handle a row click — descend into folders, open files in the Files app.
146564
+ * Handle a folder row click by descending into it. A file row is a
146565
+ * real link to the Files app and never reaches this.
146321
146566
  *
146322
- * @param {object} item the clicked item.
146567
+ * @param {object} item the clicked folder item.
146323
146568
  * @return {void}
146324
146569
  */
146325
146570
  onItemClick(item) {
146326
- if (item.isFolder) {
146327
- const next = this.joinPath(this.currentSubPath, item.name);
146328
- this.navigateTo(next);
146329
- } else {
146330
- this.openFileInFilesApp(item.fileId);
146331
- }
146571
+ this.navigateTo(this.joinPath(this.currentSubPath, item.name));
146332
146572
  },
146333
146573
 
146334
146574
  /**
@@ -146371,19 +146611,6 @@ var script$3b = {
146371
146611
  return `${trimmedBase}/${trimmedName}`
146372
146612
  },
146373
146613
 
146374
- /**
146375
- * Deep-link a file into the Nextcloud Files app in a new tab.
146376
- *
146377
- * @param {number|string} fileId the Nextcloud file id.
146378
- * @return {void}
146379
- */
146380
- openFileInFilesApp(fileId) {
146381
- const url = this.fileUrl(fileId);
146382
- if (url) {
146383
- window.open(url, '_blank', 'noopener,noreferrer');
146384
- }
146385
- },
146386
-
146387
146614
  /**
146388
146615
  * The Files-app permalink for a file.
146389
146616
  *
@@ -148470,7 +148697,8 @@ const DEBOUNCE_MS = 200;
148470
148697
  * Data origin (decoupling seam): all data flows through a consumer-supplied
148471
148698
  * `dataSource` prop OR the `cnSpendAnalyticsSource` injection — an object
148472
148699
  * exposing `fetchSummary(args)`, `fetchVendorCommitments(args)`,
148473
- * `fetchNarrative(args)`, and optionally `resolveDeepLink(app, kind, id)`. The
148700
+ * `fetchNarrative(args)`, and optionally `resolveDeepLink(app, kind, id)`
148701
+ * (pure and synchronous: it runs for every row on every render). The
148474
148702
  * renderer imports NO financeq / procest / launchpad service module and never
148475
148703
  * calls axios itself; the consuming app (typically over GraphQL) owns the
148476
148704
  * transport. The `requires.graphql` hint lives only in the registry entry, not
@@ -148507,8 +148735,9 @@ var script$37 = {
148507
148735
  * Consumer-supplied data source overriding the
148508
148736
  * `cnSpendAnalyticsSource` injection. Must expose `fetchSummary`,
148509
148737
  * `fetchVendorCommitments`, and `fetchNarrative`; may expose
148510
- * `resolveDeepLink`. When `null` the injection (then the empty state)
148511
- * is used.
148738
+ * `resolveDeepLink`, which must be pure and synchronous, since it is
148739
+ * called for every row on every render. When `null` the injection
148740
+ * (then the empty state) is used.
148512
148741
  *
148513
148742
  * @type {object|null}
148514
148743
  */
@@ -154248,19 +154477,6 @@ var script$2$ = {
154248
154477
  },
154249
154478
 
154250
154479
  computed: {
154251
- /**
154252
- * Each run's link href by uuid, resolved once per render.
154253
- *
154254
- * @return {{[uuid: string]: string}}
154255
- */
154256
- runHrefs() {
154257
- const out = {};
154258
- for (const run of [...this.rows, ...this.completedRows]) {
154259
- out[run.uuid] = this.runHref(run);
154260
- }
154261
- return out
154262
- },
154263
-
154264
154480
  /**
154265
154481
  * Effective translate function: the explicit prop, then the injected
154266
154482
  * host one, then `@nextcloud/l10n` under the library's own app id.
@@ -154720,15 +154936,15 @@ function render$2$(_ctx, _cache, $props, $setup, $data, $options) {
154720
154936
  ($options.rows.length === 0)
154721
154937
  ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_6$1L, vue$1.toDisplayString($options.emptyLabel), 1 /* TEXT */))
154722
154938
  : (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_7$1x, [
154723
- (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.rows, (run) => {
154939
+ (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.rows, (run, index) => {
154724
154940
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
154725
- key: run.uuid,
154941
+ key: run.uuid || `row-${index}`,
154726
154942
  class: vue$1.normalizeClass(["cn-flow-runs-widget__row", { 'cn-flow-runs-widget__row--linked': $options.isLinked }]),
154727
154943
  "data-status": run.status
154728
154944
  }, [
154729
- (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.runHrefs[run.uuid] ? 'a' : 'div'), {
154945
+ (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.runHref(run) ? 'a' : 'div'), {
154730
154946
  class: "cn-flow-runs-widget__row-content",
154731
- href: $options.runHrefs[run.uuid] || undefined,
154947
+ href: $options.runHref(run) || undefined,
154732
154948
  onClick: $event => ($options.onRowClick($event, run))
154733
154949
  }, {
154734
154950
  default: vue$1.withCtx(() => [
@@ -154756,15 +154972,15 @@ function render$2$(_ctx, _cache, $props, $setup, $data, $options) {
154756
154972
  ($setup.completedError)
154757
154973
  ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_16$u, vue$1.toDisplayString($options.tr('Could not load the run history')), 1 /* TEXT */))
154758
154974
  : (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_17$s, [
154759
- (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.completedRows, (run) => {
154975
+ (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.completedRows, (run, index) => {
154760
154976
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
154761
- key: run.uuid,
154977
+ key: run.uuid || `completed-${index}`,
154762
154978
  class: vue$1.normalizeClass(["cn-flow-runs-widget__row cn-flow-runs-widget__row--terminal", { 'cn-flow-runs-widget__row--linked': $options.isLinked }]),
154763
154979
  "data-status": run.status
154764
154980
  }, [
154765
- (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.runHrefs[run.uuid] ? 'a' : 'div'), {
154981
+ (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.runHref(run) ? 'a' : 'div'), {
154766
154982
  class: "cn-flow-runs-widget__row-content",
154767
- href: $options.runHrefs[run.uuid] || undefined,
154983
+ href: $options.runHref(run) || undefined,
154768
154984
  onClick: $event => ($options.onRowClick($event, run))
154769
154985
  }, {
154770
154986
  default: vue$1.withCtx(() => [
@@ -158749,6 +158965,8 @@ var script$2Z = {
158749
158965
  },
158750
158966
 
158751
158967
  methods: {
158968
+ preventMiddleClickAutoscroll,
158969
+
158752
158970
  /**
158753
158971
  * Start (or restart) the refetch interval, unless polling is off.
158754
158972
  *
@@ -159057,6 +159275,7 @@ function render$2Z(_ctx, _cache, $props, $setup, $data, $options) {
159057
159275
  class: "cn-tasks-widget__row",
159058
159276
  "data-state": task.state,
159059
159277
  onClick: $event => ($options.onRowClick(task, $event)),
159278
+ onMousedown: _cache[1] || (_cache[1] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
159060
159279
  onAuxclick: $event => ($options.onRowAuxClick(task, $event))
159061
159280
  }, [
159062
159281
  vue$1.createElementVNode("span", _hoisted_8$1l, [
@@ -161549,7 +161768,6 @@ function render$2T(_ctx, _cache, $props, $setup, $data, $options) {
161549
161768
  variant: "tertiary",
161550
161769
  href: $options.savedHref,
161551
161770
  target: "_blank",
161552
- rel: "noopener noreferrer",
161553
161771
  "data-testid": "cn-interaction-form-open"
161554
161772
  }, {
161555
161773
  icon: vue$1.withCtx(() => [
@@ -169718,8 +169936,7 @@ function render$2C(_ctx, _cache, $props, $setup, $data, $options) {
169718
169936
  ? (vue$1.openBlock(), vue$1.createBlock(_component_NcButton, {
169719
169937
  key: 2,
169720
169938
  href: $options.helpUrl,
169721
- target: "_blank",
169722
- rel: "noopener noreferrer"
169939
+ target: "_blank"
169723
169940
  }, {
169724
169941
  icon: vue$1.withCtx(() => [
169725
169942
  vue$1.createVNode(_component_HelpCircleOutline, { size: 20 })
@@ -170216,7 +170433,7 @@ var script$2B = {
170216
170433
  },
170217
170434
  },
170218
170435
 
170219
- emits: ['card-click', 'moved', 'refused', 'stale'],
170436
+ emits: ['card-click', 'card-aux-click', 'moved', 'refused', 'stale'],
170220
170437
 
170221
170438
  data() {
170222
170439
  return {
@@ -170296,6 +170513,8 @@ var script$2B = {
170296
170513
  methods: {
170297
170514
  t: l10n.translate,
170298
170515
 
170516
+ preventMiddleClickAutoscroll,
170517
+
170299
170518
  /**
170300
170519
  * Open one card. The pointer and the keyboard both come through here,
170301
170520
  * so a reader on Enter reaches the same record as a reader on click.
@@ -170306,13 +170525,15 @@ var script$2B = {
170306
170525
  */
170307
170526
  openCard(card, event) {
170308
170527
  /**
170309
- * @event card-click Emitted when a reader opens a card, by click, Enter or middle click. Payload: `(card, event)` — the card row and the native event, so the host can open it in a new tab on a ctrl/cmd/shift or middle click.
170528
+ * @event card-click Emitted when a reader opens a card, by click or Enter. Payload: `(card, event)` — the card row and the native event, so the host can open it in a new tab on a ctrl/cmd/shift click. A middle click emits `card-aux-click` instead.
170310
170529
  */
170311
170530
  this.$emit('card-click', card, event);
170312
170531
  },
170313
170532
 
170314
170533
  /**
170315
- * Middle click on a card's open button: open it like a click would.
170534
+ * Middle click on a card's open button: emits `card-aux-click`, not
170535
+ * `card-click`, so an existing listener that navigates never moves the
170536
+ * current tab away.
170316
170537
  *
170317
170538
  * @param {object} card The card the reader picked.
170318
170539
  * @param {MouseEvent} event The auxclick event.
@@ -170320,7 +170541,10 @@ var script$2B = {
170320
170541
  */
170321
170542
  onCardAuxClick(card, event) {
170322
170543
  if (isRowMiddleClick(event)) {
170323
- this.openCard(card, event);
170544
+ /**
170545
+ * @event card-aux-click Emitted when a reader middle-clicks a card, for opening it in a new tab (see `openRowTarget`). Payload: `(card, event)` — the card row and the native auxclick event.
170546
+ */
170547
+ this.$emit('card-aux-click', card, event);
170324
170548
  }
170325
170549
  },
170326
170550
 
@@ -170545,7 +170769,7 @@ function render$2B(_ctx, _cache, $props, $setup, $data, $options) {
170545
170769
  role: "listitem",
170546
170770
  "data-testid": "cn-board-column",
170547
170771
  "data-column": column.key,
170548
- onDragover: _cache[0] || (_cache[0] = vue$1.withModifiers(() => {}, ["prevent"])),
170772
+ onDragover: _cache[1] || (_cache[1] = vue$1.withModifiers(() => {}, ["prevent"])),
170549
170773
  onDrop: $event => ($options.onDrop(column, $event))
170550
170774
  }, [
170551
170775
  vue$1.createElementVNode("h3", _hoisted_7$1j, [
@@ -170582,6 +170806,7 @@ function render$2B(_ctx, _cache, $props, $setup, $data, $options) {
170582
170806
  "data-card-id": $options.cardKey(card),
170583
170807
  "aria-label": $options.cardLabel(card, column),
170584
170808
  onClick: $event => ($options.openCard(card, $event)),
170809
+ onMousedown: _cache[0] || (_cache[0] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
170585
170810
  onAuxclick: $event => ($options.onCardAuxClick(card, $event))
170586
170811
  }, vue$1.toDisplayString($options.openLabel), 41 /* TEXT, PROPS, NEED_HYDRATION */, _hoisted_11$J),
170587
170812
  ($options.canMove)
@@ -170720,7 +170945,7 @@ var script$2A = {
170720
170945
  },
170721
170946
  },
170722
170947
 
170723
- emits: ['click', 'select'],
170948
+ emits: ['click', 'select', 'aux-click'],
170724
170949
 
170725
170950
  computed: {
170726
170951
  /**
@@ -170755,6 +170980,14 @@ var script$2A = {
170755
170980
  const listeners = { select: () => this.toggleSelect(object) };
170756
170981
  if (!this.selectable || this.clickToView) {
170757
170982
  listeners.click = (_card, event) => this.$emit('click', object, event);
170983
+ // A middle click, kept off `click` so a navigating listener stays put.
170984
+ listeners['aux-click'] = (_card, event) => {
170985
+ /**
170986
+ * @event aux-click Emitted when a navigating card is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the card's object and the native auxclick event.
170987
+ * @type {object} The card's object.
170988
+ */
170989
+ this.$emit('aux-click', object, event);
170990
+ };
170758
170991
  }
170759
170992
  return listeners
170760
170993
  },
@@ -171060,7 +171293,7 @@ var script$2z = {
171060
171293
  },
171061
171294
  },
171062
171295
 
171063
- emits: ['row-click'],
171296
+ emits: ['row-click', 'row-aux-click'],
171064
171297
 
171065
171298
  computed: {
171066
171299
  /** @return {object} The layout. */
@@ -171103,23 +171336,27 @@ var script$2z = {
171103
171336
  methods: {
171104
171337
  t: l10n.translate,
171105
171338
 
171339
+ preventMiddleClickAutoscroll,
171340
+
171106
171341
  /**
171107
171342
  * Open one record. Both the bar on the axis and the label of an
171108
171343
  * undated row come through here, so the two paths cannot drift.
171109
171344
  *
171110
171345
  * @param {object} row The record the reader picked.
171111
- * @param {MouseEvent} [event] The click or middle-click event.
171346
+ * @param {MouseEvent} [event] The click event.
171112
171347
  * @return {void} Nothing.
171113
171348
  */
171114
171349
  openRow(row, event) {
171115
171350
  /**
171116
- * @event row-click Emitted when a reader opens a record, from its bar on the axis or from the label of an undated row, on a click or a middle click. Payload: `(row, event)` — the row and the native click/auxclick event, so the host can open it in a new tab on a ctrl/cmd/shift or middle click.
171351
+ * @event row-click Emitted when a reader opens a record, from its bar on the axis or from the label of an undated row. Payload: `(row, event)` — the row and the native click event, so the host can open it in a new tab on a ctrl/cmd/shift click. A middle click emits `row-aux-click` instead.
171117
171352
  */
171118
171353
  this.$emit('row-click', row, event);
171119
171354
  },
171120
171355
 
171121
171356
  /**
171122
- * Middle click on a bar: open the record like a click would.
171357
+ * Middle click on a bar or an undated row's label: emits
171358
+ * `row-aux-click`, not `row-click`, so an existing listener that
171359
+ * navigates never moves the current tab away.
171123
171360
  *
171124
171361
  * @param {object} row The record the reader picked.
171125
171362
  * @param {MouseEvent} event The auxclick event.
@@ -171127,7 +171364,10 @@ var script$2z = {
171127
171364
  */
171128
171365
  onAuxClick(row, event) {
171129
171366
  if (isRowMiddleClick(event)) {
171130
- this.openRow(row, event);
171367
+ /**
171368
+ * @event row-aux-click Emitted when a reader middle-clicks a record's bar or undated-row label, for opening it in a new tab (see `openRowTarget`). Payload: `(row, event)` — the row and the native auxclick event.
171369
+ */
171370
+ this.$emit('row-aux-click', row, event);
171131
171371
  }
171132
171372
  },
171133
171373
 
@@ -171292,6 +171532,7 @@ function render$2z(_ctx, _cache, $props, $setup, $data, $options) {
171292
171532
  style: vue$1.normalizeStyle($options.barStyle(bar)),
171293
171533
  "aria-label": $options.barLabel(bar),
171294
171534
  onClick: $event => ($options.openRow(bar.row, $event)),
171535
+ onMousedown: _cache[0] || (_cache[0] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
171295
171536
  onAuxclick: $event => ($options.onAuxClick(bar.row, $event))
171296
171537
  }, vue$1.toDisplayString($options.barText(bar)), 45 /* TEXT, STYLE, PROPS, NEED_HYDRATION */, _hoisted_5$1D))
171297
171538
  }), 128 /* KEYED_FRAGMENT */))
@@ -171310,6 +171551,7 @@ function render$2z(_ctx, _cache, $props, $setup, $data, $options) {
171310
171551
  "data-row-id": $options.rowKeyOf(row),
171311
171552
  "aria-label": $options.unplannedLabelFor(row),
171312
171553
  onClick: $event => ($options.openRow(row, $event)),
171554
+ onMousedown: _cache[1] || (_cache[1] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
171313
171555
  onAuxclick: $event => ($options.onAuxClick(row, $event))
171314
171556
  }, vue$1.toDisplayString($options.nameOf(row)), 41 /* TEXT, PROPS, NEED_HYDRATION */, _hoisted_8$18))
171315
171557
  }), 128 /* KEYED_FRAGMENT */))
@@ -171398,7 +171640,7 @@ var script$2y = {
171398
171640
  // again from `$emit('click', object)` — twice per click, with different
171399
171641
  // payloads. Declaring the names here removes them from `$attrs`, which is
171400
171642
  // also what stops VTU v2 recording the native DOM event into `emitted()`.
171401
- emits: ['select', 'click'],
171643
+ emits: ['select', 'click', 'aux-click'],
171402
171644
 
171403
171645
  setup() {
171404
171646
  // Tell a deliberate row click apart from a text-selection drag.
@@ -171489,15 +171731,29 @@ var script$2y = {
171489
171731
  return
171490
171732
  }
171491
171733
  /**
171492
- * @event click Emitted when a non-selectable row is clicked or middle-clicked (navigation). Payload: `(object, event)` — the row's object and the native click/auxclick event, for opening it in a new tab on a ctrl/cmd/shift or middle click.
171734
+ * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.
171493
171735
  * @type {object} The row's object.
171494
171736
  */
171495
171737
  this.$emit('click', this.object, event);
171496
171738
  },
171497
171739
 
171498
171740
  /**
171499
- * Row-body middle click: emits `click` like a click on a
171500
- * non-selectable row.
171741
+ * Row mousedown: record the press for the drag guard, and on a
171742
+ * non-selectable row keep a middle press from starting autoscroll.
171743
+ *
171744
+ * @param {MouseEvent} event The mousedown event.
171745
+ */
171746
+ onRowMouseDown(event) {
171747
+ this.onPointerDown(event);
171748
+ if (!this.selectable) {
171749
+ preventMiddleClickAutoscroll(event);
171750
+ }
171751
+ },
171752
+
171753
+ /**
171754
+ * Row-body middle click on a non-selectable row: emits `aux-click`, not
171755
+ * `click`, so an existing `click` listener that navigates never moves
171756
+ * the current tab away.
171501
171757
  *
171502
171758
  * @param {MouseEvent} event The auxclick event.
171503
171759
  */
@@ -171505,7 +171761,11 @@ var script$2y = {
171505
171761
  if (this.selectable || !isRowMiddleClick(event)) {
171506
171762
  return
171507
171763
  }
171508
- this.$emit('click', this.object, event);
171764
+ /**
171765
+ * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.
171766
+ * @type {object} The row's object.
171767
+ */
171768
+ this.$emit('aux-click', this.object, event);
171509
171769
  },
171510
171770
  },
171511
171771
  };
@@ -171533,7 +171793,7 @@ function render$2y(_ctx, _cache, $props, $setup, $data, $options) {
171533
171793
 
171534
171794
  return (vue$1.openBlock(), vue$1.createElementBlock("div", {
171535
171795
  class: vue$1.normalizeClass(["cn-object-row", { 'cn-object-row--selected': $props.selected }]),
171536
- onMousedown: _cache[5] || (_cache[5] = (...args) => (_ctx.onPointerDown && _ctx.onPointerDown(...args))),
171796
+ onMousedown: _cache[5] || (_cache[5] = (...args) => ($options.onRowMouseDown && $options.onRowMouseDown(...args))),
171537
171797
  onClick: _cache[6] || (_cache[6] = $event => ($options.onRowClick($event))),
171538
171798
  onAuxclick: _cache[7] || (_cache[7] = $event => ($options.onRowAuxClick($event)))
171539
171799
  }, [
@@ -171705,7 +171965,7 @@ var script$2x = {
171705
171965
  },
171706
171966
  },
171707
171967
 
171708
- emits: ['click', 'select'],
171968
+ emits: ['click', 'select', 'aux-click'],
171709
171969
 
171710
171970
  computed: {
171711
171971
  /**
@@ -171736,6 +171996,7 @@ var script$2x = {
171736
171996
  const listeners = { select: () => this.toggleSelect(object) };
171737
171997
  if (!this.selectable) {
171738
171998
  listeners.click = (_row, event) => this.emitClick(object, event);
171999
+ listeners['aux-click'] = (_row, event) => this.emitAuxClick(object, event);
171739
172000
  }
171740
172001
  return listeners
171741
172002
  },
@@ -171744,16 +172005,31 @@ var script$2x = {
171744
172005
  * Emit `click` for a non-selectable row (navigation).
171745
172006
  *
171746
172007
  * @param {object} object The clicked row's object.
171747
- * @param {MouseEvent} [event] The native click/auxclick event.
172008
+ * @param {MouseEvent} [event] The native click event.
171748
172009
  */
171749
172010
  emitClick(object, event) {
171750
172011
  /**
171751
- * @event click Emitted when a non-selectable row is clicked or middle-clicked (navigation). Payload: `(object, event)` — the row's object and the native click/auxclick event, for opening it in a new tab on a ctrl/cmd/shift or middle click.
172012
+ * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.
171752
172013
  * @type {object} The clicked row's object.
171753
172014
  */
171754
172015
  this.$emit('click', object, event);
171755
172016
  },
171756
172017
 
172018
+ /**
172019
+ * Emit `aux-click` for a middle click on a non-selectable row, kept off
172020
+ * `click` so a navigating listener never moves the current tab away.
172021
+ *
172022
+ * @param {object} object The clicked row's object.
172023
+ * @param {MouseEvent} event The native auxclick event.
172024
+ */
172025
+ emitAuxClick(object, event) {
172026
+ /**
172027
+ * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.
172028
+ * @type {object} The clicked row's object.
172029
+ */
172030
+ this.$emit('aux-click', object, event);
172031
+ },
172032
+
171757
172033
  toggleSelect(object) {
171758
172034
  const id = object[this.rowKey];
171759
172035
  const newIds = this.isSelected(object)
@@ -183711,13 +183987,17 @@ var script$2q = {
183711
183987
  /**
183712
183988
  * A link entry was clicked: route a plain in-app click, leave the rest to
183713
183989
  * the browser, and emit `action` as a button would. The `handler` is not
183714
- * called, since navigating is what the link already does.
183990
+ * called, since navigating is what the link already does. A modified
183991
+ * click opens a new tab, so nothing is emitted in this one.
183715
183992
  *
183716
183993
  * @param {object} action The action descriptor.
183717
183994
  * @param {object} link The resolved link.
183718
183995
  * @param {MouseEvent} event The click event.
183719
183996
  */
183720
183997
  onLinkAction(action, link, event) {
183998
+ if (isModifiedClick(event)) {
183999
+ return
184000
+ }
183721
184001
  followItemActionLink(event, link, this.$router);
183722
184002
  this.$emit('action', { action: action.label, row: this.targetItem });
183723
184003
  },
@@ -226880,12 +227160,17 @@ var script$1P = {
226880
227160
 
226881
227161
  /**
226882
227162
  * Add button click: a plain click on an in-app link routes in place,
226883
- * anything else on a link is the browser's. Emits `add` either way.
227163
+ * anything else on a link is the browser's. Emits `add`, except for a
227164
+ * modified click on a link, which opens in a new tab: a host `@add`
227165
+ * would otherwise run in the tab the user is leaving.
226884
227166
  *
226885
227167
  * @param {MouseEvent} event The click event.
226886
227168
  */
226887
227169
  onAddClick(event) {
226888
227170
  if (this.addLink) {
227171
+ if (isModifiedClick(event)) {
227172
+ return
227173
+ }
226889
227174
  followItemActionLink(event, this.addLink, this.$router);
226890
227175
  }
226891
227176
  this.$emit('add');
@@ -226893,13 +227178,17 @@ var script$1P = {
226893
227178
 
226894
227179
  /**
226895
227180
  * A header link entry was clicked: route a plain in-app click and emit
226896
- * `header-action` as the button would.
227181
+ * `header-action` as the button would. A modified click is the
227182
+ * browser's alone (a new tab), so nothing is emitted for it.
226897
227183
  *
226898
227184
  * @param {object} entry The header action.
226899
227185
  * @param {object} link The resolved link.
226900
227186
  * @param {MouseEvent} event The click event.
226901
227187
  */
226902
227188
  onHeaderLinkClick(entry, link, event) {
227189
+ if (isModifiedClick(event)) {
227190
+ return
227191
+ }
226903
227192
  followItemActionLink(event, link, this.$router);
226904
227193
  this.$emit('header-action', { action: entry.id, id: entry.id });
226905
227194
  },
@@ -227192,8 +227481,7 @@ function render$1P(_ctx, _cache, $props, $setup, $data, $options) {
227192
227481
  ? (vue$1.openBlock(), vue$1.createBlock(_component_NcActionLink, {
227193
227482
  key: 0,
227194
227483
  href: $props.documentationUrl,
227195
- target: "_blank",
227196
- rel: "noopener noreferrer"
227484
+ target: "_blank"
227197
227485
  }, {
227198
227486
  icon: vue$1.withCtx(() => [
227199
227487
  vue$1.createVNode(_component_BookOpenVariantOutline, { size: 20 })
@@ -235256,19 +235544,39 @@ function resolveRowToken(value, row) {
235256
235544
  }
235257
235545
 
235258
235546
  /**
235259
- * The route params a `handler: "navigate"` action pushes for a row: the row id,
235260
- * overridden by the declared `params` after the `{field}` token grammar. A
235261
- * token naming a field the row lacks is dropped.
235547
+ * The implicit `{ id }` param for a row, only when the named route declares
235548
+ * `:id`: vue-router warns about (and drops) a param its path does not take.
235549
+ * Without a router to ask, or for a route it does not know, the id is kept.
235262
235550
  *
235263
- * @param {object} action Manifest action descriptor.
235551
+ * @param {object} [router] The app's router.
235552
+ * @param {string} name The route name.
235264
235553
  * @param {object} row The row.
235265
235554
  * @param {string} rowKey The row's id field.
235555
+ * @return {object} `{ id }`, or an empty object.
235556
+ */
235557
+ function rowIdParam(router, name, row, rowKey) {
235558
+ const routes = typeof router?.getRoutes === 'function' ? router.getRoutes() : null;
235559
+ const route = routes ? routes.find((r) => r.name === name) : null;
235560
+ if (route && !/:id\b/.test(route.path)) {
235561
+ return {}
235562
+ }
235563
+ return { id: row?.[rowKey] }
235564
+ }
235565
+
235566
+ /**
235567
+ * The route params a `handler: "navigate"` action pushes for a row: the row id
235568
+ * (when the route takes one), overridden by the declared `params` after the
235569
+ * `{field}` token grammar. A token naming a field the row lacks is dropped.
235570
+ *
235571
+ * @param {object} action Manifest action descriptor.
235572
+ * @param {object} row The row.
235573
+ * @param {object} ctx Dispatch context (`rowKey`, `router`).
235266
235574
  * @param {boolean} warn Whether to warn about a dropped param.
235267
235575
  * @return {object} The params.
235268
235576
  */
235269
- function navigateParams(action, row, rowKey, warn) {
235577
+ function navigateParams(action, row, ctx, warn) {
235270
235578
  const declaredParams = (action.params && typeof action.params === 'object') ? action.params : null;
235271
- const params = { id: row?.[rowKey] };
235579
+ const params = rowIdParam(ctx.router, action.route, row, ctx.rowKey);
235272
235580
  for (const [key, declared] of Object.entries(declaredParams || {})) {
235273
235581
  const { resolved, value } = resolveRowToken(declared, row);
235274
235582
  if (resolved) {
@@ -235307,7 +235615,7 @@ function resolveActionTarget(action, row, ctx, warn = false) {
235307
235615
  return null
235308
235616
  }
235309
235617
  if (type === 'open-page') {
235310
- return { target: { name: target, params: { id: row?.[ctx.rowKey] } }, external: false }
235618
+ return { target: { name: target, params: rowIdParam(ctx.router, target, row, ctx.rowKey) }, external: false }
235311
235619
  }
235312
235620
  return { target, external: isExternalActionTarget(target) }
235313
235621
  }
@@ -235315,7 +235623,7 @@ function resolveActionTarget(action, row, ctx, warn = false) {
235315
235623
  if (typeof action.route !== 'string' || action.route.length === 0) {
235316
235624
  return null
235317
235625
  }
235318
- return { target: { name: action.route, params: navigateParams(action, row, ctx.rowKey, warn) }, external: false }
235626
+ return { target: { name: action.route, params: navigateParams(action, row, ctx, warn) }, external: false }
235319
235627
  }
235320
235628
  return null
235321
235629
  }
@@ -235334,8 +235642,8 @@ function resolveActionTarget(action, row, ctx, warn = false) {
235334
235642
  * - `open-modal` → not wired for index actions; falls back to `@action`.
235335
235643
  *
235336
235644
  * Handler dispatch (`type: 'handler'`, the default) reads `action.handler`:
235337
- * - `navigate` → $router.push to `action.route` with `{ id: row[rowKey] }`,
235338
- * merged with the `action.params` map (declared params win — so a
235645
+ * - `navigate` → $router.push to `action.route` with `{ id: row[rowKey] }`
235646
+ * (when the route declares `:id`), merged with the `action.params` map (declared params win — so a
235339
235647
  * "New X" action can navigate to a detail route with `{ id: "new" }`).
235340
235648
  * Param strings run the `{field}` row-token grammar: `"{id}"` resolves to
235341
235649
  * `row.id` (type preserved), `"item-{id}"` interpolates, and a brace-less
@@ -235406,7 +235714,7 @@ function resolveActionHandler(action, ctx) {
235406
235714
  // `{field}` row-token grammar first — an unresolved token is dropped
235407
235715
  // rather than pushed as a literal `%7Bid%7D` path segment.
235408
235716
  return (row) => {
235409
- ctx.router.push({ name: route, params: navigateParams(action, row, ctx.rowKey, true) });
235717
+ ctx.router.push({ name: route, params: navigateParams(action, row, ctx, true) });
235410
235718
  }
235411
235719
  }
235412
235720
 
@@ -236619,7 +236927,8 @@ function namedFilterToQuery(values) {
236619
236927
  * @event {object} mass-export — Mass export confirmed. Payload: { ids, format }
236620
236928
  * @event {object} mass-import — Mass import confirmed. Payload: import data
236621
236929
  * @event {void} refresh — Refresh button clicked
236622
- * @event {object} row-click — Table row or card clicked or middle-clicked. Payload: (row, event) — the row object and the native click/auxclick event
236930
+ * @event {object} row-click — Table row or card clicked. Payload: (row, event) — the row object and the native click event
236931
+ * @event {object} row-aux-click — Table row or card middle-clicked. Payload: (row, event) — the row object and the native auxclick event
236623
236932
  * @event {{ key: string, order: string }} sort — Column sort changed
236624
236933
  * @event {number} page-changed — Pagination page changed
236625
236934
  * @event {number} page-size-changed — Pagination page size changed
@@ -238192,6 +238501,7 @@ var script$1y = {
238192
238501
  'quick-filter-change',
238193
238502
  'refresh',
238194
238503
  'row-click',
238504
+ 'row-aux-click',
238195
238505
  'search',
238196
238506
  'select',
238197
238507
  'sort',
@@ -238434,6 +238744,9 @@ var script$1y = {
238434
238744
  * that is what Add does (no host `@add` listener) and the router can
238435
238745
  * resolve it. The bar then renders Add as a real link; null otherwise.
238436
238746
  *
238747
+ * `$.vnode.props` is not reactive, so an `add` listener attached or
238748
+ * removed after mount does not re-evaluate this.
238749
+ *
238437
238750
  * @return {string|object|null}
238438
238751
  */
238439
238752
  addLinkTo() {
@@ -241189,21 +241502,60 @@ var script$1y = {
241189
241502
  /**
241190
241503
  * Row/card click: toggles selection when `selectable` (covers the custom
241191
241504
  * `cardComponent` path), otherwise emits `row-click` for navigation. A
241192
- * ctrl/cmd/shift or middle click opens a named source's row in a new tab.
241505
+ * ctrl/cmd/shift click opens a named source's row in a new tab.
241193
241506
  *
241194
241507
  * The `@event` block below sits directly against its `$emit`, and must
241195
241508
  * stay there. vue-docgen binds an event's description to the emit it
241196
241509
  * IMMEDIATELY precedes.
241197
241510
  *
241198
241511
  * @param {object} row The clicked row object
241199
- * @param {MouseEvent|KeyboardEvent} [event] The originating click/auxclick event.
241512
+ * @param {MouseEvent|KeyboardEvent} [event] The originating click event.
241200
241513
  */
241201
241514
  onRowClick(row, event) {
241515
+ if (!this.routeClickedRow(row, event)) {
241516
+ return
241517
+ }
241518
+ /**
241519
+ * @event row-click Emitted on a row/card click for navigation. Fires when `selectable` is false, OR when `rowClickToView` is set and something can open the row (selection then happens via the checkbox). Payload: `(row, event)` — the clicked row and the native click event (absent for a keyboard shortcut or map marker), so a host can open the row in a new tab on a ctrl/cmd/shift click with `openRowTarget`. A middle click emits `row-aux-click` instead.
241520
+ * @type {object} The clicked row object.
241521
+ */
241522
+ this.$emit('row-click', ...(event ? [row, event] : [row]));
241523
+ },
241524
+
241525
+ /**
241526
+ * Row/card middle click: opens a named source's row in a new tab and
241527
+ * emits `row-aux-click`, not `row-click`, so a host whose `row-click`
241528
+ * listener navigates never moves the current tab away.
241529
+ *
241530
+ * @param {object} row The clicked row object
241531
+ * @param {MouseEvent} event The originating auxclick event.
241532
+ */
241533
+ onRowAuxClick(row, event) {
241534
+ if (!this.routeClickedRow(row, event)) {
241535
+ return
241536
+ }
241537
+ /**
241538
+ * @event row-aux-click Emitted on a row/card middle click, under the same conditions as `row-click`, so a host can open the row in a new tab with `openRowTarget`. Payload: `(row, event)` — the clicked row and the native auxclick event.
241539
+ * @type {object} The clicked row object.
241540
+ */
241541
+ this.$emit('row-aux-click', row, event);
241542
+ },
241543
+
241544
+ /**
241545
+ * The shared part of a row click and a middle click: on a selectable
241546
+ * page a plain click toggles selection instead, and a named source opens
241547
+ * its own row.
241548
+ *
241549
+ * @param {object} row The clicked row object
241550
+ * @param {MouseEvent|KeyboardEvent} [event] The originating event.
241551
+ * @return {boolean} Whether the click navigates, so the caller emits.
241552
+ */
241553
+ routeClickedRow(row, event) {
241202
241554
  if (this.selectable && !this.rowClickOpens) {
241203
241555
  if (!event || event.button === undefined || event.button === 0) {
241204
241556
  this.onSelect(this.toggleIdInArray(this.internalSelectedIds, row[this.rowKey]));
241205
241557
  }
241206
- return
241558
+ return false
241207
241559
  }
241208
241560
  // A named source knows where its rows live. Emitting only would leave
241209
241561
  // the click inert on a manifest page, which has no listener to bind —
@@ -241250,11 +241602,7 @@ var script$1y = {
241250
241602
  }
241251
241603
  }
241252
241604
  }
241253
- /**
241254
- * @event row-click Emitted on a row/card click (or middle click) for navigation. Fires when `selectable` is false, OR when `rowClickToView` is set and something can open the row (selection then happens via the checkbox). Payload: `(row, event)` — the clicked row and the native click/auxclick event (absent for a keyboard shortcut or map marker), so a host can open the row in a new tab on a ctrl/cmd/shift or middle click with `openRowTarget`.
241255
- * @type {object} The clicked row object.
241256
- */
241257
- this.$emit('row-click', ...(event ? [row, event] : [row]));
241605
+ return true
241258
241606
  },
241259
241607
 
241260
241608
  /**
@@ -241268,17 +241616,31 @@ var script$1y = {
241268
241616
  return typeof Event !== 'undefined' && value instanceof Event
241269
241617
  },
241270
241618
 
241619
+ /**
241620
+ * Mousedown on a custom list/card component's root: when a middle click
241621
+ * opens the row, keep the browser from starting autoscroll.
241622
+ *
241623
+ * @param {MouseEvent} event The mousedown event.
241624
+ * @return {void}
241625
+ */
241626
+ onCustomItemMouseDown(event) {
241627
+ if (!this.selectable || this.rowClickOpens) {
241628
+ preventMiddleClickAutoscroll(event);
241629
+ }
241630
+ },
241631
+
241271
241632
  /**
241272
241633
  * Middle click on a custom list/card component's root: open the row
241273
- * like a click would.
241634
+ * like a middle click on a built-in card would. Skipped when something
241635
+ * inside the component already opened it in a new tab.
241274
241636
  *
241275
241637
  * @param {object} row The component's row.
241276
241638
  * @param {MouseEvent} event The auxclick event.
241277
241639
  * @return {void}
241278
241640
  */
241279
241641
  onCustomItemAuxClick(row, event) {
241280
- if (isRowMiddleClick(event)) {
241281
- this.onRowClick(row, event);
241642
+ if (isRowMiddleClick(event) && !isNewTabHandled(event)) {
241643
+ this.onRowAuxClick(row, event);
241282
241644
  }
241283
241645
  },
241284
241646
 
@@ -242685,6 +243047,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242685
243047
  onSort: $options.onSortEvent,
242686
243048
  onSelect: $options.onSelect,
242687
243049
  onRowClick: $options.onRowClick,
243050
+ onRowAuxClick: $options.onRowAuxClick,
242688
243051
  onRowContextMenu: $options.onRowContextMenu
242689
243052
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
242690
243053
  vue$1.renderList($options.slotColumns, (col) => {
@@ -242785,7 +243148,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242785
243148
  key: "1"
242786
243149
  }
242787
243150
  : undefined
242788
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["schema", "columns", "rowIcon", "rowIndicators", "rowIndicatorCap", "rows", "sortKey", "sortOrder", "sortKeys", "selectable", "rowClickToView", "selectedIds", "rowKey", "emptyText", "excludeColumns", "includeColumns", "columnOverrides", "rowClass", "onSort", "onSelect", "onRowClick", "onRowContextMenu"]))
243151
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["schema", "columns", "rowIcon", "rowIndicators", "rowIndicatorCap", "rows", "sortKey", "sortOrder", "sortKeys", "selectable", "rowClickToView", "selectedIds", "rowKey", "emptyText", "excludeColumns", "includeColumns", "columnOverrides", "rowClass", "onSort", "onSelect", "onRowClick", "onRowAuxClick", "onRowContextMenu"]))
242789
243152
  : ($data.currentViewMode === 'map')
242790
243153
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnMapWidget, {
242791
243154
  key: 3,
@@ -242811,8 +243174,9 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242811
243174
  runTransition: $props.runTransition,
242812
243175
  paged: $options.isPaged,
242813
243176
  onCardClick: $options.onRowClick,
243177
+ onCardAuxClick: $options.onRowAuxClick,
242814
243178
  onMoved: $options.onBoardMoved
242815
- }, null, 8 /* PROPS */, ["rows", "statusFieldSchema", "statusField", "cardFields", "swimlaneField", "rowKey", "runTransition", "paged", "onCardClick", "onMoved"]))
243179
+ }, null, 8 /* PROPS */, ["rows", "statusFieldSchema", "statusField", "cardFields", "swimlaneField", "rowKey", "runTransition", "paged", "onCardClick", "onCardAuxClick", "onMoved"]))
242816
243180
  : ($data.currentViewMode === 'dateAxis')
242817
243181
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnDateAxisView, {
242818
243182
  key: 5,
@@ -242822,8 +243186,9 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242822
243186
  laneField: $props.dateAxis.laneField || '',
242823
243187
  labelField: $props.dateAxis.labelField || '',
242824
243188
  rowKey: $props.rowKey,
242825
- onRowClick: $options.onRowClick
242826
- }, null, 8 /* PROPS */, ["rows", "startField", "endField", "laneField", "labelField", "rowKey", "onRowClick"]))
243189
+ onRowClick: $options.onRowClick,
243190
+ onRowAuxClick: $options.onRowAuxClick
243191
+ }, null, 8 /* PROPS */, ["rows", "startField", "endField", "laneField", "labelField", "rowKey", "onRowClick", "onRowAuxClick"]))
242827
243192
  : ($data.currentViewMode === 'list')
242828
243193
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnObjectList, {
242829
243194
  key: 6,
@@ -242835,6 +243200,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242835
243200
  rowKey: $props.rowKey,
242836
243201
  emptyText: $props.emptyText,
242837
243202
  onClick: $options.onRowClick,
243203
+ onAuxClick: $options.onRowAuxClick,
242838
243204
  onSelect: $options.onSelect
242839
243205
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
242840
243206
  (_ctx.$slots['list-item'])
@@ -242859,9 +243225,10 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242859
243225
  register: $props.register,
242860
243226
  selected: selected,
242861
243227
  onClick: (...args) => $options.onRowClick(object, args.find($options.isDomEvent)),
243228
+ onMousedown: $options.onCustomItemMouseDown,
242862
243229
  onAuxclick: $event => ($options.onCustomItemAuxClick(object, $event)),
242863
243230
  onSelect: $event => ($options.onSelect($options.toggleIdInArray($data.internalSelectedIds, object[$props.rowKey])))
242864
- }, null, 40 /* PROPS, NEED_HYDRATION */, ["item", "object", "schema", "register", "selected", "onClick", "onAuxclick", "onSelect"]))
243231
+ }, null, 40 /* PROPS, NEED_HYDRATION */, ["item", "object", "schema", "register", "selected", "onClick", "onMousedown", "onAuxclick", "onSelect"]))
242865
243232
  ]),
242866
243233
  key: "1"
242867
243234
  }
@@ -242899,7 +243266,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242899
243266
  key: "4"
242900
243267
  }
242901
243268
  : undefined
242902
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["objects", "schema", "config", "selectable", "selectedIds", "rowKey", "emptyText", "onClick", "onSelect"]))
243269
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["objects", "schema", "config", "selectable", "selectedIds", "rowKey", "emptyText", "onClick", "onAuxClick", "onSelect"]))
242903
243270
  : (vue$1.openBlock(), vue$1.createBlock(_component_CnCardGrid, {
242904
243271
  key: 7,
242905
243272
  objects: $options.displayObjects,
@@ -242910,6 +243277,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242910
243277
  rowKey: $props.rowKey,
242911
243278
  emptyText: $props.emptyText,
242912
243279
  onClick: $options.onRowClick,
243280
+ onAuxClick: $options.onRowAuxClick,
242913
243281
  onSelect: $options.onSelect
242914
243282
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
242915
243283
  (_ctx.$slots.card)
@@ -242934,9 +243302,10 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242934
243302
  register: $props.register,
242935
243303
  selected: selected,
242936
243304
  onClick: (...args) => $options.onRowClick(object, args.find($options.isDomEvent)),
243305
+ onMousedown: $options.onCustomItemMouseDown,
242937
243306
  onAuxclick: $event => ($options.onCustomItemAuxClick(object, $event)),
242938
243307
  onSelect: $event => ($options.onSelect($options.toggleIdInArray($data.internalSelectedIds, object[$props.rowKey])))
242939
- }, null, 40 /* PROPS, NEED_HYDRATION */, ["item", "object", "schema", "register", "selected", "onClick", "onAuxclick", "onSelect"]))
243308
+ }, null, 40 /* PROPS, NEED_HYDRATION */, ["item", "object", "schema", "register", "selected", "onClick", "onMousedown", "onAuxclick", "onSelect"]))
242940
243309
  ]),
242941
243310
  key: "1"
242942
243311
  }
@@ -242956,7 +243325,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242956
243325
  key: "2"
242957
243326
  }
242958
243327
  : undefined
242959
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["objects", "schema", "selectable", "clickToView", "selectedIds", "rowKey", "emptyText", "onClick", "onSelect"])),
243328
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["objects", "schema", "selectable", "clickToView", "selectedIds", "rowKey", "emptyText", "onClick", "onAuxClick", "onSelect"])),
242960
243329
  vue$1.createVNode(_component_CnContextMenu, {
242961
243330
  open: $setup.contextMenuOpen,
242962
243331
  "onUpdate:open": _cache[21] || (_cache[21] = $event => (($setup.contextMenuOpen) = $event)),
@@ -256271,8 +256640,9 @@ var script$1a = {
256271
256640
  * (`@objectId` / `@object.<field>` / `@workspace.<key>`) AND provided on
256272
256641
  * `cnSectionContext` for host section components that inject. Mirrors the
256273
256642
  * `cnObjectContext` ref the abstract list/stat widgets already read.
256643
+ * `setObject(object)` shows an object a section saved without a re-fetch.
256274
256644
  *
256275
- * @return {{objectId: (string|null), object: (object|null), register: string, schema: string}}
256645
+ * @return {{objectId: (string|null), object: (object|null), register: string, schema: string, setObject: function(object): void}}
256276
256646
  */
256277
256647
  sectionContext() {
256278
256648
  const resolved = this.resolvedSidebar || {};
@@ -256282,6 +256652,7 @@ var script$1a = {
256282
256652
  register: resolved.register || this.register || this.sidebarProps?.register || '',
256283
256653
  schema: resolved.schema || this.schema || this.resolvedObjectType || this.sidebarProps?.schema || '',
256284
256654
  config: this.cnAppConfigRef,
256655
+ setObject: (object) => this.setCurrentObject(object),
256285
256656
  }
256286
256657
  },
256287
256658
  },
@@ -256778,6 +257149,32 @@ var script$1a = {
256778
257149
  this.$emit('related-row-click', payload);
256779
257150
  },
256780
257151
 
257152
+ /**
257153
+ * Replace the page's object in the store cache, for a section that saved
257154
+ * it and holds the saved version. An object with another id is ignored.
257155
+ *
257156
+ * @param {object} object The saved object.
257157
+ */
257158
+ setCurrentObject(object) {
257159
+ const store = this.effectiveObjectStore;
257160
+ const type = this.resolvedObjectType;
257161
+ if (!store || !type || !this.objectId || !object) {
257162
+ // eslint-disable-next-line no-console -- tells the integrating section its save is not shown
257163
+ console.warn('[CnDetailPage] setObject ignored: the page has no object store, type or id');
257164
+ return
257165
+ }
257166
+ const id = object.id ?? object['@self']?.id;
257167
+ if (id !== undefined && id !== null && String(id) !== String(this.objectId)) {
257168
+ // eslint-disable-next-line no-console -- tells the integrating section its save is not shown
257169
+ console.warn(`[CnDetailPage] setObject ignored: object ${id} is not the page's object ${this.objectId}`);
257170
+ return
257171
+ }
257172
+ store.objects = {
257173
+ ...store.objects,
257174
+ [type]: { ...(store.objects?.[type] || {}), [this.objectId]: object },
257175
+ };
257176
+ },
257177
+
256781
257178
  /**
256782
257179
  * Schema-driven fetch entry point — no-op outside the
256783
257180
  * `register`+`schema`+`objectId` mode. Registers the type on
@@ -273549,14 +273946,21 @@ var script$F = {
273549
273946
  */
273550
273947
  'action',
273551
273948
  /**
273552
- * @event row-click Emitted when a log row's body is clicked or
273553
- * middle-clicked, whether or not `rowDetail` opened the detail dialog —
273554
- * so a host can navigate instead of (or as well as) showing the dialog.
273555
- * Payload: `(row, event)`, the second being the native click/auxclick
273556
- * event.
273949
+ * @event row-click Emitted when a log row's body is clicked, whether or
273950
+ * not `rowDetail` opened the detail dialog — so a host can navigate
273951
+ * instead of (or as well as) showing the dialog. Payload: `(row, event)`,
273952
+ * the second being the native click event. A middle click emits
273953
+ * `row-aux-click` instead.
273557
273954
  * @type {object}
273558
273955
  */
273559
273956
  'row-click',
273957
+ /**
273958
+ * @event row-aux-click Emitted when a log row's body is middle-clicked,
273959
+ * for opening it in a new tab. Payload: `(row, event)`, the second being
273960
+ * the native auxclick event.
273961
+ * @type {object}
273962
+ */
273963
+ 'row-aux-click',
273560
273964
  ],
273561
273965
 
273562
273966
  setup(props) {
@@ -274059,26 +274463,43 @@ var script$F = {
274059
274463
  /**
274060
274464
  * Handle a row-body click: navigate to `rowRoute` when one is declared,
274061
274465
  * else open the detail dialog when `rowDetail` is set. Always re-emits
274062
- * so a host can do its own thing regardless. A ctrl/cmd/shift or middle
274063
- * click opens `rowRoute` in a new tab; a middle click never opens the
274064
- * dialog.
274466
+ * so a host can do its own thing regardless. A ctrl/cmd/shift click
274467
+ * opens `rowRoute` in a new tab.
274065
274468
  *
274066
274469
  * @param {object} row The clicked log entry.
274067
- * @param {MouseEvent} [event] The originating click/auxclick event.
274470
+ * @param {MouseEvent} [event] The originating click event.
274068
274471
  */
274069
274472
  onRowClick(row, event) {
274070
274473
  if (this.rowRoute) {
274071
274474
  markNewTabHandled(event, openRowTarget(event, { name: this.rowRoute, params: { id: row?.[this.rowKey] } }, this.$router));
274072
- } else if (this.rowDetail && !(event && event.button === 1)) {
274475
+ } else if (this.rowDetail) {
274073
274476
  this.detailRow = row;
274074
274477
  }
274075
274478
  /**
274076
- * @event row-click Emitted when a log row's body is clicked or middle-clicked. Payload: `(row, event)` — the log entry and the native click/auxclick event.
274479
+ * @event row-click Emitted when a log row's body is clicked. Payload: `(row, event)` — the log entry and the native click event.
274077
274480
  * @type {object}
274078
274481
  */
274079
274482
  this.$emit('row-click', row, event);
274080
274483
  },
274081
274484
 
274485
+ /**
274486
+ * Handle a row-body middle click: open `rowRoute` in a new tab, never
274487
+ * the detail dialog, and emit `row-aux-click` rather than `row-click`.
274488
+ *
274489
+ * @param {object} row The clicked log entry.
274490
+ * @param {MouseEvent} event The originating auxclick event.
274491
+ */
274492
+ onRowAuxClick(row, event) {
274493
+ if (this.rowRoute) {
274494
+ markNewTabHandled(event, openRowTarget(event, { name: this.rowRoute, params: { id: row?.[this.rowKey] } }, this.$router));
274495
+ }
274496
+ /**
274497
+ * @event row-aux-click Emitted when a log row's body is middle-clicked. Payload: `(row, event)` — the log entry and the native auxclick event.
274498
+ * @type {object}
274499
+ */
274500
+ this.$emit('row-aux-click', row, event);
274501
+ },
274502
+
274082
274503
  /** Close the row-detail dialog. */
274083
274504
  closeDetail() {
274084
274505
  this.detailRow = null;
@@ -274190,7 +274611,8 @@ function render$F(_ctx, _cache, $props, $setup, $data, $options) {
274190
274611
  sortKeys: $options.effectiveSortKeys,
274191
274612
  emptyText: $props.emptyText,
274192
274613
  onSort: $options.onSort,
274193
- onRowClick: $options.onRowClick
274614
+ onRowClick: $options.onRowClick,
274615
+ onRowAuxClick: $options.onRowAuxClick
274194
274616
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
274195
274617
  vue$1.renderList($options.slotColumns, (col) => {
274196
274618
  return {
@@ -274212,7 +274634,7 @@ function render$F(_ctx, _cache, $props, $setup, $data, $options) {
274212
274634
  key: "0"
274213
274635
  }
274214
274636
  : undefined
274215
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["schema", "columns", "rows", "rowKey", "fixedLayout", "sortKey", "sortOrder", "sortKeys", "emptyText", "onSort", "onRowClick"]),
274637
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["schema", "columns", "rows", "rowKey", "fixedLayout", "sortKey", "sortOrder", "sortKeys", "emptyText", "onSort", "onRowClick", "onRowAuxClick"]),
274216
274638
  ($options.paginationState && $options.paginationState.pages > 1)
274217
274639
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnPagination, {
274218
274640
  key: 0,
@@ -276900,7 +277322,8 @@ function render$y(_ctx, _cache, $props, $setup, $data, $options) {
276900
277322
  showEditAction: false,
276901
277323
  actions: $options.rowActions,
276902
277324
  rowClickToView: "",
276903
- onRowClick: $options.openFlow
277325
+ onRowClick: $options.openFlow,
277326
+ onRowAuxClick: $options.openFlow
276904
277327
  }, {
276905
277328
  "header-actions": vue$1.withCtx(() => [
276906
277329
  vue$1.createVNode(_component_NcButton, {
@@ -276917,7 +277340,7 @@ function render$y(_ctx, _cache, $props, $setup, $data, $options) {
276917
277340
  }, 8 /* PROPS */, ["to"])
276918
277341
  ]),
276919
277342
  _: 1 /* STABLE */
276920
- }, 8 /* PROPS */, ["title", "description", "columns", "objects", "loading", "actions", "onRowClick"]))
277343
+ }, 8 /* PROPS */, ["title", "description", "columns", "objects", "loading", "actions", "onRowClick", "onRowAuxClick"]))
276921
277344
  }
276922
277345
 
276923
277346
  script$y.render = render$y;
@@ -283168,6 +283591,7 @@ function render$q(_ctx, _cache, $props, $setup, $data, $options) {
283168
283591
  ? (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.resolvedComponent), vue$1.mergeProps({ key: $options.pageRenderKey }, { ..._ctx.$attrs, ...$options.resolvedProps }, {
283169
283592
  onView: $options.onRowOpen,
283170
283593
  onRowClick: $options.onRowOpen,
283594
+ onRowAuxClick: $options.onRowOpen,
283171
283595
  onEditOpen: $options.onRowOpen,
283172
283596
  onConfigure: _cache[0] || (_cache[0] = $event => ($data.showConfigModal = true))
283173
283597
  }), vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
@@ -283204,7 +283628,7 @@ function render$q(_ctx, _cache, $props, $setup, $data, $options) {
283204
283628
  key: "0"
283205
283629
  }
283206
283630
  : undefined
283207
- ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onEditOpen"]))
283631
+ ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onRowAuxClick", "onEditOpen"]))
283208
283632
  : vue$1.createCommentVNode("v-if", true),
283209
283633
  ($options.widgetsBySlot.has('header-actions'))
283210
283634
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnWidgetGrid, {
@@ -283246,6 +283670,7 @@ function render$q(_ctx, _cache, $props, $setup, $data, $options) {
283246
283670
  ? (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.resolvedComponent), vue$1.mergeProps({ key: $options.pageRenderKey }, { ..._ctx.$attrs, ...$options.resolvedProps }, {
283247
283671
  onView: $options.onRowOpen,
283248
283672
  onRowClick: $options.onRowOpen,
283673
+ onRowAuxClick: $options.onRowOpen,
283249
283674
  onEditOpen: $options.onRowOpen,
283250
283675
  onConfigure: _cache[1] || (_cache[1] = $event => ($data.showConfigModal = true))
283251
283676
  }), vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
@@ -283282,7 +283707,7 @@ function render$q(_ctx, _cache, $props, $setup, $data, $options) {
283282
283707
  key: "0"
283283
283708
  }
283284
283709
  : undefined
283285
- ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onEditOpen"]))
283710
+ ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onRowAuxClick", "onEditOpen"]))
283286
283711
  : vue$1.createCommentVNode("v-if", true),
283287
283712
  (!$options.hasRenderableBody)
283288
283713
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_2$A, [
@@ -296211,8 +296636,7 @@ function render$7(_ctx, _cache, $props, $setup, $data, $options) {
296211
296636
  key: 0,
296212
296637
  variant: "primary",
296213
296638
  href: $options.resolvedSuggestUrl,
296214
- target: "_blank",
296215
- rel: "noopener noreferrer"
296639
+ target: "_blank"
296216
296640
  }, {
296217
296641
  icon: vue$1.withCtx(() => [
296218
296642
  vue$1.createVNode(_component_Plus, { size: 20 })
@@ -300263,6 +300687,7 @@ var translations$s = {
300263
300687
  "One of": "One of",
300264
300688
  Open: "Open",
300265
300689
  "Open access:": "Open access:",
300690
+ "Open row": "Open row",
300266
300691
  Operator: "Operator",
300267
300692
  Order: "Order",
300268
300693
  "Owner:": "Owner:",
@@ -301468,6 +301893,7 @@ var translations$c = {
301468
301893
  "One of": "Één van",
301469
301894
  Open: "Openen",
301470
301895
  "Open access:": "Openbare toegang:",
301896
+ "Open row": "Rij openen",
301471
301897
  Operator: "Operator",
301472
301898
  Order: "Volgorde",
301473
301899
  "Owner:": "Eigenaar:",