I am using Phonegap + jQueryMobile + Android. When I create my <li> static it is working fine, but dynamically it is not working like static. Please check what mistake I did in the code shown below:
In jquery:-
$(document).unbind('pageinit').bind('pageinit', function () {
callMenuConnection();
});
function callMenuConnection() {
$.support.cors = true;
$.ajax({
type: "GET",
url: "one.html",
contentType: "text/xml",
dataType: "xml",
data: "",
cache:false,
processData:false,
crossDomain:true,
success: processSuccess,
error: processError
});
}
function processSuccess(data) {
$(data).find("category").each(function () {
var id = $(this).find('id').text();
var title = $(this).find('title').text();
$('#cat_list').append('<li><span>'+title+'</span></li>');
});
}
function processError(data)
{
alert("error");
}
$(function(){
var step = 1;
var current = 0;
var maximum = $(".categories ul li").size();
var visible = 2;
var speed = 500;
var liSize = 120;
var height = 60;
var ulSize = liSize * maximum;
var divSize = liSize * visible;
$('.categories').css("width", "auto").css("height", height+"px").css("visibility", "visible").css("overflow", "hidden").css("position", "relative");
$(".categories ul li").css("list-style","none").css("display","inline");
$(".categories ul").css("width", ulSize+"px").css("left", -(current * liSize)).css("position", "absolute").css("white-space","nowrap").css("margin","0px").css("padding","5px");
$(".categories").swipeleft(function(event){
if(current + step < 0 || current + step > maximum - visible) {return; }
else {
current = current + step;
$('.categories ul').animate({left: -(liSize * current)}, speed, null);
}
return false;
});
$(".categories").swiperight(function(){
if(current - step < 0 || current - step > maximum - visible) {return; }
else {
current = current - step;
$('.categories ul').animate({left: -(liSize * current)}, speed, null);
}
return false;
});
});
In css:-
div.sc_menu {
/* Set it so we could calculate the offsetLeft */
position: relative;
height: 145px;
width: 300px;
overflow: auto;
}
ul.sc_menu {
display: block;
height: 110px;
/* max width here, for users without javascript */
width: 1500px;
padding: 15px 0 0 15px;
/* removing default styling */
margin: 0;
background: url('navigation.png');
list-style: none;
}
.sc_menu li {
display: block;
float: left;
padding: 0 4px;
}
.sc_menu a {
display: block;
text-decoration: none;
}
.sc_menu span {
/* display: none; */
margin-top: 3px;
text-align: center;
font-size: 12px;
color: #fff;
}
.sc_menu a:hover span {
display: block;
}
.sc_menu img {
border: 3px #fff solid;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
}
.sc_menu a:hover img {
filter:alpha(opacity=50);
opacity: 0.5;
}
/* Here are styles for the back button, don't look at them */
#back {
display: block;
width: 500px;
text-align: center;
color: #003469;
font-size: 16px;
}
In Html5:-
<div data-role="page" data-theme="b" id="jqm-home">
<div class="categories">
<ul id="cat_list"></ul>
</div>
</div>
Try jqMobile + iScrollView + Infinite Scrolling.
For more details please check : Infinite Scrolling
And also You can see a demo here at the plugin site https://github.com/watusi/jquery-mobile-iscrollview
Refresh your ul list
function processSuccess(data) {
$(data).find("category").each(function () {
var id = $(this).find('id').text();
var title = $(this).find('title').text();
$('#cat_list').append('<li><span>'+title+'</span></li>');
});
$('#cat_list').listview('refresh');
}
OR
$('#cat_list').append('<li><span>'+title+'</span></li>').listview('refresh');
EDIT:
function processSuccess(data) {
var data="";
$(data).find("category").each(function () {
var id = $(this).find('id').text();
var title = $(this).find('title').text();
data+='<li><span>'+title+'</span></li>';
});
$("#cat_list").html(data).listview('refresh');
}
Try $('#mylist').listview(); to enforce rendering.
Finally i got the answer of these
In HTML5:-
<div data-role="page" data-theme="b" id="jqm-home">
<div data-role="footer" data-position="fixed" data-theme="c">
<div class="categories" id="cat">
<ul id="cat_list" class="cat_list_class"></ul>
</div>
</div>
</div>
In jquery:-
var step = 1;
var current = 0;
var maximum = 0;
var visible = 2;
var speed = 500;
var liSize = 120;
var height = 60;
var ulSize = liSize * maximum;
var divSize = liSize * visible;
$(document).unbind('pageinit').bind('pageinit', function () {
callMenuConnection();
$('.categories').css("width", "auto").css("height", height+"px").css("visibility", "visible").css("overflow", "hidden").css("position", "relative");
$(".categories ul a").css("list-style","none").css("display","inline");
$(".categories ul").css("width", ulSize+"px").css("left", -(current * liSize)).css("position", "absolute").css("white-space","nowrap").css("margin","0px").css("padding","5px");
});
$(document).unbind('click').bind('click', function () {
scroll();
});
function callMenuConnection() {
$.support.cors = true;
$.ajax({
type: "GET",
url: "one.html",
contentType: "text/xml",
dataType: "xml",
data: "",
cache:false,
processData:false,
crossDomain:true,
success: processSuccess,
error: processError
});
}
var scripts ="";
function processSuccess(data) {
$(data).find("category").each(function () {
var id = $(this).find('id').text();
var title = $(this).find('title').text();
scripts = scripts+'<a class="ids_cat" data-role="button" data-transition="slide" data-inline="true" >' +title+ '</a>';
});
$('#cat_list').append(scripts);
$('#cat_list').trigger('create');
maximum = $(".categories ul a").size();
}
function processError(data)
{
alert("error");
}
function scroll(){
$(".categories").swipeleft(function(event){
if(current + step < 0 || current + step > maximum - visible) {return; }
else {
current = current + step;
$('.categories ul').animate({left: -(liSize * current)}, speed, null);
}
return false;
});
$(".categories").swiperight(function(event){
if(current - step < 0 || current - step > maximum - visible) {return; }
else {
current = current - step;
$('.categories ul').animate({left: -(liSize * current)}, speed, null);
}
return false;
});
}
Related
Im injecting html and js in my web view. What im trying to do is allow support on my Android phone to connect to a local Node.js Server to send and receive Audio and Video.
This is my Server.js that runs:
const HTTPS_PORT = 8443;
const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');
const WebSocketServer = WebSocket.Server;
// Yes, TLS is required
const serverConfig = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
};
// ----------------------------------------------------------------------------------------
// Create a server for the client html page
const handleRequest = function(request, response) {
// Render the single client html file for any request the HTTP server receives
console.log('request received: ' + request.url);
if(request.url === '/') {
response.writeHead(200, {'Content-Type': 'text/html'});
response.end(fs.readFileSync('client/index.html'));
} else if(request.url === '/webrtc.js') {
response.writeHead(200, {'Content-Type': 'application/javascript'});
response.end(fs.readFileSync('client/webrtc.js'));
}
};
const httpsServer = https.createServer(serverConfig, handleRequest);
httpsServer.listen(HTTPS_PORT, '192.168.1.62');
// ----------------------------------------------------------------------------------------
// Create a server for handling websocket calls
const wss = new WebSocketServer({server: httpsServer});
wss.on('connection', function(ws) {
ws.on('message', function(message) {
// Broadcast any received message to all clients
console.log('received: %s', message);
wss.broadcast(message);
});
});
wss.broadcast = function(data) {
this.clients.forEach(function(client) {
if(client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
};
console.log('Server running. Visit https://localhost:' + HTTPS_PORT + ' in Firefox/Chrome.\n\n\
Some important notes:\n\
* Note the HTTPS; there is no HTTP -> HTTPS redirect.\n\
* You\'ll also need to accept the invalid TLS certificate.\n\
* Some browsers or OSs may not allow the webcam to be used by multiple pages at once. You may need to use two different browsers or machines.\n'
);
This is the HTML thats viewable on the Webview in Android:
<!DOCTYPE html>
<html lang="en">
<head>
<title>P2P Video Chat</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=320, initial-scale=1" />
<script src="https://unpkg.com/peerjs#1.3.1/dist/peerjs.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<style>
div::-webkit-scrollbar {
display: none; /* for Chrome, Safari, and Opera */
}
#live {
background-color: #000;
height:100%;
width:100%;
}
#local-video {
width: 100%;
background-color:black;
}
#divider{
height:20px;
background-color:black;
}
#remote-video {
width: 100%;
background-color:black;
}
#end-call {
position: absolute;
top: 0;
left: 0;
padding: 8px;
background-color: red;
color: white;
border: none;
}
.d1{border-bottom:1px solid #ffffff;font-weight:bold;font-size:22px;color:#90CAF9;top:20px;left:20px;padding:8px;background-color:#0D47A1;opacity:0.7;text-align:center;}
.s1{color:white;font-size:12px;}
.d2{position:absolute;left:20px;top:20px;width:70px;height:70px;border-radius:35px;background-color:green;opacity:0.7;display:flex:justify-content:center;align-items:center;}
.i1{width:50px;height:50px;margin-left:10px;margin-top:10px;}
#record1{display:none;left:20px;border-radius:25px;width:50px;height:50px;position:absolute;background-color:red;opacity:0.7;padding:8px;color:white;font-weight:bold;font-size:18px;margin-top:-180px;z-index:400;}
#timer1{width:100%;margin-top:-50px;position:absolute;text-align:center;color:white;padding:8px;z-index:800;font-size:10px;}
.d3{position:absolute;opacity:0.7;padding:0px;color:white;font-weight:bold;font-size:18px;margin-top:-105px;display:inline-block;z-index:1000}
.d4{font-weight:bold;margin-top:-15px;margin-left:15px;position:absolute;width:120px;height:30px;z-index:300;}
.i2{float:left;width:50px;height:50px;margin-top:3px;}
.d5{float:left;color:black;margin-top:0px;margin-left:5px;}
.d6{position:absolute;color:gray;font-size:23px;text-align:center;z-index:200;width:100%;margin-top:-22px;padding:0px;background-color:white;}
.d7{background-color:white;padding:10px;border-radius:25px;font-size:23px;}
.d8{position:absolute;opacity:0.7;padding:0px;color:white;font-weight:bold;font-size:18px;margin-top:70px;display:inline-block;z-index:400;}
#timer2{width:100%;margin-top:80px;position:absolute;text-align:center;color:white;padding:8px;z-index:800;font-size:3px;}
#record2{display:none;left:20px;border-radius:25px;width:50px;height:50px;position:absolute;background-color:red;opacity:0.7;padding:8px;color:white;font-weight:bold;font-size:18px;margin-top:135px;z-index:100}
.d9{position:absolute;left:20px;bottom:20px;width:70px;height:70px;border-radius:35px;background-color:green;z-index:1200;opacity:0.7;display:flex:justify-content:center;align-items:center;}
.i3{width:50px;height:50px;margin-left:10px;margin-top:10px;}
.d10{border-top:1px solid #ffffff;text-align:center;font-weight:bold;font-size:22px;color:#90CAF9;position:absolute;left:0;bottom:0;right:0;padding:8px;background-color:#0D47A1;opacity:0.7;}
.s2{color:white;font-size:12px;}
/* Exact resolution */
#media (-webkit-device-pixel-ratio: 1) {
}
/* Minimum resolution */
#media (-webkit-min-device-pixel-ratio: 1.1) {
.d1{font-size:8px;}
.d2{width:40px;height:40px;background-color:red;}
.d2 img{width:20px;height:20px}
#record1{width:20px;height:20px;border-radius:10px; margin-top:-100px;}
#timer1{font-size:8px;}
#record2{width:20px;height:20px;border-radius:10px;margin-top:53px;}
#timer2{font-size:8px;margin-top:15px;}
.d3{font-size:12px;display:inline-block;}
.d5{font-size:8px;margin-top:4px;}
.d6{font-size:23px;}
.d8{font-size:12px;margin-top:50px;display:inline-block;}
.d3 img{ width:20px; height:20px;margin-right:5px; padding:2px;display:inline-block;}
.d8 img{ width:20px; height:20px;margin-right:5px;padding:2px;display:inline-block;}
.i2{float:left;width:20px;height:20px;}
.d9{width:40px;height:40px;background-color:red;}
.d9 img{width:20px;height:20px;}
.i4{width:20px;height:20px;margin-right:5px;}
.i5{width:20px;height:20px;margin-right:5px;}
.d7{font-size:10px;}
.d10{font-size:8px;}
.d11{display:inline-block;margin-top:16px;position:absolute;width:300px;font-size:8px;}
.d12{display:inline-block;margin-top:16px;position:absolute;width:300px;font-size:8px;}
}
/* Maximum resolution */
#media (-webkit-max-device-pixel-ratio: 3) {
}
</style>
</head>
<body style="margin:0;padding:0;overflow:hidden;" leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">
<!-- App code -->
<div id="live">
<div class=""><div class="d1"><img class="i4" src="vote.png" />VOTE: <span class="s1">123</span></div></div>
<div class="d2"><img class="i1" src="like.png" /></div>
<video id="remote-video" autoplay muted="true"></video>
<div id="divider">
<div id="record1" class=""></div>
<div id="timer1" class="">15 seconds</div>
<div class="d3"><img class="i1" src="rap.png" /><div class="d11">MC Trix</div></div>
<div class="d4">
<img class="i2" src="views.png"/> <div class="d5">1.1k</div> </div>
<div class="d6"><div class="d7">VS</div></div>
<div class="d8"><img class="i1" src="rap.png" /><div class="d12">MC Trix and Metz</div></div>
<div id="timer2" class="">15 seconds</div>
<div id="record2" class=""></div>
</div>
<video id="local-video" muted="true" autoplay></video>
<input value="lfnvsfnsnfvsnvsn" style="z-index:10000;position:absolute;top:0;left:0;" type="button" onclick="start(true)" />
<div class="d9"><img class="i3" src="like.png" /></div>
<div class=""><div class="d10"><img class="i5" src="vote.png" />VOTE: <span class="s2">123</span></div></div>
<!--<button id="end-call" onclick="endCall()">End Call</button>-->
</div>
</body>
</html>
<script>
var timer = 15;
setTimeout(setTimer1, 5000);
var interval;
function setTimer1(){
interval = setInterval(setTimer1Elapsed, 1000);
}
function setTimer1Elapsed(){
--timer;
if(timer > 0){
$("#timer1").text(timer + " seconds");
}else{
$("#record1").fadeTo(100, 0.3, function() { $(this).fadeTo(500, 1.0); });
$("#remote-video")[0].muted = !$("#remote-video")[0].muted;
$("#timer1").text("");
interval = null;
}
}
var timer2 = 15;
var interval2;
//function setTimer2AfterContestantFinish(){
setTimeout(setTimer2, 5000);
//}
function setTimer2(){
interval2 = setInterval(setTimer1Elapsed2, 1000);
}
function setTimer1Elapsed2(){
if(timer2 > 0){
$("#timer2").text(timer2 + " seconds");
}else{
$("#record2").fadeTo(100, 0.3, function() { $(this).fadeTo(500, 1.0); });
$("#local-video")[0].muted = !$("#local-video")[0].muted;
$("#timer2").text("");
interval = null;
}
--timer2;
}
var height = $(document).height() / 2 - 60;
$("#remote-video").height(height);
$("#local-video").height(height);
$("#remote-video").css("opacity", 0);
$("#local-video").css("opacity", 0);
$("#live").width($(document).width());
$("#live").height($(document).height());
var localVideo;
var localStream;
var remoteVideo;
var peerConnection;
var uuid;
var serverConnection;
var peerConnectionConfig = {
'iceServers': [
{'urls': 'stun:stun.stunprotocol.org:3478'},
{'urls': 'stun:stun.l.google.com:19302'},
]
};
pageReady();
async function pageReady() {
uuid = createUUID();
localVideo = document.getElementById('local-video');
remoteVideo = document.getElementById('remote-video');
serverConnection = new WebSocket('wss://' + "192.168.1.62" + ':8443');
serverConnection.onmessage = gotMessageFromServer;
var constraints = {
video: true,
audio: false,
};
var stream;
if(navigator.mediaDevices.getUserMedia) {
stream = await navigator.mediaDevices.getUserMedia(constraints).catch(errorHandler);
getUserMediaSuccess(stream);
} else {
alert('Your browser does not support getUserMedia API');
}
}
function getUserMediaSuccess(stream) {
alert(uuid);
$("#local-video").css("opacity", 1);
localStream = stream;
localVideo.srcObject = stream;
localVideo.play();
}
function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.ontrack = gotRemoteStream;
peerConnection.addStream(localStream);
if(isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
function gotMessageFromServer(message) {
if(!peerConnection) start(false);
var signal = JSON.parse(message.data);
// Ignore messages from ourself
if(signal.uuid == uuid) return;
if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(function() {
// Only create answers in response to offers
if(signal.sdp.type == 'offer') {
peerConnection.createAnswer().then(createdDescription).catch(errorHandler);
}
}).catch(errorHandler);
} else if(signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
function gotIceCandidate(event) {
if(event.candidate != null) {
serverConnection.send(JSON.stringify({'ice': event.candidate, 'uuid': uuid}));
}
}
function createdDescription(description) {
console.log('got description');
peerConnection.setLocalDescription(description).then(function() {
serverConnection.send(JSON.stringify({'sdp': peerConnection.localDescription, 'uuid': uuid}));
}).catch(errorHandler);
}
function gotRemoteStream(event) {
console.log('got remote stream');
remoteVideo.srcObject = event.streams[0];
}
function errorHandler(error) {
console.log("xxxxx " + error);
}
// Taken from http://stackoverflow.com/a/105074/515584
// Strictly speaking, it's not a real UUID, but it gets the job done here
function createUUID() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}
</script>
I have the local video loading, just when the start(true) is causing the error:
WebSocket is already in CLOSING or CLOSED state.
I need to have a footer which is always visible on the screen, except when the virtual keyboard is open. This is the default behaviour on iOS, however on Android the footer rises up above the keyboard. Can this be prevented?
<div class="cont">
<input />
<input />
<!-- Lots more inputs -->
</div>
<p class="footer">Footer</p>
.cont {
display: flex;
flex-direction: column;
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: blue;
color: white;
text-align: center;
height: 50px;
line-height: 50px;
}
https://codepen.io/adsfdsfhdsafkhdsafjkdhafskjds/pen/qBbROeG
here is a demo by using Jquery: https://codepen.io/nomi9995/pen/ZEQLyyy
here is a demo by using Javascript: https://codepen.io/nomi9995/pen/eYJgLbo
Actually when keyboard opens. it resize the screen. we can detect resize screen and give bottom to auto when keyboard open and give bottom to 0when keyboard close
Jquery
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
var sumedges = $(window).width() + $(window).height();
$(window).resize(function () {
if ($(window).width() + $(window).height() < sumedges) {
$(".footer").css("bottom", "auto");
} else {
$(".footer").css("bottom", "0");
}
});
}
Javascript
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
var sumedges = window.innerWidth + window.innerHeight;
window.onresize = function () {
if (window.innerWidth + window.innerHeight < sumedges) {
const footerArr = document.getElementsByClassName("footer");
for (let i = 0; i < footerArr.length; i++) {
footerArr[i].style.bottom = "auto";
}
} else {
const footerArr = document.getElementsByClassName("footer");
for (let i = 0; i < footerArr.length; i++) {
footerArr[i].style.bottom = "0";
}
}
};
}
I want to create a Group chat application based on Android and socket.io functionality just like Whatsapp.
I guess I don't really understand the question, but here is a very small simple chat room I wrote with socket.io a couple of years ago. I hope you can use it as a skeleton..
<body><ul id="Messages"></ul>
<form action="">
<input id="Message" autocomplete="off">
<input type="button" id="Send" value="Send">
</form>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$.getScript('socket.io/socket.io.js', function () {
initSocket();
});
var initSocket = function () {
var socket = io();
$('#Send').click(function () {
var userNameTag = $('#UserNameTag');
var nameTag = userNameTag.html();
if (nameTag) {
socket.emit('ioChatMessage', { text: nameTag + ': ' + $('#Message').val(), style: userNameTag[0].style });
} else {
socket.emit('ioChatMessage', { text: $('#Message').val() });
}
$('#Message').val('');
return false;
});
socket.on('ioChatMessage', function (msg) {
$('#Messages').append($('<li>').text(msg.text).css(msg.style));
});
window.onbeforeunload = function () {
socket.disconnect();
};
};
</script>
</body>
App.js
var app = require('express')();
var http = require('http').Server(app);
var socket = require('socket.io')(http);
app.get('*', function(req, res){
res.sendFile(__dirname + '/index.html');
});
socket.on('connection', function (io) {
io.on('ioChatMessage', function (msg) {
socket.emit('ioChatMessage', msg);
});
});
http.listen(process.env.PORT);
In this page you can learn how to build a chat group using socket.io in a browser:
https://socket.io/get-started/chat/
My recomendation if you want it to be an Android app is to do it like you see in the tutorial and then use Apache Cordova to make it an Android App anyone can install.
You can download it from here:
https://cordova.apache.org/
The final index.html should look like this:
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
#messages { margin-bottom: 40px }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
window.scrollTo(0, document.body.scrollHeight);
});
});
</script>
</body>
</html>
And the index.js:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var port = process.env.PORT || 3000;
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
http.listen(port, function(){
console.log('listening on *:' + port);
});
Is there any way to get the native look and feeling in Navigation drawer(Menu) in ionic v1 application rather than pushing the center content?
I want to get the Android native look and feel in ionic application like above picture.
Though this is an old question and Ionic v2+ is currently available with this native Navigation drawer features (<ion-menu>). I just thought to share some code that shows how to implement this feature in Ionic v1 app. I think it will help to those who are still using Ionic v1 in their mobile app. Also Ionic v2+ implementation could be found at the end of this post.
Ionic v1
I just created a sample Ionic v1 app using their ready-made sidemenu app template.
ionic start myApp sidemenu --type ionic1
Then I created the following nativeSideMenu.js file inside js folder.
(function () {
'use strict';
angular.module('ionic.contrib.NativeDrawer', ['ionic'])
.controller('drawerCtrl', ['$rootScope', '$scope', '$element', '$attrs', '$ionicGesture', '$ionicBody', '$document', function ($rootScope, $scope, $element, $attr, $ionicGesture, $ionicBody, $document) {
var el = document.querySelectorAll("drawer")[0];
var mainContent = angular.element(document.querySelectorAll("ion-pane")[0]);
var dragging = false;
var startX, lastX, offsetX, newX, startY, lastY, offsetY, newY;
var side;
var isOpen = false;
var primaryScrollAxis = null;
mainContent.addClass('drawer-content');
// How far to drag before triggering
var thresholdX = 10;
// How far from edge before triggering
var edgeX = 40;
// Width of drawer set in css
var drawerWidth = 270;
var LEFT = 0;
var RIGHT = 1;
var isTargetDrag = false;
var isContentDrag = false;
var width = $element[0].clientWidth;
var height = $element[0].clientHeight;
var enableAnimation = function () {
angular.element(el).addClass('animate');
};
var disableAnimation = function () {
angular.element(el).removeClass('animate');
};
// Check if this is on target or not
var isTarget = function (el) {
while (el) {
if (el === $element[0]) {
return true;
}
el = el.parentNode;
}
};
var startDrag = function (e) {
disableAnimation();
dragging = true;
offsetX = lastX - startX;
offsetY = lastY - startY;
$ionicBody.addClass('drawer-open');
};
var startTargetDrag = function (e) {
disableAnimation();
dragging = true;
isTargetDrag = true;
offsetX = lastX - startX;
offsetY = lastY - startY;
};
var doEndDrag = function (e) {
startX = null;
lastX = null;
offsetX = null;
startY = null;
lastY = null;
offsetY = null;
isTargetDrag = false;
if (!dragging) {
return;
}
dragging = false;
enableAnimation();
if (isOpen && newX < (-width / 3)) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + (-width - 5) + 'px, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
} else if (newX < (-width / 1.5)) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + (-width - 5) + 'px, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
} else {
el.style.transform = el.style.webkitTransform = 'translate3d(0px, 0, 0)';
$ionicBody.addClass('drawer-open');
isOpen = true;
}
};
var doEndContentDrag = function (e) {
if (startX > lastX) {
startX = null;
lastX = null;
offsetX = null;
startY = null;
lastY = null;
offsetY = null;
isTargetDrag = false;
isContentDrag = false;
if (!dragging) {
return;
}
dragging = false;
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(-101%, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
}
else {
el.style.transform = el.style.webkitTransform = 'translate3d(0 0, 0)';
}
};
var doDrag = function (e) {
if (e.defaultPrevented) {
return;
}
if (!lastX) {
startX = e.gesture.touches[0].pageX;
}
if (!lastY) {
startY = e.gesture.touches[0].pageY;
}
lastX = e.gesture.touches[0].pageX;
lastY = e.gesture.touches[0].pageY;
if (!dragging) {
// Dragged 15 pixels and finger is by edge
if (Math.abs(lastX - startX) > thresholdX) {
if (isTarget(e.target)) {
startTargetDrag(e);
} else if (startX < edgeX) {
startDrag(e);
}
}
// Closing from outside of drawer
else if (isOpen && startX > width) {
disableAnimation();
dragging = true;
isContentDrag = true;
}
} else {
newX = Math.min(0, (-width + (lastX - offsetX)));
newY = Math.min(0, (-height + (lastY - offsetY)));
var absX = Math.abs(lastX - startX);
var absY = Math.abs(lastY - startY);
if (isContentDrag && lastX < startX) {
var drawerOffsetX = lastX - drawerWidth;
el.style.transform = el.style.webkitTransform = 'translate3d(' + -absX + 'px, 0, 0)';
}
else if (isTargetDrag && absX > absY + 5) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
} else {
el.style.transform = el.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
}
}
if (dragging) {
e.gesture.srcEvent.preventDefault();
}
};
side = $attr.side == 'left' ? LEFT : RIGHT;
var dragFunction = function (e) {
if (el.attributes.candrag) {
doDrag(e);
}
};
var dragEndFunction = function (e) {
if (el.attributes.candrag) {
doEndDrag(e);
}
};
var onContentDrag = function (e) {
if (isOpen) {
doDrag(e);
}
};
var onContentTap = function (e) {
if (isOpen) {
closeDrawer();
e.gesture.srcEvent.preventDefault();
}
};
var contentDragEndFunction = function (e) {
if (isOpen) {
doEndContentDrag(e);
e.gesture.srcEvent.preventDefault();
}
};
var openDrawer = function () {
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(0%, 0, 0)';
$ionicBody.addClass('drawer-open');
isOpen = true;
};
var closeDrawer = function () {
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(-101%, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
};
var toggleDrawer = function () {
if (isOpen) {
closeDrawer();
} else {
openDrawer();
}
};
this.close = function () {
closeDrawer();
};
$rootScope.toggleDrawerRoot = function () {
toggleDrawer();
};
this.open = function () {
openDrawer();
};
this.toggle = function () {
toggleDrawer();
};
$ionicGesture.on('drag', function (e) {
doDrag(e);
}, $document);
$ionicGesture.on('dragend', function (e) {
doEndDrag(e);
}, $document);
var dragGesture = $ionicGesture.on('drag', dragFunction, $document);
var dragEndGesture = $ionicGesture.on('dragend', dragEndFunction, $document);
var contentTapGesture = $ionicGesture.on('tap', onContentTap, mainContent);
var contentDragGesture = $ionicGesture.on('drag', onContentDrag, mainContent);
var contentDragEndGesture = $ionicGesture.on('dragend', contentDragEndFunction, mainContent);
$scope.$on('$destroy', function () {
$ionicGesture.off(dragGesture, 'drag', dragFunction);
$ionicGesture.off(dragEndGesture, 'dragend', dragEndFunction);
$ionicGesture.off(contentTapGesture, 'tap', onContentTap);
$ionicGesture.off(contentDragGesture, 'drag', onContentDrag);
$ionicGesture.off(contentDragEndGesture, 'dragend', contentDragEndFunction);
});
}])
.directive('drawer', ['$rootScope', '$ionicGesture', function ($rootScope, $ionicGesture) {
return {
restrict: 'E',
controller: 'drawerCtrl',
link: function ($scope, $element, $attr, ctrl) {
$element.addClass($attr.side);
$scope.openDrawer = function () {
ctrl.open();
};
$scope.closeDrawer = function () {
ctrl.close();
};
$scope.toggleDrawer = function () {
ctrl.toggle();
};
}
}
}])
.directive('menuAndDrawerToggle', ['$rootScope', '$ionicGesture', function ($rootScope, $ionicGesture) {
return {
controller: '',
link: function ($scope, $element, $attr) {
$element.bind('click', function () {
$rootScope.toggleDrawerRoot();
});
}
};
}])
.directive('menuAndDrawerClose', ['$ionicViewService', function ($ionicViewService) {
return {
restrict: 'AC',
require: '^drawer',
link: function ($scope, $element, $attr, ctrl) {
$element.bind('click', function () {
ctrl.close();
});
}
};
}]);
})();
And also created the following nativeSideMenu.css file inside css folder
drawer {
display: block;
position: fixed;
width: 270px;
height: 100%;
z-index: 100;
background-color:white;
}
drawer .header-menu{
margin-top:0px;
padding-top:0px;
}
drawer .header-menu ion-list .list{
padding-top:0px;
}
drawer.animate {
-webkit-transition: all ease-in-out 400ms;
transition: all ease-in-out 400ms;
}
drawer.left {
-webkit-transform: translate3d(-101%, 0, 0);
transform: translate3d(-101%, 0, 0);
box-shadow: 1px 5px 10px rgba(0,0,0,0.3);
}
drawer.right {
right: 0;
top: 0;
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
.drawer-open .drawer-content .pane, .drawer-open .drawer-content .scroll-content {
pointer-events: none;
opacity:0.2;
}
drawer .item-icon-left .icon{
font-size: 24px;
padding-bottom: 2px;
}
ion-side-menu .current a.item-content,ion-side-menu .clickable.current, drawer .current a.item-content, drawer .clickable.current {
color:#343434 !important;
}
drawer a.item-content, drawer .clickable{
color: #858585;
font-size:20px;
}
drawer .item-complex .item-content{
padding-top:16px;
padding-bottom:16px;
font-size:20px;
}
/*This section would normally have .platform-android at the front */
.platform-android4_0 drawer.left{
box-shadow: none;
border-left:0px;
border-right:0px;
}
.header-menu{
top:0px;
bottom:44px;
}
.menu .scroll-content {
top: 42px;
}
.menu-content{
box-shadow: none;
}
.drawer-open ion-pane.pane{
background-color: rgb(0,0,0);
}
.drawer-open view{
background-color: rgb(0,0,0);
}
.ion-view.pane{
transition: opacity .25s ease-in-out;
-moz-transition: opacity .25s ease-in-out;
-webkit-transition: opacity .25s ease-in-out;
}
.menu-open ion-view.pane, .drawer-open ion-view.pane{
/* opacity:0.4;
*/
}
.bar .title.no-nav{
text-align: left;
left: 0px !important;
}
.bar .button-icon.ion-navicon{
margin-left: -20px;
padding-right: 20px;
}
.bar .title{
text-align: left;
left: 16px !important;
}
.modal-wrapper .bar .title{
text-align: center;
left: 0px !important;
}
.bar .title.title-center{
text-align: center;
left: 0px !important;
right: 0px !important;
}
.ion-ios7-arrow-back:before{
content:"\f2ca";
}
.bar .button.button-icon.ion-ios7-arrow-back:before{
font-size: 17px;
line-height: 32px;
padding-right: 100px;
}
After that I added reference links to index.html file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link rel="manifest" href="manifest.json">
<!-- un-comment this code to enable service worker
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.log('Error', err));
}
</script>-->
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<link href="css/nativeSideMenu.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/nativeSideMenu.js"></script>
<script src="js/controllers.js"></script>
</head>
<body ng-app="starter">
<ion-nav-view></ion-nav-view>
</body>
</html>
Then I included the ionic.contrib.NativeDrawer in angular.module in app.js file.
angular.module('starter', ['ionic', 'starter.controllers','ionic.contrib.NativeDrawer'])
After that I updated the code of menu.html file inside templates folder like below.
<ion-side-menus>
<ion-side-menu-content>
<ion-nav-bar class="bar-stable bar-positive-900">
<ion-nav-back-button>
</ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" menu-and-drawer-toggle>
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-pane drawer-menu-content>
<ion-nav-view name="menuContent"></ion-nav-view>
</ion-pane>
</ion-side-menu-content>
<drawer side="left">
<ion-content>
<ion-list>
<ion-item menu-and-drawer-close ng-click="login()">
Login
</ion-item>
<ion-item menu-and-drawer-close href="#/app/search">
Search
</ion-item>
<ion-item menu-and-drawer-close href="#/app/browse">
Browse
</ion-item>
<ion-item menu-and-drawer-close href="#/app/playlists">
Playlists
</ion-item>
</ion-list>
</ion-content>
</drawer>
</ion-side-menus>
Now just run the ionic serve and have the native feeling in Navigation drawer.
Use bellow reference links for more details
Ref. 1
Ref. 2
Ref. 3
Ionic v2+
We do not have that much of work to do in Ionic v2+ because by default it is giving the native feeling of the Navigation drawer. But we could change that behavior by passing the value to type on the <ion-menu>
<ion-menu type="overlay" [content]="mycontent">...</ion-menu>
According to DOC type details as bellow.
The display type of the menu. Default varies based on the mode, see
the menuType in the config. Available options: "overlay", "reveal",
"push".
Hope this will help to someone else!
In android application i want the touch or mouse swipe which swipe the data which is present in footer.in phonegap i am making the android application plz help me out how to write a jquery script and css3 for these swipe event
in jquery:-
function get_Menu_List() {
window.my_cat_index=0;
$(location).attr('href', '#menu_list');
$.support.cors = true;
$.ajax({
type: "GET",
url: "xyz.html",
contentType: "text/xml",
dataType: "xml",
data: "",
crossDomain:true,
success: function(xml) {
$(xml).find('category').each(function(){
var menu_cat_id = $(this).find('id').text();
var menu_cat_title = $(this).find('title').text();
my_cat_index++;
$('#scroller').append('<li class="selected" id="envy_cat_ID'+my_cat_index+'"><span>'+menu_cat_title+'</span></li>');
});
in html5:-
<div data-role="page" id="menu_list">
<div data-role="footer" data-position="fixed" id="footer_ids" data-theme="c">
<div class="titles" id="wrapper" onmousedown="startReverseSlider(event)" ontouchstart="startReverseSlider(event)">
<ul id="scroller" ></ul>
</div>
<div class="sliderOuterDiv" >
<div class="sliderThumb" onmousedown="start(event)" ontouchstart="start(event)" style="width: 1263.3445783132531px;"></div>
</div>
</div>
plz tell me how to write its script part and css part plz help me out
thank in advance
Here is your answer.
In HTML 5:
<div data-role="page" data-theme="b" id="jqm-home">
<div data-role="footer" data-position="fixed" data-theme="c">
<div class="categories" id="cat">
<ul id="cat_list" class="cat_list_class"></ul>
</div>
</div>
In Jquery:
var step = 1;
var current = 0;
var maximum = 0;
var visible = 2;
var speed = 500;
var liSize = 120;
var height = 60;
var ulSize = liSize * maximum;
var divSize = liSize * visible;
$(document).unbind('pageinit').bind('pageinit', function () {
callMenuConnection();
$('.categories').css("width", "auto").css("height", height+"px").css("visibility", "visible").css("overflow", "hidden").css("position", "relative");
$(".categories ul a").css("list-style","none").css("display","inline");
$(".categories ul").css("width", ulSize+"px").css("left", -(current * liSize)).css("position", "absolute").css("white-space","nowrap").css("margin","0px").css("padding","5px");
});
$(document).unbind('click').bind('click', function () {
scroll();
});
function callMenuConnection() {
$.support.cors = true;
$.ajax({
type: "GET",
url: "one.html",
contentType: "text/xml",
dataType: "xml",
data: "",
cache:false,
processData:false,
crossDomain:true,
success: processSuccess,
error: processError
});
}
var scripts ="";
function processSuccess(data) {
$(data).find("category").each(function () {
var id = $(this).find('id').text();
var title = $(this).find('title').text();
scripts = scripts+'<a class="ids_cat" data-role="button" data-transition="slide" data-inline="true" >' +title+ '</a>';
});
$('#cat_list').append(scripts);
$('#cat_list').trigger('create');
maximum = $(".categories ul a").size();
}
function processError(data)
{
alert("error");
}
function scroll(){
$(".categories").swipeleft(function(event){
if(current + step < 0 || current + step > maximum - visible) {return; }
else {
current = current + step;
$('.categories ul').animate({left: -(liSize * current)}, speed, null);
}
return false;
});
$(".categories").swiperight(function(event){
if(current - step < 0 || current - step > maximum - visible) {return; }
else {
current = current - step;
$('.categories ul').animate({left: -(liSize * current)}, speed, null);
}
return false;
});
}
Is it correct.?
Finally i got the answer of these
In HTML5:-
<div data-role="page" data-theme="b" id="jqm-home">
<div data-role="footer" data-position="fixed" data-theme="c">
<div class="categories" id="cat">
<ul id="cat_list" class="cat_list_class"></ul>
</div>
</div>
In jquery:-
var step = 1;
var current = 0;
var maximum = 0;
var visible = 2;
var speed = 500;
var liSize = 120;
var height = 60;
var ulSize = liSize * maximum;
var divSize = liSize * visible;
$(document).unbind('pageinit').bind('pageinit', function () {
callMenuConnection();
$('.categories').css("width", "auto").css("height", height+"px").css("visibility", "visible").css("overflow", "hidden").css("position", "relative");
$(".categories ul a").css("list-style","none").css("display","inline");
$(".categories ul").css("width", ulSize+"px").css("left", -(current * liSize)).css("position", "absolute").css("white-space","nowrap").css("margin","0px").css("padding","5px");
});
$(document).unbind('click').bind('click', function () {
scroll();
});
function callMenuConnection() {
$.support.cors = true;
$.ajax({
type: "GET",
url: "one.html",
contentType: "text/xml",
dataType: "xml",
data: "",
cache:false,
processData:false,
crossDomain:true,
success: processSuccess,
error: processError
});
}
var scripts ="";
function processSuccess(data) {
$(data).find("category").each(function () {
var id = $(this).find('id').text();
var title = $(this).find('title').text();
scripts = scripts+'<a class="ids_cat" data-role="button" data-transition="slide" data-inline="true" >' +title+ '</a>';
});
$('#cat_list').append(scripts);
$('#cat_list').trigger('create');
maximum = $(".categories ul a").size();
}
function processError(data)
{
alert("error");
}
function scroll(){
$(".categories").swipeleft(function(event){
if(current + step < 0 || current + step > maximum - visible) {return; }
else {
current = current + step;
$('.categories ul').animate({left: -(liSize * current)}, speed, null);
}
return false;
});
$(".categories").swiperight(function(event){
if(current - step < 0 || current - step > maximum - visible) {return; }
else {
current = current - step;
$('.categories ul').animate({left: -(liSize * current)}, speed, null);
}
return false;
});
}