When i first saw jQuery desktop i was amazed of what jQuery can do. I decided to “fork” the idea to YUI and check if it was possible. It took me 2 days to built it from scratch well not actually, because most of the functionality was taken from the YUI library examples. For example the panels, dialogs and menus are all taken from the examples provided with the full YUI library, but i think i did some work myself.
So here it is:
Applications Bar
First of all, i wanted the flowing application’s bar on the bottom of the desktop (i like Mac screens but i don’t own one. So if you think the desktop sucks at emulating a Mac desktop… Then you are right :) ) . So i used the sticky footer code from http://www.cssstickyfooter.com/ to place the applications bar where i wanted.
Then i needed to add the icons with an effect that would make them feel like flowing (i like calling this liquid). What i did was the same trick as the YUIBox image gallery, only slightly customized. I added a mouseover listener to all images with class name = link, and a mouseout listener too. So the mouseover event to animate the resizing of the images with an easing effect and the mouseout event to restore the images original size. This is the code:
window.onload=function() {
YAHOO.namespace("example.container");
//menu();
YAHOO.example.container.manager = new YAHOO.widget.OverlayManager();
var as = document.getElementsByTagName("img");
for(var i=0; i<as.length; i++) {
var a = as[i];
if(a.className.indexOf("link")>=0){
YAHOO.util.Event.addListener(a.id, "mouseover", setupAnim);
YAHOO.util.Event.addListener(a.id, "mouseout", unsetupAnim);
}
}
}
var setupAnim = function(e){
var move = new YAHOO.util.Anim(e.target.id, {
height: { to: 64 },
width: { to: 64 }
},0.3,YAHOO.util.Easing.easeBoth);
move.animate();
}
var unsetupAnim = function(e){
var unmove = new YAHOO.util.Anim(e.target.id, {
height: { to: 36 },
width: { to: 36 } ,
}, 1,YAHOO.util.Easing.easeOut);
unmove.animate();
}
The code above creates a cool effect. The images seem like flowing (a little buggy though. Tell me if you find it and please provide a solution too!!!) and our applications bar is almost ready.
The next step was to give a depth to the applications bar. What i did was to create a simple image like this:
this image will act as a “table” where our icons will stand on. The icons i used was taken from the crystal project package for KDE. So, i set this image as a background image for the footer of the desktop and it then looked like this:
The Top Menu
The top menu was easy to create. The YUI examples had one ready so, i used this. The JS code needed is:
YAHOO.util.Event.onContentReady("topmenu", function () {
/*
Instantiate a MenuBar: The first argument passed to the constructor
is the id for the Menu element to be created, the second is an
object literal of configuration properties.
*/
var oMenuBar = new YAHOO.widget.MenuBar("topmenu", {
autosubmenudisplay: true,
hidedelay: 750,
lazyload: true });
/*
Define an array of object literals, each containing
the data necessary to create a submenu.
*/
var aSubmenuData = [
{
id: "file",
itemdata: [
{
text: "New",
submenu: {
id: "new",
itemdata: [
{ text: "File", onclick:{ fn: newfile } },
{ text: "Application", url:"#" },
{ text: "Shortcut", url: "#" },
{ text: "Desktop", url: "#" }
]
}
},
{ text: "Open", onclick:{ fn : openfile } },
{ text: "Save", url: "#" },
{ text: "Save as...", url: "#" },
{ text: "Exit", url: "#" }
]
},
{
id: "edit",
itemdata: [
{ text: "Undo", url: "#" },
{ text: "Copy", url: "#" },
{ text: "Paste", url: "#" },
{ text: "Select All", url: "#" }
]
},
{
id: "view",
itemdata: [
{ text: "HTML Source", url: "view-source:"+document.location },
{ text: "Javascript Source", url: "view-source:"+document.location+"k800.js" },
{ text: "CSS Source", url: "view-source:"+document.location+"css/style.css" }
]
},
{
id: "go",
itemdata: [
{ text: "Google", url: "http://www.google.com" },
{ text: "Yahoo!", url: "http://www.yahoo.com" },
{ text: "Jeez Tech", url: "http://jeez.eu" },
{ text: "Reddit", url: "http://reddit.com" }
]
}
];
/*
Subscribe to the "beforerender" event, adding a submenu
to each of the items in the MenuBar instance.
*/
oMenuBar.subscribe("beforeRender", function () {
var nSubmenus = aSubmenuData.length,
i;
if (this.getRoot() == this) {
for (i = 0; i < nSubmenus; i++) {
this.getItem(i).cfg.setProperty("submenu", aSubmenuData[i]);
}
}
});
/*
Call the "render" method with no arguments since the
markup for this MenuBar instance is already exists in
the page.
*/
oMenuBar.render();
});
and the html code is:
<div id="doc"> <div id="hd"> <!-- start: your content here --> <!-- end: your content here --> </div> <div id="bd"> <!-- start: primary column from outer template --> <div id="yui-main"> <div> <!-- start: stack grids here --> <div id="topmenu"> <div> <ul> <li> <a href="#">File</a> </li> <li> <a href="#">Edit</a> </li> <li> <a href="#">View</a> </li> <li> <a href="#">Go</a> </li> </ul> </div> </div> </div> </div> <!-- end: primary column from outer template --> <!-- start: secondary column from outer template --> <div> </div> <!-- end: secondary column from outer template --> </div> <div id="ft"> </div> </div>
Now, the desktop had an applications bar and a top menu. The next thing to do was to add some functionality.
Functionality
What i wanted to do was to allow the icons on the applications bar to be able of opening some windows, a context menu and some top menu functionality like:
- Display a text editor when we click on the New -> File item, and
- display an Open File dialog when we click on the Open File item.
Open windows from application icons
This was easier than i thought. I just added an event listener on the click event for all icons and a function to create a window for each one of them, based on their id and title. I also wanted to handle focus on every window, so i registered each panel in a container manager. Another thing i wanted the windows was to be resizable, draggable and the ability to maximize and minimize them.
The code needed (needs some refactoring too):
var openPanel = function(e){
var pano = new YAHOO.widget.Panel("pano"+e.target.id, { xy:[250*(e.target.id/3),100*(e.target.id/3)], width:"600px", height:"300px", visible:false, draggable:false, close:true} );
pano.setHeader(e.target.title+"<span id='max' class='container-max'></span><span id='min' class='container-min'></span>");
pano.setBody("You clicked on the "+e.target.src+" image with id "+e.target.id+"");
pano.setFooter("End of Panel #"+e.target.id);
pano.render("wrap");
pano.cfg.setProperty("draggable",true);
var resize = new YAHOO.util.Resize("pano"+e.target.id, {
handles: ['br'],
autoRatio: true,
minWidth: 300,
minHeight: 100,
status: false,
proxy: true
});
resize.on("resize", function(args) {
var D = YAHOO.util.Dom;
var clientRegion = D.getClientRegion();
var elRegion = D.getRegion(this.element);
resize.set("maxWidth", clientRegion.right - elRegion.left - YAHOO.widget.Overlay.VIEWPORT_OFFSET);
resize.set("maxHeight", clientRegion.bottom - elRegion.top - YAHOO.widget.Overlay.VIEWPORT_OFFSET);
pano.cfg.setProperty("height",args.panelHeight+"px");
}, pano, true);
YAHOO.example.container.manager.register([pano]);
pano.show();
YAHOO.util.Event.addListener('max', "click", function(e){
pano.cfg.setProperty('width',screen.width+100);
pano.cfg.setProperty('height',YAHOO.util.Dom.getViewportHeight()-30);
},pano,true);
YAHOO.util.Event.addListener('min', "click", function(e){
pano.cfg.setProperty('width',600);
pano.cfg.setProperty('height',300);
},pano,true);
}
Create new file
This one was a little tricky. I had to set the focusAtStart: true property uppon creation of the editor in order to make the editor usable in the dialog. The code used is:
function newfile(){
if(document.getElementById('dialogContainer')){
dlg.destroy();
}
var results = document.getElementById('menuresult');
var newdiv = document.createElement('div');
newdiv.setAttribute('id', 'dialogContainer');
newdiv.innerHTML = "<div class='hd'>Enter Title and Contents:</div><div class='bd'><form id='dialogForm' name='dialogForm' method='post' action='#'><p><label for='title'>Title:</label> <input name='title' id='title' /></p><p><label for='description'>Contents:</label></p><textarea name='editor' id='editor'></textarea><div id='descriptionContainer'></div></form></div>";
results.appendChild(newdiv);
//create the RTE:
var editor = new YAHOO.widget.Editor('editor', {
width: '702px',
height: '200px',
focusAtStart: true
});
//After the Editor renders it, we will hide it
//so the iframe doesn't bleed through
//editor.on('afterRender', editor.hide);
//render the editor explicitly into a container
//within the Dialog's DOM:
editor.render();
//create Dialog:
var dlg = new YAHOO.widget.Dialog("dialogContainer", {
width:"725px",
fixedcenter:false,
modal:false,
close:false,
visible:false
});
//event handlers for our Dialog buttons:
//if the user clicks "save", then we save the HTML
//content of the RTE and submit the dialog:
function handleSave() {
alert("You pressed on Save");
}
//if the user clicks cancel, we call Dialog's
//cancel method:
function handleCancel() {
this.destroy();
}
//set up buttons for the Dialog and wire them
//up to our handlers:
var myButtons = [ { text:"Save",
handler:handleSave },
{ text:"Cancel",
handler:handleCancel,
isDefault:true } ];
dlg.cfg.queueProperty("buttons", myButtons);
var onSuccess = function(o) {
}
var onFailure = function(o) {
}
dlg.callback.success = onSuccess;
dlg.callback.failure = onFailure;
//Now that our Dialog is fully configured, we can
//render it:
dlg.render();
dlg.showEvent.subscribe(editor.show, editor, true);
dlg.hideEvent.subscribe(editor.hide, editor, true);
//instantiate button to show Dialog:
//
dlg.show();
}
Open file dialog
The same logic as the “create new file” method used:
function openfile(){
if(document.getElementById('dialogContainer')){
dlg.destroy();
}
var results = document.getElementById('menuresult');
var newdiv = document.createElement('div');
newdiv.setAttribute('id', 'dialogContainer');
newdiv.innerHTML = "<div class='hd'>Open File...</div><div class='bd'><input type='file'></div>";
results.appendChild(newdiv);
var handleYes = function() {
alert("Opening file...");
this.destroy();
};
var handleNo = function() {
this.destroy();
};
var dlg1 = new YAHOO.widget.Dialog("dialogContainer",
{ width: "300px",
fixedcenter: true,
visible: false,
draggable: true,
icon: YAHOO.widget.SimpleDialog.ICON_HELP,
close: false,
constraintoviewport: true,
buttons: [ { text:"Open File", handler:handleYes, isDefault:true },
{ text:"Cancel", handler:handleNo } ]
} );
// Render the Dialog
dlg1.render(results);
dlg1.show();
}
Context Menu
This was the easiest of all. The code needed is:
var oFieldContextMenuItemData = [
{ text: "Visit Jeez Tech", url: "http://jeez.eu" },
{ text: "About", onclick: { fn: about } }
];
/*
Instantiate a ContextMenu: The first argument passed to the constructor
is the id for the Menu element to be created, the second is an
object literal of configuration properties.
*/
var oFieldContextMenu = new YAHOO.widget.ContextMenu(
"fieldcontextmenu",
{
trigger: "wrap",
itemdata: oFieldContextMenuItemData,
lazyload: true
}
);
Demo and Download
You can view a live demo or download the desktop.
Popularity: 4%
Related posts:
- Creating an Unobtrusive Javascript Image Callery Using YUI The Yahoo User Interface (YUI) is a set of utilities...
- 17 Awesome Rich Text Editors A rich text editor (RTE) is a WYSIWYG editor that...
- Using Bing’s API To Create A Custom Search Engine Microsoft’s search engine Bing, is a getting more popular each...
- Decrypting Bit.ly Links on Twitter and Not Only Although URL shorteners are something we can’t live without, there...
- Google Visualizations From A To Z Google has released an API that you can use to...
About the Author:
Filed under: Tools, Tutorials - Trackback Uri











Excellent job, I’ve also done a very similar work called Mock OS X based on YUI and jQuery. http://97.107.138.40:8080/prime-showcase/ui/macosx.jsf
Wow!!! The mock dock looks exactly as i wanted mine to look!!! I will look into your code later!! Superb!!