@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
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/dist/nextcloud-vue.cjs.js.map
3
- size: 33677319 bytes
4
- sha256: 01032564aced4b648d5ee120b13ec9044a3664bce422f2588379b83ccab9bc63
3
+ size: 33724477 bytes
4
+ sha256: c593f3967574b3cc9859bbff81c44bf2dcc4e304406f11ca2a1267065ef51df2
@@ -364,6 +364,32 @@
364
364
  background-color: var(--color-primary-light);
365
365
  }
366
366
 
367
+ /* A row with a route is a real link (see CnDataTable's row link): the anchor
368
+ in its first cell is stretched over the whole row. The row's own controls
369
+ sit above it so they stay usable; keep the list in step with NESTED_CONTROL
370
+ in utils/rowAuxClick.js. */
371
+ .cn-table-row--linked {
372
+ position: relative;
373
+ }
374
+
375
+ .cn-table-row__link {
376
+ position: absolute;
377
+ inset: 0;
378
+ cursor: pointer;
379
+ }
380
+
381
+ .cn-table-row__link:focus-visible {
382
+ outline: 2px solid var(--color-main-text);
383
+ outline-offset: -2px;
384
+ }
385
+
386
+ .cn-table-row--linked .cn-table-col--checkbox,
387
+ .cn-table-row--linked .cn-table-col--actions,
388
+ .cn-table-row--linked td :is(a, button, input, select, textarea, label, summary, [role='button'], [role='checkbox'], [role='link'], [contenteditable='true']):not(.cn-table-row__link) {
389
+ position: relative;
390
+ z-index: 1;
391
+ }
392
+
367
393
  /* Column Types */
