How to make HTML5 contenteditable div allowing only text in firefox? - html

I want to make div with contentEditable attribute which is allowing only text. It's easily achievable in Chrome by using:
<div contenteditable="plaintext-only"></div>
However it doesn't work in Firefox. Is there a way how to make text-only contenteditable div in Firefox ? I know it is possible, because Google Plus has such div, but I don't know how they do it.

I ran into this problem myself. Here is my solution which I have tested in Firefox and Chrome:
Ensure the contenteditable div has the css white-space: pre, pre-line or pre-wrap so that it displays \n as new lines.
Override the "enter" key so that when we are typing, it does not create any <div> or <br> tags
myDiv.addEventListener("keydown", e => {
//override pressing enter in contenteditable
if (e.keyCode == 13)
{
//don't automatically put in divs
e.preventDefault();
e.stopPropagation();
//insert newline
insertTextAtSelection(myDiv, "\n");
}
});
Secondly, override the paste event to only ever fetch the plaintext
//override paste
myDiv.addEventListener("paste", e => {
//cancel paste
e.preventDefault();
//get plaintext from clipboard
let text = (e.originalEvent || e).clipboardData.getData('text/plain');
//insert text manually
insertTextAtSelection(myDiv, text);
});
And here is the supporting function which inserts text into the textContent of a div, and returns the cursor to the proper position afterwards.
function insertTextAtSelection(div, txt) {
//get selection area so we can position insert
let sel = window.getSelection();
let text = div.textContent;
let before = Math.min(sel.focusOffset, sel.anchorOffset);
let after = Math.max(sel.focusOffset, sel.anchorOffset);
//ensure string ends with \n so it displays properly
let afterStr = text.substring(after);
if (afterStr == "") afterStr = "\n";
//insert content
div.textContent = text.substring(0, before) + txt + afterStr;
//restore cursor at correct position
sel.removeAllRanges();
let range = document.createRange();
//childNodes[0] should be all the text
range.setStart(div.childNodes[0], before + txt.length);
range.setEnd(div.childNodes[0], before + txt.length);
sel.addRange(range);
}
https://jsfiddle.net/1te5hwv0/

Sadly, you can’t. As this answer points out the spec only specifies true, false and inherit as valid parameters. The subject seems to have been discussed but if I’m not mistaken only Webkit implements support for plaintext-only.

Related

Copying text with a new line to <input type="text"/> not working in IE

My problem is the following:
I have an input, simple as that:
<input type="text"/>
And when I try to paste some text that contains a new line in it, all the text after the new line does not appear.
Now I know this type of input shouldn't support such behavior, and the best scenario is to use a textarea but that would be hardly achievable in the current project I am working on.
However, other browsers convert the new line to a space character and append the text after the new line so you eventually get the whole text in a single line. IE doesn't do that.
I have found the following solution to intercept paste event and I thought maybe I can use it to transform the string into a single-lined but it doesn't work in firefox. I can try a browser detection but I am afraid it can fail in many other scenarios as well.
Is there something else that I can do to make IE behave like other browsers and what are my best options?
I found this answer that might be the solution to your problem:
JavaScript get clipboard data on paste event (Cross browser)
It should work in IE6+, FF 22+, Chrome & Safari.
HTML
<input id='editableDiv' contenteditable='true' type="text"/>
JavaScript
function handlePaste (e) {
var clipboardData, pastedData;
// Stop data actually being pasted into input field
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
// Remove new line characters
alert(pastedData);
var res = pastedData.replace(/\r?\n|\r/g, );
}
document.getElementById('editableDiv').addEventListener('paste', handlePaste);
Hope this helps mate.
Thanks for your answer George K - yours was the base for my solution. I had a few remaining problems to get past:
addEventListener was giving me 'element not found'
concatenated value wasn't populating the field
So I ended up with these slight modifications to your javascript:
function handlePaste(e) {
var clipboardData, pastedData;
// Stop data actually being pasted into input field
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
// Remove new line characters
var res = pastedData.replace(/\r?\n|\r/g, ' ');
document.getElementById(e.target.id).value = res; // <- added this to populate value
}
// added this also - this fixed my 'element not found' error
window.addEventListener('load', function () {
document.getElementById('editableDiv').addEventListener('paste', handlePaste);
})
BTW, I am using an <asp:textbox> instead of an <input> element.
This works for me in both IE (11) and Chrome (83.x).

How do you tab through text in html text input?

