Does anyone know how I can remove the address bar from the Android browser to better view my web app and make it look more like a native app?
You can do that with the next code
if(navigator.userAgent.match(/Android/i)){
window.scrollTo(0,1);
}
I hope it helps you!
Here's the NON-jQuery solution that instantly removes the address bar without scrolling. Also, it works when you rotate the browser's orientation.
function hideAddressBar(){
if(document.documentElement.scrollHeight<window.outerHeight/window.devicePixelRatio)
document.documentElement.style.height=(window.outerHeight/window.devicePixelRatio)+'px';
setTimeout(window.scrollTo(1,1),0);
}
window.addEventListener("load",function(){hideAddressBar();});
window.addEventListener("orientationchange",function(){hideAddressBar();});
It should work with the iPhone also, but I couldn't test this.
If you've loaded jQuery, you can see if the height of the content is greater than the viewport height. If not, then you can make it that height (or a little less). I ran the following code in WVGA800 mode in the Android emulator, and then ran it on my Samsung Galaxy Tab, and in both cases it hid the addressbar.
$(document).ready(function() {
if (navigator.userAgent.match(/Android/i)) {
window.scrollTo(0,0); // reset in case prev not scrolled
var nPageH = $(document).height();
var nViewH = window.outerHeight;
if (nViewH > nPageH) {
nViewH -= 250;
$('BODY').css('height',nViewH + 'px');
}
window.scrollTo(0,1);
}
});
Referring to Volomike's answer, I would suggest replacing the line
nViewH -= 250;
with
nViewH = nViewH / window.devicePixelRatio;
It works exactly as I check on a HTC Magic (PixelRatio = 1) and a Samsung Galaxy Tab 7" (PixelRatio = 1.5).
The one below works for me every time..
This site also has a few other suggestions, but this no-nonsense, no-worry one is available in a github:gist and answers your question (pasted here for convenience):
function hideAddressBar()
{
if(!window.location.hash)
{
if(document.height < window.outerHeight)
{
document.body.style.height = (window.outerHeight + 50) + 'px';
}
setTimeout( function(){ window.scrollTo(0, 1); }, 50 );
}
}
window.addEventListener("load", function(){ if(!window.pageYOffset){ hideAddressBar(); } } );
window.addEventListener("orientationchange", hideAddressBar );
As far as I can tell, the combination of extra height added to the page (which caused problems for you) and the scrollTo() statement make the address bar disappear.
From the same site the 'simplest' solution to hiding the address bar is using the scrollTo() method:
window.addEventListener("load", function() { window.scrollTo(0, 1); });
This will hide the address bar until the user scrolls.
This site places the same method inside a timeout function (the justification is not explained, but it claims the code doesn't work well without it):
// When ready...
window.addEventListener("load",function() {
// Set a timeout...
setTimeout(function(){
// Hide the address bar!
window.scrollTo(0, 1);
}, 0);
});
The problem with most of these is that the user can still scroll up and see the addressbar.
To make a permanent solution, you need to add this as well.
//WHENEVER the user scrolls
$(window).scroll(function(){
//if you reach the top
if ($(window).scrollTop() == 0)
//scroll back down
{window.scrollTo(1,1)}
})
this works on android (at least on stock gingerbread browser):
<body onload="document.body.style.height=(2*window.innerHeight-window.outerHeight)+'px';"></body>
further if you want to disable scrolling you can use
setInterval(function(){window.scrollTo(1,0)},50);
Here's an example that makes sure that the body has minimum height of the device screen height and also hides the scroll bar. It uses DOMSubtreeModified event, but makes the check only every 400ms, to avoid performance loss.
var page_size_check = null, q_body;
(q_body = $('#body')).bind('DOMSubtreeModified', function() {
if (page_size_check === null) {
return;
}
page_size_check = setTimeout(function() {
q_body.css('height', '');
if (q_body.height() < window.innerHeight) {
q_body.css('height', window.innerHeight + 'px');
}
if (!(window.pageYOffset > 1)) {
window.scrollTo(0, 1);
}
page_size_check = null;
}, 400);
});
Tested on Android and iPhone.
I hope it also useful
window.addEventListener("load", function()
{
if(!window.pageYOffset)
{
hideAddressBar();
}
window.addEventListener("orientationchange", hideAddressBar);
});
Finally I Try with this. Its worked for me..
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ebook);
//webview use to call own site
webview =(WebView)findViewById(R.id.webView1);
webview.setWebViewClient(new WebViewClient());
webview .getSettings().setJavaScriptEnabled(true);
webview .getSettings().setDomStorageEnabled(true);
webview.loadUrl("http://www.google.com");
}
and your entire main.xml(res/layout) look should like this:
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/webView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
don't go to add layouts.
I found that if you add the command to unload, he keeps down the page, ie the page that move!
Hope it works with you too!
window.addEventListener("load", function() { window.scrollTo(0, 1); });
window.addEventListener("unload", function() { window.scrollTo(0, 1); });
Using a 7-inch tablet with android, www.kupsoft.com visit my website and check how it behaves page, I use this command in my portal.
Related
I am using appium and webdriverIO to automate android native app. I need to perform scroll down and i have used
ele.scrollIntoView(true) //this returns not yet implemented error
is there any other way to scroll down?
I don't used java script to scroll down. but I have already given a detail answer with different approach (by some text, element and screen size). Please have a look on it.
How to reach the end of a scroll bar in appium?
Hope it will help.
I have find a way to perform swipe down by calling JsonWireProtocol api directly from my code.
https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol
here is my code
module.exports.scrollAndroid = function (ele) {
console.log('driver.sessionID = ', driver.sessionId);
while (!$(ele).isDisplayed()) { . //$(ele)=$(//xpath or any other attribute)
this.scrollAPICall();
driver.pause(3000);
}
};
module.exports.scrollAPICall = function () {
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
console.log("result status >> ", this.status);
console.log("result text >> ", this.responseText);
};
url1 = `http://127.0.0.1:4723/wd/hub/session/${driver.sessionId}/touch/flick`;
xhttp.open('POST', url1);
console.log("URL >> ", url1)
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.setRequestHeader("charset", "UTF-8");
xhttp.send(JSON.stringify({
xspeed: 10,
yspeed: -100,
}));
if you want to scroll up then give yspeed as + value. ex:100
You can achieve a scroll down by performing a Screen Swipe Up action. Implementation of swipe class can be found from Boilerplate project. The Gestures.js class has all required functions. Here is the link to class
Please keep in mind that the swipe is performed based on the percentage. Once you implement this Gestures class you can then use it like below:
while(!element.isDisplayed()) {
Gestures.swipeUp(0.5)
}
I'm building a little browser app using android webview and I've been using window.getSelection() in javascript to get the nature of any text selected by the user and show a custom context menu based on the type of the selection i.e. whether it's a range, a carat, whether it's in a contenteditable etc.
This works fine unless the selection is in an iframe, then the browser security measures kick in and prevent me sniffing what has been selected using window.getSelection(). How can I workaround this?
Ideally I need a way to get better information about what was selected from the webview or if that's not possible I need a way to sniff whether the selection occurred in an iframe so I can disable my custom context menu logic and fallback to the default android context menu.
UPDATE/FURTHER CLARIFICATION 07/05/2019:
Seems I wasn't clear enough in my initial description...
My goal is to have a visually and functionally custom menu when selecting content in the webview that can cut/copy/paste as the standard context menu does in any part of the page/iframes etc. e.g.
I realised my original approach using javascript to detect the type of selection and to perform the cut/copy/paste was wrong because it will be blocked by cross origin security in iframes.
What I need is a native android/webview based approach. I've discovered that I can sniff the type of selection in the webview by looking at the items in mode.getMenu() on onActionModeStarted. This will allow me to show the correct buttons in my custom menu UI but I have been unable to manually trigger the same logic that gets called when cut/copy/paste is clicked. I thought I found the solution with webView.performAccessibilityAction(AccessibilityNodeInfo.ACTION_CUT, null); but this doesn't work for some reason so I guess my question really is how can I manually trigger cut/copy/paste on the selected text from webview without using javascript? or any other approach that will allow me to have a custom selection menu with lots of options based on what was selected without hitting the browser security limitations?
Okay I figured out how roughly how to do this.
Step 1) In your activity, override onActionModeStarted and check the menu items available in the default context menu. This gives you a clue as to what the type of selection is and which buttons you will need to show in your custom menu. Also it gives you a reference to the item ID which you can use to later to trigger the action e.g.
systemSelectionMenu = mode.getMenu(); // keep a reference to the menu
MenuItem copyItem = systemSelectionMenu.getItem(0); // fetch any menu items you want
copyActionId = copyItem.getItemId(); // store reference to each item you want to manually trigger
Step 2) Instead of clearing the menu, use setVisible() to hide each menu item you want a custom button for e.g.
copyItem.setVisible(false);
Step 3) In your custom button onclick event you can trigger the copy action using:
myActivity.systemSelectionMenu.performIdentifierAction(myActivity.copyActionId, 0)
You can retrieve iframe's selection only if it has the same origin. Otherwise, you have no chances to track any iframe's events(clicks, touches, key presses, etc.).
const getSelectedText = (win, doc) => {
const isWindowSelectionAvailable = win && typeof win.getSelection != "undefined";
if (isWindowSelectionAvailable) {
return win.getSelection().toString();
}
const hasDocumentSelection = doc && typeof doc.selection != "undefined" && doc.selection.type == "Text";
if (hasDocumentSelection) {
return doc.selection.createRange().text;
}
return '';
}
const doIfTextSelected = (win, doc, cb) => () => {
const selectedText = getSelectedText(win, doc);
if (selectedText) {
cb(selectedText);
}
}
const setupSelectionListener = (win, doc, cb) => {
doc.onmouseup = doIfTextSelected(win, doc, cb);
doc.onkeyup = doIfTextSelected(win, doc, cb);
}
const getIframeWinAndDoc = (iframe) => {
try {
const doc = iframe.contentDocument || iframe.contentWindow.document;
const win = iframe.contentWindow || iframe.contentDocument.defaultView;
return { win, doc };
} catch (e) {
console.error(`${e}`);
return {};
}
}
const callback = console.log;
setupSelectionListener(window, document, callback);
document.querySelectorAll('iframe').forEach(iframe => {
const { win, doc } = getIframeWinAndDoc(iframe, console.log);
// Only for same origin iframes due to https://en.wikipedia.org/wiki/Same-origin_policy
if (win && doc) {
setupSelectionListener(win, doc, callback);
}
})
<h3>Select me</h3>
<div class="container">
<iframe src="https://teimurjan.github.io"></iframe>
</div>
This issue varying from browser to other if it works with internet explorer so it may fall with chrome
Try this
App.util.getSelectedText = function(frameId) {
var frame = Ext.getDom(frameId);
var frameWindow = frame.contentWindow;
var frameDocument = frameWindow.document;
if (frameDocument.getSelection) {
return frameDocument.getSelection();
}
else if (frameDocument.selection) {
return frameDocument.selection.createRange().text;
}
};
Hope it runs fine
Main problem is the window.getSelection() will return selection only for the main context/window. As iframe is the other window and other context, you should call getSelection() from iframe which is "current".
I'm developing a cross platform app using cordova with an angular material front end.
I use HTML5 video tags in a list of md-cards to play videos with external urls. When inline the videos play correctly, and display the native controls as expected.
<video class="project-video" video-directive item="$ctrl.project" ng-src="{{$ctrl.project.videoUrl | trustUrl}}" preload="auto"
controls poster="{{$ctrl.project.video.thumbnail_url}}">
Your browser does not support the video tag.
</video>
However when I click the "toggle full-screen" button the video does go to full-screen, but the default controls disappear. I cannot get back to the app after this - the native android back button does not close the full screen - instead it closes the whole app.
The solution I am looking for will make the controls always appear even in full screen mode; this works out the box running the same code on iOS.
Therefore I do not want to spend time developing my own custom video controls just for android, if I can help it! So please do not post answers about how to do that (plenty already available on SO and elsewhere).
I am using a Meizu m2 note android device.
Thanks!
EDIT:
The controls are still there but are showing up in the shadow DOM tree in css as being of size 0 x 0px. Even when I change their size in chrome dev tools using the !important flag, they do not show up.
Any ideas?
This is an issue with Flyme OS which is used by Meizu devices. Since the controls are available and not visible, this should be resolved by ugrading the Flyme OS.
Please update Flyme OS to resolve this as the older versions of Flyme seems to have quiet some problems with fullscreen video mode. Hope it helps. Cheers
set the values which then allow to exit fullscreen.
var videoElement = document.getElementById("myvideo");
function toggleFullScreen() {
if (!document.mozFullScreen && !document.webkitFullScreen) {
if (videoElement.mozRequestFullScreen) {
videoElement.mozRequestFullScreen();
} else {
videoElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
}
document.mozFullScreen = true;
document.webkitFullScreen = true;
} else {
if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else {
document.webkitCancelFullScreen();
}
}
}
document.addEventListener("keydown", function(e) {
if (e.keyCode == 13) {
toggleFullScreen();
}
}, false);
add these two lines ..
document.mozFullScreen = true;
document.webkitFullScreen = true;
if you want something better
fullScreenButton.addEventListener("click", function() {
if (!document.fullscreenElement && // alternative standard method
!document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement ) { // current working methods
if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.msRequestFullscreen) {
video.msRequestFullscreen();
} else if (video.mozRequestFullScreen) {
video.mozRequestFullScreen();
} else if (video.webkitRequestFullscreen) {
video.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}
});
How about this in your code your not mentioned controls attribute fully may be that could cause the problem
<video id="myvideo">
<source src="path/to/movie.mp4" />
</video>
<p onclick="toggleControls();">Toggle</p>
<script>
var video = document.getElementById("myvideo");
function toggleControls() {
if (video.hasAttribute("controls")) {
video.removeAttribute("controls")
} else {
video.setAttribute("controls","controls")
}
}
</script>
My question is exactly the same as this one but for Android and not iOS.
Get URL from remote URL in webview and open it in safari
Anyone have an idea. I am creating a cross-platform app and I have used the Clayton's answer to get it to work for iOS with some tweaks to open with a controller. But when trying different methods on Android and it is not working. This is as close as I have gotten (which is what Aaron provided on that same page) and it is not quite right as it opens the remote web page in a new browser window as well in the apps webview:
$.floorView.addEventListener('load', function(e) {
if (e.url.indexOf("http") !== -1) {
// stop the event
e.bubble = false;
// stop the url from loading
$.floorView.stopLoading();
// open
Ti.Platform.openURL(e.url);
}
});
Thanks!
I'd listen to the beforeload event, although I'm not 100% sure if you can actually prevent the Webview from still continuing the load as well.
Another way would be to intercept these links via JS you load or inject (evalJS()) in the webpage. Then fire a Ti.App event and respond to it in Titanium.
The Titanium.UI.Webview has a specific property for intercepting links: onlink.
This is not implemented as an event because it is a callback and needs to return a boolean to tell the Webview whether or not to load the URL of the link.
Oddly, setting the onlink callback right away makes the URL immediately load in Safari, so I did it this way:
$.webview.addEventListener('load', function(e) {
$.webview.onlink = function(e) {
Ti.Platform.openURL(e.url);
return false;
};
});
You can of course check the e.url string and decide whether to open it internally or externally.
I think I may have figured it out. Thanks to those whose ideas and suggestions lead to this code.
It appears to be working as I want on iOS and Android. Any suggestions or issues that you guys have I would appreciate the feedback. Thanks!
if ("iOS") {
$.webView.addEventListener('beforeload', function(e) {
if (e.navigationType == Titanium.UI.iOS.WEBVIEW_NAVIGATIONTYPE_LINK_CLICKED) {
// stop the event
e.bubble = false;
// stop the url from loading
$.webView.stopLoading();
//opens up the clicked URL for bill in new webView
var link = e.url;
var args = {url: link,};
// open link in my default webView for iOS
var newWebView=Alloy.createController('defaultWebView', args).getView();
newWebView.open();
}
});
}
else if ("Android") {
$.webView.addEventListener('beforeload', function(e) {
if (e.url.indexOf("http") !== -1) {
function Parser(text) {
var html = text;
var urlRegex = /((http|https):\/\/(\w+:{0,1}\w*#)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%#!\-\/]))?)/gi;
this.getHTML = function() {
return html;
};
} // end Parser
var parser = new Parser(e.url);
html = parser.getHTML();
if (html != "url of $.webView") {
// stop it from loding in current webView
$.webView.stopLoading();
// open link in browser
Ti.Platform.openURL(html);
}
}
});
}
else {
.....................
}
I'm working on making an Android app using Phonegap and AngularJS. I'm attempting to create a button to be used as both a "cancel" and a "back" button, that will essentially just hit the browser's 'back' button.
Here's some sample HTML for the cancel button:
cancel
And here is the controller for that page, with the goBack() button:
function NewOccasionCtrl($scope, $window) {
$scope.$window = $window;
$scope.goBack = function() {
$window.history.back();
};
}
This throws no errors, but also doesn't work... the emulator remains on the same page. Without the $scope.$window = $window it throws an error. I was hoping to achieve a functional 'back' button without having to create/use a directive, because as far as I understand those then implement templating and things I don't need/want.
Is there a way to do this? Thanks
I went with using a Directive to make the back functionality reusable. Here is my final code:
HTML:
<a href back-button>back</a>
Javascript:
app.directive('backButton', function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', goBack);
function goBack() {
history.back();
scope.$apply();
}
}
}
});
I had an issue like this using phonegap and angular, $window.history.back() would not work. So I created a workaround.
$scope.urlHistory = [];
$scope.$on('$routeChangeSuccess', function () {
if ($location.$$absUrl.split('#')[1] !== $scope.urlHistory[$scope.urlHistory.length - 1]) {
$scope.urlHistory.push($location.$$absUrl.split('#')[1]);
}
});
$scope.goBack = function () {
$scope.urlHistory.pop();
$location.path($scope.urlHistory[$scope.urlHistory.length - 1]);
};
Hope this help someone else.