Home >
Little more than a two years ago YAHOO! decided to make its library of cross-browser JavaScript components available to the public with a BSD license as the YUI, the YAHOO! User Interface library. It is now reaching the end of its second major version with dozens of minor versions, each new one bringing a few more components with it.
Since YAHOO! is the major user of YUI, actually, since the millions of users accessing YAHOO! are the major end-users, the YUI is a very effective tool (admittedly, not all YAHOO! uses the YUI yet). YUI was developed to satisfy an existing need in a tough and varied environment. Clients may be anywhere, with different bandwidths, can have different browsers with different settings and several applications might need to coexist in the same page.
The most unusual feature of YUI as a JavaScript library is, strange as it may sound, that it can work even if the end user does not have JavaScript enabled. YUI can be used to enhance existing markup, that is, a page can be produced by the server as a plain HTML page, functional but featureless. If JavaScript is enabled, the YUI can enhance it with all the modern features it provides. For example, the Rich Text Editor component expects an HTML textarea as its container. If JavaScript is not enabled, the user will still be able to edit plain text in the textarea. Menus and TreeViews can take an unordered list of links so that if JavaScript is not enabled, the page will be functional. This feature, though important to those who need to deliver services to the general public, has a cost, pages have to be designer to look good with both JavaScript enabled and without; since the initial markup has to be created dynamically pages cannot be cached on the client side and the server side has to be able to reply to both asynchronous and regular requests.
The YUI library also provides several CSS stylesheets. Some of them are meant to normalize the presentation across all browsers. For example, the default font sizes in different browsers are not exactly alike and these styles makes all sizes compatible. Another stylesheet provides several static layouts based on absolute positioning and floats (the library also has a dynamic layout component). Furthermore, several components have their own stylesheets controlling their visual presentation. YUI allows for a skinning mechanism and though YUI initially has provided only a single skin (the 'sam' skin named after its designer), some users have made their own and at least one has made his public.
The YUI library has been carefully designed to coexist safely with other
third party code running on the same client such as mashups, ad providers,
search boxes and
such. The whole library uses a single name in the global namespace, YAHOO,
thus avoiding collisions with variables declared elsewhere. HTML elements are
the other point of contact in between libraries coexisting on a page.
Here, the YUI library uses the yui- prefix for any identifier attached to
an element, be it for the id attribute, classNames or extra custom
attributes. Other libraries can
be used at the same time as long as they don't use the YAHOO
variable or the yui- prefix. Under this single variable name, several properties contain the several objects that make the
library. All visible UI elements fall under YAHOO.widget: YAHOO.widget.Editor,
YAHOO.widget.TreeView and so on. Under YAHOO.lang we find those
functions that provide functionality that JavaScript should have but is missing,
deficient or unreliable, such as variable type detection. Finally, YAHOO.util
gathers all the rest such as DOM manipulation, event handling, asynchronous
communication and others.
This subdivision of the YAHOO namespace should not be confused with
'components'. In YUI 'components' are basically delivery units. A
single component might contain objects from more than one branch of the named
above. The Menu component, for example, contains several objects
under YAHOO.widget for their visible elements but it also has some under YAHOO.util,
which are not visible but remain in the background keeping track of open menu
panels.
The performance enhancements in the library have been continuous. The YUI team receives feedback from other departments within YAHOO!, some of them dedicated to performance, which then get reflected on the library. An important tool has been the YUI Compressor which is able to reduce the size of the JavaScript and CSS stylesheets to improve delivery time. For the smaller components, where the latency time is greater than the transmission time, several such components were packed into a single file which, once compressed, can be delivered in the shortest possible time. These are called aggregate files. The YUI team has even re-written several of the components to maximize the compression rates, for example, avoiding references to long global names, which cannot be minimized, using local variables instead. And if you are concerned that your servers might not be capable of efficiently delivering those components worldwide, YAHOO! has placed the library in its own distributed servers for public access so your servers only need to provide your application and YAHOO! delivers the YUI library itself.
YUI achieves an unusual balance. Though programmers might find other libraries more elegant or cleaner, YUI satisfies most of those involved in delivering enhanced applications to end users. It is tested in all major browsers, it has a small size/performance ratio, it has been carefully designed to coexist with other code on the client machine, it is flexible in the communication options with the servers so that even existing applications might be enhanced by YUI without requiring major reworking on the server side and it can even allow you to deliver workable pages to browsers with JavaScript disabled.
The YUI library is very well documented. Besides the API reference, produced automatically from the original source code, the user guides and the examples cover most of the features. The YUI blog and YUI Theater provides some more in-depth articles, pointers to related material elsewhere, news and videos.
The next major version will bring a reordering of the library since its own unexpected growth has introduced a few inconsistencies. This will certainly satisfy the programmers who want a cleaner library. It wasn't until some common patterns were detected in several of the components that some base objects were developed and though now all new components inherit from those, the old ones still have their own ways. More exciting will be the possibility of third party participation in code development. So far, the YUI team is the only one working on the library, with external developers able to participate through SourceForge in reporting bugs and suggesting future features and the mailing list. With the reordering of the library and the establishment of clearer guidelines, third parties will be able to effectively develop new components or add to existing ones.
Loading components
There are two ways to load the YUI components, you can do it directly via <script>
and <link> tags, as shown in most examples
or in Eric Miraglia's article or you could use the YUI Loader. The Loader
is often overlooked in the documentation. The 'Getting Started' section of each component usually lists the library
dependencies providing a code block which you can copy and paste right into your
code. Most
people miss to read the brief sentence that gives the name you need to provide
the YUI Loader to load the component and all its dependencies. Admittedly,
using the YUI Loader is slower than including the library files directly since
none of the files will even start to load until after the Loader itself has
loaded and decided what to do. If performance is an issue, then it is
better to load components directly. To help you handle dependencies,
specially when there is more than one component involved, the
configurator
utility lets you build your own includes, otherwise, the YUI Loader is the
easiest choice. The configurator actually uses the YUI Loader to build the dependency lists.
Assuming that in your HTML page you have included the script for the YUI Loader:
<script src="http://yui.yahooapis.com/2.5.1/build/yuiloader/yuiloader-beta-min.js"
type="text/javascript"></script>
Then you just need to put this code in the accompanying JavaScript
(function(){
var loader = new YAHOO.util.YUILoader();
loader.require('editor','datatable');
loader.insert({
// filter: 'raw', // or filter:'debug',
// base: '/yui-2.5.1/build/',
loadOptional: true,
onSuccess: function(){
YAHOO.util.Event.onDOMReady(function () {
// your code here
});
},
onFailure:function(msg) {
YAHOO.log(msg,'error','myPage');
}
});
})();
The above sample carry lots of information, lets analyze it. In the <script>
tag you can see the address for the YAHOO! servers which can be used to load the
YUI library. The servers have copies of all the public releases of the
library since unavoidable differences in between versions might make one version
slightly incompatible with previous ones. By having a folder for each
version, you can stick with the version you know your application works with
instead of rushing to change your application when the YUI version
changes. The filename for the YUI Loader component also tells us that it
is still beta and we are loading the compressed version ('minified', thus the -min
suffix).
The JavaScript code that follows is enclosed in an anonymous function.
Its purpose is to turn all the variables declared inside, such as loader,
local to that function and, thus, not visible in the global scope. Notice
the very last set of empty parenthesis at the bottom of the code box indicating that the function is immediately
executed. Within that anonymous function we declare a variable loader
which we initialize with an instance of the YUI Loader. This is the first
YUI component we are using. As we mentioned, all YUI components
are defined under the YAHOO namespace.
If, just as we did, we define all our own variables as local to
an anonymous function, we are further protected from the risk of namespace
collisions.
We then declare which components we want to load. There is no need to get concerned
with dependencies and such, the loader will take care of that. We are
asking here for the DataTable and the Rich Text Editor components. This
will also load any stylesheets associated with these components and if within
the dependency files it finds any group that belong to an aggregate file, it
will load that one, unless you explicitly tell it not to by setting the allowRollup
option to false.
Finally we tell the loader to insert the requested components into our
page. The insert method takes an object literal as its argument
specifying several options. The main one is the onSuccess property which
will be called when all scripts and stylesheets requested have been loaded and
are ready to use. However, this does not mean that the page itself is ready to
use. Though in many cases the body of the page will be loaded by the time the
loader finishes its work, there might be cases when it is not, for example, when
the page contains information from many database queries which might delay its
completion. So, we make a further check to see if the DOM is ready for us
to use via method onDOMReady which we call passing it a function which it
should call when everything is ready. That is the place for our code, everything
we could need should be ready. At this point we
are three levels deep into functions contained within functions so any
variables we declare inside are local to that function and not visible
elsewhere (variables used but not explicitly declared will go into the global namespace,
a source of much frustration when they collide with others with the same name).
The loader has several options such as filter which lets you specify
which version of the files to load. By default, the compressed versions get
loaded but you can specify 'raw' to load the regular version which still
has all the formatting, comments and original variable names so it can be
stepped through with a debugger and make sense of it, or the 'debug'
version which has extra code to log messages into the YUI Logger, another
component of the library which is also available to developers to log their own
messages in a consistent way in all supported browsers.
The base option allows you to change the default base path for all library
components. By default the components get loaded from the YUI servers, if
you don't want that, you can say so. The loadOptional option lets
you specify whether you want some extra non-vital dependencies that provide a
layer of icing such as animated movements or drag and drop. Finally, the onFailure
function gets called if anything went wrong and it provides a message indicating
the cause. We are using the YUI Logger to show it. The YUI Logger might be
loaded or not, the call to YAHOO.log won't fail if it hasn't. In
this example, we have not loaded it, but it is still good to have those log
messages in your code just in case something does go wrong. Though the
Logger can be loaded by including the name 'logger' in the call to loader.require,
to log any messages produced by the Loader, it needs to be included separately, just as the
Loader itself.
Loading your own Components
We can use the YUI Loader to load our own code and libraries. We do this by
using the addModule method:
loader.addModule({
name: 'myModuleName',
type: 'js',
fullpath: 'js/myModule.js',
requires: ['myLibrary', 'datatable', 'connect']
});
We have to give each module a name which can later be used in require lists,
tell the loader whether it is a JavaScript or CSS file, the path to locate it
and its dependencies which can be any mix of YUI components and our own which
should be declared elsewhere with this same addModule method.
To let the loader know when a module has been loaded, we need to add a line of code at the end of each.
YAHOO.register('myModuleName',entryPoint,{version:'2.5.1',build:'0'});
The first argument should be the same name given to the addModule
method. If a module fails to register, the Loader.insert method
will remain waiting and will never call the onSuccess callback function.
While page code can, for the most part, be contained within the local
scope of a function and thus avoid cluttering the global namespace, libraries
have to be public and expose some of its members. We may device and manage an
schema analogous to the YAHOO namespace or we may fit within by using
the YAHOO.namespace function:
YAHOO.namespace('myOrganization');
This will create a YAHOO.myOrganization object which can be later
populated with your own library objects. This call can be safely repeated
in each of your library modules since it does not clear any previous contents,
if there is any.
Amongst the several objects we will likely include in our libraries are our own customized versions of YUI objects. From SimpleDialog we might derive confirmation or information boxes styled to our site, from Panel we can make wait or 'in progress' boxes or we might tailor the Rich Text Editor by adding or removing tools from its toolbar or adding a completely separate toolbar.
Functions YAHOO.lang.extend and YAHOO.lang.augment are very
helpful in doing that. They are located in the lang branch since, in a
language which in principle allows inheritance, it is quite funny that there
should be no built in method to do it. Both methods could and ideally
should be added as prototypes to the Object object but to avoid clashes
with other code, the YUI library never modifies the base libraries and it tries,
as much as possible, to be tolerant should it find them modified by others.
The YUI library is a solid and ever growing product. It has a very demanding in-house user, which constitutes a huge user base on its own though it is far from the only one. The YUI team is very responsive, all its members are regular contributors to the mailing list, many of them providing helpful articles and examples in their own personal web sites. The product is well documented and, should all else fail, the (uncompressed) code itself is clear and well commented. The community of developers is also quite big with several of its members quite knowledgeable in many of the components so there are few questions that remain unanswered for long.
In later articles, we will try some of its components




Facebook Application Development
YUI was an eye opener for web developers.
It was an example of the level of quality that a (javascript) framework can achieve when an entity the size of Yahoo puts its resources behind it.
In my perception as a web developer, YUI raised the bar and marked the beginning of ajax as an enterprise level framework to deliver web interfaces. Soon after YUI, Ext JS appeared on the map as -the- apex of ajax.
But, YUI still stands as the pattern to follow when good'ol unlimited backwards compatibility is a requirement.
I started using YUI very early on. One of the reasons I choose to use it vs using prototype was that it had so much good documentation.
The most exciting piece of YUI in the 2.x versions have been the focus on web performance.