PhoneGap / Android custom keyboard - android

I'm developing an app with multiple input[type=numer] elements. Android only for now.
The built-in numeric keyboard has two problems:
* it's inconsistent (different on different versions of Android)
* it has unnecessary keys (space, dash, comma and "next") which add confusion.
I'd like to have a keyboard with just numbers, comma and backspace. Is that possible?
Edit Oct 3, 2013. A third problem appeared and it's by far the worst. It looks like Samsung decided to skip the decimal character (".") from their numeric keyboard, at least the one that pops when input[type=numer] gets the focus in the browser. It seems all Galaxy S4 devices are affected (I've seen it on the S4 Mini, I don't have access to many Samsung devices... all I see are Nexus lovers :-)). I couldn't find much about the issue in Google, but I've seen Galaxy S4 users complain about it in 2012 (I've tried it on one S3 a few weeks ago and it was OK).
Long story short, after a careful consideration I decided to implement my own keyboard in html/javascript (Samsung is too important, I'm getting bad reviews just because of it and I don't think I can do anything to fix it). I'm in the process of rewriting my app, I'll try to remember and tell the story when I'm done.
Edit Dec 3, 2013. My current solution (still in alpha stage, the app rewrite takes me way longer than I expected) is a keyboard implemented entirely in javascript. I used regular <span> elements instead of <input> to prevent OS keyboard from popping out. As an added benefit, I get to control everything about the keyboard, so I added a few arithmetical keys (x, -, *, /, ( and )) and the user can type in expressions, for example "3x(2+5.5)" instead of "15". I'll link to the app when it's ready (still at least a few more weeks).

Sure it is.
First, configure your activity to never show the keyboard (try android:windowSoftInputMode = "stateAlwaysHidden"). You may have some problems if EditText insists on pulling it up, but you can make a mock EditText based on TextView to go around that, or inherit EditText and override some methods. There are multiple guide on that, like here: Close/hide the Android Soft Keyboard
Second, create your own UI-keyboard element, with any buttons you want in however layout you want, and catch button presses on this keyboard, for each press, append the appropriate character to the EditText/TextView's displayed text.
That said, users may not like it. As much as you hate that keyboards look differently for each device, each user is used to his own keyboard, and expects to see it when editing text. I urge you to reconsider.

