Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Only set white-space on mirrored div for textareas #52

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

schinizel
Copy link

@schinizel schinizel commented Feb 18, 2019

This addresses an issue with incorrect top coordinates being returned in cases where the mirrored div wraps hyphenated text.

See issue #51 for context. By only applying the white-space property to textarea and not input it allows people to set a white-space: nowrap on the element if we need it. I debated setting it explicitly (since inputs never wrap) but it seemed better to simply allow people to control the property on their own.

@anotherCoward
Copy link

A white-space: nowrap would collapse spaces, but this won't happen on input fields. Try:

<input type="text" style="white-space: nowrap" value="     ">

It will always display 5 spaces, no matter of the white-space-property.

The pre is required as the mirror would otherwise use 'normal' and with a white-space: normal it may ignore multiple spaces and so on. With white-space: pre it won't break at all and will handle multiple spaces correctly for input fields.

This should be added after the style-prop-loop:

if (isInput) // force pre instead of pre-wrap on the input mirror
  style.whiteSpace = 'pre';

Greetings

@schinizel
Copy link
Author

@anotherCoward good call. Updated and pushed.

@anotherCoward
Copy link

I changed a lot more, at the time i required this snippet. Test around here http://jsfiddle.net/anotherCoward/sezkrm2c/
(I removed almost any comment and commented only the changes i did)

Added some options, like getting the absolute/relative position and support for almost any text-element (like contenteditable="true" or any text that could be selected).

Changes

  • Added contenteditable support (for contenteditable="true" and contenteditable="plaintext-only")
  • Added input type="password" support. (masks the Mirror too)
  • Added relative-Scroll-Position (options.withScrolls = boolean)
  • Added viewport-related position detection. (options.absolute = boolean)
  • Added tabindex, iframe and canvas stuff. (options.checkTabIndex = boolean)
  • Changed font-family of the position-detection-span for textarea/input to monospace, a single dot is to small on fonts like serif/sans-serif, but only if there is no following text.
  • Reduced the size of the following-text to 1024 chars, this should be fine on most installments. (Could improve performance on extrem long textareas/inputs)
  • Added auto-position-detection, giving a position is no longer required (uses always the caret focus position)
    Still works as before, if set.
  • Added auto-element-detection, giving an element is no longer required (uses document.activeElement and calls itself)
    Still works as before, if set.
  • Added a "node" to the result, which returns the focused node.
    on textareas and inputs, it is the element itself, on contenteditable it is #text it most cases. Depending on selection.range
  • Added option: nextToParent = boolean (textarea/input only)
    The textarea/input-clone will be added to the same node as the textarea/input is to apply possible unknown css selectors
  • Added option: applyClass = 'string' (textarea/input only)
    if set, the cloned divs class will apply this string
  • Added a check if the element.isConnected to avoid calculations that are not possible at all (https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected)
  • Added style.all = 'unset' to the divs span and lineHeight = '1em' to get the correct caret-height, even if lineHeight = 'normal' (https://developer.mozilla.org/en-US/docs/Web/CSS/all)
    To avoid * { whatever } CSS-Rules.
  • Fixed the line-height NaN Bug on Chrome
  • Replaced the debug option with an options object.
  • Implemented a fallback for getComputedStyle(EL) to avoid the check everywhere.
  • Added some more style-Stuff that could hardly change the position
    overflowWrap, overflowAnchor, fontKerning, textRendering, textUnderlinePosition, writingMode, textAlignLast, -webkit-text-security, -webkit-text-emphasis-style, transform

Usage

getCaretCoordinates(element, position, options);

element [optional] HTMLElement

  • HTML Node Element that is connected to the root in any way
    Note: Fill in null, if you want to use the document.activeElement and detect the rest automatically

position [optional] number

Note: This value will be ignored on HTMLElements except input/textarea

  • number of index position to use, gets automatically detected if the element has focus
    Note: Fill in null, if you want to detect it automatically and apply options

options [optional] object

  • withScrolls boolean - returns the relative position depending on scroll inside the selected node
  • checkTabIndex boolean checks if tabindex of the given activeElement is set (required for certain divs to get the relative position to this div) otherwise it will fall back to body.
  • nextToParent boolean creates the clone on the same node as the textarea/input clone is.
  • applyClass string applys the given classes to the mirror (textarea/input only)
  • absolute boolean left and top values are relative to the viewport, ideal for nodes, that should be placed next to the caret. (position: fixed)
  • debug removed

Known Issues

  • There is an issue with the following text on textareas while editing like: |[new text]<span>loooooooooooooooooooooooooooooooooooooooooooooong word</span>
    It may be calculated for the next line, even if the caret is displayed at the line before.
  • There is a small issue in contenteditable="true" with html elements different to text, depending on the browser selection.
  • IE below 9 is not supported anymore, it is just to old. (anyway even Microsoft warns from using it https://techcommunity.microsoft.com/t5/Windows-IT-Pro-Blog/The-perils-of-using-Internet-Explorer-as-your-default-browser/ba-p/331732)
  • On content-editable stuff it always uses the next Sibling or Parent to detect the high, which could result in a wrong height value.
    image
    (the red line is the caret, it's hard to see on the image directly)

There might be some more issues and things i forgot to mention and i had a some trouble with Edge at that time (like no scrollLeft-values on Edges input elements) - but as Edge switched to Chromium Engine the checks for Edge could be removed.

Greetings

@schinizel
Copy link
Author

@anotherCoward sorry it has taken a while to respond to this. The changes you posted certainly resolve my issue and would make this PR unnecessary. Will these changes be published/committed any time soon?

@CodingDive
Copy link

@schinizel I think the changes live on their fork see https://github.com/anotherCoward/textarea-caret-position. I'm not sure if @anotherCoward has ever published their new version to npm though.

@anotherCoward
Copy link

anotherCoward commented Oct 24, 2019

I have never published it, but feel free to use it. If it helps. =)

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants