Skip to content

Commit bf89b63

Browse files
committed
fix link export
1 parent f773a13 commit bf89b63

5 files changed

Lines changed: 66 additions & 8 deletions

File tree

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
prepareCommentParaIds,
1212
prepareCommentsXmlFilesForExport,
1313
} from './v2/exporter/commentsExporter.js';
14+
import { HYPERLINK_RELATIONSHIP_TYPE } from './constants.js';
1415

1516
class SuperConverter {
1617
static allowedElements = Object.freeze({
@@ -504,15 +505,16 @@ class SuperConverter {
504505
const existingId = rel.attributes.Id;
505506
const existingTarget = relationships.elements.find((el) => el.attributes.Target === rel.attributes.Target);
506507
const isNewMedia = rel.attributes.Target?.startsWith('media/') && existingId.length > 6;
507-
508-
if (existingTarget && !isNewMedia) {
508+
const isNewHyperlink = rel.attributes.Type === HYPERLINK_RELATIONSHIP_TYPE && existingId.length > 6;
509+
510+
if (existingTarget && !isNewMedia && !isNewHyperlink) {
509511
return;
510512
}
511513

512514
// Update the target to escape ampersands
513515
rel.attributes.Target = rel.attributes?.Target?.replace(/&/g, '&');
514516

515-
// Update the ID. If we've assigned a long ID (ie: images) we leave it alone
517+
// Update the ID. If we've assigned a long ID (ie: images, links) we leave it alone
516518
rel.attributes.Id = existingId.length > 6 ? existingId : `rId${++largestId}`;
517519

518520
newRels.push(rel);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const HYPERLINK_RELATIONSHIP_TYPE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink';

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

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,25 +601,69 @@ function translateLinkNode(params) {
601601

602602
const linkMark = node.marks.find((m) => m.type === 'link');
603603
const link = linkMark.attrs.href;
604+
604605
let rId = linkMark.attrs.rId;
605606
if (!rId) {
606607
rId = addNewLinkRelationship(params, link);
607608
}
608609

609610
node.marks = node.marks.filter((m) => m.type !== 'link');
611+
610612
const outputNode = exportSchemaToJson({ ...params, node });
613+
const contentNode = processLinkContentNode(outputNode);
614+
611615
const newNode = {
612616
name: 'w:hyperlink',
613617
type: 'element',
614618
attributes: {
615619
'r:id': rId,
616620
},
617-
elements: [outputNode],
621+
elements: [contentNode],
618622
};
619623

620624
return newNode;
621625
}
622626

627+
function processLinkContentNode(node) {
628+
if (!node) return node;
629+
630+
const contentNode = carbonCopy(node);
631+
if (!contentNode) return contentNode;
632+
633+
const hyperlinkStyle = {
634+
name: 'w:rStyle',
635+
attributes: { 'w:val': 'Hyperlink' },
636+
};
637+
const color = {
638+
name: 'w:color',
639+
attributes: { 'w:val': '467886' },
640+
};
641+
642+
if (contentNode.name === 'w:r') {
643+
const runProps = contentNode.elements.find((el) => el.name === 'w:rPr');
644+
645+
if (runProps) {
646+
const foundColor = runProps.elements.find((el) => el.name === 'w:color');
647+
const foundHyperlinkStyle = runProps.elements.find((el) => el.name === 'w:rStyle');
648+
if (!foundColor) runProps.elements.unshift(color);
649+
if (!foundHyperlinkStyle) runProps.elements.unshift(hyperlinkStyle);
650+
} else {
651+
// we don't add underline by default
652+
const runProps = {
653+
name: 'w:rPr',
654+
elements: [
655+
hyperlinkStyle,
656+
color,
657+
],
658+
};
659+
660+
contentNode.elements.unshift(runProps);
661+
}
662+
}
663+
664+
return contentNode;
665+
}
666+
623667
/**
624668
* Create a new link relationship and add it to the relationships array
625669
*
@@ -630,7 +674,10 @@ function translateLinkNode(params) {
630674
function addNewLinkRelationship(params, link) {
631675
const newId = 'rId' + generateDocxRandomId();
632676

633-
if (!params.relationships || !Array.isArray(params.relationships)) params.relationships = [];
677+
if (!params.relationships || !Array.isArray(params.relationships)) {
678+
params.relationships = [];
679+
}
680+
634681
params.relationships.push({
635682
type: 'element',
636683
name: 'Relationship',
@@ -641,6 +688,7 @@ function addNewLinkRelationship(params, link) {
641688
TargetMode: 'External',
642689
},
643690
});
691+
644692
return newId;
645693
}
646694

@@ -1817,6 +1865,7 @@ function prepareUrlAnnotation(params) {
18171865
const newId = addNewLinkRelationship(params, attrs.linkUrl);
18181866

18191867
const linkTextNode = getTextNodeForExport(attrs.linkUrl, marks, params);
1868+
const contentNode = processLinkContentNode(linkTextNode);
18201869

18211870
return {
18221871
name: 'w:hyperlink',
@@ -1825,7 +1874,7 @@ function prepareUrlAnnotation(params) {
18251874
'r:id': newId,
18261875
'w:history': 1,
18271876
},
1828-
elements: [linkTextNode],
1877+
elements: [contentNode],
18291878
};
18301879
}
18311880

packages/super-editor/src/tests/export/annotations/fieldAnnotationExporter.test.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ describe('AnnotationNodeExporter', async () => {
6666
const shortFieldType = fieldElements.find((f) => f.name === 'w:fieldTypeShort');
6767
expect(shortFieldType.attributes['w:val']).toBe('link');
6868

69-
const text = getTextFromNode(body.elements[10].elements[1].elements[1].elements[0]);
69+
const node = body.elements[10].elements[1].elements[1].elements[0];
70+
const run = node.elements.find((el) => el.name === 'w:r');
71+
const text = run?.elements[1].elements[0].text;
72+
7073
expect(text).toEqual('https://vitest.dev/guide/coverage');
7174
expect(params.relationships[2].attributes.Target).toBe('https://vitest.dev/guide/coverage');
7275
});

packages/super-editor/src/tests/export/annotations/fieldAnnotationFinalDoc.test.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ describe('AnnotationNodeExporter for final doc', async () => {
4646

4747
it('export url annotation correctly', async() => {
4848
const hyperLinkNode = body.elements[10].elements[1];
49-
const text = getTextFromNode(hyperLinkNode);
49+
50+
const run = hyperLinkNode.elements.find((el) => el.name === 'w:r');
51+
const text = run?.elements[1].elements[0].text;
52+
5053
expect(text).toBe('https://vitest.dev/guide/coverage');
5154
expect(hyperLinkNode.attributes['r:id']).toBe(params.relationships[2].attributes.Id);
5255
});

0 commit comments

Comments
 (0)