Skip to content
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### Version: 1.0.6
#### Date: June-09-2025
- Used 'title' and 'target' in a tags

### Version: 1.0.5
#### Date: Oct-10-2024
Expand Down
13 changes: 8 additions & 5 deletions Contentstack.Utils.Tests/Constants/JsonToHtmlConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ public static class JsonToHtmlResultConstants
public const string kTableHtml = "<table><thead><tr><th><p>Header 1</p></th><th><p>Header 2</p></th></tr></thead><tbody><tr><td><p>Body row 1 data 1</p></td><td><p>Body row 1 data 2</p></td></tr><tr><td><p>Body row 2 data 1</p></td><td><p>Body row 2 data 2</p></td></tr></tbody></table>";
public const string kBlockquoteHtml = "<blockquote>Praesent eu ex sed nibh venenatis pretium.</blockquote>";
public const string kCodeHtml = "<code>Code template.</code>";
public const string kLinkInPHtml = "<p style=\"text-align:left;\"><strong><em><u><sub></sub></u></em></strong><a href=\"LINK.com\">LINK</a></p>";
public const string kLinkInPMailToHtml = "<p style=\"text-align:left;\"><strong><em><u><sub></sub></u></em></strong><a href=\"mailto:support@contentstack.com\">LINK</a></p>";
public const string kLinkInPHtml = "<p style=\"text-align:left;\"><strong><em><u><sub></sub></u></em></strong><a href=\"LINK.com\" target=\"_self\" title=\"\" >LINK</a></p>";
public const string kLinkInPMailToHtml = "<p style=\"text-align:left;\"><strong><em><u><sub></sub></u></em></strong><a href=\"mailto:support@contentstack.com\" target=\"_self\" title=\"\" >LINK</a></p>";
public const string kLinkInPMailToTARGEtHtml = "<p style=\"text-align:left;\"><strong><em><u><sub></sub></u></em></strong><a href=\"mailto:support@contentstack.com\" target=\"_self\">LINK</a></p>";
public const string kEmbedHtml = "<iframe src=\"https://www.youtube.com/watch?v=AOP0yARiW8U\"></iframe>";
public const string stringClassIdResult = "<p><span id=\"i3\">This</span> is a <span class=\"c1\" id=\"i1\">text</span> to be <span class=\"c2\">ignored</span></p>" ;
public const string stringClassIdResult = "<p><span id=\"i3\">This</span> is a <span class=\"c1\" id=\"i1\">text</span> to be <span class=\"c2\">ignored</span></p>";
public const string kJSONRTEResult = "<p><strong>demoText</strong><u> is</u><em> demoText</em></p><p><em><sub>This</sub></em><em> </em><em><sup>is</sup></em><em> </em><em><strike>same </strike></em></p><p><strike><span>demoText2</span></strike></p><p><strike><span>demoText3</span></strike>demoText4</p><p>demoText3<a href=\"https://www.google.com/\" target=\"_blank\" title=\"demoText5\" >demoText2</a></p>";

}

