Improved App.Utils class.

This commit is contained in:
Martin Edenhofer 2015-12-27 23:29:04 +01:00
parent caa3e77997
commit 8b10b2accf
4 changed files with 217 additions and 62 deletions

View file

@ -1,24 +1,24 @@
# coffeelint: disable=no_unnecessary_double_quotes # coffeelint: disable=no_unnecessary_double_quotes
class App.Utils class App.Utils
# textCleand = App.Utils.textCleanup( rawText ) # textCleand = App.Utils.textCleanup(rawText)
@textCleanup: ( ascii ) -> @textCleanup: (ascii) ->
$.trim( ascii ) $.trim( ascii )
.replace(/(\r\n|\n\r)/g, "\n") # cleanup .replace(/(\r\n|\n\r)/g, "\n") # cleanup
.replace(/\r/g, "\n") # cleanup .replace(/\r/g, "\n") # cleanup
.replace(/[ ]\n/g, "\n") # remove tailing spaces .replace(/[ ]\n/g, "\n") # remove tailing spaces
.replace(/\n{3,20}/g, "\n\n") # remove multiple empty lines .replace(/\n{3,20}/g, "\n\n") # remove multiple empty lines
# htmlEscapedAndLinkified = App.Utils.text2html( rawText ) # htmlEscapedAndLinkified = App.Utils.text2html(rawText)
@text2html: ( ascii ) -> @text2html: (ascii) ->
ascii = @textCleanup(ascii) ascii = @textCleanup(ascii)
#ascii = @htmlEscape(ascii) #ascii = @htmlEscape(ascii)
ascii = @linkify(ascii) ascii = @linkify(ascii)
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>')
# rawText = App.Utils.html2text( html ) # rawText = App.Utils.html2text(html)
@html2text: ( html ) -> @html2text: (html) ->
# remove not needed new lines # remove not needed new lines
html = html.replace(/>\n/g, '>') html = html.replace(/>\n/g, '>')
@ -37,11 +37,11 @@ class App.Utils
.replace(/\r/g, "\n") # cleanup .replace(/\r/g, "\n") # cleanup
.replace(/\n{3,20}/g, "\n\n") # remove multiple empty lines .replace(/\n{3,20}/g, "\n\n") # remove multiple empty lines
# htmlEscapedAndLinkified = App.Utils.linkify( rawText ) # htmlEscapedAndLinkified = App.Utils.linkify(rawText)
@linkify: (ascii) -> @linkify: (ascii) ->
window.linkify( ascii ) window.linkify(ascii)
# wrappedText = App.Utils.wrap( rawText, maxLineLength ) # wrappedText = App.Utils.wrap(rawText, maxLineLength)
@wrap: (ascii, max = 82) -> @wrap: (ascii, max = 82) ->
result = '' result = ''
counter_lines = 0 counter_lines = 0
@ -80,19 +80,19 @@ class App.Utils
result += "\n" result += "\n"
result result
# quotedText = App.Utils.quote( rawText ) # quotedText = App.Utils.quote(rawText)
@quote: (ascii, max = 82) -> @quote: (ascii, max = 82) ->
ascii = @textCleanup(ascii) ascii = @textCleanup(ascii)
ascii = @wrap(ascii, max) ascii = @wrap(ascii, max)
$.trim( ascii ) $.trim(ascii)
.replace /^(.*)$/mg, (match) -> .replace /^(.*)$/mg, (match) ->
if match if match
'> ' + match '> ' + match
else else
'>' '>'
# htmlEscaped = App.Utils.htmlEscape( rawText ) # htmlEscaped = App.Utils.htmlEscape(rawText)
@htmlEscape: ( ascii ) -> @htmlEscape: (ascii) ->
return ascii if !ascii return ascii if !ascii
return ascii if !ascii.replace return ascii if !ascii.replace
ascii.replace(/&/g, '&amp;') ascii.replace(/&/g, '&amp;')
@ -101,8 +101,9 @@ class App.Utils
.replace(/"/g, '&quot;') .replace(/"/g, '&quot;')
.replace(/'/g, '&#39;') .replace(/'/g, '&#39;')
# textWithoutTags = App.Utils.htmlRemoveTags( html ) # textWithoutTags = App.Utils.htmlRemoveTags(html)
@htmlRemoveTags: (html) -> @htmlRemoveTags: (html) ->
html = @_checkTypeOf(html)
# remove comments # remove comments
@_removeComments(html) @_removeComments(html)
@ -111,17 +112,18 @@ class App.Utils
@_removeWordMarkup(html) @_removeWordMarkup(html)
# remove tags, keep content # remove tags, keep content
html.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6').replaceWith( -> html.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, fieldset, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6').replaceWith( ->
$(@).contents() $(@).contents()
) )
# remove tags & content # remove tags & content
html.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6, br, hr, img, svg, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe').remove() html.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, fieldset, textarea, font, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6, br, hr, img, svg, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe, meta, link, title, head').remove()
html html
# htmlOnlyWithRichtext = App.Utils.htmlRemoveRichtext( html ) # htmlOnlyWithRichtext = App.Utils.htmlRemoveRichtext(html)
@htmlRemoveRichtext: (html) -> @htmlRemoveRichtext: (html) ->
html = @_checkTypeOf(html)
# remove comments # remove comments
@_removeComments(html) @_removeComments(html)
@ -133,17 +135,18 @@ class App.Utils
@_removeWordMarkup(html) @_removeWordMarkup(html)
# remove tags, keep content # remove tags, keep content
html.find('li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6').replaceWith( -> html.find('li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, fieldset, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6').replaceWith( ->
$(@).contents() $(@).contents()
) )
# remove tags & content # remove tags & content
html.find('li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6, hr, img, svg, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe').remove() html.find('li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, fieldset, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6, hr, img, svg, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe, meta, link, title, head').remove()
html html
# cleanHtmlWithRichText = App.Utils.htmlCleanup( html ) # cleanHtmlWithRichText = App.Utils.htmlCleanup(html)
@htmlCleanup: (html) -> @htmlCleanup: (html) ->
html = @_checkTypeOf(html)
# remove comments # remove comments
@_removeComments(html) @_removeComments(html)
@ -155,7 +158,7 @@ class App.Utils
@_removeWordMarkup(html) @_removeWordMarkup(html)
# remove tags, keep content # remove tags, keep content
html.find('a, font, small, time, form').replaceWith( -> html.find('a, font, small, time, form, label').replaceWith( ->
$(@).contents() $(@).contents()
) )
@ -179,16 +182,22 @@ class App.Utils
) )
# remove tags & content # remove tags & content
html.find('font, hr, img, svg, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe').remove() html.find('font, hr, img, svg, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe, meta, link, title, head, fieldset').remove()
html html
@_checkTypeOf: (item) ->
return item if typeof item isnt 'string'
return $(item) if item.substr(0,9) isnt '<!DOCTYPE' && item.substr(0,5) isnt '<html'
$("<div>#{item}</div>")
@_removeAttributes: (html) -> @_removeAttributes: (html) ->
html.find('*') html.find('*')
.removeAttr( 'style' ) .removeAttr('style')
.removeAttr( 'class' ) .removeAttr('class')
.removeAttr( 'title' ) .removeAttr('title')
.removeAttr( 'lang' ) .removeAttr('lang')
.removeAttr('type')
html html
@_removeComments: (html) -> @_removeComments: (html) ->
@ -201,37 +210,38 @@ class App.Utils
@_removeWordMarkup: (html) -> @_removeWordMarkup: (html) ->
match = false match = false
htmlTmp = html.get(0).outerHTML htmlTmp = html.get(0).outerHTML
regex = new RegExp('<(/w|w)\:[A-Za-z]{3}>') regex = new RegExp('<(/w|w)\:[A-Za-z]')
if htmlTmp.match(regex) if htmlTmp.match(regex)
match = true match = true
htmlTmp = htmlTmp.replace(regex, '') htmlTmp = htmlTmp.replace(regex, '')
regex = new RegExp('<(/o|o)\:[A-Za-z]{1}>') regex = new RegExp('<(/o|o)\:[A-Za-z]')
if htmlTmp.match(regex) if htmlTmp.match(regex)
match = true match = true
htmlTmp = htmlTmp.replace(regex, '') htmlTmp = htmlTmp.replace(regex, '')
if match if match
html.html(htmlTmp) return window.word_filter(html)
html
# signatureNeeded = App.Utils.signatureCheck( message, signature ) # signatureNeeded = App.Utils.signatureCheck(message, signature)
@signatureCheck: (message, signature) -> @signatureCheck: (message, signature) ->
messageText = $( '<div>' + message + '</div>' ).text().trim() messageText = $('<div>' + message + '</div>').text().trim()
messageText = messageText.replace(/(\n|\r|\t)/g, '') messageText = messageText.replace(/(\n|\r|\t)/g, '')
signatureText = $( '<div>' + signature + '</div>' ).text().trim() signatureText = $('<div>' + signature + '</div>').text().trim()
signatureText = signatureText.replace(/(\n|\r|\t)/g, '') signatureText = signatureText.replace(/(\n|\r|\t)/g, '')
quote = (str) -> quote = (str) ->
(str + '').replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&") (str + '').replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&")
#console.log('SC', messageText, signatureText, quote(signatureText)) #console.log('SC', messageText, signatureText, quote(signatureText))
regex = new RegExp( quote(signatureText), 'mi' ) regex = new RegExp(quote(signatureText), 'mi')
if messageText.match(regex) if messageText.match(regex)
false false
else else
true true
# messageWithMarker = App.Utils.signatureIdentify( message, false ) # messageWithMarker = App.Utils.signatureIdentify(message, false)
@signatureIdentify: (message, test = false) -> @signatureIdentify: (message, test = false) ->
textToSearch = @html2text( message ) textToSearch = @html2text(message)
# count lines, if we do have lower the 10, ignore this # count lines, if we do have lower the 10, ignore this
textToSearchInLines = textToSearch.split("\n") textToSearchInLines = textToSearch.split("\n")
@ -450,19 +460,23 @@ class App.Utils
value value
) )
# true|false = App.Utils.lastLineEmpty( message ) # true|false = App.Utils.lastLineEmpty(message)
@lastLineEmpty: (message) -> @lastLineEmpty: (message) ->
messageCleanup = message.replace(/>\s+</g, '><').replace(/(\n|\r|\t)/g, '').trim() messageCleanup = message.replace(/>\s+</g, '><').replace(/(\n|\r|\t)/g, '').trim()
return true if messageCleanup.match(/<(br|\s+?|\/)>$/im) return true if messageCleanup.match(/<(br|\s+?|\/)>$/im)
return true if messageCleanup.match(/<div(|\s.+?)><\/div>$/im) return true if messageCleanup.match(/<div(|\s.+?)><\/div>$/im)
false false
# cleanString = App.Utils.htmlAttributeCleanup( string ) # string = App.Utils.removeEmptyLines(stringWithEmptyLines)
@removeEmptyLines: (string) ->
string.replace(/^\s*[\r\n]/gm, '')
# cleanString = App.Utils.htmlAttributeCleanup(string)
@htmlAttributeCleanup: (string) -> @htmlAttributeCleanup: (string) ->
string.replace(/((?![-a-zA-Z0-9_]+).|\n|\r|\t)/gm, '') string.replace(/((?![-a-zA-Z0-9_]+).|\n|\r|\t)/gm, '')
# diff = App.Utils.formDiff( dataNow, dataLast ) # diff = App.Utils.formDiff(dataNow, dataLast)
@formDiff: ( dataNowRaw, dataLastRaw ) -> @formDiff: (dataNowRaw, dataLastRaw) ->
dataNow = clone(dataNowRaw) dataNow = clone(dataNowRaw)
@_formDiffNormalizer(dataNow) @_formDiffNormalizer(dataNow)
dataLast = clone(dataLastRaw) dataLast = clone(dataLastRaw)

