Home » Data » Seek and Destroy: Root Out Newlines and Carriage Returns in Multi-Line Text Fields

Seek and Destroy: Root Out Newlines and Carriage Returns in Multi-Line Text Fields

Sitecore Technology MVP 2016
Sitecore MVP 2015
Sitecore MVP 2014

Enter your email address to follow this blog and receive notifications of new posts by email.

Tweets

Advertisements

A couple of days ago, Sitecore MVP Brian Pedersen wrote an article discussing how newlines and carriage returns in Multi-Line Text fields can intrusively launch Sitecore’s “Do you want to save the changes to the item?” dialog box when clicking away from an item — even when you’ve made no changes to the item. Brian then offered an extension method on the String class as a way to remedy this annoyance.

However, Brian’s extension method cannot serve a solution on its own. It has to be invoked from somewhere to stamp out the substring malefactors — newlines (“\n”), carriage returns (“\r”), tabs (“\t”), and non-breaking spaces (“\xA0”).

This article gives one possible solution for uprooting these from Multi-Line Text fields within the Sitecore client by removing them upon item save.

First, I created a utility class that removes specified substrings from a string passed to it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sitecore.Sandbox.Utilities.StringUtilities.Base
{
    public interface ISubstringAnnihilator
    {
        string AnnihilateSubstrings(string input);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Sitecore.Sandbox.Utilities.StringUtilities.Base;

namespace Sitecore.Sandbox.Utilities.StringUtilities
{
    public class SubstringAnnihilator : ISubstringAnnihilator
    {
        private const string ReplacementString = " ";
        private static readonly IEnumerable<string> SubstringsToAnnihilate = new string[] { "\r\n", "\n", "\r", "\t", "\xA0"};

        private SubstringAnnihilator()
        {
        }

        public string AnnihilateSubstrings(string input)
        {
            foreach (string substringToAnnihilate in SubstringsToAnnihilate)
            {
                input = input.Replace(substringToAnnihilate, ReplacementString);
            }

            return input;
        }

        public static ISubstringAnnihilator CreateNewSubstringAnnihilator()
        {
            return new SubstringAnnihilator();
        }
    }
}

It would probably be ideal to move the target substrings defined within the SubstringsToAnnihilate string array into a configuration file or even into Sitecore itself. I decided not introduce that complexity here for the sake of brevity.

Next, I created a Save pipeline. I used .NET Reflector to see how other Save pipelines in /configuration/sitecore/processors/saveUI/ in the Web.config were built — I used these as a model for creating my own — and used my SubstringAnnihilator utility class to seek and destroy the target substrings (well, just replace them with a space :)).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Sitecore.Data;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Pipelines.Save;

using Sitecore.Sandbox.Utilities.StringUtilities;
using Sitecore.Sandbox.Utilities.StringUtilities.Base;

namespace Sitecore.Sandbox.Pipelines.SaveUI
{
    public class FixMultiLineTextFields
    {
        private static readonly ISubstringAnnihilator Annihilator = SubstringAnnihilator.CreateNewSubstringAnnihilator();

        public void Process(SaveArgs saveArgs)
        {
            FixAllItemFieldsWhereApplicable(saveArgs);
        }

        private static void FixAllItemFieldsWhereApplicable(SaveArgs saveArgs)
        {
            AssertSaveArgs(saveArgs);
            foreach (SaveArgs.SaveItem saveItem in saveArgs.Items)
            {
                FixSaveItemFieldsWhereApplicable(saveItem);
            }
        }

        private static void AssertSaveArgs(SaveArgs saveArgs)
        {
            Assert.ArgumentNotNull(saveArgs, "saveArgs");
            Assert.IsNotNull(saveArgs.Items, "saveArgs.Items");
        }

        private static void FixSaveItemFieldsWhereApplicable(SaveArgs.SaveItem saveItem)
        {
            Item item = GetItem(saveItem);
            foreach (SaveArgs.SaveField saveField in saveItem.Fields)
            {
                FixSaveItemFieldIfApplicable(item, saveField);
            }
        }

        private static Item GetItem(SaveArgs.SaveItem saveItem)
        {
            if (saveItem != null)
            {
                return Client.ContentDatabase.Items[saveItem.ID, saveItem.Language, saveItem.Version];
            }

            return null;
        }

        private static void FixSaveItemFieldIfApplicable(Item item, SaveArgs.SaveField saveField)
        {
            if (ShouldEnsureFieldValue(item, saveField))
            {
                saveField.Value = Annihilator.AnnihilateSubstrings(saveField.Value);
            }
        }

        private static bool ShouldEnsureFieldValue(Item item, SaveArgs.SaveField saveField)
        {
            Field field = item.Fields[saveField.ID];
            return ShouldEnsureFieldValue(field);
        }

        private static bool ShouldEnsureFieldValue(Field field)
        {
            return field.TypeKey == "memo"
                    || field.TypeKey == "multi-line text";
        }
    }
}

Now, it’s time to insert my new Save pipeline within the SaveUI pipeline stack. I’ve done this with my /App_Config/Include/FixMultiLineTextFields.config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
	<sitecore>
		<processors>
			<saveUI>
				<processor mode="on" type="Sitecore.Sandbox.Pipelines.SaveUI.FixMultiLineTextFields, Sitecore.Sandbox" patch:after="processor[@type='Sitecore.Pipelines.Save.TightenRelativeImageLinks, Sitecore.Kernel']" />
			</saveUI>
		</processors>
	</sitecore>
</configuration>

Let’s take the above for a spin. I’ve inserted a sentence with newlines after every word within it into my Blurb Multi-Line Text field:

newlines-galore

Now, I’ve clicked save, and all newlines within my Blurb Multi-Line Text field have been annihilated:

newlines-annihilated

I would like to thank to Brian Pedersen for writing his article the other day — it served as the bedrock for this one, and kindled something in me to write the code above.

Keep smiling when coding!

Advertisements

1 Comment

  1. Stephany says:

    Very good article. I’m experiencing a few of these issues as well..

Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: