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 = @textCleanup(ascii)
#ascii = @htmlEscape(ascii) #ascii = @htmlEscape(ascii)
ascii = @linkify(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 = '<div>' + ascii.replace(/\n/g, '</div><div>') + '</div>'
ascii.replace(/<div><\/div>/g, '<div><br></div>') ascii.replace(/<div><\/div>/g, '<div><br></div>')
@ -1269,3 +1271,42 @@ class App.Utils
.filter (elem) -> .filter (elem) ->
elem? elem?
.join '/' .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) { Plugin.prototype.getHtmlFromClipboard = function(clipboardData) {
e.preventDefault() try {
this.log('paste') 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 var clipboardData
if (e.clipboardData) { // ie if (e.clipboardData) { // ie
clipboardData = e.clipboardData clipboardData = e.clipboardData
@ -281,30 +302,41 @@
else { else {
throw "No clipboardData support" throw "No clipboardData support"
} }
return clipboardData
}
if (clipboardData && clipboardData.items && clipboardData.items[0]) { Plugin.prototype.getClipboardDataImage = function(clipboardData) {
var imageInserted = false if (!clipboardData.items || !clipboardData.items[0]) {
var item return
}
return $.grep(clipboardData.items, function(item){
return item.kind == 'file' && (item.type == 'image/png' || item.type == 'image/jpeg')
})[0]
}
Plugin.prototype.onPaste = function (e) {
e.preventDefault()
var clipboardData, clipboardImage, text, htmlRaw, htmlString
this.log('paste')
clipboardData = this.getClipboardData(e)
// look for image only if no HTML with textual content is available. // look for image only if no HTML with textual content is available.
// E.g. Excel provides images of the spreadsheet along with HTML. // E.g. Excel provides images of the spreadsheet along with HTML.
// While some browsers make images available in clipboard as HTML, // While some browsers make images available in clipboard as HTML,
// sometimes wrapped in multiple nodes. // sometimes wrapped in multiple nodes.
htmlRaw = this.getHtmlFromClipboard(clipboardData)
var rawHTML = clipboardData.getData('text/html') if (!App.Utils.clipboardHtmlIsWithText(htmlRaw)) {
var parsedHTML = jQuery(jQuery.parseHTML(rawHTML))
if(parsedHTML.text().trim().length == 0) { // insert and in case, resize images
item = jQuery.grep(clipboardData.items, function(item){ clipboardImage = this.getClipboardDataImage(clipboardData)
return item.kind == 'file' && (item.type == 'image/png' || item.type == 'image/jpeg') if (clipboardImage) {
})[0]
}
if (item) { this.log('paste image', clipboardImage)
this.log('paste image', item)
console.log(item)
var imageFile = item.getAsFile() var imageFile = clipboardImage.getAsFile()
var reader = new FileReader() var reader = new FileReader()
reader.onload = $.proxy(function (e) { reader.onload = $.proxy(function (e) {
@ -340,74 +372,35 @@
}, this) }, this)
reader.readAsDataURL(imageFile) reader.readAsDataURL(imageFile)
imageInserted = true return true
} else {
item = clipboardData.items[0]
} }
} }
if (imageInserted) {
return
}
// check existing + paste text for limit // insert html
var text, docType if (htmlRaw) {
try { htmlString = App.Utils.clipboardHtmlInsertPreperation(htmlRaw, this.options)
text = clipboardData.getData('text/html') if (htmlString) {
docType = 'html' this.log('insert html from clipboard', htmlString)
if (!text || text.length === 0) { this.paste(htmlString)
docType = 'text' return true
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') { // insert text
if (this.options.mode === 'textonly') { text = this.getTextFromClipboard(clipboardData)
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) { if (!text) {
text = App.Utils.text2html(text.text()) return false
this.log('text2html', text)
}
}
else {
text = App.Utils.text2html(text)
this.log('text2html', text)
} }
htmlString = App.Utils.text2html(text)
if (!this.maxLengthOk(text.length)) { // check length limit
if (!this.maxLengthOk(htmlString.length)) {
return return
} }
// cleanup htmlString = App.Utils.removeEmptyLines(htmlString)
text = App.Utils.removeEmptyLines(text) this.log('insert text from clipboard', htmlString)
this.log('insert', text) this.paste(htmlString)
this.paste(text)
return true return true
} }

View file

@ -63,6 +63,35 @@ test("text2html", function() {
result = App.Utils.text2html(source) result = App.Utils.text2html(source)
equal(result, should, 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 // 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 // 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') 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')
});