Fix #936: too many return characters inserted when pasting formatted text from OpenOffice

This commit is contained in:
josdejong 2020-05-13 08:17:54 +02:00
parent 79beb26d66
commit ad021ec7af
4 changed files with 134 additions and 17 deletions

View File

@ -3,6 +3,12 @@
https://github.com/josdejong/jsoneditor https://github.com/josdejong/jsoneditor
## not yet published, version 8.6.8
- Fix #936: too many return characters inserted when pasting formatted text
from OpenOffice.
## 2020-05-10, version 8.6.7 ## 2020-05-10, version 8.6.7
- Fix #858: the `dist/jsoneditor.js` bundle containing a link to a - Fix #858: the `dist/jsoneditor.js` bundle containing a link to a

View File

@ -5,7 +5,7 @@ const VanillaPicker = require('./vanilla-picker') // may be undefined in case of
const { treeModeMixins } = require('./treemode') const { treeModeMixins } = require('./treemode')
const { textModeMixins } = require('./textmode') const { textModeMixins } = require('./textmode')
const { previewModeMixins } = require('./previewmode') const { previewModeMixins } = require('./previewmode')
const { clear, extend, getInternetExplorerVersion, parse } = require('./util') const { clear, extend, getInnerText, getInternetExplorerVersion, parse } = require('./util')
const { tryRequireAjv } = require('./tryRequireAjv') const { tryRequireAjv } = require('./tryRequireAjv')
const { showTransformModal } = require('./showTransformModal') const { showTransformModal } = require('./showTransformModal')
const { showSortModal } = require('./showSortModal') const { showSortModal } = require('./showSortModal')
@ -484,6 +484,7 @@ JSONEditor.VanillaPicker = VanillaPicker
// expose some utils (this is undocumented, unofficial) // expose some utils (this is undocumented, unofficial)
JSONEditor.showTransformModal = showTransformModal JSONEditor.showTransformModal = showTransformModal
JSONEditor.showSortModal = showSortModal JSONEditor.showSortModal = showSortModal
JSONEditor.getInnerText = getInnerText
// default export for TypeScript ES6 projects // default export for TypeScript ES6 projects
JSONEditor.default = JSONEditor JSONEditor.default = JSONEditor

View File

@ -663,7 +663,6 @@ export function setSelectionOffset (params) {
} }
} }
} }
/** /**
* Get the inner text of an HTML element (for example a div element) * Get the inner text of an HTML element (for example a div element)
* @param {Element} element * @param {Element} element
@ -674,21 +673,28 @@ export function getInnerText (element, buffer) {
const first = (buffer === undefined) const first = (buffer === undefined)
if (first) { if (first) {
buffer = { buffer = {
text: '', _text: '',
flush: function () { flush: function () {
const text = this.text const text = this._text
this.text = '' this._text = ''
return text return text
}, },
set: function (text) { set: function (text) {
this.text = text this._text = text
} }
} }
} }
// text node // text node
if (element.nodeValue) { if (element.nodeValue) {
return buffer.flush() + element.nodeValue // remove return characters and the whitespace surrounding return characters
const trimmedValue = element.nodeValue.replace(/\s*\n\s*/g, '')
if (trimmedValue !== '') {
return buffer.flush() + trimmedValue
} else {
// ignore empty text
return ''
}
} }
// divs or other HTML elements // divs or other HTML elements
@ -703,7 +709,9 @@ export function getInnerText (element, buffer) {
const prevChild = childNodes[i - 1] const prevChild = childNodes[i - 1]
const prevName = prevChild ? prevChild.nodeName : undefined const prevName = prevChild ? prevChild.nodeName : undefined
if (prevName && prevName !== 'DIV' && prevName !== 'P' && prevName !== 'BR') { if (prevName && prevName !== 'DIV' && prevName !== 'P' && prevName !== 'BR') {
innerText += '\n' if (innerText !== '') {
innerText += '\n'
}
buffer.flush() buffer.flush()
} }
innerText += getInnerText(child, buffer) innerText += getInnerText(child, buffer)
@ -717,15 +725,6 @@ export function getInnerText (element, buffer) {
} }
return innerText return innerText
} else {
if (element.nodeName === 'P' && getInternetExplorerVersion() !== -1) {
// On Internet Explorer, a <p> with hasChildNodes()==false is
// rendered with a new line. Note that a <p> with
// hasChildNodes()==true is rendered without a new line
// Other browsers always ensure there is a <br> inside the <p>,
// and if not, the <p> does not render a new line
return buffer.flush()
}
} }
// br or unknown // br or unknown

View File

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSONEditor test getInnerHtml</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style>
html, body {
font-family: verdana;
background: #f5f5f5;
font-size: 11pt;
}
#editableDiv {
width: 600px;
height: 200px;
border: 1px solid red;
background: white;
font-family: monospace;
}
#editableDiv p {
margin: 0;
}
#innerText,
#getInnerText,
#innerTextStr,
#textContentStr {
width: 600px;
}
#innerText,
#getInnerText {
height: 200px;
border: 1px solid green;
}
#innerTextStr,
#textContentStr {
width: 600px;
border: 1px solid gray;
background: #f5f5f5;
font-family: monospace;
}
</style>
</head>
<body>
contenteditable div:
<div id="editableDiv" contenteditable="true">
<p>Hello world</p>
<p>test paste from OpenOffice </p>
a
<p>
<br>
</p>
<p>test</p>
</div>
<p>
innerText: <br/>
<textarea id="innerText"></textarea>
</p>
<p>
getInnerText: <br/>
<textarea id="getInnerText"></textarea>
</p>
<p>
<p>
inner text (stringified): <br/>
<input id="innerTextStr" readonly />
</p>
<p>
text content (stringified): <br/>
<input id="textContentStr" readonly />
</p>
<script>
const editableDiv = document.getElementById('editableDiv')
const innerText = document.getElementById('innerText')
const getInnerTextDiv = document.getElementById('getInnerText')
const innerTextStr = document.getElementById('innerTextStr')
const textContentStr = document.getElementById('textContentStr')
function updateInnerTexts () {
innerText.value = editableDiv.innerText
getInnerTextDiv.value = JSONEditor.getInnerText(editableDiv)
innerTextStr.value = JSON.stringify(editableDiv.innerText)
textContentStr.value = JSON.stringify(editableDiv.textContent)
}
editableDiv.oninput = updateInnerTexts
updateInnerTexts()
innerText.oninput = function () {
editableDiv.innerText = innerText.value
getInnerTextDiv.value = getInnerText(editableDiv)
}
getInnerTextDiv.oninput = function () {
editableDiv.innerText = getInnerTextDiv.value
innerText.value = editableDiv.innerText
}
</script>
</body>
</html>