Welcome, guest Sign In

Video: Satyen Desai — YUI3: Design Goals and Architecture

Video published 2009-05-13.

Transcript:

Satyen Desai: Afternoon. My name's Satyen Desai, in case we haven't met. I work for the YUI team, and I'm an engineer. And today I'm going to walk you guys through YUI 3: the next gen of YUI product. Mainly focusing on the core design concepts, and what we learned from YUI 2 along the way, which kind of led us to the design decisions which went into YUI 3.

So just real quickly, before we jump in — how many of you guys actually use YUI 2, or are familiar with it? Cool. So, I imagine what's going through most of your minds at this point is: what actually needed fixing? What are we trying to do with YUI 3? And in seriousness, YUI 2 is a stable, mature library. It's been out there for over four years, I think, now. It's a got a strong internal and external community behind it, it's got a ton of bug fixes, patches, feature requests supplied against it. It's fully featured, so it has a robust utility set, a robust widget set. So it does beg the question: What is it that we're trying to fix with YUI 3, in re-thinking this thing? And I'll cover those at a high level on this slide, and then we'll dig in to some of the details on the other slides.

The first set of feedback we've been getting from internal as well as external developers, is the issue of lightness, or K-weight, essentially. So YUI 2 is fairly a la carte in and of itself — you can choose to include yahoo/dom/event, if all you're interested in is the browser normalization layer. You can choose to add anim and DD if you want to add some flourish to your page. So you have that level of granularity. But with YUI 3, what we wanted to do was to get to a finer level of granularity, to a feature level of granularity. We'll be looking at some of the things we did to achieve that on some of the future slides.

So, apart from the way we're breaking up code, the other aspect of lightness was emphasizing code re-use. We didn't want to duplicate code across the library. Just the way a library evolves, the way YUI 2 has evolved over the course of four years, there's bound to be some duplicate code which crops up. And we wanted to take this opportunity to refine that, normalize that, introduce the concept of a common base class, across all classes, the concept of plugins and extensions, which goes to feature re-use, which we'll get to, too.

The other aspect of YUI 2 we've been getting feedback on, is the concept of making it easier to use. And that kind of boils down to two main points: a) is providing a consistent API. And again, nothing against YUI 2, but as a library develops, especially since it's initially the first incarnation of a library, there's a certain set of functionality which exists at the beginning, and a new gets added later. And it leads to a consistent API across the library. Good example of that for YUI 2 is the widget family, essentially. So, we've got a certain set of widgets, which were introduced at the beginning of the library, which are basically plain old Javascript object-based. Certain set of widgets which were introduced towards the middle, which have this notion of configurable properties, and are based on the config object. And a certain set of widgets which are derived from Element, or an attribute provider, which came later. So the API is kind of difficult to get on top of across the entire widget family. Additionally, things like Selector, for example, with YUI 3 Selector is going to be a core part of the library. Any time you need a node reference, you can use a selector string to retrieve it.

So that's in terms of utility functions, in the form of Selector, plus a base widget class, for example, which provides normalizations. The reason the IO/Get/DataSource example is up there is that even in cases where we don't derive things from a common base class, if they're doing the same type of thing — for example, in this case, sending out requests across the wire, a transaction based request — we want to make sure that they have a similar API to work with. So in this case, we're trying to make sure that the events these guys fire are all similar, all meaning the same thing, across all three components.

The other part of easier is just convenience. We've got a lot of feedback for YUI 2 regarding verbosity, lengthiness of the code, which you end up writing when working on top of YUI 2. And there's a whole bunch of functionality built into YUI 3, which aims to address this problem, starting from iteration support to loop around collections. The ability to bind functions to a specific context, and set of arguments. The ability to cue operations; built in support for that. And also, the idea of chainability. So to be able to write more succinct code, by chaining methods together, where it's appropriate — so, where we don't have a logical return value to return from an operation, we try to make that method chainable, so you can write more succinct code. General sugar is basically just little pieces of code which add a tremendous amount of value. For example, at the event layer in YUI 3, you have the ability to register multiple listeners and one call, instead of having multiple calls to subscribe — or unsubscribe, for that matter, too. So, just the idea of making common tasks a lot easier.