So I need a way of being able to tab to the next line in an html text input without it skipping to the next html input, is this possible?
You can do it by Jquery:
Activating next input field in form on enter
Focus on next input field inside table with enter key press
focusNextInputField With jsfiddle demo
Easiest one is:
$("input").change(function() {
var inputs = $(this).closest('form').find(':input');
inputs.eq( inputs.index(this)+ 1 ).focus();
});
If these solutions doesn't help then provide your code, so that it will be easier to understand.
If you really are trying to MAKE a textarea field where users can tab, you don't need jQuery.
See this jsFiddle : http://jsfiddle.net/2wAzx/13/
function enableTab(id) {
var el = document.getElementById(id);
el.onkeydown = function(e) {
if (e.keyCode === 9) { // tab was pressed
// get caret position/selection
var val = this.value,
start = this.selectionStart,
end = this.selectionEnd;
// set textarea value to: text before caret + tab + text after caret
this.value = val.substring(0, start) + '\t' + val.substring(end);
// put caret at right position again
this.selectionStart = this.selectionEnd = start + 1;
// prevent the focus lose
return false;
}
};
}
// Enable the tab character onkeypress (onkeydown) inside textarea...
// ... for a textarea that has an `id="my-textarea"`
enableTab('my-textarea');
Also, if that is your question, i'd recommend marking it as a duplicate since it has been asked more than once on SO...

Google App Script Page break at cursor?

I have a button in my sidebar of which's purpose is to insert a page break where the cursor is. I tried scripting it to just insert a page break (not at the cursor but just in the body) and it works fine.
However, I can't seem to get it to work at the cursor:
function pageBreak() {
var cursor = DocumentApp.getActiveDocument().getOffset();
insertPageBreak(cursor);
}
How can I accomplish this?
You need to know the element type at the cursor position. Not all element types allow a page break to be inserted.
Begin by getting the element at the cursor position, then work from there.
function insertPgBrk() {
var theCursor = DocumentApp.getActiveDocument().getCursor();
var theElement = theCursor.getElement();
var elementTypeAtCursor = theElement.getType();
Logger.log('elementTypeAtCursor: ' + elementTypeAtCursor);
if (elementTypeAtCursor === DocumentApp.ElementType.PARAGRAPH) {
Logger.log('its the right type');
theElement.insertPageBreak(0);
};
};
You can't insert a page break in a TEXT element. The element needs to be a PARAGRAPH or a LISTITEM.

Retrieving the selected HTML from a contenteditable div

I'm trying to get the selected HTML from a contenteditable div in a particular situation. First of all let me tell you that i read the questions from Get selected element's outer HTML and Get Selected HTML in browser via Javascript.
and that i am using Redactor http://imperavi.com/redactor/
So I tried the following function to retrieve the selected HTML:
function getSelectionHtml() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
} else if (typeof document.selection != "undefined") {
if (document.selection.type == "Text") {
html = document.selection.createRange().htmlText;
}
}
return html;
}
Now the situation is this: i have something like an italic text, then i select it and i modify the DOM to make it look bolded too.
When i select the text and make it bolded, the HTML i get looks like this:
<span class="bold">​</span><strong><span class="bold" data-redactor="verified" data-redactor-inlineMethods="">fermentum</span><span></span></strong>
I click somewhere else within the page. The text is deselected.
When i select the text for the second time and i make it italic i get the following:
​fermentum
As you can see, the second time i don't get the elements which allow me to determine that it is bolded.
So, it DOESN'T WORK on Internet Explorer 10.
It WORKS on Firefox.
It DOESN'T WORK on Chrome.
Is there an effective way to get the selected HTML from a contenteditable div other than this one?

Contenteditable paragraph tag on enter

I was wondering if there is an acceptable way to force all major browsers to insert paragraph tag instead of the default tag that they insert on pressing enter key when contentEditable is true.
As far as I know IE inserts p automatically. But Google Chrome inserts div tag and Firefox inserts br (WTF?!).
Thanks in advance!
you can use document.execCommand('formatBlock', false, 'p'); in event like keypress or keydown, etc. to use paragraphs after enter press. For example:
element.addEventListener('keypress', function(ev){
if(ev.keyCode == '13')
document.execCommand('formatBlock', false, 'p');
}, false);
As its build in the browser you can't change that behaviour. You could work around by detecting browser and replacing elements correspondingly. Very ugly, I know.
Also check WhatWG for background: http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2011-May/031577.html
I had this same problem and found the solution (CHROME, MSIE, FIREFOX), follow my code in the link.
$(document).on('click','#myButton',function() {
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1)
var str = $('#myDiv').html().replace(/<br>/gi,'').replace(/<div>/gi,'<br>').replace(/<\/div>/gi,'');
else if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1)
var str = $('#myDiv').html().replace(/<\/br>/gi,'').replace(/<br>/gi,'<br>').replace(/<\/br>/gi,'');
else if (navigator.userAgent.toLowerCase().indexOf("msie") == -1)
var str = $('#myDiv').html().replace(/<br>/gi,'').replace(/<p>/gi,'<br>').replace(/<\/p>/gi,'');
$('#myDiv2').removeClass('invisible').addClass('visible').text(str);
$('#myDiv3').removeClass('invisible').addClass('visible').html(str);
});
https://jsfiddle.net/kzkxo70L/1/