public static class JsonToHtmlConstants
Expand Down Expand Up @@ -48,15 +50,15 @@ public static class JsonToHtmlConstants
public const string kEntryReferenceLinkJson = "{ \"uid\":\"06e34a7 5e4 e549d\", \"_version\":1, \"attrs\":{ }, \"children\":[{\"uid\":\"7626ea98e0e95d602210\",\"type\":\"reference\",\"attrs\":{\"target\":\"_self\",\"href\":\"/copy-of-entry-final-02\",\"display-type\":\"link\",\"entry-uid\":\"UID_08\",\"content-type-uid\":\"embeddedrte\",\"locale\":\"en-us\",\"type\":\"entry\",\"class-name\":\"embedded-entry\"},\"children\":[{\"text\":\"/copy-of-entry-final-02\"}]}],\"type\":\"doc\"}";
public const string kEntryReferenceInlineJson = "{ \"uid\":\"06e34a7 5e4 e549d\", \"_version\":1, \"attrs\":{ }, \"children\":[{\"uid\":\"506 4878f3f46 s21f0cbc aff\",\"type\":\"reference\",\"attrs\":{\"display-type\":\"inline\",\"entry-uid\":\"UID_09\",\"content-type-uid\":\"embeddedrte\",\"locale\":\"en-us\",\"type\":\"entry\",\"class-name\":\"embedded-entry\"},\"children\":[{\"text\":\"\"}]}],\"type\":\"doc\"}";
public const string kHRJson = "{ \"uid\":\"06e34a7 5e4 e549d\", \"_version\":1, \"attrs\":{ }, \"children\":[{\"uid\":\"f5a7b57 40a8a5c3 576828276b\",\"type\":\"hr\",\"children\":[{\"text\":\"\"}],\"attrs\":{ }}],\"type\":\"doc\"}";
public const string classId = "{ \"uid\":\"06e34a7 5e4 e549d\", \"_version\":1, \"attrs\":{ }, \"children\":[{\"uid\":\"f5a7b57 40a8a5c3 576828276b\",\"type\":\"doc\",\"children\":[{\"text\":\"Thorisbest\",\"classname\": \"c2\",\"id\": \"i2\"}],\"attrs\":{ }}],\"type\":\"text\"}";
public const string classId = "{ \"uid\":\"06e34a7 5e4 e549d\", \"_version\":1, \"attrs\":{ }, \"children\":[{\"uid\":\"f5a7b57 40a8a5c3 576828276b\",\"type\":\"doc\",\"children\":[{\"text\":\"demoTextisdemoText\",\"classname\": \"c2\",\"id\": \"i2\"}],\"attrs\":{ }}],\"type\":\"text\"}";
public const string stringClassId = "{ \"type\": \"doc\", \"attrs\": {}, \"uid\": \"8622288a91dc4c76985d776d2540b395\", \"children\": [ { \"type\": \"p\", \"uid\": \"396ee25abd0f4296a45eac63809450ef\", \"attrs\": {}, \"children\": [ { \"text\": \"This\", \"classname\": \"\", \"id\": \"i3\" }, { \"text\": \" is a \" }, { \"text\": \"text\", \"classname\": \"c1\", \"id\": \"i1\" }, { \"text\": \" to be \" }, { \"text\": \"ignored\", \"classname\": \"c2\", \"id\": \"\" } ] } ], \"_version\": 4 }";
public const string KAssetNode = "\"embedded_itemsConnection\": { \"edges\": [{ \"node\": { \"system\": { \"content_type_uid\": \"sys_assets\", \"uid\": \"UID_12\" }, \"created_at\": \"2020-08-19T09:13:32.785Z\", \"updated_at\": \"2020-08-19T09:13:32.785Z\", \"created_by\": \"Created_at\", \"updated_by\": \"Created_at\", \"content_type\": \"application/pdf\", \"file_size\": \"13264\", \"filename\": \"dummy.pdf\", \"url\":\"/v3/assetsUID_12/dummy.pdf\", \"_version\": 1, \"title\": \"dummy.pdf\" } } ]}";
public const string KEntryBlocNode = "\"embedded_itemsConnection\": { \"edges\": [{ \"node\": { \"title\": \"Update this title\", \"url\": \"\", \"locale\": \"en-us\", \"system\": { \"uid\": \"UID_07\", \"content_type_uid\": \"content_block\" }, \"_version\": 5, \"_in_progress\": false, \"multi_line\": \"\", \"rich_text_editor\": \"\" } } ]}";
public const string KEntryLinkNode = "\"embedded_itemsConnection\": { \"edges\": [{ \"node\": { \"title\": \"Entry with embedded entry\", \"rich_text_editor\": [ \"\" ], \"locale\": \"en-us\", \"system\": { \"uid\": \"UID_08\", \"content_type_uid\": \"embeddedrte\" }, \"_in_progress\": false } } ]}";
public const string KEntryInlineNode = "\"embedded_itemsConnection\": { \"edges\": [{ \"node\": { \"title\": \"updated title\", \"rich_text_editor\": [ \"\" ], \"locale\": \"en-us\", \"system\": { \"uid\": \"UID_09\", \"content_type_uid\": \"embeddedrte\", }, \"_in_progress\": false } } ]}";
public static string KGQLModel(string node, string embedConnection = null)
{
return $"{{\"multiplerte\":{{\"json\":[{node}]{(embedConnection != null ? ","+embedConnection : "")} }}, \"singlerte\":{{\"json\":{node}{(embedConnection != null ? "," + embedConnection : "")}}} }}";
return $"{{\"multiplerte\":{{\"json\":[{node}]{(embedConnection != null ? "," + embedConnection : "")} }}, \"singlerte\":{{\"json\":{node}{(embedConnection != null ? "," + embedConnection : "")}}} }}";
}

