boogdesign posts

Longer posts on standards based web design, portable web development and Linux, intermingled with some stuff on my other nerd interests.

Rob Crowther, London, UK based Blogger, Web Developer, Web Designer and System Administrator - read my Curriculum Vitae

Buy my book!

Book CoverHello! HTML5 and CSS3 available now

Buy my other book!

Book CoverEarly access to HTML5 in Action available now

21/01/08

11:41:55 pm Permalink Web Development for the Blackberry Pearl

Categories: Usability & Accessibility, Front End Web Development

We had a potential client which wanted to use our web application on their Blackberry Pearl devices. I figured "How hard can it be?", downloaded an emulator and got cracking :) I wanted to make the standard pages support the Pearl, I didn't want to write a whole new web app, without changing how they worked on desktop browser to avoid confusing existing customers.

The tips below are things I specifically ran into on the Pearl, I imagine they'll apply pretty well to any low end mobile browsing device.

Tables make layout inflexible - the Blackberry has a fairly narrow screen when compared to a desktop. If your form laid out is in a table which is several hundred pixels wide the chances are it's not going to fit in the width. Since your page is most likely already too long for the display this is going to leave users having to scroll in two axes to complete the form. To avoid this I changed all the forms I expected to get used on the Pearl into a tableless layout which then used CSS to achieve the same display on the desktop, and then add a mobile stylesheet to override this:

<link rel="stylesheet" href="style/handheld.css" media="handheld" type="text/css">

This meant they lay out in a grid on a desktop browser but in a linear column on mobile devices

No javascript by default - the web app I was working with has been in production for more than five years, so it has it's share of hairy code particularly in the javascript department - a mixture of inline and external. One of the main issues for me was that so much of the supporting functionality depended on JS - for instance the search form could be filled out and submitted, but the functionality for scrolling through the results depended on onclick events on buttons. I re-wrote the forward and back buttons to be wrapped in little forms of their own which submitted to the correct URLs to solve that fairly easily (and that worked just as well for full desktop browsers too).

The more difficult situation was the input form, which, although it allows free text input, also allows you to select from a list of available options. Unfortunately the way this has always worked is for users to click on a button which launches a pop-up window, then double click on the item they want out of the resulting select list. The value is then inserted into the main form and the window closed, and the whole process is driven by javascript.

So, obviously it's not going to work at all without any javascript. I should point out this represents a bad design decision, I should have started with a form which worked without javascript and layered the enhanced behaviours on top (a technique known as progressive enhancement, but way back when the decisions were made I didn't know any better and neither did anyone I worked with. So I was re-writing the page in my ASP era web app, but I wanted to keep visually identical (close enough, at least) to the previous version. Here's an example of what the form components looked like before I started (names have been changed to protect the innocent):

<tr>
<td>
  <input class="standardWidth" value="Service Group" onclick="openPopup('Default.asp?WCI=listItems','PopUp','300','680');" type="button">
</td>
<td>
  <input autocomplete="off" name="txtITEM" id="txtITEM" size="25" maxlength="20" title="Click button to display list" value="" type="text">
<div style="display: none;" class="auto_complete" id="txtITEM_complete">
</div>
<script type="text/javascript">
new Ajax.Autocompleter('txtITEM', 'txtITEM_complete', 'Default.asp?WCI=listItemUL', {minChars: 2});
</script>
</td>
</tr>

A quick note here so you don't get lost - I'm using scriptaculous for the auto complete, openPopup is a fairly standard popup function, all the server side functionality is encapsulated in a WebClass, basically a VB6 DLL embedded in an ASP page, so different pages are called up by varying the WCI= parameter.

After I'd switched to a tableless layout (see above), my first step was to comment out all the javascript, this broke everything &amp;#58;&amp;#41; Next, I changed the input element to be a submit. Every button on the form would submit it and I planned to then detect which button had been clicked on the server side. This is relatively straightforward, just give all your submit buttons a common name (but a unique id so you can reference them individually in script):

<div>
    <span class="colLeft">
        <input type="submit" name="butLogForm" id="subITEM" class="standardWidth" value="ITEM">
    </span>
    <span class="colRight">
        <input type="text" name="txtITEM" id="txtITEM" size="25" maxlength="25" value="" title="Click button to display list">
    </span>
</div>

