Skip to content
New issue

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

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

Already on GitHub? Sign in 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. =)

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

Successfully merging this pull request may close these issues.

None yet

3 participants