diff --git a/scripts/odf/templating/fillOdtTemplate.js b/scripts/odf/templating/fillOdtTemplate.js index a13f3d9..6ca8047 100644 --- a/scripts/odf/templating/fillOdtTemplate.js +++ b/scripts/odf/templating/fillOdtTemplate.js @@ -1,6 +1,6 @@ import {ZipReader, ZipWriter, BlobReader, BlobWriter, TextReader, Uint8ArrayReader, TextWriter, Uint8ArrayWriter} from '@zip.js/zip.js'; -import {parseXML, serializeToString, Node} from '../../DOMUtils.js' +import {parseXML, serializeToString} from '../../DOMUtils.js' import {makeManifestFile, getManifestFileData} from '../manifest.js'; import prepareTemplateDOMTree from './prepareTemplateDOMTree.js'; @@ -164,8 +164,3 @@ export default async function fillOdtTemplate(odtTemplate, data) { return writer.close(); } - - - - - diff --git a/scripts/odf/templating/prepareTemplateDOMTree.js b/scripts/odf/templating/prepareTemplateDOMTree.js index 995c202..6974b2f 100644 --- a/scripts/odf/templating/prepareTemplateDOMTree.js +++ b/scripts/odf/templating/prepareTemplateDOMTree.js @@ -35,7 +35,6 @@ function findAllMatches(text, pattern) { return results; } - /** * * @param {Node} node1 @@ -72,7 +71,6 @@ function getAncestors(node) { return ancestors; } - /** * text position of a node relative to a text nodes within a container * @@ -268,8 +266,6 @@ function removeNodesBetween(startBranch, endBranch, commonAncestor) { } } - - /** * Consolidate markers which are split among several Text nodes * @@ -277,23 +273,33 @@ function removeNodesBetween(startBranch, endBranch, commonAncestor) { */ function consolidateMarkers(document){ // Perform a first pass to detect templating markers with formatting to remove it - const potentialMarkerContainers = [ + const potentialMarkersContainers = [ ...Array.from(document.getElementsByTagName('text:p')), ...Array.from(document.getElementsByTagName('text:h')) ] - for(const potentialMarkerContainer of potentialMarkerContainers) { - // Check if any template marker is split across multiple text nodes - // Get all text nodes within this container + for(const potentialMarkersContainer of potentialMarkersContainers) { + const consolidatedMarkers = [] + /** @type {Text[]} */ - const containerTextNodesInTreeOrder = []; + let containerTextNodesInTreeOrder = []; + + function refreshContainerTextNodes(){ + containerTextNodesInTreeOrder = [] + + traverse(potentialMarkersContainer, node => { + if(node.nodeType === Node.TEXT_NODE) { + containerTextNodesInTreeOrder.push(/** @type {Text} */(node)) + } + }) + } + + refreshContainerTextNodes() + let fullText = '' - traverse(potentialMarkerContainer, node => { - if(node.nodeType === Node.TEXT_NODE) { - containerTextNodesInTreeOrder.push(/** @type {Text} */(node)) - fullText = fullText + node.textContent - } - }) + for(const node of containerTextNodesInTreeOrder){ + fullText = fullText + node.textContent + } // Check for each template marker const positionedMarkers = [ @@ -307,10 +313,11 @@ function consolidateMarkers(document){ console.log('positionedMarkers', positionedMarkers) // If no markers found, skip this container - if(positionedMarkers.length >= 1) { + while(consolidatedMarkers.length < positionedMarkers.length) { + refreshContainerTextNodes() // For each marker, check if it's contained within a single text node - for(const positionedMarker of positionedMarkers) { + for(const positionedMarker of positionedMarkers.slice(consolidatedMarkers.length)) { console.log('positionedMarker', positionedMarker) let markerStart = -1; @@ -342,9 +349,16 @@ function consolidateMarkers(document){ currentPos = nodeEnd; } + /*if(!startNode){ + throw new Error(`Could not find startNode for marker '${positionedMarker.marker}'`) + }*/ + + /*if(!endNode){ + throw new Error(`Could not find endNode for marker '${positionedMarker.marker}'`) + }*/ + // Check if marker spans multiple nodes if(startNode !== endNode) { - console.log('startNode !== endNode') const commonAncestor = findCommonAncestor(startNode, endNode); // Calculate relative positions within the nodes @@ -364,8 +378,6 @@ function consolidateMarkers(document){ // Find the diverging point in the paths const lowestCommonAncestorChild = findDivergingPoint(pathToStart, pathToEnd); - console.log('lowestCommonAncestorChild', lowestCommonAncestorChild) - if(!lowestCommonAncestorChild) { // Direct parent-child relationship or other simple case // Handle separately @@ -392,6 +404,8 @@ function consolidateMarkers(document){ // Create a new node for the start of the marker const startOfMarkerNode = document.createTextNode(positionedMarker.marker); + console.log('parentOfStartNode', parentOfStartNode) + // Insert after the modified start node if(startNode.nextSibling) { parentOfStartNode.insertBefore(startOfMarkerNode, startNode.nextSibling); @@ -437,15 +451,18 @@ function consolidateMarkers(document){ removeNodesBetween(startBranch, endBranch, commonAncestor); } - // After consolidation, we can break as the DOM structure has changed + // After consolidation, break as the DOM structure has changed + // and containerTextNodesInTreeOrder needs to be refreshed + consolidatedMarkers.push(positionedMarker) break; } + + consolidatedMarkers.push(positionedMarker) } } } } - /** * isolate markers which are in Text nodes with other texts * @@ -529,8 +546,6 @@ function isolateMarkers(document){ }) } - - /** * This function prepares the template DOM tree in a way that makes it easily processed by the template execution * Specifically, after the call to this function, the document is altered to respect the following property: diff --git a/tests/fill-odt-template/formatting.js b/tests/fill-odt-template/formatting.js index a2d5221..64df339 100644 --- a/tests/fill-odt-template/formatting.js +++ b/tests/fill-odt-template/formatting.js @@ -5,8 +5,8 @@ import {getOdtTemplate} from '../../scripts/odf/odtTemplate-forNode.js' import {fillOdtTemplate, getOdtTextContent} from '../../exports.js' -test('template filling {#each ...}{/each} with formating in {#each ...} start marker', async t => { - const templatePath = join(import.meta.dirname, '../fixtures/liste-nombres-avec-formattage.odt') +test('template filling with several layers of formatting in {#each ...} start marker', async t => { + const templatePath = join(import.meta.dirname, '../fixtures/formatting-liste-nombres-plusieurs-couches.odt') const templateContent = `Liste de nombres Les nombres : {#each nombres as n}{n} {/each} !! @@ -29,4 +29,31 @@ Les nombres : {#each nombres as n}{n} {/each} !! Les nombres : 1 2 3 5  !! `) +}); + + +test('template filling - both {#each ...} and {/each} within the same Text node are formatted', async t => { + const templatePath = join(import.meta.dirname, '../fixtures/formatting-liste-nombres-2-markeurs-formatted.odt') + const templateContent = `Liste de nombres + +Les nombres : {#each nombres as n}{n} {/each} !! +` + + const data = { + nombres : [2,3,5,8] + } + + const odtTemplate = await getOdtTemplate(templatePath) + + const templateTextContent = await getOdtTextContent(odtTemplate) + t.deepEqual(templateTextContent, templateContent, 'reconnaissance du template') + + const odtResult = await fillOdtTemplate(odtTemplate, data) + + const odtResultTextContent = await getOdtTextContent(odtResult) + t.deepEqual(odtResultTextContent, `Liste de nombres + +Les nombres : 2 3 5 8  !! +`) + }); \ No newline at end of file diff --git a/tests/fixtures/formatting-liste-nombres-2-markeurs-formatted.odt b/tests/fixtures/formatting-liste-nombres-2-markeurs-formatted.odt new file mode 100644 index 0000000..0ff9cce Binary files /dev/null and b/tests/fixtures/formatting-liste-nombres-2-markeurs-formatted.odt differ diff --git a/tests/fixtures/liste-nombres-avec-formattage.odt b/tests/fixtures/formatting-liste-nombres-plusieurs-couches.odt similarity index 100% rename from tests/fixtures/liste-nombres-avec-formattage.odt rename to tests/fixtures/formatting-liste-nombres-plusieurs-couches.odt