diff --git a/package.json b/package.json index 1b889eb9..d06d84a3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@manuscripts/transform", "description": "ProseMirror transformer for Manuscripts applications", - "version": "4.5.7", + "version": "4.5.8-LEAN-6032.0", "repository": "github:Atypon-OpenSource/manuscripts-transform", "license": "Apache-2.0", "main": "dist/cjs", diff --git a/src/jats/__tests__/__snapshots__/jats-exporter.test.ts.snap b/src/jats/__tests__/__snapshots__/jats-exporter.test.ts.snap index ef53ab1c..4c6e5d15 100644 --- a/src/jats/__tests__/__snapshots__/jats-exporter.test.ts.snap +++ b/src/jats/__tests__/__snapshots__/jats-exporter.test.ts.snap @@ -1,7 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`JATS exporter > export latest version > jats-export 1`] = `"
This is the Article TitleWhich has a SubtitleMember, IEEEDayNathan123University of Life, Houston, TX, Houston, TX, USACorrespondence: nday@inera.com.

Author_Footnote.

DisclaimerThis is an unlabelled author footnote with a separate title.

This is information about Competing Interests.

120520090104200902052009

The direct interaction of phenobarbital with the epidermal growth factor receptor reveals a new network interface in nuclear receptor signaling.

Introduction

This is a sectionalized abstract.

Results

These are the results of the experiment.

ParagraphsexportingtestingNLM DTD
IntroductionA level 2 subheadA level 3 subheadA level 4 subheadA level 5 subhead

Materials and Methods

Some more text

Results

Some text that introduces a poem:

Poetry Source: Wikipedia

You might1 peruse, e.g., Box 1. See also .

Boxed boxes.Box_Head_1Box_Head_2

Box_Textc

See also, 1 and . Kinds of tables This is a table title continued paragraph Table_Head Table_Body* * Table_Footnote Block_Quote Source: Wikipedia Paragraph_Continued with a graphic in the middlewhere the paragraph continues.

Num_Bul_List_1

List_1_Continued

Num_Bul_List_2

List_2_Continued

level 1, bullet 2

Discussion

ParagraphUnnumbered_List_1 Another unnumbered itemwith another paragraph that continues after a list.

Conclusions

Paragraph

This is an appendixAppendix_Head_1Appendix_Head_2

Appendix_Text

Acknowledgements

Acknowledgement

Data availability

This is some information about data availability.

Ethics statement

Paragraph, seeb and Figure 1.

A picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

A missing picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

Author Contibutions are described here.

This is a Financial Disclosure.

Footnotes

Box Note

This is a footnote.

Footnote called out in a box

Day RN. This is the article title. EDCC. 2008;3(2):123-134.
"`; +exports[`JATS exporter > export latest version > jats-export 1`] = `"
This is the Article TitleWhich has a SubtitleMember, IEEEDayNathan123University of Life, Houston, TX, Houston, TX, USACorrespondence: nday@inera.com.

Author_Footnote.

DisclaimerThis is an unlabelled author footnote with a separate title.

This is information about Competing Interests.

120520090104200902052009

The direct interaction of phenobarbital with the epidermal growth factor receptor reveals a new network interface in nuclear receptor signaling.

Introduction

This is a sectionalized abstract.

Results

These are the results of the experiment.

ParagraphsexportingtestingNLM DTD
IntroductionA level 2 subheadA level 3 subheadA level 4 subheadA level 5 subhead

Materials and Methods

Some more text

Results

Some text that introduces a poem:

Poetry Source: Wikipedia

You might1 peruse, e.g., Box 1. See also .

Boxed boxes.Box_Head_1Box_Head_2

Box_Textc

See also, 1 and . Kinds of tables This is a table title continued paragraph Table_Head Table_Body* * Table_Footnote Block_Quote Source: WikipediaParagraph_Continued with a graphic in the middlewhere the paragraph continues.

Num_Bul_List_1

