Remove formatting from a contentEditable div - javascript

I have a contentEditable Div and I want remove any formatting especially for copy and paste text.

You can add a listener to the "paste" event and reformat the clipboard contents. Like so:
let editableDiv = document.querySelector('div[contenteditable="true"]');
editableDiv.addEventListener("paste", function(e) {
e.preventDefault();
var text = e.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, text);
});
Here another example for all containers in the body:
let allEditableDivs = document.querySelectorAll('div[contenteditable="true"]');
[].forEach.call(allEditableDivs, function (el) {
el.addEventListener('paste', function(e) {
e.preventDefault();
var text = e.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, text);
}, false);
}
Saludos.

Have you tried using innerText?
ADDED:
If you want to strip markup from content pasted into the editable div, try the old hack of creating a temporary div -- see example below.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Strip editable div markup</title>
<script type="text/javascript">
function strip(html) {
var tempDiv = document.createElement("DIV");
tempDiv.innerHTML = html;
return tempDiv.innerText;
}
</script>
</head>
<body>
<div id="editableDiv" contentEditable="true"></div>
<input type="button" value="press" onclick="alert(strip(document.getElementById('editableDiv').innerText));" />
</body>
</html>

Was looking for answer to this for ages and ended up writing my own.
I hope this helps others. At the time of writing this it appears to work in ie9, latest chrome and firefox.
<div contenteditable="true" onpaste="OnPaste_StripFormatting(this, event);" />
<script type="text/javascript">
var _onPaste_StripFormatting_IEPaste = false;
function OnPaste_StripFormatting(elem, e) {
if (e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData) {
e.preventDefault();
var text = e.originalEvent.clipboardData.getData('text/plain');
window.document.execCommand('insertText', false, text);
}
else if (e.clipboardData && e.clipboardData.getData) {
e.preventDefault();
var text = e.clipboardData.getData('text/plain');
window.document.execCommand('insertText', false, text);
}
else if (window.clipboardData && window.clipboardData.getData) {
// Stop stack overflow
if (!_onPaste_StripFormatting_IEPaste) {
_onPaste_StripFormatting_IEPaste = true;
e.preventDefault();
window.document.execCommand('ms-pasteTextOnly', false);
}
_onPaste_StripFormatting_IEPaste = false;
}
}
</script>

Try <div id="editableDiv" contentEditable="plaintext-only"></div>

I know it's been a while, but I had the same problem. On my case, it's a GWT application to make it even worse.
Anyway, resolved the problem with:
var clearText = event.clipboardData.getData('text/plain');
document.execCommand('inserttext', false, clearText);
See: https://jsfiddle.net/erikwoods/Ee3yC/
I preferred "inserttext" command instead of "insertHTML", because the documentation says it's exactly to insert plain text, so seems more suitable.
See https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

With Jquery you can use .text() method, so, when blur for example you can replace the content with the text content
$("#element").blur(function(e) {
$(this).html($(this).text());
});

You can't access the system clipboard so you'll need a hack. See this question: JavaScript get clipboard data on paste event (Cross browser)

I'd like to add my solution to this issue:
ContentEditableElement.addEventListener('input', function(ev) {
if(ev.target.innerHTML != ev.target.textContent) {
// determine position of the text caret
var caretPos = 0,
sel, range;
sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0);
var children = ev.target.childNodes;
var keepLooping = true;
for(let i = 0; keepLooping; i++) {
if(children[i] == range.commonAncestorContainer || children[i] == range.commonAncestorContainer.parentNode) {
caretPos += range.endOffset;
keepLooping = false;
} else {
caretPos += children[i].textContent.length;
}
}
// set the element's innerHTML to its textContent
ev.target.innerHTML = ev.target.textContent;
// put the caret where it was before
range = document.createRange();
range.setStart(ev.target.childNodes[0], caretPos);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
});
(this isn't compatible with older versions of IE)

Just for my later life. ;)
styles.css
/* Not easy to look exactly like input field: */
/* https://stackoverflow.com/a/8957518/1707015 */
.contenteditable_div {
/* box-shadow: 1px 1px 1px 0 lightgray inset; */
background-color:#dddddd;
overflow-wrap:break-word;
padding:3px;
}
index.html
<!-- Firefox doesn't support contenteditable="plaintext-only" yet! -->
<div class="contenteditable_div" contenteditable="true" id="blubbi">abc</div>
script.js
// Optional: Copy font from other input field:
// $('#blubbi').css('font', $('#blubbi_input_field').css('font'));
$('.contenteditable_div').on('input', function(){
// problems with setting cursor to beginning of div!
// this.innerHTML = this.innerText;
$(this).text($(this).text());
});
Keep in mind that this solution doesn't support or care about line breaks.
And keep in mind that setting the text like this will set the cursor to the beginning of your contenteditable div - while you are typing. Still a good solution if you need it only for copy & paste. Please write a comment if you have an easy solution for this "reverse typing problem" (under 10 lines of code please). ;)
Tested on Firefox 89, Chrome 90 and Safari 14.

Related

Why document.execCommand("copy") doesn't work?

I have the following Page
When I click "Click Here To Copy", it calls document.execCommand("copy") to copy some text to the clipboard and it works.
However, when I hit the button "Open popup", it opens a div in the same page (no iframe), then when clicking on "Click Here To Copy", document.execCommand("copy") doesn't work.
Steps to reproduce :
document.execCommand("copy") works :
However if I open the popup, document.execCommand("copy") doesn't work
Does anyone know the reason for that please ?
Thanks
cheers,
Here is my entire code :
function CopyToClipBoard(d){
var c=document.createElement("textarea");
c.innerText=d;
document.body.appendChild(c);
c.select();
document.execCommand("copy");
document.body.removeChild(c);
}
<div onclick="CopyToClipBoard('text to be copied')">Click Here To copy</div>
Here is the cause of the problem :
The following code doesn't seem to work when there is an overlay of a document. For example when the caller is on a div with higher z-index or something... I'm not sure on what exactly causes this code to fail. But it seems related to overlayers, focusable elements or something... The fact is that, when the body of the document is hidden, the created text area is unable to focus and it doesn't work.
function CopyToClipBoard(d){
var c=document.createElement("textarea");
c.innerText=d;
document.body.appendChild(c);
c.select();
document.execCommand("copy");
document.body.removeChild(c);
}
<div onclick="CopyToClipBoard('text to be copied')">Click Here To copy</div>
Solution :
Instead of adding the text area to the body of the document, it can be added to the caller itself... Hence it will always be in the foreground. This assumes the text to copy is short such that the execution is fast enough for the user not to notice the creation and the removal of the text area...
function CopyToClipBoard(item, d){
var c=document.createElement("textarea");
c.value=d;
c.style.maxWidth = '0px';
c.style.maxHeight = '0px';
item.appendChild(c);
c.focus();
c.select();
document.execCommand("copy");
item.removeChild(c);
}
<div onclick="CopyToClipBoard(this,'text to be copied')">Click Here To copy</div>
Here is my working example of copyTextToClipboard function. Please try to add textArea.focus call.
const fallbackCopyTextToClipboard = text => {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
}
const copyTextToClipboard = text => {
if (navigator.clipboard) {
return navigator.clipboard.writeText(text);
}
return new Promise((resolve, reject) => {
fallbackCopyTextToClipboard(text);
resolve();
});
};

How to set cursor position at the end of input text in Google Chrome

