On input click, keep input field visible when virtual keyboard - javascript

I got a challange here and would like to get some help from your experience.
This app has floating (sticky) header (where you see store details and the tabs with Details and Contacts) and also a floating (sticky) bottom bar and the content scrolls behind them.
When a user clicks on an input field the virtual keyboard shows up.
The problem is, when the virtual keyboard shows up, if the input field is in a place where the bottom bar will stay, the input stays covered by the bottom bar.
For example the city field was near the center and the user clicked it, the virtual keyboard is shown and the input field for city is covered by the floating bottom bar.
The expected result was that the city field should be placed right above the BottomBar.
I am using window resize event to detect when the keyboard shows up. I am also using a document.querySelector(":focus") to detect the item "clicked" and checking if it's an input or textarea using the nodeName.
I have tried to apply element.scrollIntoView({block: "center"}); but if the element is initially at the center of the screen it will not scroll and will be covered by the bottom bar when the virtual keyboard shows up.
This is the javascript I am applying currently:
var inputs = document.querySelectorAll("input, textarea");
var container = document.querySelector(".screen > .content");
window.addEventListener("resize", function(e) {
var targetEl = document.querySelector(":focus");
var bottomBar = document.querySelector(".bottom-bar-wrapper");
if(targetEl.nodeName.toLowerCase() === "input" || targetEl.nodeName.toLowerCase() === "textarea") {
var scrollY = Math.floor(targetEl.getBoundingClientRect().top + targetEl.getBoundingClientRect().height + bottomBar.getBoundingClientRect().height);
container.scrollTo(0, scrollY);
}
});
It's the solution that has worked best so far but not sure if it's the more eloquent one.
The challenge part is that when a user is already typing on an input and click on another input the scroll calculations return wrong values and it scrolls to a very strange position where the clicked input is not even close.
What can be happening for the position of the elements to return wrong values?
How would you approach this?
I've created a mockup on JSFiddle that kind of replicates the issue, html and css wise.
https://jsfiddle.net/marioandrade/L5f2n3vm/14/
Thanks for your help in advance.

Related

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.

Slide parent DIV to top when input field is selected

When someone clicks on a specific input field on my website, particularly on a mobile device, I need the parent div of the input field to slide to the top of the page. I need this because the keyboard that pops up covers the entire div below the input field, which is showing the user the items that they are filtering through. I've laid out the problem below graphically. I'd appreciate some guidance here :)
Starting state:
Finished state:
something like this oughtta do:
$('input').focus(function (event) {
var offset = $('header').height();
$('body, html').animate({
scrollTop : offset
})
})
JSBin

jQuery scrolling out of view issue

I am working on building a schedule. So far it's pretty straight-forward. There is one bit of functionality I am having issues with.
I have an ul that has a fixed height to allow scrolling. There are "Labels" (li.dayLabel) withing the ul that separate the hours. What I am trying to do is to have it so that when a label is scrolled out of view it will change the text in the placeholder to it's text. Then once that works, I need it to work in reverse. So when they label scrolls back into view it updates the placeholder. Basically, I am trying to make the placeholder be a title for the available items until another label is then scrolled out of view. This is for scrolling from the top. So as you scroll down the list the placeholder is meant to be a title for the section you are viewing until you reach another section and it takes its place. Then when you scroll back down I need it to replace the text with the previous li.dayLabel so the sections stay organized. I hope this makes sense.
You can see what I am trying to do by looking at the original that I am basing this off of. Notice how the placeholder changes as you scroll down the list and changes back when you scroll back up.
Demo: jsFiddle // Note: line 54 is the part that is in question
I originally used:
$(".snlf-schedule-list li.dayLabel:visible:first").text();
as the :first selector is suppose to only match a single element.
I later tried:
$(".snlf-schedule-list li.dayLabel:visible").filter(":eq(0)")
as this is suppose to be the same thing.
It seems that when an element is out of view it still is considered :visible I believe this is my issue.
Am I doing this completely wrong? I was under the impression that when you scroll an element like this it should no longer be :visible. After reading the documentation I have learned that this is not the correct selector to use.
It would appear that scrollTop is how I should be doing this. Now I have used scrollTop for scrolling down pages to disable animations when not in view but I am not clear on how to untilize this for a ul with scrollbars.
I tried:
var _first = $('li.dayLabel:first'); // next element to scroll out of view?
if( $(this).scrollTop() > (_first.offset().top+_first.height())) {
// Out of view
console.log("out");
} else {
// in view
console.log("in");
}
Updated Demo: jsFiddle
But it seems to be redundant as it's already calculating the first element so I am not sure how to get the correct element (the next one that's about to scroll out of view.) Then I need this to work when they scroll back up...
Any insight on this is much appreciated. Hopefully it's something simple I am just over complicating or missing completely.
Thanks,
Jeremy
The solution for my case was:
// Set placeholder text on scroll
var _scrollCagePositionTop = $(".snlf-schedule-list").offset().top;
var _first = $('li.dayLabel:first'); // first dayLabel element
$(".snlf-schedule-list").scroll(function(){
var _lastOffText = $(_first).text();
$("li.dayLabel").each(function() {
if ($(this).offset().top < _scrollCagePositionTop) {
_lastOffText = $(this).text();
}
});
$("#schedule-placeholder").text(_lastOffText);
});
What I did was set the known position of the top of the scroll cage (_scrollCagePositionTop)
When the user scrolls I set a variable _lastOffText that keeps track of the last item text content when scrolled out of view (less offset top than the palceholder). I then set this value to the placeholder.
This method allows me to have the proper text in my placeholder when the user scrolls up or down.
To fix the issue of an empty placeholder when the user scrolls back to the top I just set the default of _lastOffText to be the text of the first label ($(_first).text())
Hope others find this useful.
Here is the working demo: jsFiddle Final