Then, on the form target page you check the value of butLogForm, so in VB6/ASP it's Request( "butLogForm" ), and its value will be the whatever you assigned to the button which was clicked (ITEM in the above example). So if a button other than the 'main' submit button has been pressed it's easy to detect this and redirect to the appropriate selection page for the field (which would be the same page as was originally appeared in the popup window summoned by clicking the button). I then added some plumbing to direct the popup page to either submit the value as a form or populate with javascript into opener depending on how it was called and to capture all the values behind the scenes once the user had selected them.

So now the form worked fine with javascript disabled, the only task left was to make it work as it did before in a desktop browser, popup windows and auto-completes, when javascript was enabled. This was slightly complicated by the need for the javascript to know the URLs for all the pages, and these could be changed at runtime, so I decided to pass them all in as parameters to the onload function (there is a URLFor) utility function available within the webclass which calculates them). To reduce the number of URLs to be passed in I used a naming convention so that the URL for the auto-complete function could be easily generated from the popup URL by appending 'UL' to it:

if ($('subITEM')) {
    $('subITEM').onclick = function () {openPopup(urlITEM + '&IsForPage=Log','PopUp',width,height); return false;};
    if (!$('txtITEM').readOnly) {
        var elTxtITEM = $('txtITEM');
        acDiv = document.createElement('div');
        acDiv.className = "auto_complete";
        acDiv.id = "txtITEM_complete";
        elTxtITEM.parentNode.appendChild(acDiv);
        new Ajax.Autocompleter('txtITEM', 'txtITEM_complete', urlITEM + 'UL', {minChars: 2});
    }
}

The code is fairly simple. First I check to see if the relevant submit button actually exists (there are configuration settings in the app to turn each field on and off) and, if it does, adds the old popup code to the button. Next I check to see if the text field is editable (another configurable option) and add both the div required by the Ajax.Autocompleter and then initialise the control itself.

The <button> element is useless - well it might not be completely useless, I didn't try too hard, but I decided I was only using it in the first place to show off my l33t HTML skills so I just switched them back to regular input elements.

No CSS by default - the browser on the Blackberry Pearl will not use CSS by default, though you can change the configuration to enable it and it will then respect the mobile stylesheet. The main problem this posed for me was that, in a lot of places, I was relying on padding and borders to provide spacing between text elements, eg:

<div><span><strong>Status:</strong></span><span>Active</span></div>

So when CSS is turned off you end up with tall the text running together with no spaces in between, making it hard to read. Since in this situation it's impossible to control the presentation with CSS I resorted to using markup for it and added &nbsp; glyphs inside the spans in every place where the text needed a space.

Turning on javascript leads to memory errors (slowly) - just like CSS, the browser on the Blackberry Pearl will not use javascript by default. This leads to the issues I already covered above, but a more amusing issue occurs if the user happens to enable javascript. The Pearl is a low memory device, even compared to other smart phones, and if your web app has several hundred kilobytes of javascript for it to download it will use up all of that memory in a vain attempt to parse the file. Since all the javascript gets downloaded in a standard header this led to a long wait and then an error message when you even tried to access the login page on my app. I made an extremely cut down javascript file, basically the standard field validation and date formatting functions, the openPopup function and some empty function stubs for all the onload functions (to avoid error messages). Since I didn't have the time or resources to implement WURFL or DeviceAtlas and this is only ever likely to be used in controlled corporate environments, I made a user configuration setting in order to send the cut down version to the Blackberry instead of the regular JS .

Only onchange on inputs, no onblur or onfocus - the final thing that caught me out was to do with my validation and formatting helpers on text inputs, these were all hanging off onblur and were not getting fired on the Pearl. The quick solution was to change everything to onchange instead, though the reason I'd used onblur in the first place was because I'd experienced some unreliability in the desktop browsers so this was not ideal. Unfortunately I had to wrap up this project before I had chance to get into it in more detail.


Tweet this!
Send feedback »PermalinkPermalink

25/11/07

10:37:40 pm Permalink DDD 6

Categories: Web Develop

Review: DDD6 at Microsoft UK Campus, Building 3, Thames Valley Park, Reading, Berkshire. RG6 1WG. 08:45 to 17:00