public const string kAssetMeta = "{\"uid\":\"asset_uid\",\"created_by\":\"create_by\",\"updated_by\":\"update_by\",\"content_type\":\"image/jpeg\",\"file_size\":\"62181\",\"tags\":[],\"filename\":\"crop_area.jpeg\",\"url\":\"http://image.contenstack.com/crop_area.jpeg\",\"is_dir\":false,\"parent_uid\":null,\"path\":[],\"_version\":1,\"title\":\"crop_area.jpeg\",\"dimension\":{\"height\":712,\"width\":864},\"_metadata\":{\"extensions\":{\"extension_uid\":{\"local_metadata\":{\"local_data\":\"main\",\"presets\":[{\"uid\":\"preset_01\",\"name\":\"Local Preset\",\"options\":{\"transform\":{\"height\":500,\"width\":500,\"flip-mode\":\"horiz\",\"rotate\":40},\"focal-point\":{\"x\":-0.668935003427432,\"y\":-0.9220385351936531},\"quality\":\"100\",\"image-type\":\"jpeg\"}},{\"uid\":\"preset_02\",\"name\":\"WithCrop\",\"options\":{\"quality\":\"100\",\"transform\":{\"height\":\"569.6\",\"width\":\"569.6\",\"flip-mode\":\"both\"},\"image-type\":\"jpeg\",\"crop\":{\"height\":\"569.6\",\"width\":\"569.6\",\"x\":\"147.2\",\"y\":\"71.2\"}}},{\"uid\":\"preset_03\",\"name\":\"Filter\",\"options\":{\"quality\":\"100\",\"transform\":{\"height\":712,\"width\":864},\"image-type\":\"jpeg\",\"effects\":{\"brightness\":52,\"contrast\":15,\"saturate\":-30,\"blur\":16,\"sharpen\":{\"amount\":9,\"radius\":669,\"threshold\":207}}}}]},\"global_metadata\":{\"presets\":[{\"uid\":\"preset_04\",\"name\":\"Global Preset\",\"options\":{\"quality\":\"100\",\"transform\":{\"height\":\"712\",\"width\":\"864\",\"flip-mode\":\"verti\"},\"image-type\":\"jpeg\"}}]}}}}}";
Expand All @@ -65,6 +67,7 @@ public static string KGQLModel(string node, string embedConnection = null)
public const string kAssetPresets = "{\"uid\":\"asset_uid\",\"created_by\":\"create_by\",\"updated_by\":\"update_by\",\"content_type\":\"image/jpeg\",\"file_size\":\"62181\",\"tags\":[],\"filename\":\"crop_area.jpeg\",\"url\":\"http://image.contenstack.com/crop_area.jpeg\",\"is_dir\":false,\"parent_uid\":null,\"path\":[],\"_version\":1,\"title\":\"crop_area.jpeg\",\"dimension\":{\"height\":712,\"width\":864},\"_metadata\":{\"extensions\":{\"extension_uid\":{\"local_metadata\":{\"local_data\":\"main\",\"presets\":[{\"uid\":\"preset_01\",\"name\":\"Local Preset\",\"options\":{}},{\"uid\":\"preset_02\",\"name\":\"WithCrop\",\"options\":{\"quality\":\"100\",\"transform\":{},\"image-type\":\"jpeg\",\"crop\":{}}},{\"uid\":\"preset_03\",\"name\":\"Filter\",\"options\":{\"quality\":\"100\",\"transform\":{\"height\":712,\"width\":864},\"image-type\":\"jpeg\",\"effects\":{}}}]},\"global_metadata\":{\"presets\":[{\"uid\":\"preset_04\",\"name\":\"Global Preset\",\"options\":{\"quality\":\"100\",\"transform\":{\"height\":\"712\",\"width\":\"864\",\"flip-mode\":\"verti\"},\"image-type\":\"jpeg\"}}]}}}}}";
public const string kAsset = "{\"uid\":\"asset_uid\",\"created_by\":\"create_by\",\"updated_by\":\"update_by\",\"content_type\":\"image/jpeg\",\"file_size\":\"62181\",\"tags\":[],\"filename\":\"crop_area.jpeg\",\"url\":\"http://image.contenstack.com/crop_area.jpeg\",\"is_dir\":false,\"parent_uid\":null,\"path\":[],\"_version\":1,\"title\":\"crop_area.jpeg\",\"dimension\":{\"height\":712,\"width\":864},\"_metadata\":{}}";
public const string kAssetMetaURLQuery = "{\"uid\":\"asset_uid\",\"created_by\":\"create_by\",\"updated_by\":\"update_by\",\"content_type\":\"image/jpeg\",\"file_size\":\"62181\",\"tags\":[],\"filename\":\"crop_area.jpeg\",\"url\":\"http://image.contenstack.com/crop_area.jpeg?render=full&noval\",\"is_dir\":false,\"parent_uid\":null,\"path\":[],\"_version\":1,\"title\":\"crop_area.jpeg\",\"dimension\":{\"height\":712,\"width\":864},\"_metadata\":{\"extensions\":{\"extension_uid\":{\"local_metadata\":{\"local_data\":\"main\",\"presets\":[{\"uid\":\"preset_01\",\"name\":\"Local Preset\",\"options\":{\"transform\":{\"height\":500,\"width\":500,\"flip-mode\":\"horiz\",\"rotate\":40},\"focal-point\":{\"x\":-0.668935003427432,\"y\":-0.9220385351936531},\"quality\":\"100\",\"image-type\":\"jpeg\"}},{\"uid\":\"preset_02\",\"name\":\"WithCrop\",\"options\":{\"quality\":\"100\",\"transform\":{\"height\":\"569.6\",\"width\":\"569.6\",\"flip-mode\":\"both\"},\"image-type\":\"jpeg\",\"crop\":{\"height\":\"569.6\",\"width\":\"569.6\",\"x\":\"147.2\",\"y\":\"71.2\"}}},{\"uid\":\"preset_03\",\"name\":\"Filter\",\"options\":{\"quality\":\"100\",\"transform\":{\"height\":712,\"width\":864},\"image-type\":\"jpeg\",\"effects\":{\"brightness\":52,\"contrast\":15,\"saturate\":-30,\"blur\":16,\"sharpen\":{\"amount\":9,\"radius\":669,\"threshold\":207}}}}]},\"global_metadata\":{\"presets\":[{\"uid\":\"preset_04\",\"name\":\"Global Preset\",\"options\":{\"quality\":\"100\",\"transform\":{\"height\":\"712\",\"width\":\"864\",\"flip-mode\":\"verti\"},\"image-type\":\"jpeg\"}}]}}}}}";
public const string kJSONRTE = "{ \"uid\":\"uid\",\"_version\":1,\"locale\":\"en-us\",\"children\":[{\"type\":\"p\",\"children\":[{\"text\":\"demoText\",\"bold\":true},{\"text\":\" is\",\"underline\":true},{\"text\":\" demoText\",\"italic\":true}]},{\"type\":\"p\",\"children\":[{\"text\":\"This\",\"italic\":true,\"subscript\":true},{\"text\":\" \",\"italic\":true},{\"text\":\"is\",\"italic\":true,\"superscript\":true},{\"text\":\" \",\"italic\":true},{\"text\":\"same \",\"italic\":true,\"strikethrough\":true}]},{\"type\":\"p\",\"children\":[{\"text\":\"demoText2\",\"strikethrough\":true,\"inlineCode\":true}]},{\"type\":\"p\",\"children\":[{\"text\":\"demoText3\",\"strikethrough\":true,\"inlineCode\":true},{\"text\":\"demoText4\"}]},{\"type\":\"p\",\"children\":[{\"text\":\"demoText3\"},{\"type\":\"a\",\"attrs\":{\"url\":\"https://www.google.com/\",\"target\":\"_blank\",\"title\":\"demoText5\"},\"children\":[{\"text\":\"demoText2\"}]}]}],\"type\":\"doc\"}";

}
}
4 changes: 2 additions & 2 deletions Contentstack.Utils.Tests/DefaultRenderTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Contentstack.Utils.Models;
using Contentstack.Utils.Models;
using Xunit;
using Contentstack.Utils.Tests.Mocks;
using Contentstack.Utils.Enums;
Expand Down Expand Up @@ -178,7 +178,7 @@ public void testLinkhDocument()

