Posts filed under 'Web'

Diff for Javascript, revisited

Last weekend I finally revisited the diff-in-javascript code I’d written a couple of years back, adding (very simple) patch-like and diff3-like functionality.

On the way, not only did I discover Khanna, Kunal and Pierce’s excellent paper “A Formal Investigation of Diff3“, but I found revctrl.org, the revision-control wiki, which I’m just starting to get my teeth into. I’m looking forward to learning more about merge algorithms.

The code I wrote last weekend is available: just download diff.js. The tools included:

  • Diff.diff_comm - works like a simple Unix comm(1)
  • Diff.diff_patch - works like a simple Unix diff(1)
  • Diff.patch - works like a (very) simple Unix patch(1) (it’s not a patch on Wall’s patch)
  • Diff.diff3_merge - works like a couple of the variations on GNU’s diff3(1)

Read on for some examples showing the library in action.

Continue Reading Add comment May 9th, 2008 tonyg

XML CDATA and escaping

XML’s syntax for CDATA looks like this:

  <![CDATA[some text]]>

Tag syntax within a CDATA section is suspended, so this is well-formed XML:

  <![CDATA[some <more> text]]>

even though it looks like the “<more>” tag is unclosed.

There’s only one thing you can’t say in a CDATA section: “]]>”. But there’s a trick to save us, even here. To print an arbitrary string in a CDATA enclosure, replace each instance of “]]>” with “]]]]><![CDATA[>”, and then put the normal “<![CDATA[”/”]]>” brackets around it:

  my ]]> text

becomes

  <![CDATA[my ]]]]><![CDATA[> text]]>

1 comment October 25th, 2007 tonyg

Why does everything on the web require registration?

Some sites or services, quite reasonably, need to know who I am (and that I really am that person, to some acceptable level of verifiability). It’s usually because they hold data on my behalf, and neither me nor they want anyone else getting at that data.

But why does InfoQ require me to register to download a free PDF? They say, … we’re happy to offer a free version for download, to get this knowledge in as many peoples hands as possible; however, I had to complete a long form (to which I mostly invented answers), then verify my email address, then navigate back to the page. I hardly see how that is compatible with the stated aim.

After running into that, I almost despaired when I went to download the official MySQL JDBC driver. Almost: there’s actually a link below the register (or log in) options saying “No thanks, just take me to the downloads!”.

Yay for MySQL.com!

3 comments June 12th, 2007 mikeb

Only two things are infinite

YAHOO has announced that it will soon be offering unlimited storage to users of its free web-mail product. What does it really mean, and what can we learn from this about the marriage between engineering and marketing.

Continue Reading 5 comments March 28th, 2007 Tom Berger

Improved unobtrusive linked select boxes

Here’s a problem that crops up regularly in Web interfaces: having a dropdown whose available options depend on another dropdown. The canonical example, if you like, is the date selector:

Select date

This has the obvious (though not serious) problem that one can select, say, February 31st. We’d like to catch those errors by having the values in the “day” select depend on what is chosen in “month”. It’s easy to do this on the server with a round-trip, of course, but that has the problems that the user interface can be in an inconsistent state before the form is submitted; it would be nice to be able to finesse the interface, using JavaScript, to remove that possibility.

We can do this ad-hoc, of course, but that needs specialised code for each instance (well, for each type of data and dependency); a general solution would be better. We’d also like it to be unobtrusive, by which I mean two closely related things:

  1. The markup is meaningful
  2. It works without JavaScript

Bobby van der Sluis gives a pretty good general solution. Briefly, the technique involves keeping a full set of the dependent options and picking the appropriate options from it when necessary.

It relies on encoding the dependency as an HTML class: to me it’s a muddy use of class, but the real problem is that it’s not a very obvious way of making the dependency explicit in the markup. I think we can improve on it. Using OPTGROUP we can produce straight-forward markup that makes the dependency obvious:

      <form>
      <fieldset>
        <legend>Select date</legend>
        <label for="month">Month</label>
        <select id="month">
          <option value="jan">January</option>
          <option value="feb">February</option>
          <option value="mar">March</option>
          ...
        </select>
        <label for="day">Day</label>
        <select id="day">
          <optgroup label="January">
            <option value="1">01</option>
            <option value="1">02</option>
            <option value="1">03</option>
            ...
          </optgroup>
          <optgroup label="February">
          ...
        </select>

Without JavaScript it looks like this:

Select date

Here’s my (allegedly) improved unobtrusive linked select box code (it uses MochiKit to avoid some verbose DOM manipulation — just read $(x) as “select the element with ID ‘x’”, and the rest does what it says):

function linkSelects(parent, child) {
  var parent = $(parent);
  var child  = $(child);
  var cloned = child.cloneNode(true);
  removeEmptyTextNodes(cloned);
  refreshDynamicSelectOptions(parent, child, cloned);
  connect(parent, 'onchange', function(event) {
    refreshDynamicSelectOptions(parent, child, cloned);
  });
}