List_1_Continued

Num_Bul_List_2

List_2_Continued

level 1, bullet 2

Discussion

ParagraphUnnumbered_List_1 Another unnumbered itemwith another paragraph that continues after a list.

Conclusions

Paragraph

This is an appendixAppendix_Head_1Appendix_Head_2

Appendix_Text

Acknowledgements

Acknowledgement

Data availability

This is some information about data availability.

Ethics statement

Paragraph, seeb and Figure 1.

A picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

A missing picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

Author Contibutions are described here.

This is a Financial Disclosure.

Footnotes

Box Note

This is a footnote.

Footnote called out in a box

Day RN. This is the article title. EDCC. 2008;3(2):123-134.
"`; -exports[`JATS exporter > export v1.1 > jats-export-1.1 1`] = `"
This is the Article TitleWhich has a SubtitleMember, IEEEDayNathan123University of Life, Houston, TX, Houston, TX, USACorrespondence: nday@inera.com.

Author_Footnote.

DisclaimerThis is an unlabelled author footnote with a separate title.

This is information about Competing Interests.

120520090104200902052009

The direct interaction of phenobarbital with the epidermal growth factor receptor reveals a new network interface in nuclear receptor signaling.

Introduction

This is a sectionalized abstract.

Results

These are the results of the experiment.

ParagraphsexportingtestingNLM DTD
IntroductionA level 2 subheadA level 3 subheadA level 4 subheadA level 5 subhead

Materials and Methods

Some more text

Results

Some text that introduces a poem:

Poetry Source: Wikipedia

You might1 peruse, e.g., Box 1. See also .

Boxed boxes.Box_Head_1Box_Head_2

Box_Textc

See also, 1 and . Kinds of tables This is a table title continued paragraph Table_Head Table_Body* * Table_Footnote Block_Quote Source: Wikipedia Paragraph_Continued with a graphic in the middlewhere the paragraph continues.

Num_Bul_List_1

List_1_Continued

Num_Bul_List_2

List_2_Continued

level 1, bullet 2

Discussion

ParagraphUnnumbered_List_1 Another unnumbered itemwith another paragraph that continues after a list.

Conclusions

Paragraph

This is an appendixAppendix_Head_1Appendix_Head_2

Appendix_Text

Acknowledgements

Acknowledgement

Data availability

This is some information about data availability.

Ethics statement

Paragraph, seeb and Figure 1.

A picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

A missing picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

Author Contibutions are described here.

This is a Financial Disclosure.

Footnotes

Box Note

This is a footnote.

Footnote called out in a box

Day RN. This is the article title. EDCC. 2008;3(2):123-134.
"`; +exports[`JATS exporter > export v1.1 > jats-export-1.1 1`] = `"
This is the Article TitleWhich has a SubtitleMember, IEEEDayNathan123University of Life, Houston, TX, Houston, TX, USACorrespondence: nday@inera.com.

Author_Footnote.

DisclaimerThis is an unlabelled author footnote with a separate title.

This is information about Competing Interests.

120520090104200902052009

The direct interaction of phenobarbital with the epidermal growth factor receptor reveals a new network interface in nuclear receptor signaling.

Introduction

This is a sectionalized abstract.

Results

These are the results of the experiment.

ParagraphsexportingtestingNLM DTD
IntroductionA level 2 subheadA level 3 subheadA level 4 subheadA level 5 subhead

Materials and Methods

Some more text

Results

Some text that introduces a poem:

Poetry Source: Wikipedia

You might1 peruse, e.g., Box 1. See also .

Boxed boxes.Box_Head_1Box_Head_2

Box_Textc

See also, 1 and . Kinds of tables This is a table title continued paragraph Table_Head Table_Body* * Table_Footnote Block_Quote Source: WikipediaParagraph_Continued with a graphic in the middlewhere the paragraph continues.

Num_Bul_List_1

List_1_Continued

Num_Bul_List_2

