Archive for March, 2014

Try the demo in Internet Explorer 11 and in a real browser.

IE now implements Range objects, representing a range of text that may span several elements. It's the basis for the standards-based part of bililiteRange. And it almost works. It's a little flaky: inserting text that contains '\n' without '\r', what I consider the "normal" way, automatically inserts the '\r'. Then using node.nodeValue returns a string without the '\r', but Range.toString() includes them. But that I can hack around.

The real bug is that ranges cannot end with a '\n'. If you try, the range is truncated. I can't find any way around that, so I had to change the way bililiteRange returned text: I went from range.toString() to element.textContent.slice(). Since that works with no other changes, I suspect that the error is in IE's toString() function itself rather than reflecting an underlying error in the Range.

Now to report that to Microsoft.

Evidently I'm doing test-driven development wrong. Or at least it could be easier. I will have to look at Google's karma to automate the testing (rather than running the test suite in each browser individually). That of course means I need to start using Node's npm package manager (which I probably should anyway, since all the cool kids are). I've been using chocolatey for installing programs, but it explicitly is designed to not overlap with Node and its package manager (though it will install Node itself).

This post will have to be my reminder to start hacking with all of this sooner rather than later. Now I have to see patients...

Turns out Internet Explorer is even worse than imagined. It's right at the bottom of the Uncanny Valley--close enough to a real browser to make it look like it works, but lots of near-impossible-to-track-down bugs that make life miserable. Turns out that Node.normalize is broken (see the bug reports and a workaround), so I had to add a test in bililiteRange to check for that, and not bother normalizing text if it's broken. Normalization just means merging adjacent text nodes, so losing it makes things less efficient but it should still work. I'm not going to lose sleep over Internet Explorer's inefficiencies.

Trying to debug bililiteRange in IE11; some of the problems were easily fixed with .replace(/\r/g, '') liberally scattered about, since IE really likes its return characters in <div>s (anything that is not a <textarea> or an <input> and will add them even if I am just inserting a newline.

I'm still getting a WrongDocumentError on some tests, but when I run them individually they pass; there must be some subtle global interaction that I am just not getting. I will consider those passed for now, though it is annoying seeing the red when I run the tests.

That leaves one error in find, one error in sendkeys, and whole bunch in ex, which isn't officially working yet anyway. Progress!

Well, I ran the test code for bililiteRange and got "132 assertions of 151 passed, 19 failed." Better than none passed, I suppose, but it means I've got some work ahead of me. Or I could just give up on IE, but IE11 is supposed to be standards-compliant, so the errors might actually reflect a problem.

Some of the results are weird: the expected and actual results look identical, so I imagine there's some '\r's rearing their ugly heads, even in IE11. The selection is not being retained on losing focus in input elements; that might be a real problem. And then some tests are failing with a "WrongDocumentError". Never seen that before.

I'll add this to my list of things to get to eventually.

Finally got a new machine (Toshiba Satellite C75), with Windows 8.1, and despite all the negative hype, it doesn't suck. My wife has had a Windows 8 computer for a while now, and I had explained that teh way to think about it was as two separate operating systems: the old, mouse-oriented one; and the new, touch-oriented one. She's adapted well to that.

But playing on my own machine made me realize that's the wrong mindset. I now treat the Start screen as a big Start menu, organized with all the programs I want the way I want them. The first thing was to remove all the junk that was on there (I kept the weather app and the news but that's it) and start pinning my programs (Notepad++, Chrome, Git Bash, etc). Now it's Windows key or mouse lower-left, then type or click what I want. I had to write a few .bat files and pin the shortcuts to get websites to open in Chrome, but that works as well.

Now to see what all the fuss with IE 11 is about...

The question came up about using "European" dates (day/month/year) rather than "American" dates (month/day/year) in flexcal. The biggest problem is that the built-in Date.parse() (which is used by new Date(string)) uses the American format, at least with my browsers and settings.

The code in flexcal that does the formatting are in the following methods:

format({Date})
Converts a Date into a String. Used for external formatting: it determines what string is put in the input element after the user selects a date.
_date2string({Date})
Converts a Date into a String. Used for internal formatting: the rel attribute of each day link in the calendar is set with this.
_createDate(d, oldd)
Attempts to coerce d into a Date. If it is a valid Date, just returns that. Otherwise returns new Date(d). If that does not create a valid Date, returns oldd.
this._createDate(this._date2string(d)) must equal d in order for the calendar to work, and this._createDate(this.format(d)) must equal d for the calendar to be able to parse the string in the input element.

So to use European dates, we have to replace each of those methods. I'll use the "dd.mm.yyyy" format.

<input id="eurodate" value="01.02.2014" /> Should start as February first, not January second.

function euroformat (d){
  return d.getDate()+"."+(d.getMonth()+1)+"."+d.getFullYear();
}
$.widget('bililite.euroflexcal', $.bililite.flexcal, {
  format: euroformat,
  _date2string: euroformat,
  _createDate: function (d, oldd){
    // converts d into a valid date
    oldd = oldd || new Date;
    if (!d) return oldd;
    if (typeof d == 'string' && d.match(/(\d+)\.(\d+)\.(\d+)/)){
      d = RegExp.$2 + '/' + RegExp.$1 + '/' + RegExp.$3; // convert to American style
    }
    if (!(d instanceof Date)) d = new Date(d);
    if (isNaN(d.getTime())) return oldd;
    return d;
  }
});
$('#eurodate').euroflexcal();