I'm more of a web developer than a 'Microsoft developer', but I use a lot of the MS stuff at work and I really enjoyed WebDD last February so I thought I'd give the more .Net focussed parent event a try.

Why IronRuby? (Presentation) Dave Verwer - I'd been to a couple of Dave's talks at the WebDD event and enjoyed them tremendously, so I went in to this one with high expectations. The talk started with some of the benefits of Ruby - a dynamic language with elegant syntax designed for simplicity and productivity, before going on to discuss how IronRuby and the DLR are implemented in .Net. The DLR is basically a layer for dynamic languages on top of the standard CLR, it is an abstraction of the what was developed in the course of getting IronPython up and running. At this point Dave admitted that IronRuby wasn't yet ready for use, so the rest of his talk would be about (C based) Ruby 1.8 - which IronRuby is targeting for compatibility. This was a bit of a disappointment for me, because really I was after a more practical demonstration of IronRuby than another presentation on Ruby - but it's possible I was in the minority given the audience. Check out the IronRuby website if you want to learn more.

Entity Framework (Presentation) James Winters - I had no idea what this was before the talk, but the title sounded more interesting than the others available in this slot, and it saved me leaving the room when I knew I wanted to see the talks either side. In the event, I was glad I stayed. To give a simple sound bite - Entity Framework is like an ORM on steroids, which will allow transparent mapping to non-relational stores, such as LDAP, as well as the more usual SQL stuff. The plan is for all MS server products to move to Entity Framework for their data access, though at the time of the talk the only backend available was SQL Server and all the examples were basic ORM stuff. The logical model of Entity Framework is made up of three levels:

  • O-SPACE - the object model, eg. LINQ
  • C-SPACE - the conceptual model, eg. Entity Client
  • S-SPACE - the store - eg. ADO.Net.SqlProvider

All levels are scoped by an entity container, which defines a namespace and an object model, and the goal of the MS Visual Studio team is to be able to generate the lower levels using visual tools.

Entity Framework supports multiple querying methods:

  • ESQL - very similar to HQL in Hibernate
  • Object Query - a generic object interface with caching and lazy loading, which can either be read only or mergeable
  • Use Entities directly
  • LINQ

There are some limitiation, there is no locking by default and, while it's going to be possible to map stored procedures the visual tools aren't going to support it for some time so you have to write up the XML manually. Generally, though it has a slight whiff of the architecture astronaut, it looks like an interesting addition to the .Net toolbox (Slides available here).

Why do I need an Inversion of Control Container? (Presentation) Mike Hadlow - I'd heard of Inversion of Control (IoC), but hadn't really understood what it was for. The presenter, Mike, had been in a similar position until he started studying it seriously, and now he was here to share his epiphany. The main problems IoC is trying to address is that the relationship between component size and complexity is not linear - double the size of your components and you quadruple the complexity - but breaking components into smaller pieces tends to lead to increased dependencies. Inversion of control reduces the complexity of large components and manages the dependencies between them. The principals of inversion of control (paraphrased from Robert Martin) are:

  • High level modules should not depend on low level modules
  • Abstractions should not depend on details
  • Details should not depend on abstractions
Typical problems of OO code without IoC are:

Inversion of control helps with all these by allowing constructor injection and property injection. If these can be injected into components at runtime, rather than hard-wired into the components, then it becomes possible to modify the behaviour of components without having to modify the components thus satisfying the open/closed principal and reducing the coupling (property injection) and also to easily mock objects for unit testing (constructor injection). Mike then moved on to some detailed demonstrations using the Windsor component from the Castle project, before concluding that IoC is really just the thorough application of design patterns and other OOP best practices. Therefore you should only start considering inversion of control once you're already familiar with these and have already implemented things like unit testing (Slides available here).

Dynamic Languages on .NET (Presentation) Michael Foord - My first session of the afternoon and by this point I was flagging a bit after having to get up early and make the trip out to Reading. Michael is one of the authors of Resolver, a spreadsheet based application environment, aimed at the financial markets and written in IronPython. The app is approximately 30000 lines of code, thus refuting the myth that it's impossible to write large applications in a dynamic language, and it's spreadsheet model is implemented in a Python hash table, making it very easy to extend Resolver with new types and operators. After a discussion of what constitutes a 'dynamic language' and the overall benefits of Python and IronPython in particular, Michael moved on to some practical examples based on his IronPython Web IDE (Slides available here)

Testing Your Applications With MbUnit Gallio (Presentation) Ben Hall - unit testing is a popular topic on programmer blogs these days, and this was reflected in a fairly full room for one of the 'minor' talks (ie. we weren't in one of the big rooms). Ben covered some best practices of automating unit testing on .Net with MbUnit and Gallio, starting at the database layer (use transactions and rollbacks or COM+ transactions), the business object layer (mocking and inversion of control) and the user interface (don't try and automate it!). An interesting if slightly hurried talk which I was unfortunately too tired to pay full attention too (Slides available here)

Overall a good day, I definitely learned more than one new thing per talk and the Microsoft conference room facility is a good venue for these sorts of things, so 4 out of 5, and I'll almost certainly try and get to the next one.

Technorati tags for this review:  

Tweet this!
Send feedback »PermalinkPermalink

16/11/07

07:32:19 pm Permalink IE6 & 7 Up/Down Keypress Issues with Ajax.Autocompleter in Scriptaculous 1.8.0

Categories: Front End Web Development

I started a new project at work today, adding some ajaxy interactivity to a slightly long in the tooth web application. In a previous iteration I'd plugged prototype.js 1.5.1 into this app, now I wanted snazzy effects and autocomplete fields. Figuring it was a good time to move up to the latest version of scriptaculous, I downloaded the recently released 1.8.0 version (which includes prototype 1.6.0).

