Call javascript function from objective C on orientation change - javascript

First off I would like to say I am an absolute Objective C novice.
I have been looking everywhere for a solution for this, but somehow I cannot seem to get it to work.
All I want is to run a Javascript function from Objective C when an orientation change event occurs, seeing how this is the only way to execute Javascript before the orientation change animation starts.
I have been able to get a NSLog to show when an orientation change occurs, but no matter what I try, I am unable to execute any Javascript. Not even a console.log() or an alert(), let alone the actual function I want to trigger.
Could anyone please save me another afternoon of trial and error?
SOLVED
Place this in didFinishLaunchingWithOptions (AppDelegate.m):
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(orientationDidChange:)
name: UIApplicationDidChangeStatusBarOrientationNotification
object: nil];
And this just below
- (void) orientationDidChange: (NSNotification *) note
{
[self.viewController.webView stringByEvaluatingJavaScriptFromString:#"hideContentsDuringOrientationChange();"];
}

You should be able to do this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[(UIWebView *)self.visibleViewController.view stringByEvaluatingJavaScriptFromString:#"someGlobalJSFunction();"];
}
Your reference to the UIWebView may have to change based on how your project is setup.
You can use didRotateFromInterfaceOrientation for an event after the rotation is complete. I've found this sometimes fires just a bit early for the JS to redraw, though. I fixed that by putting a short timeout in the JS function it calls.

Related

Call function without actually executing it

So I have such a weird question and I don't know if this is possible, but I will give it a shot anyways.
We have implemented OneTrust, which is a third-party cookie consent vendor and it works great and all, but we have one small hiccup that we are trying to resolve.
So within the below function:
toggleVideo: function (videoWrapper, src, cover, type, element) {
var videoElement = video.buildVideo(src, type);
// We build out video-player element
videoWrapper.html(videoElement);
// We define our variables
let onetrust = window.OneTrust;
let onetrust_obj = window.ONETRUST_MODULE;
let target = videoWrapper.html(videoElement).children('iframe');
console.log(onetrust.Close());
// Now we wait and observe for a src attribute and then show the video.
onetrust_obj.src_observer(target, function() {
video.toggle_show(videoWrapper, cover);
});
},
We have an <iframe> element that when clicked play, will wait for consent to execute - The problem is that it needs to "refresh" OneTrust so that it can change the data-src to src attribute (This is all handled using OneTrust JS, so I have no control).
When I add in the console.log(onetrust.Close());, it works just as intended and resumes playing the video when consent is given, the downfall is that it outputs an error in the console. If I remove it, the videos will not play after consent is given.
I don't want to actually execute the onetrust.Close() method as it will close the banner.
OneTrust doesn't have a proper way to "Refresh" their initialization, the techs told me that this was a one-off case, where they don't even know how to handle it.
My questions:
Is there a way that I can properly call onetrust.Close() (Seems to be the only call that actually engages the video to play after) without actually executing it?
If not, is there a way that I can somehow similarly log it, but not actually log it in the console?
Thanks all!
Strange one, may be a race-condition issue so making your code run in the next procedural iteration may resolve the issue - this can be done by adding a setTimeout with no timer value.
setTimeout(() => {
onetrust_obj.src_observer(target, function() {
video.toggle_show(videoWrapper, cover);
});
});
Alternatively, it may be worth digging into the onetrust.Close() method to see if there are any public utilities that may help 'refresh' the context you are working in.
Another idea would be to see what happens after if you ran the onetrust_obj.src_observer code block again.
EDIT: I would like to be clear that I'm just trying to help resolve debugging this, without seeing a working environment it's difficult to offer suggestions 😄

Looping audio in midijs?

I'm trying to use MIDIjs to play audio (specifically because I'm using WAD.js, which uses it). Unfortunately I can't figure out how to loop audio, there's a frustrating lack of documentation, and I'm not finding anything in the source code. At the very least I'd like to know when the file has naturally ended to restart using MIDIjs.play(), but I'm not even seeing anything for that.
I'd appreciate it if someone pointed me towards a solution, thank you.
Correct, there's no loop function (that's documented anywhere here).
However, we can at least simulate it with MIDIjs.player_callback, which is called every 100ms with an object that looks like { time : number }. This is time in seconds elapsed. We can combine this with get_duration to detect the end of playback.
function playAutoReset(url)
{
// get_duration requires a callback as it returns nothing.
MIDIjs.get_duration(url, function (duration)
{
console.info(`Duration: ${duration}`);
// Start the initial play
MIDIjs.play(url);
// This lets us keep track of current play time in seconds
MIDIjs.player_callback = function (mes)
{
if (mes.time / duration >= 1)
{
console.info('End reached');
// This plays the audio again
MIDIjs.play(url);
}
};
});
}
Note:
This does call play each time, so it will probably re-download the source (the docs seem to imply that this is always the case). If you want something more network-efficient, you may want to look into XHRs/AJAX and creating an object URL, as the docs do specify that play takes a URL. However, I thought this would be the simplest solution, and it does show what you have to do to play the midi track again when it ends.
I had this same issue and wasn't entirely satisfied with the workaround in the other answer because of how it reloaded the file every time the url was passed into a MIDIjs function and it seemed to loop slightly too early.
So, I started digging into the MIDIjs source, which also has a map file, but I didn't bother trying to maximize/deobfuscate it. I noticed a couple mentions of loop that are set by second parameter t in function X. I wasn't sure, but thought maybe X was play, so I tried it.
MIDIjs.play(url, true);
It worked!
Since I'm working with Kotlin/JS, here's my external code:
external object MIDIjs {
fun play(url: String, loop: Boolean = definedExternally)
fun stop()
}
Call it in Kotlin exactly the same way, without the semicolon.
MIDIjs.play(url, true)

