Adding an absolute positioned element causes line break - javascript

So I have a "cursor" object created like so:
var cursor=document.createElement('span');
cursor.id="currentCursor";
cursor.innerHTML="|";
cursor.style.fontWeight="bold";
cursor.style.position = 'absolute';
cursor.style.marginLeft="-1px";
Then I add it to the page where someone clicks with this:
var selection = window.getSelection();
var currentRange = selection.getRangeAt(0);
currentRange.insertNode(cursor);
The problem I'm running into is in certain places (mainly end of lines) if the cursor object is added it creates a line break before the object. Using insertNode to move it to another area removes the line break. Also if I set the display to "none", wait for a few seconds and then set it back to "inline" the line break is removed.
This seems like maybe a browser bug in adding absolute elements, but I was wondering if someone had a workaround. I've tried setting the width to 0px but it has no effect.
Update
So if I change the cursor to
cursor.style.position = 'static';
It doesn't have random line breaks. However this causes space to be created around the element. Any way to not allow elements to create space around them?
Update 2
Added a fiddle to show the problem:
http://jsfiddle.net/Mctittles/pSg2D/1/
Original code is a bit large but I slimmed it down to highlight this problem.
If you click at the end of the smiley face and then type it causes line 33 to trigger creating a new text node. After typing a couple letters you'll see the cursor object is forced to the next line. Clicking somewhere else to move it makes the lines merge again.
If you un-comment lines 38 and 40 you'll see what I was talking about with making it initially display:none and changing it later. This time it doesn't cause a line break.
I took out some cross-browser code for fiddler, so this might only work in Chrome

However [position:static] causes space to be created around the element.
No, it doesn’t cause it – there is no actual space created “around it”, it’s just the display width of a character plus spacing in the used font, and that gives the span element itself a width that is more than the | character itself. But when you position the element absolutely, you don’t notice that, because it is taken out of the flow, so it doesn’t push the following characters to the right.
My workaround proposal: Don’t put | into the span as innerHTML, but leave it empty – and then implement the line by giving the element a border-left:1px solid. Remove position:absolute, so that it defaults to static.
Then you might probably not like the height your cursor is getting with that – but that can be fixed as well, by setting display to inline-block, and giving it a height as well.
Here, see how you like ’dem apples: http://jsfiddle.net/pSg2D/9/

You should use CSS instead. Using z-index and maybe even float would (atleast should) fix this.
Edit: Always make sure no other styles make it break line!

Related

Find location of line on screen

So I have HTML text being rendered in a browser (in this case an Android WebView). I want to find out what the (x,y) location in pixels of any given line of text is AFTER it is rendered. The working definition of line I am using is not just all the text contained in a <p> tag or that appears before a <br> tag. I mean a line as it would appear to the user.
I am open to any suggested method.
Is there any CSS property that you are able to find the number of lines in a div and their respective heights? That would provide a workable solution.
Thanks!!
You can't access a line individually. But, with some JavaScript, you can find the position of a line with a known index; here's a basic outline:
var p = document.getElementById("ptag"); //get the text container that contains your line
var nthline = 3; //the line for which you'd like to find the position
var lnheight = parseInt(window.getComputedStyle(p).lineHeight); //get the height of each line
var linepos = [p.offsetLeft, p.offsetTop + lnheight * (nthline - 1)]; //a [left, top] pair that represents the line's position
Note: This assumes the container doesn't have anything but text.
There is no standard way of doing that, you will have to refer to your imagination and invent some hack, right now I can think of two ideas for this:
Enclose each word within a span, like <span
class="word">word</span>, that could easily be done with regex or
string functions, later loop over each <span> reading its
position, add some calculation and you could find out how many
lines, where a line starts (word that incremented its top position
from last one) and when a line ends (last word of line + width of
that word).
Apply some style to first line using :first-line pseudoelement,
like
p:first-line{ background-color: white; /* same existent color so
no affecting display*/ }
later find in DOM what text that style was applied. This idea is not
as good and first one but maybe it can make you think of other ways.

How to have transparent fonts except for the 'text-caret' in a textarea?

