-
Notifications
You must be signed in to change notification settings - Fork 2
Sharing data between SketchUp Ruby and Javascript
If you are building rich WebDialogs in your SketchUp Plugin, then you are probably using Javascript + DHTML (Dynamic HTML) to show the UI and handle user input. In practical terms, this means that you could easily have as much Javascript code in your plugin as Ruby code! But the SketchUp API documentation doesn't give much guidance on using Javascript to talk to SketchUp. What's a coder to do?
Sharing data between Javascript and Ruby can be a bit of a black art. The Ruby API provides two mechanisms that we can leverage:
-
WebDialog.add_action_callback()
allows us to define a Ruby method that a WebDialog can call. This allows us to send data DOWN from Javascript to Ruby. -
WebDialog.execute_script()
allows us to run a bit of Javascript code from inside Ruby. This allows us to send data UP from Ruby to Javascript.
By using these two mechanisms together, we can create a nice, generic way for Javascript to get whatever it needs from Ruby.
For our example, let's imagine we have two files inside our Plugins directory: selectionInfo.rb and selectionInfo.html. Together, these files provide a new feature to SketchUp: a floating window that shows us how many objects are selected inside SketchUp.
Our first step is to show a WebDialog and establish our action callback. Here's the minimal code required to make this work:
selectionInfo.rb
my_dialog = UI::WebDialog.new("Selection Info", false, "Selection Info", 200, 200, 200, 200, true)
selectionInfo.rb
my_dialog.add_action_callback("get_data") do |web_dialog,action_name|
UI.messagebox("Ruby says: Your javascript has asked for " + action_name.to_s)
end
selectionInfo.rb
html_path = Sketchup.find_support_file "selectionInfo.html" ,"Plugins"
my_dialog.set_file(html_path)
my_dialog.show()
selectionInfo.html
<html>
<script>
function callRuby(actionName) {
query = 'skp:get_data@' + actionName;
window.location.href = query;
}
</script>
<body>
<h3 id="output">You have 0 things selected.</h3>
<input type="button" onclick="callRuby('pull_selection_count')" value="Refresh">
</body>
</html>
If you create these two files and save them into your Plugins directory, you'll see a very simple WebDialog the next time you restart SketchUp. Click on the "Refresh" button and you'll see a messagebox that was generated by our Ruby (but controlled based on data from the Javascript.)
Make sense? We now have a mechanism for sending data down to Ruby, which is a way for Javascript to ask Ruby a question. Now we just need Ruby to provide an answer...
The next step in our data sharing scheme requires us to respond. Let's add a few lines of code to our files...
selectionInfo.rb
my_dialog = UI::WebDialog.new("Selection Info", false, "Selection Info", 200, 200, 200, 200, true)
selectionInfo.rb
my_dialog.add_action_callback("get_data") do |web_dialog,action_name|
if action_name=="pull_selection_count"
total_selected = Sketchup.active_model.selection.length
js_command = "passFromRubyToJavascript("+ total_selected.to_s + ")"
web_dialog.execute_script(js_command)
end
end
selectionInfo.rb
html_path = Sketchup.find_support_file "selectionInfo.html" ,"Plugins"
my_dialog.set_file(html_path)
my_dialog.show()
selectionInfo.html
<html>
<script>
function callRuby(actionName) {
query = 'skp:get_data@' + actionName;
window.location.href = query;
}
function passFromRubyToJavascript(value) {
var message = "You have " + value + " items selected.";
document.getElementById('output').innerHTML = message;
}
</script>
<body>
<h3 id="output">You have 0 things selected.</h3>
<input type="button" onclick="callRuby('pull_selection_count')" value="Refresh">
</body>
</html>
Save these changes, and then restart SketchUp. Now when you click on the "Refresh" button, you get an updated web page showing the number of objects selected.
Looking ahead: Using JSON for more complex data We've been working with an extremely simple example where we're passing a single number. In a real world application you would probably be sending more complex data. In this case, JSON (Javascript Object Notation) is the perfect mechanism. It's a way where you can pass nested objects and arrays in a single command.
We'll explore more about JSON in a future blog post. But for now, consider the following example.
selectionInfo.rb
js_command = "passFromRubyToJavascript({typename:'ComponentInstance',name:'Bryce',x:10.5,y:13.5,z:0.0})"
web_dialog.execute_script(js_command)
This kind of approach is a great way to allow Javascript to get large, structured data sets out of SketchUp whenever your application needs them. Stay tuned for a deeper exploration of this idea.