Skip to content

Commit 0829adb

Browse files
authored
Merge pull request #2095 from nextcloud/polish-inline-editing
enh: Polish inline editing fields
2 parents b92b956 + fad982d commit 0829adb

6 files changed

Lines changed: 89 additions & 110 deletions

File tree

cypress/e2e/column-number-stars.cy.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ describe('Test column stars', () => {
1818
beforeEach(function() {
1919
cy.login(localUser)
2020
cy.visit('apps/tables')
21-
})
22-
23-
it('Table and column setup', () => {
2421
cy.createTable(tableTitle)
2522
})
2623

@@ -29,22 +26,23 @@ describe('Test column stars', () => {
2926
cy.createNumberStarsColumn(columnTitle, 2, true)
3027

3128
// insert default value row
32-
cy.get('button').contains('Create row').click()
33-
cy.get('.modal__content').contains('★★☆☆☆').should('be.visible')
34-
cy.get('button').contains('Save').click()
35-
cy.get('.custom-table table tr td div').contains('★★☆☆☆').should('be.visible')
29+
cy.get('[data-cy="createRowBtn"]').click()
30+
cy.get('[data-cy="createRowModal"] .stars').contains('★★☆☆☆').should('be.visible')
31+
cy.get('[data-cy="createRowSaveButton"]').click()
32+
cy.get('.custom-table table tr td .interactive-stars .star.filled').should('have.length', 2)
33+
cy.get('.custom-table table tr td .interactive-stars').should('contain', '★').and('contain', '☆')
3634

3735
// insert row
38-
cy.get('button').contains('Create row').click()
36+
cy.get('[data-cy="createRowBtn"]').click()
3937
cy.get('.slot button').last().click().click()
40-
cy.get('button').contains('Save').click()
41-
cy.get('.custom-table table tr td div').contains('★★★★☆').should('be.visible')
38+
cy.get('[data-cy="createRowSaveButton"]').click()
39+
cy.get('.custom-table table tr').last().find('.star.filled').should('have.length', 4)
4240

4341
// insert row
44-
cy.get('button').contains('Create row').click()
42+
cy.get('[data-cy="createRowBtn"]').click()
4543
cy.get('.slot button').first().click().click()
46-
cy.get('button').contains('Save').click()
47-
cy.get('.custom-table table tr td div').contains('☆☆☆☆☆').should('be.visible')
44+
cy.get('[data-cy="createRowSaveButton"]').click()
45+
cy.get('.custom-table table tr').last().find('.star.filled').should('have.length', 0)
4846
})
4947

5048
})