I have a simple textarea and I need to make transparent letters while allowing the text-caret to be visible. When I apply the following rules then I get invisible caret:
textarea {
background: transparent;
opacity: 0;
}
When I type invisible text, I need to see the text-caret move.
EDIT: I need to make editor to edit td cell in table. When I click on a cell I show a textarea and start typing. On a each character letter, I insert a context in a cell. After that, I hide a textarea.
This jsFiddle DEMO uses an online tutorial method that has been slightly modified to create a non-native browser text-caret along with transparent text.
Also, this jsFiddle New Method I created handles that goal differently but isn't IE8 friendly.
Status Update: I've improved the above jsFiddle DEMO with this newer version titled:
jsFiddle New Method that's Newer!!
The above jsFiddle version now allows the inside of the text-area to be clicked and the caret will respect that clicked location. This extra functionality was made possible by a great question and answer here.
Time to throw my $0.02 in.
This is an answer to the question, as I understood it, that works, it's quick and dirty, so feel free to make suggestions. This code is untested, but I did create a working fiddle here: http://jsfiddle.net/66RXc/
<html>
<head>
<title>Testing</title>
<script type="text/javascript">
<!--
function call(val) {
document.getElementById('result').value += val.charAt(val.length - 1);
document.getElementById('result').value =
document.getElementById('result').value.substr(0, val.length);
document.getElementById('test').value =
document.getElementById('test').value.replace(/[^\^]/g, ' ');
}​
-->
</script>
</head>
<body>
<textarea name="textarea" cols="20" rows="5" id="test"
onKeyUp="call(this.value);"></textarea>
<textarea style="display:block" cols="20" rows="5" id="result" disabled>
</textarea>​
</body>
</html>
The way I approached it was every time a character is typed in textarea "test", copy it over to a hidden text box, and replace all the characters in "test" except ^ with spaces. The characters are hidden, and the carat is still there. The full text is still in the other box. You could use display:hidden instead of display:block to hide it.
This isn't exactly the best implementation in the world, just something I did quickly. You have to type kind of slow (~15-20 WPM) for it to work.
Here is a CSS3 solution for making the text, itself, transparent:
Set the color attribute to be color: rgba(0,0,0,0); for the text
The only problem is that the caret goes invisible to. I did a quick search and found out that the caret and its styling are completely at the disposal of the browser. As such, the only option that I can think of for you is to use Javascript to add a simulated caret to the end of what you are typing.
I have an idea of how to do this, but it's messy and I wouldn't exactly call it ideal - I am, however, going to write it in case it helps further someone else's idea:
add a hidden label to the page
make sure it's hidden and not display: none; (so that it has actual width)
set white-space: nowrap; to keep it all on one line)
make sure the text is styled exactly the same as the text in the textarea
add the element <span id="caret">|</span> right before the textarea (I will refer to this as the caret for the rest of the spec)
set its position to position: relative;
increase its z-index to make it overlay
shift it right in order to set it on top of where the ACTUAL caret's initial position would be
make a function to check take in the value of the textarea and check the width of the textarea against the position of the caret (lookup selectionStart if you don't know how to do this)
the problem here is that characters are not always the same length, nor are they always the same length as their counterparts in other fonts
to solve this, as text is entered into the textarea you should have it imitated in the hidden label you created in step 1
imitate only the text from the start of the textarea to the caret's current position
wrap each character (including spaces) in their own span
next you will have to call a function to compare the width of the label with the width of the textarea
if the label is less wide than the textarea, get the width of the last span in the hidden label and shift the caret to the right by that width, then move on to step 4
as this is function will be run as text is entered it will happen one character at a time
be careful here that the caret doesn't go outside the textarea when it's in its last and near last positions
if the label is wider than the textarea:
add the widths of the characters (spans) in the label one at a time until you reach the width of the textarea
shift the position of the caret down by the height of the font and back to the horizontal starting position (as the caret's position is relative, just change its left position back to (0 + offsetToACTUALCaretPosition)
use a flag (e.g. class="break") to mark the last span (character) in the previous row
call the width comparison function again
make sure that you include a condition to check for the flags that you added at the end of each "row" (if any)
if you haven't already, apply any desired CSS styles to the caret span and change the color of the textarea's text to be color: rgba(0,0,0,0);
Caveats:
this will have a lot of overhead for the tiny job it does
you will have to adjust this method to account for padding
you will have to adjust this method to add support for deleting characters and moving the carets to an earlier position (to the left)
if you leave the textarea scrollable, you will have to add support for that (also for similar settings, like static heights causing text to scroll or move off screen/out of the textarea's visible area)
As I said before, I know that this solution is very rough, but it may help someone come up with a better one.
Good luck!
Based on your edit, if you need to just hide a textarea why don't you use jQuery $('#your_id').hide();

What characters will a TextArea wrap at, other than spaces?

I'm working on the latest version of my plugin, Textarea Line Counter (http://mostthingsweb.com/?p=84). To make it even more accurate, I want to identify regions of text that wrap because they are too large to fit on the line (like a sequence of repeated characters).
I'm assuming that browsers only wrap text at spaces. Are there any other characters that lines can be wrapped at? Thank you,
Looks like it depends on the browser, my Opera wraps also on e.g. + % ? $ / ( [ { } \ ° ! ¿
Safari/Chrome on ¿ ? too
(guess there are lots more)
Nice idea for a plugin. Fighting the accuracy issues is going to be a challenge.
There's not a universal catch all for the way textarea is going to handle a string (other than line breaks at spaces), or using word-wrap.
IE produced a break with . , () {} ?, but not with / * = +
In this example, textarea seems to have that "special" feeling like a td
Based on all your advice, I have created a solution. It is rather large, and in fact I think I will make it into a separate plugin, as well as including it in my Textarea Line Counter. It works like this:
Create a div to act as a container, and set the font to something monospaced (i.e. every character is the same width)
Create a span within the container, and place a single letter.
Take the width measurement of the span (which will be the width of the letter, once margins, padding, and some other CSS attributes are cloned)
Create another div within the container and clone its CSS attributes. Set it's width to be two times the width of the letter found in step 3, and record its height.
To test if a character will cause a wrap, set the text of the div to: A[some character]A. [some character] is a character you are trying to test.
Test the height of the div. If it is larger than the height found in step 4, the text has wrapped.
I'm looking forward to releasing this plugin. Thank you again for all your advice.
some browsers will break inside words if the word is longer than the col width,
otherwise they break on spaces.
I notice some browsers set this by default- you can, too in most bowsers with:
textarea{word-wrap: break-word}
you can be sure it is not set by using textarea{word-wrap: normal}

Scroll an input box to the cursor position in javascript

I've written a simple JS function that places the cursor at the end of the contents of an input box when it receives focus (the most common action in the box being to append). I haven't checked in IE, but when there is more text than is visible, even moving the cursor to the end of input doesn't scroll the view to the end of input in firefox 3.6.
Any idea how to do this?
P.S. And no I'm not using JQuery, nor is it an option ;)
Found a solution here using different wording (caret instead of cursor)
You can scroll by assigning to the textarea's scrollTop property:
// scroll to bottom
elt.scrollTop = elt.scrollHeight;
Firefox and Safari also offer scrollByLines, and IE has doScroll, but the scrollTop property is cross-browser and simpler to use.
Personally, I don't like it when the cursor is moved for me to the end of a textarea. If I want it at the end, it takes a fraction of a second to do it my self. It takes around a second to move the cursor from the end to somewhere in the middle (the end is a larger target, thus takes less time to hit). Unless the textarea has a special purpose, I wouldn't bother with the append-on-focus function.

JavaScript: Check width of a <div> object before placing it

Consider:
$("#PlotPlace").append('<div style="position:absolute;left:200px;top:40px;font-size:smaller">Hello world!</div>');
I need to execute that line only if the width of the resultant text would be less than 60px. How can I check the width before placing the object?
Unfortunately, the div will only have a width value once it is rendered into the DOM.
I would append that content to an inconspicuous area of the document, perhaps even absolutely positioned so that no flow disruption occurs, and make sure that it is set to "visibility:hidden". That way it will be inserted into the DOM and be rendered, but be invisible to the viewer.
You can then check the width on it, and move it into position and set it to "visibility:visible" at that point. Otherwise, you can remove it from the document.
Maybe you can append it invisible, then check it's width, and then consider to show or hide.
$("#PlotPlace").append('<div style="position:absolute;left:9001px;top:40px;font-size:smaller">Hello world!</div>');
var div = $('#PlotPlace').children("div");
if(div.width() < 60)
div.css({left:200})
Sounds like something you'd have to hack. I don't believe the JavaScript runtime in any browser has an event you can hook into in between calculating the layout and displaying the element, so you can add it in a way that it can't be seen and doesn't affect the height (doesn't cause additional scrolling), and then show/hide it based on the width at this point. It's hacky and ugly, but because you don't have many event hooks it might be the only way to do it.
You can´t. At least not so easy. The text you insert is written in a specific font, which must be rendered by the browser, then you know the width of the element. By the Way, what exactly do you want to insert, with such a restriction? Wouldn´t it be simpler to cut the text within the output parameters?

Categories

Resources