368
394
  .cn-table-col--checkbox {
369
395
  width: 50px;
@@ -5995,6 +6021,32 @@ svg.leaflet-image-layer.leaflet-interactive path {
5995
6021
  background-color: var(--color-primary-light);
5996
6022
  }
5997
6023
 
6024
+ /* A row with a route is a real link (see CnDataTable's row link): the anchor
6025
+ in its first cell is stretched over the whole row. The row's own controls
6026
+ sit above it so they stay usable; keep the list in step with NESTED_CONTROL
6027
+ in utils/rowAuxClick.js. */
6028
+ .cn-table-row--linked {
6029
+ position: relative;
6030
+ }
6031
+
6032
+ .cn-table-row__link {
6033
+ position: absolute;
6034
+ inset: 0;
6035
+ cursor: pointer;
6036
+ }
6037
+
6038
+ .cn-table-row__link:focus-visible {
6039
+ outline: 2px solid var(--color-main-text);
6040
+ outline-offset: -2px;
6041
+ }
6042
+
6043
+ .cn-table-row--linked .cn-table-col--checkbox,
6044
+ .cn-table-row--linked .cn-table-col--actions,
6045
+ .cn-table-row--linked td :is(a, button, input, select, textarea, label, summary, [role='button'], [role='checkbox'], [role='link'], [contenteditable='true']):not(.cn-table-row__link) {
6046
+ position: relative;
6047
+ z-index: 1;
6048
+ }
6049
+
5998
6050
  /* Column Types */
5999
6051
  .cn-table-col--checkbox {
6000
6052
  width: 50px;
@@ -9701,14 +9753,18 @@ a.cn-deck-tab__card-title[data-v-3501a864]:hover {
9701
9753
  background: none;
9702
9754
  border: none;
9703
9755
  padding: 6px 0;
9704
- cursor: pointer;
9705
9756
  text-align: left;
9706
9757
  color: inherit;
9707
9758
  font: inherit;
9708
9759
  text-decoration: none;
9709
9760
  box-sizing: border-box;
9710
9761
  }
9711
- .cn-email-card__open:hover .cn-email-card__subject[data-v-fda51a6a] {
9762
+
9763
+ /* Only a row with Mail ids is a link; the rest must not look clickable. */
9764
+ a.cn-email-card__open[data-v-fda51a6a] {
9765
+ cursor: pointer;
9766
+ }
9767
+ a.cn-email-card__open:hover .cn-email-card__subject[data-v-fda51a6a] {
9712
9768
  color: var(--color-primary-element);
9713
9769
  }
9714
9770
  .cn-email-card__avatar[data-v-fda51a6a] {
@@ -9949,10 +10005,14 @@ a.cn-deck-tab__card-title[data-v-3501a864]:hover {
9949
10005
  border-radius: var(--border-radius-large, 8px);
9950
10006
  color: inherit;
9951
10007
  text-decoration: none;
9952
- cursor: pointer;
9953
10008
  position: relative;
9954
10009
  }
9955
- .cn-email-tab__row[data-v-0bcebbac]:hover {
10010
+
10011
+ /* Only a row with Mail ids is a link; the rest must not look clickable. */
10012
+ a.cn-email-tab__row[data-v-0bcebbac] {
10013
+ cursor: pointer;
10014
+ }
10015
+ a.cn-email-tab__row[data-v-0bcebbac]:hover {
9956
10016
  background-color: var(--color-background-hover);
9957
10017
  }
9958
10018
  .cn-email-tab__unread-dot[data-v-0bcebbac] {
@@ -17677,7 +17737,11 @@ to { background-position: -200% 0;
17677
17737
  }
17678
17738
 
17679
17739
  /* A fade over the clipped edge, only on the side that hides tabs. Stops a
17680
- pixel above the bar's rule so the rule keeps its full colour. */
17740
+ pixel above the bar's rule so the rule keeps its full colour.
17741
+
17742
+ z-index 2 so the fades outrank a lifted tab: CnTabsWidget puts the open tab
17743
+ at 1, and a tie goes to DOM order, which would draw that tab over the start
17744
+ fade (it precedes the tabs) while the end fade still covered it. */
17681
17745
  .cn-tabs__strip[data-v-5c1a056f]::before,
17682
17746
  .cn-tabs__strip[data-v-5c1a056f]::after {
17683
17747
  content: '';
@@ -17686,7 +17750,7 @@ to { background-position: -200% 0;
17686
17750
  pointer-events: none;
17687
17751
  position: absolute;
17688
17752
  width: 56px;
17689
- z-index: 1;
17753
+ z-index: 2;
17690
17754
  }
17691
17755
  .cn-tabs__strip[data-v-5c1a056f]::before {
17692
17756
  background: linear-gradient(to right, var(--color-main-background) 30%, transparent);
@@ -17720,7 +17784,7 @@ to { background-position: -200% 0;
17720
17784
  padding: 0;
17721
17785
  position: absolute;
17722
17786
  width: 28px;
17723
- z-index: 2;
17787
+ z-index: 3;
17724
17788
  }
17725
17789
 
17726
17790
  /* Nextcloud's `button:hover` rule would otherwise fill the chevron. */
package/l10n/en.json CHANGED
@@ -374,6 +374,7 @@
374
374
  "One of": "One of",
375
375
  "Open": "Open",
376
376
  "Open access:": "Open access:",
377
+ "Open row": "Open row",
377
378
  "Operator": "Operator",
378
379
  "Order": "Order",
379
380
  "Owner:": "Owner:",
package/l10n/nl.json CHANGED
@@ -372,6 +372,7 @@
372
372
  "One of": "Één van",
373
373
  "Open": "Openen",
374
374
  "Open access:": "Openbare toegang:",
375
+ "Open row": "Rij openen",
375
376
  "Operator": "Operator",
376
377
  "Order": "Volgorde",
377
378
  "Owner:": "Eigenaar:",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduction/nextcloud-vue",
3
- "version": "2.56.0-beta.4",
3
+ "version": "2.56.0-beta.5",
4
4
  "description": "Shared Vue component library for Conduction Nextcloud apps — complements @nextcloud/vue with higher-level components, OpenRegister integration, and NL Design System support",
5
5
  "homepage": "https://github.com/ConductionNL/nextcloud-vue#readme",
6
6
  "bugs": {
@@ -109,7 +109,7 @@
109
109
  @event add
110
110
  @description User clicked the primary Add button. No payload.
111
111
  -->
112
- <!-- With `addHref` / `addTo` the button is a real link (middle-click, new tab), and still emits `add`. -->
112
+ <!-- With `addHref` / `addTo` the button is a real link (middle-click, new tab), and still emits `add`, except on a modified click, which opens a new tab. -->
113
113
  <NcButton v-if="showAdd"
114
114
  variant="primary"
115
115
  :disabled="addDisabled"
@@ -153,8 +153,7 @@
153
153
 
154
154
  <NcActionLink v-if="documentationUrl"
155
155
  :href="documentationUrl"
156
- target="_blank"
157
- rel="noopener noreferrer">
156
+ target="_blank">
158
157
  <template #icon>
159
158
  <BookOpenVariantOutline :size="20" />
160
159
  </template>
@@ -372,6 +371,7 @@ import ViewGridOutline from 'vue-material-design-icons/ViewGridOutline.vue'
372
371
  import ViewListOutline from 'vue-material-design-icons/ViewListOutline.vue'
373
372
  import CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'
374
373
  import { followItemActionLink, resolveItemActionLink } from '../../utils/actionLink.js'
374
+ import { isModifiedClick } from '../../utils/linkNavigation.js'
375
375
  import { CnIcon } from '../CnIcon/index.js'
376
376
 
377
377
  /**
@@ -923,12 +923,17 @@ export default {
923
923
 
924
924
  /**
925
925
  * Add button click: a plain click on an in-app link routes in place,
926
- * anything else on a link is the browser's. Emits `add` either way.
926
+ * anything else on a link is the browser's. Emits `add`, except for a
927
+ * modified click on a link, which opens in a new tab: a host `@add`
928
+ * would otherwise run in the tab the user is leaving.
927
929
  *
928
930
  * @param {MouseEvent} event The click event.
929
931
  */
930
932
  onAddClick(event) {
931
933
  if (this.addLink) {
934
+ if (isModifiedClick(event)) {
935
+ return
936
+ }
932
937
  followItemActionLink(event, this.addLink, this.$router)
933
938
  }
934
939
  this.$emit('add')
@@ -936,13 +941,17 @@ export default {
936
941
 
937
942
  /**
938
943
  * A header link entry was clicked: route a plain in-app click and emit
939
- * `header-action` as the button would.
944
+ * `header-action` as the button would. A modified click is the
945
+ * browser's alone (a new tab), so nothing is emitted for it.
940
946
  *
941
947
  * @param {object} entry The header action.
942
948
  * @param {object} link The resolved link.
943
949
  * @param {MouseEvent} event The click event.
944
950
  */
945
951
  onHeaderLinkClick(entry, link, event) {
952
+ if (isModifiedClick(event)) {
953
+ return
954
+ }
946
955
  followItemActionLink(event, link, this.$router)
947
956
  this.$emit('header-action', { action: entry.id, id: entry.id })
948
957
  },
@@ -69,7 +69,6 @@
69
69
  v-if="showRequestFeature && resolvedRequestFeatureUrl"
70
70
  :href="resolvedRequestFeatureUrl"
71
71
  target="_blank"
72
- rel="noopener noreferrer"
73
72
  :data-testid="`${testidBase}-action-request-feature`"
74
73
  :closeAfterClick="true"
75
74
  @click="onRequestFeatureClick">
@@ -92,7 +91,6 @@
92
91
  v-if="showReportBug && resolvedReportBugUrl"
93
92
  :href="resolvedReportBugUrl"
94
93
  target="_blank"
95
- rel="noopener noreferrer"
96
94
  :data-testid="`${testidBase}-action-report-bug`"
97
95
  :closeAfterClick="true">
98
96
  <template #icon>
@@ -104,7 +102,6 @@
104
102
  v-if="showDocumentation && resolvedDocumentationUrl"
105
103
  :href="resolvedDocumentationUrl"
106
104
  target="_blank"
107
- rel="noopener noreferrer"
108
105
  :data-testid="`${testidBase}-action-documentation`"
109
106
  :closeAfterClick="true">
110
107
  <template #icon>
@@ -47,8 +47,7 @@
47
47
  <NcButton
48
48
  v-if="showHelp && helpUrl"
49
49
  :href="helpUrl"
50
- target="_blank"
51
- rel="noopener noreferrer">
50
+ target="_blank">
52
51
  <template #icon>
53
52
  <HelpCircleOutline :size="20" />
54
53
  </template>
@@ -108,6 +108,7 @@
108
108
  :data-card-id="cardKey(card)"
109
109
  :aria-label="cardLabel(card, column)"
110
110
  @click="openCard(card, $event)"
111
+ @mousedown="preventMiddleClickAutoscroll"
111
112
  @auxclick="onCardAuxClick(card, $event)">
112
113
  {{ openLabel }}
113
114
  </button>
@@ -161,7 +162,7 @@ import { translate as t } from '@nextcloud/l10n'
161
162
  import { buildBoardColumns } from '../../utils/boardColumns.js'
162
163
  import { buildSwimlanes } from '../../utils/boardSwimlanes.js'
163
164
  import { DROP_OUTCOMES, runBoardDrop } from '../../utils/boardTransition.js'
164
- import { isRowMiddleClick } from '../../utils/rowAuxClick.js'
165
+ import { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'
165
166
 
166
167
  /**
167
168
  * CnBoardView — the index page's rows as a board, one column per stage.
@@ -253,7 +254,7 @@ export default {
253
254
  },
254
255
  },
255
256
 
256
- emits: ['card-click', 'moved', 'refused', 'stale'],
257
+ emits: ['card-click', 'card-aux-click', 'moved', 'refused', 'stale'],
257
258
 
258
259
  data() {
259
260
  return {
@@ -333,6 +334,8 @@ export default {
333
334
  methods: {
334
335
  t,
335
336
 
337
+ preventMiddleClickAutoscroll,
338
+
336
339
  /**
337
340
  * Open one card. The pointer and the keyboard both come through here,
338
341
  * so a reader on Enter reaches the same record as a reader on click.
@@ -343,13 +346,15 @@ export default {
343
346
  */
344
347
  openCard(card, event) {
345
348
  /**
346
- * @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.
349
+ * @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.
347
350
  */
348
351
  this.$emit('card-click', card, event)
349
352
  },
350
353
 
351
354
  /**
352
- * Middle click on a card's open button: open it like a click would.
355
+ * Middle click on a card's open button: emits `card-aux-click`, not
356
+ * `card-click`, so an existing listener that navigates never moves the
357
+ * current tab away.
353
358
  *
354
359
  * @param {object} card The card the reader picked.
355
360
  * @param {MouseEvent} event The auxclick event.
@@ -357,7 +362,10 @@ export default {
357
362
  */
358
363
  onCardAuxClick(card, event) {
359
364
  if (isRowMiddleClick(event)) {
360
- this.openCard(card, event)
365
+ /**
366
+ * @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.
367
+ */
368
+ this.$emit('card-aux-click', card, event)
361
369
  }
362
370
  },
363
371
 
@@ -149,7 +149,7 @@ export default {
149
149
  },
150
150
  },
151
151
 
152
- emits: ['click', 'select'],
152
+ emits: ['click', 'select', 'aux-click'],
153
153
 
154
154
  computed: {
155
155
  /**
@@ -184,6 +184,14 @@ export default {
184
184
  const listeners = { select: () => this.toggleSelect(object) }
185
185
  if (!this.selectable || this.clickToView) {
186
186
  listeners.click = (_card, event) => this.$emit('click', object, event)
187
+ // A middle click, kept off `click` so a navigating listener stays put.
188
+ listeners['aux-click'] = (_card, event) => {
189
+ /**
190
+ * @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.
191
+ * @type {object} The card's object.
192
+ */
193
+ this.$emit('aux-click', object, event)
194
+ }
187
195
  }
188
196
  return listeners
189
197
  },
@@ -94,6 +94,7 @@
94
94
  import { NcActionButton, NcActionLink, NcActions } from '@nextcloud/vue'
95
95
  import { CTX_MENU_DATA_ATTR, CTX_MENU_POPPER_ATTR } from '../../composables/useContextMenu.js'
96
96
  import { followItemActionLink, resolveItemActionLink } from '../../utils/actionLink.js'
97
+ import { isModifiedClick } from '../../utils/linkNavigation.js'
97
98
  import { CnIcon } from '../CnIcon/index.js'
98
99
 
99
100
  /**
@@ -493,13 +494,17 @@ export default {
493
494
  /**
494
495
  * A link entry was clicked: route a plain in-app click, leave the rest to
495
496
  * the browser, and emit `action` as a button would. The `handler` is not
496
- * called, since navigating is what the link already does.
497
+ * called, since navigating is what the link already does. A modified
498
+ * click opens a new tab, so nothing is emitted in this one.
497
499
  *
498
500
  * @param {object} action The action descriptor.
499
501
  * @param {object} link The resolved link.
500
502
  * @param {MouseEvent} event The click event.
501
503
  */
502
504
  onLinkAction(action, link, event) {
505
+ if (isModifiedClick(event)) {
506
+ return
507
+ }
503
508
  followItemActionLink(event, link, this.$router)
504
509
  this.$emit('action', { action: action.label, row: this.targetItem })
505
510
  },
@@ -229,7 +229,7 @@ features are folded in here as opt-in props (bare-table usage is unchanged):
229
229
  - `fetchParams` — extra query params for the self-fetch (a resolved filter map,
230
230
  `_order[field]` ordering, `_limit`); changing it re-triggers the fetch. Used by
231
231
  `CnWidgetObjectTable`'s declarative `source`.
232
- - `rowClickRoute` — a function mapping a clicked row to a vue-router route to push.
232
+ - `rowClickRoute` — a function mapping a row to a vue-router route. Each such row renders a real `<a href>` in its first cell, stretched over the row, so hovering shows the URL, a plain or alt click routes in place, a ctrl/cmd/shift or middle click opens a new tab, and the row is reachable with Tab. The link is named by the first cell's text ("Open row" when that is empty or not plain text). There is no link on a `selectable` table without `rowClickToView`, where a row click selects. `CnWidgetObjectTable` rows inherit it. Trade-offs: cell text cannot be selected by dragging on a linked row, and a right-click on it shows the browser's link menu only when no host listens to `row-context-menu`.
233
233
  - `hideHeader` — drop the column-label row for a compact list widget.
234
234
  - `#footer` slot — supply a custom footer link (e.g. "+ New" or an always-shown
235
235
  "View all") with its own handler; works outside a vue-router context.
@@ -139,12 +139,13 @@
139
139
  :data-testid-row-id="row[rowKey]"
140
140
  :class="[
141
141
  isSelected(row) ? 'cn-table-row--selected' : '',
142
+ rowLinks[String(row[rowKey])] ? 'cn-table-row--linked' : '',
142
143
  rowClass ? rowClass(row) : '',
143
144
  ]"
144
- @mousedown="onPointerDown"
145
+ @mousedown="onRowMouseDown"
145
146
  @click="onRowClick(row, $event)"
146
147
  @auxclick="onRowAuxClick(row, $event)"
147
- @contextmenu.prevent="onRowContextMenu(row, $event)">
148
+ @contextmenu="onRowContextMenu(row, $event)">
148
149
  <!-- Checkbox -->
149
150
  <td v-if="selectable"
150
151
  class="cn-table-col--checkbox"
@@ -168,6 +169,18 @@
168
169
  :class="[col.class || '', col.cellClass || '', cellClass ? cellClass(row, col) : '']"
169
170
  :style="col.width ? { maxWidth: col.width } : {}"
170
171
  @mouseenter="titleWhenClipped">
172
+ <!-- A row with a `rowClickRoute` is a real link: this anchor
173
+ is stretched over the whole row by CSS, so hovering shows
174
+ the URL, a middle or ctrl click opens a new tab natively,
175
+ and the row is reachable with Tab. The row's own click
176
+ handlers treat it as a nested control and leave it be. -->
177
+ <a v-if="colIndex === 0 && rowLinks[String(row[rowKey])]"
178
+ class="cn-table-row__link"
179
+ :href="rowLinks[String(row[rowKey])].href"
180
+ :aria-label="rowLinkLabel(row, col)"
181
+ draggable="false"
182
+ data-testid="cn-row-link"
183
+ @click="onRowLinkClick(row, $event)" />
171
184
  <!-- The padlock rides the FIRST data cell, beside whatever
172
185
  names the row. Deliberately OUTSIDE the #column-<key>
173
186
  slot: a consumer overriding that column's rendering is
@@ -274,9 +287,9 @@ import { translate as t } from '@nextcloud/l10n'
274
287
  import { generateUrl } from '@nextcloud/router'
275
288
  import { NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'
276
289
  import { useClickDragGuard } from '../../composables/useClickDragGuard.js'
277
- import { openRowTarget } from '../../utils/linkNavigation.js'
290
+ import { followLinkClick, openRowTarget, resolveHref } from '../../utils/linkNavigation.js'
278
291
  import { nextSortState } from '../../utils/multiColumnSort.js'
279
- import { isNewTabHandled, isRowMiddleClick, markNewTabHandled } from '../../utils/rowAuxClick.js'
292
+ import { isNewTabClick, isNewTabHandled, isRowMiddleClick, markNewTabHandled, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'
280
293
  import { DEFAULT_ROW_INDICATOR_CAP, resolveRowIndicators } from '../../utils/rowIndicators.js'
281
294
  import { columnsFromSchema } from '../../utils/schema.js'
282
295
  import { CnCellRenderer } from '../CnCellRenderer/index.js'
@@ -692,9 +705,11 @@ export default {
692
705
 
693
706
  /**
694
707
  * Convenience navigation (folded from CnTableWidget): a function that
695
- * receives the clicked row and returns a vue-router route to push. When
696
- * set, a row click navigates there (the `row-click` event still fires);
697
- * a ctrl/cmd/shift or middle click opens it in a new tab.
708
+ * receives a row and returns the vue-router route it opens. When set,
709
+ * each row renders as a real link to that route, stretched over the
710
+ * row: a click navigates there (the `row-click` event still fires), and
711
+ * a ctrl/cmd/shift or middle click opens it in a new tab. A table whose
712
+ * row click selects (`selectable` without `rowClickToView`) gets no link.
698
713
  *
699
714
  * @type {((row: object) => object)|null}
700
715
  */
@@ -717,7 +732,7 @@ export default {
717
732
  },
718
733
  },
719
734
 
720
- emits: ['row-click', 'row-context-menu', 'select', 'select-all', 'sort', 'view-all'],
735
+ emits: ['row-click', 'row-aux-click', 'row-context-menu', 'select', 'select-all', 'sort', 'view-all'],
721
736
 
722
737
  setup() {
723
738
  // Tell a deliberate row click apart from a text-selection drag.
@@ -867,6 +882,32 @@ export default {
867
882
  *
868
883
  * @return {Array<{key: string, order: 'asc'|'desc'}>}
869
884
  */
885
+ /**
886
+ * The link each row opens, keyed by row key: the `rowClickRoute`
887
+ * location and its href. Empty when rows have no route, or when a row
888
+ * click selects instead of navigating.
889
+ *
890
+ * @return {{[key: string]: {target: object, href: string}}}
891
+ */
892
+ rowLinks() {
893
+ const links = {}
894
+ if (!this.rowClickRoute || !this.$router || (this.selectable && !this.rowClickToView)) {
895
+ return links
896
+ }
897
+ for (const row of this.effectiveRows) {
898
+ const route = this.rowClickRoute(row)
899
+ if (!route) {
900
+ continue
901
+ }
902
+ const target = typeof route === 'string' ? { path: route } : route
903
+ const href = resolveHref(target, this.$router)
904
+ if (href) {
905
+ links[String(row[this.rowKey])] = { target, href }
906
+ }
907
+ }
908
+ return links
909
+ },
910
+
870
911
  effectiveSortKeys() {
871
912
  if (this.sortKeys && this.sortKeys.length > 0) {
872
913
  return this.sortKeys
@@ -1343,9 +1384,23 @@ export default {
1343
1384
  },
1344
1385
 
1345
1386
  /**
1346
- * Row-body middle click: emits `row-click` like a click, so the host
1347
- * (or `rowClickRoute`) can open the row in a new tab. Ignored for other
1348
- * buttons, nested controls, drags and select-on-click tables.
1387
+ * Row mousedown: record the press for the drag guard, and on a row a
1388
+ * middle click opens, keep the browser from starting autoscroll.
1389
+ *
1390
+ * @param {MouseEvent} event The mousedown event.
1391
+ */
1392
+ onRowMouseDown(event) {
1393
+ this.onPointerDown(event)
1394
+ if (!this.selectable || this.rowClickToView) {
1395
+ preventMiddleClickAutoscroll(event)
1396
+ }
1397
+ },
1398
+
1399
+ /**
1400
+ * Row-body middle click: emits `row-aux-click`, not `row-click`, so an
1401
+ * existing `row-click` listener that navigates never moves the current
1402
+ * tab away; `rowClickRoute` still opens the row in a new tab. Ignored
1403
+ * for other buttons, nested controls, drags and select-on-click tables.
1349
1404
  *
1350
1405
  * @param {object} row The clicked row object
1351
1406
  * @param {MouseEvent} event The originating auxclick event.
@@ -1357,23 +1412,39 @@ export default {
1357
1412
  if (this.selectable && !this.rowClickToView) {
1358
1413
  return
1359
1414
  }
1360
- this.emitRowClick(row, event)
1415
+ /**
1416
+ * @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.
1417
+ * @type {object} The clicked row object.
1418
+ */
1419
+ this.$emit('row-aux-click', row, event)
1420
+ this.followRowClickRoute(row, event)
1361
1421
  },
1362
1422
 
1363
1423
  /**
1364
1424
  * Emit `row-click` and follow `rowClickRoute` when set.
1365
1425
  *
1366
1426
  * @param {object} row The clicked row object
1367
- * @param {MouseEvent} [event] The originating click or auxclick event.
1427
+ * @param {MouseEvent} [event] The originating click event.
1368
1428
  */
1369
1429
  emitRowClick(row, event) {
1370
1430
  /**
1371
- * @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`).
1431
+ * @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.
1372
1432
  * @type {object} The clicked row object.
1373
1433
  */
1374
1434
  this.$emit('row-click', row, event)
1375
- // A ctrl/cmd/shift or middle click opens the route in a new tab,
1376
- // unless a row-click listener already did.
1435
+ this.followRowClickRoute(row, event)
1436
+ },
1437
+
1438
+ /**
1439
+ * Follow `rowClickRoute` for a row click: in place, or in a new tab on
1440
+ * a ctrl/cmd/shift or middle click.
1441
+ *
1442
+ * @param {object} row The clicked row object
1443
+ * @param {MouseEvent} [event] The originating click or auxclick event.
1444
+ */
1445
+ followRowClickRoute(row, event) {
1446
+ // A new-tab click opens the route in a new tab, unless a listener
1447
+ // already did.
1377
1448
  if (this.rowClickRoute && this.$router && !isNewTabHandled(event)) {
1378
1449
  const route = this.rowClickRoute(row)
1379
1450
  if (route) {
@@ -1382,14 +1453,57 @@ export default {
1382
1453
  }
1383
1454
  },
1384
1455
 
1456
+ /**
1457
+ * A plain or alt click on a row link routes in place; a new-tab click
1458
+ * is left to the browser, which opens the href itself.
1459
+ *
1460
+ * @param {object} row The row the link belongs to.
1461
+ * @param {MouseEvent} event The click event.
1462
+ */
1463
+ onRowLinkClick(row, event) {
1464
+ const link = this.rowLinks[String(row[this.rowKey])]
1465
+ if (!link) {
1466
+ return
1467
+ }
1468
+ // Alt-click on a link downloads it; a row opens like a plain click.
1469
+ if (event.altKey && !isNewTabClick(event) && !event.defaultPrevented) {
1470
+ event.preventDefault()
1471
+ this.$router.push(link.target).catch(() => {})
1472
+ return
1473
+ }
1474
+ followLinkClick(event, link.target, this.$router)
1475
+ },
1476
+
1477
+ /**
1478
+ * The row link's accessible name: the row's first cell when it holds
1479
+ * plain text, else a generic name.
1480
+ *
1481
+ * @param {object} row The row.
1482
+ * @param {object} col The first data column.
1483
+ * @return {string}
1484
+ */
1485
+ rowLinkLabel(row, col) {
1486
+ const value = this.cellValue(row, col)
1487
+ if (['string', 'number'].includes(typeof value) && String(value).trim() !== '') {
1488
+ return String(value)
1489
+ }
1490
+ return t('nextcloud-vue', 'Open row')
1491
+ },
1492
+
1385
1493
  /**
1386
1494
  * Row right-click: forward the row + originating event so a host can
1387
- * open a context menu (the browser default is prevented).
1495
+ * open a context menu. The browser menu is prevented, except on a row
1496
+ * link when no host listens, so its link actions stay available.
1388
1497
  *
1389
1498
  * @param {object} row The right-clicked row object.
1390
1499
  * @param {MouseEvent} event The originating contextmenu event.
1391
1500
  */
1392
1501
  onRowContextMenu(row, event) {
1502
+ const fromRowLink = event.target?.closest?.('.cn-table-row__link')
1503
+ // `$.vnode.props`, not `$attrs`: a declared emit is stripped from `$attrs`.
1504
+ if (!fromRowLink || this.$.vnode.props?.onRowContextMenu) {
1505
+ event.preventDefault()
1506
+ }
1393
1507
  /**
1394
1508
  * @event row-context-menu Emitted on a row right-click (contextmenu) for hosts that render a context menu.
1395
1509
  * @type {{ row: object, event: MouseEvent }}