src/shared/components/ncTable/partials/RichEditor.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,12 @@ export default {
115115
<style lang="scss" scoped>
116116
.rich-editor-edit-mode {
117117
position: relative;
118-
border: 1px solid var(--color-border-maxcontrast);
118+
border: 2px solid var(--color-border-maxcontrast);
119+
min-height: 24px;
120+
121+
:deep(.smart-picker-menu-container) {
122+
display: none;
123+
}
119124
}
120125
121126
.loading-indicator {

src/shared/components/ncTable/partials/TableCellEditor.vue

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
-->
55
<template>
66
<div class="cell-editor" :style="{ opacity: !canEditCell() ? 0.6 : 1 }">
7-
<div v-if="!isEditing" @click="handleStartEditing">
7+
<div v-show="!isEditing" class="cell-display-mode" @click="handleStartEditing">
88
<NcEditor v-if="value && value.trim()"
99
:can-edit="false"
1010
:text="value"
1111
:show-border="false"
1212
:show-readonly-bar="false" />
1313
</div>
14-
<RichEditor v-else
14+
<RichEditor v-show="isEditing"
1515
ref="richEditor"
1616
:value="value"
1717
:loading="localLoading"
@@ -109,11 +109,24 @@ export default {
109109
<style lang="scss" scoped>
110110
.cell-editor {
111111
width: 100%;
112+
position: relative;
112113
}
113114
114-
.cell-editor > div {
115+
.cell-display-mode {
115116
cursor: pointer;
116117
min-height: 24px;
118+
border: 2px solid transparent;
119+
position: relative;
120+
121+
:deep(.content-wrapper) {
122+
padding-left: 22px;
123+
}
124+
}
125+
126+
.cell-display-mode,
127+
:deep(.rich-editor-edit-mode) {
128+
width: 100%;
129+
min-height: 24px;
117130
}
118131
119132
:deep(.text-editor__wrapper div.ProseMirror) {

src/shared/components/ncTable/partials/TableCellStars.vue

Lines changed: 54 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -4,90 +4,81 @@
44
-->
55
<template>
66
<div class="cell-stars" :style="{ opacity: !canEditCell() ? 0.6 : 1 }">
7-
<div v-if="!isEditing" @click="startEditing">
8-
<div class="stars-display">
9-
{{ getValue }}
10-
</div>
11-
</div>
12-
<div v-else
13-
ref="editingContainer"
14-
class="inline-editing-container"
15-
tabindex="0"
16-
@keydown.enter="saveChanges"
17-
@keydown.escape="cancelEdit">
18-
<div class="align-center" :class="{ 'is-loading': localLoading }">
19-
<div class="clickable-stars">
20-
<span v-for="star in 5"
21-
:key="star"
22-
class="star"
23-
:class="{ 'filled': star <= editValue, 'clickable': !localLoading && canEditCell() }"
24-
:aria-label="t('tables', 'Set {star} stars', { star })"
25-
@click="setStar(star)">
26-
{{ star <= editValue ? '★' : '☆' }}
27-
</span>
28-
</div>
29-
<div v-if="localLoading" class="icon-loading-small icon-loading-inline" />
7+
<div class="inline-editing-container">
8+
<div class="interactive-stars"
9+
@mouseleave="hoverValue = null">
10+
<span v-for="star in 5"
11+
:key="star"
12+
class="star"
13+
:class="{
14+
'filled': star <= displayValue,
15+
'clickable': isClickable,
16+
'hovering': hoverValue !== null
17+
}"
18+
:aria-label="t('tables', 'Set {star} stars', { star })"
19+
@mouseenter="hoverValue = star"
20+
@click="setStar(star)">
21+
{{ star <= displayValue ? '★' : '☆' }}
22+
</span>
3023
</div>
24+
<div v-if="localLoading" class="icon-loading-small icon-loading-inline" />
3125
</div>
3226
</div>
3327
</template>
3428

3529
<script>
36-
import cellEditMixin from '../mixins/cellEditMixin.js'
3730
import { translate as t } from '@nextcloud/l10n'
31+
import cellEditMixin from '../mixins/cellEditMixin.js'
3832
3933
export default {
4034
name: 'TableCellStars',
4135
4236
mixins: [cellEditMixin],
4337
4438
props: {
45-
column: {
46-
type: Object,
47-
default: () => {},
48-
},
49-
rowId: {
50-
type: Number,
51-
default: null,
52-
},
5339
value: {
5440
type: Number,
5541
default: 0,
5642
},
5743
},
5844
45+
data() {
46+
return {
47+
hoverValue: null,
48+
editValue: this.value,
49+
}
50+
},
51+
5952
computed: {
60-
getValue() {
61-
const starEmpty = ''
62-
const starFull = ''
63-
const v = this.value
64-
return starFull.repeat(v) + starEmpty.repeat(5 - v)
53+
displayValue() {
54+
return this.hoverValue !== null ? this.hoverValue : this.editValue
55+
},
56+
57+
isClickable() {
58+
return !this.localLoading && this.canEditCell()
6559
},
6660
},
6761
6862
watch: {
69-
isEditing(newValue) {
70-
if (newValue) {
71-
this.$nextTick(() => {
72-
document.addEventListener('click', this.handleClickOutside)
73-
})
74-
} else {
75-
document.removeEventListener('click', this.handleClickOutside)
76-
}
63+
value(newValue) {
64+
this.editValue = newValue
7765
},
7866
},
7967
8068
methods: {
8169
t,
8270
8371
setStar(starNumber) {
84-
if (!this.localLoading && this.canEditCell()) {
72+
if (this.isClickable) {
8573
// If clicking on a star that represents the current rating, clear to 0
86-
if (starNumber === this.editValue) {
74+
if (starNumber === this.value) {
8775
this.editValue = 0
8876
} else {
8977
this.editValue = starNumber
9078
}
79+
80+
this.hoverValue = null
81+
this.saveChanges()
9182
}
9283
},
9384
@@ -97,25 +88,16 @@ export default {
9788
}
9889
9990
if (this.editValue === this.value) {
100-
this.isEditing = false
10191
return
10292
}
10393
10494
const success = await this.updateCellValue(this.editValue)
10595
10696
if (!success) {
107-
this.cancelEdit()
97+
this.editValue = this.value
10898
}
10999
110100
this.localLoading = false
111-
this.isEditing = false
112-
},
113-
114-
handleClickOutside(event) {
115-
// Check if the click is outside the editing container
116-
if (this.$refs.editingContainer && !this.$refs.editingContainer.contains(event.target)) {
117-
this.saveChanges()
118-
}
119101
},
120102
},
121103
}
@@ -126,45 +108,35 @@ export default {
126108
width: 100%;
127109
}
128110
129-
.cell-stars > div:first-child {
130-
cursor: pointer;
131-
}
132-
133-
.stars-display {
134-
font-size: 20px;
135-
cursor: pointer;
136-
}
137-
138-
.align-center {
139-
align-items: center;
111+
.inline-editing-container {
140112
display: flex;
141-
142-
&.is-loading {
143-
opacity: 0.7;
144-
}
113+
align-items: center;
145114
}
146115
147-
.clickable-stars {
116+
.interactive-stars {
148117
display: flex;
149118
align-items: center;
150-
gap: 2px;
119+
gap: 0;
151120
}
152121
153122
.star {
154-
font-size: 1.4em;
155-
padding: 4px;
156-
transition: transform 0.1s ease;
123+
font-size: 20px;
124+
color: var(--color-main-text);
125+
padding: 0;
126+
transition: color 0.1s ease;
157127
158128
&.clickable {
159129
cursor: pointer;
160-
161-
&:hover {
162-
transform: scale(1.1);
163-
}
164130
}
165131
166132
&.filled {
167-
color: var(--color-warning);
133+
color: var(--color-main-text);
134+
}
135+
136+
&.hovering {
137+
&.filled {
138+
color: var(--color-text-maxcontrast);
139+
}
168140
}
169141
}
170142

src/shared/components/ncTable/partials/TableCellTextLine.vue

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{{ value || '' }}
99
</div>
1010
<div v-else class="inline-editing-container">
11-
<NcTextField v-model="editValue" :aria-label="t('tables', 'Cell input')" :disabled="localLoading || !canEditCell()" class="cell-input"
11+
<NcTextField ref="input" v-model="editValue" :aria-label="t('tables', 'Cell input')" :disabled="localLoading || !canEditCell()" class="cell-input"
1212
@keyup.enter="saveChanges" @keyup.esc="cancelEdit" @blur="saveChanges" />
1313
<div v-if="localLoading" class="icon-loading-small icon-loading-inline" />
1414
</div>
@@ -26,16 +26,6 @@ export default {
2626
NcTextField,
2727
},
2828
29-
filters: {
30-
truncate(string, num) {
31-
if (string?.length >= num) {
32-
return string.substring(0, num) + '...'
33-
} else {
34-
return string
35-
}
36-
},
37-
},
38-
3929
mixins: [cellEditMixin],
4030
4131
props: {

src/shared/components/ncTable/sections/CustomTable.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ export default {
566566
.inline-editing-container {
567567
position: relative;
568568
width: 100%;
569+
overflow-y: hidden;
569570
570571
.cell-input {
571572
width: 100%;

0 commit comments

Comments
 (0)