Text 'text after {/each} in same text node' failing
This commit is contained in:
parent
6ad0bab069
commit
53114fcb01
@ -1,5 +1,6 @@
|
|||||||
import {traverse, Node} from '../../DOMUtils.js'
|
import {traverse, Node} from '../../DOMUtils.js'
|
||||||
import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js'
|
import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js'
|
||||||
|
import prepareTemplateDOMTree from './prepareTemplateDOMTree.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef TextPlaceToFill
|
* @typedef TextPlaceToFill
|
||||||
@ -85,6 +86,8 @@ function findPlacesToFillInString(str, compartment) {
|
|||||||
* @returns {{startChild: Node, endChild:Node, content: DocumentFragment}}
|
* @returns {{startChild: Node, endChild:Node, content: DocumentFragment}}
|
||||||
*/
|
*/
|
||||||
function extractBlockContent(blockStartNode, blockEndNode) {
|
function extractBlockContent(blockStartNode, blockEndNode) {
|
||||||
|
console.log('[extractBlockContent] blockEndNode', blockEndNode.textContent)
|
||||||
|
|
||||||
// find common ancestor of blockStartNode and blockEndNode
|
// find common ancestor of blockStartNode and blockEndNode
|
||||||
let commonAncestor
|
let commonAncestor
|
||||||
|
|
||||||
@ -118,7 +121,10 @@ function extractBlockContent(blockStartNode, blockEndNode) {
|
|||||||
const startChild = startAncestryToCommonAncestor.at(-1)
|
const startChild = startAncestryToCommonAncestor.at(-1)
|
||||||
const endChild = endAncestryToCommonAncestor.at(-1)
|
const endChild = endAncestryToCommonAncestor.at(-1)
|
||||||
|
|
||||||
|
console.log('[extractBlockContent] endChild', endChild.textContent)
|
||||||
|
|
||||||
// Extract DOM content in a documentFragment
|
// Extract DOM content in a documentFragment
|
||||||
|
/** @type {DocumentFragment} */
|
||||||
const contentFragment = blockStartNode.ownerDocument.createDocumentFragment()
|
const contentFragment = blockStartNode.ownerDocument.createDocumentFragment()
|
||||||
|
|
||||||
/** @type {Element[]} */
|
/** @type {Element[]} */
|
||||||
@ -135,6 +141,8 @@ function extractBlockContent(blockStartNode, blockEndNode) {
|
|||||||
contentFragment.appendChild(sibling)
|
contentFragment.appendChild(sibling)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('extractBlockContent contentFragment', contentFragment.textContent)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
startChild,
|
startChild,
|
||||||
endChild,
|
endChild,
|
||||||
@ -231,11 +239,19 @@ function fillIfBlock(ifOpeningMarkerNode, ifElseMarkerNode, ifClosingMarkerNode,
|
|||||||
*/
|
*/
|
||||||
function fillEachBlock(startNode, iterableExpression, itemExpression, endNode, compartment) {
|
function fillEachBlock(startNode, iterableExpression, itemExpression, endNode, compartment) {
|
||||||
//console.log('fillEachBlock', iterableExpression, itemExpression)
|
//console.log('fillEachBlock', iterableExpression, itemExpression)
|
||||||
//console.log('startNode', startNode.nodeType, startNode.nodeName)
|
console.log('startNode', startNode.nodeName, startNode.textContent)
|
||||||
//console.log('endNode', endNode.nodeType, endNode.nodeName)
|
console.log('endNode', endNode.nodeName, endNode.textContent)
|
||||||
|
console.log('endNode parent', endNode.parentNode.childNodes.length, endNode.parentNode.textContent)
|
||||||
|
|
||||||
|
const doc = startNode.ownerDocument.documentElement
|
||||||
|
|
||||||
|
console.log('doc text', doc.textContent)
|
||||||
|
|
||||||
const {startChild, endChild, content: repeatedFragment} = extractBlockContent(startNode, endNode)
|
const {startChild, endChild, content: repeatedFragment} = extractBlockContent(startNode, endNode)
|
||||||
|
|
||||||
|
console.log('endChild after extractBlockContent', endChild.textContent)
|
||||||
|
console.log('doc text', doc.textContent)
|
||||||
|
|
||||||
// Find the iterable in the data
|
// Find the iterable in the data
|
||||||
// PPP eventually, evaluate the expression as a JS expression
|
// PPP eventually, evaluate the expression as a JS expression
|
||||||
let iterable = compartment.evaluate(iterableExpression)
|
let iterable = compartment.evaluate(iterableExpression)
|
||||||
@ -244,12 +260,18 @@ function fillEachBlock(startNode, iterableExpression, itemExpression, endNode, c
|
|||||||
iterable = []
|
iterable = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// create each loop result
|
// create each loop result
|
||||||
// using a for-of loop to accept all iterable values
|
// using a for-of loop to accept all iterable values
|
||||||
for(const item of iterable) {
|
for(const item of iterable) {
|
||||||
|
console.log('{#each}', itemExpression, item)
|
||||||
|
console.log('doc text', doc.textContent)
|
||||||
|
|
||||||
/** @type {DocumentFragment} */
|
/** @type {DocumentFragment} */
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const itemFragment = repeatedFragment.cloneNode(true)
|
const itemFragment = repeatedFragment.cloneNode(true)
|
||||||
|
console.log('itemFragment', itemFragment.textContent)
|
||||||
|
|
||||||
let insideCompartment = new Compartment({
|
let insideCompartment = new Compartment({
|
||||||
globals: Object.assign({}, compartment.globalThis, {[itemExpression]: item}),
|
globals: Object.assign({}, compartment.globalThis, {[itemExpression]: item}),
|
||||||
@ -262,12 +284,19 @@ function fillEachBlock(startNode, iterableExpression, itemExpression, endNode, c
|
|||||||
insideCompartment
|
insideCompartment
|
||||||
)
|
)
|
||||||
|
|
||||||
|
console.log('{#each} fragment', itemFragment.textContent)
|
||||||
|
|
||||||
endChild.parentNode.insertBefore(itemFragment, endChild)
|
endChild.parentNode.insertBefore(itemFragment, endChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('doc text after each', doc.textContent)
|
||||||
|
|
||||||
// remove block marker elements
|
// remove block marker elements
|
||||||
startChild.parentNode.removeChild(startChild)
|
startChild.parentNode.removeChild(startChild)
|
||||||
endChild.parentNode.removeChild(endChild)
|
endChild.parentNode.removeChild(endChild)
|
||||||
|
|
||||||
|
console.log('doc text after removes', doc.textContent)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -352,10 +381,14 @@ export default function fillOdtElementTemplate(rootElement, compartment) {
|
|||||||
if(currentlyOpenBlocks.length === 1) {
|
if(currentlyOpenBlocks.length === 1) {
|
||||||
eachClosingMarkerNode = currentNode
|
eachClosingMarkerNode = currentNode
|
||||||
|
|
||||||
|
console.log('before fillEachBlock', eachClosingMarkerNode.parentNode.textContent)
|
||||||
|
|
||||||
// found an {#each} and its corresponding {/each}
|
// found an {#each} and its corresponding {/each}
|
||||||
// execute replacement loop
|
// execute replacement loop
|
||||||
fillEachBlock(eachOpeningMarkerNode, eachBlockIterableExpression, eachBlockItemExpression, eachClosingMarkerNode, compartment)
|
fillEachBlock(eachOpeningMarkerNode, eachBlockIterableExpression, eachBlockItemExpression, eachClosingMarkerNode, compartment)
|
||||||
|
|
||||||
|
console.log('after fillEachBlock', rootElement.documentElement.textContent)
|
||||||
|
|
||||||
eachOpeningMarkerNode = undefined
|
eachOpeningMarkerNode = undefined
|
||||||
eachBlockIterableExpression = undefined
|
eachBlockIterableExpression = undefined
|
||||||
eachBlockItemExpression = undefined
|
eachBlockItemExpression = undefined
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
//@ts-check
|
||||||
|
|
||||||
import {traverse, Node} from "../../DOMUtils.js";
|
import {traverse, Node} from "../../DOMUtils.js";
|
||||||
import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js'
|
import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js'
|
||||||
|
|
||||||
@ -39,7 +41,7 @@ function findAllMatches(text, pattern) {
|
|||||||
*
|
*
|
||||||
* @param {Node} node1
|
* @param {Node} node1
|
||||||
* @param {Node} node2
|
* @param {Node} node2
|
||||||
* @returns {Node | undefined}
|
* @returns {Node}
|
||||||
*/
|
*/
|
||||||
function findCommonAncestor(node1, node2) {
|
function findCommonAncestor(node1, node2) {
|
||||||
const ancestors1 = getAncestors(node1);
|
const ancestors1 = getAncestors(node1);
|
||||||
@ -51,7 +53,7 @@ function findCommonAncestor(node1, node2) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
throw new Error(`node1 and node2 do not have a common ancestor`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -281,6 +283,8 @@ function consolidateMarkers(document){
|
|||||||
newStartNode.parentNode?.removeChild(newStartNode)
|
newStartNode.parentNode?.removeChild(newStartNode)
|
||||||
|
|
||||||
commonAncestor.insertBefore(newStartNode, commonAncestorStartChild.nextSibling)
|
commonAncestor.insertBefore(newStartNode, commonAncestorStartChild.nextSibling)
|
||||||
|
|
||||||
|
//console.log('commonAncestor after before-text split', commonAncestor.textContent )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -299,11 +303,15 @@ function consolidateMarkers(document){
|
|||||||
endNode.parentNode?.removeChild(endNode)
|
endNode.parentNode?.removeChild(endNode)
|
||||||
commonAncestor.insertBefore(endNode, commonAncestorEndChild)
|
commonAncestor.insertBefore(endNode, commonAncestorEndChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//console.log('commonAncestor after after-text split', commonAncestor.textContent )
|
||||||
}
|
}
|
||||||
|
|
||||||
// then, replace all nodes between (new)startNode and (new)endNode with a single textNode in commonAncestor
|
// then, replace all nodes between (new)startNode and (new)endNode with a single textNode in commonAncestor
|
||||||
replaceBetweenNodesWithText(newStartNode, endNode, positionedMarker.marker)
|
replaceBetweenNodesWithText(newStartNode, endNode, positionedMarker.marker)
|
||||||
|
|
||||||
|
//console.log('commonAncestor after replaceBetweenNodesWithText', commonAncestor.textContent )
|
||||||
|
|
||||||
// After consolidation, break as the DOM structure has changed
|
// After consolidation, break as the DOM structure has changed
|
||||||
// and containerTextNodesInTreeOrder needs to be refreshed
|
// and containerTextNodesInTreeOrder needs to be refreshed
|
||||||
consolidatedMarkers.push(positionedMarker)
|
consolidatedMarkers.push(positionedMarker)
|
||||||
@ -323,6 +331,8 @@ function consolidateMarkers(document){
|
|||||||
*/
|
*/
|
||||||
function isolateMarkers(document){
|
function isolateMarkers(document){
|
||||||
traverse(document, currentNode => {
|
traverse(document, currentNode => {
|
||||||
|
//console.log('isolateMarkers', currentNode.nodeName, currentNode.textContent)
|
||||||
|
|
||||||
if(currentNode.nodeType === Node.TEXT_NODE) {
|
if(currentNode.nodeType === Node.TEXT_NODE) {
|
||||||
// find all marker starts and ends and split textNode
|
// find all marker starts and ends and split textNode
|
||||||
let remainingText = currentNode.textContent || ''
|
let remainingText = currentNode.textContent || ''
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {getOdtTemplate} from '../../scripts/odf/odtTemplate-forNode.js'
|
|||||||
import {fillOdtTemplate, getOdtTextContent} from '../../exports.js'
|
import {fillOdtTemplate, getOdtTextContent} from '../../exports.js'
|
||||||
|
|
||||||
|
|
||||||
test('basic template filling with {#each}', async t => {
|
test.skip('basic template filling with {#each}', async t => {
|
||||||
const templatePath = join(import.meta.dirname, '../fixtures/enum-courses.odt')
|
const templatePath = join(import.meta.dirname, '../fixtures/enum-courses.odt')
|
||||||
const templateContent = `🧺 La liste de courses incroyable 🧺
|
const templateContent = `🧺 La liste de courses incroyable 🧺
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ Pâtes à lasagne (fraîches !)
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('Filling with {#each} and non-iterable value results in no error and empty result', async t => {
|
test.skip('Filling with {#each} and non-iterable value results in no error and empty result', async t => {
|
||||||
const templatePath = join(import.meta.dirname, '../fixtures/enum-courses.odt')
|
const templatePath = join(import.meta.dirname, '../fixtures/enum-courses.odt')
|
||||||
const templateContent = `🧺 La liste de courses incroyable 🧺
|
const templateContent = `🧺 La liste de courses incroyable 🧺
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ test('Filling with {#each} and non-iterable value results in no error and empty
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('template filling with {#each} generating a list', async t => {
|
test.skip('template filling with {#each} generating a list', async t => {
|
||||||
const templatePath = join(import.meta.dirname, '../fixtures/liste-courses.odt')
|
const templatePath = join(import.meta.dirname, '../fixtures/liste-courses.odt')
|
||||||
const templateContent = `🧺 La liste de courses incroyable 🧺
|
const templateContent = `🧺 La liste de courses incroyable 🧺
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ test('template filling with {#each} generating a list', async t => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('template filling with 2 sequential {#each}', async t => {
|
test.skip('template filling with 2 sequential {#each}', async t => {
|
||||||
const templatePath = join(import.meta.dirname, '../fixtures/liste-fruits-et-légumes.odt')
|
const templatePath = join(import.meta.dirname, '../fixtures/liste-fruits-et-légumes.odt')
|
||||||
const templateContent = `Liste de fruits et légumes
|
const templateContent = `Liste de fruits et légumes
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ Poivron 🫑
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('template filling with nested {#each}s', async t => {
|
test.skip('template filling with nested {#each}s', async t => {
|
||||||
const templatePath = join(import.meta.dirname, '../fixtures/légumes-de-saison.odt')
|
const templatePath = join(import.meta.dirname, '../fixtures/légumes-de-saison.odt')
|
||||||
const templateContent = `Légumes de saison
|
const templateContent = `Légumes de saison
|
||||||
|
|
||||||
@ -247,7 +247,43 @@ Hiver
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('template filling of a table', async t => {
|
test('template filling with text after {/each} in same text node', async t => {
|
||||||
|
const templatePath = join(import.meta.dirname, '../fixtures/text-after-closing-each.odt')
|
||||||
|
const templateContent = `Légumes de saison
|
||||||
|
|
||||||
|
{#each légumes as légume}
|
||||||
|
{légume},
|
||||||
|
{/each} en {saison}
|
||||||
|
`
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
saison: 'Printemps',
|
||||||
|
légumes: [
|
||||||
|
'Asperge',
|
||||||
|
'Betterave',
|
||||||
|
'Blette'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
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, `Légumes de saison
|
||||||
|
|
||||||
|
Asperge,
|
||||||
|
Betterave,
|
||||||
|
Blette, en Printemps
|
||||||
|
`)
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test.skip('template filling of a table', async t => {
|
||||||
const templatePath = join(import.meta.dirname, '../fixtures/tableau-simple.odt')
|
const templatePath = join(import.meta.dirname, '../fixtures/tableau-simple.odt')
|
||||||
const templateContent = `Évolution énergie en kWh par personne en France
|
const templateContent = `Évolution énergie en kWh par personne en France
|
||||||
|
|
||||||
|
|||||||
BIN
tests/fixtures/text-after-closing-each.odt
vendored
Normal file
BIN
tests/fixtures/text-after-closing-each.odt
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user