View file

@ -96,41 +96,54 @@
// just paste text // just paste text
this.$element.on('paste', function (e) { this.$element.on('paste', function (e) {
e.preventDefault()
_this.log('paste') _this.log('paste')
// check existing + paste text for limit // check existing + paste text for limit
var text var text = e.originalEvent.clipboardData.getData('text/html')
if (window.clipboardData) { // IE var docType = 'html'
text = window.clipboardData.getData('Text') if (!text || text.length === 0) {
docType = 'text'
text = e.originalEvent.clipboardData.getData('text/plain')
} }
else { if (!text || text.length === 0) {
text = (e.originalEvent || e).clipboardData.getData('text/plain') docType = 'text2'
text = e.originalEvent.clipboardData.getData('text')
} }
_this.log('paste', docType, text)
if ( !_this.maxLengthOk( text.length) ) { if (!_this.maxLengthOk(text.length)) {
e.preventDefault()
return return
} }
// use setTimeout() with 0 to execute it right after paste event if (docType == 'html') {
if ( _this.options.mode === 'textonly' ) { text = '<div>' + text + '</div>' // to prevent multible dom object. we need it at level 0
if ( !_this.options.multiline ) { if (_this.options.mode === 'textonly') {
setTimeout($.proxy(function(){ if (!_this.options.multiline) {
App.Utils.htmlRemoveTags(this.$element) text = App.Utils.htmlRemoveTags(text)
}, _this), 0) }
else {
text = App.Utils.htmlRemoveRichtext(text)
}
} }
else { else {
setTimeout($.proxy(function(){ text = App.Utils.htmlCleanup(text)
App.Utils.htmlRemoveRichtext(this.$element) }
}, _this), 0) text = text.html()
// as fallback, take text
if (!text) {
text = App.Utils.text2html(text.text())
} }
} }
else { else {
setTimeout($.proxy(function(){ text = App.Utils.text2html(text)
App.Utils.htmlCleanup(this.$element)
}, _this), 0)
} }
// cleanup
text = App.Utils.removeEmptyLines(text)
_this.log('insert', test)
document.execCommand('insertHTML', false, text)
return true return true
}) })

