X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a27a325af77e31a184cdb33dc05cb658de697e0b..c8cfec96dc11a3adaed7f7c3545ca35faa5deab3:/resources/js/wysiwyg/ui/defaults/forms/tables.ts diff --git a/resources/js/wysiwyg/ui/defaults/forms/tables.ts b/resources/js/wysiwyg/ui/defaults/forms/tables.ts index a045ba55d..031e00983 100644 --- a/resources/js/wysiwyg/ui/defaults/forms/tables.ts +++ b/resources/js/wysiwyg/ui/defaults/forms/tables.ts @@ -1,16 +1,109 @@ import { EditorFormDefinition, - EditorFormFieldDefinition, + EditorFormFieldDefinition, EditorFormFields, EditorFormTabs, EditorSelectFormFieldDefinition } from "../../framework/forms"; import {EditorUiContext} from "../../framework/core"; -import {setEditorContentFromHtml} from "../../../actions"; +import {EditorFormModal} from "../../framework/modals"; +import {$getSelection} from "lexical"; +import { + $forEachTableCell, $getCellPaddingForTable, + $getTableCellColumnWidth, + $getTableCellsFromSelection, $getTableFromSelection, + $getTableRowsFromSelection, + $setTableCellColumnWidth +} from "../../../utils/tables"; +import {formatSizeValue} from "../../../utils/dom"; +import {TableCellNode, TableNode, TableRowNode} from "@lexical/table"; +import {CommonBlockAlignment} from "lexical/nodes/common"; +import {colorFieldBuilder} from "../../framework/blocks/color-field"; +import {$addCaptionToTable, $isCaptionNode, $tableHasCaption} from "@lexical/table/LexicalCaptionNode"; + +const borderStyleInput: EditorSelectFormFieldDefinition = { + label: 'Border style', + name: 'border_style', + type: 'select', + valuesByLabel: { + 'Select...': '', + "Solid": 'solid', + "Dotted": 'dotted', + "Dashed": 'dashed', + "Double": 'double', + "Groove": 'groove', + "Ridge": 'ridge', + "Inset": 'inset', + "Outset": 'outset', + "None": 'none', + "Hidden": 'hidden', + } +}; + +const borderColorInput: EditorFormFieldDefinition = { + label: 'Border color', + name: 'border_color', + type: 'text', +}; + +const backgroundColorInput: EditorFormFieldDefinition = { + label: 'Background color', + name: 'background_color', + type: 'text', +}; + +const alignmentInput: EditorSelectFormFieldDefinition = { + label: 'Alignment', + name: 'align', + type: 'select', + valuesByLabel: { + 'None': '', + 'Left': 'left', + 'Center': 'center', + 'Right': 'right', + } +}; + +export function $showCellPropertiesForm(cell: TableCellNode, context: EditorUiContext): EditorFormModal { + const styles = cell.getStyles(); + const modalForm = context.manager.createModal('cell_properties'); + modalForm.show({ + width: $getTableCellColumnWidth(context.editor, cell), + height: styles.get('height') || '', + type: cell.getTag(), + h_align: cell.getAlignment(), + v_align: styles.get('vertical-align') || '', + border_width: styles.get('border-width') || '', + border_style: styles.get('border-style') || '', + border_color: styles.get('border-color') || '', + background_color: cell.getBackgroundColor() || styles.get('background-color') || '', + }); + return modalForm; +} export const cellProperties: EditorFormDefinition = { submitText: 'Save', async action(formData, context: EditorUiContext) { - setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || ''); + context.editor.update(() => { + const cells = $getTableCellsFromSelection($getSelection()); + for (const cell of cells) { + const width = formData.get('width')?.toString() || ''; + + $setTableCellColumnWidth(cell, width); + cell.updateTag(formData.get('type')?.toString() || ''); + cell.setAlignment((formData.get('h_align')?.toString() || '') as CommonBlockAlignment); + cell.setBackgroundColor(formData.get('background_color')?.toString() || ''); + + const styles = cell.getStyles(); + styles.set('height', formatSizeValue(formData.get('height')?.toString() || '')); + styles.set('vertical-align', formData.get('v_align')?.toString() || ''); + styles.set('border-width', formatSizeValue(formData.get('border_width')?.toString() || '')); + styles.set('border-style', formData.get('border_style')?.toString() || ''); + styles.set('border-color', formData.get('border_color')?.toString() || ''); + + cell.setStyles(styles); + } + }); + return true; }, fields: [ @@ -18,37 +111,31 @@ export const cellProperties: EditorFormDefinition = { build() { const generalFields: EditorFormFieldDefinition[] = [ { - label: 'Width', + label: 'Width', // Colgroup width name: 'width', type: 'text', }, { - label: 'Height', + label: 'Height', // inline-style: height name: 'height', type: 'text', }, { - label: 'Cell type', + label: 'Cell type', // element name: 'type', type: 'select', valuesByLabel: { - 'Cell': 'cell', - 'Header cell': 'header', + 'Cell': 'td', + 'Header cell': 'th', } } as EditorSelectFormFieldDefinition, { + ...alignmentInput, // class: 'align-right/left/center' label: 'Horizontal align', name: 'h_align', - type: 'select', - valuesByLabel: { - 'None': '', - 'Left': 'left', - 'Center': 'center', - 'Right': 'right', - } - } as EditorSelectFormFieldDefinition, + }, { - label: 'Vertical align', + label: 'Vertical align', // inline-style: vertical-align name: 'v_align', type: 'select', valuesByLabel: { @@ -60,40 +147,181 @@ export const cellProperties: EditorFormDefinition = { } as EditorSelectFormFieldDefinition, ]; - const advancedFields: EditorFormFieldDefinition[] = [ + const advancedFields: EditorFormFields = [ { - label: 'Border width', + label: 'Border width', // inline-style: border-width name: 'border_width', type: 'text', }, + borderStyleInput, // inline-style: border-style + colorFieldBuilder(borderColorInput), + colorFieldBuilder(backgroundColorInput), + ]; + + return new EditorFormTabs([ { - label: 'Border style', - name: 'border_style', - type: 'select', - valuesByLabel: { - 'Select...': '', - "Solid": 'solid', - "Dotted": 'dotted', - "Dashed": 'dashed', - "Double": 'double', - "Groove": 'groove', - "Ridge": 'ridge', - "Inset": 'inset', - "Outset": 'outset', - "None": 'none', - "Hidden": 'hidden', - } - } as EditorSelectFormFieldDefinition, + label: 'General', + contents: generalFields, + }, { - label: 'Border color', - name: 'border_color', + label: 'Advanced', + contents: advancedFields, + } + ]) + } + }, + ], +}; + +export function $showRowPropertiesForm(row: TableRowNode, context: EditorUiContext): EditorFormModal { + const styles = row.getStyles(); + const modalForm = context.manager.createModal('row_properties'); + modalForm.show({ + height: styles.get('height') || '', + border_style: styles.get('border-style') || '', + border_color: styles.get('border-color') || '', + background_color: styles.get('background-color') || '', + }); + return modalForm; +} + +export const rowProperties: EditorFormDefinition = { + submitText: 'Save', + async action(formData, context: EditorUiContext) { + context.editor.update(() => { + const rows = $getTableRowsFromSelection($getSelection()); + for (const row of rows) { + const styles = row.getStyles(); + styles.set('height', formatSizeValue(formData.get('height')?.toString() || '')); + styles.set('border-style', formData.get('border_style')?.toString() || ''); + styles.set('border-color', formData.get('border_color')?.toString() || ''); + styles.set('background-color', formData.get('background_color')?.toString() || ''); + row.setStyles(styles); + } + }); + return true; + }, + fields: [ + // Removed fields: + // Removed 'Row Type' as we don't currently support thead/tfoot elements + // TinyMCE would move rows up/down into these parents when set + // Removed 'Alignment' since this was broken in our editor (applied alignment class to whole parent table) + { + label: 'Height', // style on tr: height + name: 'height', + type: 'text', + }, + borderStyleInput, // style on tr: height + colorFieldBuilder(borderColorInput), + colorFieldBuilder(backgroundColorInput), + ], +}; + +export function $showTablePropertiesForm(table: TableNode, context: EditorUiContext): EditorFormModal { + const styles = table.getStyles(); + const modalForm = context.manager.createModal('table_properties'); + + modalForm.show({ + width: styles.get('width') || '', + height: styles.get('height') || '', + cell_spacing: styles.get('cell-spacing') || '', + cell_padding: $getCellPaddingForTable(table), + border_width: styles.get('border-width') || '', + border_style: styles.get('border-style') || '', + border_color: styles.get('border-color') || '', + background_color: styles.get('background-color') || '', + caption: $tableHasCaption(table) ? 'true' : '', + align: table.getAlignment(), + }); + return modalForm; +} + +export const tableProperties: EditorFormDefinition = { + submitText: 'Save', + async action(formData, context: EditorUiContext) { + context.editor.update(() => { + const table = $getTableFromSelection($getSelection()); + if (!table) { + return; + } + + const styles = table.getStyles(); + styles.set('width', formatSizeValue(formData.get('width')?.toString() || '')); + styles.set('height', formatSizeValue(formData.get('height')?.toString() || '')); + styles.set('cell-spacing', formatSizeValue(formData.get('cell_spacing')?.toString() || '')); + styles.set('border-width', formatSizeValue(formData.get('border_width')?.toString() || '')); + styles.set('border-style', formData.get('border_style')?.toString() || ''); + styles.set('border-color', formData.get('border_color')?.toString() || ''); + styles.set('background-color', formData.get('background_color')?.toString() || ''); + table.setStyles(styles); + + table.setAlignment(formData.get('align') as CommonBlockAlignment); + + const cellPadding = (formData.get('cell_padding')?.toString() || ''); + if (cellPadding) { + const cellPaddingFormatted = formatSizeValue(cellPadding); + $forEachTableCell(table, (cell: TableCellNode) => { + const styles = cell.getStyles(); + styles.set('padding', cellPaddingFormatted); + cell.setStyles(styles); + }); + } + + const showCaption = Boolean(formData.get('caption')?.toString() || ''); + const hasCaption = $tableHasCaption(table); + if (showCaption && !hasCaption) { + $addCaptionToTable(table, context.translate('Caption')); + } else if (!showCaption && hasCaption) { + for (const child of table.getChildren()) { + if ($isCaptionNode(child)) { + child.remove(); + } + } + } + }); + return true; + }, + fields: [ + { + build() { + const generalFields: EditorFormFieldDefinition[] = [ + { + label: 'Width', // Style - width + name: 'width', + type: 'text', + }, + { + label: 'Height', // Style - height + name: 'height', + type: 'text', + }, + { + label: 'Cell spacing', // Style - border-spacing + name: 'cell_spacing', + type: 'text', + }, + { + label: 'Cell padding', // Style - padding on child cells? + name: 'cell_padding', type: 'text', }, { - label: 'Background color', - name: 'background_color', + label: 'Border width', // Style - border-width + name: 'border_width', type: 'text', }, + { + label: 'Show caption', // Caption element + name: 'caption', + type: 'checkbox', + }, + alignmentInput, // alignment class + ]; + + const advancedFields: EditorFormFields = [ + borderStyleInput, + colorFieldBuilder(borderColorInput), + colorFieldBuilder(backgroundColorInput), ]; return new EditorFormTabs([