And the last real goal was the performance goal. And the main point I want to make here was, aside from the whole idea of re-factoring critical paths to optimize your loops, optimize your DOM touch points etc. The key concept I want to convey here is that moving to a new rev, a new major revision of the library, really gives a chance to take a step back and rethink implementations. And a really good example here is Dav's drag and drop implementation. He took the YUI 3 opportunity to step back and completely change the way drag and drop is implemented, so that instead of listening and calculating region overlaps with each mousemove event he's introduced the concept of shims, and basically relies on mouseover for it to fire that first calculation point. So, major re-factoring points like that. Another example would potentially be modality implementation in the container family, for example, where we're aware that's a major performance pinpoint. And this is our opportunity to clean it up.

So, jumping right in. We'll be covering some core concepts of YUI 3.

The first major shift is the move from the Yahoo! global namespace to the YUI instance. The YUI library has always been a good global citizen, if you will. The entire library has always hung off a global namespace called YAHOO, which avoids it from interfering with other application code you have on the page. YUI 3, we're taking it a step further, and saying that in addition to protecting the global namespace, we also want to be able to protect the version of library you're actually writing code against. And this becomes important in the mash up custom app development, like the app world, or the portal environment. And it comes up a lot at Yahoo!, where you've got different modules of code being delivered by different developers, and you want to make sure that when you're writing code, you're writing it for a specific version of the YUI library, and that's honoured. So again, what that really means is: in the YUI 2 world, we had the global namespace which was a page level namespace, essentially. Anything on it would be shared across the scope of the page.

So what that means is: when you're instantiating a new anim instance, for example, you wouldn't necessarily know which version of anim you'd be instantiating. If you had full control over the page, obviously you would, but where you're mashing up code, someone else could be introducing another version of the library, which would overwrite the anim instance, potentially. And you'd be getting that version of anim to play with. In the YUI 3 world, since we're giving you your own instance of the library to work with, the anim instance you're creating is guaranteed to be the version which you expect it to be. So you can write your application code guaranteed that you're working against a certain version of animation. We'll get into some examples of this later.

So that covers, pretty much, most of the stuff I've talked about. I just want to point out that even though you're working with your own instance of the library, you always have the choice to make it available globally. If you're in full control of the page, and you know there's not ever going to be any external code added to the page, you can set it up as a global reference. But by default, the default programming paradigm will be that you get an instance of the library, and that's what you work against.

This core YUI instance which we're talking about — it's not only protected from other YUI instances on the page, but it's also self-populating. And if you think about it, this kind of goes hand-in-hand with the whole lighter approach we were talking about. It's easy to say that we'll break stuff up into finer modules, but if that's going to make it easier for the developer to figure out what the dependencies are, what gets added to the page, that really doesn't help. So in YUI 3, the core YUI object has Get and Loader metadata built in. It can calculate dependencies for you — that's the default way to develop if you're developing something and you just want to get it up and going really fast. We'll look at an example of this later, but all you really need to do is instantiate your YUI object, tell it which modules you want to use, and it'll take care of dependencies, and it'll do it optimally.

A side effect of that is that you're no longer bound by file order dependency concerns. You can include files in the order you want on the page. When you get your YUI instance, it will make sure that the class is attached to it, or attached in the right dependency order, so that file-order dependency doesn't become a concern any longer.

It's about this time people start to question whether I'm an engineer or a product manager, so that's why that is there. The concrete example. Say you're developing a stock tracker application. You've written your code based on the 3.4 version of YUI — that's the version you're pulling onto the page when someone includes that app, or portlet applet. And you've got code which says: create my YUI instance, use the overlay module, which will handle the dependency change we talked about. And when everything's on the page, invoke the app code in my callback. I'll talk about this in a little more detail, but the key point here is that the overlay you expect to be working with is the 3.4 version of overlay.