string result = defaultRender.RenderNode("a", nodeLink, (nodes) => { return text; });

Assert.Equal($"<a href=\"{nodeLink.attrs["url"]}\">{text}</a>", result);
Assert.Equal($"<a href=\"{nodeLink.attrs["url"]}\" target=\"{nodeLink.attrs["target"]}\" title=\"{nodeLink.attrs["title"]}\" >Text To set Link</a>", result);
}

[Fact]
Expand Down
8 changes: 8 additions & 0 deletions Contentstack.Utils.Tests/JsonToHtmlTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -489,5 +489,13 @@ public void TestForClassandId()

Assert.Equal(new List<string>() { JsonToHtmlResultConstants.stringClassIdResult }, result);
}

[Fact]
public void Should_Render_All_Marks_And_Target_Attribute()
{
Node node = NodeParser.parse(JsonToHtmlConstants.kJSONRTE);
var result = Utils.JsonToHtml(node, defaultRender);
Assert.Equal(JsonToHtmlResultConstants.kJSONRTEResult, result);
}
}
}
2 changes: 1 addition & 1 deletion Contentstack.Utils.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Global
{EB2B5E23-E45F-4C6C-BF98-FE3971DE4250}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
version = 1.0.5
version = 1.0.6
Policies = $0
$0.DotNetNamingPolicy = $1
$1.DirectoryNamespaceAssociation = PrefixedHierarchical
Expand Down
45 changes: 28 additions & 17 deletions Contentstack.Utils/Models/Options.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System;
using System.Collections.Generic;
using Contentstack.Utils.Enums;
using Contentstack.Utils.Enums;
using Contentstack.Utils.Interfaces;
using Newtonsoft.Json.Linq;

