I am working on a hybrid HTML5/iOS app that uses the Safari Webview. We are using AirPrint to allow the user print the contents of the webview. The problem I am having is that after the print dialog is opened, the print styles are taking affect on the screen, and even after printing is complete or canceled do not go away. This does not happen in our Windows or Android versions of the app, which use CEF and Android System Webview respectively. Print styles in those versions of the application are only applied to the print out, as expected.
Anyone have any experience using AirPrint with Safari Webview that could shed some light on a solution? I have considered just adding/removing the link tag containing the CSS with javascript before and after printing, but that feels hacky, and doesn't answer the curious question of why print styles are being applied to the screen.
Any help appreciated! Sorry there is no real way to attach code to this!
Yes, this is indeed a not expected behaviour. However, we can try to solve this using JavaScript.
Theory: When the print is done, let's reload the stylesheets. The browser will paint the page again and hopefully using screen definitions.
Practice: As we don't have a JavaScript callback after printing, you could try reload your stylesheets using the window.onfocus event, as follows:
function updateStylesheets(){
var links = document.getElementsByTagName("link");
for (var x in links) {
var link = links[x];
if (link.getAttribute("type").indexOf("css") > -1) {
link.href = link.href + "?id=" + new Date().getMilliseconds();
}
}
}
window.onfocus = updateStylesheets;
In detail, it grabs all <link> tags and appends a random number after, forcing a reload on the stylesheets.
Please let me know if that worked, I'd be glad to help.
Related
How does requestFullscreen in Dart works? I want enable Fullscreen-mode on mobile devices.
I wrote following Code. But it changes nothing.
querySelector(".btn").onTouchEnd.listen((l) {
var body = document.body;
body.requestFullscreen();
});
But it didn't worked.I'm becomming on click always same error document.body.requestFullscreen is not a function
Seems to be something like https://api.dartlang.org/stable/1.24.3/dart-html/VideoElement/enterFullscreen.html, so you need to call it on your video element.
Edit: Oh, yes, there's also https://api.dartlang.org/stable/1.24.3/dart-html/Element/requestFullscreen.html -- that might be the one you want.
Edit2: Apparently, this has already been asked and answered, and needs a workaround: How to request fullscreen in compiled dart
I'm afraid im having the same probem as this unasnwered question.
I have a blank IFRAME In my cordova ionic IOS App for embedded YouTube videos.
I change the NG-SRC="" of iframe by clicking Next Video. But upon testing it appears that the phone/cordova/webview is caching the old content of the iframes. I can only get through 20 videos or so before crashing out of memory.
I have tried using angular.element.remove() to remove the iframe as well as setting the iframe src to blank first, and neither seemed to affect how much memory is in use, per Xcode. I've also tried the cordova plugin ClearCache and that didnt clear any memory either.
Please help! Is there a better way to embed youtube in a cordova app?
I have spent weeks working on this all to have it crashing down around me (no pun intended)
My Video view is like:
<ion-view view-title="Random Video">
<iframe id="youtube" sandbox="allow-scripts allow-same-origin" ng-src="{{video.url | trustAsResourceUrl}}" frameborder="0" allowfullscreen></iframe>
<h4>{{video.title}}</h4>
<button ng-click="nextVideo()">
</ion-view>
My controller is like:
angular.module('starter.controllers')
.controller('VideoCtrl', function(VideoService) {
$scope.video = {};
$scope.nextVideo = function() {
$scope.video = null; //doesnt seem to help
//$scope.$destroy(); //doesn't help
//angular.element(document.querySelector( '#youtube' )).attr("src", " ");
//angular.element(document.querySelector( '#youtube' )).remove();
//neither of the above 2 remove any memory
VideoService.getVideo().then(function(response){
$scope.video = response.data;
});
}
$scope.nextVideo();
});
Note, when I load my app onto a website instead, and load in chrome, I can cycle through videos without seeing the memory usage go up (looking at taskmgr.exe at least)
It might seem like setting the iframe to an empty string should be enough, but for some browsers and some situations it isn't. It might be necessary to recursively delete event listeners and elements one by one. Maybe surprisingly, the recursive method (1) below is faster than just setting to an empty string (2):
1.Recursive
while (box.lastChild) {
box.removeChild(box.lastChild);
}
2. Setting empty string
myNode.innerHTML = '';
See https://stackoverflow.com/a/3955238/1158376 for reference.
Additionally, in the recursive approach, one might need to apply special treatment to some items, for example first remove event listeners, nullify functions (http://javascript.crockford.com/memory/leak.html), and use dedicated cleanup methods, like with jQuery (http://javascript.info/tutorial/memory-leaks).
Another strategy you could try is to load a new web page with a fresh iframe for every video you play. Loading a new page should enable the browser to release the previously claimed memory.
I have started developing html applications for mutliple platforms. I recently heard about Cordova 2.0(PhoneGap) and ever since I have been curious to know how the bridge works.
After lot of code walking, i saw that the Exec.js is the code where call from JS -> Native happens
execXhr = execXhr || new XMLHttpRequest();
// Changeing this to a GET will make the XHR reach the URIProtocol on 4.2.
// For some reason it still doesn't work though...
execXhr.open('HEAD', "file:///!gap_exec", true);
execXhr.setRequestHeader('vc', cordova.iOSVCAddr);
if (shouldBundleCommandJson()) {
execXhr.setRequestHeader('cmds', nativecomm());
}
execXhr.send(null);
} else {
execIframe = execIframe || createExecIframe();
execIframe.src = "gap://ready";
But want to understand how that works, what is the concept here, what does file:///!gap_exec or gap://ready do? and how does the call propgate to the lower layers (native code layers)
thanks a bunch in advance.
The trick is easy:
There is a webview. This displays your app. The webview will handle all navigation events.
If the browser navigates to:
file:///!gap_exec
or
gap://
the webview will cancel the navigation. Everything behind these strings is re-used as an identifier, to get the concrete plugin/plugin-method and parameter:
pseudo-url example:
gap://echoplugin/echothistext?Hello World
This will cause phonegap to look for an echoplugin and call the echothistext method to send the text "Hello World" to the (native) plugin.
update
The way back from native to javascript is (or may be) loading a javascript: url into the webview.
The concrete implementation is a little bit more complex, because the javascript has to send a callback-id to native code. There could be more than one native call are running at the same time. But in fact this is no magic at all. Just a number to get the correct JSON to the right javascript-callback.
There are different ways to communicate between the platform and javascript. For Android there are three or four different bridges.
I am trying to figure this out in more detail, too. Basically there are 2 Methods on the iOS side that can help ...
- webView:shouldStartLoadWithRequest:navigationType: and
- stringByEvaluatingJavaScriptFromString:script
From the sources it seems cordova sends a "READY" message using webView:shouldStartLoadWithRequest:... and then picks up results with the second message, but I am not sure.
Cordova Sources iOSExec
There is much to learn there.
I'm developing a mobile application using Backbone, jQueryMobile and Phonegap. The app works great on Android, iOS and BB >= 6, but on BB5 as expected there are countless issues coming up.
I'm now facing problems with Backbone itself. I'm debugging it and looks like the problem is in the routes definition. The application crashes on start time due to something related to it (still investigating, but debugging is painful for BB5...).
Also, I read that BB5 won't play nice with hash listening, which Backbone relies on to do the navigation, so I am wondering if somebody has been able to create a backbone app on OS5, or is it simply not possible?
I'm updating this question just in case someone faces the same issue:
Short story: it's not possible to run Backbone on OS5. I debugged into backbone and some instructions with regular expressions were causing a crash. Even if these are fixed in the future, we determined that the js support was simply not good enough and finally discarded the OS5 version.
It is probably not worth it in most cases but this is doable.
I managed to get an app running after quite a bit of work - the javascript support is really not great in OS 5.0 and debugging is very very slow as suggested in bfcapell's answer.
To get backbone to work you need to comment out the code that uses the hashchange event to handle url changes (this is assuming that the router is being used). THere is a fallback in backbone which uses setinterval to poll for changes.
// Depending on whether we're using pushState or hashes, and whether
// 'onhashchange' is supported, determine how we check the URL state.
/*if (this._hasPushState)
{
alert('pushstate');
$(window).bind('popstate', this.checkUrl);
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE)
{
alert('hashchange');
$(window).bind('hashchange', this.checkUrl);
} else if (this._wantsHashChange)
{*/
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
//}
The foreach method in underscore also needs to be modified to not use the native foreach method. This is needed for collections to be rendered correctly.
var each = _.each = _.forEach = function (obj, iterator, context)
{
if (obj == null) return;
/*if (nativeForEach && obj.forEach === nativeForEach)
{
obj.forEach(iterator, context);
}
else*/
if (obj.length === +obj.length)
The above should get at least backbone mostly working. (I say mostly because I have a completely working app but I suspect to find a couple more OS5 specific issues in time).
Here's the issue:
I have a hook in IE that reacts on WebBrowser.OnNavigateComplete2 event to parse the content of the document for some precise info.
That document contains frames, so I look into the HTMLDocument.frames. For each one, I look into the document.body.outerHTML property to check for the content.
Problem is, the string I'm looking for never shows there, whereas it is displayed in the finale page. So, am I looking in the wrong place? If it is displayed when the page is fully loaded, then it's downloaded at some point, right? But in which object should I look ?
BTW, I Don't know if that is of any importance, but the page I'm searching into comes from a ASP.NET application.
public void OnNavigateComplete2(object pDisp, ref object url)
{
document = (HTMLDocument)webBrowser.Document;
mshtml.FramesCollection frames = document.frames;
for (int i = 0; i < frames.length; i++)
{
object refIdx = i;
IHTMLWindow2 frame = (IHTMLWindow2)frames.item(ref refIdx);
string frameContent = frame.document.body.outerHTML;
}
}
Thank your for your help.
#rams
This event is launched many times for each page, so I figured it was each time a framed is loaded, even if i don't get to catch the one I'm looking for. If not, what would be the event to catch the frames content?
What I want to do is detect some precise info on a precise frame, then save it. later, a web page is loaded triggered by some user action, where I need the info I got from parsing the frame.
Do you know the name/id of the frame you are looking for content? If so, in your navigateComplete2 event, can you get a reference to the frame like
iFrame frm = document.frames(<your frame id>);
int readyState=0;
while(frm.readystate !=4){
// do nothing. be careful to not create an endless loop
}
if(frm.readyState==4){
// get your content now
}
HTH
Are you using some kind of threading? Running the browser in a separate thread really messes up things. Try to execute it in an STAThread and check if you get the correct result.
The reason your string does not show is because of the frame. The web browser control fires the document navigate complete event after it has loaded the main document. At this point, the frames haven't yet requested their sources. After the document is parsed by the web browser control, requests for the frame sources are issues and downloaded.
Can you please describe what you are trying to accomplish?