sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    WebDialog.execute_script on OSX

    Scheduled Pinned Locked Moved Developers' Forum
    2 Posts 2 Posters 364 Views 2 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J Offline
      jeemang
      last edited by

      Howdy all;

      For the last couple of months I've been working on building a UI for a plug-in using the APIs WebDialog object. During this time I've encountered a fair amount of difficulty in exchanging data between WebDialog API objects and their HTML/CSS/Javascript. The most significant problem I've had is getting the WebDialog's execute_script method to work as I expect on OSX. I wanted to use this post to document some of the problems I've discovered, and workarounds I've found.

      My difficulty centres on using the execute_script method to call user-defined JavaScript functions during WebDialog creation.

      For example:

      HTML

      
      <html>
      <script type="text/javascript">
        function test_alert() {
      	alert("Hello world!");
        }
      </script>
      <body>
      <h3>TEST</h3>
      </body>
      </html>
      
      

      Ruby

      def test_wd
          $my_dialog = UI;;WebDialog.new("Selection Info", false, "Selection Info", 200, 200, 200, 200, true)
          html_path = Sketchup.find_support_file "rubyjstest.html" ,"Plugins/testing"
          $my_dialog.set_file(html_path)
          $my_dialog.show_modal()
          $my_dialog.execute_script("alert('Hello World!');")
          $my_dialog.execute_script("test_alert();")
      end
      

      When I execute the test_wd method, the alert that's called directly within the execute_script method fires, but the one wrapped in the test_alert function in the HTML file does not. Changing the order of the execute_script calls doesn't change this.

      However, if the test_alert method is called later -- whether by attaching it to a UI event (eg a button), or from the Ruby console, it works as expected. This suggests the issue in some way involves timing -- whether because of threading issues, or asynchronism, or something else.

      To investigate the issue of timing, I did some more tests. First, I modified the Ruby code to look like so:

      def test_wd
          $my_dialog = UI;;WebDialog.new("Selection Info", false, "Selection Info", 200, 200, 200, 200, true)
          html_path = Sketchup.find_support_file "rubyjstest.html" ,"Plugins/testing"
          $my_dialog.set_file(html_path)
          $my_dialog.show_modal()
          $my_dialog.execute_script("alert('Hello World!');")
          sleep 5  ## ADDED THIS LINE, USING RUBY'S BUILT IN SLEEP COMMAND
          $my_dialog.execute_script("test_alert();")
      end
      

      I quickly found that this crashes Sketchup every time. To test if this was just a matter of the "sleep" command and the API not getting along period, I ran the following code:

      def test_sleep
          puts "start"
          sleep 5
          puts "end"
      end
      

      This runs as expected. Armed with this new knowledge, I further modified the test_wd method to look like this:

      def test_wd
          $my_dialog = UI;;WebDialog.new("Selection Info", false, "Selection Info", 200, 200, 200, 200, true)
          html_path = Sketchup.find_support_file "rubyjstest.html" ,"Plugins/testing"
          $my_dialog.set_file(html_path)
          $my_dialog.show_modal()
          $my_dialog.execute_script("alert('Hello World!');")
          for i in 1..9999999   ##
              2 + 4 / 3             ## UGLY JUNK ADDED TO USE UP TIME
          end                         ##
          $my_dialog.execute_script("test_alert();")
      end
      

      Running this results in the first alert fires as expected. At about the same time, an empty WebDialog window is created, but the HTML within it is not rendered -- this doesn't happen until after the for loop finishes executing. And, most importantly, the second alert still doesn't fire.

      Knowing that the HTML doesn't render until, it seems, everything within the test_wd method has run, I got the idea to use jQuery's ready() method. So, I modified the HTML to look like so:

      <html>
      <script type="text/javascript" src="./jquery-1.4.4.min.js"></script>
      <script type="text/javascript">
      	function test_alert() {
      		alert("This is a test alert");
      	}
      	
      	$(document).ready(function() {
      		test_alert();
      	})
      </script>
      <body>
      <h3>TEST</h3>
      </body>
      </html>
      

      I also got rid of the $my_dialog.execute_script("test_alert();") line from the test_wd method -- essentially, I moved it, from the Ruby code into the $(document).ready() callback function. The result: SUCCESS!

      After completing these tests, I set about restructuring my code to take advantage of the knowledge I had gained, and ended sticking a few consecutive calls to functions I'd created for my menu's initialization into the $(document).ready() callback. It was here that I ran into yet another stumbling block that has been noted in other posts: the asynchronism of Ruby callbacks. The final thing I'll add to this thread is a simple workaround I developed that seems to help here: the JavaScript setTimeout function. This function allows you to execute a JavaScript command, provided as a string argument, after a given delay, provided, in milliseconds, as a numerical argument. For example:

      setTimeout("my_function()",1000)
      

      calls my_function() after a 1 second delay. I found that setting the delay to even 1 ms seems to avoid any trouble with consecutive Ruby callbacks.

      So, that's it. Hopefully this is in some way helpful to people like me who are hacking around with the eccentric, somewhat buggy, and sparsely-documented world of WebDialogs.

      1 Reply Last reply Reply Quote 0
      • thomthomT Offline
        thomthom
        last edited by

        I use the jQuery .ready() event that loads when the DOM is ready to make a callback back to Ruby. Then I can 100% sure I can use execute_script. Works on both platforms. No need for sleep or timers.

        I've made a few notes about WebDialogs: http://forums.sketchucation.com/viewtopic.php?f=180&t=23445

        Thomas Thomassen — SketchUp Monkey & Coding addict
        List of my plugins and link to the CookieWare fund

        1 Reply Last reply Reply Quote 0
        • 1 / 1
        • First post
          Last post
        Buy SketchPlus
        Buy SUbD
        Buy WrapR
        Buy eBook
        Buy Modelur
        Buy Vertex Tools
        Buy SketchCuisine
        Buy FormFonts

        Advertisement