Expand All @@ -23,47 +23,47 @@ public virtual string RenderOption(IEmbeddedObject embeddedObject, Metadata meta
switch (metadata.StyleType)
{
case Enums.StyleType.Block:
string renderString = "<div><p>" + embeddedObject.Uid + "</p>";
string renderString = "<div><p>" + embeddedObject.Uid + "</p>";
if (embeddedObject is IEmbeddedEntry)
{
renderString += "<p>Content type: <span>" + ((IEmbeddedEntry)embeddedObject).Title + "</span></p>";
renderString += "<p>Content type: <span>" + ((IEmbeddedEntry)embeddedObject).Title + "</span></p>";
}
else
{
renderString += "<p>Content type: <span>" + embeddedObject.ContentTypeUid + "</span></p>";
renderString += "<p>Content type: <span>" + embeddedObject.ContentTypeUid + "</span></p>";
}
renderString = renderString + "</div>";
return renderString;

case Enums.StyleType.Inline:
if (embeddedObject is IEmbeddedEntry)
{
return "<span>" + ((IEmbeddedEntry)embeddedObject).Title + "</span>";
return "<span>" + ((IEmbeddedEntry)embeddedObject).Title + "</span>";
}
return "<span>" + embeddedObject.Uid + "</span>";
return "<span>" + embeddedObject.Uid + "</span>";

case Enums.StyleType.Link:
if (embeddedObject is IEmbeddedEntry)
{
return "<a href=\"" + embeddedObject.Uid + "\">" + (metadata.Text ?? ((IEmbeddedEntry)embeddedObject).Title) + "</a>";
return "<a href=\"" + embeddedObject.Uid + "\">" + (metadata.Text ?? ((IEmbeddedEntry)embeddedObject).Title) + "</a>";
}
return "<a href=\"" + embeddedObject.Uid + "\">" + (metadata.Text ?? embeddedObject.Uid) + "</a>";
return "<a href=\"" + embeddedObject.Uid + "\">" + (metadata.Text ?? embeddedObject.Uid) + "</a>";

case Enums.StyleType.Display:
if (embeddedObject is IEmbeddedAsset)
{
return "<img src=\"" + ((IEmbeddedAsset)embeddedObject).Url + "\" alt=\"" + ((IEmbeddedAsset)embeddedObject).Title + "\" />";
return "<img src=\"" + ((IEmbeddedAsset)embeddedObject).Url + "\" alt=\"" + ((IEmbeddedAsset)embeddedObject).Title + "\" />";
}
return "<img src=\"" + embeddedObject.Uid + "\" alt=\"" + embeddedObject.Uid + "\" />";
return "<img src=\"" + embeddedObject.Uid + "\" alt=\"" + embeddedObject.Uid + "\" />";

case Enums.StyleType.Download:
if (embeddedObject is IEmbeddedAsset)
{
return "<a href=\"" + ((IEmbeddedAsset)embeddedObject).Url + "\">" + (metadata.Text ?? ((IEmbeddedAsset)embeddedObject).Title) + "</a>";
return "<a href=\"" + ((IEmbeddedAsset)embeddedObject).Url + "\">" + (metadata.Text ?? ((IEmbeddedAsset)embeddedObject).Title) + "</a>";
}
return "<a href=\"" + embeddedObject.Uid + "\">" + (metadata.Text ?? embeddedObject.Uid) + "</a>";
return "<a href=\"" + embeddedObject.Uid + "\">" + (metadata.Text ?? embeddedObject.Uid) + "</a>";
}
return "";
return "";
}

