How to make contenteditable div accept only plaintext? - javascript

I have a div as a textarea, because div can change it's height based on the text inside it, the problem here is if someone copied some styled text (text and html) and pasted it, the style sticks with the text, contenteditable='plaintext-only' would solve the problem but it seems to be a webkit-only feature.
So is there a way to allow text only inside a div?
For reference: https://jsfiddle.net/w25dnuen/

Here's an example of a text area that will grow based on the contents you enter:
http://jsfiddle.net/janjarfalk/r3Ekw/
The reason that the elastic text area works is the external jquery.elastic.source.js which is located here: http://jquery-elastic.googlecode.com/svn/trunk/jquery.elastic.source.js
so now that you have looked at those two resources, let's talk about what it does. The script has an "udpate" function that basically just adds whitespace when it gets to the end of the row here:
// Add an extra white space so new rows are added when you are at the end of a row.
$twin.html(textareaContent+' ');
And then here you can see the respective functions:
// Updates the width of the twin. (solution for textareas with widths in percent)
function setTwinWidth(){
var curatedWidth = Math.floor(parseInt($textarea.width(),10));
if($twin.width() !== curatedWidth){
$twin.css({'width': curatedWidth + 'px'});
// Update height of textarea
update(true);
}
}
// Sets a given height and overflow state on the textarea
function setHeightAndOverflow(height, overflow){
var curratedHeight = Math.floor(parseInt(height,10));
if($textarea.height() !== curratedHeight){
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
}
}
This is all in the elastic function. Hopefully this gives a little insight and helps you out.

Related

Unable to calculate the hover element's exact position

I am just trying to get the mouse hover div's position at the right according to the space around. Somehow I am able to do this in first two columns but not for other columns. May be my calculations while writing the condition state are wrong.
Can anyone please help?
JS Fiddle URL:
http://jsfiddle.net/mufeedahmad/2u1zr11f/7/
JS Code:
$('.thumb-over-team li').find('.cover').css({opacity:0});
$('.thumb-over-team li').on('mouseenter', function(){
var $this = $(this),
thisoffset = $this.position().left,
openDivId = $(this).find('.cover'),
thumbContainer = '.thumb-over-team',
speedanim = 200;
if(thisoffset + openDivId.outerWidth() >= $(thumbContainer).outerWidth()){
//thisoffset = $(thumbContainer).outerWidth() - openDivId.outerWidth() - 212;
thisoffset = thisoffset - openDivId.outerWidth()+10;
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':-thisoffset}, 200);
}else{
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':'212px'}, 200);
}
}).on('mouseleave', function(){
$(this).find('.cover').stop().css({'z-index':'-1'}).animate({'opacity':'0', 'left':'200px'}, 200);
});
$('.close-parent').on('click', function(){
$(this).parents('.cover').stop().css({'z-index':'-1'}).animate({'opacity':'0', 'left':'200px'}, 200);
});;
In your first conditional, try to calculate the position of the offset as:
thisoffset = ($(thumbContainer).outerWidth() - openDivId.outerWidth() - thisoffset);
That way, you're adjusting the appearing square (.cover) when it doesn't fit inside the container, to be as close possible to its rightmost edge: (maximum width - appearing square width - current li position)
Calculated this way, you can animate it with the new offset in positive:
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':thisoffset}, 200);
See it working here.
For elements that "almost" fit, the current system isn't completely precise because of what I already pointed out in my previous comment: the appearing square, even if it were at 0 opacity, would still be inside the containing element (($(thumbContainer)) or .thumb-over-team) and it would add its width to the total width of the container.
So your conditional may think that there's enough available space in the container to make the expandable element fit, but that would go out of the screen. As an example, notice that there's a horizontal scrollbar from the very beginning, caused by this effect, where your containing .thumb-over-team element doesn't fit in the screen.
But I would say that more precision in this point would require a fresh new approach to your system where the appearing .cover elements were out of the containing ul .thumb-over-team
Fresh take on the problem, essentially based on the main issue: the expandable text block (.cover) used to add its width to the container (.thumb-over-team). This altered the calculations on available container space, and made the text containers go off screen.
The solution is to make sure the expandable .cover elements aren't contained inside the .thumb-over-team element, so they won't impact the calculations on available width.
Here is a JSFiddle containing this new approach: link.
Explanation of how it works:
The idea was to create a separate element called .cover-container and let's put all the expandable .cover elements in there.
We want to associate every image in the li elements in .thumb-over-team with their appropriate .cover (so the first image triggers the first .cover to show, the second image would show the second cover, and so on.) We achieve is by finding out the index of the element that triggered the event:
thisLiIndex = $this.index() + 1
And then selecting the cover in the matching position:
openDivId = $('.cover-container .cover:nth-child(' + thisLiIndex + ')')
The expandable covers shouldn't interfere with the mouseenter or mouseleave events of .thumb-over-team, so we make it to ignore mouse events via CSS:
.cover-container{pointer-events:none;}
Changing from one image to another would automatically trigger new events, so the expanding covers stay visible when the mouse stays on the images, but close automatically when the mouse exits them.
Since the covers are now outside of $(thumbContainer), openDivID.outerWidth() does not alter $(thumbContainer).outerWidth(), and we can use that safely in our positioning.
If I understand the placement that you want, for covers that fit, the position is the current offset (position of the li element that triggered the event) plus the width of the image and some subtle margin
imageWidth + rightSeparation + thisoffset
And for covers that won't fit inside of the screen, we keep them just inside of the screen
thisoffset = $(thumbContainer).outerWidth() - openDivId.outerWidth();