function refreshDynamicSelectOptions(parent, child, optionholder) {
  var alreadySelectedValue = (child.selectedIndex >= 0) && child.options[child.selectedIndex].value;
  replaceChildNodes(child);
  var selectedLabel = strip(scrapeText(parent.options[parent.selectedIndex]));
  for (var i=0; i < optionholder.childNodes.length; i++) {
    var opt = optionholder.childNodes[i];
    if (opt.tagName.toLowerCase() == "option") {
      var newopt = opt.cloneNode(true);
      if (newopt.value == alreadySelectedValue) newopt.selected = true;
      appendChildNodes(child, newopt);
    }
    else if (opt.tagName.toLowerCase() == "optgroup" && opt.label==selectedLabel) {
      for (var j=0; j < opt.childNodes.length; j++) {
    var newopt = opt.childNodes[j].cloneNode(true);
    if (newopt.value == alreadySelectedValue) newopt.selected = true;
    appendChildNodes(child, newopt);
      }
    }
  }
}

and lastly, here’s the working version:

Select date

There remain a couple of weaknesses. It relies on the convention of OPTGROUP labels being the same as OPTION text; it’s reasonable, since there is a semantic link between those two things. Also, it doesn’t always get selection right — easily seen in this example, where you’d expect a choice of ‘01′ to persist when changing months. I think those are tweaks away.

Add comment February 21st, 2007 mikeb

Web Development with Python

For a new web project we’re working on, we wanted to use a dynamic environment. We’ve resolved to use Python, a language we feel very comfortable with, and I went to test several pythonic web components, in particular the stuff that gets bundled with TurboGears and web.py.

Continue Reading 18 comments November 15th, 2006 Tom Berger

DLAs, mashups and canapes

TV Chefs and blogs have had it — networking evenings and portals are back

Last Thursday I went to and event titled Digital Lifestyle Aggregators at the ever so posh BT Centre and learnt three things about this latest web 2.0 trend

  • Digital Content Aggregation is when you present a load of different content sources in a single interface (yes, what used to be called a Portal, but is now, like most consumer marketing things, a lifestyle)
  • A Mashup is when you put this stuff together (integrating RSS feeds and using stuff like the Google Earth or other web2-style API)
  • If you want to get funded, do a DCA Mashup - although it’s probably already too late, as pretty much everyone at the event seemed to have found VCs recently. Even BT themselves sounded committed to it. Their director of strategy suggested they would be embracing the new internet economy by promoting Skype, amongst other things, within their own portal.

Having been integrating feeds and services from other sites for years it’s strange to see businesses so conceptually and technically simple seeing significant funding. It has to be said that there are some great interface designs in some of these companies sites - Netvibes for example is probably the best of the crop. We have yet to see whether they have the marketing muscle to see it through.

Oh yes, I almost forgot, BT do great canapés.

1 comment September 25th, 2006 mike

Managing CSS: part 1, Factoring

In these days of semantic markup, liquid three column layouts and image replacement it’s quite evident that using CSS is just not as simple as it promises to be. There’s not only the flow and box models to internalise, but the numerous quirks in how browsers implement them, and the constraints imposed by accessibility guidelines, and—well, special cases galore. As usual the solution is care, attention, and better tools.

Grouping rules

To start, there is the matter of how to arrange CSS code: One reason why CSS can be trouble to maintain is that there’s no obvious best factoring of rules. Do you clump like properties together under a single selector

