Entries from April 2006 ↓
April 29th, 2006 — Nuggets, Ruby
The title pretty much covers it, but i’ll elaborate.
A few days ago I decided it was about time I had a tinker with Google Sitemaps, part of which involves uploading a temporary file so google can be sure the website you’re trying to claim is actually yours. Anyway, fun things aside, google gave me an error message (“We’ve detected that your 404 (file not found) error page returns a status of 200 (OK) in the header.”) when it tried to read the file.
The error message was caused by a feature of Ruby on Rails, which when in Development mode, invalid pages are still served by Rails and sent with a 200 header, but logged as having a Routing error of “Recognition failed”.
All information pointed to a simple fix of setting the rails environment (ENV['RAILS_ENV']) to production mode, which would disable the aforementioned feature. Unfortunately for me, my environment was already set to production! I double checked this, logged into the ruby console on my web-server and checked the variables, then even checked which log file was being written to; everything was pointing to it being in production mode.
After a lot of browsing of forums and chatting in IRC channels, I succumbed to randomly trying anything, which is when i noticed in my environment.rb file there was a line of code that I couldn’t for the life of me remember why it was in there, or what it was doing; removing this line of code worked a treat, everything snapped back to how it should be functioning.
For future reference, the line in question was:
require 'error_handler_basic' # defines AC::Base#rescue_action_in_public
So there you go, now I have a 404 page and google accepted my site map, so we can all live happily ever after.
April 26th, 2006 — .Net, JavaScript
I’ve created a small update for my ServerControlIDs control, which removes the problem caused by controls within Repeaters and DataGrid.
If you had a repeater that for each item contained an Hyperlink control, you’d get a duplicate entry in the ClientIDs object for every record, to avoid this problem I simply don’t output any sub-controls from within repeater style objects.
That may sound like a bit of a hack, maybe it is, but if you want to refer to multiple elements within another, you shouldn’t really be doing it by ID anyway.
You can get the updated source here or view the full article here.
April 26th, 2006 — Nuggets
I apparently got around to reading Coding Horror a bit too late, as I missed this gem. It’s an article about a small application used to bend XP’s IIS to your every whim, perfect for those of us suffering at the hands of Microsoft.
The basic gist of the application is that it removes the limits of XP’s IIS, namely the problem of only being allowed one website and 10 concurrent users. It takes a bit of getting used to, especially if you’re using Visual Studio; if you are, remember to reset IIS to it’s default website before opening a website created prior to using IISAdmin.
April 12th, 2006 — .Net, Code, JavaScript
ASP.Net has an interesting way of handing the potential ID conflicts caused by embedding third-party controls within your web-page; it prefixes any sub-controls with their parent’s ID.
<asp:TextBox ID="txtUsername" Runat="server" /> within a standard page simply has an ID of txtUsername within the HTML output. On the other hand, the following example would result in something along the lines of _parent_txtUsername as the ID:
<div id="parent" runat="server">
<asp:TextBox ID="txtUsername" Runat="server" />
</div>
This isn’t really much of a problem when all you are working with is server-side code, but when you start tinkering with JavaScript, things become quite annoying and get an overall feeling of hackyness.
One solution, which I have used time-and-again, is to use a script block at the end of your page where you create a series of variables that contain the actual IDs. You then use these variables to reach the actual elements via JavaScript.
<script type="text/javascript">
var txtUsernameID = '<%= txtUsername.ClientID %>';
var txtPasswordID = '<%= txtPassword.ClientID %>';
</script>
This solution works fine, but it isn’t exactly pretty and it doesn’t weigh well on my conscience.
Javascript Mapping
I’ve created a simple class that traverses the control structure and outputs an object that contains the mappings, as above, but without any client-side intervention; not a <%= ...ClientID %> in sight.
An example of the output would be:
var ClientIDs = {
txtUsername = 'ctrl0_txtUsername',
txtPassword = 'ctrl0_txtPassword'
};
Which enables you to reference elements, that you know are server-controls, by calling ClientIDs.txtUsername.
Before:
<script type="text/javascript">
var txtUsernameID = '<%= txtUsername.ClientID %>';
var txtPasswordID = '<%= txtPassword.ClientID %>';
function validate() {
var username = $(txtUsernameID).value;
var password = $(txtPasswordID).value;
if (username == 'james') {
alert("you shouldn't be here!");
}
}
</script>
After:
<script type="text/javascript">
function validate() {
var username = $(ClientIDs.txtUsername).value;
var password = $(ClientIDs.txtPassword).value;
if (username == 'james') {
alert("you shouldn't be here!");
}
}
</script>
ServerControlIDs class
Methods
void Emit(page) - Builds the controls of the page into a mapped structure, registering a client-side script block for the output.
void Emit(control, literal) - Builds the controls of the control into a mapped structure, rendering the output into the literal control supplied. The literal is best suited to being placed into the <head> tag, which helps improve the semantic nature of your page.
Properties
bool Whitespace - Sets whether the output should contain whitespace, provided only for “prettifying” your code; defaults to off.
string VariableName - Sets the JavaScript variable name used; defaults to ClientID.
Usage
To use this class, simply create an instance in the PreRender event for your page — this ensures that all the controls have been set to their correct state — then call the Emit method you desire.
History
[1.1] Removed IDs from Repeater/DataGrid contained controls.
[1.0] Initial release
Download
That’s all there is to it, use the link below to get the latest version of ServerControlIDs.
Please note that this code isn’t pretty and it could probably do with some revising, but it works and that’s what’s important to me. I’m open to suggestions and feature requests.
Current Version (1.1)
April 12th, 2006 — Code, JavaScript
Handling events from within your page has always been a hit and miss affair, especially for somebody who doesn’t like mixing their code and markup. The way to go with events for a long time was to embed an attribute on the element in question; like onclick="do_something()".
That works fine, but we sure know it isn’t semantic. The way forward — greatly popularised by the Prototype, Dojo and Behaviour libraries — is to use DOM compliant event listeners. These fire arbitrary code, in a very similar way to attributes, when an event is raised. Unlike attributes these event listeners can be hidden away in their rightful place, the document header.
Perfect - clean semantic markup and real event handling.
…or is it? Unfortunately nothing is ever smooth when dealing with standards (it’s hard to promote the underdog when the underdog barely works anyway…).
Our Problem
The biggest setback for using event listeners is that nothing will fire until the whole of the body has finished loading, including any images that need to be downloaded. This can cause something similar to the FOUC, where a page appears in one state for a moment until the javascript executes; not a pretty sight and generally hard to sell as a browser fault.
If you had the following code in your header tag, the element aTable would be visible until the page has finished loading, at which point it would suddenly dissapear.
<script type="text/javascript">
function hideATable() {
document.getElementById('aTable').style['display'] = 'none';
}
Event.observe(window, 'load', hideATable, false);
</script>
What we really need is an onBodyRendered event to hook to, which fires as soon as the body has been parsed, irrelevant of whether the content has been loaded.
The Solution
The only real solution to this problem, as there isn’t an onBodyRendered event, is to force the browser to parse our javascript before it has finished loading. The method of doing this is to embed a script block just before the end of the body tag containing the functions you wish to execute. The reason this works is because the browser parses any javascript it encounters within the body tag and evaluates it while rendering.
The following code would hide the table before the page has finished rendering; exactly what we want.
<script type="text/javascript">
hideATable();
</script>
My additions
The above method isn’t completely desirable, because it is still mixing code with markup and any code within the footer will not be cached. There isn’t much you can do about that really, but one thing that i’ve taken to doing in my websites is to make sure there is only ever one function call in that footer script block.
My method of doing such a thing is to create a special object that represents all my pages and their individual footer script blocks. You can see below an example of such an object, there’s an wrapper object that allows for further extensions (such as Unload or Validation sections) and then the Load object that contains each pages onload function. Each page then has a single line script block like Pages.Load.Home();
var Pages = {};
Pages.Load = {
Home: function() {
highlightSomething();
hideSomething();
saveCookies();
},
Portfolio: function() {
hideSomething();
makeMeLookGood();
},
Contact: function() {
highlightFields();
}
};
So the above code is stored in an external js file and loaded in the usual way, thus being cached.
Before:
<script type="text/javascript">
highlightSomething();
hideSomething();
saveCookies();
</script>
After:
<script type="text/javascript">
Pages.Load.Home();
</script>
April 6th, 2006 — CSS
Well that’s it, the Annual CSS Naked Day is over, so everything is back to normal here.
It was a fun little outing, which gave me some little insights into modifications I need to make to my website. The two things that stand out to me the most are accesskeys for links and tab indexes for forms.
While I’m on that subject, I’ll be launching a new design for this blog sometime soon, one that matches the main sites appearance.
April 4th, 2006 — CSS
For this day only I am participating in the Annual CSS Naked Day; drop your styles and let everyone see your bits!
So don’t worry if everything looks a bit, naked, it’s all planned.
April 4th, 2006 — Personal
You should now be receiving this syndicated content from my new(ish) website http://www.jagregory.com. I’ve finally moved away from the .Text powered blogging system I’ve been using for the past few years in favor of Typo, a Ruby on Rails system.
I have a few reasons for doing this but the main one is that my blog as well as my personal website both validate to XHTML 1.0. On top of that, with the dynamic nature of Ruby on Rails, I can make changes to the layouts without having to recompile.
Please drop me a line if you spot anything out of place.