How do I get the height of a textarea

I need to get the height of a textarea. Seemingly so simple but it's driving me mad.
I have been researching for ages on stackoverflow with no luck: textarea-value-height and jquery-js-get-the-scrollbar-height-of-an-textarea and javascript-how-to-get-the-height-of-text-inside-of-a-textarea, among many others.
This is how it looks currently:
This is how I want it to look, open a full height:
.
Here is my html:
<textarea id="history" class="input-xxlarge" placeholder="Enter the content ..." rows="13"></textarea>
CSS:
.input-xxlarge {
display: inline-block;
height: auto;
font-size: 12px;
width: 530px;
resize: none;
overflow: auto;
}
jQuery:
var textarea = $('#history');
I've tried (inter alia):
1. textarea.height() --> always returns 0
2. textarea.ready(function() { // wait for DOM to load
textarea.height();
}
3. getting scrollheight from textarea as an HTMLTextareaElement (i.e. DOM Element) --> returns 0
4. var contentSpan = textarea.wrapInner('<span>');
var height = contentSpan.height(); --> always returns 0
Please help, I'm at my wit's end!
Ok, I've found a solution. Whether it's the best solution, I don't know, but it works and that, frankly, is all I care about, having spent almost a day on this issue.
Here it is for anyone who faces the same problem:
Select the textarea:
var textarea = $('#history');
Get the textarea's text:
var text = textarea.text();
Create a temporary div:
var div = $('<div id="temp"></div>');
Set the temp div's width to be the same as the textarea. Very important else the text will be all on one line in the new temp div!:
div.css({
"width":"530px"
});
Insert the text into the new temp div:
div.text(text);
Append it to the DOM:
$('body').append(div);
Get the height of the div:
var divHeight = $('#temp').height();
Remove the temp div from the DOM:
div.remove();
Had a similar issue, in my case I wanted to have an expand button, that would toggle between two states (expanded/collapsed). After searching also for hours I finally came up with this solution:
Use the .prop to get the content height - works with dynamically filled textareas and then on a load command set it to your textarea.
Get the inner height:
var innerHeight = $('#MyTextarea').prop('scrollHeight');
Set it to your element
$('#MyTextarea').height(innerHeight);
Complete code with my expand button(I had min-height set on my textarea):
$(document).on("click", '.expand-textarea', function () {
$(this).toggleClass('Expanded');
if($(this).hasClass('Expanded'))
$($(this).data('target')).height(1);
else
$($(this).data('target')).height($($(this).data('target')).prop('scrollHeight'));
});
Modern answer: textarea sizing is a few lines of ES6 implementable two primary ways. It does not require (or benefit from) jQuery, nor does it require duplication of the content being sized.
As this is most often required to implement the functionality of auto-sizing, the code given below implements this feature. If your modal dialog containing the text area is not artificially constrained, but can adapt to the inner content size, this can be a perfect solution. E.g. don't specify the modal body's height and remove overflow-y directives. (Then no JS will be required to adjust the modal height at all.)
See the final section for additional details if you really, truly only actually need to fetch the height, not adapt the height of the textarea itself.
Line–Based
Pro: almost trivial. Pro: exploits existing user-agent behavior which does the heavy lifting (font metric calculations) for you. Con: impossible to animate. Con: extended to support constraints as per my codepen used to explore this problem, constraints are encoded into the HTML, not part of the CSS, as data attributes.
/* Lines must not wrap using this technique. */
textarea { overflow-x: auto; white-space: nowrap; resize: none }
for ( let elem of document.getElementsByTagName('textarea') ) {
// Prevent "jagged flashes" as lines are added.
elem.addEventListener('keydown', e => if ( e.which === 13 ) e.target.rows = e.target.rows + 1)
// React to the finalization of keyboard entry.
elem.addEventListener('keyup', e => e.target.rows = (elem.value.match(/\n/g) || "").length + 1)
}
Scrollable Region–Based
Pro: still almost trivial. Pro: animatable in CSS (i.e. using transition), though with some mild difficulty relating to collapsing back down. Pro: constraints defined in CSS through min-height and max-height. Con: unless carefully calculated, constraints may crop lines.
for ( let elem of document.getElementsByTagName('textarea') )
elem.addEventListener('keyup', e => {
e.target.style.height = 0 // SEE NOTE
e.target.style.height = e.target.scrollHeight + 'px'
})
A shocking percentage of the search results utilizing scrollHeight never consider the case of reducing size; for details, see below. Or they utilize events "in the wrong order" resulting in an apparent delay between entry and update, e.g. pressing enter… then any other key in order to update. Example.
Solution to Initial Question
The initial question specifically related to fetching the height of a textarea. The second approach to auto-sizing, there, demonstrates the solution to that specific question in relation to the actual content. scrollHeight contains the height of the element regardless of constraint, e.g. its inner content size.
Note: scrollHeight is technically the Math.max() of the element's outer height or the inner height, whichever is larger. Thus the initial assignment of zero height. Without this, the textarea would expand, but never collapse. Initial assignment of zero ensures you retrieve the actual inner content height. For sampling without alteration, remove the height override (assign '') or preserve (prior to) then restore after retrieval of scrolllHeight.
To calculate just the height of the element as-is, utilize getComputedStyle and parse the result:
parseInt(getComputedStyle(elem).height, 10)
But really, please consider just adjusting the CSS to permit the modal to expand naturally rather than involving JavaScript at all.
Place this BEFORE any HTML elements.
<script src="/path/to/jquery.js"></script>
<script>
$(document).ready(function(){
var textarea = $('#history');
alert(textarea.height()); //returns correct height
});
</script>
You obviously do not have to alert it. I was just using an easily visible example.
Given a textarea with an id of "history", this jQuery will return it's height:
$('#history').height()
Please see a working example at http://jsfiddle.net/jhfrench/JcGGR/
You can also retrieve the height in pixels by using $('#history').css('height'); if you're not planning on doing any calculations.
for current height in px:
height = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('height')
for current width in px:
width = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('width')
change 'textarea' to '#history' or like a css selector. or textarea, since a variable is declared to select element.

Get real width of elements with jQuery

I am writing a validator for "visual correctness" of html files. The goal is to detect too wide elements.
Here is a demo of my problem.
The dotted red line is an indicator of the max width of the document (200px in this example). The first paragraph is fine, but the second is too wide. Nevertheless, all of the following commands still return "200px" as the width:
// all return 200, but the value should be larger
$('#two').width();
$('#two').outerWidth();
$('#two').prop('clientWidth');
Please see the Fiddle for more details.
How can i detect such oversized elements?
Updated question: Better to ask, how can i detect text that exceeds the borders of their parent elements?
Updated requirement: I am not allowed to change anything in the source HTML or CSS. But i can do anything i want with jQuery to modify the document, so that i can detect those too wide elements.
As others have said, temporarily wrap the text node in an inline element.
var two = document.getElementById('two'),
text = two.firstChild,
wrapper = document.createElement('span');
// wrap it up
wrapper.appendChild(text);
two.appendChild(wrapper);
// better than bad, it's good.
console.log(wrapper.offsetWidth);
// put it back the way it was.
two.removeChild(wrapper);
two.appendChild(text);
http://jsfiddle.net/vv68y/12/
Here is a getInnerWidth function that should be useful to you. Pass it an element and it will handle the wrapping and unwrapping.
function getInnerWidth(element) {
var wrapper = document.createElement('span'),
result;
while (element.firstChild) {
wrapper.appendChild(element.firstChild);
}
element.appendChild(wrapper);
result = wrapper.offsetWidth;
element.removeChild(wrapper);
while (wrapper.firstChild) {
element.appendChild(wrapper.firstChild);
}
return result;
}
http://jsfiddle.net/vv68y/13/
scrollWidth will do it:
$("#two").get()[0].scrollWidth
or
getElementById("two").scrollWidth
this outputs 212px, the real width you are looking for.
This effect is called "shrinkwrapping", and there's a couple of ways to determine the "real" width of the element.
Float
One of the ways that you can use is to float your <p> element which will force it as small as possible, but you'll need to use a clearfix if anything inside your div is floating:
#two { float: left; }
Inline-block element
Inserting an inline element should work.
<p>content</p>
would become
<p><span>content</span></p>
Absolutely positioned element
Changing the element position to be absolute should also work:
#two { position: absolute; }
If you can't statically change the markup or the style, you can always change them dynamically through JavaScript.
(absolutely positioned element)
var realWidth = $("#two").css("position", "absolute").width();
(float)
var realWidth = $("#two").css("float", "left").width();
(inline-block element)
var t = $("#two").html();
var realWidth = $("#two")
.empty()
.append($("<span>").html(t))
.width();
Apply word-wrap: break-word; to it.. so the word will break and there won't be any text going out of the container... btw you can't check the width of the text which is going out of the container.
Example
Update: You can check if the width of text in it is bigger than the width of the container like this
As others have pointed out, changing the position of the element to absolute also works.
Doing this will result in an inline-style which can mess with your css afterwards if you don't watch out. Here is a solution to get rid of the inline style again.
//Change position to absolute
$('#two').css("position", "absolute");
var textWidth = $('#two').width();
//Get rid of the inline style again
$('#two').removeStyle("position");
//Plugin format
(function ($) {
$.fn.removeStyle = function (style) {
var search = new RegExp(style + '[^;]+;?', 'g');
return this.each(function () {
$(this).attr('style', function (i, style) {
return style.replace(search, '');
});
});
};
}(jQuery));
The element itself is constrained to 200px, but the text inside spills out. If you insert a span (or any other inline element) inside the P tag it works fine.
http://jsfiddle.net/will/vv68y/5/
Hope that helps :)

