Safari Extension Questions

Like everyone else at this point, I'm still climbing the learning curve, but here's how I've handled this problem:

I have a simple extension with no chrome and one injected end script (script.js). For the purpose of loading settings I've added a simple global page (proxy.html). When script.js is injected, it sends a getSettings message to proxy.html. proxy.html responds with a setSettings message, and script.js continues initialization.

The most helpful page I've found in the docs on this topic is Messages and Proxies.

proxy.html:

<!doctype html>
<html lang="en">
<head>
  <script type="text/javascript">
    safari.application.addEventListener( "message", function( e ) {
      if( e.name === "getSettings" ) {
        e.target.page.dispatchMessage( "setSettings", {
          sort_keys: safari.extension.settings.getItem( "sort_keys" )
        } );
      }
    }, false );
  </script>
</head>
<body></body>
</html>

script.js:

( function() {
  var settings, init = function() {
    // do extension stuff
  };

  // listen for an incoming setSettings message
  safari.self.addEventListener( "message", function( e ) {
    if( e.name === "setSettings" ) {
      settings = e.message;
      init();
    }
  }, false );

  // ask proxy.html for settings
  safari.self.tab.dispatchMessage( "getSettings" );
}() )

It took me several days, but I think I found a workable solution using the canLoad() messaging method. My injection script retrieves settings by calling the global HTML page like this:

settings = safari.self.tab.canLoad( event );

My global HTML file, in turn, returns those settings as:

settings = {
  'setting1': safari.extension.settings.getItem( 'setting1' )
}

msgEvent.message = settings;

It's still a bit more "hacky" than I'd like. I can't seem to simply return the settings object itself, so I have to compile a new object by retrieving each setting manually. Not ideal, but it does seem to be effective.


EDIT: like you said in your initial post update, the injected script doesn't have the same kind of access that a global HTML page would have. This is my working solution, imagine you want to know the value of setting "foo" in the injected script:

Injected script code:

function getMessage(msgEvent) {

    if (msgEvent.name == "settingValueIs")
        alert("Value for asked setting is: " + msgEvent.message);

}

safari.self.tab.dispatchMessage("getSettingValue", "foo"); // ask for value
safari.self.addEventListener("message", getMessage, false); // wait for reply

Global HTML code:

function respondToMessage(messageEvent) {

    if (messageEvent.name == "getSettingValue") {

           // getItem("foo");
        var value = safari.extension.settings.getItem(messageEvent.message);
        // return value of foo to injected script
           safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("settingValueIs", value);

    } 

}

safari.application.addEventListener("message",respondToMessage,false);

Hope this helps !


Initial post: I'm having the same 2nd problem as you, I can't access my settings (or secureSettings) from an injected script. In my case the script is loaded after page load, but even that way I can't use safari.extension.settings.

The only way it works is with a toolbar/button, the HTML behind that element can getItem and setItem as expected.

My conclusion is that, for some reason, injected scripts can't access settings (actually, they don't even seem to have access to the safari element). Bug or intended feature, that's left to figure out.