Thanks for the update. Here is how I'm implementing it. It might be similar to how you are doing it. I'd be curious what issues you've run into so far.
I haven't moved this to production yet so still testing but it seems to work well so far. I've removed some validations from the code below to make it much shorter...
Basically the keyboard is 1 line on the iPad and 2 lines on the phone. It supports any input field with the class "keyboard" and highlights the entire ".keyboard-item" so it is clear to the user which field they are updating.
<div id="stuff">
<ul>
<li> <label for="name">Name</label> </li>
<li> <input type="text" id="name" class="required"/> </li>
</ul>
<ul class="keyboard-item">
<li> <label for="number">#</label> </li>
<li> <input type="text" id="number" class="keyboard required" pattern="[0-9]*" readonly="readonly" onkeypress="dosomething(this)"/> </li>
</ul>
</div>
<div class="mobile-number-keyboard">
<div class="mobile-number-keyboard1"> <span style="padding-left: 20px;">0</span> <span>1</span> <span>2</span> <span>3</span> <span>4</span> <span style="padding-right: 20px;">5</span> </div>
<div class="mobile-number-keyboard2"> <span style="padding-left: 20px;">6</span> <span>7</span> <span>8</span> <span>9</span> <span style="width: 8px;">.</span> <span style="padding-right: 20px;"><</span> </div>
</div>
<style>
.mobile-number-keyboard { width: 101%; height: 40px; margin: auto; margin-bottom: 20px; }
body.phone .mobile-number-keyboard { height: 80px; }
.mobile-number-keyboard span { float: left; padding: 8px 22px; border: 1px outset White; cursor: pointer; background-color: #4F81BD; color: White; }
.mobile-number-keyboard span:hover { background-color: #87CEFA; }
.mobile-number-keyboard span:active { border-style: inset; background-color: #00E5EE; }
body.phone .mobile-number-keyboard2 { clear: both; height: 40px; }
.keyboard-focus { background: #FFC1C1; border: 1px solid red; }
.keyboard-item-focus { background: #00E5EE; }
</style>
<script>
function initCustomKeyboard(jContainer) {
jContainer.find('input, select, textarea').click(function() {
$('.keyboard-focus').removeClass('keyboard-focus');
$('.keyboard-item-focus').removeClass('keyboard-item-focus');
var me = $(this);
if (me.hasClass('keyboard')) {
me.addClass('keyboard-focus');
var parent = me.parent();
if (parent.hasClass('keyboard-item')) {
parent.addClass('keyboard-item-focus');
} else {
parent = parent.parent();
if (parent.hasClass('keyboard-item')) {
parent.addClass('keyboard-item-focus');
} else {
parent = parent.parent();
if (parent.hasClass('keyboard-item')) {
parent.addClass('keyboard-item-focus');
}
}
}
}
});
jContainer.find('.mobile-number-keyboard').find('span').click(function() {
var me = $(this);
var val = me.text();
var box = jContainer.find('.keyboard-focus');
var bval = box.val();
var blen = bval.length
if (box.length > 0) {
if (val === '<') {
if (blen === 0) { return; }
if (blen > 1 && bval.substring(blen-2, blen-1) === ' ') {
box.val( bval.substring(0, blen - 2) );
} else {
box.val( bval.substring(0, blen - 1) );
}
var whichCode = 8;
} else {
var max = box.attr('maxlength');
var whichCode = val.charCodeAt(0);
if (max === undefined || parseInt(max) > blen) {
box.val(bval + val);
} else {
return;
}
}
var ev = $.Event('keydown');
ev.which = whichCode;
box.trigger(ev);
ev = $.Event('keypress');
ev.which = whichCode;
box.trigger(ev);
ev = $.Event('keyup');
ev.which = whichCode;
box.trigger(ev);
}
});
}
$(function() { initCustomKeyboard('#stuff'); }
</script>

Related

Javascript autotab keyup/keydown not working in Cordova Android Browser

I created an autotab function that switches from input to input when user enter a number. The autotab works great on ios and when using a computer keyboard. It doesnt work in Android with touch events. What is the workaround?
code
$('.digits').find('input').each(function() {
$(this).attr('maxlength', 1);
$(this).on('keyup', function(e) {
var parent = $($(this).parent());
if(e.keyCode === 8 || e.keyCode === 37) {
var prev = parent.find('input#' + $(this).data('previous'));
if(prev.length) {
$(prev).select();
}
} else if((e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 65 && e.keyCode <= 90) || (e.keyCode >= 96 && e.keyCode <= 105) || e.keyCode === 39) {
var next = parent.find('input#' + $(this).data('next'));
if(next.length) {
$(next).select();
} else {
if(parent.data('autosubmit')) {
parent.submit();
}
}
}
});
});
.verification-code {
max-width: 100%;
position: relative;
/*margin:50px auto;*/
text-align:center;
}
.control-label{
display:block;
margin:40px auto;
font-weight:900;
}
.verification-code--inputs input[type=text] {
border: 2px solid #e1e1e1;
width: 46px;
height: 46px;
padding: 10px;
text-align: center;
display: inline-block;
box-sizing:border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="verification-code">
<label class="control-label">Validation Code</label>
<div class="verification-code--inputs digits text-black">
<input oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1');" class="text-black" id="digit-1" name="digit-1" data-next="digit-2" type="text" maxlength="1" />
<input oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1');" class="text-black" id="digit-2" name="digit-2" data-next="digit-3" type="text" maxlength="1" />
<input oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1');" class="text-black" id="digit-3" name="digit-3" data-next="digit-4" type="text" maxlength="1" />
<input oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1');" class="text-black" id="digit-4" name="digit-4" type="text" maxlength="1" />
<!--<input id="digit-5" name="digit-5" type="text" maxlength="1" />-->
</div>
</div>
It could be as simple as replacing your .select() method with the .focus() method. There are also simpler ways to add your events than using find. You could just add a class and attach the events based on that class. Instead of using attributes to find your next input, you could simply use the .next() DOM Traversal method. Also you could probably make your number only check work more simply using regex. There are a lot of ways to reduce your code here:
$(document).on('keyup', 'input.text-black', function(e){
var _this = $(this),
next = _this.next();
_this.val(e.target.value.replace(/[^0-9]/g, ''))
if (!!next && _this.val().length)
{
next.focus();
}
});
I did test this on android, and it appeared to work for me. I've also added a check to verify that the input has a length before moving to the next input.
Demo

Sliding an image when the scroll reaches it

HTML:
<div id="slideimage">
<img src="file:///android_asset/images/mainpageimage1.jpg" style="width:100%; height:auto; padding-bottom:7px;" >
<img src="file:///android_asset/images/mainpageimage2.jpg" style="width:100%; height:auto;" >
</div>
Script:
window.onscroll = function () { scrollFunction() };
function scrollFunction() {
if (document.body.scrollTop > 700 ) {
$("slideimage").animate({left: '250px'});
}
I have the code above but it doesn't do anything.
I just need a simple code to slide the image.
The problem is that the code is an Android app based on HTML code, not a website, and I'm new to it so I don't know if it works the same.
You are forgetting the hash (#) in the jQuery selector.
window.onscroll = function () { scrollFunction() };
function scrollFunction() {
if (document.body.scrollTop > 700 ) {
$('#slideimage').animate({left: '250px'});
}
}
Check to see if it works right now.

Prevent standard action when you select [CSS, JS, android]

I have made an app in android webview and I want that something can be copied. So when you press a button you will have something copied to your clipboard.
I have tried "clipboard.js" works browers but not on android. So I used this javascript:
var copyXBT = function () {
var theTheCopyXBTAdr = $('#theToCopyXBT');
theTheCopyXBTAdr.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copying text command was ' + msg);
} catch (err) {
console.log('Oops, unable to copy');
}
};
But when you pressed the input type text will get a blue color,.. and blue border(android webview yellow) and on android your keyboard will pop up.
I use this css styling to "hide" it. Because I can't say display none. If I do that I won't work.
#theToCopyETH{
color: white;
border: 0px solid white;
}
::selection{
background: white;
color: white;
}
This is a piece of my HTML:
<button class="btn btn-coinchecker" id="copyETH">Copy ETH address</button><button class="btn btn-coinchecker" data-toggle="modal" data-target="#showETHQR">Click me to get the QR-code</button>
<input type="text" id="theToCopyETH" value="*********************">
See fiddle for example (please open in Google Chrome)
So my question is how to prevent the pop-up of the keyboard and get rid of the yellow-border in android (google chrome on desktop is that blue)
Thanks in advance for helping me!
I found the answer.
What do I need to do to hide my keyboard is this js:
enter var hidekeyboard = function (e) {
e.attr('readonly', 'readonly'); // Force keyboard to hide on input field.
e.attr('disabled', 'true'); // Force keyboard to hide on textarea field.
setTimeout(function() {
e.blur(); //actually close the keyboard
// Remove readonly attribute after keyboard is hidden.
e.removeAttr('readonly');
e.removeAttr('disabled');
}, 100)
};
I need to add that after my selection has happend otherwise I won't work.
My copyETH looks like this then:
var copyETH = function () {
var theTheCopyETHAdr = $('#theToCopyETH');
theTheCopyETHAdr.removeClass('toggleDisplay');
theTheCopyETHAdr.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copying text command was ' + msg);
} catch (err) {
console.log('Oops, unable to copy');
}
hidekeyboard(theTheCopyETHAdr);
theTheCopyETHAdr.addClass('toggleDisplay');
};
So you can see I do also a removeClass and addClass. Because If I only use the hidekeyboard you can see the selection but with his css class it's gone + no-one can change the input field.
Here to see the solved fiddle
This should be enough to hide the input and prevent any activity when it's clicked/tapped, but not break your JS:
#theToCopyETH {
visibility: hidden;
pointer-events: none;
}

Update textbox from java code (Android, Cordova, HTML5)

I am developing one Android app using Cordova. On the app startup I want to show some dynamic message on the UI which is index.html. How can I show this message from Java code.
index.html
MainActivity.java
How to update the value of text box on index.html ?
In short I want to update some value from my JAVA code not from JavaScript!
Thank you
This is how i do it. (less stress)
First you need to attach an event listener to the OnLoad Event of the index.
HTML
<body onLoad="showMessage()">
JavaScript
function showMessage()
{
alert('Hello Message');
}
Now the showMessage() function will be called as soon as the page load is completed. Do note that you can also create your own method for displaying a message instead of using an alert.
You're welcome.
UPDATE
This is a simple method for showing a dynamic message (instead of an alert)
I'm only adding this because i'm guessing that you are requesting help with the code also. So here is a super sweet alert box, complete with animations.
First make sure you have the required HTML on the page that will be used to display the message
HTML
<div id="Page_Alert" class="Animate_Opacity">
<div id="Page_Alert_Box_Container" class="Box_Container Animate_MarginTop">
<div id="Page_Alert_Title">Alert Preview</div>
<div id="Page_Alert_Content">This is just a preview of what an alert popUp will look like.</div>
<div class="Buttons_Container">
<div class="BTN" onClick="hide_AlertWindow()">OK</div>
<!-- <div class="BTN">CANCEL</div> -->
</div>
</div>
<div class="bg"></div>
</div><!-- End Alert Pop Up -->
CSS
#Page_Alert{position:absolute; top:0; left:0%; width:100%; height:100%; z-index:-20; opacity:0; overflow:hidden;}
#Page_Alert > .bg{position:absolute; top:0; left:0; width:100%; height:100%; background:BLACK; opacity:.6; z-index:0;}
#Page_Alert > .Box_Container{position:relative; margin:auto; margin-top:-45%; width:80%; min-height:100px; background:WHITE; color:#444; z-index:1;}
#Page_Alert > .Box_Container > #Page_Alert_Title{position:relative; margin:auto; padding-top:18px; width:90%; font-family:OpenSansBold; color:BLACK; font-weight:bold; font-size:1.2em; z-index:1;}
#Page_Alert > .Box_Container > #Page_Alert_Content{position:relative; margin:auto; margin-top:12px; width:90%; background2:RED; font-size:.9em; z-index:1;}
#Page_Alert > .Box_Container > .Buttons_Container{position:relative; margin:auto; margin-top:24px; width:95%; height:40px; background2:RED; z-index:1;}
#Page_Alert > .Box_Container > .Buttons_Container > .BTN{position:relative; margin-right:13px; min-width:3px; height:30px; color:#0286A4; display:block; float:right; text-align:right; font-size:1.15em; font-family:OpenSansSemiBold;}
.Animate_Opacity
{
transition:opacity .5s;
-moz-transition:opacity .5s; /* Firefox 4 */
-webkit-transition:opacity .5s; /* Safari and Chrome */
-o-transition:opacity .5s; /* Opera */
}
.Animate_MarginTop
{
transition:margin-top .4s;
-moz-transition:margin-top .4s; /* Firefox 4 */
-webkit-transition:margin-top .4s; /* Safari and Chrome */
-o-transition:margin-top .4s; /* Opera */
}
Now all you do is call this function on page load (or when ever you wish to show an alert.
JavaScript
function show_AlertWindow(_title,_content)
{
var Page = document.getElementById('Page_Alert');
var Box = document.getElementById('Page_Alert_Box_Container');
var Title = document.getElementById('Page_Alert_Title');
var Content = document.getElementById('Page_Alert_Content');
Title.innerHTML = _title;
Content.innerHTML = _content;
Page.style.zIndex=15;
setTimeout(function(){ Page.style.opacity=1; },100);
setTimeout(function(){ Box.style.marginTop = 45 +'%'; },400);
}
function hide_AlertWindow()
{
var Page = document.getElementById('Page_Alert');
var Box = document.getElementById('Page_Alert_Box_Container');
Page.style.opacity=0;
setTimeout(function(){ Page.style.zIndex=-1; },200);
setTimeout(function(){ Box.style.marginTop = -45 +'%'; },300);
}
Soooo... if your body tag is like this
<body onLoad="show_AlertWindow('Alert Title','Hello message from alert')">
You will see a sweet dynamic alert box animate onto the screen.
Your welcome! (I practically did all of the work for you)

Google Maps v3 too close and height is incorrect on jQuery Mobile and PhoneGap

I want to add Google maps v3 with Geolocation into my jQuery Mobile / PhoneGap Android app but I've some problems:
It locates my position correct, but it's (the radius?) too close. I've changed the value of the radius at my code, but nothing happens. You can see the problem here: http://s7.directupload.net/images/131214/nbc3wudy.png
The second problem concers the height. You can see that at the screenshot too. The maps is too high for the screen, but I don't know how to change it.
And the last problem is this error: /android_asset/www/js/jquery.ui.map.js: Line 46 : Uncaught TypeError: Cannot call method 'apply' of undefined
Here is my code:
index.html
<div data-role="page" id="GPS">
<div data-role="header">
LeftPanel
<h1></h1>
</div>
<div data-role="content" id="map-content">
<div id="map-container"></div>
</div>
<script type="text/javascript">
$('#GPS').on("pagecreate", function() {
var positionOutput = function(position){
var longpos = position.coords.longitude;
var latpos = position.coords.latitude;
$('#map-container').height($(window).height());
$('#map-container').gmap('getCurrentPosition', function(position, status) {
if ( status === 'OK' ) {
var clientPosition = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
$('#map-container').gmap('addMarker', {'position': clientPosition, 'bounds': true});
$('#map-container').gmap('addShape', 'Circle', {
'strokeWeight': 0,
'fillColor': "#008595",
'fillOpacity': 0.25,
'center': clientPosition,
'radius': 15,
'clickable': false
});
}
});
};
navigator.geolocation.getCurrentPosition(positionOutput);
});
</script>
</div>
CSS:
#map-content {
padding: 0px;
}

Categories

Resources