is there a way to strip specific tags from coming into tiny MCE through a copy+paste from an external source (e.g. Word)? I'd like to prevent font-family and image tags from being copy+pasted over, but have no problem with font-size etc.
Thank you!
You can't really stop someone from pasting something, so I believe your best bet would be to filter out the unwanted tags by calling a function on form submit, or onchange of the tiny MCE textarea. Then you could use some regular expression replacement to get rid of the unwanted tags.
EDIT: Actually there is a simple way. check the TinyMCE documentation.
Here is the link to a similar SO question with a detailed description of howto strip out unwanted tags: TinyMCE Paste As Plain Text
I don't know how useful this will be, but you might want to take a look at this jQuery plugin which allows you to filter tags and attributed from the text your are pasting.
FilteredPaste.js - A jQuery Plugin To Filter & Clean Pasted Input
Although "You can't really stop someone from pasting something" indeed, you can transform what your web app inserts into your TinyMCE textbox (or any other input).
Listen to the browser's native paste event.
Parse the clipboard's text/html string with DOMParser.
Make changes in the generated DOM tree.
Set the textbox content to the stripped content.
Prevent the paste default action.
Check this out:
editor.on ('paste', event => {
// Get clipboard's original HTML string
const clipboard = event.clipboardData
const originalHtml = clipboard.getData ('text/html')
// Parse HTML string into a DOMElement
const parser = new DOMParser
const doc = parser.parseFromString (originalHtml, 'text/html')
// Modify DOM tree
const elems = doc.body.querySelectorAll ('*')
elems.forEach (elem => {
elem.style.fontFamily = ''
// Do other modifications here...
})
// Set textbox content to modified HTML
editor.setContent (doc.body.innerHTML)
// Prevent pasting original content
event.preventDefault ()
})
Related
I have a contentEditable div.
The problem is when I type in HTML tags, say, <h1> Then the angle brackets get replaced with their entity names < and > in the DOM.
How do I prevent that from happening?
I want the actual tags to be inserted instead of the HTML entity.
Here's a jsFiddle to depict the problem: https://jsfiddle.net/m0xbd2j9/28/
This is what is expected to happen. Otherwise, users could easily mess HTML of your page.
If you REALLY want to do that (I don't recommend you to do so in production) you can intercept keyup event and perform a replace over element contents. Something like (untested example using jquery for the sake of brevity):
var editable = $("#editableDiv");
editable.on("keyup", function(event) {
// TODO: Better check if event key is either "<" or ">"
// to avoid extra processing if not necessary.
editable.html(
editable.html()
.replace("<", "<")
.replace(">", ">")
);
});
On the other hand, if what you want is simply to read that contents (not render it) as unescaped HTML, you can simply do the same replacement on the reading process.
HINT: ON the backend you probably have some library functions, like html_entity_decode() in PHP, which does just that and much more for you.
I'm using a rich text editor type control, which is a written as a jQuery plugin. It basically inserts an IFrame onto the page, and makes it editable - fairly standard for rich text controls.
Now, what I'm looking to do is improve upon an option which removes all formatting from the text editor. Currently it is being done with a large list of regular expressions, and a quick google search suggests that this is not the correct way to go about it. I'm looking to allow this unformatting some degree of flexibility, so that I can leave certain tags in (like paragraph tags).
I was trying to use the jQuery built in DOM parsing to do this easily, but I seem to be having trouble.
Let's assume I have a sample HTML string:
<Body><p>One <strong>Two</strong> <em>Three</em></p></Body>
I'm looking to un-format it so that all non paragraph tags are removed. So, I'd be expecting the output to be a string which looks like this:
<Body><p>One Two Three</p></Body>
Sample code:
//Some very simple HTML obtained from an editable iframe
var text = '<Body><p>One <strong>Two</strong> <em>Three</em></p></Body>';
var $text = $(text);
//All tags which are not paragraphs
$(':not(p)',$text).each(function() {
//Replace the tag + content with just content
$(this).html($(this).text());
});
//I'll be honest, I found this snippet somewhere else on stackoverflow,
//It seems to parse the jquery object back into an HTML string.
var returnVal = "";
$text.each(function(){
returnVal += $(this).clone().wrap('<p>').parent().html();
});
//Should be equal to '<p>One Two Three</p>'
return returnVal;
This seems like it should work, but unfortunately it doesn't. In the above example, 'returnVal' is the same as the input (minus the 'body' header tags). Is there anything I'm obviously doing wrong here?
Replace this line:
$(this).html($(this).text());
... with this:
$(this).replaceWith($(this).text());
... and it should work (at least it works here).
...snip
// Here's your bug:
$(':not(p)',$text).each(function() {
// You can't use .html() to replace the content
// $(this).html($(this).text());
// You have to replace the entire element, not just its contents:
$(this).replaceWith($(this).text());
});
...snip
I am using CLEditor, http://premiumsoftware.net/cleditor/, for my text editor. There is a function for 'paste as text' that when the button is clicked a pop up window appears with a textarea to paste your content in and the styles are stripped out.
What I would like to do is take this same functionality, but anytime someone paste into the primary textarea this action is performed automatically. How would I trigger this?
I have created a JS Fiddle, http://jsfiddle.net/helpinspireme/naubS/, but was unable to paste all the JS in there so to link to the main JS file for CLEditor visit their site: http://premiumsoftware.net/cleditor/
Thank you for your help.
I am aware that I am not answering your actual question, but in case your real problem is the garbage generated by a user who tries pasting text from Microsoft Office (Word for example) I would recommend to consider an alternative solution.
The CLEditor itself can switch between an iFrame (rich text mode) and a textarea (source mode). The 'Paste as text' functionality makes use of a textarea which does not support rich text by ifself, so it will not allow garbage html in the first place.
However if the editor is in rich text mode, it is very difficult to prevent a user pasting from Word (he can use the regular paste button, press CTRL-V or even use the right-mouse button context menu, which are all different events and hard to intercept using javascript). So now the damage is already done; you have messy html inside your editor. So instead of trying to sanitize the garbage produced by Word I implemented the following check (javascript) upon saving the captured input:
if(clEditorValue && (clEditorValue.indexOf('<!--') !== -1 || clEditorValue.indexOf('mso-ansi-language') !== -1 ) ) {
alert('Unable to process text pasted from Word, please use "Paste as text" or modify your input');
return;
}
I hope this answer is useful for other people trying to achieve the same.
When pasting into cleditor, the editor picks up all the html from the source. I ended up editing jquery.cleditor.js and added a bind function to the $doc.click(hidePopups) function. I used setTimeouts to allow the text to populate the input and the updateTextArea function to complete.
.bind("paste", function() {
setTimeout(function() {
refreshButtons(editor);
updateTextArea(editor, true);
//remove any and all html from the paste action
setTimeout(function() {
//clean up the html with removeHtml function
$(editor.doc.body).html(removeHtml($(editor.doc.body).html()));
//change the input value with new clean string
$("#" + editor.$area[0].id).val($(editor.doc.body).html());
}, 100);
}, 100);
})
I use the removeHtml function below to remove all the HTML from the pasted content.
//remove html altogether
function removeHtml(str) {
var regex = /(<([^>]+)>)/ig;
var result = str.replace(regex, "");
return result;
}
This solution is now in production.
I am playing around with creating an HTML-textarea based plain text editor to edit my scripts (using e.g. Mozilla Prism + a localhost install/ webserver). It works fine so far, but when I want to insert something at the cursor position, it gets slow in Firefox when there is a lot of text in the textarea (Chrome works fine). E.g. with 133k filled in the textarea it takes around 1 sec to perform inserting 4 spaces.
I already have and use elm.selectionStart and elm.selectionEnd. Based on these I then copy the text, manipulate it, and set the value back into the textarea -- perhaps that is what's causing the bottleneck (I'm using the similar approach as answered on this site before). Ideally, I would probably like to have something like elm.selectedText = 'foobar' but can't find this...
It doesn't necessarily need to be crossbrowser...
Can someone help?
According to this article on codemirror, using designMode is faster than using a textarea, because you can edit parts of the content instead of editing the whole text in one go.
There's an API that replaces the selected text: textarea.setRangeText('text').
Here's a demo:
const textarea = document.querySelector('textarea');
textarea.addEventListener('click', () => {
textarea.setRangeText('WOW');
});
<textarea rows="10" cols="40">Click anywhere or select any text in here. It will be replaced by WOW</textarea>
There's also document.execCommand('insertText') with undo support but it's not cross-browser. Try insert-text-textarea for a cross-browser solution.
Is there a way to determine when the contents of a HTML tag has changed? I would prefer to catch an event rather than polling it.
My use case is I have text enclosed in span tags within a rich text editor, and I need to remove the span tags when the enclosing text is modified by the user.
Are you using one of the typical WYSIWYG editors, and don't want to update their code to break updatability? Then maybe you could listen to the onTextChange event (or something similar) that the WYSIWYG editor is sending, check the contents of the change, and react on that.
Just an idea, given that you give a bit too little information in your question.
I don't think there is an event available (except for input elements), however you could poll it.
$element = $('#my-element');
var originalHtml = $element.html();
var pollHtml = setInterval(function() {
if (originalHtml !== $element.html()) {
alert('HTML changed!');
clearInterval(pollHtml);
};
}, 100);
I can't add a comment so I'm putting my suggestion here,
#Justin Johnson
$("#close-question-2114317").change(function() {alert(1);});
$("#close-question-2114317").text( function(){
$(this).trigger('change');
return "Close!!!";
});
I believe we can call the trigger if that's the case...
You must be using JavaScript to modify the DOM in some way. Polling is in most cases a bad idea. I have set up a demo here that gives you a good idea on how you might want to check the HTML for changes. Just call that function when needed... even if it is just polling.