Now, say the user goes and adds another app onto that same page. That app might have been developed against 3.0 version of the library. And what that means is, if they're asking for that version of overlay, in the YUI 2 world, the global overlay reference would have been the 3.0 version. So, when this code kicks in, you would have been referring to a 3.0 version of the overlay. In the YUI 3 world, both of these instances are guaranteed to have the version you asked for. So, in this case, you're including 3.4 on the page — if you create an instance right after that include, it's bound to the 3.4 version of the library, and any code inside it will be using the 3.4 version of the library. In this snippet of code, they've included 3.0 on the page. They're creating their instance right after their include, and anything from there on will be the 3.0 version of the library. Right? So that's the whole protected sandbox environment.

The self-populating concept, and the whole point I was making about making it easy to get up and going. The basic boiler plate to start writing YUI 3 code, all you really need on the page is a reference to the seed file, which last time I checked, was about 7 KB, if I'm not mistaken. Include the reference to the seed file, again, which has Get and metadata built in, and include your boiler plate code. So, you're asking for your own YUI instance, you want to use a particular module, and this function is essentially a callback. If you think about it, if this process is going to be going out and asking for script files, dependencies, to include on the page — you need to be notified when all of them are ready on the page, and ready to use. So when that happens, this callback is invoked. Your YUI instance, the instance you're specifically working with, gets passed through to it, and you can start writing your application code. So, apart from the whole protected library sandbox environment, you've also got a natural anonymous function in which you can start writing your app code: don't have to worry about polluting the global namespaces as long as you remember your var [declarations], essentially.

So in terms of self-populating, what that call will actually do is go out and pull all the dependencies which anim needs on the page, without you having to worry about that aspect. And additionally, out of the box, it'll do it optimally. So it'll go to the CDN, it'll combine the set of requests, and include them on the page as one request. And when that actually returns, your callback is going to get invoked , where you YUI instance will have an anim class which it can work against.

On the previous slide, there was a point about self-healing. Just to touch on that a little bit. This was a case where all you had on the page was the seed, and that's it. In cases where there potentially could be files already on the page from previous requests, or which you had loaded upfront, the YUI instance, Get, and Loader metadata will take care of just filling out the missing pieces. So it'll heal your dependency tree on the page, to make sure that it's only pulling the files it needs once.

So that was kind of the whole shift from YAHOO to YUI, and the whole sandbox approach, the core part of the library.

Sorry — before we move on there, one point worth making is: Just the notion of moving from Yahoo! to YUI, in terms of a name, also allows you to mix and match 3X and 2X code seamlessly, essentially. So you could have YUI 3 on the page, also include YUI 2 code, and since the top level namespaces differ, there's nothing you have to worry about in terms of conflicts. So, sorry — moving on to the kitchen sink point.

One of the key things we're trying to do with YUI 3 — again, going back to the lighter approach — is to really avoid packaging the kitchen sink, and forcing you to take it. And what that really means is the idea that in YUI 2 you had, for example, DOM. If there are only certain pieces of functionality within DOM, which you wanted to use, for example, you were interested in viewport screen coordinates or that stuff, all you wanted to do was have class management included. You had no choice but to take the whole DOM package. It wasn't broken down at the feature level. And that's what I mean by the kitchen sink, essentially. At the utility level, it's not that apparent. It may not even be that much of a problem. But when it comes to widgets, or heavier components, you really are forced... For example, for calendar. If you include calendar in YUI 2, you're forced to take the entire feature set which has been built into calendar since the day it started. And that's something we really wanted to try and avoid in the YUI 3 world. So you have the ability to take just the cool pieces of the feature set you want, regardless of what they are. So if you're so inclined, the cool pieces could be the relaxation fountain, if you wanted them to be.

But anyway, translating it into code terms. Let's take the IO utility. In YUI 3, it's lighter to begin with, compared to YUI 2. But IO would be the module you'd include if you wanted the kitchen sink, if you wanted the entire set of functionality which is available for IO. But you also have the opportunity to pull in the specific pieces you want. So, say you're only interested in a core light wrapper to wrap the native XHR functionality across browsers, and you're not really interested in form mining support, or transaction support. You have the ability to pull in just io-base, and that'll work independently of these other sub-modules, to provide you basic XHR wrapper functionality. But you could also say: I want basic XHR functionality, plus the ability to do cross-domain requests, in which case you could ask for io-xdr. Again, based on the self-populating notion, it would figure out the dependencies and pull in probably io-base, I imagine, as a dependency, along with io-xdr, and give you just the functionality you need. So, no kitchen sink. Although you have the opportunity, like I mentioned, to pull in the kitchen sink if you needed to. If you're using all of this, you'd pull in the whole IO package.

