33 - SPDX-License-Identifier: AGPL-3.0-or-later
44-->
55<template >
6- <div >
7- <ul >
8- <li v-for =" v in getObjects()" :key =" v.id" >
9- {{ v.label }}<span v-if =" v.deleted" :title =" t('tables', 'This option is outdated.')" >  ; ⚠️</span >
10- </li >
11- </ul >
6+ <div class =" cell-multi-selection" >
7+ <div v-if =" !isEditing" class =" non-edit-mode" @click =" startEditing" >
8+ <ul >
9+ <li v-for =" v in getObjects()" :key =" v.id" >
10+ {{ v.label }}<span v-if =" v.deleted" :title =" t('tables', 'This option is outdated.')" >  ; ⚠️</span >
11+ </li >
12+ </ul >
13+ </div >
14+ <div v-else
15+ ref =" editingContainer"
16+ class =" edit-mode"
17+ tabindex =" 0"
18+ @keydown.enter =" saveChanges"
19+ @keydown.escape =" cancelEdit" >
20+ <NcSelect v-model =" editValues "
21+ :tag-width =" 80 "
22+ :options =" getAllNonDeletedOrSelectedOptions "
23+ :multiple =" true "
24+ :aria-label-combobox =" t (' tables' , ' Options' )"
25+ :disabled =" localLoading || ! canEditCell ()"
26+ style =" width : 100% ;" />
27+ <div v-if =" localLoading" class =" loading-indicator" >
28+ <div class =" icon-loading-small icon-loading-inline" />
29+ </div >
30+ </div >
1231 </div >
1332</template >
1433
1534<script >
16-
35+ import { NcSelect } from ' @nextcloud/vue '
1736import { translate as t } from ' @nextcloud/l10n'
37+ import cellEditMixin from ' ../mixins/cellEditMixin.js'
1838
1939export default {
2040 name: ' TableCellMultiSelection' ,
2141
42+ components: {
43+ NcSelect,
44+ },
45+
46+ mixins: [cellEditMixin],
47+
2248 props: {
2349 column: {
2450 type: Object ,
@@ -35,20 +61,125 @@ export default {
3561 default: null ,
3662 },
3763 },
64+
65+ computed: {
66+ getOptions () {
67+ return this .column .selectionOptions || []
68+ },
69+ getAllNonDeletedOrSelectedOptions () {
70+ const options = this .getOptions .filter (item => {
71+ return ! item .deleted || this .optionIdIsSelected (item .id )
72+ }) || []
73+
74+ options .forEach (opt => {
75+ if (opt .deleted ) {
76+ opt .label += ' ⚠️'
77+ }
78+ })
79+ return options
80+ },
81+ },
82+
83+ watch: {
84+ isEditing (isEditing ) {
85+ if (isEditing) {
86+ this .initEditValues ()
87+ // Use a small delay to prevent the same click event that triggered editing
88+ // from immediately triggering the click outside handler
89+ this .$nextTick (() => {
90+ setTimeout (() => {
91+ document .addEventListener (' click' , this .handleClickOutside )
92+ }, 10 )
93+ })
94+ } else {
95+ // Remove click outside listener
96+ document .removeEventListener (' click' , this .handleClickOutside )
97+ }
98+ },
99+ },
100+
38101 methods: {
39102 t,
103+
40104 getObjects () {
41105 return this .column .getObjects (this .value )
42106 },
43- },
44107
108+ optionIdIsSelected (id ) {
109+ // Check if the given id is selected (in the value array)
110+ return this .value && this .value .includes (id)
111+ },
112+
113+ getIdArrayFromObjects (objects ) {
114+ const ids = []
115+ objects .forEach (o => {
116+ ids .push (o .id )
117+ })
118+ return ids
119+ },
120+
121+ initEditValues () {
122+ if (this .value !== null ) {
123+ this .editValues = this .column .getObjects (this .value )
124+ } else {
125+ this .editValues = []
126+ }
127+ },
128+ async saveChanges () {
129+ if (this .localLoading ) {
130+ return
131+ }
132+
133+ const newValue = this .getIdArrayFromObjects (this .editValues )
134+
135+ const success = await this .updateCellValue (newValue)
136+
137+ if (success) {
138+ // Emit the updated value to parent to trigger immediate re-render
139+ this .$emit (' input' , newValue)
140+ this .$emit (' update:value' , newValue)
141+ this .isEditing = false
142+ } else {
143+ this .cancelEdit ()
144+ }
145+
146+ this .localLoading = false
147+ },
148+
149+ handleClickOutside (event ) {
150+ // Check if the click is outside the editing container
151+ if (this .$refs .editingContainer && ! this .$refs .editingContainer .contains (event .target )) {
152+ this .saveChanges ()
153+ }
154+ },
155+ },
45156}
46157 </script >
47158<style lang="scss" scoped>
159+ .cell-multi-selection {
160+ width : 100% ;
161+
162+ .non-edit-mode {
163+ cursor : pointer ;
164+ min-height : 20px ;
165+ }
166+ }
167+
168+ .edit-mode {
169+ .editor-buttons {
170+ display : flex ;
171+ gap : 8px ;
172+ margin-top : 8px ;
173+ align-items : center ;
174+ }
175+
176+ .icon-loading-inline {
177+ margin-left : 4px ;
178+ }
179+ }
48180
49181ul {
50182 list-style-type : disc ;
51183 padding-left : calc (var (--default-grid-baseline ) * 3 );
52184}
53-
54185 </style >
0 commit comments