Weblog update

Hey all I wanted to give you an update:

Three of our active contributors are moving on: Aaron, Eddie, and Val. They plan to stay active in the Rails community, as well as new areas like Facebook. You can follow their work at blog.hungrymachine.com. It has been a great pleasure to work with them and we wish them the best.

Weblog update

Hey all I wanted to give you an update:

Three of our active contributors are moving on: Aaron, Eddie, and Val. They plan to stay active in the Rails community, as well as new areas like Facebook. You can follow their work at blog.hungrymachine.com. It has been a great pleasure to work with them and we wish them the best.

Javascript: Event.onElementReady

We deal with a lot of Javascript at RHG. Rather then create functional one-offs that become hard to maintain and very duplicative, we prefer to have collections of behavior that can be assigned to parts of the document. Our CSS designers especially like this because it makes our markup clean and easy to read. It also means we can have tests that exercise a series of interactions.

However, there is a problem we run into when loading the page over a slow connection: the Javascript is not run until window.onload, meaning our users suffer as they can see part of the page rendered but not use it until it’s fully loaded. For those who don’t know, window.onload will not execute until all images, CSS, and Javascript files have loaded. Our first solution to this problem was to use onDOMReady. This has worked fairly well and kept our site running reasonably quickly. We’ve run into problems with onDOMReady in IE6 however, and as a result disabled it in favor of having our pages render all the time. In the IE family of browsers if a script tries to access a part of the DOM before it has been completely processed the browser will raise an exception “operation aborted”. After this alert message pops up, the web page becomes unusable and the browser could even crash.

After some careful thinking we decided we would attach our behavior objects in smaller chunks of the DOM. Rather then wait until the window.onload or onDomReady events fire we can use a few inline script tags that call a function that figures out how to attach itself to its most immediate parentNode.

For example, we do this:


<div class="parent">
<div class="bvr-blah">
</div>
<script type="text/javascript">
RHG.Behavior.attach();
</script>
</div>

There could be multiple behaviors in the above block of markup that are all contained within the hypothetical div.parent element.

Now, to allow this to work the div.parent must be ready. Otherwise, IE will cancel the whole page rendering with the “Operation Aborted” alert.

Event.onElementReady checks for features of the DOM element to determine whether or not the element is really ready to be manipulatd. Thankfully, IE doesn’t mind if you read from an element before it’s ready only if you try and modify it. This method will poll the DOM element until either the nextSibling or the textContent is non null.


Object.extend(Event,{
// check whether or not the DOM element is ready
onElementReady: function(element,callback)
{
if( element && (element.nextSibling || element.textContent) ){
callback();
}
else{
setTimeout( this.onElementReady.bind(this,element,callback), 1 );
}
}
});

Now we can attach our behaviors as the page is rendering and avoid “Operation Aborted” alerts from IE.

Javascript: Event.onElementReady

We deal with a lot of Javascript at RHG. Rather then create functional one-offs that become hard to maintain and very duplicative, we prefer to have collections of behavior that can be assigned to parts of the document. Our CSS designers especially like this because it makes our markup clean and easy to read. It also means we can have tests that exercise a series of interactions.

However, there is a problem we run into when loading the page over a slow connection: the Javascript is not run until window.onload, meaning our users suffer as they can see part of the page rendered but not use it until it’s fully loaded. For those who don’t know, window.onload will not execute until all images, CSS, and Javascript files have loaded. Our first solution to this problem was to use onDOMReady. This has worked fairly well and kept our site

Continue reading “Javascript: Event.onElementReady”

CSS: CSS Browser Selector

Each browser has its quirks. Having a clear way of organizing the work arounds
for those quirks is a challenge. Using CSS selectors is not a new idea, but I thought it might be helpful to others to give an example of the technique and how we’ve been able to successfully deploy it for revolutionhealth.com.

First, for IE (the browser that usually requires a hack), we can rely on conditional comments. This is good because it means we don’t need to depend on Javascript. For other browsers we’ll have to rely on a document.write solution. For Safari, Opera, and Firefox, we rely on the script from http://rafael.adm.br/css_browser_selector/ and for IE, conditional comments.

Here’s what we include at the top of our document. (The browser_detect_start partial.)


<!--[if lt IE 7.]>
<div class='ie ie6'>
<![endif]-->
<!--[if IE 7]>
<div class='ie ie7'>
<![endif]-->
<script type="text/javascript">//<![CDATA[
var d = browserCSSDetection();
if( d.browser != "ie" ){ document.write( "<div class='" + d.browser + " " + d.os + "'>" ); }
//]]></script>

And here’s what we do for the end of the document. (The browser_detect_end partial.)