In visual terms, that's the same thing we just discussed. But again, the idea that in YUI 2 — IO is the equivalent connection, by the way, if I didn't mention that — you'd be pulling in about 12k of connection code, regardless of how much of it you're actually using. In the YUI 3 world, not only is the full package smaller, and more feature rich I imagine, but you also have the ability to pull in specific subsets of it, to get the lightest possible footprint on your page.

The idea of doing that for utilities is not necessarily trivial, but it is simpler than doing it for things like widgets, and more complex components. In the utility world, generally you've got a static object, and one sub-module, maybe adding a couple of methods. You pull in the other sub-module, it's adding a couple more methods which are largely unrelated to the previous set. So it seems trivial to do that break up, and package things differently and add them to the page. When it comes to components which have more configuration support, that becomes a little more challenging.

And that's why in YUI 3 we're introducing the notion of plugins and extensions. I'll try to explain what that means. Again, the concept is pretty much the same: the ability to mix and match feature sets as you need them. So in the YUI 2 world, for example, we've got an overlay class. As it's defined currently in YUI 2, its entire feature set is hard coded into the class, so even if you wanted to strip it down, it's not going to be trivial to take the YUI implementation and try and figure out which pieces to pull out, and which pieces not to. It's got basic XY positioning built in; advanced positioning, like center and viewport-constraint built in, shimming, stacking, header/body/footer, the rest of it. It's all inbuilt into the class, it's all intermingled, essentially. That's the way it's been developed. So what that means is that any time you're creating an instance of overlay, you have all that functionality regardless of whether you need it or not, on that particular instance. And more importantly, I think, when you extend overlay to create custom classes, you're getting all of that functionality whether you need it or not, just by the fact that it's hard-coded into this overlay class.

With YUI 3, what we're trying to do is loosen up that coupling. So, instead of writing positioning support, or advanced positioning support, or shimming support straight into the overlay class, we're trying to write them as discrete, re-usable components, which at the class level we're calling extensions. So each particular extension will be bringing in its own set of attributes its own set of methods, and its own set of events, which it needs to fulfil the feature set it's responsible for. So, for example, positioning would add X and Y attributes and the methods, for example, will move to actually work with them. Advanced positioning may add center attribute support, and the ability to center in the viewport. Shimming would add Z-index and iframe support. And the fact that overlay doesn't have this code built in, and they're available as discrete packages, means that tooltip now no longer has to extend overlay statically to get that feature set. It can mix in the set of functionality it needs, providing a lighter-weight class, lighter k-weight footprint, potentially, and still offer all the functionality it needs to add.

Additionally, you also have that flexibility at the instance level. So you can say: I've got a core overlay class on the page, but for one particular instance out of the five instances that I do have on my page, I want it to be animated when I show and hide. Or, I want it to be bound to an external URL to retrieve content. Plugins are what allows you to do that at the instance level. So again, extensions laid in mix and match features to build classes; plugins allow you to customize instances on an instance-level basis, to provide custom functionality, so you're not tied in to the entire feature set, or the kitchen sink, ever.

In terms of code, what that kind of looks like. You're creating an overlay class using the base.build function, without getting into too many details there. But you're creating an overlay class which extends widget, our base widget class, which we'll touch on a little later, and you're adding basic positioning support, advanced positioning support, stacking support, and standard module, which is header/body/footer support, to that class. And this way, tooltip now no longer needs to extend overlay — it just extends the base widget class, and adds the feature set it needs.

