Fixed issue #2924 - Unable to paste from clipboard in note field in ticket zoom.

This commit is contained in:
Martin Edenhofer 2020-02-10 09:06:39 +01:00 committed by Thorsten Eckel
parent 343415d6e8
commit ddb4bb5150
3 changed files with 180 additions and 85 deletions

View file

@ -73,6 +73,8 @@ class App.Utils
ascii = @textCleanup(ascii)
#ascii = @htmlEscape(ascii)
ascii = @linkify(ascii)
ascii = ascii.replace(/(\n\r|\r\n|\r)/g, "\n")
ascii = ascii.replace(/ /g, '  ')
ascii = '<div>' + ascii.replace(/\n/g, '</div><div>') + '</div>'
ascii.replace(/<div><\/div>/g, '<div><br></div>')
@ -1269,3 +1271,42 @@ class App.Utils
.filter (elem) ->
elem?
.join '/'
@clipboardHtmlIsWithText: (html) ->
if !html
return false
parsedHTML = jQuery(jQuery.parseHTML(html))
if !parsedHTML || !parsedHTML.text
return false
if parsedHTML.text().trim().length is 0
return false
true
@clipboardHtmlInsertPreperation: (htmlRaw, options) ->
if options.mode is 'textonly'
if !options.multiline
html = App.Utils.htmlRemoveTags(htmlRaw)
else
html = App.Utils.htmlRemoveRichtext(htmlRaw)
else
html = App.Utils.htmlCleanup(htmlRaw)
htmlString = html.html()
if !htmlString && html && html.text && html.text()
htmlString = App.Utils.text2html(html.text())
# as fallback, get text from htmlRaw
if !htmlString || htmlString == ''
parsedHTML = jQuery(jQuery.parseHTML(htmlRaw))
if parsedHTML
text = parsedHTML.text().trim()
if text
htmlString = App.Utils.text2html(text)
htmlString

View file