List_2_Continued

level 1, bullet 2

Discussion

ParagraphUnnumbered_List_1 Another unnumbered itemwith another paragraph that continues after a list.

Conclusions

Paragraph

This is an appendixAppendix_Head_1Appendix_Head_2

Appendix_Text

Acknowledgements

Acknowledgement

Data availability

This is some information about data availability.

Ethics statement

Paragraph, seeb and Figure 1.

A picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

A missing picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

Author Contibutions are described here.

This is a Financial Disclosure.

Footnotes

Box Note

This is a footnote.

Footnote called out in a box

Day RN. This is the article title. EDCC. 2008;3(2):123-134.
"`; -exports[`JATS exporter > export with & and < in bibliography metadata > jats-export-with-xml-unsafe-in-biblios 1`] = `"
This is the Article TitleWhich has a SubtitleMember, IEEEDayNathan123University of Life, Houston, TX, Houston, TX, USACorrespondence: nday@inera.com.

Author_Footnote.

DisclaimerThis is an unlabelled author footnote with a separate title.

This is information about Competing Interests.

120520090104200902052009

The direct interaction of phenobarbital with the epidermal growth factor receptor reveals a new network interface in nuclear receptor signaling.

Introduction

This is a sectionalized abstract.

Results

These are the results of the experiment.

ParagraphsexportingtestingNLM DTD
IntroductionA level 2 subheadA level 3 subheadA level 4 subheadA level 5 subhead

Materials and Methods

Some more text

Results

Some text that introduces a poem:

Poetry Source: Wikipedia

You might1 peruse, e.g., Box 1. See also .

Boxed boxes.Box_Head_1Box_Head_2

Box_Textc

See also, 1 and . Kinds of tables This is a table title continued paragraph Table_Head Table_Body* * Table_Footnote Block_Quote Source: Wikipedia Paragraph_Continued with a graphic in the middlewhere the paragraph continues.

Num_Bul_List_1

List_1_Continued

Num_Bul_List_2

List_2_Continued

level 1, bullet 2

Discussion

ParagraphUnnumbered_List_1 Another unnumbered itemwith another paragraph that continues after a list.

Conclusions

Paragraph

This is an appendixAppendix_Head_1Appendix_Head_2

Appendix_Text

Acknowledgements

Acknowledgement

Data availability

This is some information about data availability.

Ethics statement

Paragraph, seeb and Figure 1.

A picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

A missing picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

Author Contibutions are described here.

This is a Financial Disclosure.

Footnotes

Box Note

This is a footnote.

Footnote called out in a box

Day RN. This is the article title. & Sons 55 < 135. EDCC. 2008;3(2):123-134.
"`; +exports[`JATS exporter > export with & and < in bibliography metadata > jats-export-with-xml-unsafe-in-biblios 1`] = `"
This is the Article TitleWhich has a SubtitleMember, IEEEDayNathan123University of Life, Houston, TX, Houston, TX, USACorrespondence: nday@inera.com.

Author_Footnote.

DisclaimerThis is an unlabelled author footnote with a separate title.

This is information about Competing Interests.

120520090104200902052009

The direct interaction of phenobarbital with the epidermal growth factor receptor reveals a new network interface in nuclear receptor signaling.

Introduction

This is a sectionalized abstract.

Results

These are the results of the experiment.

ParagraphsexportingtestingNLM DTD
IntroductionA level 2 subheadA level 3 subheadA level 4 subheadA level 5 subhead

Materials and Methods

Some more text

Results

Some text that introduces a poem:

Poetry Source: Wikipedia

You might1 peruse, e.g., Box 1. See also .

Boxed boxes.Box_Head_1Box_Head_2

Box_Textc

See also, 1 and . Kinds of tables This is a table title continued paragraph Table_Head Table_Body* * Table_Footnote Block_Quote Source: WikipediaParagraph_Continued with a graphic in the middlewhere the paragraph continues.