And at the plugin level, similarly, you've got a core overlay. As we saw in the other slide, it has basic XY support, shimming support, etc. You're creating an instance of it, and you're saying for this particular instance, I want it to have IO capabilities. So I want to add the IO plugin, which goes out to this URL, and populates a certain section of the overlay with the contents. But I only want this for this particular instance. In this case we're saying, again, give me a core overlay basic feature set, but add animation to this particular one. And that would basically change the behavior of overlay, so that when I show and hide, it's an animated show and hide, as opposed to being a simple flip of visibility. And that's a subtle difference which is maybe worth pointing out here, is, in this case, the overlay IO plugin is not really modifying the existing behaviors, the core overlay. It's not changing any of its behavior, it's just adding additional behavior in the form of this IO namespace, which then has IO specific methods and attributes available on it. In this case, the animation plugin is actually changing the default behavior of the show and hide methods, and it does this through the AOP infrastructure, which is a new addition to the YUI 3 stack. But it's actually replacing the default show and hide behaviors of the overlay, to replace them with animated versions. So it's affecting the default behavior of the overlay.

So in terms of slides and architecture diagrams, that's pretty easy to draw out; it's easy to break out features as separate boxes, and draw lines between them, and say this is how we'll re-use them. When it comes down to implementation, you really need something which will allow you to decouple code pieces from one another. So you can write basic positioning code which is entirely decoupled from shimming code, for example. And if there are dependencies, they depend on something more loosely coded than actual method calls. And that's where the beefed up custom event infrastructure kicks in. For YUI 3, the custom event infrastructure has been enhanced quite a bit with the set of features mentioned there — we'll dig into each one of those in a bit of detail. But that's what really allows us to write the plugin and extension model we talked about earlier, with highly decoupled, but standalone pieces of code.

The first real enhancement for event worth touching on is the concept of event facades. In the YUI 2 world, when you're working with events, you needed to know when to go the static event utility to normalize properties or behaviors which weren't normalized in the browser by default. So you needed to know that you had to go to Yahoo.utilevent.getTarget to actually get a target, because that was a property which needed normalization. Or you needed to know to go to Yahoo.utilevent.preventDefault to actually prevent default behavior, because that wasn't something supported normally, across all browsers. In the YUI 3 world, we're introducing the concept of an event façade. So for each of your listeners, you'll actually get an event façade, which you can actually interact with directly. And through its implementation, it'll decide whether stuff needs normalizing or not. And so you can reference the event façade to pull out event-specific info, you can reference the event façade to execute stuff like preventDefault, and stopPropagation, etc, which we'll look at in a bit of detail later. But the point is, you have one place to go, and you'll see a similar concept when we get to node, also.

More importantly, the idea of an event façade also extends over to the pure custom event world. So when you're defining custom events for your code, you have the ability to define them to have event facades, and you can work on them in the same way you're familiar with in the DOM world, essentially. So you have event specific properties hanging off of the façade, you have methods on the façade which control notification flow.

The second big change was the idea of built-in on and after moments. If you've been using YUI 2 for awhile, you've either written code, or have seen code, which looks similar to this. So, say if I wanted to write a show method on a particular component. I'd normally fire something called a beforeShow event, for example, which would let listeners listen in before any state has actually changed. I'd wrap that in an if statement, so that they have the ability to prevent that default state change, which I'm about to write, from happening. This is my set of default state change codes. So that would be enclosed in this if bracket here, to say: If no one has stopped me during the before show moment, do what I need to do as part of my show method, and then let people know that I'm done. So I fire the show event. And on the subscriber side of things, they'd be listening for two separate events. They'd be listening for the beforeShow event, with its own set of arguments, and they'd return something a little arbitrary called false, to prevent the default behavior from going through. And they'd listen to a separate event, the show event, if they want to be notified after that particular moment.

In the YUI 3 world, that pattern becomes a lot, lot simpler. As part of my show method, all I really need to do is fire a show event. I can wrap my default state change logic in a separate method which, when I'm publishing my show event, I tell the system what that method is. So I say: I'm publishing a show event, the default behavior for this show event is wrapped up in this class. And that's all I really need to do, as a publisher. So when I fire the show event, subscribers have the ability to listen before the default behavior's kicked in, something which you're probably familiar with in the DOM world, using the on method. I listen for the show event, and I have the ability to preventDefault by calling something concrete on the event façade. And if I want to listen for after the show behavior has been implemented, or executed, I can listen for the after moment.

An added advantage of moving on and after behavior down to the custom event layer is the fact that this event façade is now shared across both listeners, which wasn't true in the previous case. In the YUI 2 case, the beforeShow event was completely separate for the show event. The event system had no idea that these two things were related. In this case, the show event is the event, and you're either listening before the default behavior, or after it.

Quick visualization of that. So I'm firing a select custom event, for example. I've got two on listeners, and three after listeners. When I fire that event, that's the order in which things will be invoked, and it'll invoke my on listeners first, execute my default state change behavior, and then execute my after listeners. The interesting part comes in with what I'm able to do with the event façade. So now, since I have a combined event stack, I can do stuff I'm familiar with in the DOM world, in my custom event world. So, I have the ability to call stopImmediatePropagation, and prevent the rest of the listeners from being invoked. But default behavior is still invoked; the state change still happens. More interestingly, and more common, I have the ability to call preventDefault, to prevent the default state change from happening. Also, just to highlight the fact that calling preventDefault after the state change has happened has no impact, really. But I can call stopImmediatePropagation, and have it have an impact.

So that was the whole on after notification flow. There's another part to it, which is interesting also: the idea of bubbling, or delegation, coming to the custom event worlds. So it's something you're probably familiar with in the DOM world, where you want to listen for events somewhere higher up in the ancestry, in the document. You set up your listeners at that higher level, and route code based on the events they get. In YUI 3, you now have the ability to do that with Javascript objects. So if you have an object design where you have a parent object and a child object, or you have manager object and a managed object, you have the ability to set up bubbling relationships between those two things, and enforce the same kind of delegation. For example, say we have a menu widget, or object, and it takes menu items as its children. Potentially, in its addItem method, I could register the parent object, the menu, as a bubble target, for each of the children I'm adding to it. And what this allows me to do is listen for any events fired by the child object at the parent level. So, I can write consolidated code at the parent, which says any time a menu item is selected, do this. And I don't have to have that listener set up on each of my children, which in certain applications can amount to many, many, many children. The same reason you'd use delegation in the DOM world, you'd potentially use it in the Javascript object world.

And additionally, this also allows external app developers to jump in and say: when menu item two fires its select event, I want to stop it from bubbling up to the parent, because I don't like what the parent's doing with it, I'll handle it myself. So you have the ability to use stopPropagation in that event flow in the same way you'd be using it in the DOM world.

Again, a simple little visualization of that. So, we've got the parent object — it's got listeners which are registered on it. And you've got the child object — it's got listeners which are registered on it. When the menu item fires its select event, its on listeners get notified first. The event bubbles up to the parent, where its stack is processed, and then continues with the child stack. And the interesting part comes in when you have the ability to call stopPropagation to prevent the default behavior, the parent, from happening. In which case you're processing the child stack, the parent behavior doesn't kick in, and you have the opportunity to overwrite it, if you need to.

The last event-related topic is the idea of detaching listeners. In the YUI 2 world, to be able to detach listeners, you'd have to hold onto the listener method or function which was being registered, potentially also hold onto the context for that particular method, so that you could unsubscribe it at a particular point in time, later. And that wasn't always so easy, because you might have anonymous functions that you don't want published with a name, which are your listeners. Or the listener may be set up in a scope which you have no access to, so you have a way to go to get to myShowHandler to unsubscribe it. In the YUI 3 world, we're making that a lot, lot easier. So when someone subscribes a listener, they'll get a handle back, potentially, and when that handle is returned, they have the ability to call detach on the handle; they no longer need a reference to the function, or the context, to actually detach anymore. Even more powerful is the ability to say: I want to set up these listeners with this specific key I'm setting up for my application. So I want to set up a show listener, and a hide listener, which are grouped together by a key called myapp, for example. And in order to detach one, or either both of those listeners, I can use that myapp namespace key to actually detach one of them, or both of them.

Quick note: I'm not sure if that syntax is actually supported, but in concept, that's what we're going to support. I'm not sure if that's the exact right syntax to detach both listeners, but again, the concept is there. That you can subscribe groups of listeners, or specific listeners, by a string-based key.