<!--[if IE ]>
</div>
<![endif]-->
<script type="text/javascript">//<![CDATA[
var d = browserCSSDetection();
if( d.browser != "ie" ){ document.write( "</div>" ); }
//]]></script>

The browser detection in Javascript. This could be enhanced further, but for us this allowed us to get the site working relatively easy in Konqueror. As well it enabled us to fix our menu’s so that they float over flash in Linux using this techinque.


function browserCSSDetection()
{
// see: http://rafael.adm.br/css_browser_selector/
var ua = navigator.userAgent.toLowerCase();
var is = function(t){ return ua.indexOf(t) != -1; };
var b = (!(/opera|webtv/i.test(ua))&&/msie (\d)/.test(ua)) ?
('ie ie'+RegExp.$1) :
is('gecko/') ? 'gecko' :
is('opera/9') ? 'opera opera9' :
/opera (\d)/.test(ua) ? 'opera opera'+RegExp.$1 :
is('konqueror')?'konqueror' :
is('applewebkit/') ? 'webkit safari':
is('mozilla/')?'gecko':'';
// see: http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html
var os = (is('x11')||is('linux'))?' linux':is('mac')?' mac':is('win')?' win':'';
var css = {browser:b,os:os};
return css;
}

Finally, to make all this fit nicely into a layout:


<head>
<%= javascript_include_tag 'browser_detect' %>
</head>
<body>
<%= render :partial => "browser_detect_start" %>
<%= @content_for_layout %>
<%= render :partial => "browser_detect_end" %>
</body>

Update:
Here’s a simple example of what this enables. The advantage of this over a conditionally included file is it keeps everything about the login box isolated to one place. You don’t need to worry about openning up a separate file to make your IE fixes. We do use iefix specific CSS for our site, but only for very large features like menus


#login {
padding:0px;
}
.ie6 #login {
padding: 2px;
}

CSS: CSS Browser Selector

Each browser has its quirks. Having a clear way of organizing the work arounds
for those quirks is a challenge. Using CSS selectors is not a new idea, but I thought it might be helpful to others to give an example of the technique and how we’ve been able to successfully deploy it for revolutionhealth.com.

First, for IE (the browser that usually requires a hack), we can rely on conditional comments. This is good because it means we don’t need to depend on Javascript. For other browsers we’ll have to rely on a document.write solution. For Safari, Opera, and Firefox, we rely on the script from http://rafael.adm.br/css_browser_selector/ and for IE, conditional comments.

Here’s what we include at the top of our document. (The browser_detect_start partial.)


<!--[if lt IE 7.]>
<div class='ie ie6'>
<![endif]-->
<!--[if IE 7]>
<div class='ie ie7'>
<![endif]-->
Continue reading "CSS: CSS Browser Selector"

Plugems – Why views in plugems?

When we started to develop Plugems we had multiple applications that all shared a similar look and feel. One concept that emerged recently for me was that layouts can act like objects. In our suite of applications, we have a base layout that each application can derive from to satisfy it’s unique set of presentation requirements. For example our UI plugem has the following:


ui/views/layouts/default.rhtml

Using a little magic from fora.pragprog we can extend our default layout writing the following:


<% inside_layout 'default' do -%>
<%= @content_for_layout %>
<% end -%>

As well as with layouts, there are also smaller blocks of UI that make up a page that can be shared. I’ve always thought of these as widgets, which in many cases can be defined as a set of partials and helpers. An application may place a widget on a view, feeding it the data needed to bring it to life. This is different from components because there is no controller logic. Really the presentation side of a widget can be expressed by a set of partials, Javascript, CSS and a healthy dose of ruby [e.g. helpers]. In this way partials are the basic building block on which many UI components can be built. By themselves they are incomplete, but within the context of an application they are alive…

Plugems enables you to share common UI widgets across multiple applications. Common assets (css, js, images) can live in a plugem, but be shared across applications at deployment time. I hope to post more in depth on this topic in near future.

Plugems – Why views in plugems?

When we started to develop Plugems we had multiple applications that all shared a similar look and feel. One concept that emerged recently for me was that layouts can act like objects. In our suite of applications, we have a base layout that each application can derive from to satisfy it’s unique set of presentation requirements. For example our UI plugem has the following:


ui/views/layouts/default.rhtml

Using a little magic from fora.pragprog we can extend our default layout writing the following:


< % inside_layout 'default' do -%>
< %= @content_for_layout %>
< % end -%>

As well as with layouts, there are also smaller blocks of UI that make up a page that can be shared. I’ve always thought of these as widgets, which in many cases can be defined as a set of partials and helpers. An application may place a widget on a view, feeding it the data needed to bring it to life. This is different from components because there

Continue reading “Plugems – Why views in plugems?”