hide keyboard in iphone safari webapp - iphone

I'm creating a webapp for the iPhone, based in HTML/CSS/JS. I'm using forms to receive input and pass data to the script, but a problem I'm encountering is that the keyboard won't disappear. The user will enter the information, hit submit, and since it's JavaScript the page doesn't reload. The keyboard remains in place, which is a nuisance and adds another step for users (having to close it).
Is there any way to force the keyboard in Safari to go away? Essentially, I have a feeling this question is equivalent to asking how I can force an input box to lose focus or to blur. Looking online, I find plenty of examples to detect the blur event, but none to force this event to occur.

Even more simply, you can call blur() on the currently focused element. $("#inputWithFocus").blur()

document.activeElement.blur();

You could try focus()ing on a non-text element, like the submit button.

Here's a small code snippet that always hides the keyboard whenever the focus is in an input or textarea field and the user taps outside of that element (the normal behaviour in desktop browsers).
function isTextInput(node) {
return ['INPUT', 'TEXTAREA'].indexOf(node.nodeName) !== -1;
}
document.addEventListener('touchstart', function(e) {
if (!isTextInput(e.target) && isTextInput(document.activeElement)) {
document.activeElement.blur();
}
}, false);

To detect when the return button is pressed use:
$('input').bind('keypress', function(e) {
if(e.which === 13) {
document.activeElement.blur();
}
});

I came across this issue and have spent some time until getting a satisfactory solution. My issue was slightly different from the original question as I wanted to dismiss the input event upon tapping outside input element area.
The purposed answers above work but I think they are not complete so here is my attempt in case you land this page looking for the same thing I was:
jQuery solution
We append a touchstart event listener to the whole document. When the screen is touched (doesn't matter if it's a tap, hold or scroll) it will trigger the handler and then we will check:
Does the touched area represent the input?
Is the input focused?
Given these two conditions we then fire a blur() event to remove focus from the input.
ps: I was a little bit lazy so just copied the line from above response, but you can use the jQuery selector for document in case you want to keep consistency of code
$(document).on('touchstart', function (e) {
if (!$(e.target).is('.my-input') && $('.my-input').is(':focus')) {
document.activeElement.blur();
}
});
Hammer.JS solution
Alternatively you can use Hammer.JS to handle your touch gestures. Let's say that you want to dismiss that on a tap event but the keyboard should be there if the users is just scrolling the page (or let's say, hold a text selection so he can copy that and paste into your input area)
In that situation the solution would be:
var hammer = new Hammer(document.body);
hammer.on('tap', function(e) {
if (!$(e.target).is('.search-input') && $('.search-input').is(':focus')) {
document.activeElement.blur();
}
});
Hope it helps!

$('input:focus').blur();
using the CSS attribute for focused element, this blurs any input that currently has focus, removing the keyboard.

Be sure to set, in CSS:
body {
cursor: pointer;
}
otherwise, your event handler calling document.activeElement.blur() will never get fired. For more info, see: http://www.shdon.com/blog/2013/06/07/why-your-click-events-don-t-work-on-mobile-safari

For anyone using Husky's code in AngularJs here is the rewrite:
function isTextInput(node) {
return ['INPUT', 'TEXTAREA'].indexOf(node.nodeName) !== -1;
}
angular.element($document[0]).on('touchstart', function(e) {
var activeElement = angular.element($document[0].activeElement)[0];
if(!isTextInput(e.target) && isTextInput(activeElement)) {
activeElement.blur();
}
});

In my case, I have an app:
AppComponent -> ComponentWithInput
and with the html:
<div class="app-container" (click)="onClick()">
<component-with-input></component-with-input>
</div>
And everything I do is adding (click)="onClick()"
You can leave the method empty as I did:
onClick() {
// EMPTY
}
This works for me.

Related

iPhone - iScroll doesn't work when when VoiceOver is on

