Internet & Web • OS X • 44:35
Safari Extensions can add buttons to the Safari toolbar, display a bar with custom content, or modify the appearance of a web page — all with standard HTML, CSS, and JavaScript. See how easy it is to get started with Safari's built-in Extension Builder, and how to create an extension that can execute scripts, apply CSS styles, and display context menus. Discover new user interface components for extensions such as popovers, and learn to leverage additions to the Extensions API to invoke Safari Reader, detect how users are interacting with Safari, and more.
Speakers: Jessie Berlin, Brian Weinstein
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
All right. Hi, I'm Brian Weinstein, and I'm here to talk to you guys about what is new in Safari Extensions. We're going to start by going through a quick recap of what Safari Extensions are, why you would want to use them, and what they are good for. And then we're going to dive right into what's new with Safari Extensions. We have some new events that we have given to Safari Extensions, and some new UI.
So, before we begin with talking about why you would want to use a Safari Extension, I would just like to say, if this is going to be new information, to please watch the videos from last year. There are two full sessions about how to create Safari Extensions, and they're just great. They go into much more detail than I'm going to right here.
So why should you make an extension if you haven't made one before? You might want to add something to Safari's user interface that you can't do with just a web page. You might want to add an extension bar that's always there no matter what web page the user is on, or you might want to add an extension toolbar item to natively go into Safari's toolbar.
You might want to provide a persistent experience that one web page can't provide. If you have an email client, instead of having the user keep the email open in a background tab, you might want to show a toolbar item that constantly checks your email, and then shows a badge with how many unread emails you have when clicking that toolbar item, and that will take you directly to the email. Or, you might want to put together a mashup of two sites that you use, and create a new view of these two websites without requiring your own server. You can do all the page loading and the graphics on the user's local computer.
So let's talk about what Safari Extensions are. They are all web technologies. They're HTML, JavaScript, and CSS. There's no native code in Safari Extensions. And so what this means is if you're familiar with using web development, it's incredibly easy to develop. It's just HTML and JavaScript and CSS. There isn't a new technology to learn, so it's incredibly easy to write great Safari Extensions. And since we're using HTML, it's secure, and you're not going to see crashes.
So let's talk about how the basic structure of Safari without extensions. So when a user is browsing in Safari, you might have a few windows open, and each window has a few tabs, and each tab has a web page inside of it. Safari also provides some additional UI. It provides bars, like the bookmarks bar or the tab bar, and it can provide toolbar items like back, forward, or home. And then you have your Safari extensions.
The extensions are a self-contained bundle that are made up of a few different components. You can add toolbar items in your extension. You can also have bars and context menus.
[Transcript missing]
So, now you've seen a little bit of how extensions are put together, you might want to get started building them right now.
So to do that, you need to go to the Safari Developer Center and sign up for the free Safari Developer Program and download your certificate. You can do that at developer.apple.com/safari and you can get started today. And once you do, you can open up the Develop menu and show the Extension Builder, which is your one-stop shop for developing and building extensions.
You can specify your various UI elements here, and you can put together some information that the user sees, like the name that's displayed or a website that they can find more information about your extension. So, that was a quick recap of what extensions can do and how they are built. And once again, if this was new information to you, please watch the videos from last year. They go into much more detail. And they just did a great job. Let's talk about what's new with Safari extensions.
We introduced extensions at WWDC a year ago, and we have just been blown away by some of the extensions that you guys have put together. They've just been incredible and done things we couldn't have even imagined. However, in the process, we got a lot of feedback about what you guys would also like to see in extensions, and we've incorporated that and are excited to tell you about what's new today.
One of the first things that we heard a lot of feedback about is you want to know how users interact with the browser. Do they keep a lot of windows open? Do they keep a lot of tabs open? And how long do they stay at certain pages? We've added some new events that let you determine just that and use that to provide an even more custom experience to your users in an extension.
Another thing we introduced in Safari 5 was Safari Reader. And it's been a huge hit, and it's a great way for people to read articles. But we've also heard you want to be able to interact with Reader in your extensions. And we've added Reader events that allow you to do that.
The first event we added is the Available event. And that is sent to a tab when it's determined that Reader is available for that tab. This is a great time to automatically enter Reader and provide a great article reading experience for your users using the enter and exit APIs we've added on the Reader object.
However, the user might not want to enter Reader on every site. They might want to on site A, but not site B. And we've also added the Activate and Deactivate events. Which tells you when the user enters or exits Reader. If they enter Reader on site A, you can use the Available event to always enter Reader on site A. And if they don't use it on site B, it doesn't have to automatically enter it on site B.
So, along with Reader, you also wanted to know how the user interacts with windows and tabs. We've also added window and tab events to make this easier. Let's say you have an extension that keeps track of all of the tabs that a user's opened and has never read.
I know that happens to me all the time. I start opening links in background tabs, and I just get distracted and forget which ones I've read. So, you would probably want to listen for when a tab is opened, and add it to your list of unread tabs, and then you would want to remove it when it's either closed or selected.
And to help you get started with that, we've added open and close events, which are sent to a tab or a window when it opens or closes. Let's take a look at when these events are fired in a typical browsing session. So, when the user opens a window, an open event is sent to that window, and a tab will also be opened as part of the process, and an open event will be sent to that tab.
When the user opens a second tab, an open event is sent to that tab. Some navigation might happen, and then the user might be done with that tab, and we'll close it, and we send a close event to that tab. And then when the window is closed, a close event is sent to every tab in the window, and then to the window itself.
However, this only gets us part of the way to that extension that keeps track of your unread tabs. You also need to know when a tab is selected, so we can also remove it from the unread tabs, because that's when it gets read. So we've also added activate and deactivate events that are sent to a tab or window when it is activated or deactivated.
So if you have a window with two tabs, and you have the first tab selected, and you want to read something on the second tab, first a deactivate event is sent to tab one, and then an activate event is sent to tab two. The deactivate event is always sent first.
Now, for another interesting extens — for another extension that I've wanted to see is how many people, when they're trying to get some work done, end up on Reddit or Facebook, and before you know it, an hour of your day is gone. Yeah, yeah, it happens. What if you could have an extension that warned you before you went to one of these sites, and if you went to the site, it kept track of how long you were on the site, and told you how long you were distracted in a certain day? It might be a little depressing to look at, but it would be a pretty useful extension.
So we've also added Before Navigate and Navigate Events. The Before Navigate Event is sent to a tab before the user navigates within that tab, and the navigation is cancelable by calling preventDefault on the event. So you can prevent that navigation from happening. And then if the navigation happens, a Navigate Event is sent when the mainframe finishes loading in a tab, and then you can keep track of how long the user was on the site by looking at the time the navigation happened and comparing it to the time they navigated away. Those are the events that we've added to Safari Extensions. How are they used? Since we're just using JavaScript, HTML, and CSS in our extensions, it makes sense for these to be just like DOM events, which means that it's the addEventListener syntax that you know and love.
So for adding listeners, since a lot of these events are fired on both windows and tabs, if you wanted to listen for when new windows open, you wouldn't want the same handler to be fired. So if you wanted to listen for when any tab or window is opened, you could add a capturing event listener to the Safari application and listen for the open event. Or if you wanted to listen for when a specific tab is activated, you could add an activate listener just to that one tab.
However, since these events are fired on both windows and tabs, you need some way to determine if it was a window or a tab, especially if you're using these capturing event listeners. And so we've also added the ability to use the instance of operator. And so you can check if the event target is an instance of a browser tab, or if the event target is an instance of a browser window, and do your behavior accordingly.
So now that we've seen some of these events, let's take a look at how easy it is to use these events to put together something awesome. When I was talking about the extension that keeps track of your unread tabs, that's a pretty great idea, so let's put that together right now. So now we have Safari open, so let's go into the develop menu and open the extension builder.
I have set up a few things about — I've set up a little bit of information about my Unread Tabs extension. I've set up the name that's displayed to the user and a description. So the basic way that this extension is going to work is it's going to listen for when tabs are opened and add them to our list of unread tabs. And then when a tab is either activated or closed, it's going to remove them from our list of unread tabs. And then we can show the user the number of unread tabs they have in each window.
And we can add a toolbar item, and then we have a natural way to show that little bit of information. We can use a badge on the toolbar item. So let's set up a global page to manage the events, and then let's add a new toolbar item. We'll call it "Unread Tabs." And we'll give it an image, and we will set up an identifier — just unread tabs.
So now our extension is configured. All we have to do is write the code. So let's open up our global HTML page. And since these are just HTML, all we need to do is set up our HTML document. But since this page isn't visible to the user, all we have to do is add a script tag.
So this extension will keep track of unread tabs, so we need a list of unread tabs. And then we also need to listen for when tabs are opened, activated, or closed. And then we also need to update our toolbar item state, so we'll listen for a validate event, which is sent to a toolbar item whenever an interesting event happens in the browser, and it's a good time to update your toolbar item state. So we now have our list of unread tabs, and we have our event listeners.
When a tab is opened, all we want to do is, if it's actually a tab, we want to add it to our list of unread tabs. So all we do is we check if our event target is a browser tab, we add it to our list of unread tabs. That's a pretty easy start. So now if a tab is either activated or closed, we remove it from our list of unread tabs, and since we'll be doing that in two different locations, let's have a function that does it for us.
So all this function does is it looks for a tab in the list of unread tabs, and if it's there, removes it. Then, when a tab is either activated or closed, all it needs to do is check if it's actually a tab and remove the tab from the unread tabs.
Now, for the validate event, what we want to do is we want to look at all of our unread tabs and see how many of them belong to the same browser window as the toolbar item we're updating our state for. So we have our validate handler, and it first checks the event command, making sure it's unread tabs, and then it looks over all the unread tabs and checks to see if their browser window is the same browser window as the toolbar item, which is the event target. And then we will disable our toolbar item if there aren't any unread tabs in the window, and we will set our badge to be the number of unread tabs we have in that window.
So let's save, go back to Safari, and the Extension Builder is open, so let's install our extension. And we now have a toolbar item in our extension, and when we open up a few background tabs, You can see that our count updates. We now have three unread tabs in this window.
When we select one, the count goes down to two. And if we open a new window and open a few background tabs in that window, You can see that our count updates per window, and we now have two unread tabs in one window, and three unread tabs in the other window.
Great. So now we have a way to keep track of the number of unread tabs we have in each window. Okay, so what did we look at in that demo? We went through a quick refresher of the Extension Builder and showed how easy it is to use to configure your extensions.
We looked at how to add listeners for the new events that we've added, and how to handle when the events are fired, and we looked at how to use the validate event to update the state of our toolbar items. So those were the new events that we added to Safari Extension. So I'm going to hand it over to Jessie Berlin to talk about the new UI we have. Thanks, Brian.
Hi, my name is Jessie Berlin, and I'm an engineer on the Safari and WebKit team. Just like Brian, I've been really impressed by what you guys have done with extensions over the past year. And in the next 20 minutes or so, I'm going to show you some cool new UI elements that you can use to make your extensions even better.
So going back to Brian's unread tabs extension, it's really cool that we have the number of unread tabs. But it'd be even cooler if I could know which tabs I haven't read yet, and maybe close out all the tabs that I'm already done with. So how could we do this today? Well, we could add extension context menu items for each one of the unread tabs. Context menu items will be shown when the user right-clicks in the page.
But that doesn't seem appropriate for the unread tabs extension, because what does the context of the page really have to do with my unread tabs? So what else could we do? Well, we could inject a script into the web page and draw a menu approximately beneath where we expect the toolbar item to be.
But that's really fragile, because the web page can change the JavaScript and the CSS in ways the extension really isn't expecting, and might make the menus look really bad. So it looks like we really don't have a great way today to show a list of options to the user from within the Safari UI with extensions. Which is why we added extension menus. Menus are a great way to show the user a list of items or options.
Say you want to show the user a list of languages that your extension can translate into, or maybe some style sheets that they can use to change the look of the current page. Menus are a great way to do that. They have a native look and feel, so they look right both on Mac and Windows.
And they can be shown when the user clicks on the toolbar item, clicks and holds on the toolbar item, or just when you call show menu on that toolbar item. So you're probably wondering, okay, what can I put in these extension menus? Let's go over what you can do with an individual extension menu item. So first off, there's the title.
This is the text that will be shown to the user, and you should keep it pretty short and sweet, because you don't really want your menu taking up half the page just to accommodate one really long title. If you want to show the user what's currently on or in use, you can use a check mark.
And if you want to add a little bit of visual splash to your menu, you can use images. These are specified through Safari Extension URLs or HTTP URLs, and they'll be automatically scaled to 16 by 16 pixels, so they can fit in the menu. Sometimes there's an option that's not really appropriate in the current context.
A great example of this is an undo item, when there's nothing for the user to undo. You want them to know it's there for the future, but you don't want them to be able to select it. All you have to do is disable the menu item, and it will remain grayed out and not selectable until you enable it again.
You should use separators to make it easier for your users to find your menu items, if you have a lot of them. And last but not least, you can even use submenus. for advanced options, or again, to help you organize your menu items. Okay, so how do we create these menus? Well, we added a new section to the Extension Builder for creating these menus.
But what if you wanted to show the user a list of the current pages that are embedded in the website they're visiting? You wouldn't really know that information when you go to create your menu in the Builder. So we've also added ways to create menus and menu items at runtime on the Extension object and on the individual menus themselves. You can modify these menus and menu items up until they become visible to the user. So make sure you check the visible attributes available both on the menus and the menu items before you make your modifications.
And whether you create them in the Builder or at runtime, your menus will be available on the menus array in the menus array on the Extension object. And you can get to them, you can find your menu by using the unique identifier you specified when creating it. You're probably wondering, how do I know what's going on with my menu? How is the user interacting with it? We added extension menu events.
Before the menu is shown to the user, you're going to get two things. One, you're going to get the menu event with the menu as its target. And then you're going to get validated events for each one of the menu items. This is a perfect time for you to update your menus and your menu items before they're shown to the user. When the user selects one of these menu items, you'll get a command event. Let's take a look at an example of handling a command event.
So as you can see, I've registered the listener on the application object, but you can register it on the target or any of its ancestors. And I don't have to use capture because the menu, command, and validate events all bubble. When we're handling the command event, all you have to do is check the command to figure out what the user wanted you to do. It's that simple.
and take a look at actually creating and using one of these menus. I'm going to go ahead and modify Brian's unread tabs extension, so that it will show me a list of the unread tabs and also allow me to close out any tabs that I've already read. So I'm first going to bring up the Extension Builder by going to the develop menu and showing the Extension Builder, and then I'm going to add the menu and a toolbar item for that menu to be shown from, and then after that, we'll go ahead and show how to handle the command and menu events in the global page.
In the Builder, we have added a new section for creating menus. I'm going to click on the New Menu button and give it a unique identifier of Unread Tabs Menu. Let's go ahead and create that menu item for closing all our red tabs. I'm going to click the New Menu Item button, give it a title of Close All Red Tabs. and a unique identifier of Close All Red Tabs.
So let's go to the toolbar item and tell it that we want to show that menu when the user clicks on the toolbar item. I'm going to go to the menu section and select the Unread Tabs menu that I've just created. Now, last but not least, We're going to want to have access to the titles of all of the tabs to show them in that menu.
So that means we need to have access to the titles of the web pages, so I'm going to set the access level to All, even the secure pages, because we want to show those too in our menu. So now that we're done configuring the extension in the Builder, let's go ahead and pull up the global page and handle the command and menu events.
[Transcript missing]
So let's talk about the menu event first. We're going to want to add menu items for each of the unread tabs. But we're also going to want to make sure that we clear out any other menu items we had from the previous time we showed the menu, because we only want to do this right before the menu is shown. So let's go ahead and look at the code for that.
As you can see, I'm appending a menu item to the event target, which is the menu. I'm using the index into the unread tabs array as the identifier, and grabbing the title of the tab as the title of the menu item. Then I'm also going to go ahead and try to get the favicon for the site to make it look pretty. Let's go ahead and clear out the old menu items.
You'll notice that I'm clearing out all but the first one because I want to keep around my "Clear all red tabs" menu item. Now, we don't want the user to mistake clear all red tabs for just another one of their unread tabs. That could be pretty bad. So let's go ahead and add a separator to make that distinction clear.
And that's all we need to do to handle that menu event which is sent when the menu is about to be shown. Let's go ahead and handle the command events now that will be sent when each of the menu items are selected. And let's take on the Close All Red Tabs menu item first.
So it's fairly simple. All it's doing is getting all the tabs in the current window, comparing them against the list of unread tabs, and closing out all the ones we've already read. All that's left to do is go ahead and implement handling the menu items, the individual unread tab menu items.
And that's very simple, because their command is going to be the index into that array of unread tabs. So all I have to do is using that command to index into that array and activate that tab. Let's go ahead and see this in action. I'm back at the Extension Builder, and I'm going to click the reload button.
And we'll open up a bunch of background tabs. As you can see, the toolbar item is Toolbar Items Badge went up, and if I click on it, it shows our menu. Let's go see the page about the iPod. It brought me right there. If we want to get rid of everything we've already read, all you have to do is select the "Close all read tabs" option. And as you can see, we're only left with the tabs that we haven't read. So that's Extension menus. I hope you guys go ahead. and use them, they're in the seed. I can't wait to see what you guys do with them.
So what did we just see? We saw how to create a menu in the Extension Builder. We saw how to handle the menu and command events. And we saw how to create and use those extension menu items. So menus are pretty cool, but what if I wanted to show a large chunk of content to the user, maybe a weather map for the local area? Well, how could we do this today? We could use an extension bar.
Extension bars are great for showing a small amount of content that you want to persist across windows and tabs, but they are designed for a small amount of content. They're given 30 pixels, and they take that away from the page. So what else could we do? Well, we could use full-page extension content, which is a file from the Safari Extension Bundle that is loaded into a window or a tab.
But that requires the user to navigate away from the page they're currently visiting, and maybe we don't want to interrupt their current experience to do that. Right now, we don't really have a good way to show Large chunks of custom content to the user without navigating or stealing real estate from the page. And we heard your requests, and we added extension popovers.
Popovers are a great way to show a large chunk of custom content to your user. Say you wanted to do that persistent email experience that Brian was talking about earlier. You can do that login in a popover. Just like extension menus, popovers are shown from toolbar items, and they don't steal real estate from the page.
And they don't require any navigation. As I mentioned before, they are shown from toolbar items, and you can have it shown when the user clicks on the toolbar item, clicks and holds on the toolbar item, or just call show popover on the toolbar item. So you're probably wondering, okay, great, what's in these extension popovers? Well, HTML, JavaScript, and CSS, web technologies.
All this content comes from a file within the Safari Extension Bundle, and it's loaded Popover is created. The content window attribute represents the DOM window for that popover. You can use the content window on the popover and on the global page and on extension bars to communicate among these objects in the application layer.
Say you wanted to send some information to a global page from a popover. All you have to do is call a method on that global pages content window. You can also set a variable on the content window for the bar so that it has new state. How do we create these? Well, just like for menus, we added a new section to the Extension Builder.
But you can also create them at runtime using methods that we added onto the Extension object. And whether you created them in the Builder or created them at runtime, they'll be available on the popovers array on the Extension object. You should use the unique identifier you specified when creating the popover to find it in that array. Let's talk a little bit more about using popovers. When a popover is about to be shown, We send a popover event. This is the perfect time for you to update any UI in a pertinent state before it is shown to the user.
One thing you might want to update is the width and height of your popover to make it fit your content better. They'll start off with a default of 300 by 400 pixels, but you can change that any time, even when it's visible to the user. Popovers hide when focus is lost.
So when the user clicks on a page or clicks somewhere on the window, the popover will automatically go away. But you can also call hide on the popover to make it go away programmatically. So let's go ahead and actually create and use an extension popover. So sometimes it's hard to determine what colors will really look good together out in the wild.
It's not obvious when you put two colors side by side that they'll look good as a background color and a text color. So a little while back, I created an extension that will show me this color information in a bar. And let's go ahead and take a look at that right now. Let's check out a page that has a lot of colors. For example, Flickr. I'm going to view my bar by going into the View menu and showing the Colors bar.
Now, as you can see, it shows me a lot of background colors and some text colors. But wait, there's more. There are more text colors, and there are even border colors. The problem is, It doesn't really fit that well in an extension bar, but I don't really want to open up another page to show the user the colors. They should be able to see it while they're on the website.
So let's put this into a popover where we'll have enough room to show those colors and maybe even the color strings that are being used to generate them. I'm going to show you how easy it is to turn this display code that's being used in a bar into display code that can be used in a popover. First, we need to bring up the Extension Builder.
By going to the Develop menu and selecting Show Extension Builder, I'm going to go to my Color Finder extension. And here we need to configure it so that it uses a popover instead of a bar. Once we're done with the configuration, I'll show you how to handle the popover event that is set when it's just about to be shown to the user.
So what we need to do first is probably get rid of that bar. So we're just going to click the X in the right-hand corner. And go to the New Popover section and press the New Popover button to create a new popover. I'm going to give it a unique identifier of Show Colors Popover.
It's going to use the popover.html file, which we will see in a few minutes. And we're going to need a toolbar item to show this popover from. So I'm going to press the New Toolbar Item button and give it a label "Show Colors." It needs an image to show in the toolbar item, and a unique identifier.
Now, I want to point out here that I'm leaving the command blank. If I had specified a command, the command would be sent when the user clicked on the toolbar item, and the popover wouldn't be shown until the user clicked and held on the toolbar item. This is also true of menus.
So we want to make sure that we don't have a command here, because we want it to be shown when the user just clicks on the toolbar item. So we're done in the Builder. Let's go ahead and look at the code to actually show the popover. So let's look at what we have here.
We have some CSS to style the content that'll go in the popover. And then you'll notice that I'm including this file called show_colors.js. show_colors.js waits for a message from the content script And then unpacks that message, gets all the color information out of it, and generates HTML to show in the popover.
This is actually code that I am sharing with the bar implementation, because processing a message is not specific to popovers. It works just as well for bars and global page as it does for popovers. I'm going to be a little hand-wavy at this point, in the interest of keeping it short, but all of this code for the Color Finders Extension, the Unread Tabs Extension, and some other extensions are available as sample code on the Safari Developer Center. So you should check it out if you want to learn more about how I'm generating that HTML content for the popover, and how I'm doing the message passing between the content script, which is injected into the web page, and application layer.
So go ahead and make sure you check that out. But right now, we're going to want to handle the popover event, which is sent right before the popover is about to be shown. And we're going to want to tell the content script, "Okay, right now I actually do need the color information, so gather it and send it back up to me so I can show those great colors in the popover." Let's go ahead and do that right now.
So I'm just adding the codes to — adding the event listener for the popover, And then once we get the popover event, I'm getting rid of any color information from the last time we showed the popover, because that might have been a different page, or it might have changed in between.
And then I'm going ahead and dispatching a message to the content script telling it, "Go get that color information." So we're almost done, but I want to make sure that our content fits inside the popover. We don't want a lot of extra white space if there aren't that many colors on the page, or we don't want to have a really small popover if there are a lot of colors and force the user to scroll through a lot of colors and text. So I'm going to go ahead and find that popover and adjust its height once we're done generating that HTML content.
So as you can see, it's fairly simple. It just goes through the popovers in the array on the extension, finds the one with the unique identifier that we specified in the builder, and then sets the height to be the height of the document. So let's go ahead and see this in action. I'm going to bring back up the builder.
and reload the extension. The bar went away. And as you can see, we have this new toolbar item for showing the colors. When I click it — oops, I forgot one thing. For the — in the Builder, I need to make sure that I specify my new popover as the popover to be shown for the toolbar item. So let's try that again. I'm going to reload the extension. Click on the toolbar item, and we get this great popover with all of our colors. You can see the color strings, and it's much easier to get the information.
So popovers are also available in the Seed. I'm really excited to see what you guys do with them. So go ahead and check them out today. And let's just quickly recap what we just did. We saw how to create a popover in the Extension Builder. We saw how to handle that popover event, which is sent right before the popover is about to be shown.
And we saw how easy it was to reuse code that is being — doing display in a bar to also display information in a popover. Today we've learned a lot. We've saw how extensions are a great way to add new functionality to Safari's UI. We've talked about the great new events that we've added so that you guys can know what the user is doing with Reader and with Windows and Tabs.
We talked about the exciting new menus API that allows you to show the user a list of options from within the Safari UI. And last but not least, we talked about the popovers API, which we know you guys have been wanting and we hope you have a lot of fun with. If you're looking for more information, you should contact Vicki Murley, our awesome Safari technologies evangelist. And you should check out the gallery. It's been revamped, it looks pretty cool.
And this is where your users are gonna go to find the new and cool extensions. Go ahead and check out what other developers have done and submit your extension to the gallery today. For a more in-depth coverage, of these APIs, you're going to want to check out the Safari extensions reference.
The one that's next to the seed on the Safari Dev Center has information about all the new APIs we talked about today. And once we actually release, you'll see all the information in the normal reference docs, and the guide for creating Safari extensions will be updated to talk about how to create popovers and menus as well.
Speaking of which, you should check out the Safari Developer Center. It has sample code, it has great references for doing development for extensions and other parts of Safari, and that's also where you're going to find a link to the videos from last year in iTunes for those of you who are totally new to extensions and want to have a more in-depth coverage of how to create and use a basic extension. There are other labs that you should check out.