View file

@ -0,0 +1,84 @@
// (C) sbrin - https://github.com/sbrin
// https://gist.github.com/sbrin/6801034
window.word_filter = function(editor){
var content = editor.html();
// Word comments like conditional comments etc
content = content.replace(/<!--[\s\S]+?-->/gi, '');
// Remove comments, scripts (e.g., msoShowComment), XML tag, VML content,
// MS Office namespaced tags, and a few other tags
content = content.replace(/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi, '');
// Convert <s> into <strike> for line-though
content = content.replace(/<(\/?)s>/gi, "<$1strike>");
// Replace nbsp entites to char since it's easier to handle
//content = content.replace(/&nbsp;/gi, "\u00a0");
content = content.replace(/&nbsp;/gi, ' ');
// Convert <span style="mso-spacerun:yes">___</span> to string of alternating
// breaking/non-breaking spaces of same length
content = content.replace(/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi, function(str, spaces) {
return (spaces.length > 0) ? spaces.replace(/./, " ").slice(Math.floor(spaces.length/2)).split("").join("\u00a0") : '';
});
editor.html(content);
// Parse out list indent level for lists
$('p', editor).each(function(){
var str = $(this).attr('style');
var matches = /mso-list:\w+ \w+([0-9]+)/.exec(str);
if (matches) {
$(this).data('_listLevel', parseInt(matches[1], 10));
}
});
// Parse Lists
var last_level=0;
var pnt = null;
$('p', editor).each(function(){
var cur_level = $(this).data('_listLevel');
if(cur_level != undefined){
var txt = $(this).text();
var list_tag = '<ul></ul>';
if (/^\s*\w+\./.test(txt)) {
var matches = /([0-9])\./.exec(txt);
if (matches) {
var start = parseInt(matches[1], 10);
list_tag = start>1 ? '<ol start="' + start + '"></ol>' : '<ol></ol>';
}else{
list_tag = '<ol></ol>';
}
}
if(cur_level>last_level){
if(last_level==0){
$(this).before(list_tag);
pnt = $(this).prev();
}else{
pnt = $(list_tag).appendTo(pnt);
}
}
if(cur_level<last_level){
for(var i=0; i<last_level-cur_level; i++){
pnt = pnt.parent();
}
}
$('span:first', this).remove();
pnt.append('<li>' + $(this).html() + '</li>')
$(this).remove();
last_level = cur_level;
}else{
last_level = 0;
}
})
$('[style]', editor).removeAttr('style');
$('[align]', editor).removeAttr('align');
$('span', editor).replaceWith(function() {return $(this).contents();});
$('span:empty', editor).remove();
$("[class^='Mso']", editor).removeAttr('class');
$('p:empty', editor).remove();
return editor
}

File diff suppressed because one or more lines are too long