0

I'm building a custom input field in javascript. (i.e. not using content editable, input, textarea or iframes).

I need it to support the basic options in a textarea field e.g.:

  • Mouse click for cursor position
  • Selection
  • Copy/paste
    ...

At this point i'm listening for keypress on an underlying input field. When a key is pressed:
1. the value of the key String.fromCharCode(event.keyCode) is passed to a tmp span.
2. The width of the span is measured, and stored in an array.
3. the caret position is calculated using the array of sizes

This works more or less in chrome, but when using internet explorer 9, the caret seems to get out of position.

It seems the width of the container with a single container, does not match the width the that character has when it's inserted into a string.

I'm guessing this has something to do with how the size of the letter is calculated in step 2. But i can't quite figure out how to go about this problem.

Does anyone have experience with the issue or point me in the right direction with some litterature, blogs apis, anything? - that would be great!

edit: Here is a link to what i've got so far;

NB: works in chrome, and has the mentioned defect in ie: 9 and 10 it's broken in firefox :)

Tau Sand
  • 23
  • 3
  • Are you sure there's not other way to place a caret other than calculating its position? Why don't you write some code? How does your DOM look like, for example? – MaxArt Jul 04 '13 at 09:01
  • A link to some dirty code has been attached to the original post.' Which other ways of positioning the caret would you suggest – Tau Sand Jul 04 '13 at 10:17

1 Answers1

0

If you want to know the position of each character in the field you can try to get the width of the preceding substring:

var text = $content.text(),
    positions = [0],
    $ghost = $("<span class='ghost'>").appendTo($content);
for (var i = 1; i < text.length; i++) {
    $ghost.text(text.substring(0, i));
    positions.push($ghost.width());
}
$ghost.remove();

This is the CSS you need:

.ghost {
    visibility: hidden;
    position: absolute;
    bottom: 0;
    right: 0;
}

Keep in mind that each time you get the size of an element, it causes a document reflow. It shouldn't be a problem for an absolutely positioned element, though.

MaxArt
  • 22,200
  • 10
  • 82
  • 81
  • This does not answer the question, What i'm looking for is a way to determine the size of a character in ie. If i go for your solution i won't have the possibility for mouse interaction as i dont know where to place the caret on a click. – Tau Sand Jul 04 '13 at 12:27
  • @TauSand Don't expect a perfect answers if you don't post what you want to do in details. Just keep in mind that measuring a single character can't be precise because of rounding of floating point precision sizes. User interactions aren't easy to replicate at all. That's why web developers use `` fields or at most `contenteditable` elements. – MaxArt Jul 04 '13 at 16:05
  • Yea i see where you are going with the floating point. i tried adding several l's to a screen and found that four l's in a row requires one less pixel than just a single l. In chrome however the sizes are correct, perhaps because it has a int px for each char or perhaps because i got lucky with the size i used? is it possible to force the font's width to be an excact integer? perhaps using css? – Tau Sand Jul 05 '13 at 08:23
  • @TauSand Unfortunately no, that's totally controlled by the browser. The best thing you can do is to calculate the witch of whole substring starting from the beginning and not of single characters, to reduce the effect of approximations. I've changed my answers to illustrate the technique. – MaxArt Jul 05 '13 at 09:31
  • Thanks for the try, i gave it a shot at a real implementation, but it works poorly with more characters than 40. and kills the real time feeling. I know it can be done since the google team from google docs did it, i just wonder how. – Tau Sand Jul 07 '13 at 11:31
  • @TauSand Look, I don't know how you implemented the snippet above, so I don't know where the performance degrades. But in Google Docs every line has a span on its own, and each space has too, so the task is much simpler. But Google Docs is an immense project with years of work: are you really sure you want to replicate something similar, instead of relying in something much simpler like `contenteditable`? – MaxArt Jul 07 '13 at 18:36
  • How come that the task is simpler for google docs? they are facing the exact same issue when calculating the size of a char as i am. and that's where im stuck. i know they do it, since they made a blogpost about it. but they didn't go into details about implementation. if they are doing something way smarter than me in order of character size calculation theplease do elaborate. I implemented it more or less the way you described it, but to update the dom and calculate the width, 40 times, on a keypress is to much calculation, for it to run smoothly. – Tau Sand Jul 07 '13 at 20:30
  • @TauSand Do the calculation on the `click` event, not on the `keypress`. – MaxArt Jul 08 '13 at 09:09
  • Great idea, i'll have to try that. firsly i discarded the idea, do to mouse selection, but if i save the size calculations this issue should be avoided. I did however implement the it with a divide and conquer strategy to find the cursor position. giving a 0(6) iterations on a 200 char line (this works kinda neet), i'll try out your proposal later and see which gives the better result. – Tau Sand Jul 08 '13 at 09:52