I'm trying to set the cursor in a text field with a focus function. I've made some research but none of the provided solutions seemed to work in Google Chrome. In Internet Explorer and Firefox this solution is working fine:
The js:
$('#Search').focus(function() {
var SearchInput = $('#Search');
var strLength= SearchInput.val().length;
SearchInput.focus();
SearchInput[0].setSelectionRange(strLength, strLength);
});
The HTML:
<input type="text" id="Search" value="Hello World" />
Here's the link to my jsfiddle.
Is there any way to make this work in Google Chrome too?
It seems like the focus event is fired before the cursor is placed when you focus an input, a hacky workaround would be to use a setTimeout like so:
$('#Search').focus(function() {
setTimeout((function(el) {
var strLength = el.value.length;
return function() {
if(el.setSelectionRange !== undefined) {
el.setSelectionRange(strLength, strLength);
} else {
$(el).val(el.value);
}
}}(this)), 0);
});
Try this fiddle: http://jsfiddle.net/esnvh/26/
Edited to 0ms timeout, as #SparK pointed out this is enough to push to end of execution queue.
Updated code
Reference: http://css-tricks.com/snippets/jquery/move-cursor-to-end-of-textarea-or-input/
setSelectionRange is not supported on IE, Opera & Safari
I suggest you to make something like this (works on IE, Chrome, Safari, Firefox).
$('#Search').on('mouseup', function() {
var element = $(this)[0];
if (this.setSelectionRange) {
var len = $(this).val().length * 2;
element.setSelectionRange(len, len);
}
else {
$(this).val($(this).val());
$(this).focus();
}
element.scrollTop = 9999;
});
Try this: http://jsfiddle.net/r5UVW/4/
Use mouseup event for that:
$("#Search").mouseup(function () {
this.setSelectionRange(this.value.length, this.value.length);
});
Without jQuery :)
private focusOnLastInput(): void {
const items = this.fields.querySelectorAll('input');
const lastInput = items[items.length - 1];
const valueLength = lastInput.value.length;
lastInput.focus();
lastInput.setSelectionRange(valueLength, valueLength);
}
FYI, currently the number input doesn't support setSelectionRange(), so a quick solution is to simply select the text using .select(). On desktop browsers this highlights the text, on mobiles this moves the cursor straight to the end of the text.

div do not support to the selected font before editing

I have an UIWebView and loaded the editable div on it. As soon as the app launch's div is loaded on UIWebViewand on tap (implemented the tap gesture), it allows to write anything on it. Now i need to select the font initially after div load's(as soon as app launches), from picker which i have already done than i tap on UIWebView to write with selected font but i am unable to achieve this. But once div / UIWebView is active i.e ready to type than below code works
[webViewForEditing stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"document.execCommand('fontName', true, '%#')",fontName]];
here is my script
<html>
<script type="text/javascript">
document.addEventListener('touchend', function(e){
// Listen for touch end on the document
// Get the touch and coordinates
var touch = e.changedTouches.item(0);
var touchX = touch.clientX;
var touchY = touch.clientY;
// Get the rect for the content
var contentDIVRect = document.getElementById('content').getClientRects()[0];
// Make sure we don't block touches to the content div
if (touchX > contentDIVRect.left && touchY < contentDIVRect.bottom) {
return;
}
// If the touch is out of the content div then simply give the div focus
document.getElementById('content').focus();
document.execCommand('fontName', true, fontName);
}, false);
function moveImageAtTo(x, y, newX, newY) {
// Get our required variables
var element = document.elementFromPoint(x, y);
if (element.toString().indexOf('Image') == -1)
{
// Attempt to move an image which doesn't exist at the point
return;
}
var caretRange = document.caretRangeFromPoint(newX, newY);
var selection = window.getSelection();
// Save the image source so we know this later when we need to re-insert it
var imageSrc = element.src;
// Set the selection to the range of the image, so we can delete it
var nodeRange = document.createRange();
nodeRange.selectNode(element);
selection.removeAllRanges();
selection.addRange(nodeRange);
// Delete the image
document.execCommand('delete');
document.execCommand('insertText', false, ' ');
// Set the selection to the caret range, so we can then add the image
var selection = window.getSelection();
var range = document.createRange();
selection.removeAllRanges();
selection.addRange(caretRange);
// Re-insert the image
document.execCommand('insertImage', false, imageSrc);
}
</script>
<style>
#content img{
height:25px;
width:25px;
}
</style>
<body>
<div id="content" contenteditable="true" style="font-family: Frank the Architect ; font-size:18px">TAP HERE TO BEGIN WRITING...</div>
</body>

Can a textarea be sized to the content entered into it

