Equivalent for UI::WebDialog.Show call back method of Skp2016?

Hi,

In Sketchup 2016, we used to have a callback available for dialog.show, like this (taken from – Class: UI::WebDialog — SketchUp Ruby API Documentation )

dialog.show {
dialog.execute_script(“alert(10)”);
}

Do we have a similar or alternate yield method available for Sketchup 2017’s – HtmlDialog’s show method ?

Thanks,
Jaya

The new pattern would be to attach a DOMContentLoaded event to the window and use it to notify the Ruby script via a callback that the dialog is ready.

1 Like

Here’s an example of using the DOMContentLoaded event:

// This is JavaScript either in the HtmlDialog HEAD, or in an external file.
// It is compatible with both HtmlDialogs and WebDialogs.
window.addEventListener('DOMContentLoaded', function() {
	if (typeof (sketchup) === "undefined") {
		window.location.href = "skp:ready";
	} else {
		sketchup.ready();
	}
});
2 Likes

I noticed most examples online show attaching the event to document rather than window. It does work for me using window although document may be more correct. I’m not sure how JavaScript resolves the scope or function call in this case.

Thanks a lot for the reply Jim, I will try using this and get back if I have any issues.

Not directly related to this topic, but from webdialog to htmldialog transition, do we have a replacement for “allow_Actions_from_host” method ?

Thanks,
Jaya

document is the official standard object of the JavaScript DOM.
So, we could argue that using document is “best practice.”

The window object is part of the “unofficial” Browser Object Model (BOM,) but has been left (so far) working so as not to break old websites. The two identifiers are basically synonymous. Ie:

*http://www.w3schools.com/js/js_window.asp*:

The window object is supported by all browsers. It represents the browser’s window.

All global JavaScript objects, functions, and variables automatically become members of the window object.

Global variables are properties of the window object.
Global functions are methods of the window object.
Even the document object (of the HTML DOM) is a property of the window object:

window.document.getElementById("head");

So you use either or both (full qualification) to get at global HTML objects, properties and methods.

But, it may be that the opposite is not true. You may need to specifically go through the BOM window object in order to access unofficial BOM objects. (window.history, window.screen, etc.)

thankyou for the explaination. In my other dialogs I had used document except in the one plugin I brought up to use as an example.

I’m converting my old code from WebDialog to HtmlDialog. My problem is that the call back does not persist. I initialize and open my new HtmlDialog and there is initialization code in the html javascript. The first time it opens the sketchup.callBack runs. I close and reopen and the dialog and get sketchup.callBack not found. What do I need to do for the call back function to persist?

We will just be guessing without a minimum snippet that reproduces the issue.

So, my guess is that you have not used a persistent reference for the dialog object.

Dan,

I can open and close the dialog any number of times from the same instance. But the call back method only seems to exist the first time I open the dialog.

Well, that’s the problem with guesses. They are often off the mark. :rolling_eyes:

Here is an example that duplicates the problem.

Plugins/MyStartup.rb

require 'sketchup.rb'
require 'extensions.rb'

# Show the Ruby Console at startup so we can
# see any programming errors we may make.
SKETCHUP_CONSOLE.show

module Sketchup::MyTest

#Register the Tools with SU's extension manager
myTestExtension = SketchupExtension.new("My Test Tool", "MyTest/MyTestMenu.rb")

#Default on in pro and off in free
Sketchup.register_extension myTestExtension, true

end # module Sketchup::MyTest

Plugins/MyTest/MyTestMenu.rb

require 'sketchup.rb'
require 'MyTest/MyTestDialog.rb'

module Sketchup::MyTest

# Add a menu item to launch our plugin.
if( not $myTestMenuLoaded )
    begin
        $myTestDialog = MyTestDialog.new
        mnuMenu = UI.menu('Extensions')
        mnuMenu = mnuMenu.add_submenu('My Test')
        mnuItem = mnuMenu.add_item('Run Test') { $myTestDialog.show }
    rescue Exception
        puts "#{$!}"
    end
    $myTestMenuLoaded = true
end

end # module Sketchup::MyTest

Plugins/MyTest/MyTestDialog.rb

module Sketchup::MyTest

class MyTestDialog
    def initialize
        begin
            @oDialog = UI::HtmlDialog.new ({
                :dialog_title => "My Test",
                :style => UI::HtmlDialog::STYLE_DIALOG
            })
            @oDialog.add_action_callback("callBack") do |dialogContext,actionName|
                puts actionName
                case actionName
                    when 'getData'
                        js_command = "getData('getting data')"
                    when 'setData'
                        js_command = "setData('setting data')"
                    when 'okay'
                        @oDialog.close()
                        js_command = 'success()'
                    when 'cancel'
                        @oDialog.close()
                        js_command = 'success()'
                    else
                        js_command = 'success()'
                end
                puts js_command
                @oDialog.execute_script(js_command)
            end
            htmlPath = Sketchup.find_support_file "MyTestDialog.html" ,"Plugins\\MyTest\\Dialogs"
            @oDialog.set_file(htmlPath)
        rescue Exception
            puts "#{$!}"
        end
    end
    
    def show
        begin
            @oDialog.show()
        rescue Exception
            puts "#{$!}"
        end
    end
    
