Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions Src/xWorks/ConfiguredLcmGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1741,24 +1741,25 @@ private static void GenerateContentForLexEntryRefsByType(List<ConfigurableDictio
if (paraOptions != null && paraOptions.DisplayEachInAParagraph)
typeNode = null;
// Generate XHTML by Type
bool outerFirst = true;
foreach (var typeGuid in lexEntryTypesFiltered)
{
var combinedContent = settings.ContentGenerator.CreateFragment();
bool first = true;
bool innerFirst = true;
foreach (var lexEntRef in lerCollection)
{
if (isComplex ? lexEntRef.ComplexEntryTypesRS.Any(t => t.Guid == typeGuid) : lexEntRef.VariantEntryTypesRS.Any(t => t.Guid == typeGuid))
{
var content = GenerateCollectionItemContent(nodeList, pubDecorator, lexEntRef, collectionOwner, settings, first, typeNode);
var content = GenerateCollectionItemContent(nodeList, pubDecorator, lexEntRef, collectionOwner, settings, innerFirst, typeNode);
if (!content.IsNullOrEmpty())
{
combinedContent.Append(content);
first = false;
innerFirst = false;
}
}
}

if (!first)
if (combinedContent.Length() > 0)
{
var lexEntryType = lexEntryTypes.First(t => t.Guid.Equals(typeGuid));
// Display the Type if there were refs of this Type (and we are factoring)
Expand All @@ -1769,8 +1770,9 @@ private static void GenerateContentForLexEntryRefsByType(List<ConfigurableDictio
: null;
var className = generateLexType ? settings.StylesGenerator.AddStyles(workingNodeList).Trim('.') : null;
var refsByType = settings.ContentGenerator.AddLexReferences(workingNodeList, generateLexType,
lexTypeContent, className, combinedContent, IsTypeBeforeForm(config));
lexTypeContent, className, combinedContent, IsTypeBeforeForm(config), outerFirst);
bldr.Append(refsByType);
outerFirst = false;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Src/xWorks/ILcmContentGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ IFragment GenerateGroupingNode(List<ConfigurableDictionaryNode> nodeList, object
IFragment AddImage(ConfigurableDictionaryNode config, ConfiguredLcmGenerator.GeneratorSettings settings, string classAttribute, string srcAttribute, string pictureGuid, string license);
IFragment AddImageCaption(ConfigurableDictionaryNode config, IFragment captionContent);
IFragment GenerateSenseNumber(List<ConfigurableDictionaryNode> nodeList, ConfiguredLcmGenerator.GeneratorSettings settings, string formattedSenseNumber, string senseNumberWs);
IFragment AddLexReferences(List<ConfigurableDictionaryNode> nodeList, bool generateLexType, IFragment lexTypeContent, string className, IFragment referencesContent, bool typeBefore);
IFragment AddLexReferences(List<ConfigurableDictionaryNode> nodeList, bool generateLexType, IFragment lexTypeContent, string className, IFragment referencesContent, bool typeBefore, bool firstItem);
void BeginCrossReference(IFragmentWriter writer, ConfigurableDictionaryNode config, ConfiguredLcmGenerator.GeneratorSettings settings, bool isBlockProperty, string className);
void EndCrossReference(IFragmentWriter writer);
void BetweenCrossReferenceType(IFragment content, List<ConfigurableDictionaryNode> nodeList, bool firstItem);
Expand Down
2 changes: 1 addition & 1 deletion Src/xWorks/LcmJsonGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ public IFragment GenerateSenseNumber(List<ConfigurableDictionaryNode> nodeList,
}

public IFragment AddLexReferences(List<ConfigurableDictionaryNode> nodeList, bool generateLexType,
IFragment lexTypeContent, string className, IFragment referencesContent, bool typeBefore)
IFragment lexTypeContent, string className, IFragment referencesContent, bool typeBefore, bool firstItem)
{
var bldr = new StringBuilder();
var fragment = new StringFragment(bldr);
Expand Down
28 changes: 22 additions & 6 deletions Src/xWorks/LcmWordGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,8 @@ public IFragment WriteProcessedCollection(List<ConfigurableDictionaryNode> nodeL
return WriteProcessedElementContent(nodeList, elementContent);
}

private IFragment WriteProcessedElementContent(List<ConfigurableDictionaryNode> nodeList, IFragment elementContent)
private IFragment WriteProcessedElementContent(List<ConfigurableDictionaryNode> nodeList, IFragment elementContent,
bool includeBefore = true)
{
var config = nodeList.Last();
bool eachInAParagraph = config.DictionaryNodeOptions is IParaOption &&
Expand Down Expand Up @@ -1098,7 +1099,7 @@ private IFragment WriteProcessedElementContent(List<ConfigurableDictionaryNode>
}

// Add Before text, if it is not going to be displayed in a paragraph.
if (!eachInAParagraph && !string.IsNullOrEmpty(config.Before))
if (includeBefore &&!eachInAParagraph && !string.IsNullOrEmpty(config.Before))
{
var beforeRun = wsId.HasValue ? CreateBeforeAfterBetweenRun(nodeList, config.Before, wsId.Value) :
CreateDefaultBeforeAfterBetweenRun(nodeList, config.Before);
Expand Down Expand Up @@ -1875,22 +1876,37 @@ public IFragment GenerateSenseNumber(List<ConfigurableDictionaryNode> nodeList,
}

public IFragment AddLexReferences(List<ConfigurableDictionaryNode> nodeList, bool generateLexType,
IFragment lexTypeContent, string className, IFragment referencesContent, bool typeBefore)
IFragment lexTypeContent, string className, IFragment referencesContent, bool typeBefore, bool firstItem)
{
var fragment = new DocFragment();
var node = nodeList.Last();
bool includeBefore = true;

// Add Between text if it is not the first item in the collection.
if (!firstItem && !string.IsNullOrEmpty(node.Between))
{
var betweenRun = CreateDefaultBeforeAfterBetweenRun(nodeList, node.Between);
fragment.DocBody.Append(betweenRun);

// To keep the Word display the same as the display in Flex:
// If there is Between text, then we should not also add the Before text. LT-22517
includeBefore = false;
}

// Generate the factored ref types element (if before).
if (generateLexType && typeBefore)
{
fragment.Append(WriteProcessedObject(nodeList, false, lexTypeContent, className));
fragment.Append(WriteProcessedElementContent(nodeList, lexTypeContent, includeBefore));
}

// Then add all the contents for the LexReferences (e.g. headwords)
fragment.Append(referencesContent);

// Generate the factored ref types element (if after).
if (generateLexType && !typeBefore)
{
fragment.Append(WriteProcessedObject(nodeList, false, lexTypeContent, className));
fragment.Append(WriteProcessedElementContent(nodeList, lexTypeContent, includeBefore));
}

return fragment;
}

Expand Down
2 changes: 1 addition & 1 deletion Src/xWorks/LcmXhtmlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,7 @@ public IFragment GenerateSenseNumber(List<ConfigurableDictionaryNode> nodeList,
}

public IFragment AddLexReferences(List<ConfigurableDictionaryNode> nodeList, bool generateLexType,
IFragment lexTypeContent, string className, IFragment referencesContent, bool typeBefore)
IFragment lexTypeContent, string className, IFragment referencesContent, bool typeBefore, bool firstItem)
{
var bldr = new StringBuilder(100);
var fragment = new StringFragment(bldr);
Expand Down
200 changes: 198 additions & 2 deletions Src/xWorks/xWorksTests/LcmWordGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ public void GenerateSenseNumberData()
}

[Test]
public void GenerateBeforeBetweenAfterContent()
public void BeforeBetweenAfterContent()
{
var wsOpts = ConfiguredXHTMLGeneratorTests.GetWsOptionsForLanguages(new[] { "en" });
var senseOptions = new DictionaryNodeSenseOptions
Expand Down Expand Up @@ -472,7 +472,7 @@ public void GenerateBeforeBetweenAfterContent()
}

[Test]
public void GenerateBeforeBetweenAfterContentWithWSAbbreviation()
public void BeforeBetweenAfterContentWithWSAbbreviation()
{
var wsOpts = new DictionaryNodeWritingSystemOptions
{
Expand Down Expand Up @@ -538,6 +538,202 @@ public void GenerateBeforeBetweenAfterContentWithWSAbbreviation()
Assert.That(outXml.Contains(afterAbbreviation), Is.True);
}

[Test]
public void BetweenContentOnceForMultipleVariantTypesGroups()
{
// LT-22517: When an entry has variants of two different types, the Between text on the
// VariantEntryTypesRS node should appear exactly once — between the two type groups —
// and not before the first group.
const string betweenText = "BETWEEN_VARIANT_TYPES";
const string secondVariantType = "Spelling Variant";

// Create entries BEFORE building list options so both types are captured in the snapshot.
var mainEntry = ConfiguredXHTMLGeneratorTests.CreateInterestingLexEntry(Cache);
var variantForm1 = ConfiguredXHTMLGeneratorTests.CreateInterestingLexEntry(Cache);
var variantForm2 = ConfiguredXHTMLGeneratorTests.CreateInterestingLexEntry(Cache);
// Two variants of different types → two type groups in the output.
ConfiguredXHTMLGeneratorTests.CreateVariantForm(Cache, mainEntry, variantForm1); // "Crazy Variant" (TestVariantName)
ConfiguredXHTMLGeneratorTests.CreateVariantForm(Cache, mainEntry, variantForm2, secondVariantType);

var variantFormTypeNameNode = new ConfigurableDictionaryNode
{
FieldDescription = "Name",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetWsOptionsForLanguages(new[] { "en" })
};
// Between is on the VariantEntryTypesRS node because that is what nodeList.Last()
// resolves to inside AddLexReferences when factoring by type.
var variantFormTypeNode = new ConfigurableDictionaryNode
{
FieldDescription = "VariantEntryTypesRS",
CSSClassNameOverride = "variantentrytypes",
IsEnabled = true,
Between = betweenText,
Children = new List<ConfigurableDictionaryNode> { variantFormTypeNameNode }
};
var formNode = new ConfigurableDictionaryNode
{
FieldDescription = "OwningEntry",
SubField = "MLHeadWord",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetWsOptionsForLanguages(new[] { "fr" })
};
var variantsNode = new ConfigurableDictionaryNode
{
FieldDescription = "VariantFormEntryBackRefs",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetFullyEnabledListOptions(
DictionaryNodeListOptions.ListIds.Variant, Cache),
Children = new List<ConfigurableDictionaryNode> { variantFormTypeNode, formNode }
};
var mainEntryNode = new ConfigurableDictionaryNode
{
FieldDescription = "LexEntry",
IsEnabled = true,
Children = new List<ConfigurableDictionaryNode> { variantsNode },
Style = DictionaryNormal
};
CssGeneratorTests.PopulateFieldsForTesting(mainEntryNode);

// SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(mainEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
var outXml = result.DocBody.OuterXml;

// Between text should appear exactly once — between the two groups, not before the first.
Assert.That(Regex.Matches(outXml, betweenText).Count, Is.EqualTo(1),
"Between text should appear exactly once, between the two variant type groups");
}

[Test]
public void BetweenContentAbsentForSingleVariantTypeGroup()
{
// LT-22517: When an entry has variants of only one type, no Between text should appear.
const string betweenText = "BETWEEN_VARIANT_TYPES";

var mainEntry = ConfiguredXHTMLGeneratorTests.CreateInterestingLexEntry(Cache);
var variantForm1 = ConfiguredXHTMLGeneratorTests.CreateInterestingLexEntry(Cache);
ConfiguredXHTMLGeneratorTests.CreateVariantForm(Cache, mainEntry, variantForm1); // single type group

var variantFormTypeNameNode = new ConfigurableDictionaryNode
{
FieldDescription = "Name",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetWsOptionsForLanguages(new[] { "en" })
};
var variantFormTypeNode = new ConfigurableDictionaryNode
{
FieldDescription = "VariantEntryTypesRS",
CSSClassNameOverride = "variantentrytypes",
IsEnabled = true,
Between = betweenText,
Children = new List<ConfigurableDictionaryNode> { variantFormTypeNameNode }
};
var formNode = new ConfigurableDictionaryNode
{
FieldDescription = "OwningEntry",
SubField = "MLHeadWord",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetWsOptionsForLanguages(new[] { "fr" })
};
var variantsNode = new ConfigurableDictionaryNode
{
FieldDescription = "VariantFormEntryBackRefs",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetFullyEnabledListOptions(
DictionaryNodeListOptions.ListIds.Variant, Cache),
Children = new List<ConfigurableDictionaryNode> { variantFormTypeNode, formNode }
};
var mainEntryNode = new ConfigurableDictionaryNode
{
FieldDescription = "LexEntry",
IsEnabled = true,
Children = new List<ConfigurableDictionaryNode> { variantsNode },
Style = DictionaryNormal
};
CssGeneratorTests.PopulateFieldsForTesting(mainEntryNode);

// SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(mainEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
var outXml = result.DocBody.OuterXml;

// No Between text should appear when there is only one type group.
Assert.That(outXml, Does.Not.Contain(betweenText),
"Between text should not appear when there is only one variant type group");
}

[Test]
public void BeforeContentSuppressedOnSubsequentVariantTypeGroupsWhenBetweenPresent()
{
// LT-22517: When Between text separates variant type groups, the Before text should
// appear only before the first group. It should NOT be re-emitted after the Between
// text on subsequent groups (which would produce e.g. "; (TypeB)" instead of "; TypeB").
// This keeps the Word Export consistent with the display in Flex.
const string beforeText = "BEFORE_VARIANT_TYPES";
const string betweenText = "BETWEEN_VARIANT_TYPES";
const string secondVariantType = "Spelling Variant";

var mainEntry = ConfiguredXHTMLGeneratorTests.CreateInterestingLexEntry(Cache);
var variantForm1 = ConfiguredXHTMLGeneratorTests.CreateInterestingLexEntry(Cache);
var variantForm2 = ConfiguredXHTMLGeneratorTests.CreateInterestingLexEntry(Cache);
ConfiguredXHTMLGeneratorTests.CreateVariantForm(Cache, mainEntry, variantForm1); // "Crazy Variant" (TestVariantName)
ConfiguredXHTMLGeneratorTests.CreateVariantForm(Cache, mainEntry, variantForm2, secondVariantType);

var variantFormTypeNameNode = new ConfigurableDictionaryNode
{
FieldDescription = "Name",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetWsOptionsForLanguages(new[] { "en" })
};
var variantFormTypeNode = new ConfigurableDictionaryNode
{
FieldDescription = "VariantEntryTypesRS",
CSSClassNameOverride = "variantentrytypes",
IsEnabled = true,
Before = beforeText,
Between = betweenText,
Children = new List<ConfigurableDictionaryNode> { variantFormTypeNameNode }
};
var formNode = new ConfigurableDictionaryNode
{
FieldDescription = "OwningEntry",
SubField = "MLHeadWord",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetWsOptionsForLanguages(new[] { "fr" })
};
var variantsNode = new ConfigurableDictionaryNode
{
FieldDescription = "VariantFormEntryBackRefs",
IsEnabled = true,
DictionaryNodeOptions = ConfiguredXHTMLGeneratorTests.GetFullyEnabledListOptions(
DictionaryNodeListOptions.ListIds.Variant, Cache),
Children = new List<ConfigurableDictionaryNode> { variantFormTypeNode, formNode }
};
var mainEntryNode = new ConfigurableDictionaryNode
{
FieldDescription = "LexEntry",
IsEnabled = true,
Children = new List<ConfigurableDictionaryNode> { variantsNode },
Style = DictionaryNormal
};
CssGeneratorTests.PopulateFieldsForTesting(mainEntryNode);

// SUT
var result = ConfiguredLcmGenerator.GenerateContentForEntry(mainEntry, mainEntryNode, null, DefaultSettings, 0) as DocFragment;
var outXml = result.DocBody.OuterXml;

// Before text should appear exactly once — only before the first group.
Assert.That(Regex.Matches(outXml, beforeText).Count, Is.EqualTo(1),
"Before text should appear exactly once, only before the first variant type group");
// Between text should appear exactly once — between the two groups.
Assert.That(Regex.Matches(outXml, betweenText).Count, Is.EqualTo(1),
"Between text should appear exactly once, between the two variant type groups");
// Before text must appear earlier in the output than Between text:
// Before belongs to the first group; Between separates the first from the second.
// If Before appeared after Between it would mean it was (incorrectly) re-emitted on the second group.
Assert.That(outXml.IndexOf(beforeText), Is.LessThan(outXml.IndexOf(betweenText)),
"Before text should precede Between text in the output — it belongs to the first group only");
}

[Test]
public void GeneratePropertyData()
{
Expand Down
Loading