I have a Cordova Mobile application which uses iScroll plugin. To my surprise scroll doesn't work when I run the app in VoiceOver mode (three finger swipe up/down gesture). It just reads page 1 of 1 even if the content is existing for more than 2 pages.
Are there any role attributes to make page to scroll ? Please help.
I found that iScroll is using transform CSS property for scrolling.
I was able to resolve this issue.
May be you can also try the same.
Add below style to your parent div
-webkit-overflow-scrolling : touch
There is a phone gap plugin to listen for VoiceOver on/off https://github.com/phonegap/phonegap-mobile-accessibility
// Define a persistent callback method to handle the event
function onScreenReaderStatusChanged(info) {
if (info && typeof info.isScreenReaderRunning !== "undefined") {
if (info.isScreenReaderRunning) {
console.log("Screen reader: ON");
// Do something to improve the behavior of the application while a screen reader is active.
} else {
console.log("Screen reader: OFF");
}
}
}
// Register the callback method to handle the event
window.addEventListener(MobileAccessibilityNotifications.SCREEN_READER_STATUS_CHANGED, onScreenReaderStatusChanged, false);
On voiceover ON event you can destroy iScroll(or make useTransform property to false).
On voiceover OFF you can re-initiate the iScroll.
Let me know if it works.

dojox/gesture/swipe prevents the html select to open dropdown

can anyone please explain to me why the html SELECT control (or any other control like BUTTON) placed inside the div (that is registered with dojox/gesture/swipe events) cannot be opened? I'd welcome any workarounds pls
require({
}, [ 'dojo/dom', 'dojox/gesture/swipe', 'dojo/on', 'dojo/_base/event' ], function(dom, swipe, on, event) {
var div = dom.byId('testSwipe');
var isSwipe = false;
on(div, swipe.end, function(e) {
console.log("### SWIPE");
});
});
http://jsfiddle.net/zLyck884/
based on the documentation here, particularly the image : http://dojotoolkit.org/reference-guide/1.10/dojox/gesture.html
the image depicts how the dojo standardizes the events (also for desktops) and how the swipe is just another layer of the touch events. so I reckoned if the mouse events are replaced by touchstart or something, then it most likely blocks the default mouse action...
once I've stopped propagating the event (on the SELECT) further, then it worked ok.
query("select", this.domNode).on(touch.press, function(e){e.stopPropagation()});
where this.domNode is the element on which the swipe is enabled
on(this.domNode, swipe, lang.hitch(this, "_onSwipe"));
Unfortunately the swipe (touch) event overriding the default behaviour is not very handy, I just left dojox/gesture/swipe or touch for now. Seems like I'll rather implement my own touch event handling.

Google Closure add onclick to button after adding this button with custom editor plugin

I am making a custom plugin for the editor provided by Google Closure. The plugin makes it able to add a button.
I am having problems by setting an onclick on the button, the other values are nicely set.
button.innerHTML = event.label;
button.className = event.initialClass;
var extraClasses = event.extraClasses;
if (extraClasses)
{
button.className += ' ' + extraClasses
}
button.onclick = function() { event.onclick };
Does anyone know what I am doing wrong and how I can fix this?
After creating a button it is added to the editors SeamlessField. A second problem that I currently have is that after creating the button, my pointer is inside the button and I can't seem to get it out of there.
I've got the follow piece of code for handling this at the moment. The var button is the created button. button contains: <button class="orange">test</button>
// We want to insert the button in place of the user's selection.
// So we restore it first, and then use it for insertion.
this.restoreOriginalSelection();
var range = this.fieldObject.getRange();
button = range.replaceContentsWithNode(button);
// Done making changes, notify the editor.
this.fieldObject.dispatchChange();
// Put the user's selection right after the newly inserted button.
goog.editor.range.placeCursorNextTo(button, false);
// Dispatch selection change event because we just moved the selection.
this.fieldObject.dispatchSelectionChangeEvent();
Any ideas about how I could fix this second problem aswell?
For the first, it does not look like you have begun using Google Closure event code. Wiring up the button to the 'click' event in Google Closure would be as follows:
goog.events.listen(button, goog.events.EventType.CLICK, event.onclick)
You should also be investigating the goog.dom and goog.dom.classes namespaces if you'd like to use Google Closure's wrappers around standard CSS class and text DOM manipulation.
For the second, were you testing in Chrome? If so, you might have ran into a range issue in Webkit, documented within the Closure code itself:
https://code.google.com/p/closure-library/source/browse/closure/goog/editor/range.js#174
I have gotten around this in the past by inserting an empty <span> element as a sibling after the offending element (the button, in your case), and placing the cursor next to the <span> instead. However, there's nothing stopping the user from moving the cursor back inside your button. You'll have to add more logic to prevent a user from placing the cursor within the button's text.