How to split html to full-screen height pages?

I need to split some html content to pages, so that each page would have height of the screen and some predefined width. Page split can happen in the middle of paragraph (or probably some other html element), so this situation should be handled somehow.
What I really want to achieve is the effect of reading the book, page by page. I assume there will be a need for some javascript, so I'd prefer to to this with jQuery, but if other framework is required, it's also okay.
I have to admit that I'm quite new to HTML and all, so sorry if my guess is stupid, but currently I'm considering the following approach: measure actual height of the visible area (need to figure out how yet), then take my html document and incrementally take tag after tag, put this into invisible div and calculate its resulting height. When I'll have its height more than page height, I'm done. However, this approach will not work in case of long tags, e.g. long paragraph.
Thanks in advance.
EDIT: thanks for your previous answers. I tried to use approach of manual calculating the size of the elements, and encountered one problem which I cannot solve in a good way. This is problem of collapsing margins. What I'm trying to do is to loop through all the paragraphs in my document and sum up results of .outerHeight(true) jQuery call. This should give me the full height of element, including padding, margin and border. And it actually does what it says, but the problem here is that it doesn't take collapsing margins into account. Because of that I end up with wrong overall size (bigger than real one), because browser throws away some of margins (of adjacent paragraphs in my case), but I take them into account.
Any ideas how to solve this other than introducing the algorithm deciding which margins are collapsed and which are not? I think it is ugly...
You could use CSS3 multi-column rules, example: http://www.quirksmode.org/css/multicolumn.html
Or for support in all browsers use a javascript plugin: http://welcome.totheinter.net/columnizer-jquery-plugin/
This plugin even has a multi-page multi-column example: http://welcome.totheinter.net/2009/06/18/dynamic-multi-page-multi-column-newsletter-layout-with-columnizer/
I can think of one framework which seems to do what you need (and a bit more): https://github.com/Treesaver/treesaver
jQuery will give you the height (in pixels) of an element with the height() function.
jQuery("BODY").height() will give you the maximum height of the view port (though only if your content height is >= the height of the BODY - otherwise it will give you the height of how much space the body is taking up in the view port.)
Counting the heights of the P tags (or other tags) seems like a good way to go. I suppose if you want to break up the content of a P tag for large paragraphs, you could define a maximum "breakage" height for the last P tag on a page. You can then break rest of the contents of the P tag by creating a new P tag with jQuery("#the-next-page-id).append(jQuery("<P>"+restOfTheParagraphContent+"</P>"))
Use your own logic to calculate the height of each element in the html body
using jQuery code
$('selector').height();
Using this, you can calculate the height of some html elements and decide how much
elements should be displayed on your device screen.
for more, please visit jQuery Height Documentation
In case anyone still looking for something like this I recently did it using JQuery. It also leaves the first page empty (for title and such):
https://jsfiddle.net/xs31xzvt/
It basically iterates over the movable items and insert them into a new div if the previous div is full.
(function($) {
$(document).ready(formatPages)
function formatPages() {
var container = $('.container');
var subPage = $('.subpage').get(0);
var subPageHeight = subPage.offsetHeight;
var subPageScrollHeight = subPage.scrollHeight;
// See how many pages we'll need
var pages = Math.floor(subPageScrollHeight / subPageHeight) + 1;
//add a new page
var pageCount = 2;
var pageDiv = createPageDiv(pageCount);
var subPageDiv = createSubPageDiv(pageCount);
var addPage = function (){
pageCount++;
pageDiv = createPageDiv(pageCount);
subPageDiv = createSubPageDiv(pageCount);
pageDiv.append(subPageDiv);
container.append(pageDiv);
pageContentHeight = 0;
}
addPage()
container.append(pageDiv);
$('.movable').each(function() {
var element = $(this);
//remove the element
element.detach();
//try to add the element to the current page
if (pageContentHeight + element.get(0).offsetHeight > subPageHeight) {
subPageDiv.append(getFooterDiv().show());
//add a new page
addPage();
}
subPageDiv.append(element);
pageContentHeight += element.get(0).offsetHeight;
});
}
function createPageDiv(pageNum) {
return $('<div/>', {
class: 'page',
id: 'page' + pageNum
});
}
function createSubPageDiv(pageNum) {
return $('<div/>', {
class: 'subpage',
id: 'subpage' + pageNum
});
}
function getFooterDiv() {
return $('.footer').first().clone();
}
}(jQuery));

Javascript: detect textarea to be full

I am trying detect when a textarea becomes full for creating pagination effect. Using the .length property will not work, however, because long words 'jump' to new lines.
| I like to dooo| displays as | I like to |
| oooodle | | dooooooodle |
So what ends up happening is that the textarea always runs out of space before the .length property reaches the textarea limit. Is there any other way to detect textarea fullness? Jquery solutions are fine as well. Thanks.
You can try to check if scrollbars have appeared in your textarea. Here is a simple way to do this. Initially make the scrollbar one line shorter than the ultimate height you want to show, then on keypress check if scrollbars have appeared, then wait for the next space char to be entered. As soon as space char is entered do the following:
1. delete the space char,
2. increase the textarea height one line linger (so scrollbar disappears),
3. create a new textarea and move focus to the new textarea.
Update
Here is a demo. I changed my method a bit and this is the code:
Markup
<textarea class="paginate"></textarea>
JS
$('textarea.paginate').live('keydown', function() {
// scrollbars apreared
if (this.clientHeight < this.scrollHeight) {
var words = $(this).val().split(' ');
var last_word = words.pop();
var reduced = words.join(' ');
$(this).val(reduced);
$(this).css('height', '65px');
$(this).after('<textarea class="paginate"></textarea>');
$(this).next().focus().val(last_word);
}
});
CSS
.paginate { height: 60px; width: 200px; display: block;}
In runtime, you may listen to the key-press event of the textarea, pass the textarea.val() value into a hidden <pre id="mypre" style="display:none; "></pre>, then get mypre's width or even height $("#mypre").width(). It's your decision how you'll work with the "simulated" width/height.

Categories