React Native: How to keep multi-line textinput visible above keyboard - javascript

I have a TextInput with multiline set to true.
I am scrolling to the input on focus with:
scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
React.findNodeHandle(this.refs.myInput),
0,
true
);
However when the multiline TextInput expands the text will be hidden beneath the keyboard.
I only want to scroll down when the cursor/current text is not visible. So I can't just run the code above on text change as it would scroll the view even if the current cursor/current text is visible (like editing on the first line).
Is there any way to get the cursor/current text position on screen?
Or is there any other way to do what I'm trying to?
Currently:
What I'm trying to achieve:

You may use the onLayout method, provided by the View (which Text extends). It returns the dimensions of the view, which you may use to recalculate the scroll position of your scrollview.

The best way to do it seems to be with the react-native-keyboard-aware-scroll-view library and use the method _scrollToInput and follow what the docs say.
The one thing I had to change was to call "this.scroll.props.scrollToFocusedInput(reactNode)" instead of "this.scroll.scrollToFocusedInput(reactNode)" in the docs!

I found this component... but it's not working for me (I get errors on "import"). I assume that they will get fixed eventually.
https://github.com/VansonLeung/react-native-keyboard-aware-view

Related

How to shift Vuetify component ```VDatePicker``` according to the position of its parent component on the screen

I am using VMenu component from vuetify and inside it is another vuetify component VDatePicker. The functionality is such that when I click a text field, the calender(VDatePicker) is seen. The VDatePicker component appears normally always under the text field, provided there is enough space under the field until the end of the screen.
But now the problem is that the text field is positioned such that there is little space between it and the end of the screen, so the DatePicker tries to adjest itself and pushes itself a little above and hence it hides the field underneath (snap shot attached).
The question is that How can I shift it such that when such a case occurs where there is little space between field and end of screen then it should position itself at the top of the filed and not on it.
I assume you want to shift it to the side?
You can use nude-right="300px" in the v-menuto nudge the Datepicker 300px to the right
Sample:
https://codepen.io/j3n50m4t/pen/xxZzVLG

Make Input Suggestion Controls move with Input

Hopefully, that title makes sense to what's occurring.
I have a CodeSandox here for you all to have a look.
I have a div that gets hidden when a user focuses on an input.
When this occurs (for me at least), The input goes to the top of the parent div and but the browser suggested input element (in this case, email address) sticks to where the element used to be.
Is it possible to adjust the suggestion element in any way so that it follows the position of the input?
CSS:
Put input and suggestion box in container, then set position of suggestion box relatively or absolutely to container.
JS:
Calculate position of input then set position of suggestion box using that data.

Can't get css("left") of Stack Exchange help drop down - returns auto, wanted in px

I want to get left property of Stack Exchange help drop down which has class .help-dialog, but it always returns auto, and I'd like to see it in px.
To avoid complicated explanations, just execute this in your address bar after any SE site is loaded:
javascript:alert($(".help-dialog").css("left"))
You'll get auto in the alert. How to solve it?
I have already seen this question, but second and third suggestions don't appear to work, other ones are inapplicable.
It returns auto because the element is not visible after page load, see:
$('.help-dialog').is(':visible')
The help menu is initialized on click and that's when the left attribute is set. Click on it after page load and try again:
$('.help-dialog').css('left'))
To solve this, use:
$('a.js-help-button').click();
var left=$('.help-dialog').css('left');
$('a.js-help-button').click();
alert(left);
This returns 840.5 on my screen at https://meta.stackexchange.com/.
javascript:$('.help-dialog').show();var left=$(".help-dialog").offset().left;$('.help-dialog').hide(); alert(left)
Try position method instead of css method,
$('a.js-help-button').click();
$(".help-dialog").position();
.help-dialog is hidden, try to make it visible by clicking on it. and then get its position . You will get its top and left in px
Did you try this?
$('.help-dialog')[0].offsetLeft;

RSpec and Capybara: How to get the horizontal and vertical position of an element