end

end # module Sketchup::MyTest

Plugins/MyTest/Dialogs/MyTestDialog.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
  <title>My Test Dialog</title>
</head>
<body>
  <input id="txtTest">
  <br>
  <br>
  <input onclick="evntGetClick()" id="btnGet" value="Get" type="button"> 
  <input onclick="evntSetClick()" id="btnSet" value="Set" type="button"> 
  <input onclick="evntOkayClick()" id="btnOkay" value="Okay" type="button"> 
  <input onclick="evntCancelClick()" id="btnCancel" value="Cancel" type="button">
  <br>
  <br>
<script type="text/javascript" src="MyTestDialog.js">
</script>
</body>
</html>

Plugins/MyTest/Dialogs/MyTestDialog.js

// Call sketchup application
function callBack(value) {
    try {
        sketchup.callBack(value);
    } catch(err) {
        alert("Error in [callBack]: " + err.message);
    }
}

// Get data
function getData(value) {
    try {
        document.getElementById("txtTest").value = value;
    } catch(err) {
        alert("Error in [getData]: " + err.message);
    }        
}

// Set data
function setData(value) {
    try {
        document.getElementById("txtTest").value = value;
    } catch(err) {
        alert("Error in [getData]: " + err.message);
    }        
}

// Get data
function evntGetClick() {
    try {
        callBack("getData")
    } catch(err) {
        alert("Error in [evntGetClick]: " + err.message);
    }            
}

// Set data
function evntSetClick() {
    try {
        callBack("setData")
    } catch(err) {
        alert("Error in [evntSetClick]: " + err.message);
    }            
}

// Okay and exit
function evntOkayClick() {
    try {
        callBack("setData")
        callBack("okay");
    } catch(err) {
        alert("Error in [evntOkayClick]: " + err.message);
    }            
}

// Cancel and exit
function evntCancelClick() {
    try {
        callBack("cancel");
    } catch(err) {
        alert("Error in [evntCancelClick]: " + err.message);
    }            
}

// Initialize form
try {
    callBack("getData");
} catch(err) {
    alert("Error in [initialization]: " + err.message);
}    

@thewized

To get code to format correctly on this forum, wrap it in triple back-ticks. For example:

```ruby 
# Enter/Paste Ruby Code Here
```
1 Like

At a minimum you need to enclose your code snippet between lines of triple-backticks so that the forum’s engine doesn’t make a mess reformatting it. Better would be to upload the file(s) directly so that we can test them without transcribing your stuff.

1 Like

for starters, UI::HtmlDialog is using ‘Chrome Embedded Framework’, so you should be using HTML 5

<!DOCTYPE html>
<html>
<head>
  <title>My Title</title>
  <meta charset="UTF-8">
</head>
<body>

john

I’ve looked through, and cannot see any error that would cause the issue you describe.

I’ll try to run it later this afternoon, on one of my v2017 test machines.


These notes have nothing to do with the the issue. Just Ruby coding in general.

(1) The first thing you MUST do.
Edit the above examples, and move your class and code into your OWN unique toplevel namespace module. (When I post examples, I’ll often use a generic namespace like Author or Company.)

It is big no-no to define code in Trimble’s Sketchup module !

(2) Not that important, but Ruby uses 2 spaces indents. (More causes excessive horizontal scrolling in the forum code boxes.)
Javascript and HTML use 4 at the least. (There are even some specs that say JS should use 8 spaces, which wastes so much horizontal space.)

(3) NEVER use global variables. And actually there is no reason to use them inside your own module namespace(s). Use @@ module variables instead.

I tried your code (after some editing along the lines that Dan suggested). What I am getting is that the first time it displays by clicking the menu, it works. The next time the dialog opens but is blank and unresponsive (even to the point that the Chromium inspector won’t open). Is that what you are getting, or did I break something else?

I’m still not sure why I’m getting a blank dialog when I close then reopen it (could be a bug in HtmlDialog), but the reason your data function doesn’t get called is that it is just executed at the bottom of your javascript file:

// Initialize form
try {
    callBack("getData");
} catch(err) {
    alert("Error in [initialization]: " + err.message);
}

That means it is run when the js is loaded into the page, but never again! Simply opening an existing dialog doesn’t cause it to reload any html or javascript.

I also saw some missing semi-colons so I pasted the Javascript into http://jslint.com/
and it did confirm some issues. (Many are because it doesn’t see global objects like sketchup.)

I’ll see if I can collect the files and run them in a few minutes.