Doug Smith
Doug Smith

Reputation: 29316

What's wrong with this simple Safari Extension code?

I'm creating a Safari extension that will stay in Safari's menubar, and upon being clicked, it will open all links containing a certain string. However, it's not working.

This is what my extension builder screen looks like: https://i.sstatic.net/GSBRw.png

I don't have any external scripts set as I have the script in my HTML file, because I only want it to run when clicked.

And I have a global.html page with the following code in it:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head>
        <script type="text/javascript" src="jquery.js"></script>
    </head>
    <body>
        <script>
            safari.application.addEventListener("comnand", performCommand, false);

            Function performCommand(event) {  
                if (event.command == "open-designs") {  
                    $(document).ready(function() {
                        $('a[href*="/Create/DesignProduct.aspx?"]').each(function() {
                            window.open($(this).attr('href'),'_blank');
                        });
                    });
                }  
            }
        </script>
    </body>
</html>

Should this not work? I'm allowed to mix jQuery and JS write, as jQuery is JS? And isn't that how I'd target the links?

Upvotes: 3

Views: 1871

Answers (2)

Alex Taylor
Alex Taylor

Reputation: 1823

The problem is that your extensions Global page does not have direct access to the currently loaded page's DOM. To be able to achieve what you need, you'll have to use an Injected Script and use the messaging proxy to talk to the page.

For instance, your global would look like:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head>
        <script type="text/javascript" src="jquery.js"></script>
    </head>
    <body>
        <script>
            $(document).ready(function() {
                safari.application.addEventListener("command", performCommand, false);
            });

            function performCommand(event) {  
                if (event.command == "open-designs") { 
                    safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("open-designs", "all");
                }  
            }
        </script>
    </body>
</html>

And then, in Extension Builder, you'd need to add two "Start Scripts", one is jquery, the other, a new file that gets loaded into the page and looks similar to this:

function extensionname_openAll(event)
{
    if (event.name == 'open-designs')
    {
        $('a[href*="/Create/DesignProduct.aspx?"]').each(function(index,elem) {
            window.open($(elem).attr('href'),'_blank');
        });
    }
}
safari.self.addEventListener("message", extensionname_openAll, true);

Upvotes: 4

Lix
Lix

Reputation: 47956

  1. One clear thing I'm seeing is that your $(document).ready() function is located within another function. This essentially alleviates the need for a $(document).ready() provided you only call that function once the DOM and jQuery are fully loaded.

    Rearrange your code to only add the event listener once the DOM and jQuery are loaded. That is what you use the $(document).ready() callback for.

  2. In addition there is one more issue I see with the callback function for .each(). That function needs to handle two parameters the index and the element that it references. A call to each() iterates over a collection of elements. For each element entering the callback function, its index is passed as a parameter and also the element itself that is located at that index. Check out the documentation for more info.

$(document).ready(function() {
 safari.application.addEventListener("command", performCommand, false);
 console.log("Document is ready to go!");
});

function performCommand(event) {  
  console.log("event recieved");
  if (event.command == "open-designs") {     
    console.log("got 'open-designs' event");
    $('a[href*="/Create/DesignProduct.aspx?"]').each(function(index,elem) {
      console.log("opening window", index, elem);
      window.open($(elem).attr('href'),'_blank');
    });
  }  
}

You use the $(document).ready() callback as an indication that your DOM is ready and jQuery has been initialized. Once you know everything is ready, you can setup your event listener. The function performCommand() can not be called before the listener is added (unless there is some other reference to it).

Upvotes: 3

Related Questions