How can I keep iPhone Safari keyboard from scrolling a fixed navbar up?

I'm building an app with PhoneGap and I have a screen that has a fixed navigation bar, a scrollable area below, and a text field in that area (think facebook message screen). When you tap on the text field, keyboard pops up and although nav bar is fixed, it scrolls up and out of the screen. I want it to stay fixed and scrollable area should get narrower.
Is there a way to do this?
Here's a diagram (sorry for poor quality):
diagram
set frames here:
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
// change base view frame
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// reset base view frame
}
Rather than using C, just use javascript and window.scrollTo for this (on input focus)
$('input').live('focus', function(e) {
e.preventDefault(); e.stopPropagation();
window.scrollTo(0,0); //no scroll > stays fixed!
});
If you don't want to set a static value for the Y scroll position, feel free to use this short plugin I've written that automatically aligns the keyboard underneath the input field (unless there's no need to scroll). Just call this on focus as shown above:
setKeyboardPos(e.target.id);

Automatic Textarea cursor movement

My question is almost similar to Automatic newline in textarea in textarea but my context is more complex. I have multiple textareas which have a 1 row attribute thus giving an impression of writing on air(just meaning empty area on the website with no borders since the textarea border i have set in css as >>> border: 0;).
I would like to use JQuery or Javascript to calculate when the text entered by the user if he/she has reached the end of the row of the textarea so as to automatically move to the next textarea below. One way to solve this would be to try and count the characters but different characters have different widths.
I'm thinking of inserting a hidden element at the edge of the textareas to act as a trigger for the nexttextarea.focus() event but i have no idea of how i can achieve this.
I have tried goofing around and thinking of different hacks but only one seems to be the solution... Try to store each character in an array and give them their default space taking value in px...like 'a'=>0.7px,'b'=>0.9px or something of the sort if their is a list somewhere (although it looks like it would take a lot of overhead in terms of memory as i would have to store both capital, small letters and many other characters.) Then do some calculations depending on the width of the browser if it has been re-sized or if not the full size to determine when the textarea row width becomes full at the browser width edge. (For the time being the textarea width is 100% and has no parent therefore fills the whole browser width).
If anybody has an idea of a complex or simple way i can accomplish this, help me. A big problem is that IE and Mozilla introduce scroll-bars if the browser window is re-sized, and scroll-bars is what i never want the user to see(remember impression of typing into thin air).
Forgive me for being so verbose..just wanted to be accurate and detailed.
This is harder than it looks. Try checking the scrollHeight and scrollWidth of the textarea; if they changed, the text overflowed. At that point, you can move text from the end of the current textarea to the beginning of the next textarea until the scroll height/width goes away.
Here's an example:
document.onkeyup = function(evt) {
var event = evt || window.event;
var target = event.target;
var nextArea = target.nextSibling; // assumes no whitespace between textareas.
var chars;
if (target.tagName == 'TEXTAREA' && (target.scrollLeft || target.scrollTop)) {
chars = 0;
while (target.scrollLeft || target.scrollTop) {
target.value = target.value.replace(/.$/, function(m0) {
nextArea.value = m0 + nextArea.value;
return '';
})
++chars;
target.selectionStart = target.value.length;
}
nextArea.focus();
nextArea.selectionStart = chars;
}
}​
http://jsfiddle.net/L73RG/3/
Note that a fully-working solution will need to bind this to more than just keyup events, because the user can paste with the context menu, for example. You may want to bind it to some mouse events or even run it occasionally on a timer if you find the box can be modified without triggering events (e.g. through a top level "edit" menu).
Check on every keypress if the content of your textarea is overflowing with the answer provided to this question: Determine if an HTML element's content overflows
You'll then have to remove the extra characters and put them into the next textarea. Probably one by one, using your check overflow function after each character is moved to see if the text area is still overflowing.
A possible solution is to measure the size of the text. Ext-JS does it by creating an offscreen absolutely positioned div, giving it style properties for the font you want to measure, and them measuring the div itself.
You can use Ext-JS's code as inspiration http://docs.sencha.com/ext-js/4-1/#!/api/Ext.util.TextMetrics

Categories