h1, h2, h3, div.title  {color: #f3c;}

on the basis that there’s then one place to change that property of these related elements; or, group like selectors

h1 { color: #f3c; font-size: largest; font-weight: bold; }

so that the entire style of a particular set of related elements can be changed at once?

There is at least one program that will automagically group rules for you, but it does it dumbly, collecting rules by common properties, and as it’s been pointed out, that’s not always what you want.

The real answer is that it depends on for what each property is intended. If a property is part of the overall theme, it should be in one place. Colours often fall into this category, as do fonts. If the property is a consequence of some extra semantics you’re asserting with your selector, it belongs with all the other such properties under one rule. For example, if I create a distinction between hyperlinks to elsewhere in my site and hyperlinks leading away from my site by using the class external, I would put all the properties related to external links in one rule.

These rules may have related selectors:

// Thematic property --- this colour is part of my colour scheme
h1, h2, h3, div.title {color: #0f0;}

// Semantic properties -- I'm asserting a set of things that are titles
*.title {
  margin-left: 32px;
  background-image: url('images/title-marker.gif');
  background-repeat: no-repeat;
}

(Note to CSS standards authors: some extra sugar for selectors would be helpful, like distributing combinators over parentheses; for example thead (th, td) as shorthand for thead th, thead td)

Cascade Simply, Stupid

The typical practice is to put hooks in the HTML upon which to hang styles. An id attribute can be used for unique (per page) elements, and the class attribute can be used to create arbitrary sets of elements. This coupling between the HTML and the CSS introduces a maintenance burden, since when the HTML changes the CSS must change, and vice versa.

There’s many ways to select a particular element, and there’s many ways of getting a style to apply to an element. A question Mark Bernstein poses is how do you make sure your style applies to precisely the right set of elements, now and forever?

We want to minimise three things: the knock-on effect of changing the CSS or the HTML, the possibility of unintended matches, and dependencies between rules. We can go a long way with both by keeping selectors simple and predictable.

Use either very general selectors with thematic properties (”set all body text to green”), or very specific selectors (”the element with this ID has a blue background”). This makes it easier to predict which elements will be affected by a rule, and reduces the chance that undesired properties will be inherited.

If you use relative units on elements that can be nested, you can end up with effects like shrinking text. This applies not only to single rules, but to combinations of rules:

span.info { font-size: 0.8em; }
// OK, since it won't be nested

fieldset#login { font-size: 0.9em; }
// but what if we put a span.info in that fieldset?

To avoid this situation, keep relative units away from generic containers. Let paragraphs default to whatever the body text size is, and adjust only for non-nesting elements.

Use selector connectors (descendant, child, sibling) very sparingly: they appear specific without being very predictable. Qualify sub-selectors with a class, or better an ID, to help avoid matching undesired elements.

Refactoring

Refactoring is the process of removing duplication and other bad smells from code. We can do the same for CSS.

What are the bad smells?

Sets of repeated properties in several rules often signal that there’s a common class to be extracted. You have to be careful though: it may be coincidence. A rule of thumb is that if you can consider the set of selected elements semantically alike, then you can replace the rules with a class. The semantic similarity means there’s a reasonable chance that the class, and the elements to which it it is attributed, aren’t going to change.

Class names or IDs that mention styles, for example .redBox, suggest that thematic properties are being mixed with semantic properties (or possibly that you were running short on imagination that day). Move the thematic properties into their own rule and think of a new name that reflects why you’re saying the elements with this class are different to other elements; e.g., .warning.

Long chains of combined selectors, for example body#about-page div.sidebar p a {...} may mean you’re trying too hard to narrow a selection — use a class or ID further down the chain to simplify the rule and make the selection clearer: p.about-page-links a {...}.

The hypothetical refactoring browser

What’s really needed is a refactoring browser. Not only would this browser let you view and edit CSS and HTML (and HTML-like code) side-by-side, it would understand how CSS applies to HTML, so you could

  • see which rules apply to an element
  • see which elements a selector matches
  • see how the effective properties of an element are derived (inherited properties, relative units)
  • see dependencies between rules (which rules will cascade)

It would also offer refactoring transformations:

  • move common properties into another rule
  • merge similar rules (and put the remainder into another rule)
  • move a class into or out of a nested element
  • collapse (redundantly) cascading rules

By definition, refactoring transformations should not alter the observable output of the code; however, you will also want to know when something you’ve done has failed to preserve that, so the refactoring browser should tell you.

Xylescope comes very close—it does a excellent job of showing you both which rules apply to an element and to which elements a rule applies, and has some handy visualisations of CSS properties (especially the box model). Sadly it doesn’t have a stellar editing facility, or any refactoring, but we can hope that culturedcode are planning to extend it.

Care and attention

While tools go an awfully long way, the most important thing is to give CSS your care and attention. Don’t let it get out of hand, by constantly refactoring; update the CSS when you update the HTML to remove unneeded rules; and confirm that each new rule does what you think it does. This last activity is the essence of testing, which I’ll talk about next time.

Add comment September 13th, 2006 mikeb

Coming to an Interweb near you

Schmoogle, the search engine for finding industry events.

Really, this is imminent, if not already extant …

1 comment September 1st, 2006 mikeb

Small and healthily skeptical is good

Tim Malbon says he’s pleased to be involved in this Web thing, but appears to conflate lack of full assimilation with brain-washing.

One can be a tiny bundle of techno-lust and not believe that successive versions of the Web will lead directly to a shiny new future.

Posting photos to Flickr (Web2.0) seems like something of a tenuous, circuitious route to finding housing for homeless children (shiny future). On the other hand, if you followed that link you’re contributing to something like a counter-argument.

It’s not that I begrudge boosterism, because some interesting things come about that way. I just find the juxtaposition of They see [the Web] as ‘work’ rather than the defining social revolution du jour with They have the air of people who belong to a mind control cult as, well, exquisite.

Having said all that: I quite agree with Tim’s sentiments that Small is Good, creating neat technology isn’t work, and I’d rather be passionate about what I do than uninterested (happily, I am the former).

3 comments August 25th, 2006 mikeb

Previous Posts