I have a textarea on a form that is populated with text from a database query ready for someone to edit.
I would like the textarea to show the whole content without the need to scroll, but don't want to put a large textarea when there is only a small amount of text.
Text can be from 5 to 300 characters.
I have seen a solution to this type of issue but only where the textarea grows onkeyup as shown below.
<script>
function textAreaAdjust(o) {
o.style.height = "1px";
o.style.height = (25+o.scrollHeight)+"px";
}
</script>
<textarea onkeyup="textAreaAdjust(this)" style="overflow:hidden"></textarea>
Firstly, don't use onkeyup. It's not suitable for detecting text input.
I use the following code to resize a textarea to constantly resize a textarea element to fit the content:
var tarea = document.getElementsByTagName("textarea")[0];
tarea.oninput = function () {
tarea.style.height = tarea.scrollHeight + "px";
}
​
However, oninput isn't supported in older versions of IE, so you'll need to add onpropertychange if you need it to work in IE 8 and lower:
var tarea = document.getElementsByTagName("textarea")[0];
tarea.oninput = tarea.onpropertychange = function (evt) {
evt = evt || window.evt;
if (evt.type == "propertychange" && evt.propertyName != "value")
return;
tarea.style.height = tarea.scrollHeight + "px";
}
Working Demo: http://jsfiddle.net/D5e8t/
You can call the method on page load.
Copy the content of textarea to a invisible div, with the same width, and styles that affect size (font-size, line-height, padding, etc.). Measure the height of said div, and set your textarea to the same height.
Just little modifications to the above code will make textarea autosizable.
Just perfiorm the below steps
1) Add id to your text area
<textarea onkeyup="textAreaAdjust(this)" id="txt" runat="server" style="overflow:hidden"></textarea>
2) Before a closing of bode tag add the javascript code to call the testAreaAdjust block
<script type="text/javascript">
textAreaAdjust(document.getElementById('txt'));
</script>
This will autosize the textbox.
Hope this will help you

How to autosize a textarea using Prototype?