Toggle Entire Accordion Functionality with Link or Button

I have an accordion that works great. I'm trying to figure out a way to search all the flaps of the accordion:
Find String on Page (Ctrl+F) when jQuery Accordion in Use
I have used the destroy method on a link and then reinitializing on another link, but it would be great to toggle this with one button. ((I originally asked this question without this solution here, so the answer below is just this. I won't accept it until I see if any better solutions come up))
$(document).ready(function() {
$("#hide").click(function() {
$(".accordion").accordion("destroy");
});
$("#show").click(function() {
$(".accordion").accordion({
navigation : true,
collapsible : true,
heightStyle : "fill",
active :
});
});
});
I was also able to toggle the entire accordion with jQuery toggle() but this just makes the entire thing disappear. What I want is to toggle the accordion functionality, while leaving the div structure behind so it's visible, just as if someone disabled JavaScript in the browser.
So the above kind of does what I want, except in reality, the better solution is to actually remove the class .accordion because that makes the page truly look like it should. Destroying the accordion actually breaks some stuff and this is undesirable.
I thought it would be as easy as this but it's not working:
$(document).ready(function() {
$("#hide").click(function() {
$("#accordion").removeClass(".accordion");
});
$("#show").click(function() {
$("#accordion").addClass(".accordion");
});
});
This does seem to be adding and removing the class I'm telling it to, but the initial remove is not removing the accordion class to remove the accordion itself.
I have used the destroy method on a link and then reinitializing on another link (although one button toggle would be better):
$(document).ready(function() {
$("#hide").click(function() {
$(".accordion").accordion("destroy");
});
$("#show").click(function() {
$(".accordion").accordion({
navigation : true,
collapsible : true,
heightStyle : "fill",
active :
});
});
});
I had to edit some CSS to make this work out, but it's the best I could find.
NOTE
I should note that I ended up finding even a simpler approach to this. Simply adding a reload restores the page back to its original state:
$("#show").click(function() {
location.reload();
});
The destroy and reload is a very simple solution. The one button aspect is solved with this event which goes in the document ready function:
// event to destroy accordion and make it's content searchable
$("#open-1").on("click",function() {
// if the button says Enable reload to bring the accordion back
if ($(this).html() == "Enable") {
location.reload();
}
// otherwise destroy the accordion and change the button to Enable
else {
$("#accord-1").accordion('destroy');
$(this).html("Enable");
}
});
The button can say anything you want initially. The key is that it's set to "Enable" and tested for "Enable" to reload the page. You can make that any string you want as well. Here's a complete example.

jquery live click event stopPropagation

I have a dropdown menu which contains a input and several buttons. The dropdown should hide when I click one of the buttons or somewhere else, but don't hide when keypress on the input. I use the following code, it doesn't work. Though it works when I use
$('.dropdown input').click(function(e){
})
instead of live.
But I do need live, so is there any solution for this?
/* dropdown menu */
$('.dropdown input').live('click', function(e) {
e.stopPropagation();
});
$(document).click(function(e){
if(e.isPropagationStopped()) return; //important, check for it!
});
e.stopPropagation() will do no good for you in .live(), because the handler is bound to the document, so by the time the handler is invoked, the event has already bubbled.
You should stopPropagation from a more local ancestor of the element being clicked.
Since you were using .live(), I assume there are some dynamic elements being created. If so, the proper element to bind to will depend on the rest of your code.
Side note, but you never "need" .live(). There are other ways to handle dynamically created elements.
did you try:
$('.dropdown').on('click', 'input', function(e) {
e.stopPropagation();
});
OR
$('.dropdown').delegate('input', 'click', function(e) {
e.stopPropagation();
});
NOTE: e.stopPropagation(); is not effective for live event
According to you question I have a dropdown menu which contains a input and several buttons. The dropdown should hide... means that dropdown is already exists within you DOM. If it already exists then you don't need live event.
what version of jQuery are you using? > 1.7 then:
$(document).on({"click":function(e){
//do your work, only input clicks will fire this
}},".dropdown input",null);
notes:
properly paying attention to event.target should help out with overlapping 'click' definitions using .on();