I have a need to make some text bold or add links, and for it to then be added within a P tag that has a css class added to it.
The P tag class is specific to the template, and to I don't want to add it to the stylesheet and ask the editor to style the text.
One option is to use umbraco.library.RemoveFirstParagraphTag() but that's going to mess up if by any chance they do add a second paragraph.
In V4 there used to be a simple editor which was a textarea that helped style with <strong />s and <a />s, but that's gone.
I realise the simplest option is to change the CSS to get the styles applied by a parent class. Unfortunately there are loads of issues like this in the template and doing this is apparently not an option.
Currently I have a couple of extension methods that seem to work, but I'm worried about performance.
I thought I'd post my extension method in case anyone else finds it useful.
public static IHtmlString AddCssClass(this IHtmlString htmlString,
IEnumerable<KeyValuePair<string, string>> tagsAndClasses)
{
if (htmlString == null)
return null;
if (tagsAndClasses == null) throw new ArgumentNullException("tagsAndClasses");
try
{
using (UmbracoContext.Current.Application.ProfilingLogger.DebugDuration<HtmlString>("AddCssClass"))
{
var tagsAndClassesArr = tagsAndClasses.AsArray();
var str = htmlString.ToHtmlString();
//Check if we can get away with any of the tags have a class attribute
//if not then otherwise a simple regex replace should work
var simpleReplaceOkay = str.IndexOf(" class=", StringComparison.InvariantCultureIgnoreCase) < 0 ||
tagsAndClassesArr
.Select(pair => pair.Key)
.All(tagName => !Regex.IsMatch(str, "<" + Regex.Escape(tagName) + @"\s[^>]*class.*>",
RegexOptions.IgnoreCase | RegexOptions.Multiline));
if (simpleReplaceOkay)
{
foreach (var pair in tagsAndClassesArr)
{
var tagName = Regex.Escape(pair.Key);
var cssClass = pair.Value;
str = Regex.Replace(str,
string.Format(@"<{0}(?=[\s>])", tagName),
string.Format(@"<{0} class='{1}' ", tagName, cssClass),
RegexOptions.IgnoreCase | RegexOptions.Multiline);
}
return new HtmlString(str);
}
//Full expensive HTML parse using HtmlAgilityPack
var doc = new HtmlDocument();
doc.LoadHtml(str);
foreach (var pair in tagsAndClassesArr)
{
var tagName = pair.Key;
var cssClass = pair.Value;
foreach (var tag in doc.DocumentNode.SelectNodes("//" + tagName))
{
var att = tag.Attributes["class"];
if (att == null)
tag.Attributes.Add("class", cssClass);
else
att.Value += " " + cssClass;
}
}
var textReader = new StringWriter();
doc.Save(textReader);
return new HtmlString(textReader.ToString());
}
}
catch (Exception exception)
{
LogHelper.Warn<HtmlString>("Unable to add css class to html: " + exception.Message);
}
return htmlString;
}
I wouldn't even worry about the regex approach you are doing. I would stick with just the "expensive HTML parse" approach instead. The performance shouldn't be that bad.
If you are really worried about performance, you could cache the conversion in a dictionary for fast lookup on subsequent conversion attempts. They key would be the original text, and the value would be the modified text.
If you went with the dictionary approach, you might be worried about memory building up. However, if this is rich text entered by users of the CMS, the variety of text that gets cached should be relatively minimal (i.e., perhaps a few thousand strings). If you really wanted to optimize for memory, you could also implement an expiring/max memory cache (i.e., entries would be removed after a certain duration, or the oldest entries would be removed after the dictionary reached a certain size).
Rich text editor without a P tag
I have a need to make some text bold or add links, and for it to then be added within a P tag that has a css class added to it.
The P tag class is specific to the template, and to I don't want to add it to the stylesheet and ask the editor to style the text.
One option is to use
umbraco.library.RemoveFirstParagraphTag()
but that's going to mess up if by any chance they do add a second paragraph.In V4 there used to be a simple editor which was a textarea that helped style with
<strong />
s and<a />
s, but that's gone.I realise the simplest option is to change the CSS to get the styles applied by a parent class. Unfortunately there are loads of issues like this in the template and doing this is apparently not an option.
Currently I have a couple of extension methods that seem to work, but I'm worried about performance.
Anyone got a better idea?
I thought I'd post my extension method in case anyone else finds it useful.
I wouldn't even worry about the regex approach you are doing. I would stick with just the "expensive HTML parse" approach instead. The performance shouldn't be that bad.
If you are really worried about performance, you could cache the conversion in a dictionary for fast lookup on subsequent conversion attempts. They key would be the original text, and the value would be the modified text.
If you went with the dictionary approach, you might be worried about memory building up. However, if this is rich text entered by users of the CMS, the variety of text that gets cached should be relatively minimal (i.e., perhaps a few thousand strings). If you really wanted to optimize for memory, you could also implement an expiring/max memory cache (i.e., entries would be removed after a certain duration, or the oldest entries would be removed after the dictionary reached a certain size).
is working on a reply...
This forum is in read-only mode while we transition to the new forum.
You can continue this topic on the new forum by tapping the "Continue discussion" link below.