Qt function runJavaScript() does not execute JavaScript code

I am trying to implement the displaying of a web page in Qt. I chose to use the Qt WebEngine to achieve my task. Here's what I did :
Wrote a sample web page consisting of a empty form.
Wrote a JS file with just an API to create a radio button inside the form.
In my code, it looks like this :
View = new QWebEngineView(this);
// read the js file using qfile
file.open("path to jsFile");
myJsApi = file.Readall();
View->page()->runjavascript (myjsapi);
View->page()->runjavascript ("createRadioButton(\"button1\");");
I find that the runJavaScript() function has no effect on the web page. I can see the web page in the output window, but the radio button I expected is not present. What am I doing wrong?
I think you will have to connect the signal loadFinished(bool) of your page() to a slot, then execute runJavaScript() in this slot.
void yourClass::mainFunction()
{
View = new QWebEngineView(this);
connect( View->page(), SIGNAL(loadFinished(bool)), this, SLOT(slotForRunJS(bool)));
}
void yourClass::slotForRunJS(bool ok)
{
// read the js file using qfile
file.open("path to jsFile");
myJsApi = file.Readall();
View->page()->runJavaScript(myjsapi);
View->page()->runJavaScript("createRadioButton(\"button1\");");
}
I had this problem, runJavascript didn't have any effect. I had to put some html content into the view (with page().setHtml("") before running it.
Check the application output, it might contain JavaScript errors. Even if your JS code is valid, you might encounter the situation where the script is run before DOMContentLoaded event, that is document.readyState == 'loading'. Therefore, the DOM might not be available yet, as well as variables or functions provided by other scripts. If you depend on them for your code to run, when you detect this readyState, either wait for the event or try calling the function later, after a timeout. The second approach with timeout might be needed if you need to get the result of the code execution, as this can be done only synchronously.

UIWebview Screen Shot after executing injected JavaScript on the page

What is the best approach for handling the following. I have an HTML page with some JavaScript which I load into UIWebview control. I would like to invoke a js function on the page which mutates the DOM, and after the DOM mutation I would like to capture a screenshot of the webpage. The problem I am facing is that the image captured from the UIWebview does not represent the current state of the html page. It represents the state of the DOM prior to the invocation of the [myWebview stringbyevaluatingjavascriptfromstring:#"myHandle.func()"]; from below.
[myWebview stringbyevaluatingjavascriptfromstring:#"myHandle.func()"];
UIGraphicsBeginImageContext(myWebview .bounds.size);
[myWebview .layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I believe that the problem is related to the fact that the Native UI updates are not updated until the end of the current Run Loop. Therefor the UIWebView does not reflect the current state of the DOM at the point of screen capture.
I have managed to get the functionality I seek working via the following two approaches. Calling both immediately after
[myWebview stringbyevaluatingjavascriptfromstring:#"myHandle.func()"];
1.
[self performSelector:#selector(createWebviewImage) withObject:nil afterDelay:0]
where createWebViewImage simply holds the following logic
UIGraphicsBeginImageContext(myWebview .bounds.size);
[myWebview .layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
2.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Back to the main thread for a chunk of code
dispatch_sync(dispatch_get_main_queue(), ^{
[self createWebviewImage];
});
});
Theses two methods do work in my small test case although I am extremely apprehensive about using them as I am afraid of a case where they may fail.
Thanks to question https://stackoverflow.com/a/26301724/680778
Below is the best approach I have been able to come up with
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAfterWaiting, NO, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity)
{
[self createWebviewImage];
});
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
This approach adds an observer to the Main Run loop to be executed during the kCFRunLoopAfterWaiting stage which as mentioned in the reference all UI operations execute during the kCFRunLoopBeforWaiting stage. Hope this helps someone else.

Show What Functions Were Called In Javascript

I need this because I often work on existing projects, and I'm required to crash right into the middle of somebody else's work. With little time nowadays, I'm looking for whatever tool I can find to do this:
Load a JS application
Start / Pause recording activity
Show me exactly what happened, in the form of what functions were called without requiring me to change the source code.
For example:
<script language="javascript">
var fn1 = function(strvar){ alert('var='+strvar); fn2(strvar); }
var fn2 = function(strvar2){ alert('var='+strvar2); }
</script>
click here
After I click the anchor, (at best) should get something like this:
(click) event on a
(call) fn1("click here")
(call) fn2("click here") from inside fn1 called at pct. 2
Some sort of stack tracing but without having to alter the source because it takes formidable time as it is.
If you write
debugger;
in your innermost function, you can open firebug or the chrome dev tools and their debugger will pause when it hits that line. Then in the section on the right of the tools, you can see the stack trace and other relevant data (locals, etc...).
You only need to add one line to a function you own and it will show you any calls made with anyone's code.

Categories

Resources