# Experience Editor bug: Multi-line text field deletes extra lines on save


<!--kg-card-begin: markdown-->
There is a pretty annoying bug when editing multi-line text fields through the Experience Editor which has been there since Sitecore 8.1 Update-1 and is not fixed as of 8.1 Update-3.
 
## The issue
 
If you enter multiple lines into a multi-line text field when editing with the Experience Editor and save, then only the first line is actually saved – all extra lines are deleted.
 
This happens because of a greedy Regular Expression – `<br.*/?>` – in the class `Sitecore.ExperienceEditor.WebUtility` which removes all content between the first `<br>` and the last `>` in the content.
 
Sitecore is aware of the problem and has registered the bug, but they do not have a temporaray fix for it, as they usually have.
 
The `WebUtility` class is a static class only meant for internal use by Sitecore and as such is not replacable through config files as most other things are.
 
You can read a bit more about this issue including another multi-line bug [here](http://www.kasaku.co.uk/2016/03/21/multiline-field-bugs-in-sitecore-8-1/) and [here](http://www.kayee.nl/2016/01/10/sitecore-8-1-multi-line-text-field-with-experience-button-problem/).
 
## A solution/workaround
 
While `WebUtility` being static makes the issue a bit more problematic to fix globally it is not impossible to at least workaround the Experience Editor issue.
 
By creating a fixed version of the relevant method in the `WebUtility` class and replacing the `CallServerSavePipeline` processor with our own we can workaround the problem. We get a bit dependent on changes to these parts by Sitecore in future releases, but hopefully this will be fixed in the next release so we don’t need to do this fix.
 
## The code
 
We start out by creating our fixed version of the `WebUtility.GetFields(Database, Dictionary<string, string>)` method. I’ve highlighted the interesting part below.

```csharp
public class WebUtility
{
    public static IEnumerable<PageEditorField> GetFields(Database database, Dictionary<string, string> dictionaryForm)
    {
        Assert.ArgumentNotNull(dictionaryForm, "dictionaryForm");
        var list = new List<PageEditorField>();
        foreach (var key in dictionaryForm.Keys)
        {
            if (!key.StartsWith("fld_", StringComparison.InvariantCulture) &&
                !key.StartsWith("flds_", StringComparison.InvariantCulture))
            {
                continue;
            }

            var text = key;
            var str1 = dictionaryForm[key];
            var indexOfDollarSign = text.IndexOf('$');
            if (indexOfDollarSign >= 0)
            {
                text = StringUtil.Left(text, indexOfDollarSign);
            }
            var values = text.Split('_');
            var itemId = ShortID.DecodeID(values[1]);
            var fieldId = ShortID.DecodeID(values[2]);
            var language = Language.Parse(values[3]);
            var version = Sitecore.Data.Version.Parse(values[4]);
            var revision = values[5];
            var item = database.GetItem(itemId);

            if (item == null)
                continue;

            var field = item.Fields[fieldId];
            if (key.StartsWith("flds_", StringComparison.InvariantCulture))
            {
                str1 = (string)WebUtil.GetSessionValue(str1);
                if (string.IsNullOrEmpty(str1))
                    str1 = field.Value;
            }
            switch (field.TypeKey)
            {
                case "html":
                case "rich text":
                    str1 = str1.TrimEnd(' ');
                    break;
                case "text":
                    str1 = StringUtil.RemoveTags(str1);
                    break;
                // FIX START
                case "multi-line text":
                case "memo":
                    str1 = StringUtil.RemoveTags(new Regex("<br.*?/*>", RegexOptions.IgnoreCase)
                                     .Replace(str1, "\r\n"));
                    break;
                // FIX END
            }
            var pageEditorField = new PageEditorField()
            {
                ControlId = text,
                FieldID = fieldId,
                ItemID = itemId,
                Language = language,
                Revision = revision,
                Value = str1,
                Version = version
            };
            list.Add(pageEditorField);
        }
        return list;
    }
}
```
 
Next up we need to create a new processor which gets called when you save through the Experience Editor.

```csharp
public class CallServerSavePipeline : PipelineProcessorRequest<PageContext>
{
    public override PipelineProcessorResponseValue ProcessRequest()
    {
        var responseValue = new PipelineProcessorResponseValue();
        var pipeline = PipelineFactory.GetPipeline("saveUI");
        pipeline.ID = ShortID.Encode(ID.NewID);
        var saveArgs = RequestContext.GetSaveArgsPatched(); // FIX
        using (new ClientDatabaseSwitcher(RequestContext.Item.Database))
        {
            pipeline.Start(saveArgs);
            CacheManager.GetItemCache(RequestContext.Item.Database).Clear();
            responseValue.AbortMessage = Translate.Text(saveArgs.Error);
            return responseValue;
        }
    }
}
```
 
On the highlighted line we call a new extension method on `PageContext`, which is just a fixed version of the original method `GetSaveArgs()` except we call our new `WebUtility.GetFields()` method instead.

```csharp
public static class PageContextExtensions
{
    public static SaveArgs GetSaveArgsPatched(this PageContext pageContext)
    {
        var args = PipelineUtil.GenerateSaveArgs(pageContext.Item,
            WebUtility.GetFields(pageContext.Item.Database, pageContext.FieldValues), // FIX
            "",
            pageContext.LayoutSource,
            "",
            Sitecore.ExperienceEditor.WebUtility.GetCurrentLayoutFieldId().ToString());
        args.HasSheerUI = false;
        new ParseXml().Process(args);
        return args;
    }
}
```
 
At last all we need to do is to replace the processor with our new one.

```xml
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <sitecore.experienceeditor.speak.requests>
      <request name="ExperienceEditor.Save.CallServerSavePipeline"
               set:type="YourAsembly.CallServerSavePipeline, YourAssembly"/>
    </sitecore.experienceeditor.speak.requests>
  </sitecore>
</configuration>
```
 
That’s it! Now your multi-line text fields will work correctly when editing them in the Experience Editor. Hopefully Sitecore will fix this soon in the core product.
 <!--kg-card-end: markdown-->
