2626
2727<template >
2828 <AttachmentDragAndDrop v-if =" card" :card-id =" card.id" class =" drop-upload--card" >
29- <div :class =" {'compact': compactMode, 'current-card': currentCard, 'has-labels': card.labels && card.labels.length > 0, 'is-editing': editing, ' card__editable': canEdit, 'card__archived': card.archived }"
29+ <div :class =" {'compact': compactMode, 'current-card': currentCard, 'has-labels': card.labels && card.labels.length > 0, 'card__editable': canEdit, 'card__archived': card.archived }"
3030 tag =" div"
3131 class =" card"
3232 @click =" openCard" >
3939 <h3 v-if =" inlineEditingBlocked" dir =" auto" >
4040 {{ card.title }}
4141 </h3 >
42- <h3 v-else-if = " !editing "
42+ <h3 v-else
4343 dir =" auto"
44- tabindex =" 0"
4544 class =" editable"
46- :aria-label =" t('deck', 'Edit card title')"
47- @keydown.enter.stop.prevent =" startEditing(card)" >
48- <span @click.stop =" startEditing(card)" >{{ card.title }}</span >
45+ :aria-label =" t('deck', 'Edit card title')" >
46+ <span ref =" titleContentEditable"
47+ tabindex =" 0"
48+ contenteditable =" true"
49+ role =" textbox"
50+ @blur =" blurTitle"
51+ @keyup.esc =" cancelEdit"
52+ @keyup.stop >{{ card.title }}</span >
4953 </h3 >
50- <form v-else-if =" editing"
51- v-click-outside =" cancelEdit"
52- class =" dragDisabled"
53- @click.stop
54- @keyup.esc =" cancelEdit"
55- @submit.prevent =" finishedEdit(card)" >
56- <input v-model =" copiedCard.title"
57- v-focus
58- dir =" auto"
59- type =" text"
60- autocomplete =" off"
61- required
62- pattern =" .*\S+.*" >
63- <input type =" submit" value =" " class =" icon-confirm" >
64- </form >
6554
6655 <CardMenu v-if =" showMenuAtTitle" :card =" card" class =" right card-menu" />
6756 </div >
@@ -126,12 +115,6 @@ export default {
126115 default: false ,
127116 },
128117 },
129- data () {
130- return {
131- editing: false ,
132- copiedCard: null ,
133- }
134- },
135118 computed: {
136119 ... mapState ({
137120 compactMode : state => state .compactMode ,
@@ -183,9 +166,6 @@ export default {
183166 return this .$store .getters .config (' cardIdBadge' )
184167 },
185168 showMenuAtTitle () {
186- if (this .editing ) {
187- return false
188- }
189169 return this .compactMode || (! this .compactMode && ! this .hasBadges && ! this .hasLabels )
190170 },
191171 showMenuAtLabels () {
@@ -207,6 +187,12 @@ export default {
207187 this .$nextTick (() => this .$el .scrollIntoView ({ behavior: ' smooth' , block: ' center' , inline: ' center' }))
208188 }
209189 },
190+ ' card.title' (value) {
191+ if (document .activeElement === this .$refs .titleContentEditable || this .$refs .titleContentEditable .textContent === value) {
192+ return
193+ }
194+ this .$refs .titleContentEditable .textContent = value
195+ },
210196 },
211197 methods: {
212198 openCard () {
@@ -216,18 +202,17 @@ export default {
216202 const boardId = this .card && this .card .boardId ? this .card .boardId : this .$route .params .id
217203 this .$router .push ({ name: ' card' , params: { id: boardId, cardId: this .card .id } }).catch (() => {})
218204 },
219- startEditing ( card ) {
220- this . copiedCard = Object . assign ({}, card)
221- this . editing = true
222- },
223- finishedEdit ( card ) {
224- if ( this . copiedCard . title !== card . title ) {
225- this . $store . dispatch ( ' updateCardTitle ' , this . copiedCard )
205+ blurTitle ( e ) {
206+ // TODO Handle empty title
207+ if ( e . target . innerText !== this . card . title ) {
208+ this . $store . dispatch ( ' updateCardTitle ' , {
209+ ... this . card ,
210+ title: e . target . innerText ,
211+ } )
226212 }
227- this .editing = false
228213 },
229214 cancelEdit () {
230- this .editing = false
215+ this .$refs . titleContentEditable . textContent = this . card . title
231216 },
232217 applyLabelFilter (label ) {
233218 if (this .dragging ) {
@@ -279,15 +264,6 @@ export default {
279264
280265 .card - upper {
281266 display: flex;
282- form {
283- display: flex;
284- padding: 3px 5px ;
285- width: 100 % ;
286- input[type= text] {
287- flex- grow: 1 ;
288- }
289-
290- }
291267 h3 {
292268 margin: 0 ;
293269 padding: 6px ;
@@ -300,17 +276,19 @@ export default {
300276 & .editable {
301277 span {
302278 cursor: text;
279+ padding- right: 8px ;
280+
281+ & : focus, & : focus- visible {
282+ outline: none;
283+ }
303284 }
304285
305- & : focus {
286+ & : focus- within {
306287 outline: 2px solid var (-- color- border- dark);
307288 border- radius: 3px ;
308289 }
309290 }
310291 }
311- input[type= text] {
312- font- size: 100 % ;
313- }
314292 .card - menu {
315293 height: 44px ;
316294 align- self : end;
0 commit comments