Skip to content

Commit

Permalink
feat(table): add row, column buttons outside of table
Browse files Browse the repository at this point in the history
Signed-off-by: Luka Trovic <luka@nextcloud.com>
  • Loading branch information
luka-nextcloud committed Oct 17, 2024
1 parent 1d2f4cc commit ae3ed5a
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/css/prosemirror.scss
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,10 @@ div.ProseMirror {

table {
border-spacing: 0;
width: calc(100% - 50px);
width: calc(100% - 84px);
table-layout: auto;
white-space: normal; // force text to wrapping
margin-bottom: 1em;
margin-bottom: 4em;
&+ * {
margin-top: 1em;
}
Expand Down
12 changes: 12 additions & 0 deletions src/nodes/Table/TableCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { TableCell } from '@tiptap/extension-table-cell'
import { Plugin } from '@tiptap/pm/state'
import { Fragment } from '@tiptap/pm/model'
import { mergeAttributes } from '@tiptap/core'

export default TableCell.extend({
content: 'inline*',
Expand Down Expand Up @@ -58,6 +59,17 @@ export default TableCell.extend({
}
},

renderHTML({ HTMLAttributes }) {
const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)
if (attributes.colspan === 1) {
delete attributes.colspan
}
if (attributes.rowspan === 1) {
delete attributes.rowspan
}
return ['td', attributes, 0]
},

addProseMirrorPlugins() {
return [
new Plugin({
Expand Down
12 changes: 12 additions & 0 deletions src/nodes/Table/TableHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { TableHeader } from '@tiptap/extension-table-header'
import { mergeAttributes } from '@tiptap/core'

export default TableHeader.extend({
content: 'inline*',
Expand Down Expand Up @@ -39,6 +40,17 @@ export default TableHeader.extend({
]
},

renderHTML({ HTMLAttributes }) {
const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)
if (attributes.colspan === 1) {
delete attributes.colspan
}
if (attributes.rowspan === 1) {
delete attributes.rowspan
}
return ['th', attributes, 0]
},

addAttributes() {
return {
...this.parent?.(),
Expand Down
95 changes: 91 additions & 4 deletions src/nodes/Table/TableView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
-->

<template>
<NodeViewWrapper data-text-el="table-view" class="table-wrapper">
<NodeViewWrapper data-text-el="table-view" class="table-wrapper" :class="{ 'focused': isFocused }">
<NcActions v-if="isEditable"
force-menu
data-text-table-actions="settings"
Expand All @@ -22,20 +22,41 @@
</NcActionButton>
</NcActions>
<NodeViewContent class="content" as="table" />
<NcButton v-if="isEditable"
class="table-add-column"
:aria-label="t('text', 'Add column after')"
:title="t('text', 'Add column after')"
@click="addColumnAfter">
<template #icon>
<TableAddColumnAfter />
</template>
</NcButton>
<NcButton v-if="isEditable"
class="table-add-row"
:aria-label="t('text', 'Add row after')"
:title="t('text', 'Add row after')"
@click="addRowAfter">
<template #icon>
<TableAddRowAfter />
</template>
</NcButton>
<div class="clearfix" />
</NodeViewWrapper>
</template>

<script>
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2'
import { NcActions, NcActionButton } from '@nextcloud/vue'
import { TableSettings, Delete } from '../../components/icons.js'
import { NcActions, NcActionButton, NcButton } from '@nextcloud/vue'
import { TableSettings, Delete, TableAddColumnAfter, TableAddRowAfter } from '../../components/icons.js'
export default {
name: 'TableView',
components: {
TableAddColumnAfter,
TableAddRowAfter,
NcActionButton,
NcActions,
NcButton,
NodeViewWrapper,
NodeViewContent,
TableSettings,
Expand All @@ -50,25 +71,60 @@ export default {
type: Function,
required: true,
},
node: {
type: Object,
required: true,
},
},
data() {
return {
isEditable: false,
isFocused: false,
}
},
beforeMount() {
this.isEditable = this.editor.isEditable
this.editor.on('selectionUpdate', ({ editor }) => {
const startOfCurrentNode = this.getPos()
const endOfCurrentNode = startOfCurrentNode + this.node.nodeSize
const { from, to } = editor.state.selection
this.isFocused = from >= startOfCurrentNode && to <= endOfCurrentNode
})
this.editor.on('update', ({ editor }) => {
this.isEditable = editor.isEditable
})
},
methods: {
addColumnAfter() {
const headerRowNode = this.node.firstChild
this.editor.chain()
.focus()
.setTextSelection(this.getPos() + headerRowNode.nodeSize - 1)
.addColumnAfter()
.run()
},
addRowAfter() {
const lastRowNode = this.node.lastChild
this.editor.chain()
.focus()
.setTextSelection(this.getPos() + this.node?.nodeSize - lastRowNode.nodeSize + 1)
.addRowAfter()
.run()
},
},
}
</script>
<style scoped lang="scss">
.table-wrapper {
position: relative;
overflow-x: auto;
&.focused {
.table-add-column, .table-add-row {
visibility: unset;
}
}
}
.clearfix {
Expand All @@ -84,10 +140,41 @@ table {
opacity: .5;
position: absolute;
top: 0;
right: 3px;
right: var(--default-clickable-area);
&:hover {
opacity: 1;
}
}
.table-add-column {
visibility: hidden;
padding-left: 3px;
opacity: .5;
position: absolute;
top: var(--default-clickable-area);
right: 0;
bottom: 60px;
margin-top: 0 !important;
&:hover {
opacity: 1;
visibility: unset;
}
}
.table-add-row {
visibility: hidden;
padding-left: 3px;
opacity: .5;
position: absolute;
left: 0;
bottom: 12px;
width: calc(100% - 80px) !important;
&:hover {
opacity: 1;
visibility: unset;
}
}
</style>
40 changes: 20 additions & 20 deletions src/tests/fixtures/tables/handbook/handbook.out.html
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
<div class="table-wrapper" style="overflow-x: auto;">
<table>
<tr>
<th colspan="1" rowspan="1"><strong>Heading 0</strong></th>
<th colspan="1" rowspan="1"><strong>Heading 1</strong></th>
<th colspan="1" rowspan="1"><strong>Heading 2</strong></th>
<th colspan="1" rowspan="1"><strong>Heading 3</strong></th>
<th colspan="1" rowspan="1"><strong>Heading 4</strong></th>
<th><strong>Heading 0</strong></th>
<th><strong>Heading 1</strong></th>
<th><strong>Heading 2</strong></th>
<th><strong>Heading 3</strong></th>
<th><strong>Heading 4</strong></th>
</tr>
<tr>
<td colspan="1" rowspan="1"><strong>Letter</strong></td>
<td colspan="1" rowspan="1">a</td>
<td colspan="1" rowspan="1">b</td>
<td colspan="1" rowspan="1">c</td>
<td colspan="1" rowspan="1">d</td>
<td><strong>Letter</strong></td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
</tr>
<tr>
<td colspan="1" rowspan="1"><strong>Number</strong></td>
<td colspan="1" rowspan="1">1</td>
<td colspan="1" rowspan="1">2</td>
<td colspan="1" rowspan="1">3</td>
<td colspan="1" rowspan="1">4</td>
<td><strong>Number</strong></td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td colspan="1" rowspan="1"><strong>Square</strong></td>
<td colspan="1" rowspan="1">1</td>
<td colspan="1" rowspan="1">4</td>
<td colspan="1" rowspan="1">9</td>
<td colspan="1" rowspan="1">16</td>
<td><strong>Square</strong></td>
<td>1</td>
<td>4</td>
<td>9</td>
<td>16</td>
</tr>
</table>
</div>
Expand Down

0 comments on commit ae3ed5a

Please sign in to comment.