So, moving on from event to node. Similar to event facades, with node we're trying to provide a single, convenient location for you to go and do anything HTMLelement related. What node does is support the HTMLelement API, so all the methods you're familiar with in the HTMLelement world will be available on the node façade. It normalizes where it needs to, just like the event façade case. You don't have to worry about what to normalize and what not to normalize — if you've got a node façade, or a node instance you're holding on to, you can call the methods you expect to be calling, and they'll be normalized behind the scenes if they need to be. And additionally, since we have our own object which is representing HTMLelements, we have the ability to enhance it, and add more functionality which might be missing from the HTML element API spec, for example. Additionally, since we have our own object representing HTMLelements, we can extend it in the same way we can extend the overlay, for example, by adding plugins to add specific behavior to a node instance you may have. And also, it allows us to constrain behavior, which we'll look at a little later. It may not be important to everyone, but it's a point worth making.

So let's compare some code. In the YUI 2 world, when working with elements you'd probably see a lot of code which is similar to this kind of pattern. You'd go to YAHOO.util.Dom to get references state HTML elements, you'd go to YAHOO.util.Dom to work with certain aspects of HTML elements — again, you'd have to figure out when you need to go to Dom and when you don't. And you'd go to separate utility YAHOO.util.Event to actually work with the event part of nodes or Dom, essentially.

Quick note here: you could, of course, replace this with YUI 2 Selector infrastructure. But in terms of, again, the progress of the library, a lot of the widgets in YUI 2 were developed before Selector came into the library. So realistically speaking, you're more likely to see code like this, than code which actually uses Selector to make this whole selection criteria a little simpler, just because, again, Selector isn't a core part of the library in YUI 2. In YUI 3, it is.

So in the YUI 3 world, that whole chunk of code becomes a lot, lot simpler. You can use Selector anywhere where you need a node reference, so your selection criteria becomes a lot simpler. Once you get the reference, everything you need to do with the reference is available on the reference itself. You don't need to go to a separate utility to work with it, and figure out which methods to use, and which methods not to use. So you have the ability to do DOM manipulation stuff as well as basic event handling stuff, right on that node facade. And additionally, coming back to the succinct code point, you have the ability to collapse that, if you're so inclined, into a single line, for even more succinct code, based on the chain ability pattern we were talking about. So, addClass will return a reference to the node; on will return the reference to the node, I think. I'm not sure. But anyway, you have the ability to chain methods, where appropriate.

So, a few quick slides on just what we meant by supporting, enhancing, and normalizing the HTMLelement API. When you're working with node reference, as far as methods go, those will largely be transparent. You call them in the same way you'd expect to call them if you were working with an HTMLelement directly. And we'll take care of normalization, where required, for you. And that includes the entire HTMLelement API, so even vague or lesser used methods like scrollItoView — if we're not normalizing them, we'll pass them through to the HTMLelement and API to take care of. As far as attributes or properties go, you'll be going through getter and setter interfaces to actually work with them, which proves to be quite powerful. We'll look at this a little later. But, it allows you to listen for change events, which is something which you could re-use through your applications.

So again, the concept of normalizing — you don't have to worry about which methods need normalization, and which methods don't. You call the method you need for the feature you want to use, and it'll determine whether it needs to normalize for computed style, whether it needs to normalize to get the previous or next sibling, etc.

And the enhancement point, the idea that now that we're providing a node class, we can add methods onto it to fill out common use cases in the HTMLelement API, which may not be present. So, class management, XY positioning support, region based support. And again, coming back to the lighter point — you have the option to pull down lighter versions of the node class. So, say if you don't need XY support, or class management support, you have the opportunity to exclude them, and it won't show up on the node interface on your page.

Just a quick slide on the power of using getters and setters for properties. Now, since we have an implementation which wraps the HTMLelement, you have the ability to listen for property changes, react to them, and prevent default behavior if you need to — which you don't have cross browser, if you're working with the HTML element directly. Just a couple of simple cases. One where you're trying to prevent default behavior, one where you just need to know after that change has happened, so you can react to it.