Num_Bul_List_1

List_1_Continued

Num_Bul_List_2

List_2_Continued

level 1, bullet 2

Discussion

ParagraphUnnumbered_List_1 Another unnumbered itemwith another paragraph that continues after a list.

Conclusions

Paragraph

This is an appendixAppendix_Head_1Appendix_Head_2

Appendix_Text

Acknowledgements

Acknowledgement

Data availability

This is some information about data availability.

Ethics statement

Paragraph, seeb and Figure 1.

A picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

A missing picture on the kinds of figures.

The Fig Caption continues.

test paragraph

Source: Wikipedia.

Author Contibutions are described here.

This is a Financial Disclosure.

Footnotes

Box Note

This is a footnote.

Footnote called out in a box

Day RN. This is the article title. & Sons 55 < 135. EDCC. 2008;3(2):123-134.
"`; diff --git a/src/jats/__tests__/__snapshots__/jats-importer.test.ts.snap b/src/jats/__tests__/__snapshots__/jats-importer.test.ts.snap index c90858eb..a5490bf1 100644 --- a/src/jats/__tests__/__snapshots__/jats-importer.test.ts.snap +++ b/src/jats/__tests__/__snapshots__/jats-importer.test.ts.snap @@ -3163,7 +3163,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -18051,7 +18050,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -18279,7 +18277,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -18964,7 +18961,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -23392,7 +23388,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -27254,7 +27249,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -27410,7 +27404,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -31390,9 +31383,6 @@ Object { }, Object { "attrs": Object { - "attribution": Object { - "literal": "Source: Wikipedia.", - }, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -31420,18 +31410,6 @@ Object { }, "type": "figure", }, - Object { - "attrs": Object { - "dataTracked": null, - }, - "content": Array [ - Object { - "text": "Source: Wikipedia.", - "type": "text", - }, - ], - "type": "attribution", - }, Object { "attrs": Object { "dataTracked": null, @@ -31465,6 +31443,18 @@ Object { ], "type": "caption", }, + Object { + "attrs": Object { + "dataTracked": null, + }, + "content": Array [ + Object { + "text": "Source: Wikipedia.", + "type": "text", + }, + ], + "type": "attribution", + }, Object { "attrs": Object { "id": "MPAltText:test", @@ -31494,9 +31484,6 @@ Object { }, Object { "attrs": Object { - "attribution": Object { - "literal": "Source: Wikipedia.", - }, "dataTracked": null, "id": "fig1", }, @@ -31522,18 +31509,6 @@ Object { }, "type": "missing_figure", }, - Object { - "attrs": Object { - "dataTracked": null, - }, - "content": Array [ - Object { - "text": "Source: Wikipedia.", - "type": "text", - }, - ], - "type": "attribution", - }, Object { "attrs": Object { "dataTracked": null, @@ -31567,6 +31542,18 @@ Object { ], "type": "caption", }, + Object { + "attrs": Object { + "dataTracked": null, + }, + "content": Array [ + Object { + "text": "Source: Wikipedia.", + "type": "text", + }, + ], + "type": "attribution", + }, Object { "attrs": Object { "id": "MPAltText:test", @@ -31868,7 +31855,7 @@ Object { "type": "cross_reference", }, Object { - "text": ". Kinds of tables This is a table title continued paragraph Table_Head Table_Body* * Table_Footnote Block_Quote Source: Wikipedia Paragraph_Continued with a graphic in the middlewhere the paragraph continues.", + "text": ". Kinds of tables This is a table title continued paragraph Table_Head Table_Body* * Table_Footnote Block_Quote Source: WikipediaParagraph_Continued with a graphic in the middlewhere the paragraph continues.", "type": "text", }, ], @@ -33365,7 +33352,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -33445,7 +33431,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -35144,7 +35129,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -39030,7 +39014,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -39186,7 +39169,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -45241,7 +45223,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -51869,7 +51850,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -52386,7 +52366,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -52948,7 +52927,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -53604,7 +53582,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -54014,7 +53991,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -54518,7 +54494,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, @@ -54964,7 +54939,6 @@ Object { }, Object { "attrs": Object { - "attribution": undefined, "dataTracked": null, "id": "MPFigureElement:test", }, diff --git a/src/jats/exporter/jats-exporter.ts b/src/jats/exporter/jats-exporter.ts index 56cac31f..bccf2894 100644 --- a/src/jats/exporter/jats-exporter.ts +++ b/src/jats/exporter/jats-exporter.ts @@ -232,7 +232,7 @@ export class JATSExporter { type: ManuscriptNodeType ) => { const childNode = this.getFirstChildOfType(type, node) - if (childNode) { + if (childNode && childNode.content.size > 0) { $element.appendChild(this.serializeNode(childNode)) } } @@ -1167,13 +1167,6 @@ export class JATSExporter { } } } - const appendAttributions = ($element: Element, node: ManuscriptNode) => { - if (node.attrs.attribution) { - const $attrib = this.createElement('attrib') - $attrib.textContent = node.attrs.attribution.literal - $element.appendChild($attrib) - } - } const appendTable = ($element: Element, node: ManuscriptNode) => { const tableNode = this.getFirstChildOfType(schema.nodes.table, node) @@ -1271,6 +1264,7 @@ export class JATSExporter { this.appendCaption($graphic, node) this.appendChildNodeOfType($graphic, node, schema.nodes.alt_text) this.appendChildNodeOfType($graphic, node, schema.nodes.long_desc) + this.appendChildNodeOfType($graphic, node, schema.nodes.attribution) return $graphic } @@ -1309,11 +1303,11 @@ export class JATSExporter { node.type.schema.nodes.footnotes_element ) processChildNodes($fig, node, contentNodeType) - appendAttributions($fig, node) if (isExecutableNodeType(node.type)) { processExecutableNode(node, $fig) } moveAltTextAndLongDescToGraphics($fig) + this.appendChildNodeOfType($fig, node, schema.nodes.attribution) return $fig } @@ -1817,6 +1811,9 @@ export class JATSExporter { $graphic = this.serializeNode(node) as Element $floatsGroup.appendChild($graphic) } else { + if (node.type === schema.nodes.attribution && node.content.size === 0) { + return + } const $serializedNode = this.serializeNode(node) $graphic?.appendChild($serializedNode) } diff --git a/src/jats/importer/jats-dom-parser.ts b/src/jats/importer/jats-dom-parser.ts index cf4a9bd8..b263a14a 100644 --- a/src/jats/importer/jats-dom-parser.ts +++ b/src/jats/importer/jats-dom-parser.ts @@ -276,6 +276,11 @@ export class JATSDOMParser { private getFigContent = (node: Node) => { const element = node as HTMLElement const content = [this.schema.nodes.figure.create(this.getFigAttrs(element))] + const attribution = element.querySelector('attrib') + if (attribution) { + const attributionNode = this.schema.nodes.attribution.create() + content.push(this.parse(attribution, { topNode: attributionNode })) + } const altText = element.querySelector('alt-text') if (altText) { const altTextNode = this.schema.nodes.alt_text.create() @@ -608,10 +613,11 @@ export class JATSDOMParser { return Fragment.from(this.schema.text('_')) }, }, - { tag: 'attrib', node: 'attribution', + context: + 'figure_element/|image_element/|hero_image/|blockquote_element/|pullquote_element/', }, { tag: 'back', @@ -884,15 +890,8 @@ export class JATSDOMParser { node: 'figure_element', getAttrs: (node) => { const element = node as HTMLElement - const attrib = element.querySelector('attrib') - const attribution = attrib - ? { - literal: getTrimmedTextContent(attrib) ?? '', - } - : undefined return { id: element.getAttribute('id'), - attribution, } }, }, @@ -979,6 +978,11 @@ export class JATSDOMParser { tag: 'p[content-type="headshots"]', node: 'headshot_grid', }, + { + tag: 'p', + node: 'text_block', + context: 'pullquote_element/|blockquote_element/', + }, { tag: 'p', node: 'paragraph', diff --git a/src/jats/importer/jats-transformations.ts b/src/jats/importer/jats-transformations.ts index 24c70037..4e3fa24f 100644 --- a/src/jats/importer/jats-transformations.ts +++ b/src/jats/importer/jats-transformations.ts @@ -296,6 +296,28 @@ export const moveCaptionsToEnd = (body: Element) => { } } +export const mergeAttributions = ( + doc: Document, + createElement: CreateElement +) => { + const parents = [...doc.querySelectorAll(':has(> attrib)')] + + parents.forEach((parent) => { + const merged = createElement('attrib') + const attributions = parent.querySelectorAll(':scope > attrib') + attributions.forEach((attrib, index) => { + if (index > 0) { + merged.append(doc.createTextNode(' ')) + } + merged.append( + ...Array.from(attrib.childNodes).map((n) => n.cloneNode(true)) + ) + removeNodeFromParent(attrib) + }) + parent.appendChild(merged) + }) +} + const prepareAbstract = ( abstract: Element, createElement: CreateElement, diff --git a/src/jats/importer/parse-jats-article.ts b/src/jats/importer/parse-jats-article.ts index ced78376..5ab07740 100644 --- a/src/jats/importer/parse-jats-article.ts +++ b/src/jats/importer/parse-jats-article.ts @@ -30,6 +30,7 @@ import { createSupplementaryMaterialsSection, createTitles, fixTables, + mergeAttributions, moveAffiliations, moveAuthorNotes, moveAwards, @@ -67,6 +68,7 @@ const processJATS = (doc: Document, sectionCategories: SectionCategory[]) => { } moveCaptionsToEnd(body) + mergeAttributions(doc, createElement) createBody(doc, body, createElement) createAbstracts(front, body, createElement, sectionCategories) createBackmatter(doc, body, sectionCategories, createElement) diff --git a/src/schema/__tests__/docs.ts b/src/schema/__tests__/docs.ts index 8cd66b01..ee28d049 100644 --- a/src/schema/__tests__/docs.ts +++ b/src/schema/__tests__/docs.ts @@ -544,7 +544,34 @@ export const v2_3_20 = { src: 'attachment:figure1', contentType: 'image/png', dataTracked: null, + attribution: { + literal: 'Source: Wikipedia.', + }, + }, + }, + { + type: 'attribution', + attrs: { + dataTracked: null, }, + content: [ + { + type: 'text', + text: 'Source: Wikipedia.', + }, + ], + }, + { + type: 'attribution', + attrs: { + dataTracked: null, + }, + content: [ + { + type: 'text', + text: 'Source: Wiley Online Library.', + }, + ], }, { type: 'figcaption', diff --git a/src/schema/migration/migration-scripts/4.5.7.ts b/src/schema/migration/migration-scripts/4.5.7.ts new file mode 100644 index 00000000..a66decdc --- /dev/null +++ b/src/schema/migration/migration-scripts/4.5.7.ts @@ -0,0 +1,69 @@ +/*! + * © 2026 Atypon Systems LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { JSONProsemirrorNode } from '../../../types' +import { MigrationScript } from '../migration-script' + +class Migration457 implements MigrationScript { + fromVersion = '4.5.6' + toVersion = '4.5.7' + + migrateNode(node: JSONProsemirrorNode): JSONProsemirrorNode { + if (node.type !== 'figure_element') { + return node + } + + const attributionIndex = node.content?.findIndex( + (n) => n.type === 'attribution' + ) + + if (!attributionIndex || attributionIndex === -1) { + return node + } + + const attribution = node.content + ?.filter((n) => n.type === 'attribution') + .reduce( + (n, attrib) => ({ + ...attrib, + content: [...(attrib.content || []), ...(n.content || [])], + }), + { type: 'attribution', attrs: {} } + ) + + if (!attribution) { + return node + } + + const captionIndex = node.content?.findIndex((n) => n.type === 'caption') + + if (!captionIndex || captionIndex === -1) { + return node + } + + return { + ...node, + content: [ + ...(node.content?.slice(0, attributionIndex) || []), + ...(node.content?.slice(captionIndex, captionIndex + 1) || []), + attribution, + ...(node.content?.slice(captionIndex + 1) || []), + ], + } + } +} + +export default Migration457 diff --git a/src/schema/migration/migration-scripts/index.ts b/src/schema/migration/migration-scripts/index.ts index f3ea23b3..b8d97188 100644 --- a/src/schema/migration/migration-scripts/index.ts +++ b/src/schema/migration/migration-scripts/index.ts @@ -31,6 +31,7 @@ import Migration4335 from './4.3.35' import Migration442 from './4.4.2' import Migration447 from './4.4.7' import Migration453 from './4.5.3' +import Migration457 from './4.5.7' const migrations = [ new Migration125(), @@ -50,6 +51,7 @@ const migrations = [ new Migration442(), new Migration447(), new Migration453(), + new Migration457(), ] export default migrations diff --git a/src/schema/nodes/attribution.ts b/src/schema/nodes/attribution.ts index 28b73cb8..4b8c3b0f 100644 --- a/src/schema/nodes/attribution.ts +++ b/src/schema/nodes/attribution.ts @@ -34,5 +34,5 @@ export const attribution: NodeSpec = { context: 'blockquote_element/|pullquote_element/', }, ], - toDOM: () => ['footer', 0], + toDOM: () => ['footer', { class: 'attribution' }, 0], } diff --git a/src/schema/nodes/figure_element.ts b/src/schema/nodes/figure_element.ts index 69b94604..db4587f5 100644 --- a/src/schema/nodes/figure_element.ts +++ b/src/schema/nodes/figure_element.ts @@ -17,11 +17,9 @@ import { NodeSpec } from 'prosemirror-model' import { ManuscriptNode } from '../types' -import { AttributionNode } from './attribution' export interface FigureElementAttrs { id: string - attribution?: AttributionNode } export interface FigureElementNode extends ManuscriptNode { @@ -30,10 +28,9 @@ export interface FigureElementNode extends ManuscriptNode { export const figureElement: NodeSpec = { content: - '(paragraph | figure | missing_figure | placeholder)+ attribution* caption alt_text long_desc (listing | placeholder)', + '(paragraph | figure | missing_figure | placeholder)+ caption attribution? alt_text long_desc (listing | placeholder)', attrs: { id: { default: '' }, - attribution: { default: undefined }, dataTracked: { default: null }, }, selectable: false, diff --git a/src/schema/nodes/hero_image.ts b/src/schema/nodes/hero_image.ts index 75bf14e4..db3c674d 100644 --- a/src/schema/nodes/hero_image.ts +++ b/src/schema/nodes/hero_image.ts @@ -26,7 +26,7 @@ export interface HeroImageNode extends ManuscriptNode { } export const heroImage: NodeSpec = { - content: 'figure? alt_text long_desc', + content: 'figure? attribution? alt_text long_desc', attrs: { id: { default: '' }, type: { default: 'leading' }, diff --git a/src/schema/nodes/image_element.ts b/src/schema/nodes/image_element.ts index 204d7be8..dd0d11de 100644 --- a/src/schema/nodes/image_element.ts +++ b/src/schema/nodes/image_element.ts @@ -25,7 +25,7 @@ export interface ImageElementNode extends ManuscriptNode { } export const imageElement: NodeSpec = { - content: 'figure? caption alt_text long_desc', + content: 'figure? caption attribution? alt_text long_desc', attrs: { id: { default: '' }, extLink: { default: '' },