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

    WebDialog on Mac (call to Google SU engineers)

    Scheduled Pinned Locked Moved Developers' Forum
    25 Posts 10 Posters 8.4k Views 10 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.
    • M Offline
      mocathe1st
      last edited by

      Hi All,

      I've currently run into the synchronisation problem described above. The JavaScript file I have currently written is fairly simple, and only passes messages from Flash via JavaScript to Ruby. I've got a single function to take care of this. However, when I send a quick succession of messages from Flash to Ruby via JS most of the commands get lost on the Mac, this works fine on the PC.

      I was just wondering if anyone found a solution to the synchronisation problem, is there a way to create a JavaScript buffer or a way of synchronising the messages?

      Best Regards,
      Malcolm Murray

      1 Reply Last reply Reply Quote 0
      • chrisglasierC Offline
        chrisglasier
        last edited by

        @mocathe1st said:

        Hi All,

        I've currently run into the synchronisation problem described above. The JavaScript file I have currently written is fairly simple, and only passes messages from Flash via JavaScript to Ruby. I've got a single function to take care of this. However, when I send a quick succession of messages from Flash to Ruby via JS most of the commands get lost on the Mac, this works fine on the PC.

        I was just wondering if anyone found a solution to the synchronisation problem, is there a way to create a JavaScript buffer or a way of synchronising the messages?

        Best Regards,
        Malcolm Murray

        Please take a look at this topic which includes the following:

        @unknownuser said:

        Also included is revisions to code to enable testing Mac compatibility, viz:

        START control employed as no Sketchup.active_model with Mac when Ruby scripts are first loaded. (related post)

        Code rewritten so that no window.location call is followed by any javascript statements. (related post)

        Feedback from Mac users and/or coders would be much appreciated.

        together with a download of an example.

        I think it very important for the expansion of webdialog use to find and publish the best common solution. I don't expect the SU team has this at the top of their list.

        I look forward to further discussion.

        My regards

        Chris

        With TBA interfaces we can analyse what is to be achieved so that IT can help with automation to achieve it.

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

          @chrisglasier said:

          As a result, if on Mac you call in sequence 2 javascripts:

          Code: Select all
          dlg.execute_script "document.getElementById('Field1').value = '1' ; "
          dlg.execute_script "document.getElementById('Field2').value = '2' ; "

          then,

          • the first Ruby statement returns even before its javascript function starts executing
          • Most likely, only the second javascript function will be executed, because it will override the first one.

          On Windows, it works fine. Each 'execute_script' Ruby statement will only return when the javascript function has finished execution.

          I've been doing some tests on OSX, using the console. First I create a new WebDialog object:

          
          w=UI;;WebDialog.new('test', true)
          w.set_html('<html><body>Hello</body><html>')
          w.show
          
          

          Then I try with a loop to send lots of .execute_script commands.

          
          w.execute_script('document.body.innerHTML="";')
          (0..100).each{|i| w.execute_script('document.body.innerHTML="<br>Hello #{i}";') }
          
          

          When I run the script, it adds all the lines "Hello 1" to "Hello 100" - not a single .execute_script is lost...
          Also, the ruby method did not return until it was all done.

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

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

            Testing the other way - making a loop in the Javascript to do 100 window.location = 'skp:callback' and I only register the last callback. All the rest appear to have been suppressed. I only see the async going from the WebDialog to Ruby. Not the other way around.

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

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

              Here's a sample code I used to test:


              webdialog.rb

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

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

                I improved the test. Now the Ruby to WebDialog method creates a new DIV element every time, and it insert the DIV into the last inserted DIV. So if the calls are synchronous - all the elements should be nested.

                On both PC and OSX - the elements are nested. It still appears to me that it's just the Webdialog to Ruby path that's async. Which means it's related to window.location.


                webdialog.zip

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

                1 Reply Last reply Reply Quote 0
                • jeff hammondJ Offline
                  jeff hammond
                  last edited by

                  i have no idea what you're actually talking about thomas but i'm glad you are 😄 👍
                  i fear the day of a great plugin coming out only to hear this once again : "sorry, pc only"

                  dotdotdot

                  1 Reply Last reply Reply Quote 0
                  • chrisglasierC Offline
                    chrisglasier
                    last edited by

                    @thomthom said:

                    window.location

                    Yes that's the culprit as I understand what Fredo said and you have demonstrated (to yourself).

                    With TBA interfaces we can analyse what is to be achieved so that IT can help with automation to achieve it.

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

                      @chrisglasier said:

                      @thomthom said:

                      window.location

                      Yes that's the culprit as I understand what Fredo said and you have demonstrated (to yourself).

                      No, he also described .execute_script to be async - which I can't see. From my tests it returns after the Javascript is done, not before.

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

                      1 Reply Last reply Reply Quote 0
                      • fredo6F Offline
                        fredo6
                        last edited by

                        @thomthom said:

                        @chrisglasier said:

                        @thomthom said:

                        window.location

                        Yes that's the culprit as I understand what Fredo said and you have demonstrated (to yourself).

                        No, he also described .execute_script to be async - which I can't see. From my tests it returns after the Javascript is done, not before.

                        Tom,

                        There are 2 issues which all boil down to the problem of windows.location being asynchronous.

                        1. when you execute a script that should call a Ruby call back, the script returns before the call back is executed. This is unfortunately a design problem due to Safari, which I understand the SU team cannot do anything about easily.

                        2. in addition, the skp protocol eats up all callbacks and keep the last one, when sent in sequence. So you simply miss some callbacks, even if they were to be recieved asynchronously. This is a problem of implementation by the SU team (it would have deserved a buffering).

                        I had to find workarounds for both problems in my web dialog implementation in LibFredo6, precisely by buffering the callbacks in a hidden HTML field and synchronizing the Ruby code.

                        If I have some time, I will check if I could isolate the code for reuse by others. No promise however.

                        Fredo

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

                          @unknownuser said:

                          1. when you execute a script that should call a Ruby call back, the script returns before the call back is executed. This is unfortunately a design problem due to Safari, which I understand the SU team cannot do anything about easily.

                          Ah, ok. So the .execute_script is synchronous then. It's just the Javascript to Ruby callback (the skp: protocol) that's async.

                          So it's then safe to call .execute_script which calls a javascript method that stores the return data in a hidden input field where you then use .get_element_value to return data, correct? This is what I see from my testing - but I just want to make sure I'm not missing some cases here.

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

                          1 Reply Last reply Reply Quote 0
                          • fredo6F Offline
                            fredo6
                            last edited by

                            @thomthom said:

                            So it's then safe to call .execute_script which calls a javascript method that stores the return data in a hidden input field where you then use .get_element_value to return data, correct? This is what I see from my testing - but I just want to make sure I'm not missing some cases here.

                            Correct. This is what should be done to solve problem #1.
                            Can you confirm however, because it's been a while since I did not work on Web dialogs, and I don't want to mislead anybody.

                            Fredo

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

                              I've tried with loops of .execute_string followed immediately by .get_element_value where I call a Javascript function to modify an argument I pass to it and fetch the result with .get_element_value. Works fine on PC and OSX.

                              
                              // #bar is a hidden INPUT element
                              function foo(i)
                              {
                                document.getElementById('bar').valie = i * i;
                              }
                              
                              
                              
                              (2..10).each { |i|
                                dialog.execute_script("foo(#{i});")
                                x = dialog.get_element_value('bar')0
                                puts "i; #{i} - x; #{x}"
                              }
                              
                              

                              This seems to work fine.

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

                              1 Reply Last reply Reply Quote 0
                              • R Offline
                                RonB
                                last edited by

                                Sorry for exhuming this thread, but is there a workaround available now?
                                Actually i'm facing the same problem as described here and its totally driving me nuts.

                                I'm hoping for good news.

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

                                  Depends on what you are doing.

                                  One way is to make SketchUp pump for information instead of Javascript pushing information.

                                  Another way, if you need Javascript to push information is to set up a pump-system. You create a stack (an array) of the callbacks from JS to SU you want to perform. A function then takes the first item on the stack and send it to SketchUp. It then waits for SketchUp to send notification back that the message was received. Then the next item on the stack is sent ... and so on.

                                  It requires you to restructure how you pass the information around.

                                  If you give a specific usage example we could probably come up with suitable design.

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

                                  1 Reply Last reply Reply Quote 0
                                  • R Offline
                                    RonB
                                    last edited by

                                    hey thomthom, thanks for your quick response.

                                    I do have a website providing two informations for sketchup

                                    1. the actual needed version of the plugin (provided by hidden input field)

                                    2. a stream (string) of informations (provided by hidden input field)

                                    3. needs to be checked directly when the webdialog loads the site and 2) when a button is clicked (because it can be chosen which set of informations to load).

                                    Actually it is working on a PC but not on a Mac.
                                    The Website contains both window.location skp callbacks but the second one is only triggered by button.

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

                                      That sounds like you are sending back before the HTML DOM is ready. If you use jQuery use the 'ready' event to wait for the HTML DOM to be ready.

                                      How have you currently structured the loading event?

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

                                      1 Reply Last reply Reply Quote 0
                                      • R Offline
                                        RonB
                                        last edited by

                                        I guess you're right... i do have the skp callback somewhere in between of the page.
                                        I'll try to change it to jquery with the "wait for doc ready"-function and report back here.

                                        to answer your question: I'm creating a webdialog and connect by set_url to an url.
                                        Then i'm showing the dialog and wait for the callbacks.
                                        I hope that's what you was asking.

                                        1 Reply Last reply Reply Quote 0
                                        • A Offline
                                          Aerilius
                                          last edited by

                                          I again stumbled across this issue, knowing JavaScript continues before the Ruby callback ends, but I didn't think that this async nature prevents subsequent urls to reach Ruby.

                                          Example of the Problem:

                                          w = UI;;WebDialog.new("Test")
                                          w.add_action_callback("1"){|dlg, param| puts("first callback")}
                                          w.add_action_callback("2"){|dlg, param| puts("second callback")}
                                          w.set_html("<html><body><script>window.location='skp;1'; window.location='skp;2';</script></body></html>")
                                          w.show
                                          

                                          On Windows:
                                          ` %(#000000)[> first callback

                                          second callback]On OSX: > second callback`

                                          Example solution:
                                          Doesn't make anything synchronous, but makes sure all urls reach Ruby.

                                          
                                          /* class Scheduler;
                                           * This class makes sure given functions are not called more frequently than a
                                           * certain time limit.
                                           * .queue(function)
                                           *     Adds a new function. All collected functions will be executed one by one with a time interval inbetween.
                                           */
                                          Scheduler = function(dt) {
                                            var scheduled = []; // Array of scheduled functions.
                                            var t = 0; // Tracks the time of the last function call.
                                            dt = (dt) ? Number(dt) ; 250; // Minimum time interval in milliseconds between subsequent function calls.
                                            this.queue = function(fn) {
                                              scheduled.push(fn);
                                              check();
                                            };
                                            var run = function() {
                                              var toRun = scheduled.shift();
                                              toRun();
                                            };
                                            var check = function() {
                                              var c = Number(new Date().getTime());
                                              // Last function call is long enough ago (or first time), execute given function immediately.
                                              if (c > t && scheduled.length > 0) {
                                                run();
                                                // Set timer for next possible function call.
                                                t = c + dt;
                                                window.setTimeout(check, dt);
                                              }
                                            };
                                          };
                                          
                                          
                                          /* An instance of the Scheduler */
                                          var callRubyScheduler = new Scheduler(1);
                                          
                                          
                                          /* Function to call a SketchUp Ruby action_callback. */
                                          var callRuby = function(name, data) {
                                            if (!data) { data = ''; }
                                            var url = 'skp;' + name + '@' + encodeURIComponent(data);
                                            callRubyScheduler.queue(function(){ window.location.href = url; });
                                          };
                                          
                                          

                                          On Windows:
                                          ` %(#000000)[> first callback

                                          second callback]On OSX: %(#000000)[> first callback
                                          second callback]`

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

                                            Another way, that doesn't involve timing is to stack up messages in JS that call a receiving ruby method which takes care of forwarding to the correct ruby method and then send a ping back to JS which can then send the next message in the queue.

                                            I made a version like that which also gives JS a return value from ruby.

                                            Sent from my LT25i using Tapatalk 2

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

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

                                            Advertisement