github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/pubnot/trumbowyg/plugins/cleanpaste/trumbowyg.cleanpaste.js (about) 1 /* =========================================================== 2 * trumbowyg.cleanpaste.js v1.0 3 * Font Clean paste plugin for Trumbowyg 4 * http://alex-d.github.com/Trumbowyg 5 * =========================================================== 6 * Author : Eric Radin 7 */ 8 9 /** 10 * This plugin will perform a "cleaning" on any paste, in particular 11 * it will clean pasted content of microsoft word document tags and classes. 12 */ 13 (function ($) { 14 'use strict'; 15 16 function reverse(sentString) { 17 var theString = ''; 18 for (var i = sentString.length - 1; i >= 0; i -= 1) { 19 theString += sentString.charAt(i); 20 } 21 return theString; 22 } 23 24 function checkValidTags(snippet) { 25 var theString = snippet; 26 27 // Replace uppercase element names with lowercase 28 theString = theString.replace(/<[^> ]*/g, function (match) { 29 return match.toLowerCase(); 30 }); 31 32 // Replace uppercase attribute names with lowercase 33 theString = theString.replace(/<[^>]*>/g, function (match) { 34 match = match.replace(/ [^=]+=/g, function (match2) { 35 return match2.toLowerCase(); 36 }); 37 return match; 38 }); 39 40 // Put quotes around unquoted attributes 41 theString = theString.replace(/<[^>]*>/g, function (match) { 42 match = match.replace(/( [^=]+=)([^"][^ >]*)/g, '$1\"$2\"'); 43 return match; 44 }); 45 46 return theString; 47 } 48 49 function cleanIt(htmlBefore, htmlAfter) { 50 var matchedHead = ''; 51 var matchedTail = ''; 52 var afterStart; 53 var afterFinish; 54 var newSnippet; 55 56 // we need to extract the inserted block 57 for (afterStart = 0; htmlAfter.charAt(afterStart) === htmlBefore.charAt(afterStart); afterStart += 1) { 58 matchedHead += htmlAfter.charAt(afterStart); 59 } 60 61 // If afterStart is inside a HTML tag, move to opening brace of tag 62 for (var i = afterStart; i >= 0; i -= 1) { 63 if (htmlBefore.charAt(i) === '<') { 64 afterStart = i; 65 matchedHead = htmlBefore.substring(0, afterStart); 66 break; 67 } else if (htmlBefore.charAt(i) === '>') { 68 break; 69 } 70 } 71 72 // now reverse string and work from the end in 73 htmlAfter = reverse(htmlAfter); 74 htmlBefore = reverse(htmlBefore); 75 76 // Find end of both strings that matches 77 for (afterFinish = 0; htmlAfter.charAt(afterFinish) === htmlBefore.charAt(afterFinish); afterFinish += 1) { 78 matchedTail += htmlAfter.charAt(afterFinish); 79 } 80 81 // If afterFinish is inside a HTML tag, move to closing brace of tag 82 for (var j = afterFinish; j >= 0; j -= 1) { 83 if (htmlBefore.charAt(j) === '>') { 84 afterFinish = j; 85 matchedTail = htmlBefore.substring(0, afterFinish); 86 break; 87 } else if (htmlBefore.charAt(j) === '<') { 88 break; 89 } 90 } 91 92 matchedTail = reverse(matchedTail); 93 94 // If there's no difference in pasted content 95 if (afterStart === (htmlAfter.length - afterFinish)) { 96 return false; 97 } 98 99 htmlAfter = reverse(htmlAfter); 100 newSnippet = htmlAfter.substring(afterStart, htmlAfter.length - afterFinish); 101 102 // first make sure all tags and attributes are made valid 103 newSnippet = checkValidTags(newSnippet); 104 105 // Replace opening bold tags with strong 106 newSnippet = newSnippet.replace(/<b(\s+|>)/g, '<strong$1'); 107 // Replace closing bold tags with closing strong 108 newSnippet = newSnippet.replace(/<\/b(\s+|>)/g, '</strong$1'); 109 110 // Replace italic tags with em 111 newSnippet = newSnippet.replace(/<i(\s+|>)/g, '<em$1'); 112 // Replace closing italic tags with closing em 113 newSnippet = newSnippet.replace(/<\/i(\s+|>)/g, '</em$1'); 114 115 // strip out comments -cgCraft 116 newSnippet = newSnippet.replace(/<!(?:--[\s\S]*?--\s*)?>\s*/g, ''); 117 118 // strip out -cgCraft 119 newSnippet = newSnippet.replace(/ /gi, ' '); 120 // strip out extra spaces -cgCraft 121 newSnippet = newSnippet.replace(/ <\//gi, '</'); 122 123 while (newSnippet.indexOf(' ') !== -1) { 124 var anArray = newSnippet.split(' '); 125 newSnippet = anArray.join(' '); 126 } 127 128 // strip -cgCraft 129 newSnippet = newSnippet.replace(/^\s*|\s*$/g, ''); 130 131 // Strip out unaccepted attributes 132 newSnippet = newSnippet.replace(/<[^>]*>/g, function (match) { 133 match = match.replace(/ ([^=]+)="[^"]*"/g, function (match2, attributeName) { 134 if (['alt', 'href', 'src', 'title'].indexOf(attributeName) !== -1) { 135 return match2; 136 } 137 return ''; 138 }); 139 return match; 140 }); 141 142 // Final cleanout for MS Word crud 143 newSnippet = newSnippet.replace(/<\?xml[^>]*>/g, ''); 144 newSnippet = newSnippet.replace(/<[^ >]+:[^>]*>/g, ''); 145 newSnippet = newSnippet.replace(/<\/[^ >]+:[^>]*>/g, ''); 146 147 // remove unwanted tags 148 newSnippet = newSnippet.replace(/<(div|span|style|meta|link){1}.*?>/gi, ''); 149 150 htmlAfter = matchedHead + newSnippet + matchedTail; 151 return htmlAfter; 152 } 153 154 // clean editor 155 // this will clean the inserted contents 156 // it does a compare, before and after paste to determine the 157 // pasted contents 158 $.extend(true, $.trumbowyg, { 159 plugins: { 160 cleanPaste: { 161 init: function (trumbowyg) { 162 trumbowyg.pasteHandlers.push(function () { 163 try { 164 var contentBefore = trumbowyg.$ed.html(); 165 setTimeout(function () { 166 var contentAfter = trumbowyg.$ed.html(); 167 contentAfter = cleanIt(contentBefore, contentAfter); 168 trumbowyg.$ed.html(contentAfter); 169 }, 0); 170 } catch (c) { 171 } 172 }); 173 } 174 } 175 } 176 }); 177 })(jQuery); 178 179