Has anyone ever tried doing this before. Up until now I’ve only ever needed to use static html files with some JavaScript and CSS. Does anyone have a very simple example?
Here is my test code:
@html_content = <<-HTMLOUTPUT
<!doctype html>
<html>
<body style="background-color:#F2EDE5;">
This is a test
</body>
</html>
HTMLOUTPUT
@dlg00 = UI::HtmlDialog.new(
{
:dialog_title => dialog_title,
:preferences_key => 'editpointload3',
:scrollable => true,
:resizable => true,
:width => 450,
:height => 450,
:left => 1200,
:top => 100,
:min_width => 50,
:min_height => 50,
:max_width =>1600,
:max_height => 1200,
:style => UI::HtmlDialog::STYLE_DIALOG
})
@dlg00.add_action_callback("CLOSE_DIALOG") {|action_context, params|
@dlg00.close
}
@dlg00.set_file @html_content
@dlg00.show
However it only shows a blank page in my HTML window.
use @dlg00.set_html @html_content
instead of @dlg00.set_file @html_content
I just caught that right before I read your post.
Your right, that was it, should have caught that earlier.
Many times and I’ve posted about it several times here.
I’ll use your snippet as an example.
There is a quirk to UI::HtmlDialogs
that if the dialog_title:
parameter is empty,
then the dialog will fallback to using what the HTML’s <title>
element holds.
We will replace the <title>
and <body>
content in the @html
string using Ruby’s
String#%
method to replace %{keyname}
tags in the text, with values from a hash that should have matching keys to the tags in the text. (An exception will be raised if there are mismatches.)
def dialog
@html = %[
<!doctype html>
<html>
<head>
<title>%{title}</title>
</head>
<body style="background-color:#F2EDE5;">
%{body}
</body>
</html>
]
# A hash of replacement data:
@content = {
title: "Test Dialog",
body: "This is a test"
}
@dlg00 = UI::HtmlDialog.new(
dialog_title: "",
preferences_key: 'editpointload3',
scrollable: true,
resizable: true,
width: 450,
height: 450,
left: 1200,
top: 100,
min_width: 50,
min_height: 50,
max_width: 1600,
max_height: 1200,
style: UI::HtmlDialog::STYLE_DIALOG
)
# Stuff replacemrnt data into the HTML text %{key} tags
# from the hash of data. The hash keys match the %{} tags:
@html = @html % @content
@dlg00.add_action_callback("CLOSE_DIALOG") {|_, params|
@dlg00.close
}
@dlg00.set_html(@html)
@dlg00.show
end
In actual use the data for insertion is likely to come from other parts of the extension code, or could come from a JSON file imported into Ruby as a hash. Or it might be model data that has been collected into a hash.
You also do not need to define a full HTML string object. In the past I have dynamically built HTML tables by appending table row fragments with data stuffed into them (as above) using a loop and a HTML table row template. After the loop is done building the table, the code appended </tbody></table>
onto the string. The table text can then be inserted into the dialog page text’s %{table}
tag.
I’ve even loaded the CSS from a file into a string and inserted that into a %{stylesheet}
tag. Also have done this for javascript. (I may have posted an example of this.
Anyway, this is the dead simple way of creating dynamic HTML.
There are more complex ways like using the ERB library or JavaScript frameworks like Vue. (The SketchUp API Doc site is generated using YARD, which builds the HTML pages with ERB. Some of the SketchUp web interfaces are now using Vue which is somewhat complex.)
Some other topics where I’ve discussed this:
What is the difference between these to methods of grabbing the html code?
@html_content = <<-HTMLOUTPUT
HTMLOUTPUT
@html = %[
]
I think I am reasonably confident in generating dynamic html however the one thing I’ve noted is that when I use a static html page I can use relative links to my images however when I’m sending a dynamic “string” the path for images is looking for is located here:
C:\Users%username%\AppData\Local\Temp
Is there a way to set the path so I can use images found within my plugin folder or better yet this path:
C:\Users%username%\AppData\Roaming\Medeek\2025\medeek_engineering_ext\images
You can use class ENV
eg. ENV['APPDATA']
(To list valid keys, put ENV.keys
to Ruby Console)
An example to use in html (A kind of alternative method what Dan shown…how to “include” variable value to the html string)
def dialog
image = 'test.png'
imagepath = File.join(ENV['APPDATA'], 'Medeek', '2025', 'medeek_engineering_ext', 'images', "#{image}")
@html = %[
<!doctype html>
<html>
<head>
<title>Title</title>
</head>
<body style="background-color:#F2EDE5;">
<img src='#{imagepath}' alt="test">
</body>
</html>
]
@dlg00 = UI::HtmlDialog.new(
dialog_title: "",
preferences_key: 'editpointload3',
scrollable: true,
resizable: true,
width: 450,
height: 450,
left: 1200,
top: 100,
min_width: 50,
min_height: 50,
max_width: 1600,
max_height: 1200,
style: UI::HtmlDialog::STYLE_DIALOG
)
@dlg00.add_action_callback("CLOSE_DIALOG") {|_, params|
@dlg00.close
}
@dlg00.set_html(@html)
@dlg00.show
end
__
You may also need to check the Sketchup.find_support_file method …
After testing a few options I realized that this works:
############
# Initialization Check for Engineering Plugin Parameters
WIN_OS = ( Sketchup.platform == :platform_win rescue RUBY_PLATFORM !~ /(darwin)/i )
if WIN_OS
appdata = ENV['AppData'].gsub(/(\\\\|\\)/,'/')
else
appdata = File.expand_path('~/Library/Application Support')
end
if appdata.respond_to?(:force_encoding)
APPDATA = appdata.dup.force_encoding("UTF-8")
else
APPDATA = appdata
end
su_version = Sketchup.version.to_i + 2000
APPDATA_MEDEEK_ENG = File.join(APPDATA,"Medeek/#{su_version}/medeek_eng_ext")
@Eng_logo_path = APPDATA_MEDEEK_ENG + '/library_logos/' + 'EOR_LOGO_1000' + '.jpg'
then in my html:
<img src="file:///#{@Eng_logo_path}">
I’ve got a long ways to go but what I am cooking up is a nicely formatted HTML report that can be printed/saved as a PDF:
See sample PDF output below:
Medeek Design Inc.pdf (198.7 KB)
ChatGPT helped me iron out some of CSS formatting issues, I was already 90% there, pulling from my previous work with my online calculators from my website.
A % string literal is just a double quoted string (allowing interpolation) and in the example spans multiple lines. It is straightforward and comes natural to me. The power is in the option to choose whatever delimiters we want to fit the scenario. Often the text is code like HTML, CSS or JavaScript which may need to use embedded single and double quotes, as well as other certain delimiters.
A Heredoc literal is convoluted and complex, and although more powerful with regard to indentation, etc., remembering all the quirks is hard for me (as I’m past 60.)
In actual practice I’ve found that I rather prefer to have my code types in separate files so that my editor can properly lex them. Ie, having JS code embedded in an HTML <script>
tag does not display correctly.
So mainly I use Ruby literal HTML or JS code strings for very simple examples or “quick and dirty” test code (posted with a bug report, etc.)
FYI: HTML does have a <base>
element. Ex (within the <head>
of your html document):
<!DOCTYPE html>
<html>
<head>
<title>My Dialog</title>
<base href="%{basepath}">
</head>
<body>
<!-- etc. etc. -->
</body>
</html>
So in the above text you you can replace the %{basepath}
as shown above.
Or if there was a local variable or constant for your extension path predefined, you can simply use #{BASEPATH}
doing normal interpolation.
Be sure to test thoroughly, as there was some quirky behavior with how SketchUp makes temporary copies in the TEMP path.
In SketchUp 2024 and 2025 (Ruby 3.2.2) …
ENV["AppData"].encoding
#=> #<Encoding:UTF-8>
FYI, I myself have never had to do the “force_encoding” thing, but even so it was only ever an issue on Windows platform. I can’t remember when ENV
was fixed but I believe that it was.
EDIT: It was Ruby 3.0.0
- Windows: Read
ENV
names and values as UTF-8 encoded Strings [Feature #12650]