HTMLDialog::show_modal content is blank when within HTTP::Request block

I’m pretty new to Ruby and Sketchup, so hopefully this is just something I’m messing up.

If I make a HTTP::Request and then on success show a HTMLDialog, the content is blank when using show_modal, but show works fine. Any idea what I’m doing wrong?

     def self.test_func
        request = Sketchup::Http::Request.new('http://sketchup.com', Sketchup::Http::GET)
        request.start do |request, response|
          puts response.status_code

          options = {
            :dialog_title => 'Test',
            :width => 500,
            :height => 400,
            :style => UI::HtmlDialog::STYLE_DIALOG
          }
          dialog = UI::HtmlDialog.new(options)
          dialog.set_url('http://google.com')
          dialog.center
          dialog.show_modal
        end
      end

show_modal pauses the execution of the code until it is closed. You can add a puts statement after show_modal and it wont be printed until the dialog is closed. I’m not sure though how this affects set_url.

@tom10

Try the following:

# test_func
# test_func modal: true
def self.test_func(modal: false)
  Sketchup::Http::Request.new('http://sketchup.com', Sketchup::Http::GET)
    .start do |req, resp|
      puts "resp.status_code #{resp.status_code}, modal #{modal}"

      options = {
        dialog_title: 'Test', width: 500, height: 400,
        style: UI::HtmlDialog::STYLE_DIALOG
      }
      dialog = UI::HtmlDialog.new options
      dialog.set_url 'http://google.com'
      dialog.center
      if modal
        dialog.show_modal
      else
        dialog.show
      end
      answer = UI.messagebox 'In request start', MB_OK
    end
end

First, run it with test_func. Notice that the UI.messagebox appears, but the HtmlDialog is not loaded/rendered yet. Once you close the UI.messagebox, the block and the method call complete, and the HtmlDialog shows google.

Then, run it with test_func modal: true. Since the HtmlDialog is shown modal, the UI.messagebox doesn’t appear. This also means that the block passed to Sketchup::Http::Request#start hasn’t completed, so the method hasn’t finished either.

So, what’s happening is that the HtmlDialog only processes things when the ruby code has finished. By placing a modal dialog inside a block used by a method, you’re stopping the code from finishing.

JFYI –

  1. It’s not common for UI code (or any significant code) to be placed in an HTTP request. One gets the request.body and ‘moves on’…

  2. I was introduced to Ruby via SketchUp about ten years ago, but I’ve been coding for decades. For new programmers, dialogs are messy, as they involve issues like the one here, but also using callbacks, etc.

  3. I changed the style of some of your code, how you write it is your choice.

That is what I would like to do. The Http::Request is async, so I can’t figure out how to get the token without yielding the result to function that opens the dialog. Again, I’ve been only working in Ruby a few days, so excuse my inexperience with parts of the language.

What I’m doing is making a request for an access token, once I have the token then I want to pop up the dialog. I would like to do something like the following, but we return from the function before access_token has a value.

def self.get_token
...
    access_token = nil
    request.start do |request, response|
      resultJson = {}
      if response.status_code == 200 && !response.body.nil?
        resultJson = JSON.parse(response.body)

        File.write(tokenFile, resultJson['access_token'])
      end

      access_token = resultJson['access_token']
    end

    return access_token
end

It looks like using Net::HTTP::Post, instead of the Sketchup:: version gets me what I want, since it is synchronous.

That being understood, and having looked around quite a bit, I still cannot use ‘show_modal’ to my liking; the dialog is always blank.
Does the quote mean that a suite of methods cannot momentarily be interrupted with ‘_modal’, for an input request for instance ?

Any Ruby manipulation of the dialog object must come before the #show_modal method call.

Providing a snippet would help us know what you are trying to do.

That said, once the dialog is shown, the user can only work with that dialog whilst it is open. They cannot use any other application feature outside the dialog (at least on Windows.) [Note that they can switch to another application, but switching back to SketchUp will give the modal dialog the focus again. MacOS may be a bit different as to what Apple considers modality.]

What do you mean for an input request ?

Thanks Dan. It now works fine on PC.
Still blank modal html on Mac.
Will try to make a snippet.

Okay, … I cannot help much with Mac as I do not have one. But perhaps Steve can.

Have you reviewed the issues that Fredo logged in the tacker ?

Well, after playing a lot with modal HtmlDialog my conclusion is : it is way too complicated on Mac, as of now only a few people (at TT’s level) can use it, I think.
Since the purpose of ‘modal’ is to suspend the rb method till the dialog is closed,
I think a simple work around could be:

  • Split the method in 2 methods
  • At the end of the first, call the (non-modal) html dialog (no ruby after, so rb is stopped)
    to carry on with rb,
    put a call to the second method in an ‘action_callback’.

In method-1

...
...
  dialog.add_action_callback('onclick') do |action_context, var|
    @var = var
    dialog.close
    method-2
  end #do
...

You can use a readystate event to trigger a dialog callback.
See one of my examples I posted numerous times …

Add_action_callback does not work when using execute_script - #2 by DanRathbun

HtmlDialog and the Http API is driven by Chromium, which work in async separate processes. This is a challenge some times. I’ve found that starting new async within another async callbacks can be problematic.

You can often work around this by using UI.start_timer to defer the execution to be outside the context of the async callback. But that itself has issues if the timer pops up a modal dialog.

This pattern should allow you to pop up a modal in response to an HTTP request:

module Example

  def self.test_func
    request = Sketchup::Http::Request.new('http://sketchup.com', Sketchup::Http::GET)
    request.start do |request, response|
      puts response.status_code
      self.delay(0.0) do
        self.open_dialog
      end
    end
  end

  def self.open_dialog
    options = {
      :dialog_title => 'Test',
      :width => 500,
      :height => 400,
      :style => UI::HtmlDialog::STYLE_DIALOG
    }
    dialog = UI::HtmlDialog.new(options)
    dialog.set_url('http://google.com')
    dialog.center
    dialog.show_modal
  end

  def self.delay(seconds, &block)
    # Needed to avoid the timer from repeating if the block opens a modal
    # dialog or anything else that suspend execution.
    done = false
    UI.start_timer(seconds, false) do
      next if done
      done = true
      block.call
    end
  end

end # module

HtmlDialog should be consistent across both platform - as oppose to UI::WebDialog that had different behaviour between mac and Windows.

Hum… Do you mean that show.modal currently works the same on Mac & Pc ?
Or that they should and will eventually ?

For UI::HtmlDialog, they should, yes.

… except for the open bug issues as linked above. :roll_eyes: