Skip to content

Commit a93be7e

Browse files
authored
LT-22048 Make picture copyright use analysis WS style (#343)
WS to use for picture copyright is already specified as an argument in AddProperty. Added handling in the xhtml generator to add a lang element to the property. Fix before/after styles to add a span when a lang element has been added. Fix homograph unit tests.
1 parent 5e3e5de commit a93be7e

6 files changed

Lines changed: 75 additions & 18 deletions

File tree

Src/xWorks/ConfiguredLcmGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,7 +2676,7 @@ private static IFragment GenerateContentForSimpleString(List<ConfigurableDiction
26762676
{
26772677
var writingSystem = GetLanguageFromFirstOptionOrAnalysis(nodeList.Last().DictionaryNodeOptions as
26782678
DictionaryNodeWritingSystemOptions, settings.Cache);
2679-
var cssClassName = settings.StylesGenerator.AddStyles(nodeList).Trim('.');
2679+
var cssClassName = settings.StylesGenerator.AddStyles(nodeList, true).Trim('.');
26802680
return settings.ContentGenerator.AddProperty(nodeList, settings, cssClassName, false, simpleString, writingSystem);
26812681

26822682
}
@@ -3398,7 +3398,7 @@ internal struct SenseInfo
33983398
public interface ILcmStylesGenerator
33993399
{
34003400
void AddGlobalStyles(DictionaryConfigurationModel model, ReadOnlyPropertyTable propertyTable);
3401-
string AddStyles(List<ConfigurableDictionaryNode> nodeList);
3401+
string AddStyles(List<ConfigurableDictionaryNode> nodeList, bool addSpanBeforeAfter = false);
34023402
void Init(ReadOnlyPropertyTable propertyTable);
34033403
}
34043404

Src/xWorks/CssGenerator.cs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,13 @@ public void AddGlobalStyles(DictionaryConfigurationModel model, ReadOnlyProperty
8787
/// node.Parent's. Where it will differ is when a node has a reference node. Instead
8888
/// of containing 'node.Parent' it follows the path from where the reference is made.
8989
/// </param>
90+
/// <param name="addSpanBeforeAfter">This bool defaults to false but is set to true when the
91+
/// content of a given node is a simple string. In this case, a writing system span will be
92+
/// added to the style in the xhtml, and the before and after styles need "span" added in order to inherit
93+
/// the properties of that writing system span.
94+
/// </param>
9095
/// <returns>The unique node name for the last node in the list.</returns>
91-
public string AddStyles(List<ConfigurableDictionaryNode> nodeList)
96+
public string AddStyles(List<ConfigurableDictionaryNode> nodeList, bool addSpanBeforeAfter = false)
9297
{
9398
lock (_styleDictionary)
9499
{
@@ -104,7 +109,7 @@ public string AddStyles(List<ConfigurableDictionaryNode> nodeList)
104109

105110
if (!_styleDictionary.ContainsKey(uniqueNodeName))
106111
{
107-
var styleRules = GenerateCssFromConfigurationNode(workingNode, uniqueNodeName, _propertyTable).NonEmpty();
112+
var styleRules = GenerateCssFromConfigurationNode(workingNode, uniqueNodeName, _propertyTable, addSpanBeforeAfter).NonEmpty();
108113
styleRules = styleRules.Distinct().ToList(); // Remove duplicate rules.
109114
AddUniquePathToStyleRules(styleRules, uniqueNodePath);
110115
_styleDictionary[uniqueNodeName] = styleRules;
@@ -341,7 +346,7 @@ private static void GenerateCssForAudioWs(StyleSheet styleSheet, LcmCache cache)
341346
/// <summary>
342347
/// Generates css rules for a configuration node and adds them to the given stylesheet (recursive).
343348
/// </summary>
344-
private static List<StyleRule> GenerateCssFromConfigurationNode(ConfigurableDictionaryNode configNode, string baseSelection, ReadOnlyPropertyTable propertyTable)
349+
private static List<StyleRule> GenerateCssFromConfigurationNode(ConfigurableDictionaryNode configNode, string baseSelection, ReadOnlyPropertyTable propertyTable, bool addSpanBeforeAfter = false)
345350
{
346351
var cache = propertyTable.GetValue<LcmCache>("cache");
347352
switch (configNode.DictionaryNodeOptions)
@@ -375,7 +380,7 @@ private static List<StyleRule> GenerateCssFromConfigurationNode(ConfigurableDict
375380
var rule = new StyleRule();
376381

377382
var selectors = GenerateSelectorsFromNode(configNode, ref baseSelection,
378-
cache, propertyTable);
383+
cache, propertyTable, addSpanBeforeAfter);
379384

380385
var wsOptions = configNode.DictionaryNodeOptions as DictionaryNodeWritingSystemOptions;
381386
if (wsOptions != null)
@@ -828,7 +833,7 @@ private static List<StyleRule> GenerateCssFromPictureOptions(ConfigurableDiction
828833
/// This method will generate before and after rules if the configuration node requires them. It also generates the selector for the node
829834
/// </summary>
830835
private static List<StyleRule> GenerateSelectorsFromNode(ConfigurableDictionaryNode configNode,
831-
ref string baseSelection, LcmCache cache, ReadOnlyPropertyTable propertyTable)
836+
ref string baseSelection, LcmCache cache, ReadOnlyPropertyTable propertyTable, bool addSpanBeforeAfter = false)
832837
{
833838
var rules = new List<StyleRule>();
834839
var fwStyles = FontHeightAdjuster.StyleSheetFromPropertyTable(propertyTable);
@@ -937,25 +942,44 @@ private static List<StyleRule> GenerateSelectorsFromNode(ConfigurableDictionaryN
937942
if (!string.IsNullOrEmpty(configNode.Before))
938943
{
939944
var dec = new StyleDeclaration();
945+
StyleRule beforeRule;
940946
dec.Add(new Property("content") { Term = new PrimitiveTerm(UnitType.String, SpecialCharacterHandling.MakeSafeCss(configNode.Before)) });
941947
if (fwStyles != null && fwStyles.Styles.Contains(BeforeAfterBetweenStyleName))
942948
dec.Properties.AddRange(GenerateCssStyleFromLcmStyleSheet(BeforeAfterBetweenStyleName, cache.DefaultAnalWs, propertyTable));
943949
var selectorBase = collectionSelector;
944950
if (configNode.FieldDescription == "PicturesOfSenses")
945951
selectorBase += "> div:first-child";
946-
var beforeRule = new StyleRule(dec) { Value = GetBaseSelectionWithSelectors(selectorBase, ":before") };
952+
953+
// The addSpanBeforeAfter argument indicates whether we need to add a span to the before/after and skip the usual selector formatting.
954+
// This is only needed in the case that we have a writing system unaware property that has had a writing system added via "GenerateContentForSimpleString".
955+
if (addSpanBeforeAfter)
956+
{
957+
beforeRule = new StyleRule(dec) { Value = selectorBase + " span:before" };
958+
}
959+
else
960+
beforeRule = new StyleRule(dec) { Value = GetBaseSelectionWithSelectors(selectorBase, ":before") };
947961
rules.Add(beforeRule);
948962
}
949963
if(!string.IsNullOrEmpty(configNode.After))
950964
{
951965
var dec = new StyleDeclaration();
966+
StyleRule afterRule;
952967
dec.Add(new Property("content") { Term = new PrimitiveTerm(UnitType.String, SpecialCharacterHandling.MakeSafeCss(configNode.After)) });
953968
if (fwStyles != null && fwStyles.Styles.Contains(BeforeAfterBetweenStyleName))
954969
dec.Properties.AddRange(GenerateCssStyleFromLcmStyleSheet(BeforeAfterBetweenStyleName, cache.DefaultAnalWs, propertyTable));
955970
var selectorBase = collectionSelector;
956971
if (configNode.FieldDescription == "PicturesOfSenses")
957972
selectorBase += "> div:last-child";
958-
var afterRule = new StyleRule(dec) { Value = GetBaseSelectionWithSelectors(selectorBase, ":after") };
973+
974+
// The addSpanBeforeAfter argument indicates whether we need to add a span to the before/after and skip the usual selector formatting.
975+
// This is only needed in the case that we have a writing system unaware property that has had a writing system added via "GenerateContentForSimpleString".
976+
if (addSpanBeforeAfter)
977+
{
978+
afterRule = new StyleRule(dec) { Value = selectorBase + " span:after" };
979+
}
980+
else
981+
afterRule = new StyleRule(dec) { Value = GetBaseSelectionWithSelectors(selectorBase, ":after") };
982+
959983
rules.Add(afterRule);
960984
}
961985
return rules;

Src/xWorks/LcmWordGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1998,7 +1998,7 @@ public void AddGlobalStyles(DictionaryConfigurationModel model, ReadOnlyProperty
19981998
/// the situations where a unique style name is generated, because the reference needs to use the
19991999
/// unique name.
20002000
/// </summary>
2001-
public string AddStyles(List<ConfigurableDictionaryNode> nodeList)
2001+
public string AddStyles(List<ConfigurableDictionaryNode> nodeList, bool addSpanBeforeAfter = false)
20022002
{
20032003
var node = nodeList.Last();
20042004
if (WordStylesGenerator.IsParagraphStyle(node.Style, _propertyTable))

Src/xWorks/LcmXhtmlGenerator.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,16 @@ public IFragment AddProperty(List<ConfigurableDictionaryNode> nodeList,
11011101
xw.WriteStartElement(isBlockProperty ? "div" : "span");
11021102
xw.WriteAttributeString("class", className);
11031103
WriteNodeId(xw, nodeList.Last(), settings);
1104+
if (writingSystem != null)
1105+
{
1106+
xw.WriteStartElement("span");
1107+
xw.WriteAttributeString("lang", writingSystem);
1108+
}
11041109
xw.WriteString(content);
1110+
if (writingSystem != null)
1111+
{
1112+
xw.WriteEndElement();
1113+
}
11051114
xw.WriteEndElement();
11061115
xw.Flush();
11071116
return fragment;

Src/xWorks/xWorksTests/ConfiguredXHTMLGeneratorTests.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,15 @@ public void GenerateContentForEntry_HomographNumbersGeneratesCorrectResult()
483483
XHTMLStringBuilder.Append(result);
484484
XHTMLStringBuilder.AppendLine("</TESTWRAPPER>");
485485

486-
var entryWithHomograph = "/TESTWRAPPER/div[@class='lexentry']/span[@class='homographnumber' and text()='1']";
486+
// Normally the propertyvalue for a headword with homograph number is IMultiStringAccessor.
487+
// However, in the test setup the propertyvalue for homograph number is an int
488+
// and therefore hits the int case of GenerateContentForValue in ConfiguredLcmGenerator,
489+
// and is directed to "GenerateContentForSimpleString", which applies the first analysis WS.
490+
// This creates an extra "/span[@lang='en' and text()=...]" at the end of the lexentry.
491+
// We don't care if a WS is assigned, so we ignore this possible extra span and check only for the correct homograph number.
492+
var entryWithHomograph = "/TESTWRAPPER/div[@class='lexentry']/span[@class='homographnumber' and text()=1] | /TESTWRAPPER/div[@class='lexentry']/span[@class='homographnumber']/*[text()=1]";
487493
AssertThatXmlIn.String(XHTMLStringBuilder.ToString()).HasSpecifiedNumberOfMatchesForXpath(entryWithHomograph, 1);
488-
entryWithHomograph = "/TESTWRAPPER/div[@class='lexentry']/span[@class='homographnumber' and text()='2']";
494+
entryWithHomograph = "/TESTWRAPPER/div[@class='lexentry']/span[@class='homographnumber' and text()=2] | /TESTWRAPPER/div[@class='lexentry']/span[@class='homographnumber']/*[text()=2]";
489495
AssertThatXmlIn.String(XHTMLStringBuilder.ToString()).HasSpecifiedNumberOfMatchesForXpath(entryWithHomograph, 1);
490496
}
491497

@@ -5504,7 +5510,7 @@ public void GenerateContentForEntry_PictureWithCreator()
55045510
//SUT
55055511
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, settings).ToString();
55065512
const string oneSenseWithPicture = "/div[@class='lexentry']/span[@class='pictures']/div[@class='picture']/img[@class='photo' and @id]";
5507-
const string oneSenseWithPictureCaption = "/div[@class='lexentry']/span[@class='pictures']/div[@class='picture']/div[@class='captionContent']/span[@class='creator' and text()='Jason Naylor']";
5513+
const string oneSenseWithPictureCaption = "/div[@class='lexentry']/span[@class='pictures']/div[@class='picture']/div[@class='captionContent']/span[@class='creator']/span[@lang='en' and text()='Jason Naylor']";
55085514
//This assert is dependent on the specific entry data created in CreateInterestingLexEntry
55095515
AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(oneSenseWithPicture, 1);
55105516
AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(oneSenseWithPictureCaption, 1);
@@ -6488,7 +6494,7 @@ public void GenerateContentForEntry_DateCustomFieldGeneratesContent()
64886494
var settings = new ConfiguredLcmGenerator.GeneratorSettings(Cache, m_propertyTable, false, false, null);
64896495
//SUT
64906496
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, settings).ToString();
6491-
var customDataPath = string.Format("/div[@class='lexentry']/span[@class='customdate' and text()='{0}']", customData.ToLongDateString());
6497+
var customDataPath = string.Format("/div[@class='lexentry']/span[@class='customdate']/span[@lang='en' and text()='{0}']", customData.ToLongDateString());
64926498
AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(customDataPath, 1);
64936499
}
64946500
}
@@ -6518,7 +6524,7 @@ public void GenerateContentForEntry_IntegerCustomFieldGeneratesContent()
65186524
var settings = new ConfiguredLcmGenerator.GeneratorSettings(Cache, m_propertyTable, false, false, null);
65196525
//SUT
65206526
var result = ConfiguredLcmGenerator.GenerateContentForEntry(testEntry, mainEntryNode, null, settings).ToString();
6521-
var customDataPath = string.Format("/div[@class='lexentry']/span[@class='custominteger' and text()='{0}']", customData);
6527+
var customDataPath = string.Format("/div[@class='lexentry']/span[@class='custominteger']/span[@lang='en' and text()='{0}']", customData);
65226528
AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(customDataPath, 1);
65236529
}
65246530
}

Src/xWorks/xWorksTests/LcmJsonGeneratorTests.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,13 +1103,31 @@ public void SavePublishedJsonWithStyles_DisplayXhtmlPopulated()
11031103
DefaultDecorator, 1,
11041104
new DictionaryConfigurationModel { Parts = new List<ConfigurableDictionaryNode> { mainEntryNode } },
11051105
m_propertyTable, "test.json", null, out int[] _);
1106-
var expectedResults = @"{""xhtmlTemplate"":""lexentry"",""guid"":""g" + testEntry.Guid + @""",""letterHead"": ""c"",""sortIndex"": 0,
1106+
1107+
// An explicitly stated writing system is not necessary for the homograph number to be correct.
1108+
// Normally the propertyvalue for a headword with homograph number is IMultiStringAccessor.
1109+
// However, in the test setup the propertyvalue for homograph number is an int
1110+
// and therefore hits the int case of GenerateContentForValue in ConfiguredLcmGenerator,
1111+
// and is directed to "GenerateContentForSimpleString", which applies the first analysis WS.
1112+
// The homograph portion of this test is only concerned with checking value of the homograph number; we don't care if a WS is assigned.
1113+
var expectedResultsWithoutWs = @"{""xhtmlTemplate"":""lexentry"",""guid"":""g" + testEntry.Guid + @""",""letterHead"": ""c"",""sortIndex"": 0,
11071114
""homographnumber"":""0"",""citationform"":[{""lang"":""fr"",""value"":""Citation""}],
11081115
""displayXhtml"":""<div class=\""lexentry\"" nodeId=\""" + mainEntryNode.GetNodeId() +
11091116
@"\"" id=\""g" + testEntry.Guid + @"\""><span class=\""homographnumber\"" nodeId=\""" + homographNum.GetNodeId() +
11101117
@"\"">0</span><span class=\""citationform\""><span nodeId=\""" + citationForm.GetNodeId() + @"\"" lang=\""fr\"">Citation</span></span></div>""}";
1111-
var expected = (JObject)JsonConvert.DeserializeObject(expectedResults, new JsonSerializerSettings { Formatting = Formatting.None });
1112-
VerifyJson(results[0][0].ToString(Formatting.None), expected);
1118+
var expectedResultsWithWs = @"{""xhtmlTemplate"":""lexentry"",""guid"":""g" + testEntry.Guid + @""",""letterHead"": ""c"",""sortIndex"": 0,
1119+
""homographnumber"":""0"",""citationform"":[{""lang"":""fr"",""value"":""Citation""}],
1120+
""displayXhtml"":""<div class=\""lexentry\"" nodeId=\""" + mainEntryNode.GetNodeId() +
1121+
@"\"" id=\""g" + testEntry.Guid + @"\""><span class=\""homographnumber\"" nodeId=\""" + homographNum.GetNodeId() +
1122+
@"\""><span lang=\""en\"">0</span></span><span class=\""citationform\""><span nodeId=\""" + citationForm.GetNodeId() + @"\"" lang=\""fr\"">Citation</span></span></div>""}";
1123+
1124+
var expectedWithoutWs = (JObject)JsonConvert.DeserializeObject(expectedResultsWithoutWs, new JsonSerializerSettings { Formatting = Formatting.None });
1125+
var expectedWithWs = (JObject)JsonConvert.DeserializeObject(expectedResultsWithWs, new JsonSerializerSettings { Formatting = Formatting.None });
1126+
1127+
dynamic jsonResult = JsonConvert.DeserializeObject(results[0][0].ToString(Formatting.None), new JsonSerializerSettings { Formatting = Formatting.None });
1128+
string actualReformatted = JsonConvert.SerializeObject(jsonResult, Formatting.Indented);
1129+
Assert.That(actualReformatted, Is.AnyOf(JsonConvert.SerializeObject(expectedWithoutWs, Formatting.Indented),
1130+
JsonConvert.SerializeObject(expectedWithWs, Formatting.Indented)));
11131131
}
11141132

11151133
[Test]

0 commit comments

Comments
 (0)