We implemented the ValidateRtfCopyPasteCommand Extension to resolve this issue. Please find sample code below:
Tridion.Type.registerNamespace("SDLPS.Extensions");
SDLPS.Extensions.ValidateRtfInputCommand = function ValidateRtfInputCommand() {
Tridion.OO.enableInterface(this, "SDLPS.Extensions.ValidateRtfInputCommand");
this.addInterface("Tridion.Web.UI.Editors.Base.Commands.CommandBase", ["ValidateRtfInputCommand"]);};
SDLPS.Extensions.ValidateRtfInputCommand.prototype._isAvailable = function ValidateRtfInputCommand$_isAvailable(selection, pipeline) {
return true;
};
SDLPS.Extensions.ValidateRtfInputCommand.prototype._isEnabled = function ValidateRtfInputCommand$_isEnabled(selection, pipeline) {
return true;
};
// Global variables exposed to all
var currentData_cpc = {};
var pasteEventFired_cpc = false;
var activateExtension_cpc = false;
$vri = SDLPS.Extensions.ValidateRtfInputCommand;
$vri.range, $vri.cursorLocation;
$vri.markerId = "PasteParent";
// the pasted entry will be stripped of <br> tags if set to false the pasted content will be left as is.
$vri.removeBrExisting = true;
if ($display && activateExtension_cpc) {
$evt.addEventHandler($display, "start", onDisplayStarted_cpc);
}
function onDisplayStarted_cpc() {
$evt.removeEventHandler($display, "start", onDisplayStarted_cpc);
var view = $display.getView();
if (view && Tridion.OO.implementsInterface(view, "Tridion.Cme.Views.Component")) {
var fieldBuilder = view.properties.controls.fieldBuilder;
$evt.addEventHandler(fieldBuilder, "load", _applyLoadEvent_cpc);
$evt.addEventHandler(fieldBuilder, "change", _applyLoadEvent_cpc);
$evt.addEventHandler(fieldBuilder, "insert", _applyLoadEvent_cpc);
}
}
function evtPaste_cpc(event) {
var entryKey = this.entrykey;
var curCtrl = $j("iframe.FAIFrame[id='" + entryKey + "']");
var selection = curCtrl.focus()[0].contentWindow.getSelection();
$vri.range = selection.getRangeAt(0);
$vri.caretStartContainer = $vri.range.startContainer;
if ($vri.caretStartContainer.firstChild) {
$vri.caretStartContainer.firstChild.id = "endPaste";
$vri.endPasteSet = true;
}
else if ($vri.caretStartContainer.nextSibling) {
$vri.caretStartContainer.nextSibling.id = "endPaste";
$vri.endPasteSet = true;
} else {
$vri.endPasteSet = false;
}
$vri.caretEndContainer = $vri.range.endContainer;
$vri.caretContainerNodeType = $vri.caretStartContainer.nodeType;
$vri.pasteNodeText = $vri.range.startContainer.data;
$vri.caretStartOffset = $vri.range.startOffset;
pasteEventFired_cpc = true;
};
function finalizeRtfInput_cpc(entryKey) {
console.debug("ValidateRtfInput: finalizeRtfInput_cpc called on save or save and close");
var currentInput = $j("iframe.FAIFrame[id='" + entryKey + "']");
if (!currentInput) {
console.error("ValidateRtfInput: was unable to locate the RTF Field with id -> " + entryKey);
return;
}
var currentVal;
try {
currentVal = currentInput[0].contentDocument.activeElement.innerHTML;
} catch (err) {
console.error("ValidateRtfInput: Unable to access the innerHTML of the RTF Filed with id -> " + entryKey);
console.error("ValidateRtfInput Error Message: " + err.message);
return;
}
var lastVal = currentData_cpc[entryKey];
var dmp = new diff_match_patch();
dmp.Patch_Margin = 10;
console.debug("ValidateRtfInput: \n-------------\nLastEntry:\n" + lastVal + "\n-------------\n\nCurrentEntry:\n" + currentVal + "\n-------------\n");
var arDiff = dmp.diff_main(lastVal, currentVal, false);
if (arDiff.length >= 2) {
for (index = 0; index < arDiff.length; index++) {
// check each diff
if (arDiff[index][0] == 1) {
var valToCheck = arDiff[index][1];
var newVal = valToCheck.replace(/ <br>/, ' ');
newVal = newVal.replace(/ <\/p>/, '<\/p>');
newVal = newVal.replace(/ <br><\/p>/, '<\/p>');
console.debug("ValidateRtfInput: Checked val[" + index + "][1]: " + valToCheck);
console.debug("ValidateRtfInput: --- newVal: " + newVal);
arDiff[index][1] = newVal;
if (newVal == " ") console.debug("ValidateRtfInput: Final matches found a space all alone to be added. Maybe need to look ahead and see if the next change contains <br or other html");
}
}
}
else {
console.debug("ValidateRtfInput extension expected a diff >= 2 and got " + arDiff.length + " It is likely there were no changes in this RTF Field");
}
var patchMade = dmp.patch_make(arDiff);
var cleanedTxt = dmp.patch_apply(patchMade, lastVal);
console.debug("ValidateRtfInput: patch_apply results: " + cleanedTxt[0]);
var nextUpdate = cleanedTxt[0];
if (nextUpdate.match(/ <br>/g)) {
console.debug("ValidateRtfInput: Update data contains ' <br>' stripping now");
nextUpdate = nextUpdate.replace(/ <br>/, ' ');
console.debug("ValidateRtfInput: ------------\nNew save value: \n" + nextUpdate + "\n------------");
}
currentData_cpc[entryKey] = nextUpdate;
currentInput[0].contentDocument.activeElement.innerHTML = nextUpdate;
if (lastVal == currentVal) {
console.debug("ValidateRtfInput: previous and current values have not changed for: " + entryKey);
}
};