Web Browser Object, Javascript and a Bug

Why will this code work and then stop working? Also, how do I post the code example and keep it neat? @admin Is this the bug you were referring to in the PDF documentation?

“Note: Right now, there is a bug that prevents this feature from working 100%. It works when you first open the window containing the web browser, but then stops working if the web page is ever reloaded for any reason. Hopefully I’ll figure this out soon.”

`htext = |||

Untitled

This is a test!

||||`

I see you figured out how to format the code neatly. Much better :slight_smile: And now I can actually see what the code is.

Why will this code work and then stop working?

Well, I wish I knew the answer to this – then I could easily fix the bug! As I recall, I tracked it down to something in Apple’s code, and couldn’t get any farther. It might even be an Apple bug. Since there is so much else going on, I will not get to work on this any further for quite a long time.

By the way, some of you may not know what @goMiddleton is referring to when he says “PDF documentation” – in fact that thru me at first. But he is talking about the slides for the video classes. This topic, calling Panorama code from inside a web browser page, was covered in the class a year ago. But it isn’t yet included in the “official” Panorama X documentation.

Why is the ‘var myResult’ given a value and then immediately overwriting that same variable with a new value?

Robert Ameeti

He probably just put it in for testing and then neglected to remove it when he added the second line.

I am curious, is there a way to have the web browser object “post” to itself? Probably the wrong terminology and maybe it can be done by parsing the html. I want to grab entries done in a form displayed with the web browser object to update fields in the database. I thought this might be a temporary solution until the javascript bug is figured out. There are many really interesting and slick things that can be done if and when javascript can chat with Panorama X. one example, view as list forms with editable fields done in html, displayed with the web browser object and connected to the database locally through javascript.

I am having a similar problem as @goMiddleton. Namely, I am interacting with a Web site where I can fill a form with criteria directly from the Panorama database, submit it and scrape the resulting web page for the data the form returns.

The problem is when I use Panorama to analyze these results I have two outcomes … either “good” results requiring no further data acquisition from the site (for that record), or “bad” results which require a re-query of the site with different criteria. In the latter circumstance I have programmed Panorama to automatically resubmit the form with alternate criteria but I can no longer get the updated page’s source code from the Browser object to scrape the new results.

I was hoping that this was a timing issue, where Panorama was not waiting for the webpage to completely load prior to executing subsequent commands, so I wrote several applescripts that control Safari (since it uses WebKit too) and which do the same process as described above. By using the appleScript “delay” command, I was able to make the re-query work and subsequently scrape the updated data which I previously could not do in Panorama.

Of interest, I created a loop in Panorama using info(“millisecond”) to simulate a delay, but this did not solve the problem. I also attempted to use a timer to try to achieve the same effect and it also did not create the desired delay.

Is there a way to make this work … to make Panorama wait for a Browser’s webpage to finish loading or to recognize/return the reloaded web page’s source code?

I’m hoping that the Browser object in Panorama can be updated to allow the developer to query whether the page has been loaded completely (this doesn’t work by querying the JavaScript “document.readyState” for Panorama’s Browser object) or that Panorama would have a “delay” function similar to that of AppleScript or similar function … one where the browser object would be allowed to continue processing and finish loading it’s page while Panorama waits to execute subsequent commands.

I’d be happy to provide both my database and the AppleScripts to you, Jim, if you think that’d be worthwhile.

I guess I could use Panorama’s ability to execute AppleScript to accomplish this task, but it would be much more satisfactory to complete this project without having to leave Panorama, especially since seeing the web site in the Browser object is useful to the end user of this project.

Regards,

Eric

If that doesn’t work then it’s probably not possible.

There is really almost none of my code involved in this process.There’s just a few lines of code that access the ability that Apple has put into NSWebView to allow arbitrary JavaScript to be run inside the browser view. When you do that, 99.999% of the code that runs when you run a JavaScript is WebKit code provided by Apple. Panorama itself has no concept of what’s going on inside the web browser view, it’s completely a black box other than the ability to run JavaScript. Panorama is just sending some text it doesn’t understand (which you must make sure is valid JavaScript source code) to a black box, and then getting back some other text it doesn’t understand from that black box (the results from the JavaScript).

I’m assuming that you have correctly identified document.readyState as the correct part of the DOM to query to find this out. I’m barely a newbie as far as DOM programming goes, though I have acquired a collection of books and training videos that I hope to get to someday to become more proficient on this topic. If it doesn’t work, then maybe there is some other location in the DOM that actually contains this information?

If delaying in AppleScript worked then using Panorama’s StartTimer function should also, they work basically the same way internally.

This is my attempt at using the StartTimer:

wbTimer:

// these variable are windowglobals
wbCtrCycles = 5
wbTmrCtr = 0

// tdSolutionText is used in a text display object and provides information.

stoptimer "wbCheck"
if error
    tdSolutionText = "wbTimer: No timer running"
    showwindowvariables tdSolutionText
endif
starttimer "wbCheck", "code", {    
if wbTmrCtr = 0
    tdSolutionText = "wbTimer: PAUSING, Ctr = " + wbTmrCtr
    showwindowvariables tdSolutionText
    pause ""
elseif wbTmrCtr = wbCtrCycles - 1
    resume ""
    stoptimer "wbCheck"
    tdSolutionText = "wbTimer: RESUMING, Timer Stopped"
    showwindowvariables tdSolutionText
else
    tdSolutionText = "wbTimer: PAUSED, Ctr = " + wbTmrCtr
    showwindowvariables tdSolutionText
endif
wbTmrCtr = wbTmrCtr + 1
}, "interval", 1, "next", wbCtrCycles, "scope", "window"
return

When I refresh the Browser object (by submitting a second query), I call this subroutine immediately afterward. It initializes, but doesn’t get to the resume function (it should do that after five seconds). I assume that the pause function pauses the timer as well.

How should I change this to get it to work? Clearly, I’m doing something wrong!

The pause and resume functions weren’t designed to be used with a timer like that. I don’t think that technique will work at all.

Another problem is that your “next” parameter is set to a time far in the past. If you want it five seconds into the future, you should use

"next",supernow()+wbCtrCycles

If you just want some code to run once after a 5 second delay, do it like this:

starttimer "runCodeLater",
    "repeat",1",
    "next",supernow()+5,
    "code",{
         your delayed code here, keep in mind that local variables are not shared with the rest of the code
    }

You may also want to set the scope and background options as needed.

Panorama itself uses this exact technique in at least a dozen places, especially now for the client/server code.

Jim, in the code below wbCtrCycles is a windowglobal variable set to the numerical value of zero in the form event procedure. When the timer runs, the form is active, yet the message printed from within the timer code is “0”, not “Test”.

What is the scope of the code inside the timer? Which scope of variable does that code see? It appears that a windowglobal variable is not visible to the timer code.

    wbCtrCycles = "Test"
    starttimer "runCodeLater",
    "repeat",1,
    "next",supernow() + 2,
    "scope","window",
    "background", "yes",
    "code",{
    message wbCtrCycles
    }

I’m reminded that the context of how the procedure is initiated matters.

To answer my own question, if the procedure is initiated from the form window (via button or other UI element), then a windowglobal variable (e.g., wbCtrCycles) works. If the procedure is initiated from it’s own window, then it likely won’t (depending on when and if the form window is brought to the front). The window global variables are only active when the window they are associated with is frontmost.