public virtual string RenderMark(MarkType markType, string text, string className = "", string id = "")
Expand Down Expand Up @@ -97,8 +97,10 @@ public virtual string RenderNode(string nodeType, Node node, NodeChildrenCallBac
{
string href = "";
string styleAttrs = "";
string target = "";
string title = "";

if (node.attrs.ContainsKey("style"))
if (node.attrs?.ContainsKey("style") == true)
{
var styleVal = node.attrs["style"];
if (styleVal != null)
Expand All @@ -125,11 +127,20 @@ public virtual string RenderNode(string nodeType, Node node, NodeChildrenCallBac
case "p":
return $"<p{styleAttrs}>{callBack(node.children)}</p>";
case "a":
if (node.attrs.ContainsKey("url"))
if (node.attrs?.ContainsKey("url")==true)
{
href = (string)node.attrs["url"];
}
return $"<a href=\"{href}\"{styleAttrs}>{callBack(node.children)}</a>";
if (node.attrs?.ContainsKey("target") == true)
{
target = (string)node.attrs["target"];
}
if (node.attrs?.ContainsKey("title") == true)
{
title = (string)node.attrs["title"];
}
return $"<a href=\"{href}\" target=\"{target}\" title=\"{title}\" {styleAttrs}>{callBack(node.children)}</a>";

case "img":
if (node.attrs.ContainsKey("url"))
{
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<Version>1.0.5</Version>
<Version>1.0.6</Version>
</PropertyGroup>
</Project>
Loading