Category: JavaScript

Easy template injection in JavaScript for userscript authors, plugin devs, and other people who want to fuck with Web page content

The Predator Alert Tool for Twitter is coming along nicely, but it's frustratingly slow going. It's extra frustrating for me because ever since telling corporate America and its project managers to go kill themselves, I've grown accustomed to an utterly absurd speed of project development. I know I've only been writing and rewriting code for just under two weeks (I think—I honestly don't even know or care what day it is), but still.

I think it also feels extra slow is because I'm learning a lot of new stuff along the way. That in and of itself is great, but I'm notoriously impatient. Which I totally consider a virtue because fuck waiting. Still, all this relearning and slow going has given me the opportunity to refine a few techniques I used in previous Predator Alert Tool scripts.

Here's one technique I think is especially nifty: template injection.

Read more

Cross-post: Edenfantasys’s unethical technology is a self-referential black hole

This entry was originally published at my other blog. I’m cross-posting it here in order to make sure it gets copied to more servers, as some people have suggested I’ll face a cease and desist order for publishing it in the first place. Please help distribute this important information by freely copying and republishing this post under the conditions of my CC-BY-NC-ND license: provide me with attribution and a (real) back link, and you are free to republish an unaltered version of this post wherever you like. Thanks.

A few nights ago, I received an email from Editor of EdenFantasys’s SexIs Magazine, Judy Cole, asking me to modify this Kink On Tap brief I published that cites Lorna D. Keach’s writing. Judy asked me to “provide attribution and a link back to” SexIs Magazine. An ordinary enough request soon proved extraordinarily unethical when I discovered that EdenFantasys has invested a staggering amount of time and money to develop and implement a technology platform that actively denies others the courtesy of link reciprocity, a courtesy on which the ethical Internet is based.

While what they’re doing may not be illegal, EdenFantasys has proven itself to me to be an unethical and unworthy partner, in business or otherwise. Its actions are blatantly hypocritical, as I intend to show in detail in this post. Taking willful and self-serving advantage of those not technically savvy is a form of inexcusable oppression, and none of us should tolerate it from companies who purport to be well-intentioned resources for a community of sex-positive individuals.

For busy or non-technical readers, see the next section, Executive Summary, to quickly understand what EdenFantasys is doing, why it’s unethical, and how it affects you whether you’re a customer, a contributor, or a syndication partner. For the technical reader, the Technical Details section should provide ample evidence in the form of a walkthrough and sample code describing the unethical Search Engine Optimization (SEO) and Search Engine Marketing (SEM) techniques EdenFantasys, aka. Web Merchants, Inc., is engaged in. For anyone who wants to read further, I provide an Editorial section in which I share some thoughts about what you can do to help combat these practices and bring transparency and trust—not the sabotage of trust EdenFantasys enacts—to the market.

EXECUTIVE SUMMARY

Internet sex toy retailer Web Merchants, Inc., which bills itself as the “sex shop you can trust” and does business under the name EdenFantasys, has implemented technology on their websites that actively interferes with contributors’ content, intercepts outgoing links, and alters republished content so that links in the original work are redirected to themselves. Using techniques widely acknowledged as unethical by Internet professionals and that are arguably in violation of major search engines’ policies, EdenFantasys’s publishing platform has effectively outsourced the task of “link farming” (a questionable Search Engine Marketing [SEM] technique) to sites with which they have “an ongoing relationship,” such as AlterNet.org, other large news hubs, and individual bloggers’ blogs.

Articles published on EdenFantasys websites, such as the “community” website SexIs Magazine, contain HTML crafted to look like links, but aren’t. When visited by a typical human user, a program written in JavaScript and included as part of the web pages is automatically downloaded and intercepts clicks on these “link-like” elements, fetching their intended destination from the server and redirecting users there. Due to the careful and deliberate implementation, the browser’s status bar is made to appear as though the link is legitimate, and that a destination is provided as expected.

For non-human visitors, including automated search engine indexing programs such as Googlebot, the “link” remains non-functional, making the article a search engine’s dead-end or “orphan” page whose only functional links are those whose destination is EdenFantasys’s own web presence. This makes EdenFantasys’ website(s) a self-referential black hole that provides no reciprocity for contributors who author content, nor for any website ostensibly “linked” to from article content. At the same time, EdenFantasys editors actively solicit inbound links from individuals and organizations through “link exchanges” and incentive programs such as “awards” and “free” sex toys, as well as syndicating SexIs Magazine content such that the content is programmatically altered in order to create multiple (real) inbound links to EdenFantasys’s websites after republication on their partner’s media channels.

How EdenFantasys’s unethical practices have an impact on you

Regardless of who you are, EdenFantasys’s unethical practices have a negative impact on you and, indeed, on the Internet as a whole.

See for yourself: First, log out of any and all EdenFantasys websites or, preferably, use a different browser, or even a proxy service such as the Tor network for greater anonymity. Due to EdenFantasys’s technology, you cannot trust that what you are seeing on your screen is what someone else will see on theirs. Next, temporarily disable JavaScript (read instructions for your browser) and then try clicking on the links in SexIs Magazine articles. If clicking the intended off-site “links” doesn’t work, you know that your article’s links are being hidden from Google and that your content is being used for shady practices. In contrast, with JavaScript still disabled, navigate to another website (such as this blog), try clicking on the links, and note that the links still work as intended.

Here’s another verifiable example from the EdenFantasys site showing that many other parts of Web Merchants, Inc. pages, not merely SexIs Magazine, are affected as well: With JavaScript disabled, visit the EdenFantasys company page on Aslan Leather (note, for the sake of comparison, the link in this sentence will work, even with JavaScript off). Try clicking on the link in the “Contact Information” section in the lower-right hand column of the page (shown in the screenshot, below). This “link” should take you to the Aslan Leather homepage but in fact it does not. So much for that “link exchange.”

(Click to enlarge.)

  • If you’re an EdenFantasys employee, people will demand answers from you regarding the unethical practices of your (hopefully former) employer. While you are working for EdenFantasys, you’re seriously soiling your reputation in the eyes of ethical Internet professionals. Ignorance is no excuse for the lack of ethics on the programmers’ part, and it’s a shoddy one for everyone else; you should be aware of your company’s business practices because you represent them and they, in turn, represent you.
  • If you’re a partner or contributor (reviewer, affiliate, blogger), while you’re providing EdenFantasys with inbound links or writing articles for them and thereby propping them up higher in search results, EdenFantasys is not returning the favor to you (when they are supposed to be doing so). Moreover, they’re attaching your handle, pseudonym, or real name directly to all of their link farming (i.e., spamming) efforts. They look like they’re linking to you and they look like their content is syndicated fairly, but they’re actually playing dirty. They’re going the extra mile to ensure search engines like Google do not recognize the links in articles you write. They’re trying remarkably hard to make certain that all roads lead to EdenFantasys, but none lead outside of it; no matter what the “link,” search engines see it as stemming from and leading to EdenFantasys. The technically savvy executives of Web Merchants, Inc. are using you without giving you a fair return on your efforts. Moreover, EdenFantasys is doing this in a way that preys upon people’s lack of technical knowledge—potentially your own as well as your readership’s. Do you want to keep doing business with people like that?
  • If you’re a customer, you’re monetarily supporting a company that essentially amounts to a glorified yet subtle spammer. If you hate spam, you should hate the unethical practices that lead to spam’s perpetual reappearance, including the practices of companies like Web Merchants, Inc. EdenFantasys’s unethical practices may not be illegal, but they are unabashedly a hair’s width away from it, just like many spammers’. If you want to keep companies honest and transparent, if you really want a “sex shop you can trust,” this is relevant to you because EdenFantasys is not it. If you want to purchase from a retailer that truly strives to offer a welcoming, trustworthy community for those interested in sex positivity and sexuality, pay close attention and take action. For ideas about what you can do, please see the “What you can do” section, below.
  • If you’ve never heard about EdenFantasys before, but you care about a fair and equal-opportunity Internet, this is relevant to you because what EdenFantasys is doing takes advantage of non-tech-savvy people in order to slant the odds of winning the search engine game in their favor. They could have done this fairly, and I personally believe that they would have succeeded. Their sites are user-friendly, well-designed, and solidly implemented. However, they chose to behave maliciously by not providing credit where credit is due, failing to follow through on agreements with their own community members and contributors, and sneakily utilizing other publishers’ web presences to play a very sad zero-sum game that they need not have entered in the first place. In the Internet I want, nobody takes malicious advantage of those less skilled than they are because their own skill should speak for itself. Isn’t that the Internet and, indeed, the future you want, too?

TECHNICAL DETAILS

What follows is a technical exploration of the way the EdenFantasys technology works. It is my best-effort evaluation of the process in as much detail as I can manage within strict self-imposed time constraints. If any of this information is incorrect, I’d welcome any and all clarifications provided by the EdenFantasys CTO and technical team in an appropriately transparent, public, and ethical manner. (You’re welcome—nay, encouraged—to leave a comment.)

Although I’m unconvinced that EdenFantasys understands this, it is the case that honesty is the best policy—especially on the Internet, where everyone has the power of “View source.”

The “EF Framework” for obfuscating links

Article content written by contributors on SexIs Magazine pages is published after all links are replaced with a <span> element bearing the class of linklike and a unique id attribute value. This apparently happens across any and all content published by Web Merchants, Inc.’s content management system, but I’ll be focusing on Lorna D. Keach’s post entitled SexFeed:Anti-Porn Activists Now Targeting Female Porn Addicts for the sake of example.

These fake links look like this in HTML:

And according to Theresa Flynt, vice president of marketing for Hustler video, <span class="linklike" ID="EFLink_68034_fe64d2">female consumers make up 56% of video sales.</span>

This originally published HTML is what visitors without JavaScript enabled (and what search engine indexers) see when they access the page. Note that the <span> is not a real link, even though it is made to look like one. (See Figure 1; click it to enlarge.)

Figure 1:

In a typical user’s browser, when this page is loaded, a JavaScript program is executed that mutates these “linklike” elements into <a> elements, retaining the “linklike” class and the unique id attribute values. However, no value is provided in the href (link destination) attribute of the <a> element. See Figure 2.

Figure 2:

The JavaScript program is downloaded in two parts from the endpoint at http://cdn3.edenfantasys.com/Scripts/Handler/jsget.ashx. The first part, retrieved in this example by accessing the URI at http://cdn3.edenfantasys.com/Scripts/Handler/jsget.ashx?i=jq132_cnf_jdm12_cks_cm_ujsn_udm_stt_err_jsdm_stul_ael_lls_ganl_jqac_jtv_smg_assf_agrsh&v_14927484.12.0, loads the popular jQuery JavaScript framework as well as custom code called the “EF Framework”.

The EF Framework contains code called the DBLinkHandler, an object that parses the <span> “linklike” elements (called “pseudolinks” in the EF Framework code) and retrieves the real destination. The entirety of the DBLinkHandler object is shown in code listing 1, below. Note the code contains a function called handle that performs the mutation of the <span> “linklike” elements (seen primarily on lines 8 through 16) and, based on the prefix of each elements’ id attribute value, two key functions (BuildUrlForElement and GetUrlByUrlID, whose signatures are on lines 48 and 68, respectively) interact to set up the browser navigation after responding to clicks on the fake links.

var DBLinkHandler = {
    pseudoLinkPrefix: "EFLink_",
    generatedAHrefPrefix: "ArtLink_",
    targetBlankClass: "target_blank",
    jsLinksCssLinkLikeClass: "linklike",
    handle: function () {
        var pseudolinksSpans = $("span[id^='" + DBLinkHandler.pseudoLinkPrefix + "']");
        pseudolinksSpans.each(function () {
            var psLink = $(this);
            var cssClass = $.trim(psLink.attr("class"));
            var target = "";
            var id = psLink.attr("id").replace(DBLinkHandler.pseudoLinkPrefix, DBLinkHandler.generatedAHrefPrefix);
            var href = $("<a></a>").attr({
                id: id,
                href: ""
            }).html(psLink.html());
            if (psLink.hasClass(DBLinkHandler.targetBlankClass)) {
                href.attr({
                    target: "_blank"
                });
                cssClass = $.trim(cssClass.replace(DBLinkHandler.targetBlankClass, ""))
            }
            if (cssClass != "") {
                href.attr({
                    "class": cssClass
                })
            }
            psLink.before(href).remove()
        });
        var pseudolinksAHrefs = $("a[id^='" + DBLinkHandler.generatedAHrefPrefix + "']");
        pseudolinksAHrefs.live("mouseup", function (event) {
            DBLinkHandler.ArtLinkClick(this)
        });
        pseudolinksSpans = $("span[id^='" + DBLinkHandler.pseudoLinkPrefix + "']");
        pseudolinksSpans.live("click", function (event) {
            if (event.button != 0) {
                return
            }
            var psLink = $(this);
            var url = DBLinkHandler.BuildUrlForElement(psLink, DBLinkHandler.pseudoLinkPrefix);
            if (!psLink.hasClass(DBLinkHandler.targetBlankClass)) {
                RedirectTo(url)
            } else {
                OpenNewWindow(url)
            }
        })
    },
    BuildUrlForElement: function (psLink, prefix) {
        var psLink = $(psLink);
        var sufix = psLink.attr("id").toString().substring(prefix.length);
        var id = (sufix.indexOf("_") != -1) ? sufix.substring(0, sufix.indexOf("_")) : sufix;
        var url = DBLinkHandler.GetUrlByUrlID(id);
        if (url == "") {
            url = EF.Constants.Links.Url
        }
        var end = sufix.substring(sufix.indexOf("_") + 1);
        var anchor = "";
        if (end.indexOf("_") != -1) {
            anchor = "#" + end.substring(0, end.lastIndexOf("_"))
        }
        url += anchor;
        return url
    },
    ArtLinkClick: function (psLink) {
        var url = DBLinkHandler.BuildUrlForElement(psLink, DBLinkHandler.generatedAHrefPrefix);
        $(psLink).attr("href", url)
    },
    GetUrlByUrlID: function (UrlID) {
        var url = "";
        UrlRequest = $.ajax({
            type: "POST",
            url: "/LinkLanguage/AjaxLinkHandling.aspx",
            dataType: "json",
            async: false,
            data: {
                urlid: UrlID
            },
            cache: false,
            success: function (data) {
                if (data.status == "Success") {
                    url = data.url;
                    return url
                }
            },
            error: function (xhtmlObj, status, error) {}
        });
        return url
    }
};

Once the mutation is performed and all the content “links” are in the state shown in Figure 2, above, an event listener has been bound to the anchors that captures a click event. This is done using prototypal extension, aka. classic prototypal inheritance, in another part of the code, the live function on line 2,280 of the (de-minimized) jsget.ashx program, as shown in code listing 2, here:

        live: function (G, F) {
            var E = o.event.proxy(F);
            E.guid += this.selector + G;
            o(document).bind(i(G, this.selector), this.selector, E);
            return this
        },

At this point, clicking on one of the “pseudolinks” triggers the EF Framework to call code set up by the GetUrlByUrlID function from within the DBLinkHandler object, initiating an XMLHttpRequest (XHR) connection to the AjaxLinkHandling.aspx server-side application. The request is an HTTP POST containing only one parameter, called urlid, and its value matches a substring from within the id value of the “pseudolinks.” In this example, the id attribute contains a value of EFLink_68034_fe64d2, which means that the unique ID POST’ed to the server is 68034. This is shown in Figure 3, below.

Figure 3:

The response from the server, shown in Figure 4, is also simple. If successful, the intended destination is retrieved by the GetUrlByUrlID object’s success function (on line 79 of Code Listing 1, above) and the user is redirected to that web address, as if the link was a real one all along. The real destination, in this case to CNN.com, is thereby only revealed after the XHR request returns a successful reply.

Figure 4:

All of this obfuscation effectively blinds machines such as the Googlebot who are not JavaScript-capable from seeing and following these links. It deliberately provides no increased Pagerank for the link destination (as a real link would normally do) despite being “linked to” from EdenFantasys’s SexIs Magazine article. While the intended destination in this example link was at CNN.com, it could just as easily have been—and is, in other examples—links to the blogs of EdenFantasys community members and, indeed, everyone else linked to from a SexIs Magazine article or potentially any website operated by Web Merchants, Inc. that makes use of this technology.

The EdenFantasys Outsourced Link-Farm

In addition to creating a self-referential black hole with no gracefully degrading outgoing links, EdenFantasys also actively performs link-stuffing through its syndicated content “relationships,” underhandedly creating an outsourced and distributed link-farm, just like a spammer. The difference is that this spammer (Web Merchants, Inc. aka EdenFantasys) is cleverly crowd-sourcing high-value, high-quality content from its own “community.”

Articles published at SexIs Magazine are syndicated in full to other large hub sites, such as AlterNet.org. Continuing with the above example post by Lorna D. Keach, Anti-Porn Activists Now Targeting Female Porn Addicts, we can see that this content was republished on AlterNet.org shortly after original publication through EdenFantasys’ website on May 3rd at http://www.alternet.org/story/146774/christian_anti-porn_activists_now_targeting_female_. However, a closer look at the HTML code of the republication shows that each and every link contained within the article points to the same destination: the same article published on SexIs Magazine, as shown in Figure 5.

Figure 5:

Naturally, these syndicated links provided to third-party sites by EdenFantasys are real and function as expected to both human visitors and to search engines indexing the content. The result is “natural,” high-value links to the EdenFantasys website from these third-party sites; EdenFantasys doesn’t merely scrounge pagerank from harvesting the sheer number of incoming links, but as each link’s anchor text is different, they are setting themselves up to match more keywords in search engine results, keywords that the original author likely did not intend to direct to them. Offering search engines the implication that EdenFantasys.com contains the content described in the anchor text, when in fact EdenFantasys merely acts as an intermediary to the information, is very shady, to say the least.

In addition to syndication, EdenFantasys employs human editors to do community outreach. These editors follow up with publishers, including individual bloggers (such as myself), and request that any references to published material provide attribution and a link back to us, to use the words of Judy Cole, Editor of SexIs Magazine in an email she sent to me (see below), and presumably many others. EdenFantasys has also been known to request “link exchanges,” and offer incentive programs that encouraged bloggers to add the EdenFantasys website to their blogroll or sidebar in order to help raise both parties search engine ranking, when in fact EdenFantasys is not actually providing reciprocity.

More information about EdenFantasys’s unethical practices, which are not limited to technical subterfuge, can be obtained via AAGBlog.com.

EDITORIAL

It is unsurprising that the distributed, subtle, and carefully crafted way EdenFantasys has managed to crowd-source links has (presumably) remained unpenalized by search engines like Google. It is similarly unsurprising that nontechnical users such as the contributors to SexIs Magazine would be unaware of these deceptive practices, or that they are complicit in promoting them.

This is no mistake on the part of EdenFantasys, nor is it a one-off occurrence. The amount of work necessary to implement the elaborate system I’ve described is also not even remotely feasible for a rogue programmer to accomplish, far less accomplish covertly. No, this is the result of a calculated and decidedly underhanded strategy that originated from the direction of top executives at Web Merchants, Inc. aka EdenFantasys.

It is unfortunate that technically privileged people would be so willing to take advantage of the technically uneducated, particularly under the guise of providing a trusted place for the community which they claim to serve. These practices are exactly the ones that “the sex shop you can trust” should in no way support, far less be actively engaged in. And yet, here is unmistakable evidence that EdenFantasys is doing literally everything it can not only to bolster its own web presence at the cost of others’, but to hide this fact from its understandably non-tech-savvy contributors.

On a personal note, I am angered that I would be contacted by the Editor of SexIs Magazine, and asked to properly “attribute” and provide a link to them when it is precisely that reciprocity which SexIs Magazine would clearly deny me (and everyone else) in return. It was this request originally received over email from Judy Cole, that sparked my investigation outlined above and enabled me to uncover this hypocrisy. The email I received from Judy Cole is republished, in full, here:

From: Judy Cole <luxuryholmes@gmail.com>
Subject: Repost mis-attributed
Date: May 17, 2010 2:42:00 PM PDT
To: kinkontap+viewermail@gmail.com
Cc: Laurel <laurelb@edenfantasys.com>

Hello Emma and maymay,

I am the Editor of the online adult magazine SexIs (http://www.edenfantasys.com/sexis/). You recently picked up and re-posted a story of ours by Lorna Keach that Alternet had already picked up:

http://kinkontap.com/?s=alternet

We were hoping that you might provide attribution and a link back to us, citing us as the original source (as is done on Alternet, with whom we have an ongoing relationship), should you pick up something of ours to re-post in the future.

If you would be interested in having us send you updates on stories that might be of interest, I would be happy to arrange for a member of our editorial staff to do so. (Like your site, by the way. TBK is one of our regular contributors.)

Thanks and Best Regards,

Judy Cole
Editor, SexIs

Judy’s email probably intended to reference the new Kink On Tap briefs that my co-host Emma and I publish, not a search result page on the Kink On Tap website. Specifically, she was talking about this brief: http://KinkOnTap.com/?p=676. I said as much in my reply to Judy:

Hi Judy,

The URL in your email doesn’t actually link to a post. We pick up many stories from AlterNet, as well as a number from SexIs, because we follow both those sources, among others. So, did you mean this following entry?

http://KinkOnTap.com/?p=676

If so, you should know that we write briefs as we find them and provide links to where we found them. We purposefully do not republish or re-post significant portions of stories and we limit our briefs to short summaries in deference to the source. In regards to the brief in question, we do provide attribution to Lorna Keach, and our publication process provides links automatically to, again, the source where we found the article. :) As I’m sure you understand, this is the nature of the Internet. Its distribution capability is remarkable, isn’t it?

Also, while we’d absolutely be thrilled to have you send us updates on stories that might be of interest, we would prefer that you do so in the same way the rest of our community does: by contributing to the community links feed. You can find detailed instructions for the many ways you can do that on our wiki:

http://wiki.kinkontap.com/wiki/Community_links_feed

Congratulations on the continued success of SexIs.

Cheers,
-maymay

At the time when I wrote the email replying to Judy, I was perturbed but could not put my finger on why. Her email upset me because she seemed to be suggesting that our briefs are wholesale “re-posts,” when in fact Emma and I have thoroughly discussed attribution policies and, as mentioned in my reply, settled on a number of practices including a length limit, automated back linking (yes, with real links, go see some Kink On Tap briefs for yourself), and clearly demarcating quotes from the source article in our editorializing to ensure we play fair. Clearly, my somewhat snarky reply betrays my annoyance.

In any event, this exchange prompted me to take a closer look at the Kink On Tap brief I wrote, at the original article, and at the cross-post on AlterNet.org. I never would have imagined that EdenFantasys’s technical subterfuge would be as pervasive as it has proven to be. It’s so deeply embedded in the EdenFantasys publishing platform that I’m willing to give Judy the benefit of the doubt regarding this hypocrisy because she doesn’t seem to understand the difference between a search query and a permalink (something any laymen blogger would grok). This is apparent from her reply to my response:

From: Judy Cole <luxuryholmes@gmail.com>
Subject: Re: Repost mis-attributed
Date: May 18, 2010 4:57:59 AM PDT
[…redundant email headers clipped…]

Funny, the URL in my email opens the same link as the one you sent me when I click on it.

Maybe if you pick up one of our stories in future, you could just say something like “so and so wrote for SexIs.” ?

As it stands, it looks as if Lorna wrote the piece for Alternet. Thanks.

Judy

That is the end of our email exchange, and will be for good, unless and until EdenFantasys changes its ways. I will from this point forward endeavor never to publish links to any web property that I know to be owned by Web Merchants, Inc., including EdenFantasys.com. I will also do my best to avoid citing any and all SexIs Magazine articles from here on out, and I encourage everyone who has an interest in seeing honesty on the Internet to follow my lead here.

As some of my friends are currently contributors to SexIs Magazine, I would like all of you to know that I sincerely hope you immediately sever all ties with any and all Web Merchants, Inc. properties, suppliers, and business partners, especially because you are friends and I think your work is too important to be sullied by such a disreputable company. Similarly, I hope you encourage your friends to do the same. I understand that the economy is rough and that some of you may have business contracts bearing legal penalties for breaking them, but I urge you to nevertheless consider looking at this as a cost-benefit analysis: the sooner you break up with EdenFantasys, the happier everyone on the Internet, including you, will be (and besides, you can loose just as much of your reputation, money, and pagerank while being happy as you can being sad).

What you can do

  • If you are an EdenFantasys reviewer, a SexIs Magazine contributor, or have any other arrangement with Web Merchants, Inc., write to Judy Cole and demand that content you produce for SexIs Magazine adheres to ethical Internet publication standards. Sever business ties with this company immediately upon receipt of any non-response, or any response that does not adequately address every concern raised in this blog post. (Feel free to leave comments on this post with technical questions, and I’ll do my best to help you sort out any l33t answers.)
  • EdenFantasys wants to stack the deck in Google. They do this by misusing your content and harvesting your links. To combat this effort, immediately remove any and all links to EdenFantasys websites and web presences from your websites. Furthermore, do not—I repeat—do not publish new links to EdenFantasys websites, not even in direct reference to this post. Instead, provide enough information, as I have done, so visitors to your blog posts can find their website themselves. In lieu of links to EdenFantasys, link to other bloggers’ posts about this issue. (Such posts will probably be mentioned in the comments section of this post.)
  • Boycott EdenFantasys: the technical prowess their website displays does provide a useful shopping experience for some people. However, that in no way obligates you to purchase from their website. If you enjoy using their interface, use it to get information about products you’re interested in, but then go buy those products elsewhere, perhaps from the manufacturers directly.
  • Watch for “improved” technical subterfuge from Web Merchants, Inc. As a professional web developer, I can identify several things EdenFantasys could do to make their unethical practices even harder to spot, and harder to stop. If you have any technical knowledge at all, even if you’re “just” a savvy blogger, you can keep a close watch on EdenFantasys and, if you notice anything that doesn’t sit well with you, speak up about it like I did. Get a professional programmer to look into things for you if you need help; yes, you can make a difference just by remaining vigilant as long as you share what you know and act honestly, and transparently.

If you have additional ideas or recommendations regarding how more people can help keep sex toy retailers honest, please suggest them in the comments.

Update: To report website spamming or any kind of fraud to Google, use the authenticated Spam Report tool.

Update: Google provides much more information about why the kinds of practices EdenFantasys is engaged in degrade the overall web experience for you and me. Read Cloaking, sneaky Javascript redirects, and doorway pages at the Google Webmaster Tools help site for additional SEO information. Using Google’s terminology, EdenFantasys’s unethical technology is a very skilled mix of social engineering and “sneaky JavaScript redirects.”

Why CSS needs delegation capabilities and not “variables”

It’s been too long since I joined the fun, if amazingly heated, debates over the direction that Web standards are moving in. Recently, given the “free” time to do so, I decided to dive head first into what is (sadly) an almost 14 year old debate. The result is this blog post, which is mostly a response to Bert Bos’s essay Why “variables” in CSS are harmful and Matt Wilcox’s opposing response to that essay, Why CSS needs to borrow from programming languages. Their articles are each worthy of a read, possibly before this one.

Here’s the summary of my argument.

Adding many “programmatic” features to the CSS language such as variables, macros, or flow control is a mistake. However, CSS’s failure to simply encode visual relationships (instead of merely typographic properties)—a severe deficiency in the core language itself—requires the addition of delegation features. With the additional capability to reference an arbitrary element’s computed value regardless of its hierarchical context, CSS will be more accessible to both amateur and professional web designers, more capable, and will more forcefully promote the semantic Web and its ideals.

In this corner: CSS variables are harmful

Bert does a great job of summarizing the conclusion of his argument himself. In his essay, Bert says:

Adding any form of macros or additional scopes and indirections, including symbolic constants, is not just redundant, but changes CSS in ways that make it unsuitable for its intended audience. Given that there is currently no alternative to CSS, these things must not be added.

As we all know, one of the wonderful things about CSS is that the core language itself is remarkably simple. (What’s not simple is the spectacular way browser manufacturers have destroyed everyone’s hope that implementing CSS-based designs in the real world will ever be easy, but that’s a whole different can of worms.) Fundamentally, CSS’s syntax can be explained with a mere three major components: property/value pairs, declaration blocks, and rule sets.

What this means is that CSS as a language is stupidly easy to learn. I think everyone would agree that it’s certainly easier to learn than, say, JavaScript or XSL. Now, that’s important because, without putting too fine a point on it, Bert mentions multiple times that CSS’s “intended audience” are the diverse and likely relatively technically ignorant content authors that are responsible for the overwhelming majority of web pages on the public Internet today.

He makes the very good point that The value of the semantic Web isn’t defined by how well structured the best documents are, but by how well structured the vast majority of documents are. In other words, CSS needs to remain instantly useable and reusable to these untrained, amateur web content publishers for the benefits of self-describing documents (i.e., the semantic Web) to see mass adoption.

To wit:

reusing other people’s style sheets is more difficult if those style sheets contain user-defined names. Class names are an example. Their names may suggest why the author created them (assuming they are in a language you understand), but typically you will have to look at the document to see where they occur and why. Symbolic constants make that problem worse.

And, later:

For many people, style sheets with constants will thus simply not be usable. It is too difficult to look in two places at once, the place where a value is used and the place where it is defined, if you don’t know why the rule is split in this way. Many people are confused by indirection anyway and adding an extra one, in addition to the element and class names, has the same effect as obfuscating the style sheet.

Whether or not you believe Bert Bos is underestimating the average web designer, it’s pretty clear that these are really good points. Nobody wants CSS to be obfuscated, hard to learn, or hard to reuse. That’d just be crazy talk.

In the other corner: CSS variables are a real-world requirement

The more features you add to an application, a programming language, or indeed any software, the more difficult it becomes to grok it. As the Python people would say, the larger a language gets the more difficult it is to hold all of it in your head. Nevertheless, adding “features” is sometimes the only way to add capabilities, and I don’t think anyone in their right mind would argue that, once written, software should never change. (That’d just be crazy talk, too.)

In his opposing arguments, Matt Wilcox recognizes this when he says, Yes, the syntax should be simple, but the capabilities of CSS should not. What he’s alluding to without verbalizing it is the balance between adding necessary capabilities without unnecessarily growing the “size of the language.”

However, Matt says that modern web design methodologies (e.g., separation of concerns between structure, presentation, and behavior) dictate that CSS needs more capabilities than it currently has:

CSS lacks capabilities to allow truly flexible design, requiring layer upon layer of ‘tricks’ to accomplish certain objectives, requiring content to be structured ‘just so’ to achieve a display objective, or in the case of some designs proving instead to be completely incapable.

[…]

CSS’s positioning is a cludge. It’s a cludge because you can only position relative to the last positioned parent container. Well, that limitation in itself dictates that all positioning relies upon how the content is structured. And that means the presentation and the content are not truly separable.

To align CSS’s capabilities with the requirements of real-world web design objectives, he says, CSS needs to be capable of describing relationships between semantically and structurally arbitrary but visually related elements.

Visual design is fundamentally about relationships between elements. For all of the artistic flourishes and creativity, it’s about relationships. ‘That yellow’ only grabs your attention because of its contrasting relationship with ‘that blue’. ‘This heading’ only works as a heading because of it’s exaggerated relationship to the size of the body text. […] CSS has no clue about relationships, period. And that’s why CSS as it stands right now, is not good enough. That’s why CSS without variables (true variables), without basic logic, without maths, can never be as flexible as we need it to be.

This is what web designers have been complaining about for (what feels like hundreds of) years. The fact that CSS has no capability to describe presentational relationships between elements in addition to directly describing an individual element’s presentational properties is a gaping hole that sorely degrades its ability to be a media-agnostic styling language. Every single web designer I’ve worked with has gasped at this omission, and though at first I didn’t understand why, the more I understood the principles behind graphic design the more I came to realize how fundamentally problematic this omission really is.

Adding delegation makes CSS easier for designers

As Matt eloquently stated, design is all about relationships. Good web designers create designs by constructing visual elements that have strong, often exacting relationships with other visual elements. There are many names and examples for this: visual language, visual hierarchy, the golden ratio, the grid, visual balance, the typographer’s scale, and so on.

What happens when the designer tries to define a relationship between elements? “How do I say that the whitespace between element A and element B should always be the same? How do I define element A’s height as half of element B’s?” These definitions, which are natural and necessary to the way designers work in both their mind and their mediums, are impossible to encode in CSS.

The closest you can get is declaring the same values to each element’s properties, not describing the relationship itself. This suffices only so long as these values are known ahead of time and are the same as one another, which severely limits the design possibilities we are capable of (without resorting to what Matt calls “tricks”). That’s why achieving simple visual effects are actually very complex and so, sadly, that’s where you’ll find the majority of indirection and obfuscation in CSS today. (I’m looking at you, faux columns.)

So who wins?

Both Bert Bos and Matt Wilcox have made some great points. Bert rightfully wishes to keep CSS lean and simple, even at the expense of some arguably beneficial styling power. Matt, on the other hand, argues that our needs as web designers have evolved faster than the technology to the point where CSS is too limited, fundamentally so.

The truth is, they’re both right. And they’re both wrong. Or rather, they are each taking a position that is too extreme. Bert’s absolutely correct when says that many of these proposed extensions are redundant and harmful, and yet Matt’s also correct that CSS lacks some fundamental capabilities that designers expect to be present.

Bert says that the CSS capabilities everyone’s asking for can be implemented using techniques that don’t rely on CSS whatsoever. These techniques, he says, make things like true CSS variables “redundant.”

There are examples of CSS with constants to satisfy all styles of programming, e.g.: David Walsh (in PHP), Tedd Sperling (in PHP), Digital Web Magazine (in PHP), Eco Consulting (in SSI), and Christian Heilmann (SSI and PHP).

Quite simply, he’s correct in stating that programmatic features need not be added to CSS proper to achieve desired results, but he’s incorrect in his apparent thinking that designers will be able to use these other tools to leverage CSS. Take, for instance, the probably more familiar (though not linked above) notion of using JavaScript to manipulate CSS values.

var x = document.getElementById('SideBar'); // get #SideBar element
var y = document.getElementById('MainColumn'); // get #MainColumn
var z = document.defaultView.getComputedStyle(y, '').getPropertyValue('height'); // get computed height of #MainColumn
x.style.height = ( parseInt(z) / 2 ) + 'px'; // set #SideBar's height 1/2 of #MainColumn's

This is an example of programmatic code that uses variables and expressions. It sets the element with the ID of SideBar to half the pixel height of the element with the ID of MainColumn. It does this by obtaining the MainColumn‘s height (at the time this code runs) and saving it in a variable, then performs some trivial math to half the value and use the result as the pixel height of the SideBar.

Doing this is currently impossible with CSS alone, yet it’s something that clearly belongs with whatever other “presentational” code exists and not in “programmatic” scripts that would otherwise be charged with defining “functionality.” As Matt states, using JavaScript to “script” solutions to CSS’s shortcomings like this is not an acceptable answer.

CSS doesn’t have [basic logic or maths]. Nor is it the job of JavaScript to make up for this lack of abilities. JavaScript is about interaction behaviour, and what we are talking about here is pure display logic. Not interaction logic.

Moreover, the place designers expect to put code like this is, of course, into a CSS style sheet. The way designers expect to put code like this into CSS is by adding delegation features. Requiring designers to learn JavaScript (or any other programming language) to encode such design relationships is nothing short of ridiculous. In what world is that easier for untrained laymen to understand than CSS?

Adding delegation to CSS is worth the effort

One of Bert’s arguments against such additions to CSS is that implementations would become harder to create, and that we’ll (almost certainly) see more bugs.

extending CSS makes implementing more difficult and programs bigger, which leads to fewer implementations and more bugs. That has to be balanced against the usefulness of the extension.

Although I do agree with his statement that an extension’s usefulness has to be balanced against its potential costs, I think something so fundamental to design methodology as delegation greatly overcompensates for the cost of such implementation efforts. Moreover, if I understand Bert correctly and as he also discusses, the majority of implementations that would need to implement such delegation already have relatively complex internal structures to make the implementation effort somewhat easier:

There is no scoping [in proposals that only define global constants]. That means that an implementation needs a symbol table, but no stack. A stack would require a little bit more memory, but mostly it would make implementations more complex. (Although every programmer has, one hopes, learnt to program a symbol table with lexical scope during his training.) Constants in CSS are thus easier than, e.g., XML Namespaces, which are lexically scoped.

It is different for those CSS implementations that provide a CSS Object Model (an API for manipulating a style sheet in memory). Those implementations do need to keep track of scope in some way, because adding or removing a line of the style sheet can make a previously redundant definition become meaningful.

In order to use JavaScript to solve many of the shortcomings of CSS, as huge numbers of professional web developers do routinely, we use the very CSS Object Model whose prior implementation already exists for us to build upon.

CSS delegation doesn’t grow the size of the language

For the sake of argument, let’s simplify our requirement somewhat so that our somewhat contrived example of design intent is to create a relationship between the MainColumn and the SideBar elements such that they are of equal height. This is more informally known as “making columns.”

Here’s what a natural, hypothetical snippet of CSS would look like if the language supported delegation features such that it could encode visual relationships.

#SideBar { height: #MainColumn; }

This code theoretically says almost the exact same thing as the JavaScript shown earlier (save for the division, of course); it takes the computed value of the MainColumn element’s height property and applies that value to the SideBar element’s height property. In other words, “The SideBar’s (element B’s) height is always the same as the MainColumn’s (element A’s).” (Of course, this is a parse error in reality today.)

This extremely trivial example has some remarkably far-reaching implications, and yet there is really nothing radical about its syntax. Making this a reality significantly expands the capabilities of CSS without dramatically increasing the size of the language. This capability would not only beat the pants offCSS tables,” it also potentially obsoletes the arguably misguided efforts of the CSS3 Advanced Layout and Grid Positioning modules, too.

We’ve long since abandoned table layouts because they force us to use presentational markup. That’s still what “CSS tables” force us to do, too. In other words, with display: table, the SideBar needs to be a child of the MainColumn element or, maybe worse and more likely, a child of a semantically meaningless wrapper element.

CSS positioning was introduced with the promise of freeing us from source-order-dependent styling, without which there is no hope of efficiently abstracting presentation away from structure. Moreover, abstracting presentation away from structure is the single most important prerequisite needed to improve document reusability and strengthen the semantic Web. Absolute positioning works, but limitations elsewhere in CSS mean its use is problematic for many designs, so in practice it doesn’t gain widespread adoption.

Here’s a theoretical solution to a two-column and a footer layout using CSS delegation with this semantic HTML:

<body>
    <div id="MainColumn">I'm the main column.</div>
    <div id="SideBar">I'm the right-hand sidebar.</div>
    <div id="Legalese">No one will read me.</div>
</body>

The CSS would look extremely familiar, possibly like this:

#MainColumn { margin: 0 25% 1em 0; float: left; }
#SideBar { width: 25%; min-height: #MainColumn; }

Using the same HTML, the same solution using the CSS3 Advanced Layout module would look something more like this, although to be frank I’m not certain I fully understand this syntax even after staring at it for months:

body {
    display: "a  b"
             ".  ." /1em
             "c  c"
             75% 25%
}
#MainColumn { position: a; }
#SideBar { position: b; }
#Legalese { position: c; }

Not only does there seem to me to be far more indirection in this method than there would be using CSS delegation, there is also an enormous increase to the size of the CSS language: a new (ASCII-art?!) value to the display property whose syntax is clunky at best. A similar story can be said of the CSS3 Grid Positioning module, which does lots more than just add a new (already complex) gr CSS unit.

The upshot is that the Advanced Layout and the Grid Positioning modules are doing some of the right things in many of the wrong ways. Both those modules add unnecessary complexity to CSS without giving designers a natural way to say what they mean. They do more to introduce obfuscation and indirection than simple delegation would, and they aren’t as broadly capable. Both of them try to solve a specific problem instead of dealing with fundamental deficiencies in the toolset designer’s have to work with.

Designers want relationships via delegation, not variables

Adding delegation such as that I’ve just shown is a natural, necessary addition to CSS because it is how designers create visual components—such as grids—in their designs. Variables (and constants, and macros, etc.), which simply reuse and modify pre-defined statements aren’t what designers care about. Adding them will bloat CSS without adding useful functionality.

“Okay,” you may be saying to yourself, “but delegation is itself a kind of variable, isn’t it?” Technically yes, however adding delegation resolves the core deficiency in the CSS language that designers need to use every day. Yes, it’s technically a form of variable, but that’s not how designers think of it. To say that one element’s visual properties is like another makes a variable only by creating a logical and visually appropriate mapping from the first element’s property to the second independent of markup, thereby avoiding indirection in the form of a variable name or other unfamiliar symbol.

Delegation like this doesn’t require the addition of anything other than what already exists in CSS. Class names and ID values are identifiers whose indirection people already have to deal with. Using them for delegation (to reference another element’s style) doesn’t increase the cognitive load any more than using them to reference HTML elements does. Though untested, the cognitive load might actually be even less since the CSS delegation’s references could be in the same (style sheet) file.

Moreover, delegation will increase the likelihood of document reusability by enabling style sheets to be more self-describing, more self-referential, in a similar way as good markup is. It satisfies a very fundamental need that designers have to define graphical relationships between elements. At the same time, it does so in a way that is natural to both their way of thinking and beneficial to the separation of concerns principle on which the “web stack” (the trifecta of HTML, CSS, and JavaScript) is based.

How web designers can do their own HTML/CSS: Read Foundation Website Creation

Last month, 37signals published a short but sweet post about why web designers should do the HTML/CSS implementations for their own designs. The bottom line is, as we’ve all been saying for a long time now, that the Web is not the same kind of medium as other mediums like print. It is a fundamentally different kind of canvas than most web designers are used to using. As a result, if you as a web designer are not intimately familiar with it, you’re not going to do great work.

designing for the web is a lot less about making something dazzle and a lot more about making it work. The design decisions that matter pertain directly to the constraints of the materials. What form elements to use. What font sizes. What composition. What flow. Those decisions are poorly made at an arm’s length.

I’ve worked with many web designers in the past who only did abstractions and then handed over pictures to be chopped and implemented by “HTML monkeys”. It never really gelled well. The things that got strong attention were all the things that Photoshop did well. Imagery, curvy lines, and the frame. All the around stuff, never the it stuff.

In other words, to do great web design you have to design in the Web, not in some other medium for the Web. I mean, serious magazine firm employs designers who don’t understand how to work with page layout programs like InDesign. Why, then, do so many web design agencies employ designers who don’t know how to work with web technologies, or even how to use programs like Dreamweaver? It doesn’t really make any sense, and it’s no wonder that the resulting implementation is rarely top-notch work.

But if you’re a graphic designer who doesn’t know much about Web technologies, what are you to do? Well, as a first step, I think you should pick up my new book, Foundation Website Creation. It’s available from all good booksellers (and probably some crappy ones) as of today. The book is targeted towards all manner of web professionals, including graphic designers and website producers, who want to learn more about what it takes to actually implement a site.

If I do say so myself, the chapters on XHTML and CSS are exceptionally thorough. The book doesn’t try to turn you into an exceptional programmer. Instead, it will explain the foundational concepts you need to know to understand how XHTML and CSS actually work, and in so doing will enable you to use the tools you already know to solve problems and get things done.

I think this book will be an excellent starting point for lots of designers and other web professionals. However, it is not going to take you from zero to hero—no book can. That’s why I recommend that, after you read Foundation Website Creation and have a solid grasp of what the technology can do for you and how it actually does it, you next take a look at these excellent books:

  • DOM Scripting by Jeremy Keith — if you’re a designer that needs to add a behavioral layer with JavaScript and Ajax to your pages, you need to read this book next.
  • Mastering CSS with Dreamweaver CS3 – if you’re familiar with Dreamweaver and want to keep using it to create standards-based web sites, then I recommend you follow Foundation Website Creation with this book by Stephanie Sullivan and Greg Rewis to take your Dreamweaver skills to the next level.

As always, most of all, have fun. Because if you’re not having fun, you’re not going to make good web sites no matter what you know.

Note: As of this writing, the book listing on Amazon still publishes the wrong author list, which is very frustrating but out of my hands. At least the image of our book’s front cover lists the correct authors.

Ridiculously simple JavaScript version string to object parser

In any kind of development, you often have to deal with version strings. Typically, these version strings are just a dot-separated list of numbers that represent different versions of the software. I recently had a need to compare two version numbers against one another to determine which one was newer. This is useful if, say, you’re building an application that wants to check its current version against the “latest” available version.

In JavaScript, this is thankfully pretty trivial. My solution is to just parse the version strings with a simple function and return them as objects with appropriate properties whose values are integers. Once in this form, we can compare them with simple math.

function parseVersionString (str) {
    if (typeof(str) != 'string') { return false; }
    var x = str.split('.');
    // parse from string or default to 0 if can't parse
    var maj = parseInt(x[0]) || 0;
    var min = parseInt(x[1]) || 0;
    var pat = parseInt(x[2]) || 0;
    return {
        major: maj,
        minor: min,
        patch: pat
    }
}

Using this new object, we can now compare two versions really simply:

var running_version = parseVersionString('3.5.2');
var latest_version = parseVersionString('3.4.5');
if (running_version.major < latest_version.major) {
    // A major new update is available!
} else if (running_version.minor < latest_version.minor || running_version.patch < latest_version.patch) {
    // A new minor or patch update is available.
} else {
    // We are running the latest version! No need to update.
}

I’m getting a book published and it’s called Foundation Website Creation

For those who have been wondering what is keeping me so busy these days, the answer is that I’m working on the final stages of a book that is getting published as one of three co-authors. Not only am contributing three chapters (the technical chapters on (X)HTML and CSS, specifically), but I am also technically reviewing the entire book.

My co-authors on the book, called Foundation Web Standards Foundation Website Creation (you can pre-order now) and published by Friends of ED, an Apress company, are Jonathan Lane of Industry Interactive, Inc. and Joe Lewis, who blogs at Sanbeiji.com. I’m not going to say much more until after the book is released in late July.

For the eager, here’s the description of the book posted on the Friends of ED website:

Foundation Website Creation explores the process of constructing a web site from start to finish. There is more to the process than just knowing HTML! Designers and developers must follow a proper process to flush out goals and objectives and determine requirements both prior to, and during project development.

Large Web projects are rarely completed by a single person. Producers, project managers, designers, developers, writers, and editors all play critical parts in a project’s evolution. This book provides an overview of the entire process, and also shows project development from the perspective of these different roles. It introduces the key concepts and duties performed by every member of such a team, and gives you the skills necessary to tackle projects like a professional.

It’s quite exciting getting a book out, and it’s quite a bit more work than I’d have ever originally thought. That being said, it’s extremely rewarding. There’s a lot more work I need to do on it between now and the time it gets released to publishing, so, well…back to work I go.

Now you all know where I’ve been spending my time writing.

The 10 Geekiest Leopard Features I Will Probably Love

This is already horribly old news, and by old I mean several days ago since that’s about as fast as it takes technology news to grow old, but Apple is releasing Mac OS X 10.5 “Leopard” at the end of this month. Apple is calling this release a “major upgrade,” and indeed Apple has rarely made its users wait so long between operating system releases as they have done between Tiger (Mac OS X 10.4) and Leopard. So, I’m already excited.

But then today I was glossing over Apple’s featured features list and I got even more excited. There are the usual, largely meaningless, fluff updates that are nice for Joe Schmo or his mother, but that power users simply don’t care about, like the new iChat support for animated buddy icons, but the list is also chock-full of really cool, really useful features.

What’s interesting is that a good deal of these features aren’t really new features at all. For instance, if you knew how to manipulate the NetInfo database on your Mac, you could already share any folder via Apple’s “Personal File Sharing” feature. (Here’s a Mac OS X Hints hint explaining how to do it.) In Leopard, however, Apple claims that this functionality is now integrated straight into a folder’s Get Info… window. If it works as smoothly as Apple claims, this is finally going to bring Mac OS X (client) into decent competition with Windows XP Professional in terms of GUI-level power-user features.

However, while all of these features are really cool, here’s a list of the ten geekiest features I will probably absolutely love, for one reason or another.

  • Ruby on Rails, out of the boxThe hot thing in web development right now is Ruby on Rails. Macs have already been the best personal desktop and web development platform because they have built-in support for the Apache web server and a host of other features, but now they will come with a ready-to-roll installation of Ruby on Rails, sporting Mongrel and (better yet) Capistrano! Specifically with the addition of Capistrano, which is terribly undersold as simply a Ruby on Rails deployment platform, these UNIX-y “toolbox” items are bound to make Macs that much more useful right out of the box.
  • Safari’s full history search — As their recent public partnerships with Google have shown, Apple is very clearly invested in search technologies. Spotlight gets a huge number of improvements in Leopard, but none which I think are going to be more useful to more people than this one: spotlight searches on the full text of each web page in your visited history list. That’s just awesome. Also awesome: using spotlight as a calculator and as a dictionary, which also shows just how Google-like Apple is trying to be. (Google also lets you ask it arithmetic questions and a dictionary.)
  • Wikipedia articles in Dictionary.app — I love Wikipedia because it’s one of the fastest ways to get (relatively) reliable information quickly. Now that Dictionary.app has built-in integration with Wikipedia, imagine the possibilities for getting that knowledge instant-gratification craving fixed. Apple has not yet announced this capability, but I can easily envision a scenario where all Cocoa text fields are instantly “wikified” (with text that matches Wikipedia articles highlighted) much in the same way that current Cocoa text fields allow you to right-click on a misspelled word and have it corrected by Dictionary.app.
  • Application-based firewall — In classic Apple fashion, functionality that was previously available via third-party additions is now available from Apple itself. In this case, I have to wonder how well Apple’s updates to its firewall will obviate the need for Little Snitch, which is basically an application-based firewall, too, and a good one at that.
  • Built-in guest log-in account — If you’re as paranoid about security as I am, you’ve already created a special, limited-access user on your system (called Guest or Visitor or whatever) and whenever friends are over, you tell them to use that account instead of your own. Now in Leopard, Apple has gone through the trouble of setting this up for us already. A small change that is going to have a big impact.
  • Scriptable System Preferences & applications — With AppleScript, you can automate the things your computer does with scripts, as long as those things are “scriptable.” In previous versions of Mac OS X, huge gaping holes of what things shipped by Apple were scriptable existed, causing me (personally) some really annoying headaches. AppleScript GUI scripting helped me get around many of those roadblocks, but now it seems Apple is finally filling in some of the most notorious gaps in this functionality with scriptable System Preferences. Yay!
  • Automator workflow variables — Automator brings the power of AppleScript I just mentioned to more people with a completely graphic programming environment. There is no need to open up a text document and write AppleScript code because Automator lets you create a script (called a Workflow in Automator jargon) using your mouse by dragging and dropping actions into the order you want them to be performed. It’s very slick, but until now it’s been very limited. With Leopard, Apple is beefing up Automator so that it includes things like variables, basic programmatic capability that was sorely lacking before. (Also majorly cool: a command-line utility to access Automator!)
  • Finder.app’s path bar — Every serious Mac user knows that the Finder needs a lot of help. Now, it’s getting some. Something the Windows Explorer has had forever (as had every desktop environment for Linux, of course) is a visual cue to show you where in your filesystem tree a given folder is located when you are viewing said folder. Now the Finder gains this capability (though Apple’s description implies that it’s going to be off by default) with what Apple is calling a “Path Bar”. Finally!
  • Cocoa and scripting bridges — Even though no one really seems to know about it, it has long been possible for languages other than AppleScript to do things like send Apple Events to Mac OS X applications. Specifically, Ruby and JavaScript, two of the most well-known web development languages in existence, can already do this with a single ScriptingAddition (OSAX). But now Apple is making this functionality a central feature and fully extending it to their Objective-C (and Cocoa) language and applications such as Xcode and Interface Builder. This means people like me will have a shallower learning curve before we’re able to create full-fledged, native Mac OS X applications. Now that’s exciting!
  • Xcode 3 refactoring — This is something you kind of have to see to believe. I got the opportunity to see it demoed at Apple’s Leopard Tech Talks last year and I was really excited by it. With the new Xcode, Apple’s development IDE, you can do away with find-and-replace searches for things like renaming functions because Xcode understands what parts of your code are what structures and, when you tell it to “change the function named myFunction to myNewFunction,” it’ll only find-and-replace function names instead of every instance of the string “myFunction.” That’s pretty big, and if it were available for more languages, it’s almost enough to make me ditch vim.

So there you have it. Ten features you might not have already known about that are some of the most promising features I can see in Leopard. And I didn’t even get into Wide-Area Bonjour, which could make services like DynDNS or No-IP a thing of the past (and which I still want to learn more about), or the new Terminal application (finally with tabs!), or even the multiple user certificates for S/MIME encrypted email.

Note: One of the least known security features available on Mac OS X is also possibly one of the best, and the simplest. Evidently, all Intel-based Macs are shipped with the XD (aka. NX, aka. DEP) bit turned on—and thankfully there doesn’t seem to be any way for users to turn it off. However, this isn’t a silver bullet and if you want to learn why you should check out this excellent Anandtech article: A Bit About the NX Bit.

Window and Element Resizing Annoyances in Internet Explorer

This has been an interesting day. In less than 8 hours, I’ve had to tackle the following IE nuisances:

document.body vs. document.documentElement

In IE 6, in order to access the current width of the window in JavaScript you need to get document.body.clientWidth only if you’re in quirks mode. If you’re in standards mode, this property not only still exists, but it means something entirely different! It instead refers to the width of the body element.

This causes real trouble for some scripts when the value of the this variable seems to suddenly become frozen or fixed at a single value instead of changing appropriately on a window resize event. Instead of document.body.clientWidth, in standards mode, use document.documentElement.clientWidth. (Reference table at QuirksMode.org)

Internet Explorer crashes when attempting min-width

If you use IE’s proprietary expression() syntax to script a CSS value, beware of calculating widths or heights that exactly match the value you’d like to set. If you do something like the following to set a minimum width on #someElement, IE will crash when you actually resize that element to be 500 pixels wide.

#someElement { width: expression(document.body.clientWidth < 500 ? "500px" : "auto"); }

Instead of doing the above, you should check for almost exactly the size you want, like so:

#someElement { width: expression(document.body.clientWidth < 501 ? "500px" : "auto"); }

However, the really important thing to keep in mind is that the minimum width you’re testing (501 in that second case) needs to be at least one pixel greater than the total content and padding width of the element. So if you have an element that needs to be no less than 500 pixels wide but also has 10 pixels of left and right padding, you need to check not for 501 pixels in width, but rather for 521 pixels in width. (Reference on CameronMoll.com.)

The Web is My Computer To Go

The other day my friend bought her first Mac. She was clearly excited but also clearly a little worried. This, she knew, was going to be a really big change. Or was it?

It occured to me while thinking about what this experience must be like for her, a smart but not technically experienced individual, that in fact a lot of what would be easy on the Mac would be the Web. Why? Because the Web is everywhere and, increasingly, every thing. The Web is the interface most people think about these days when they think about using computers.

Just take a look around. Almost everything you can do on a standard desktop application you can do on web pages these days. Instant Messaging was one of the first applications I can think of (off the top of my head) that was taken to the Web with AOL Instant Messenger’s AIM Express. Yahoo! quickly followed. I remember the days when hanging around in Yahoo Clubs Chat Rooms (now Yahoo Groups, and no longer involved with the Chat Rooms feature) used to be all the rage. I played a ton of Go and Battleship back then.

These days, more and more information is being put online and is becoming easier (and more consistent) to access. Twitter is all the rage, I do all my banking online (over verified HTTPS connections, of course), and Google has integrated GoogleTalk right into the GMail window. In fact, most of my friends never close their GMail window anymore. The browser is the new IM client.

Of course, there’s a fascinating paradox that’s worth examining in all of this. Simultaneously, the Web provides a consistent interface to my stuff (like email or banking information) and yet all of my information is consistently displayed differently. The Web is my computer—to go.

So if the Web is my computer on a take-out menu, the web browser is more and more like its own little computer inside the bigger one. Indeed, AJAX has proven itself in an ever increasing number of applications, and intelligent JavaScript is finally getting the attention it deserves. If you’ll forgive the exceptionally Mac-centric analogy, JavaScript is to the Web as AppleScript is to the Mac. Case in point, here’s a JavaScript bookmarklet that will give you a “full screen” button in any compliant Web browser:

javascript:self.moveTo(0,0);self.resizeTo(screen.availwidth,screen.availHeight);

This illustrates the point that the Web browser is becoming an ever more complex platform in its own right. People have already taken this concept further and more than a dozen Web Operating Systems are already in development. When these mature, computing, for many people, will have finally come full circle and returned to the days of dumb terminals.

By the way, my friend’s doing quite well with her Mac today. She’s even using Safari instead of Firefox these days.