I had to do some hacking around in my 'legacy' javascript to get things working in Firefox (that's how long in the tooth this application is), and then I added my Ajax.Autocompleters, got my afterUpdateElement callbacks working and was starting to feel generally quite chuffed with myself at how well it was all going. Then I thought I'd give it a quick check in IE...

In IE7 the up and down arrows didn't scroll up and down the autocomplete list, which made the whole thing kind of useless. A quick check in IE6 confirmed the same issue there, so I immediately resorted to Google. Unfortunately the answer wasn't immediately apparent in the search results and it was only when I started searching the Ruby on Rails Trac directly I finally homed in on the answer. Hoping that I can help future searchers home in on this more quickly, here's the defect: "some keypress events don't work in IE6/7"; and here's the fix.


Tweet this!
1 feedback »PermalinkPermalink

17/10/07

06:27:48 pm Permalink IT?S A MASHUP: The End of Business as Usual

Categories: Blogging and Internet Culture, Management and Communication

Review: Andy Mulholland - The End of Business as Usual at BCS, 5 Southampton Street, London WC2 October 15th, 18:15 to 20:15

I went to this BCS North London branch event because they usually have an 'enterprisey' slant and this one was supposed to be about Web 2.0 and mashups, which is not something I regularly associated with enterprise IT. Andy Mulholland was a very good speaker, it seems like we got the same presentation he regularly gives to boards of directors, the slides are available from the link in the previous paragraph. From now on I'm going to assume you've looked at them and list some of the things Andy discussed while he was showing the slides that stuck in my mind (ie. for an overview of the whole talk, read the slides).

The key trend affecting enterprise IT in the drive to web 2.0 is that users and consumers are now driving technology adoption, they get used to things at home and start to ask themselves why they can't use similar tools at work. As the proportion of tech-literate vs tech-illiterate clients and workers shifts in each industry, we pass an 'inflection point' past which businesses have to change to remain competitive. There are some businesses where this has already happened: travel; retail; music. The traditional business view of IT products is characterised by: "If I purchase this, I can work more cheaply." The user led change of priority is from the perspective: "If I purchase this, I can work more effectively."

There are some common traits of businesses which 'get it' which can easily be contrased with more traditional business practices:

New: Amazon leads with the most popular items responding to external demand
Old: Barnes and Noble leads with its internally defined offers

Right: eBay allows external demand to create new markets and indexes
Wrong: CommerceOne failed as it defined the markets that it would make available

Aware: Google business model continuously improves, people explore for the new
Adaptive: Traditional Software business model depends on set upgrade offers periodically

Innovative & Money Making: Second Life participants create over 7 million lines of code a week to improve environment. As of December 2006 456 people earn over $500; 29 over $5000; 2 over $25000 Every month from participating in Second Life. About 500,000 Chinese work in ?gold farms? creating superior players and selling them.

Web 1.0 was characterised by content, web 2.0 is characterised by contacts or community, this reflects a general shift for the knowledge worker: 20 years ago 80% of the knowledge they needed to do their job was in their heads, now only 20% is in their heads and the rest depends on them exploiting the vast information resources available, which is too vast for them to do by themselves.

Finally Andy discussed how to build a business case for mashups (and web 2.0):

  • Not all valuable business interactions involve a transaction
  • Front office to back office integration depends on open standards
  • We are fixated on productization. Move the value proposition from the box to the knowledge.
  • Wrong question: "If I had Google Apps, what would I save over MS Office?"
  • Right question: "What can I do with Google Apps that I can't do with MS Office?"

Overall this was an excellent talk, 5 out of 5, which may not be obvious from my potted summary. If you have a chance to see Andy Mulholland speaking in person I recommend you take it.

Technorati tags for this review:    

Tweet this!
Send feedback »PermalinkPermalink

16/10/07

03:02:19 pm Permalink My First Website for Mobiles

Categories: Web Design, Front End Web Development, Server Side Web Development

At work we decided to purchase a few .mobi domains, not because we have any particularly compelling mobile content, but to boost the web presence of our mobile product and, mostly, to make sure no-one else snapped up the domain names we wanted. However this did give me the opportunity to build my first website explicitly for mobile devices.

I'd checked our main website on ready.mobi, because I have written a mobile stylesheet for it, but it got a pretty crappy score mostly because of the sheer size of the content. So my main goals for this first site were to:

  • Produce a website which validated
  • Get a 'Good' score on the ready.mobi evaluator

My first task was some background reading, I had a look through the DotMobi Mobile Web Developer's Guide and Luca Passani's Global Authoring Practices for the Mobile Web. Following that, I grabbed a page off the main website and broke the content up into three XHTML-MP pages. This was easy enough to do after reading the guides, not much different from creating regular XHTML pages. The only bit I wasn't too familiar with was sorting out the navigation and access keys. It was easy on the home page (actual links changed for brevity):

<ol>
<li><a href="page1.php" accesskey="1">One</a></li>
<li><a href="page2.php" accesskey="2">Two</a></li>
<li><a href="page3.php" accesskey="3">Three</a></li>
<li><a href="page4.php" accesskey="4">Four</a></li>
</ol>

But on the other pages I wanted to avoid having a link to the current page, but keep a consistent numbering scheme, from 'page3.php':

<ol>
<li><a href="page1.php" accesskey="1">One</a></li>
<li><a href="page2.php" accesskey="2">Two</a></li>
<li value="4"><a href="page4.php" accesskey="4">Four</a></li>
</ol>

So that was the actual content sorted out, most of the issues I was seeing in the ready.mobi validator were to do with server side configuration. Some mobile browsers require a application/vnd.wap.xhtml+xml MIME type, which Apache isn't going to do by default, but is easy enough to configure. However, I wanted the website to display on my boss's desktop browser too and IE will have some difficulties with that, so I decided to use PHP to do some lightweight browser detection:

<?php
header("Cache-Control: no-transform, max-age=86400");
header("Vary: User-Agent, Accept");
if (strpos(strtolower($_SERVER['HTTP_ACCEPT']),'application/vnd.wap.xhtml+xml')>0) {
header("Content-type: application/vnd.wap.xhtml+xml");
} elseif (strpos(strtolower($_SERVER['HTTP_ACCEPT']),'application/xhtml+xml')>0) {
header("Content-type: application/xhtml+xml");
} else {
header("Content-type: text/html");
}
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

This works by looking to see what MIME types the browser says it can accept, then giving it the best one it can handle. Note that I'm also advising transcoding proxies not to transform this content.

The final setup step was to set appropriate cache headers on all the static content. This is easy to do in .htaccess:

<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 day"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType text/html "access plus 1 week"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
<FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$">
ExpiresActive Off
</FilesMatch>
</IfModule>

Note that I'm ignoring PHP files in this directive, as I'm already handling the headers in the PHP files.

One final note, as I discovered a few times while working on this, you need make sure your error pages also handle all the MIME type stuff and are valid XHTML-MP, otherwise the experience could be confusing for mobile users. This applies to 404 pages (I just made it a PHP page) and your formmail.php script (if you're using one).

And there you have it, my first real, live, mobile website!


Tweet this!
Send feedback »PermalinkPermalink

04/10/07

12:28:23 pm Permalink The only book you'll ever need

Categories: Blogging and Internet Culture

It's been a while since I posted anything, I actually have two half written posts sitting in draft status which I'll get around to eventually, but this morning I'm inspired to write &amp;#58;&amp;#41;

I followed a link from raganwald's post to The Little MLer on Amazon, the thing that caught my eye was one of the reviews:

This is a nice and at times fun introduction to ML that gives the reader a hint as to the true power and complexity of functional programming, but buyers should be aware THIS WILL NOT BE THE ONLY ML BOOK YOU WILL NEED.

What I think is surprising is that anyone could be reviewing a book on Amazon and be thinking that on there, somewhere, is a book that will tell them all they ever need to know about anything even moderately complex (ie. any subject worth writing a book about).

The same author was critical of the book because the style "kills its utility as a reference". Why would you expect a tutorial book to be a good reference? Why would you expect a reference book to be a good tutorial? Is this sort of attitude the reason why the programming books market is flooded by unnecessarily thick books which are both below average tutorials and below average references? From chapter one of Thinking in Java:

In a good object-oriented design, each object does one thing well, but doesn?t try to do too much.

Perhaps I shouldn't be surprised though. Every day on the blogosphere I see comments which seem to support the belief that just because it's possible to solve almost every programming problem in Java or C# or Python, that Java or C# or Python are appropriate for solving every programming problem; that just because Ruby on Rails presents a nice paradigm for web development, that all web development should be done in Ruby on Rails (substitute cool web framework of your choice); and people who happily use frameworks for their chosen language which require thousands of lines of XML (or worse) configuration files berate web development in general for being too hard because it requires learning more than one language (or technology, or whatever other category you like to put declarative markup into).


Tweet this!
2 feedbacks »PermalinkPermalink

31/08/07

11:19:20 pm Permalink Doing Dumb Things with the Javascript Date Object

Categories: Front End Web Development

I ran into a weird (but, in retrospect, entirely predictable) problem generating dates. The code in question is supposed to kick in when the user is booking a resource for multiple days - this day each week for four weeks, this day each month for four months etc. Taking the interval and the number of occasions it is supposed to generate a list of dates.

Originally this code worked by calculating the number of milliseconds in a day, week or month and then adding it to today's date repeatedly. Before you point out that this is a completely dumb way of doing this I should mention that the Date object was only fully supported in IE4, and this code is probably old enough that this was significant &amp;#59;&amp;#41; Anyway, the adding milliseconds approach fails whenever the sequence of dates crosses a change to or from British Summer Time, so I'd changed it to use the date object and then set the desired date using the standard methods. This worked much better in the BST case, but we started getting intermittent bug reports of strange things happening - whole months being missed in a sequence. Whenever we tried to replicate the issues, however, we didn't see a problem.

It was only when I happened to be doing some unrelated work on the same page on the 31st August that I finally realised what the problem was. Here is the code as it stood, see if you can spot the obvious problem:

var startDate = new Date;
startDate.setUTCFullYear(2000 + startDateYear);
startDate.setUTCMonth(startDateMonth);
startDate.setUTCDate(startDateDay);

Because startDate is always 'today' then on all months with 31 days in them setting the month to one with only 30 days in it is going to lead to a date like 31st September. At this point Javascript helpfully sets the date to the first of the next month (or the third, if you happen to be aiming for February). So, as I was actually busy with something else, I went for the easiest fix I could think of - switch the order of the setUTCMonth and setUTCDate lines:

var startDate = new Date;
startDate.setUTCDate(startDateDay);
startDate.setUTCMonth(startDateMonth);
startDate.setUTCFullYear(2000 + startDateYear);

It worked well enough for the 31st August case so I went with it.

Of course, that didn't really fix anything, as I discovered when the bug reports started flowing in &amp;#58;&amp;#41; Now the problem happens the other way round - in any month with less than 31 days, trying to set startDate to the 31st causes the month to increment. Setting the day, month and year separately was a legacy of the old millisecond code, so the real fix was to use the Date constructor as intended:

new Date((2000 + startDateYear), startDateMonth, startDateDay)


Tweet this!
Send feedback »PermalinkPermalink