The extendable point. Again, also stressing the whole easier point, node is based off of the same set of infrastructure which, for example, the overlay infrastructure's based off of. So you have the ability to plug in plugins to the node infrastructure, to provide custom behavior for a specific node instance, if you wanted to. Just another quick example there. So again, stressing the point that you don't have to extend node to get a drag and droppable node, or an IO bound node. You can use the plugin infrastructure to customize specific instances.

The constrainable point for node. Now that we have a node façade in place for all HTMLelements, all YUI 3 library code will be going through this façade to actually interact with the DOM. So it makes it the ideal place to enforce constraints if we wanted to. So, in a constrained environment such as Caja, Ad-Safe, for example, we could constrain node access to a particular parent node, to a particular part of the document, for example. Or, we could control which document you're using with a particular node instance. Having the node façade lets us do that, let's us jump in to control how you access the DOM.

Final slide for nodes, I think. Node is the interface you use when working with a single instance of a node, a single HTMLelement, if you will. We also have a nodeList implementation which lets you perform batch operations. Again, drawing on the whole succinct point, you can write code which gets a collection of items, and you can manipulate those items as a set, as opposed to doing something like iterating over them, and acting on them independently. So again, more succinct code. You could also chain that code if you wanted to, just like the node example we looked at.

So we've looked at the whole sandbox approach, we've looked at the whole code re-use approach with plugins, sub modules, extensions. We've looked at events, we've looked at nodes. Additionally, YUI 3 packages a whole bunch of core language utilities, some of which exist in YUI 2, some of which don't. But some more interesting ones are: you have the ability to use a lot of the more common array extra feature set you have available, and more recent Javascript implementations, to iterate around arrays, find elements within arrays. You have your basic type checking, along with a string based type of utility method, which you can use to switch code blocks based on the type of a variable. Basic bind functionality, like I mentioned, to bind functions to event context and arguments. And the other one worth calling out is the AOP infrastructure, so that's what allowed the plugin implementations themselves will use to insert code before or after a given method on the host object they're plugging into. So anyway, just the basic idea of a core set of language conveniences, which are being packaged with YUI 3.

Final few slides I want to spend on the component, the shared component infrastructure we're building into YUI 3. First one is the attribute system. Pretty much all instance based classes in YUI 3 are likely to have attribute support on them. So you have the ability to configure classes with readOnly, writeOnce after use, when you're developing your own set of classes to code with, you can define them with validates, getters and setters, which can massage the value going in and out of the attribute. More importantly, you can have on and after change events, so all of your classes stay, if it's contained in attributes, you have the ability to provide the user the ability to decide to listen for changes at the lowest level. So when an attribute changes its state, they can respond to it, as opposed to jumping in on certain methods. Just a quick note on the fact that we'll also support more complex attribute setting and getting. So, you could have an attribute called strings, which if it's for example a hash of value keys, you could extract keys, or set keys, on it, without having to pull out the whole object, and re-set it.

Base is kind of our lowest-level class, which most instance-based objects will derive from in YUI 3. It combines the attribute support we looked at on the last slide, along with the whole custom event stack support, and establishes a common pattern for the initialization and destruction of objects. Mostly, any object you work with inside YUI will have attributes, will have custom events, will manage initialization and destruction in the same way, period. And additionally, it also provides the base-level support for plugins and extensions, which we looked at earlier. Again, boiling down to the whole "easier" point — everything will basically follow a similar pattern, so you won't be learning something new each time you deal with a new object in YUI 3.

And then finally, the widget subclass. This extends from base. And in addition to the initialization and destruction phases, adds the idea of a rendered view to that lifecycle. So all our widgets will derive from Y.Widget. Again, they'll have attribute and event support based on base. That'll introduce properties or attributes based on common to the widget infrastructure, the common base set of methods to work with, plus the render moment. So hopefully that'll make working with widgets in the YUI 3 space a lot, lot easier.

I think that's about it.

[end]

Copyright © 2010 Yahoo! Inc. All rights reserved. Copyright | Privacy Policy

Help us continue to improve the Yahoo! Developer Network: Send Your Suggestions