I'm currently working on an internal sales application for the company I work for, and I've got a form that allows the user to change the delivery address.
Now I think it would look much nicer, if the textarea I'm using for the main address details would just take up the area of the text in it, and automatically resize if the text was changed.
Here's a screenshot of it currently.
Any ideas?
#Chris
A good point, but there are reasons I want it to resize. I want the area it takes up to be the area of the information contained in it. As you can see in the screen shot, if I have a fixed textarea, it takes up a fair wack of vertical space.
I can reduce the font, but I need address to be large and readable. Now I can reduce the size of the text area, but then I have problems with people who have an address line that takes 3 or 4 (one takes 5) lines. Needing to have the user use a scrollbar is a major no-no.
I guess I should be a bit more specific. I'm after vertical resizing, and the width doesn't matter as much. The only problem that happens with that, is the ISO number (the large "1") gets pushed under the address when the window width is too small (as you can see on the screenshot).
It's not about having a gimick; it's about having a text field the user can edit that won't take up unnecessary space, but will show all the text in it.
Though if someone comes up with another way to approach the problem I'm open to that too.
I've modified the code a little because it was acting a little odd. I changed it to activate on keyup, because it wouldn't take into consideration the character that was just typed.
resizeIt = function() {
var str = $('iso_address').value;
var cols = $('iso_address').cols;
var linecount = 0;
$A(str.split("\n")).each(function(l) {
linecount += 1 + Math.floor(l.length / cols); // Take into account long lines
})
$('iso_address').rows = linecount;
};
Facebook does it, when you write on people's walls, but only resizes vertically.
Horizontal resize strikes me as being a mess, due to word-wrap, long lines, and so on, but vertical resize seems to be pretty safe and nice.
None of the Facebook-using-newbies I know have ever mentioned anything about it or been confused. I'd use this as anecdotal evidence to say 'go ahead, implement it'.
Some JavaScript code to do it, using Prototype (because that's what I'm familiar with):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="http://www.google.com/jsapi"></script>
<script language="javascript">
google.load('prototype', '1.6.0.2');
</script>
</head>
<body>
<textarea id="text-area" rows="1" cols="50"></textarea>
<script type="text/javascript" language="javascript">
resizeIt = function() {
var str = $('text-area').value;
var cols = $('text-area').cols;
var linecount = 0;
$A(str.split("\n")).each( function(l) {
linecount += Math.ceil( l.length / cols ); // Take into account long lines
})
$('text-area').rows = linecount + 1;
};
// You could attach to keyUp, etc. if keydown doesn't work
Event.observe('text-area', 'keydown', resizeIt );
resizeIt(); //Initial on load
</script>
</body>
</html>
PS: Obviously this JavaScript code is very naive and not well tested, and you probably don't want to use it on textboxes with novels in them, but you get the general idea.
One refinement to some of these answers is to let CSS do more of the work.
The basic route seems to be:
Create a container element to hold the textarea and a hidden div
Using Javascript, keep the textarea’s contents synced with the div’s
Let the browser do the work of calculating the height of that div
Because the browser handles rendering / sizing the hidden div, we avoid
explicitly setting the textarea’s height.
document.addEventListener('DOMContentLoaded', () => {
textArea.addEventListener('change', autosize, false)
textArea.addEventListener('keydown', autosize, false)
textArea.addEventListener('keyup', autosize, false)
autosize()
}, false)
function autosize() {
// Copy textarea contents to div browser will calculate correct height
// of copy, which will make overall container taller, which will make
// textarea taller.
textCopy.innerHTML = textArea.value.replace(/\n/g, '<br/>')
}
html, body, textarea {
font-family: sans-serif;
font-size: 14px;
}
.textarea-container {
position: relative;
}
.textarea-container > div, .textarea-container > textarea {
word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
box-sizing: border-box;
padding: 2px;
width: 100%;
}
.textarea-container > textarea {
overflow: hidden;
position: absolute;
height: 100%;
}
.textarea-container > div {
padding-bottom: 1.5em; /* A bit more than one additional line of text. */
visibility: hidden;
}
<div class="textarea-container">
<textarea id="textArea"></textarea>
<div id="textCopy"></div>
</div>
Here's another technique for autosizing a textarea.
Uses pixel height instead of line height: more accurate handling of line wrap if a proportional font is used.
Accepts either ID or element as input
Accepts an optional maximum height parameter - useful if you'd rather not let the text area grow beyond a certain size (keep it all on-screen, avoid breaking layout, etc.)
Tested on Firefox 3 and Internet Explorer 6
Code:
(plain vanilla JavaScript)
function FitToContent(id, maxHeight)
{
var text = id && id.style ? id : document.getElementById(id);
if (!text)
return;
/* Accounts for rows being deleted, pixel value may need adjusting */
if (text.clientHeight == text.scrollHeight) {
text.style.height = "30px";
}
var adjustedHeight = text.clientHeight;
if (!maxHeight || maxHeight > adjustedHeight)
{
adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
if (maxHeight)
adjustedHeight = Math.min(maxHeight, adjustedHeight);
if (adjustedHeight > text.clientHeight)
text.style.height = adjustedHeight + "px";
}
}
Demo:
(uses jQuery, targets on the textarea I'm typing into right now - if you have Firebug installed, paste both samples into the console and test on this page)
$("#post-text").keyup(function()
{
FitToContent(this, document.documentElement.clientHeight)
});
Probably the shortest solution:
jQuery(document).ready(function(){
jQuery("#textArea").on("keydown keyup", function(){
this.style.height = "1px";
this.style.height = (this.scrollHeight) + "px";
});
});
This way you don't need any hidden divs or anything like that.
Note: you might have to play with this.style.height = (this.scrollHeight) + "px"; depending on how you style the textarea (line-height, padding and that kind of stuff).
Here's a Prototype version of resizing a text area that is not dependent on the number of columns in the textarea. This is a superior technique because it allows you to control the text area via CSS as well as have variable width textarea. Additionally, this version displays the number of characters remaining. While not requested, it's a pretty useful feature and is easily removed if unwanted.
//inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
if (window.Widget == undefined) window.Widget = {};
Widget.Textarea = Class.create({
initialize: function(textarea, options)
{
this.textarea = $(textarea);
this.options = $H({
'min_height' : 30,
'max_length' : 400
}).update(options);
this.textarea.observe('keyup', this.refresh.bind(this));
this._shadow = new Element('div').setStyle({
lineHeight : this.textarea.getStyle('lineHeight'),
fontSize : this.textarea.getStyle('fontSize'),
fontFamily : this.textarea.getStyle('fontFamily'),
position : 'absolute',
top: '-10000px',
left: '-10000px',
width: this.textarea.getWidth() + 'px'
});
this.textarea.insert({ after: this._shadow });
this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
this.textarea.insert({after: this._remainingCharacters});
this.refresh();
},
refresh: function()
{
this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
this.textarea.setStyle({
height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
});
var remaining = this.options.get('max_length') - $F(this.textarea).length;
this._remainingCharacters.update(Math.abs(remaining) + ' characters ' + (remaining > 0 ? 'remaining' : 'over the limit'));
}
});
Create the widget by calling new Widget.Textarea('element_id'). The default options can be overridden by passing them as an object, e.g. new Widget.Textarea('element_id', { max_length: 600, min_height: 50}). If you want to create it for all textareas on the page, do something like:
Event.observe(window, 'load', function() {
$$('textarea').each(function(textarea) {
new Widget.Textarea(textarea);
});
});
Here is a solution with JQuery:
$(document).ready(function() {
var $abc = $("#abc");
$abc.css("height", $abc.attr("scrollHeight"));
})
abc is a teaxtarea.
Check the below link:
http://james.padolsey.com/javascript/jquery-plugin-autoresize/
$(document).ready(function () {
$('.ExpandableTextCSS').autoResize({
// On resize:
onResize: function () {
$(this).css({ opacity: 0.8 });
},
// After resize:
animateCallback: function () {
$(this).css({ opacity: 1 });
},
// Quite slow animation:
animateDuration: 300,
// More extra space:
extraSpace:20,
//Textarea height limit
limit:10
});
});
Just revisiting this, I've made it a little bit tidier (though someone who is full bottle on Prototype/JavaScript could suggest improvements?).
var TextAreaResize = Class.create();
TextAreaResize.prototype = {
initialize: function(element, options) {
element = $(element);
this.element = element;
this.options = Object.extend(
{},
options || {});
Event.observe(this.element, 'keyup',
this.onKeyUp.bindAsEventListener(this));
this.onKeyUp();
},
onKeyUp: function() {
// We need this variable because "this" changes in the scope of the
// function below.
var cols = this.element.cols;
var linecount = 0;
$A(this.element.value.split("\n")).each(function(l) {
// We take long lines into account via the cols divide.
linecount += 1 + Math.floor(l.length / cols);
})
this.element.rows = linecount;
}
}
Just it call with:
new TextAreaResize('textarea_id_name_here');
I've made something quite easy. First I put the TextArea into a DIV. Second, I've called on the ready function to this script.
<div id="divTable">
<textarea ID="txt" Rows="1" TextMode="MultiLine" />
</div>
$(document).ready(function () {
var heightTextArea = $('#txt').height();
var divTable = document.getElementById('divTable');
$('#txt').attr('rows', parseInt(parseInt(divTable .style.height) / parseInt(altoFila)));
});
Simple. It is the maximum height of the div once it is rendered, divided by the height of one TextArea of one row.
I needed this function for myself, but none of the ones from here worked as I needed them.
So I used Orion's code and changed it.
I added in a minimum height, so that on the destruct it does not get too small.
function resizeIt( id, maxHeight, minHeight ) {
var text = id && id.style ? id : document.getElementById(id);
var str = text.value;
var cols = text.cols;
var linecount = 0;
var arStr = str.split( "\n" );
$(arStr).each(function(s) {
linecount = linecount + 1 + Math.floor(arStr[s].length / cols); // take into account long lines
});
linecount++;
linecount = Math.max(minHeight, linecount);
linecount = Math.min(maxHeight, linecount);
text.rows = linecount;
};
Like the answer of #memical.
However I found some improvements. You can use the jQuery height() function. But be aware of padding-top and padding-bottom pixels. Otherwise your textarea will grow too fast.
$(document).ready(function() {
$textarea = $("#my-textarea");
// There is some diff between scrollheight and height:
// padding-top and padding-bottom
var diff = $textarea.prop("scrollHeight") - $textarea.height();
$textarea.live("keyup", function() {
var height = $textarea.prop("scrollHeight") - diff;
$textarea.height(height);
});
});
My solution not using jQuery (because sometimes they don't have to be the same thing) is below. Though it was only tested in Internet Explorer 7, so the community can point out all the reasons this is wrong:
textarea.onkeyup = function () { this.style.height = this.scrollHeight + 'px'; }
So far I really like how it's working, and I don't care about other browsers, so I'll probably apply it to all my textareas:
// Make all textareas auto-resize vertically
var textareas = document.getElementsByTagName('textarea');
for (i = 0; i<textareas.length; i++)
{
// Retain textarea's starting height as its minimum height
textareas[i].minHeight = textareas[i].offsetHeight;
textareas[i].onkeyup = function () {
this.style.height = Math.max(this.scrollHeight, this.minHeight) + 'px';
}
textareas[i].onkeyup(); // Trigger once to set initial height
}
Here is an extension to the Prototype widget that Jeremy posted on June 4th:
It stops the user from entering more characters if you're using limits in textareas. It checks if there are characters left. If the user copies text into the textarea, the text is cut off at the max. length:
/**
* Prototype Widget: Textarea
* Automatically resizes a textarea and displays the number of remaining chars
*
* From: http://stackoverflow.com/questions/7477/autosizing-textarea
* Inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
*/
if (window.Widget == undefined) window.Widget = {};
Widget.Textarea = Class.create({
initialize: function(textarea, options){
this.textarea = $(textarea);
this.options = $H({
'min_height' : 30,
'max_length' : 400
}).update(options);
this.textarea.observe('keyup', this.refresh.bind(this));
this._shadow = new Element('div').setStyle({
lineHeight : this.textarea.getStyle('lineHeight'),
fontSize : this.textarea.getStyle('fontSize'),
fontFamily : this.textarea.getStyle('fontFamily'),
position : 'absolute',
top: '-10000px',
left: '-10000px',
width: this.textarea.getWidth() + 'px'
});
this.textarea.insert({ after: this._shadow });
this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
this.textarea.insert({after: this._remainingCharacters});
this.refresh();
},
refresh: function(){
this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
this.textarea.setStyle({
height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
});
// Keep the text/character count inside the limits:
if($F(this.textarea).length > this.options.get('max_length')){
text = $F(this.textarea).substring(0, this.options.get('max_length'));
this.textarea.value = text;
return false;
}
var remaining = this.options.get('max_length') - $F(this.textarea).length;
this._remainingCharacters.update(Math.abs(remaining) + ' characters remaining'));
}
});
#memical had an awesome solution for setting the height of the textarea on pageload with jQuery, but for my application I wanted to be able to increase the height of the textarea as the user added more content. I built off memical's solution with the following:
$(document).ready(function() {
var $textarea = $("p.body textarea");
$textarea.css("height", ($textarea.attr("scrollHeight") + 20));
$textarea.keyup(function(){
var current_height = $textarea.css("height").replace("px", "")*1;
if (current_height + 5 <= $textarea.attr("scrollHeight")) {
$textarea.css("height", ($textarea.attr("scrollHeight") + 20));
}
});
});
It's not very smooth but it's also not a client-facing application, so smoothness doesn't really matter. (Had this been client-facing, I probably would have just used an auto-resize jQuery plugin.)
For those that are coding for IE and encounter this problem. IE has a little trick that makes it 100% CSS.
<TEXTAREA style="overflow: visible;" cols="100" ....></TEXTAREA>
You can even provide a value for rows="n" which IE will ignore, but other browsers will use. I really hate coding that implements IE hacks, but this one is very helpful. It is possible that it only works in Quirks mode.
Internet Explorer, Safari, Chrome and Opera users need to remember to explicidly set the line-height value in CSS. I do a stylesheet that sets the initial properites for all text boxes as follows.
<style>
TEXTAREA { line-height: 14px; font-size: 12px; font-family: arial }
</style>
Here is a function I just wrote in jQuery to do it - you can port it to Prototype, but they don't support the "liveness" of jQuery so elements added by Ajax requests will not respond.
This version not only expands, but it also contracts when delete or backspace is pressed.
This version relies on jQuery 1.4.2.
Enjoy ;)
http://pastebin.com/SUKeBtnx
Usage:
$("#sometextarea").textareacontrol();
or (any jQuery selector for example)
$("textarea").textareacontrol();
It was tested on Internet Explorer 7/Internet Explorer 8, Firefox 3.5, and Chrome. All works fine.
Using ASP.NET, just simply do this:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Automatic Resize TextBox</title>
<script type="text/javascript">
function setHeight(txtarea) {
txtarea.style.height = txtdesc.scrollHeight + "px";
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="txtarea" runat= "server" TextMode="MultiLine" onkeyup="setHeight(this);" onkeydown="setHeight(this);" />
</form>
</body>
</html>

Categories