@ -263,11 +263,32 @@
}
}
Plugin.prototype.onPaste = function (e) {
e.preventDefault()
this.log('paste')
Plugin.prototype.getHtmlFromClipboard = function(clipboardData) {
try {
return clipboardData.getData('text/html')
}
catch (e) {
console.log('Sorry, can\'t get html of clipboard because browser is not supporting it.')
return
}
}
// insert and in case, resize images
Plugin.prototype.getTextFromClipboard = function(clipboardData) {
var text
try {
text = clipboardData.getData('text/plain')
if (!text || text.length === 0) {
text = clipboardData.getData('text')
}
return text
}
catch (e) {
console.log('Sorry, can\'t get text of clipboard because browser is not supporting it.')
return
}
}
Plugin.prototype.getClipboardData = function(e) {
var clipboardData
if (e.clipboardData) { // ie
clipboardData = e.clipboardData
@ -281,30 +302,41 @@
else {
throw "No clipboardData support"
}
return clipboardData
}
if (clipboardData && clipboardData.items && clipboardData.items[0]) {
var imageInserted = false
var item
Plugin.prototype.getClipboardDataImage = function(clipboardData) {
if (!clipboardData.items || !clipboardData.items[0]) {
return
}
return $.grep(clipboardData.items, function(item){
return item.kind == 'file' && (item.type == 'image/png' || item.type == 'image/jpeg')
})[0]
}
// look for image only if no HTML with textual content is available.
// E.g. Excel provides images of the spreadsheet along with HTML.
// While some browsers make images available in clipboard as HTML,
// sometimes wrapped in multiple nodes.
Plugin.prototype.onPaste = function (e) {
e.preventDefault()
var clipboardData, clipboardImage, text, htmlRaw, htmlString
var rawHTML = clipboardData.getData('text/html')
var parsedHTML = jQuery(jQuery.parseHTML(rawHTML))
this.log('paste')
if(parsedHTML.text().trim().length == 0) {
item = jQuery.grep(clipboardData.items, function(item){
return item.kind == 'file' && (item.type == 'image/png' || item.type == 'image/jpeg')
})[0]
}
clipboardData = this.getClipboardData(e)
if (item) {
this.log('paste image', item)
console.log(item)
// look for image only if no HTML with textual content is available.
// E.g. Excel provides images of the spreadsheet along with HTML.
// While some browsers make images available in clipboard as HTML,
// sometimes wrapped in multiple nodes.
htmlRaw = this.getHtmlFromClipboard(clipboardData)
var imageFile = item.getAsFile()
if (!App.Utils.clipboardHtmlIsWithText(htmlRaw)) {
// insert and in case, resize images
clipboardImage = this.getClipboardDataImage(clipboardData)
if (clipboardImage) {
this.log('paste image', clipboardImage)
var imageFile = clipboardImage.getAsFile()
var reader = new FileReader()
reader.onload = $.proxy(function (e) {
@ -340,74 +372,35 @@
}, this)
reader.readAsDataURL(imageFile)
imageInserted = true
} else {
item = clipboardData.items[0]
return true
}
}
if (imageInserted) {
// insert html
if (htmlRaw) {
htmlString = App.Utils.clipboardHtmlInsertPreperation(htmlRaw, this.options)
if (htmlString) {
this.log('insert html from clipboard', htmlString)
this.paste(htmlString)
return true
}
}
// insert text
text = this.getTextFromClipboard(clipboardData)
if (!text) {
return false
}
htmlString = App.Utils.text2html(text)
// check length limit
if (!this.maxLengthOk(htmlString.length)) {
return
}
// check existing + paste text for limit
var text, docType
try {
text = clipboardData.getData('text/html')
docType = 'html'
if (!text || text.length === 0) {
docType = 'text'
text = clipboardData.getData('text/plain')
}
if (!text || text.length === 0) {
docType = 'text2'
text = clipboardData.getData('text')
}
}
catch (e) {
console.log('Sorry, can\'t insert markup because browser is not supporting it.')
docType = 'text3'
text = clipboardData.getData('text')
}
this.log('paste', docType, text)
if (docType == 'html') {
if (this.options.mode === 'textonly') {
if (!this.options.multiline) {
text = App.Utils.htmlRemoveTags(text)
this.log('htmlRemoveTags', text)
}
else {
this.log('htmlRemoveRichtext', text)
text = App.Utils.htmlRemoveRichtext(text)
}
}
else {
this.log('htmlCleanup', text)
text = App.Utils.htmlCleanup(text)
}
text = text.html()
this.log('text.html()', text)
// as fallback, take text
if (!text) {
text = App.Utils.text2html(text.text())
this.log('text2html', text)
}
}
else {
text = App.Utils.text2html(text)
this.log('text2html', text)
}
if (!this.maxLengthOk(text.length)) {
return
}
// cleanup
text = App.Utils.removeEmptyLines(text)
this.log('insert', text)
this.paste(text)
htmlString = App.Utils.removeEmptyLines(htmlString)
this.log('insert text from clipboard', htmlString)
this.paste(htmlString)
return true
}

View file

@ -63,6 +63,35 @@ test("text2html", function() {
result = App.Utils.text2html(source)
equal(result, should, source)
source = "Some\nValue\n"
should = "<div>Some</div><div>Value</div>"
result = App.Utils.text2html(source)
equal(result, should, source)
source = "Some\rValue\r"
should = "<div>Some</div><div>Value</div>"
result = App.Utils.text2html(source)
equal(result, should, source)
source = "Some\n\rValue\n\r"
should = "<div>Some</div><div>Value</div>"
result = App.Utils.text2html(source)
equal(result, should, source)
source = "Some\r\nValue\r\n"
should = "<div>Some</div><div>Value</div>"
result = App.Utils.text2html(source)
equal(result, should, source)
source = "Some Value 123"
should = "<div>Some &nbsp; Value 123</div>"
result = App.Utils.text2html(source)
equal(result, should, source)
source = "Some\n Value\n 123"
should = "<div>Some</div><div> &nbsp; Value</div><div> &nbsp; &nbsp;123</div>"
result = App.Utils.text2html(source)
equal(result, should, source)
});
// htmlStrip
@ -3306,3 +3335,35 @@ test('App.Utils.joinUrlComponents()', function() {
// expect @joinUrlComponents() to filter them out of the results before joining the rest with slashes
equal(App.Utils.joinUrlComponents('foo', undefined, 'bar', null, 'baz'), 'foo/bar/baz', 'with a list including null or undefined')
});
test('App.Utils.clipboardHtmlIsWithText()', function() {
// no content with text
equal(App.Utils.clipboardHtmlIsWithText('<div></div>'), false)
equal(App.Utils.clipboardHtmlIsWithText('<div> </div>'), false)
equal(App.Utils.clipboardHtmlIsWithText('<div><img src="test.jpg"/></div>'), false)
equal(App.Utils.clipboardHtmlIsWithText('<div><!-- some comment --></div>'), false)
equal(App.Utils.clipboardHtmlIsWithText('<div><!-- some comment --> </div>'), false)
equal(App.Utils.clipboardHtmlIsWithText("<div><!-- some comment --> \n </div>"), false)
// content with text
equal(App.Utils.clipboardHtmlIsWithText('test'), true)
equal(App.Utils.clipboardHtmlIsWithText('<div>test</div>'), true)
equal(App.Utils.clipboardHtmlIsWithText('<meta http-equiv="content-type" content="text/html; charset=utf-8">sometext'), true)
});
test('App.Utils.clipboardHtmlInsertPreperation()', function() {
equal(App.Utils.clipboardHtmlInsertPreperation('<div></div>', {}), '')
equal(App.Utils.clipboardHtmlInsertPreperation('<div> </div>', {}), ' ')
equal(App.Utils.clipboardHtmlInsertPreperation('<div><img src="test.jpg"/></div>', {}), '<img src="test.jpg">')
equal(App.Utils.clipboardHtmlInsertPreperation('<div><!-- some comment --></div>', {}), '')
equal(App.Utils.clipboardHtmlInsertPreperation('<div><!-- some comment --> </div>', {}), ' ')
equal(App.Utils.clipboardHtmlInsertPreperation("<div><!-- some comment --> \n </div>", {}), " \n ")
equal(App.Utils.clipboardHtmlInsertPreperation('test', {}), 'test')
equal(App.Utils.clipboardHtmlInsertPreperation('<div>test</div>', {}), 'test')
equal(App.Utils.clipboardHtmlInsertPreperation('<meta http-equiv="content-type" content="text/html; charset=utf-8">sometext', {}), '<div>sometext</div>')
equal(App.Utils.clipboardHtmlInsertPreperation('<div><b>test</b> 123</div>', { mode: 'textonly' }), 'test 123')
equal(App.Utils.clipboardHtmlInsertPreperation('<div><b>test</b><br> 123</div>', { mode: 'textonly' }), 'test 123')
equal(App.Utils.clipboardHtmlInsertPreperation('<div><b>test</b><br> 123</div>', { mode: 'textonly', multiline: true }), 'test<br> 123')
});