diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index c49476eefc..6cc4735807 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -1086,6 +1086,7 @@ "to_add_more_collaborators": "", "to_change_access_permissions": "", "to_confirm_transfer_enter_email_address": "", + "to_insert_or_move_a_caption_make_sure_tabular_is_directly_within_table": "", "to_modify_your_subscription_go_to": "", "toggle_compile_options_menu": "", "token": "", diff --git a/services/web/frontend/js/features/source-editor/components/table-generator/contexts/table-context.tsx b/services/web/frontend/js/features/source-editor/components/table-generator/contexts/table-context.tsx index d2dbaa512a..6b0557afb7 100644 --- a/services/web/frontend/js/features/source-editor/components/table-generator/contexts/table-context.tsx +++ b/services/web/frontend/js/features/source-editor/components/table-generator/contexts/table-context.tsx @@ -29,6 +29,7 @@ const TableContext = createContext< tableEnvironment?: TableEnvironmentData rows: number columns: number + directTableChild?: boolean } | undefined >(undefined) @@ -38,7 +39,15 @@ export const TableProvider: FC<{ tableNode: SyntaxNode | null tabularNode: SyntaxNode view: EditorView -}> = ({ tableData, children, tableNode, tabularNode, view }) => { + directTableChild?: boolean +}> = ({ + tableData, + children, + tableNode, + tabularNode, + view, + directTableChild, +}) => { try { const positions: Positions = { cells: tableData.cellPositions, @@ -59,6 +68,7 @@ export const TableProvider: FC<{ tableEnvironment, rows: tableData.table.rows.length, columns: tableData.table.columns.length, + directTableChild, }} > {children} diff --git a/services/web/frontend/js/features/source-editor/components/table-generator/tabular.tsx b/services/web/frontend/js/features/source-editor/components/table-generator/tabular.tsx index 81296a641e..7c114b805a 100644 --- a/services/web/frontend/js/features/source-editor/components/table-generator/tabular.tsx +++ b/services/web/frontend/js/features/source-editor/components/table-generator/tabular.tsx @@ -227,7 +227,8 @@ export const Tabular: FC<{ view: EditorView tableNode: SyntaxNode | null parsedTableData: ParsedTableData -}> = ({ tabularNode, view, tableNode, parsedTableData }) => { + directTableChild?: boolean +}> = ({ tabularNode, view, tableNode, parsedTableData, directTableChild }) => { return ( ( @@ -241,6 +242,7 @@ export const Tabular: FC<{ tabularNode={tabularNode} tableData={parsedTableData} tableNode={tableNode} + directTableChild={directTableChild} view={view} > diff --git a/services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar-dropdown.tsx b/services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar-dropdown.tsx index c33c72e14b..ac9a044131 100644 --- a/services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar-dropdown.tsx +++ b/services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar-dropdown.tsx @@ -81,10 +81,17 @@ export const ToolbarDropdown: FC<{ ) - if (!tooltip) { + if (tooltip || (disabled && disabledTooltip)) { return ( <> - {button} + {overlay} ) @@ -92,14 +99,7 @@ export const ToolbarDropdown: FC<{ return ( <> - + {button} {overlay} ) diff --git a/services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar.tsx b/services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar.tsx index 5d72f45009..7f7505bc52 100644 --- a/services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar.tsx +++ b/services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar.tsx @@ -26,8 +26,14 @@ import { useTranslation } from 'react-i18next' export const Toolbar = memo(function Toolbar() { const { selection, setSelection } = useSelectionContext() const view = useCodeMirrorViewContext() - const { positions, rowSeparators, cellSeparators, tableEnvironment, table } = - useTableContext() + const { + positions, + rowSeparators, + cellSeparators, + tableEnvironment, + table, + directTableChild, + } = useTableContext() const { showHelp } = useTabularContext() const { t } = useTranslation() @@ -64,7 +70,10 @@ export const Toolbar = memo(function Toolbar() { { nodeRef.type.is('TabularEnvironment') ) { if (shouldDecorate(state, nodeRef)) { + const tabularNode = nodeRef.node const tableNode = ancestorOfNodeWithType( - nodeRef.node, + tabularNode, 'TableEnvironment' ) + const directChild = isDirectChildOfEnvironment( + tabularNode.parent, + tableNode + ) const tabularWidget = new TabularWidget( - nodeRef.node, + tabularNode, state.doc.sliceString( - (tableNode ?? nodeRef).from, - (tableNode ?? nodeRef).to + (tableNode ?? tabularNode).from, + (tableNode ?? tabularNode).to ), tableNode, + directChild, state ) diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/tabular.tsx b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/tabular.tsx index 7b7e896941..c4e2c6e043 100644 --- a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/tabular.tsx +++ b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/tabular.tsx @@ -16,6 +16,7 @@ export class TabularWidget extends WidgetType { private tabularNode: SyntaxNode, private content: string, private tableNode: SyntaxNode | null, + private isDirectChildOfTableEnvironment: boolean, state: EditorState ) { super() @@ -64,6 +65,7 @@ export class TabularWidget extends WidgetType { tabularNode={this.tabularNode} parsedTableData={this.parseResult} tableNode={this.tableNode} + directTableChild={this.isDirectChildOfTableEnvironment} />, this.element ) @@ -91,6 +93,7 @@ export class TabularWidget extends WidgetType { tabularNode={this.tabularNode} parsedTableData={this.parseResult} tableNode={this.tableNode} + directTableChild={this.isDirectChildOfTableEnvironment} />, this.element ) diff --git a/services/web/frontend/js/features/source-editor/utils/tree-operations/ancestors.ts b/services/web/frontend/js/features/source-editor/utils/tree-operations/ancestors.ts index 141296461e..00aeb158fb 100644 --- a/services/web/frontend/js/features/source-editor/utils/tree-operations/ancestors.ts +++ b/services/web/frontend/js/features/source-editor/utils/tree-operations/ancestors.ts @@ -278,3 +278,11 @@ export const minimumListDepthForSelection = (state: EditorState) => { } return Math.min(...depths) } + +export const isDirectChildOfEnvironment = ( + child?: SyntaxNode | null, + ancestor?: SyntaxNode | null +) => { + const possiblyAncestor = child?.parent?.parent?.parent // Text → Content → Environment + return ancestor === possiblyAncestor +} diff --git a/services/web/locales/en.json b/services/web/locales/en.json index d196c7daa6..a8c3d98a22 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1722,6 +1722,7 @@ "to_add_more_collaborators": "To add more collaborators or turn on link sharing, please ask the project owner", "to_change_access_permissions": "To change access permissions, please ask the project owner", "to_confirm_transfer_enter_email_address": "To accept the invitation, enter the email address linked to your account.", + "to_insert_or_move_a_caption_make_sure_tabular_is_directly_within_table": "To insert or move a caption, make sure \\begin{tabular} is directly within a table environment", "to_many_login_requests_2_mins": "This account has had too many login requests. Please wait 2 minutes before trying to log in again", "to_modify_your_subscription_go_to": "To modify your subscription go to", "toggle_compile_options_menu": "Toggle compile options menu", diff --git a/services/web/test/frontend/features/source-editor/components/codemirror-editor-table-generator.spec.tsx b/services/web/test/frontend/features/source-editor/components/codemirror-editor-table-generator.spec.tsx index 45f07a045e..4c885e0c0c 100644 --- a/services/web/test/frontend/features/source-editor/components/codemirror-editor-table-generator.spec.tsx +++ b/services/web/test/frontend/features/source-editor/components/codemirror-editor-table-generator.spec.tsx @@ -413,8 +413,21 @@ cell 3 & cell 4 \\\\ }) }) - // Removes caption when clicking "No caption" cy.get('@toolbar').findByText('Caption below').click() + cy.get('.table-generator-toolbar-dropdown-menu') + .findByText('Caption above') + .click() + // Check that caption is above table + cy.get('.ol-cm-command-caption').then(([caption]) => { + const { top: captionYPosition } = caption.getBoundingClientRect() + cy.get('.table-generator').then(([table]) => { + const { top: tableYPosition } = table.getBoundingClientRect() + cy.wrap(captionYPosition).should('be.lessThan', tableYPosition) + }) + }) + + // Removes caption when clicking "No caption" + cy.get('@toolbar').findByText('Caption above').click() cy.get('.table-generator-toolbar-dropdown-menu') .findByText('No caption') .click() @@ -445,5 +458,23 @@ cell 3 & cell 4 \\\\ ]) checkBordersWithNoMultiColumn([true, true, true], [true, true, true]) }) + + it('Disables caption dropdown when not directly inside table environment', function () { + mountEditor(` +\\begin{table} + \\caption{Table caption} + \\label{tab:table} + \\begin{adjustbox}{max width=\\textwidth} + \\begin{tabular}{c} + cell 1 + \\end{tabular} + \\end{adjustbox} +\\end{table}`) + cy.get('.table-generator').findByText('cell 1').click() + cy.get('.table-generator-floating-toolbar').as('toolbar').should('exist') + cy.get('@toolbar') + .contains('button', 'Caption above') + .should('be.disabled') + }) }) })