I have added visually hidden jump links to my website, that appear when they are focused (similar to e.g. GitHub, just press Tab once on the home page).
I want to test this behaviour with Capybara. I can't check for e.g. 'visibility: true/false', because the links are not really hidden (otherwise screenreaders would't see them), but only moved out from the viewport by absolute positioning. When they are focused, they are placed at their original position in the viewport.
So I guess I have to check the X and Y coordinate, but Capybara doesn't seem to offer a native method for getting them? Is this true? And if so, how would I get them for e.g. an element '#jump_to_content'? By executing some JavaScript?
Update
I found some inspiration here: https://content.pivotal.io/blog/testing-accessibility-with-rspec-and-capybara
But this doesn't seem to work for my configration:
link.native.location
NoMethodError: undefined method `location' for #<Capybara::Poltergeist::Node tag="a">
You are correct, Capybara does not offer a native method for getting an element's position in the page, but if you have access to jQuery you can use Capybara's page.evaluate_script method to easily determine an element's position. It would look something like this:
page.evaluate_script("$('.menu > div:nth-child(1)').offset().top")
The .offset() method allows us to retrieve the current position of an element relative to the document. Contrast this with .position(), which retrieves the current position relative to the offset parent
Just note that
While it is possible to get the coordinates of elements with visibility:hidden set, display:none is excluded from the rendering tree and thus has a position that is undefined.
Using capybara's page.evaluate_script will allow you to execute some JavaScript and create an assertion off the return value:
expect(page.evaluate_script("document.querySelectorAll('a#jump-to-content')[0].style.top;")).to eq('-8000px')
According to this SO answer, the best way to use JavaScript to find the position of an element is to use getBoundingClientRect(); as it returns values that are relative to the viewport.
It feels more readable to me to find the element with Capybara instead of JavaScript, and then find its position. I'm using Selenium and Chrome.
link = find("a", text: "content")
link.evaluate_script("this.getBoundingClientRect().left;")
link.evaluate_script("this.getBoundingClientRect().right;")
link.evaluate_script("this.getBoundingClientRect().top;")
link.evaluate_script("this.getBoundingClientRect().bottom;")
Some browsers (like Chrome) also have:
link.evaluate_script("this.getBoundingClientRect().x;")
link.evaluate_script("this.getBoundingClientRect().y;")
link.evaluate_script("this.getBoundingClientRect().height;")
link.evaluate_script("this.getBoundingClientRect().width;")
You can also do
link.rect.y
link.rect.height
link.rect.x
link.rect.width
As per Nuri's answer, the best way you can go is asking the browser directly(headless browsers don't read css files, afaik).
However, rather than asking the style of the element, you might want to directly check its position by using offsetTop. So something like
expect(page.evaluate_script("document.querySelector('a#jump-to-content').offsetTop;")).to eq('-8000px')
If you need more control, you could also run it all in javascript:
expect(page.evaluate_script("document.querySelector('a#jump-to-content').offsetTop < document.querySelector('body').offsetTop;").to be_true

TinyMCE limit text on scrollerActived

I have a textarea in my rails application to collect content from user in a database. The rails application is further feeding that text to an XML-driven flex application.
The flex application has number of fixed sized containers which wraps the text inside (from the XML created by Rails app on-the-fly), but truncates the text if it exceeds the container's height. Problem is; there is no way to present the large text in XML, so it gets adjusted automatically in the compiled flex application. And the fact is; the web-based rails app and front-tier flex app are entirely disconnected in terms of having awareness of their internal events. (like in this case; rails app has no knowledge of the overflow event for flex internal containers and relying on font-size and character/line count doesn't work in this scenario!)
Therefore, I wrote a JS function to watch and rescue the textarea's overflow situation and while setting its attributes (viz; line-height, font-size, font-family, width, height... yada yada) matching that of the flex control. The complex form in rails did the trick to have dynamic number of such textarea's control being observed by the JS function.
Here is the Prototype code to handle the overflow event with the corresponding rescue code for cleanup:
var timeout;
document.observe('dom:loaded', attach_obr);
function attach_obr() {
$$('.active_text').each (function(text_element){
text_element.observe('keyup', function(e){
check_limits(text_element.id);
});
text_element.observe('change', function(e){
check_limits(text_element.id);
});
});
}
function check_limits(eyeD) {
if($(eyeD).scrollHeight > $(eyeD).offsetHeight){
// overflow occured, now the rescue code here
timeout = window.setTimeout(function() {
$("error_notice").hide();
}, 4000);
$("error_notice").show().update('There is no space left in this box, please use a new box to continue adding content');
// truncate text till the scrollbar disappears
while($(eyeD).scrollHeight > $(eyeD).offsetHeight){
$(eyeD).value = $(eyeD).value.slice(0, -1);
}
}
else {
if($("error_notice").innerHTML!=""){
$("error_notice").hide().update("");
clearTime(timeout);
}
}
}
[Note: It works with a minor flaw of truncating few more characters than expected in the last line. User can retype these letters till the end of that line. I guess this is because somehow the change in width of textarea due to the appearance of scroll-bar is effecting either the scrollHeight or offsetHeight during the process & there should be something more to the loop's condition ($(eyeD).scrollHeight > $(eyeD).offsetHeight)]
The while loop makes things bit slower, but at least it is serving the purpose. WYSIWYG is achieved. (I would love to hear any suggestion from the viewers to improve that inelegant code :O )
WYSIWYG is not achieved, in terms of rich/formatted text..
Incorporating Rich Text:
Rather than expecting from user to place tags inside the area , in the next phase, I am planning to deploy tinyMCE in my app. Now, to make the above function work with tinyMCE, I have the following code:
tinyMCE.init({
theme_advanced_buttons1 : "bold, italic, underline, strikethrough, separator, justifyleft, justifycenter, justifyright, justifyfull, separator, forecolor, backcolor",
theme:"advanced",
mode:"textareas",
plugins : "safari",
width: '360px',
height: '198px',
setup : function(ed) {
ed.onChange.add(function(ed, i) {
check_limits(ed.id);
});
}
});
The binding and firing of events is working alright. Unfortunately, the aim to control the text overflow is not working. Reason being;
a) ed.id is the id of my textarea not the interactive panel created by tinyMCE. So, the attributes like scrollHeight are offsetHeight are not getting changed for the hidden textarea control.
b) The value of textarea in this case also contains HTML code rather than the actual text. So, it is very implicit to tell what is the actual text without markup (which in our case is required when truncating the overflowed text).
My questions:
Is there a way to get the scrollHeight and offsetHeight of the control created by tinyMCE?
Is there a way to get the only-text version (without markup) of inner content of tinyMCE control?
(So, when I truncate the text in check_limits function, it doesn't effect/breaks the markup/DOM created by tinyMCE for the formatted text. In other words, I would be simulating the user action of pressing backspace on tinyMCE control in the while loop.)
Elegant way to do this whole exercise with & without tinyMCE?
Any suggestions are greatly appreciated!
First you need to know that tinymce creates a contenteditable iframe to let users edit html contents; contents from that iframe get written back to the textarea onSave. The textarea gets hidden in the rtinymce intiatilization process. The editor id is equal to the textarea id.
Here some suggestions:
1. Relevant code
var frameid = editor.id+'_ifr';
var currentiframe = document.getElementById(frameid);
var offsetHeight = currentiframe .contentDocument.body.offsetHeight;
var scrollHeight = currentfr.Document.body.scrollHeight
2. code for this (using jQuery)
var plain_text = $(editor.getBody()).text();
3. The only more efficient way to handle the while loop in the "without tinymce" case will be to slice off some more characters and follow a logarithmic approach. You slice off a bigger part of the string and then get to the final value in half-part paces. Example: You slice of 20 characters, but it fits. Then you slice off 10 characters of the original string. If it does not fit you try 15 characters and so on... this is more effectife then the while approach, but more complicated to develop.
EDIT:
It seems almost impossible to get the line number from the caret position. Problem here is that you do not know where the a text line breaks. Though it is easy to find out in which paragraph the cursor is located at (tinymce uses paragraphs to wrap text nodes).
There is a way to limit insertion in tinymce based on characters (i.e. limit can be set to 100 characters), but i guess this won't work for your use case unless you use a monospace font.
Another approach could be to set the tinymce css to set the editor window to the exact same width as your flex boxes (set the widht to the iframes body element should be sufficient). In this case it sould be easier to use the scrollHeigth approach - you would only need to find out if the heigth did change after insertion of text and then you could divied the heigth with the lineheigth to egt the line number. I suggest you write an own plugin to implement this. This is not that difficult. Here is a link to a tutorial for this.

Categories