Skip to content

Commit 286ef04

Browse files
authored
Merge pull request #519 from Harbour-Enterprises/artem-highlight
HAR-9709, HAR-9712 - highlight for field annotation and table cell
2 parents 26b4f4d + 1d68998 commit 286ef04

7 files changed

Lines changed: 166 additions & 22 deletions

File tree

packages/super-editor/src/components/toolbar/super-toolbar.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,17 @@ export class SuperToolbar extends EventEmitter {
124124
},
125125

126126
setColor: ({ item, argument }) => {
127-
this.#runCommandWithArgumentOnly({ item, argument });
127+
this.#runCommandWithArgumentOnly({ item, argument }, () => {
128+
this.activeEditor?.commands.setFieldAnnotationsTextColor(argument, true);
129+
});
128130
},
129131

130132
setHighlight: ({ item, argument }) => {
131-
this.#runCommandWithArgumentOnly({ item, argument });
133+
this.#runCommandWithArgumentOnly({ item, argument, noArgumentCallback: true }, () => {
134+
let arg = argument !== 'none' ? argument : null;
135+
this.activeEditor?.commands.setFieldAnnotationsTextHighlight(arg, true);
136+
this.activeEditor?.commands.setCellBackground(arg);
137+
});
132138
},
133139

134140
toggleRuler: ({ item, argument }) => {
@@ -461,14 +467,15 @@ export class SuperToolbar extends EventEmitter {
461467
}
462468
}
463469

464-
#runCommandWithArgumentOnly({ item, argument }, callback) {
470+
#runCommandWithArgumentOnly({ item, argument, noArgumentCallback = false }, callback) {
465471
if (!argument || !this.activeEditor) return;
466472

467473
let command = item.command;
468474
const noArgumentCommand = item.noArgumentCommand;
469475

470476
if (argument === 'none' && noArgumentCommand in this.activeEditor?.commands) {
471477
this.activeEditor.commands[noArgumentCommand]();
478+
if (typeof callback === 'function' && noArgumentCallback) callback(argument);
472479
this.updateToolbarState();
473480
return;
474481
}

packages/super-editor/src/core/helpers/getActiveFormatting.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,26 @@ export function getActiveFormatting(editor) {
4747
marksToProcess.push({ name: key, attrs });
4848
});
4949

50+
// For fieldAnnotation.
51+
const textColor = marksToProcess.find((i) => i.name === 'textColor');
52+
const textHightlight = marksToProcess.find((i) => i.name === 'textHighlight');
53+
54+
if (textColor) {
55+
marksToProcess.push({
56+
name: 'color',
57+
attrs: { color: textColor.attrs?.textColor },
58+
});
59+
}
60+
if (textHightlight) {
61+
marksToProcess.push({
62+
name: 'highlight',
63+
attrs: { color: textHightlight.attrs?.textHighlight },
64+
});
65+
}
66+
5067
const hasPendingFormatting = !!editor.storage.formatCommands?.storedStyle;
5168
if (hasPendingFormatting) marksToProcess.push({ name: 'copyFormat', attrs: true });
69+
5270
return marksToProcess;
5371
}
5472

packages/super-editor/src/core/super-converter/exporter.js

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,8 @@ const translateFieldAttrsToMarks = (attrs = {}) => {
18301830
bold,
18311831
underline,
18321832
italic,
1833+
textColor,
1834+
textHighlight,
18331835
} = attrs;
18341836

18351837
const marks = [];
@@ -1838,6 +1840,8 @@ const translateFieldAttrsToMarks = (attrs = {}) => {
18381840
if (bold) marks.push({ type: 'bold', attrs: {} });
18391841
if (underline) marks.push({ type: 'underline', attrs: {} });
18401842
if (italic) marks.push({ type: 'italic', attrs: {} });
1843+
if (textColor) marks.push({ type: 'color', attrs: { color: textColor } });
1844+
if (textHighlight) marks.push({ type: 'highlight', attrs: { color: textHighlight } });
18411845
return marks;
18421846
};
18431847

@@ -1918,6 +1922,20 @@ function translateFieldAnnotation(params) {
19181922
'w:val': attrs.fontSize,
19191923
},
19201924
},
1925+
{
1926+
name: 'w:fieldTextColor',
1927+
attributes: {
1928+
'xmlns:w': customXmlns,
1929+
'w:val': attrs.textColor,
1930+
},
1931+
},
1932+
{
1933+
name: 'w:fieldTextHighlight',
1934+
attributes: {
1935+
'xmlns:w': customXmlns,
1936+
'w:val': attrs.textHighlight,
1937+
},
1938+
},
19211939
],
19221940
},
19231941
{
@@ -2128,7 +2146,7 @@ function resizeKeepAspectRatio(width, height, maxWidth) {
21282146

21292147
function applyMarksToHtmlAnnotation(state, marks) {
21302148
const { tr, doc, schema } = state;
2131-
const allowedMarks = ['fontFamily', 'fontSize'];
2149+
const allowedMarks = ['fontFamily', 'fontSize', 'highlight'];
21322150

21332151
if (
21342152
!marks.some((m) => allowedMarks.includes(m.type))
@@ -2138,32 +2156,41 @@ function applyMarksToHtmlAnnotation(state, marks) {
21382156

21392157
const fontFamily = marks.find((m) => m.type === 'fontFamily');
21402158
const fontSize = marks.find((m) => m.type === 'fontSize');
2159+
const highlight = marks.find((m) => m.type === 'highlight');
2160+
2161+
const textStyleType = schema.marks.textStyle;
2162+
const highlightType = schema.marks.highlight;
21412163

21422164
doc.descendants((node, pos) => {
21432165
if (!node.isText) return;
21442166

2145-
const found = node.marks.find((m) => m.type.name === 'textStyle');
2146-
const textStyleType = schema.marks.textStyle;
2147-
2148-
if (!found) {
2167+
const foundTextStyle = node.marks.find((m) => m.type.name === 'textStyle');
2168+
const foundHighlight = node.marks.find((m) => m.type.name === 'highlight');
2169+
2170+
// text style (fontFamily, fontSize)
2171+
if (!foundTextStyle) {
21492172
tr.addMark(pos, pos + node.nodeSize, textStyleType.create({
21502173
...fontFamily?.attrs,
21512174
...fontSize?.attrs,
21522175
}));
2153-
return;
2154-
}
2155-
2156-
if (!found?.attrs.fontFamily && fontFamily) {
2176+
} else if (!foundTextStyle?.attrs.fontFamily && fontFamily) {
21572177
tr.addMark(pos, pos + node.nodeSize, textStyleType.create({
2158-
...found?.attrs,
2178+
...foundTextStyle?.attrs,
21592179
...fontFamily.attrs,
21602180
}));
2161-
} else if (!found?.attrs.fontSize && fontSize) {
2181+
} else if (!foundTextStyle?.attrs.fontSize && fontSize) {
21622182
tr.addMark(pos, pos + node.nodeSize, textStyleType.create({
2163-
...found?.attrs,
2183+
...foundTextStyle?.attrs,
21642184
...fontSize.attrs,
21652185
}));
21662186
}
2187+
2188+
// highlight
2189+
if (!foundHighlight) {
2190+
tr.addMark(pos, pos + node.nodeSize, highlightType.create({
2191+
...highlight?.attrs,
2192+
}));
2193+
}
21672194
});
21682195

21692196
return state.apply(tr);

packages/super-editor/src/core/super-converter/v2/importer/annotationImporter.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export const handleAnnotationNode = (params) => {
2828
const isMultipleImage = sdtPr?.elements.find((el) => el.name === 'w:fieldMultipleImage')?.attributes['w:val'];
2929
const fontFamily = sdtPr?.elements.find((el) => el.name === 'w:fieldFontFamily')?.attributes['w:val'];
3030
const fontSize = sdtPr?.elements.find((el) => el.name === 'w:fieldFontSize')?.attributes['w:val'];
31+
const textColor = sdtPr?.elements.find((el) => el.name === 'w:fieldTextColor')?.attributes['w:val'];
32+
const textHighlight = sdtPr?.elements.find((el) => el.name === 'w:fieldTextHighlight')?.attributes['w:val'];
3133

3234
const attrs = {
3335
type,
@@ -38,6 +40,8 @@ export const handleAnnotationNode = (params) => {
3840
multipleImage: isMultipleImage === 'true',
3941
fontFamily: fontFamily !== 'null' ? fontFamily : null,
4042
fontSize: fontSize !== 'null' ? fontSize : null,
43+
textColor: textColor !== 'null' ? textColor : null,
44+
textHighlight: textHighlight !== 'null' ? textHighlight : null,
4145
};
4246

4347
const allAttrs = { ...attrs, ...marksAsAttrs };

packages/super-editor/src/dev/components/DeveloperPlayground.vue

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,11 @@ const onCreate = ({ editor }) => {
4747
isDebuggingPagination.value = PaginationPluginKey.getState(editor.state)?.isDebugging;
4848
4949
// editor.commands.addFieldAnnotation(0, {
50-
// type: 'html',
51-
// displayLabel: 'Paragraph',
52-
// fieldId: `123`,
50+
// type: 'text',
51+
// displayLabel: 'Some text',
52+
// fieldId: '123',
5353
// fieldType: 'TEXTINPUT',
5454
// fieldColor: '#980043',
55-
// rawHtml: '<p><span style="font-family: Courier New; font-size: 8pt;">Par 1</span></p><p>Par 2</p>',
5655
// });
5756
};
5857

packages/super-editor/src/extensions/field-annotation/field-annotation.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,31 @@ export const FieldAnnotation = Node.create({
272272
style: `font-size: ${fontSize}`,
273273
};
274274
},
275+
},
276+
277+
textHighlight: {
278+
default: null,
279+
parseDOM: (element) => element.getAttribute('data-text-highlight'),
280+
renderDOM: (attrs) => {
281+
if (!attrs.textHighlight) return {};
282+
return {
283+
'data-text-highlight': attrs.textHighlight,
284+
// takes precedence over the fieldColor.
285+
style: `background-color: ${attrs.textHighlight} !important`,
286+
};
287+
},
288+
},
275289

290+
textColor: {
291+
default: null,
292+
parseDOM: (element) => element.getAttribute('data-text-color'),
293+
renderDOM: (attrs) => {
294+
if (!attrs.textColor) return {};
295+
return {
296+
'data-text-color': attrs.textColor,
297+
style: `color: ${attrs.textColor}`,
298+
};
299+
},
276300
},
277301
/// Formatting attrs - end.
278302

@@ -843,6 +867,56 @@ export const FieldAnnotation = Node.create({
843867
}
844868
}
845869

870+
return true;
871+
},
872+
873+
setFieldAnnotationsTextHighlight:
874+
(color, setSelection = false) =>
875+
({ dispatch, tr, state, commands }) => {
876+
let { from, to, node } = state.selection;
877+
let annotations = findFieldAnnotationsBetween(from, to, state.doc);
878+
879+
if (!annotations.length) {
880+
return true;
881+
}
882+
883+
if (dispatch) {
884+
annotations.forEach((annotation) => {
885+
commands.updateFieldAnnotationsAttributes([annotation], {
886+
textHighlight: color,
887+
});
888+
});
889+
890+
if (setSelection && node?.type.name === this.name) {
891+
tr.setSelection(NodeSelection.create(tr.doc, from));
892+
}
893+
}
894+
895+
return true;
896+
},
897+
898+
setFieldAnnotationsTextColor:
899+
(color, setSelection = false) =>
900+
({ dispatch, tr, state, commands }) => {
901+
let { from, to, node } = state.selection;
902+
let annotations = findFieldAnnotationsBetween(from, to, state.doc);
903+
904+
if (!annotations.length) {
905+
return true;
906+
}
907+
908+
if (dispatch) {
909+
annotations.forEach((annotation) => {
910+
commands.updateFieldAnnotationsAttributes([annotation], {
911+
textColor: color,
912+
});
913+
});
914+
915+
if (setSelection && node?.type.name === this.name) {
916+
tr.setSelection(NodeSelection.create(tr.doc, from));
917+
}
918+
}
919+
846920
return true;
847921
},
848922
/// Formatting commands - end.

packages/super-editor/src/extensions/table/table.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { Node, Attribute } from '@core/index.js';
22
import { callOrGet } from '@core/utilities/callOrGet.js';
33
import { getExtensionConfigField } from '@core/helpers/getExtensionConfigField.js';
44
import { /* TableView */ createTableView } from './TableView.js';
5-
import { findParentNodeClosestToPos } from '@helpers/index.js';
6-
import { Fragment } from "prosemirror-model";
75
import { createTable } from './tableHelpers/createTable.js';
86
import { createColGroup } from './tableHelpers/createColGroup.js';
97
import { deleteTableWhenSelected } from './tableHelpers/deleteTableWhenSelected.js';
@@ -12,8 +10,8 @@ import { createTableBorders } from './tableHelpers/createTableBorders.js';
1210
import { createCellBorders } from '../table-cell/helpers/createCellBorders.js';
1311
import { findParentNode } from '@helpers/findParentNode.js';
1412
import { TextSelection } from 'prosemirror-state';
15-
import { getFieldAttrs } from '@helpers/annotator.js';
1613
import { getNodeType } from '@core/helpers/getNodeType.js';
14+
import { isCellSelection } from './tableHelpers/isCellSelection.js';
1715
import {
1816
addColumnBefore,
1917
addColumnAfter,
@@ -268,6 +266,23 @@ export const Table = Node.create({
268266
return true;
269267
},
270268

269+
setCellBackground:
270+
(value) => ({ editor, commands, dispatch }) => {
271+
const { selection } = editor.state;
272+
273+
if (!isCellSelection(selection)) {
274+
return false;
275+
}
276+
277+
const color = value?.startsWith('#') ? value.slice(1) : value;
278+
279+
if (dispatch) {
280+
return commands.setCellAttr('background', { color });
281+
}
282+
283+
return true;
284+
},
285+
271286
deleteCellAndTableBorders:
272287
() => ({ chain, state, tr }) => {
273288
if (!isInTable(state)) {

0 commit comments

Comments
 (0)