Application • 34:37
This session is for webpage developers who want the latest information about developing highly interactive data-intensive web applications using XmlHttpRequest objects, LiveConnect, and forms with rich text content. Safari's support of these technologies provides web developers true separation of data and user interface.
Speakers: Maciej Stachowiak, Kevin Decker
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
[Transcript missing]
and these talks are going to cover both Safari and how to make use of it using HTML and making documents for Safari and WebKit, the engine inside Safari. All right, advanced website development techniques. What exactly are we talking about here? We're talking about techniques for web applications, for more advanced sites that aren't just a collection of web pages and web documents, that really go beyond that to give the user a richer experience. They're particularly useful for data-intensive and highly interactive sites.
All of these techniques that I'm going to discuss today work in Safari and other webkit-based applications. And many are also supported in other browsers, and I'll try to mention throughout the talk which are supported in which browsers. and finally, we're going to have really in-depth coverage here today. We're going to go through a lot of code samples and hopefully by the time you leave this talk, you should know how to use all of these techniques in your own web applications.
What are we going to cover specifically? First, LiveConnect, a technique that you can use to communicate between JavaScript on the page and Java applets. We're going to talk about drag and drop, how to do drag and drop in your web pages two different ways. We're going to talk about HTML editing and how to use that inside your own web pages for pieces of the document to make them editable.
We're going to talk about XmlHttpRequest, which is a technique you can use for backend server communication. And finally, we'll talk a little about putting it all together and how to combine these techniques to make a good web application. and don't forget, this stuff is also really useful for dashboard widgets. So if you want to win that PowerBook or that iPod, pay attention. The first topic we're going to cover is LiveConnect.
Now, LiveConnect is kind of a catch-all term. People use it to refer to many different things. But in Safari, when we say LiveConnect, we mean Java-to-JavaScript communication. Some of you may be interested in plugin scriptability. If so, make sure to catch the Plugin Development for WebKit and Safari session later during this conference.
What's LiveConnect good for exactly, you may wonder? Well, one thing it's good for is you can connect to existing Java applets. If you already have a Java applet around that does something useful and you'd really like to integrate that functionality into your webpage, then LiveConnect can be a good way to go instead of trying to totally reimplement it.
It's also good for going beyond what you can really practically do in JavaScript and HTML. Web technologies are really great, but JavaScript is a fairly slow interpreted language and there's certain things that just won't cut it for it. For example, 3D graphics. That's a little beyond what you can do with JavaScript, but with Java you can do it. and Kevin DeCroix have been working on the development of the latest web applications. This session is for web developers who want the latest information about developing highly interactive data-intensive web applications using XmlHttpRequest objects, LiveConnect, and forms with rich text content.
Here's a very simple diagram of how LiveConnect works. JavaScript in your page can call the Java applet, and the Java applet can call JavaScript in your page. That's it. It's all there is to it. It's very straightforward. So let's look at a simple code example. To talk to a JavaScript applet, you just get the object for it out of the applets array and start making method calls on it, like this. You may notice I've put the may script attribute on the applet tag here to make it scriptable, and then later from JavaScript, just start calling methods. So let's see a little demo. I'm going to have Kevin Decker come up here to the stage to help me out.
Hi, Maciej. Hey, Kevin. Hi. OK, so what we have here is we have this applet, which is right here. Wait for them to put it on screen. All right. There we go. And I'm going to go ahead and start the applet and show you what it does.
[Transcript missing]
It lets you make your own custom 3D models and specify them in JavaScript, and then Java does the animation. So I can imagine lots of cool things you could do with this. You could have controls in the webpage that let you set up what exactly the model is and then use Java to animate it. All right. That's all there is to it. LiveConnect. Back to slides.
and if you're interested in learning more about LiveConnect, there's a Nutscape LiveConnect overview available at this extremely long URL. I'll go over the documentation URLs again at the end of the talk. The next topic we're going to discuss is drag and drop. All right. Drag and drop support.
In the latest Safari in the Tiger WWDC seed, we have much better drag and drop support. And when you use drag-and-drop in your web application, you can get sort of more of a desktop native app feel in your web application. We provide a more convenient API for drag-and-drop. And we'll even let you drag between windows, including between different applications.
We're going to talk about two different techniques for drag and drop. The first technique is mouse event-based dragging. This just uses the classic JavaScript mouse events, mouse down, mouse up, mouse move, and so on, to simulate a drag. and you can use this to drag or resize elements inside a page. Again, as I said, it uses the standard mouse handlers. And it's really only good for in-page drag. You can't use this to drag between different frames or to drag to other apps.
We're also going to talk about advanced drag-and-drop events. Now, these events give you a lot more detailed control over the drag and let you do much fancier things. They let you provide a custom drag image if you want, custom drag types, like you can specify whether you're dragging text or URL and so forth. And they let you drag between frames, between windows, between applications. So first let's talk about drag and drop using mouse events. The first thing you have to do to do this is add a mouse down handler to the appropriate element. It's very simple, just like this.
One other thing I've highlighted here besides just the mouse handler is that the element is absolute positioned. It's important to use some kind of positioning on the element so that when you actually change the position, it'll be reflected because if the element is in the normal HTML flow, then the position attributes will have no effect. So the mouse down handler first saves the initial position of the mouse cursor. It wants to know where the mouse cursor is relative to the element, so when you finally do the drop, you can correctly compute the new position. And this is just some simple math here.
Next, it temporarily installs an OnSelect handler. This is just to prevent accidental text selection from happening while you're doing the drag, since this is just keying off the normal mouse event and needs to make sure to prevent the default action. Now, OnSelect Start is supported in Internet Explorer, but in Mozilla, this event is not defined.
Having a handler for it will make no difference, but the way to actually prevent selection is to return false from the mousedown event handler. And here's the example. Very simple. We've got the function defined here, and we add an event listener using the standard DOM call highlighted in orange there.
All right. There's more. Next, you install mouse move and mouse up handlers. And these just compute the new position and place the element right there. So here it goes. Here I'm showing you the move handler, and the up handler is doing pretty much the same thing. Again, it's got that initial saved position. Now, I'm using a trick here called nested functions in JavaScript. If you define one function inside another and then attach it as a handler, it actually has access to the parameters of the nested function.
So this way we have access to this initial event and also to the initial offset variables that I defined a couple of slides ago. And you'll be able to see more of this in the code samples once they are downloadable. And finally, the mouse up handler removes all the temporary event handlers that you installed.
and I will be talking about the XmlHttpRequest. This is a technique that's used to totally override mouse move and mouse up handling for the whole document temporarily during the drag. Now let's look at a diagram of this. I'm going to show you all the different events that take place during the drag and process and how they relate. First we have the mouse down event. And this happens on the drag source. It's just a normal event. And the main role for this is to add the handlers for the other events.
Now we have all these other events that are installed as capturing events on the body. We have the mouse move handler, which sets the new position, the mouse up handler, which removes all these temporary handlers, and the Select Start Handler, which prevents accidental text selection during the drag. So that's it for the first dragging technique. Let's go on to number two.
Drag and drop using drag events. So drag and drop using drag events provides a very large number of events you can use, but you don't really need to hook up to most of them. But first of all, let's start by going over the exhaustive list. At the drag start site where the drag is going to originate, you have on drag start, on drag, and on drag end. The way these fire is that on drag start fires when you first begin dragging the element. On drag fires continuously while you're continuing to drag it around, and on drag end fires when the drag completes, either by dropping the item or by the user canceling the drag.
On the drag target site, you have even more events. You have on drag enter, which fires whenever the drag enters the element, which might be a possible drag target. You have on drag over, which fires continuously while you're still over the element, and you have on drag leave when you leave the element, without dropping, and finally, on drop if you actually do the drop. So let's look at how you make use of these.
Oh, before that, I have to talk about the data transfer object. Attached to drag events is a data transfer object. This lets you set the data to actually be dragged. You don't have to drag just whatever the element happens to be. You can set any custom data. It lets you customize the appearance of the drag and also other parameters about it, like what operation is it doing? Is it a copy, a move? This will affect the cursor you see while you're doing the drag. And finally, on the receiving end, you can actually get the data from the data transfer object once the drag takes place.
So now let's look at the actual code samples. The first thing you do is set event drag handlers at the drag source, like this. I've set all three here, but again, onDragStart is probably the only one that's really important, where you need to fill in the data and set up the drag appearance, and onDrag and onDragEnd, as I've shown here, you might use to give some kind of feedback at the source while the drag is still going on.
Now, you have to fill in the data transfer object at the drag source. So here's a couple of things we're doing. We're setting a custom drag image, not just using the default. We're setting the type of data and the actual data contents. Here I've used a mime type, text plane. In Safari, these drag events support arbitrary mime types.
In Internet Explorer, the only types allowed are text and URI list, and Safari also supports those for compatibility. And finally here, I've set the drag operations allowed, which is a copy. So you'd see the little plus icon. Next, you have to set the appropriate event handlers at the drop target. and Paul Schmitz are the main developers of the XmlHttpRequest project. They are the ones who are going to be working on the development of the XmlHttpRequest project.
And finally, you have to use the data transfer object at the drop site to get the data out. Here it is. You can do whatever you want with it once it's dropped. Okay, time for another diagram. This one's going to be a little fancier. We're going to look at first the event handlers that you set on the drag source.
OnDragStart sets up the data transfer object. OnDrag can optionally show some feedback while you're dragging. And OnDragEnd is going to end the feedback, if any, that you were showing, those last two being optional. Then there's all the event handlers that you might have at the drag target. You have DragEnter, which you get when you first enter, and you might use that to show some kind of feedback that this is a valid drop target or not. DragOver, which fires continuously while you're over the element. Drop, which fires only if you actually drop inside the target. Or alternately, you get DragLeave, if the user leaves the element without actually performing the drop.
So that's it. Now let's look at a little demo here. What we have is a shared annotation server that lets you mark up a copy of a webpage with little notes, and this is going to use both drag and drop techniques, and again, Kevin Decker's going to help me out with demoing this. So this is really cool. We've basically built in stickies to this common website here, so I can just drag this right here, and I'll drag another one.
So that's showing the second drag and drop technique, cross frame. The top section there is actually a different frame. And here we're demonstrating the in-page drag. That's just a normal DOM element. We've hooked up to the mouse events on it. You can also resize them using that resize corner.
and you may notice these things are translucent. That's using some of the new opacity features in Safari. And if you're interested in more stuff like that and how to make things look really cool, make sure to catch Dave Hyatt's talk on making visually compelling websites. Okay, that's it for now. Back to slides.
All right. Now, again, there's documentation on this. There's an overview of these custom drag events. And we'll go back to that at the end. The next topic I'm going to talk about is HTML editing. Now, I'm going to talk about HTML editing mainly as it applies to editing within a page, a particular section inside a page. Later on during this conference, there's going to be a talk that's currently vaguely called Advanced WebKit Features, which is going to cover how to use editing from your own custom app if you want to use it the way mail is going to, for instance.
So you can use this to support rich text editing in web pages. Now one of the most obvious ways to use this would be for a comment box, for example, on a bulletin board site or a web blog. Many of them are limited to plain text right now, but with this feature you could actually let the user do rich text editing and submit arbitrary HTML.
[Transcript missing]
So the most basic thing here is how to make an area editable. And what you start out with is you set the contenteditable property. This is a tri-state property. It can be set to true, false, or inherit, depending on whether you want the object to be editable.
You can set it just like this as an HTML attribute, or you can also set it on the object through JavaScript by saying whatever DOM element dot contenteditable equals true. So this is the way to make an area editable. You may notice I've also put an ID attribute on it so I can later find this div and perform other operations on it.
Now, one thing you want to do is if you have a fixed size area that you want to edit, you want it to be scrollable. By default, when you have an HTML element and its contents are too big to fit inside it, they'll just spill right outside that area and go all over the rest of the page. That's not what you want. But if you set the overflow auto CSS property, then automatically, once there's too much stuff to fit in the box, you'll get scroll bars.
Now, in addition, that's all you need to do to get a basic editable area. You make it editable, you make it overflow auto, give it a particular size, and you have pretty much the rich text equivalent of a text field. But you want to do more than that. You want to give the user ways to make things bold and italic. You can create buttons like this that use exec command to make text bold or italic.
Exec command is actually part of a family of functions that have a whole bunch of commands available to them. You can look this up on the net. This is also implemented in Internet Explorer and Mozilla, so you can find a lot of docs on this sort of de facto standard way of doing it. And you can use it to set in dense styles, to start new paragraphs, to add line breaks. But for now, these two examples.
Now, there's other ways to use editing commands besides just executing them. You can use these very same command choices to tell whether a command is enabled, which means, can I apply this command right now? Is it available as a current choice for the selection I have? And for bold, for example, that would depend on having either an editable piece of text selected or having a blinking carrot in the middle of some editable text.
You can also check whether the-- boy, it's hard to read that monitor. You can check whether the command is currently applied to a particular region or indeterminate, meaning it's mixed. You can check whether it's supported at all, and you can check the value, which means what's the current state.
Now, once you've done all this editing, you have to actually get the content out. You can use just the innerHtml property, which would be familiar to many of you for that. You just get the element using normal DOM techniques and use the innerHtml property to extract it. Now, here I've shown an example of a function you might have if you're doing a form submission. You might extract the HTML contents of the element you're submitting, place them in a hidden text field, and then just let that submit as part of the form.
And now we're going to demo editing in the very same shared annotation demo. Once again, Kevin Decker to help me out. Okay. So here we have our nice little stickies. So I'm just going to type in here, "Quick brown fox jumped over the lazy dog." And to illustrate what Maciej was talking about with bold, you notice here we have bold. We also have a button up here we added for italicize. So I'll just take this and go like, "Quick brown fox." Let me select the word "the." And we'll make that bold. And we'll take this part and we'll italicize it.
And there we go. And actually, it's really cool because not only can you just type right there, but it's WYSIWYG. It's what you see is what you get. So if I want to do something like this, you know, copy this part, I'll copy there and put it in this note. And then there you go. So anything pretty much on the page, images, all that stuff, right there. So there you go. Thank you.
Next topic. Our final topic is going to be XmlHttpRequest. Now, this is sort of the most abstract of the things we're going to talk about, sort of the least visual, so it may require a little explaining to explain what this is and what really it's good for. XmlHttpRequest is a way to talk back to the web server without actually having to load a page or image or anything. You just open a direct connection, send a request, and get the reply. You can use it to silently make an HTTP connection without disturbing the user with a page or frame load.
It also offers optional XmlSerialization if you'd like to send XmlData to the server, and XmlParsing if the server again replies with Xml that you'd like to process. It's sort of good for behind-the-scenes communication when you want to have some operation in the webpage and respond to it in some way on the server but not sort of put it in the user's face.
and it can also be good for hooking up a web application to an existing XML feed. Let's look at some diagrams of how this works. Before XmlHttpRequest, the way you do things is, you start with a user action. This makes an HTTP request to the server. The server saves the changes, whatever was reported by the action, it generates a new page, it sends an HTTP reply, and then finally, the client shows the results on a whole new page.
An example of a site that works like this that you may know about is Amazon, your shopping cart. Whenever you remove an item from the shopping cart, you have to select it, and then you have to do a save and wait for the server to process that and actually show you the new page.
But with XmlHttpRequest, you can actually do things in a better way. You start with the user action. Right away, you can use DOM commands to reflect that in the UI. And then in the background, you use XmlHttpRequest to make a request to the server. Server saves the changes, and it makes a reply. And the client can choose whether or not to make use of that.
One example of a website that's already using this technique is Orkut, a social networking site that some of you may have heard of. When you go to the section where you rate your friends, you can click from one to three stars or whatever to rate people. And you may have noticed when you do that, the page doesn't load a new page. It just automatically saves, but you're not disturbed at all. And that's a great way to set up your website. People don't have to wait for the page load. You can just automatically save it. their data.
Now, let's look into specifically how you'd make use of XmlHttpRequest. The first step is to create an XmlHttpRequest object and then start the load. Now, the way to create an XmlHttpRequest object is a little tricky. There's two different techniques depending on whether you're using Safari or Mozilla or other standards-based browsers or if you're using Internet Explorer.
In Windows IE, XmlHttpRequest is actually an ActiveX control, so you have to use this wacky ActiveX gobbledygook to create it. In other browsers, you can just directly create the object. So this try-catch block just encapsulates all of that. And then you open it. You tell it what HTTP method to use to do the load and what document you want to load.
So once you've kicked off this load, you probably want to get the data when it's actually loaded. And here's how it goes. You hook up a function to the onReadyStateChange property of the request before actually sending it. And that works just like an event handler. Whenever the state changes of the request, whenever more data comes in or the load kicks off or whatever, you get an update. And state four happens to be I'm all done loading. So this function just waits until you get into state four, and then it can just use the request. You can also use the response text property on the request to get the data back out.
All right. Now, you may want to actually parse Xml response data. Instead of just sending simple text messages or looking at raw Xml, you may want to parse it in some interesting way. So,
[Transcript missing]
So that's an example of how you might use XmlHttpRequest to load something in the background. But what if you want to save? Well, it's very similar.
You set up the request. In this case, instead of a get, I've used the post method, just like an HTTP form post, to post to a script, a CGI script running on the server. And to send, instead of just passing null, you can actually pass it some body data to send as the contents of the post.
But other than that, it's set up pretty much the same way as a load. Again, if you want to use XML, then you can set up a document and attach it to the request and send it. Again, instead of sending text as the body, here we're sending a document. We're just using normal DOM calls to create that and build it up.
and now, let's look at a demo. This is our little sticky app. As you can see, like we said, we can resize all this and you can edit it. But wait, there's more, because what Maciej was alluding to was using this XmlHttpRequest. All this is really saving in the background.
So, um... So even if your browser should crash, which Safari never really does. Never, never happens. So we're going to simulate the crash with a force quit. Yeah, just to prove there's no smoke and mirrors going on, we'll go ahead and crash this. Or I mean, force quit.
You may want to use the doc menu to force quit. Yeah, OK, here we go. Oh, there you go. You have to force quit, force quit. OK. So, OK. Safari actually crashed there. Safari's gone. And let's bring it back. So here we go. And there we go. All that stuff is still there.
Saved all along, and now it's loaded when you load the page again. Actually, it's a little bit smaller, but that's because when I had this browser window open before, I had it full-sized so you guys can see it. So that's actually not really a bug. It's a feature. There you go. It's all saved. It's really, really cool stuff. Okay. Hey, Kevin, stay up here.
Since I've gone through all my stuff and we have a bunch of time left, let's actually take a look at the code of the demo. Sure. So why don't you just view source on this page. Actually, you're gonna probably want to see the... Yeah, you're gonna want to show the top frame source. The header frame. So let's do that. And let's make this bigger so you guys can see it. So let's look at what we've actually done. shows some examples of applying these techniques in practice.
Here's the finished drag move that Maciej spoke about. So here's the drag and drop that I talked about first with the simple move-based drag and drop technique. You can see all that same stuff I talked about before. Just the normal mouse events hooked up, And then we've used the same thing for resize, which I briefly alluded to in the talk and which we showed. And really, you could use this drag for any kind of way of manipulating the elements on your page. You can have a draggable handle and have something else completely different move. Okay, find where XmlHttpRequest is in the page. We'll look at the load and save.
Okay. There we go. And that's where we're doing the save, just like I talked about, post to a script. Up there, it's actually creating an Xml document. Let's go up here. Okay. That's enough demo. Isn't this cool? I mean, this is cool stuff. Let's go on to the summary. Let's go to the summary.
All right, and again, XmlHttpRequest. Apple has some docs online. You can find them here. All right, summary. So we looked at all these different web features that you can use and how you can use them in your web application. And you may have seen a hint of how you can put these together to get something that is a lot fancier than a typical webpage and does a lot more. We combined drag-and-drop, editing, and XmlHttpRequest to get an effect that's really a lot more like a desktop app than like what you expect from a webpage.
and you know, you can also use this stuff for dashboard widgets. So you may be wondering when do you get all of these features? Well, they're all going to be available in the Safari 2.0 in your Tiger WWDC seed. They'll be available in the Safari 1.3 developer beta on Panther that's going to be released soon. That'll be up on the website for download soon. And XmlHttpRequest and LiveConnect are actually already in Safari 1.2.
So, in closing, let me talk a little about the progress of Safari so far. Let's look at a graph of awesomeness versus time. Now Safari 1.0 is already pretty darn awesome. 1.1, 45% more awesome. 1.2 was 69% more awesome than that. And 1.3 and 2.0, who knows how awesome they will be once they ship.
But one thing I want to mention is the version of Safari on your TigerSeed and the developer beta that will be coming out soon are not the final versions yet. Some of these new features that we've talked about may have holes in them, they may be buggy, they may not be perfect, and we'd really appreciate it if you try them out, give them a spin, and report all your bugs. And, oh yeah, legal made me add this disclaimer. All right, so here's all the reference materials we talked about during the talk. If you want to quickly note these down or look at them later on the DVD, it's all the information available.