I have an issue with trying to resizing IE11 in kiosk mode but launching in kiosk mode would force it to go fullscreen but if I turn off kiosk mode, the toolbar & navbar, etc. will all be visible which is not what I want to prevent user from editing the url, so I would I be able to achieve that? I tried using JS, but it didnt work. Is it possible to do it without using JS?
I tried Process p = new ProcessBuilder("cmd.exe", "/c", "start iexplore -k javascript:resizeTo(400,300)\"" + newUrl +"\"").inheritIO().start(); , but it prompt save file dialog, instead of resizing.
Tried this too javascript:moveTo(0,0);resizeTo(1024,768);}, cant find out what is wrong for that, since the console is disabled in kiosk mode.
Currently using java-8.
private static String newUrl = replaceUserID(url);
public static void main(String[] args) {
try{
Process p = new ProcessBuilder("cmd.exe", "/c", "start iexplore -k \"" + newUrl +"\"").inheritIO().start();
resizeBrowser();
try{
p.waitFor();
}
catch( InterruptedException ie ){
System.out.println("InterruptedException " + ie.getMessage());
}
InputStream err = p.getErrorStream();
int ctr = 0;
if ( (ctr = err.available()) > 0 ){
byte[] buf = new byte[ctr];
System.out.println("Process failed with error:\n" + new String(buf, 0, ctr));
}
}
catch(IOException ioe)
{
System.out.println("InterruptedException " + ioe.getMessage());
}
}
public static void resizeBrowser() {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine javaScript = scriptEngineManager.getEngineByName("nashorn");
try {
javaScript.eval("function resizeIE(){"
+ "newWindow = window.open(\"" + newUrl + "\", IEWindow, resizable);"
+ "newWindow.resizeTo(500,400);}");
}catch (ScriptException e) {
e.printStackTrace();
}
}
I'm afraid it's impossible to resize IE kiosk window. Kiosk mode means run browser in fullscreen window. You can't tell the browser to run in fullscreen and non-fullscreen window at the same time. That doesn't make any sense.
For similar thread, you can also refer to this link.
Related
I would like to set an NDEF message on my website if it is opened from android chrome and read it with an NFC Reader using nfcpy.
According to https://developer.mozilla.org/en-US/docs/Web/API/NDEFMessage/NDEFMessage I think I should be able to do this.
My page looks like this:
<button onclick="set_ndef()">Set NDEF msg</button>
<pre id="log"></pre>
<script>
async function set_ndef() {
if ("NDEFReader" in window) {
try {
const ndefmsg = new NDEFMessage({'records': [{'recordType': 'text', 'data': 'asd'}]});
consoleLog(ndefmsg)
} catch(error) {
consoleLog(error);
}
} else {
consoleLog("Web NFC is not supported.");
}
}
function consoleLog(data) {
var logElement = document.getElementById('log');
logElement.innerHTML += data + '\n';
}
</script>
The website uses HTTPS, and when I press the button an NDEFRecord object is printed into the div.
I have an acr122u NFC reader, which I was able to set up using nfcpy:
import nfc
import time
def on_connect(tag):
print(tag.identifier.hex())
tag_ident = tag.identifier.hex()[:8]
print(tag.ndef)
if tag.ndef:
for record in tag.ndef:
print(record)
return True
while True:
with nfc.ContactlessFrontend('usb') as clf:
tag = clf.connect(rdwr={'on-connect': on_connect, 'beep-on-connect': True})
time.sleep(1)
After I place my phone on the reader (after pressing the button on the page) I am only able to read the UID of the phone, but the tag.ndef is None
How can I do this (if I am even able to)?
https://stackoverflow.com/a/65659726/2373819 should give you some background as why this won't work, Android Chrome NFC is an NFC reader and 2 readers won't work.
Though with the acr122u NFC reader can usually be configure to behave as an NFC Tag, then Android Chrome should be able read and write NDEF messages to it (https://nfcpy.readthedocs.io/en/latest/topics/get-started.html#emulate-a-card)
I am using webview to show and edit the content in my UWP application. I want to disable the scrolling within the Webview control and make it adapt the height just to fit the entire content it has. And then it should respect the scrolling of it's parent control's scrollviewer. I have uploaded a sample application on OneDrive here: https://1drv.ms/u/s!AhChIerZubKRjQKBH5nA0KGTtPYP
In the sample app, you can see that once you reach at the end of the scrollviewer, the webview will start scrolling within itself. Instead what I would like to do is, keep scrolling (the parent scrollviewr) to the end of the webview.
Edit: Here's the code:
MainPage.xaml:
<ScrollViewer VerticalScrollBarVisibility="Auto" VerticalScrollMode="Auto" Height="200" Width="400">
<StackPanel>
<Button Content="Navigate web page 1"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Click="Button_Click"/>
<Button Content="Navigate web page 2"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Click="Button_Click_1"/>
<Button Content="Navigate web page 3"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Click="Button_Click_2"/>
<Button Content="Navigate web page 4"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Click="Button_Click_3"/>
<WebView Name="WebView" Width="400" MinHeight="200"></WebView>
</StackPanel>
</ScrollViewer>
MainPage.xaml.cs:
public sealed partial class MainPage : Page
{
private const string EditableParameter = "~editable~";
private const string SetBodyEditableScript = #"
try
{
document.body.contentEditable = '" + EditableParameter + #"';
}
catch(e)
{
}";
private const string SetTextFromClipBoardFunctionName = "setTextFromClipBoard";
private const string SetHtmlTextFromClipboardFunction =
"function " + SetTextFromClipBoardFunctionName + #"(htmlFromClipboard)
{
if (window.getSelection)
{
var range;
var sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
var el = document.createElement('div');
el.innerHTML = htmlFromClipboard + '<span></span>';
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
range.collapse(false);
window.external.notify('RefreshAndReportHtml');
}
else if (typeof document.selection != 'undefined' && document.selection.type != 'Control') {
var html = (node.nodeType == 1) ? node.outerHTML : node.data;
html += '<span></span>';
var textRange = document.selection.createRange();
textRange.pasteHTML(html);
textRange.collapse(false);
window.external.notify('RefreshAndReportHtml');
}
}
};";
private const string GetHtmlFunctionName = "getHtml";
private const string GetHtmlFunction =
"function " + GetHtmlFunctionName + #"(skipParam)
{
return document.documentElement.innerHTML;
};";
public MainPage()
{
this.InitializeComponent();
MakeWebviewEditable();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//(Window.Current.Content as Frame).Navigate(typeof(WebviewPage), "http://tsn.ua");
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
//(Window.Current.Content as Frame).Navigate(typeof(WebviewPage), "http://buzzfeed.com");
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
//(Window.Current.Content as Frame).Navigate(typeof(WebviewPage), "http://microsoft.com");
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
//(Window.Current.Content as Frame).Navigate(typeof(WebviewPage), "http://cnn.com");
}
private const string EventNotificationFormat = #"window.external.notify('{0}');";
private async void MakeWebviewEditable()
{
WebView.NavigateToString("I do not know how that about righting wrongs can be, said the bachelor, for from 707" +
"straight you have made me crooked, leaving me with a broken leg that will never see itself straight again all the days of its life and the injury you have redressed in my case" +
"has been to leave me injured in such a way that I shall remain injured for ever and the height of misadventure it was to fall in with you who go in search of adventures." +
"I do not know how that about righting wrongs can be, said the bachelor, for from 707" +
"straight you have made me crooked, leaving me with a broken leg that will never see itself straight again all the days of its life and the injury you have redressed in my case" +
"has been to leave me injured in such a way that I shall remain injured for ever and the height of misadventure it was to fall in with you who go in search of adventures.");
//await InjectJavaScriptAsync(SetBodyEditableScript.Replace(EditableParameter, "true"));
await InjectJavaScriptAsync("document.designMode='on'");
await InjectJavaScriptAsync(GetHtmlFunction);
}
private async Task InjectJavaScriptAsync(string jscript)
{
await WebView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
try
{
// Only execute JS if a document is fully loaded. This should eliminate JS exception related to UNKNOWN name errors.
//if (IsHtmlLoaded)
string result = await WebView.InvokeScriptAsync("eval", new string[] { jscript });
}
catch (Exception ex)
{
}
});
}
}
Can it be done?
To autosize WebView according to its HTML content, we can try with following code:
private async void WebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
var webView = sender as WebView;
int width;
int height;
// get the total width and height
var widthString = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth.toString()" });
var heightString = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight.toString()" });
if (!int.TryParse(widthString, out width))
{
throw new Exception("Unable to get page width");
}
if (!int.TryParse(heightString, out height))
{
throw new Exception("Unable to get page height");
}
// resize the webview to the content
webView.Width = width;
webView.Height = height;
}
And then we can use this method in XAML like:
<WebView Name="WebView" Width="400" MinHeight="200" NavigationCompleted="WebView_NavigationCompleted"/>
Or in code-behind:
public MainPage()
{
this.InitializeComponent();
MakeWebviewEditable();
this.NavigationCacheMode = NavigationCacheMode.Required;
WebView.NavigationCompleted += WebView_NavigationCompleted;
}
Here I used WebView.NavigationCompleted event because we need to make sure the current content has loaded before we try to get the content's width and height.
Update:
While on Windows 10 Mobile, above method might not completely work. This is because WebView on Windows 10 Mobile is not compatible with parent controls that require gestures to propagate up from the WebView control to the parent, such as FlipView, ScrollViewer class, and other related controls.
Ref Remarks of WebView class:
By default, WebView content is hosted on the UI thread on devices in the desktop device family, and off the UI thread on all other devices. You can use the WebView.DefaultExecutionMode static property to query the default threading behavior for the current client. If necessary, you can use the WebView(WebViewExecutionMode) constructor to override this behavior.
Note There might be performance issues when hosting content on the UI thread on mobile devices, so be sure to test on all target devices when you change DefaultExecutionMode.
A WebView that hosts content off the UI thread is not compatible with parent controls that require gestures to propagate up from the WebView control to the parent, such as FlipView, ScrollViewer, and other related controls. These controls will not be able to receive gestures initiated in the off-thread WebView.
As a workaround, usually we can try using something like
WebView WebView = new WebView(WebViewExecutionMode.SameThread);
in code-behind instead of creating web browser in XAML to solve this problem. However as the Note said, hosting content on the UI thread on mobile devices is not a good practice and in my test, this will cause HTML content can't be editable. So this may be not an acceptable solution for your question.
I'm not sure what do you want to achieve. Based on your requirement, you can try like #DecadeMoon said to put the buttons into HTML page. Or you can get the content of the HTML into a RichEditBox. Or you can change your layout and just put the WebView outside the ScrollViewer.
So you're saying you want the height of the WebView control to equal the height of the webpage it is displaying? I don't think that's possible. I imagine the WebView would employ some form of rendering optimizations such that it doesn't need to render what's not visible in the viewport. If the entire height of the webpage is visible, then it has to render everything which would be terrible for performance.
It looks like you're trying to control the webpage directly through the WebView by injecting javascript. You're going to have a hard time doing that. If there's no way to achieve what you want in XAML only, then maybe you can rewrite your app in WinJS instead?
The easiest way to achieve what you want would be to put the buttons directly in the webpage and notify the host when they are clicked so you can act.
XAML
<Grid>
<WebView x:Name="webView" ScriptNotify="webView_ScriptNotify" Height="300"/>
</Grid>
CS
private void prepareWebViewContent()
{
var html = #"
<style>
button {
padding: 15px 20px;
font-size: 40px;
border: none;
background-color: #ccc;
font-family: inherit;
display: block;
margin: 10px auto;
}
button:active {
background-color: #aaa;
}
</style>
<button onclick=""window.external.notify('Navigate1')"">Navigate to web page 1</button>
<button onclick=""window.external.notify('Navigate2')"">Navigate to web page 2</button>
<p>
I do not know how that about righting wrongs can be, said the bachelor, for from 707
straight you have made me crooked, leaving me with a broken leg that will never see itself straight again all the days of its life and the injury you have redressed in my case
has been to leave me injured in such a way that I shall remain injured for ever and the height of misadventure it was to fall in with you who go in search of adventures.
I do not know how that about righting wrongs can be, said the bachelor, for from 707
straight you have made me crooked, leaving me with a broken leg that will never see itself straight again all the days of its life and the injury you have redressed in my case
has been to leave me injured in such a way that I shall remain injured for ever and the height of misadventure it was to fall in with you who go in search of adventures.
</p>
";
webView.NavigateToString(html);
}
private void webView_ScriptNotify(object sender, NotifyEventArgs e)
{
switch (e.Value)
{
case "Navigate1":
// Handle this case
break;
case "Navigate 2":
// Handle this case
break;
}
}
It's very rudimentary, but you get the idea.
I have the following problem, I need to disable the native Keyboard completely. The keyboard should only show when I call the show() and hide when I call the close() function (this will be on a Button for the user to toggle the Keyboard).
The Keyboard showing on clicking the Field and on Focus needs to be completely disabled.
On Stackoverflow I found this:
InputMethodManager im = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
im.hideSoftInputFromWindow(editText.getWindowToken(), 0);
So my thought was In the "Init"(Line 52 in the IonicKeyboard.java) I need to change it.
if ("init".equals(action)) {
cordova.getThreadPool().execute(new Runnable() {
public void run() {
//new Logic on init
View v = cordova.getActivity().getCurrentFocus();
((InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
DisplayMetrics dm = new DisplayMetrics();
cordova.getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
final float density = dm.density;
//http://stackoverflow.com/a/4737265/1091751 detect if keyboard is showing
final View rootView = cordova.getActivity().getWindow().getDecorView().findViewById(android.R.id.content).getRootView();
OnGlobalLayoutListener list = new OnGlobalLayoutListener() {
int previousHeightDiff = 0;
#Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
rootView.getWindowVisibleDisplayFrame(r);
PluginResult result;
int heightDiff = rootView.getRootView().getHeight() - r.bottom;
int pixelHeightDiff = (int)(heightDiff / density);
if (pixelHeightDiff > 100 && pixelHeightDiff != previousHeightDiff) { // if more than 100 pixels, its probably a keyboard...
String msg = "S" + Integer.toString(pixelHeightDiff);
result = new PluginResult(PluginResult.Status.OK, msg);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
else if ( pixelHeightDiff != previousHeightDiff && ( previousHeightDiff - pixelHeightDiff ) > 100 ){
String msg = "H";
result = new PluginResult(PluginResult.Status.OK, msg);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
previousHeightDiff = pixelHeightDiff;
}
};
rootView.getViewTreeObserver().addOnGlobalLayoutListener(list);
PluginResult dataResult = new PluginResult(PluginResult.Status.OK);
dataResult.setKeepCallback(true);
callbackContext.sendPluginResult(dataResult);
}
});
return true;
}
return false; // Returning false results in a "MethodNotFound" error.
}
Sadly this does not work at all...
I think I have to change the close / show function too but I am not really sure what the correct code is, and I dont know if this change would affect other Keyboard behaviour. (But I basically need Focus without Keyboard)
I also found this Cordova Plugin
which looks very promising, but I decided to change this in the Ionic Keyboard Plugin, because I need the same behaviour in Windows too.
Very glad if someone could help me out here.
Regards Christopher
This can be accomplished by disabling all inputs with ng-disabled and later showing the keyboard with the Ionic Keyboard Plugin.
If you do not want the inputs to appear differently when disabled, you can override this style with CSS using the :disabled selector.
Hide on load:
<input ng-disabled="hideKeyboard">
hideKeyboard = true;
Show on function:
<input ng-disabled="hideKeyboard">
function showKeyboard(){
hideKeyboard = false;
cordova.plugins.Keyboard.show();
}
i am trying to redirect a user to another page in my play project. The problem is, the redirect works quite well in one view, but it doesnt work in another view.
The strange thing is, when i look at the console -, i can see that system has loaded the view (i can see this by setting system.out.println() command" but i cant see that happening in the browser view.
Working Code:
public static void deleteMessages(boolean[] chbox)
{
System.out.println("Checkbox count: "+chbox.length);
String[] referer =Request.current().headers.get("referer").toString().split("/");
String mailbox = referer[referer.length-2];
String pageNumber ="/"+ referer[referer.length-1];
for(int i = 0; i<chbox.length;i++)
{
String id=params.getAll("hdnchbox")[i].toString();
if(mailbox.equals("inbox"))
{
MessageInbox m = MessageInbox.findById(Long.parseLong(id));
m.delete();
}else
{
MessageOutbox m = MessageOutbox.findById(Long.parseLong(id));
m.delete();
}
}
show(mailbox,Integer.parseInt(pageNumber));
}
Not Working Code:
public static void deleteMessage(Long id, String mailbox)
{
if(mailbox.toLowerCase().equals("inbox"))
{
MessageInbox msg = MessageInbox.findById(id);
msg.delete();
}
else
{
MessageOutbox msg = MessageOutbox.findById(id);
msg.delete();
}
System.out.println("Redirect URL: "+"/Messages/"+mailbox);
String redirectURL = "/Messages/"+mailbox;
show(mailbox,null);
}
The show void:
public static void show(String messageBoxName,Integer pageNumber)
{
if(pageNumber == null)
{
System.out.println("pagenumber null");
pageNumber = 0;
}
List<UserMessage> msgs = messageList(pageNumber,messageBoxName);
System.out.println("The page has loaded");
render(pageNumber,msgs,messageBoxName);
}
The strangest part is i can both see the "The page has loaded" message in the system console, but i can see it in the browser window.
is it a bug, or am i doing something wrong?
(passing null value to show() works i tried that)
This may be a bug with localVariables, I had a similar problems so times ago. Even if I reassign a variable like pageNumber, I got null in my template
Try calling "show(mailbox, 0)" instead of "show(mailbox,null)" to see if it solves your problem
i've ended up redirecting with jquery instead of play redirect command. I think this is a bug in play framework. i can see the response html in firebug but no luck on the browser screen.
How can I split the content of a HTML file in screen-sized chunks to "paginate" it in a WebKit browser?
Each "page" should show a complete amount of text. This means that a line of text must not be cut in half in the top or bottom border of the screen.
Edit
This question was originally tagged "Android" as my intent is to build an Android ePub reader. However, it appears that the solution can be implemented just with JavaScript and CSS so I broadened the scope of the question to make it platform-independent.
Building on Dan's answer here is my solution for this problem, with which I was struggling myself until just now. (this JS works on iOS Webkit, no guarantees for android, but please let me know the results)
var desiredHeight;
var desiredWidth;
var bodyID = document.getElementsByTagName('body')[0];
totalHeight = bodyID.offsetHeight;
pageCount = Math.floor(totalHeight/desiredHeight) + 1;
bodyID.style.padding = 10; //(optional) prevents clipped letters around the edges
bodyID.style.width = desiredWidth * pageCount;
bodyID.style.height = desiredHeight;
bodyID.style.WebkitColumnCount = pageCount;
Hope this helps...
Speaking from experience, expect to put a lot of time into this, even for a barebones viewer. An ePub reader was actually first big project I took on when I started learning C#, but the ePub standard is definitely pretty complex.
You can find the latest version of the spec for ePub here:
http://www.idpf.org/specs.htm
which includes the OPS (Open Publication Structure), OPF (Open Packaging Format), and OCF (OEBPS Container Format).
Also, if it helps you at all, here is a link to the C# source code of the project I started on:
https://www.dropbox.com/sh/50kxcr29831t854/MDITIklW3I/ePub%20Test.zip
It's not fleshed out at all; I haven't played with this for months, but if I remember correctly, just stick an ePub in the debug directory, and when you run the program just type some part of the name (e.g. Under the Dome, just type "dome") and it will display the details of the book.
I had it working correctly for a few books, but any eBooks from Google Books broke it completely. They have a completely bizarre implementation of ePub (to me, at least) compared to books from other sources.
Anyway, hopefully some of the structural code in there might help you out!
I've had to code something like this too, and my (working) solution is this:
You have to apply these lines to the webview...
webView_.getSettings().setUseWideViewPort(true);
webView_.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
Also, you have to inject some javascript. I've had tons of problems with the differents scales of my activity and the content rendered in the webview, so my solution doesn't take any kind of value from "outside".
webView_.setWebViewClient(new WebViewClient(){
public void onPageFinished(WebView view, String url) {
injectJavascript();
}
});
[...]
public void injectJavascript() {
String js = "javascript:function initialize() { " +
"var d = document.getElementsByTagName('body')[0];" +
"var ourH = window.innerHeight; " +
"var ourW = window.innerWidth; " +
"var fullH = d.offsetHeight; " +
"var pageCount = Math.floor(fullH/ourH)+1;" +
"var currentPage = 0; " +
"var newW = pageCount*ourW; " +
"d.style.height = ourH+'px';" +
"d.style.width = newW+'px';" +
"d.style.webkitColumnGap = '2px'; " +
"d.style.margin = 0; " +
"d.style.webkitColumnCount = pageCount;" +
"}";
webView_.loadUrl(js);
webView_.loadUrl("javascript:initialize()");
}
Enjoy :)
I recently attempted something similar to this and added some CSS styling to change the layout to horizontal instead of vertical. This gave me the desired effect without having to modify the content of the Epub in any way.
This code should work.
mWebView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// Column Count is just the number of 'screens' of text. Add one for partial 'screens'
int columnCount = Math.floor(view.getHeight() / view.getWidth())+1;
// Must be expressed as a percentage. If not set then the WebView will not stretch to give the desired effect.
int columnWidth = columnCount * 100;
String js = "var d = document.getElementsByTagName('body')[0];" +
"d.style.WebkitColumnCount=" + columnCount + ";" +
"d.style.WebkitColumnWidth='" + columnWidth + "%';";
mWebView.loadUrl("javascript:(function(){" + js + "})()");
}
});
mWebView.loadUrl("file:///android_asset/chapter.xml");
So, basically you're injecting JavaScript to change the styling of the body element after the chapter has been loaded (very important). The only downfall to this approach is when you have images in the content the calculated column count goes askew. It shouldn't be too hard to fix though. My attempt was going to be injecting some JavaScript to add width and height attributes to all images in the DOM that don't have any.
Hope it helps.
-Dan
I was able to improve Nacho's solution to get horizontal swipe paging effect with WebView. You can find solution here and example code.
Edit:
Solution code.
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
wv = (HorizontalWebView) findViewById(R.id.web_view);
wv.getSettings().setJavaScriptEnabled(true);
wv.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
injectJavascript();
}
});
wv.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
int pageCount = Integer.parseInt(message);
wv.setPageCount(pageCount);
result.confirm();
return true;
}
});
wv.loadUrl("file:///android_asset/ch03.html"); // now it will not fail here
}
private void injectJavascript() {
String js = "function initialize(){\n" +
" var d = document.getElementsByTagName('body')[0];\n" +
" var ourH = window.innerHeight;\n" +
" var ourW = window.innerWidth;\n" +
" var fullH = d.offsetHeight;\n" +
" var pageCount = Math.floor(fullH/ourH)+1;\n" +
" var currentPage = 0;\n" +
" var newW = pageCount*ourW;\n" +
" d.style.height = ourH+'px';\n" +
" d.style.width = newW+'px';\n" +
" d.style.margin = 0;\n" +
" d.style.webkitColumnCount = pageCount;\n" +
" return pageCount;\n" +
"}";
wv.loadUrl("javascript:" + js);
wv.loadUrl("javascript:alert(initialize())");
}
In my WebChromeClient's onJsAlert get the number of horizontal pages which i pass to the custom HorizontalWebView to implement paging effect
HorizontalWebView.java
public class HorizontalWebView extends WebView {
private float x1 = -1;
private int pageCount = 0;
public HorizontalWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x1 = event.getX();
break;
case MotionEvent.ACTION_UP:
float x2 = event.getX();
float deltaX = x2 - x1;
if (Math.abs(deltaX) > 100) {
// Left to Right swipe action
if (x2 > x1) {
turnPageLeft();
return true;
}
// Right to left swipe action
else {
turnPageRight();
return true;
}
}
break;
}
return true;
}
private int current_x = 0;
private void turnPageLeft() {
if (getCurrentPage() > 0) {
int scrollX = getPrevPagePosition();
loadAnimation(scrollX);
current_x = scrollX;
scrollTo(scrollX, 0);
}
}
private int getPrevPagePosition() {
int prevPage = getCurrentPage() - 1;
return (int) Math.ceil(prevPage * this.getMeasuredWidth());
}
private void turnPageRight() {
if (getCurrentPage() < pageCount - 1) {
int scrollX = getNextPagePosition();
loadAnimation(scrollX);
current_x = scrollX;
scrollTo(scrollX, 0);
}
}
private void loadAnimation(int scrollX) {
ObjectAnimator anim = ObjectAnimator.ofInt(this, "scrollX",
current_x, scrollX);
anim.setDuration(500);
anim.setInterpolator(new LinearInterpolator());
anim.start();
}
private int getNextPagePosition() {
int nextPage = getCurrentPage() + 1;
return (int) Math.ceil(nextPage * this.getMeasuredWidth());
}
public int getCurrentPage() {
return (int) (Math.ceil((double) getScrollX() / this.getMeasuredWidth()));
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
}
Maybe it would work to use XSL-FO. This seems heavy for a mobile device, and maybe it's overkill, but it should work, and you wouldn't have to implement the complexities of good pagination (e.g. how do you make sure that each screen doesn't cut text in half) yourself.
The basic idea would be:
transform the XHTML (and other EPUB stuff) to XSL-FO using XSLT.
use an XSL-FO processor to render the XSL-FO into a paged format that you can display on the mobile device, such as PDF (can you display that?)
I don't know whether there is an XSL-FO processor available for Android. You could try Apache FOP. RenderX (XSL-FO processor) has the advantage of having a paged-HTML output option, but again I don't know if it could run on Android.
There is several ways this could be done. If every line is in its own element all you have to do is to check if one of it's edges goes outside of the view (either the browsers, or the "book page").
If you want to know how many "pages" there is going to be in advance, just temporary move them into the view and get what line a page ends. This could potentially be slow because of that page reflow is needed for the browser to know where anything is.
Otherwise I think that you could use the HTML5 canvas element to measure text and / or draw text.
Some info on that here:
https://developer.mozilla.org/en/Drawing_text_using_a_canvas
http://uupaa-js-spinoff.googlecode.com/svn/trunk/uupaa-excanvas.js/demo/8_2_canvas_measureText.html
Had this same problem recently and inspired by the answers found a plain CSS solution using CSS3's column-* attributes:
/* CSS */
.chapter {
width: 600px;
padding: 60px 10px;
-webkit-column-gap: 40px;
-webkit-column-width: 150px;
-webkit-column-count: 2;
height:400px;
}
/* HTML */
<div class="chapter">
your long lorem ipsum arbitrary HTML
</div>
The example above gives great results on a retina iPhone. Playing around with the different attributes yields in different spacing between the pages and such.
If you need to support multiple chapters for instance which need to start on new pages, there's an XCode 5 example on github: https://github.com/dmrschmidt/ios_uiwebview_pagination
You could split the pages in separate XHTML files and store them in a folder. Eg: page01, page02. You can then render those pages one by one underneath each other.
You can look at http://www.litres.ru/static/OR/or.html?data=/static/trials/00/42/47/00424722.gur.html&art=424722&user=0&trial=1 but the code may be heavily obfuscated, so just use Firebug to inspect DOM.
If the link isn't working, comment - would give you fixed.