Inspiration

Inspiration

Archive for 'JavaScript'

Defer document.write

I was asked today if there was a way to somehow proxy or defer document.write calls. Many advertising solutions still use this outdated way of writing banners into a website, and sometimes it would be handy just to load all the page first, and then all the advertising, to drastically improve the user experience.

I gave it some thought, and after a bit of experimenting, I actually found a solution for this problem many people tried to solve before. Let’s walk through!

1. Overwriting document.write

Yes – this sounds dirty, but you can in fact just overwrite document.write and it works across all popular browsers. Here’s my first round:

var _write = document.write;
	document.write = function(t) {
	return _write(t);
}

This simple proxy pattern, directly forwarding the call to the original method, only worked in Internet Explorer though. To whatever reason it returns the following exception in Firefox: “Illegal operation on WrappedNative prototype object”. After a bit of more experimenting, I found that document.write in FF has a ‘call’ method attached that I could use to run the native write in the document scope. So here’s the slightly modified version using the excellent IE check recently posted on Ajaxian (we can’t use the call method in IE, it doesn’t exist on document.write):

  var _write = document.write;
	document.write = function(t) {
	return 'v'=='v' ? _write(t) : _write.call(document, t);
}

2. Deferring document.write, or how to keep the context

Nice, we now have a cross-browser proxy function that delegates to the original function. But that doesn’t help much – after all, we want to delay all the writes until my page is fully loaded.

This one was an expecially tricky problem to solve, because we couldn’t just save the content to an Array or something, then echo it to the page at a later point. The reason is that we couldn’t save the context. document.write is a unique function, because it executes in the actual context, meaning on the actual line the call happens. This information, unfortunately, cannot be retrieved in any way. The obvious answer was that we have to write it to the document immediately to not loose the context information. However, we still don’t have to show it!

The final solution I came up with therefore enclosures the original write into a HTML comment block and then writes it out immediately. Of course, when the time comes, we have to resolve that comment block again through a regular expression. Here’s how our modified function looks:

var _write = document.write;
document.write = function(t) {
	t = '<!--##DEFER'+t+'DEFER##-->';
	return 'v'=='v' ? _write(t) : _write.call(document, t);
}
  

3. The final implementation

(function() {
	var _write = document.write;
	document.write = function(t) {
		t = '<!--##DEFER'+t+'DEFER##-->';
		return 'v'=='v' ? _write(t) : _write.call(document, t);
	}
})();

function resolve() {
	document.body.innerHTML = document.body.innerHTML.replace(/<!--##DEFER(.+)DEFER##-->/g, '$1');
}

I’ve additionally added a closure around the document.write proxy to save a global variable (_write is private this way), and also attached a function (I know I know, it’s lazy) called ‘resolve’ (rename it to whatever you want), that at a later point grabs the innerHTML of the body and resolves all the created comment blocks into their original content, at the right line.

Update: The innerHTML way of simply replacing the body is really lazy and should only be used for testing purposes. In a realistic setup, you mostly know where the write’s happen, and it will be much better to loop through them (i.e. using childNodes) in the DOM and filtering out comment nodes this way.

Enjoy!

The technique behind the jQuery UI demos

I’ve decided to start blogging more about the actual things I’m working on everyday, and in this series, I want to first talk about the updated and improved demos of jQuery UI. The first important thing to understand is that the demos that come with the development package, and that you can browse from the trunk, and the demos you see at the jQuery UI website are the same.

The standalone demos

To me, the new demos are truly outstanding. Let’s talk a bit about why. If you download the development package, or browse the trunk, you’ll see a demos/ folder, with sub directories for every individual plugin. If you open one of these sub-directories, you’ll see a index.html, a default.html and named individual demos, i.e. containment.html. Each of these demos:

  1. Is a standalone demo
  2. Includes all the files it needs (JavaScript / Theming )
  3. Displays a description of the current demo at the bottom

This means that those demos are excellent for learning how to do something – they come completely uncluttered, so you can copy and paste JavaScript and markup easily. Additionally, the default.html shows you the most simple state of the plugin (usually without any provided options), and the index.html provides a easy named listing to all these sub demos. Even better, if you open demos/index.html, you’ll see a page that looks very similar to the website demos section, but works like this:

  1. If you click on a plugin in the left hand navigation, i.e. ‘draggable’,
  2. it fetches the content of demos/draggable/index.html using Ajax and displays it as right hand sub navigation
  3. if you click on one of those links, the created iframe in the middle updates itself

The website demos

For the website demos, it got a bit more sophisticated. We removed the beautiful but unusable demo carousel, and created a unified demo section that automatically pulls the standalone demo files from the repository, therefore it’s never out of sync. However, the simple iframe approach couldn’t be used because of the incredible amount of server requests made that way. Here’s the technique behind it:

  1. include the theme and jQuery UI once
  2. include demos/index.html using PHP, filter out any script/style tags and the header
  3. now using JavaScript, rewrite all links to plugins to point to /demos/plugin

This shows you the index file. Perfect. What happens if you click on a link in the left hand navigation now?

  1. A server-side rewrite rule resolves demos/draggable to demos/?load=draggable
  2. in PHP:
    1. we export the ‘load’ information to Smarty, so we can access it in the template
    2. we then retrieve default.html and display it in a div frame, but filter out any script/style tags and header
    3. and we do the same for draggable/index.html, to show the right hand sub navigation
  3. in JavaScript:
    1. we loop through all demo links in the right hand nav and define click events,so the link isn’t triggered, but instead, a hash is set (for easy bookmarking) and
    2. the selected file is pulled in via ajax – again, we filter out any script/style tags with src attributes, and the header/footer, and update the frame div
    3. at last, we pull out the description at bottom of every file, and display it below the ‘frame’

So, with a little more work involved, we not only made the demos extremely responsive and fast, but also reduced the requests to the server dramatically. Every time you click on a demo, only one single request is made, to fetch the actual html page.

Pretty cool eh? Enjoy!

The Library Detector

I’m happy to announce my first Firefox extension called Library Detector. Similar to a greasemonkey script I published to the jQuery mailing lists a couple months ago that showed if jQuery is running (which proved to be pretty useful to extend the Sites using jQuery page), the library detector is able to detect multiple libraries, currently including the following:

If one of these is found on the current page, it displays their favicon in the statusbar, and if you hover it, a tooltip will show with additional information (In most cases the version of the library, in the case of jQuery UI the plugins being used, and for Dojo if Dijit is being used).

Of course, there’s one catch in some libraries: If the developer renamed the scope of the Library (i.e. window.dojo) to something entirely different, the test fails (however, usually that’s not the case).

So, if you want to know what websites use your favorite library (or which do not), go ahead and grab the Library Detector from its download page.

Additionally, I’d love to see feedback, and if you think there’s a library missing, or if you have an idea how to improve a test / show additional information, please leave me a comment.

Cheers!

Taking Usability to another level

So I love that my main interest is finally a hot topic, and recently, Aza Raskin continued doing a great job evangelizing Usability in web and application design, making it more popular than ever.

However, our efforts to usability are still limited to one single angle: The actual end user experience. While this is unquestionably the most important part, we can’t ignore another: Usability for developers. Since tackling the whole world of development is too much for one blog post, we’ll only investigate web development here.

Syntax & API

Why are certain programming languages more popular than others? Usually not because they’re faster – not even because the input or output is smaller. A single argument counts most: The easiest understandable, the one with the greatest learning curve wins.

Think about it – while binary approaches to languages and data formats are much more efficient, it’s a pain to work with. Take JavaScript – due to it’s flexible and dynamically typed nature, it’s not always the most efficient way to code – however, it’s the most popular.

Let’s think about a higher abstraction: JavaScript libraries. jQuery, for once, is highly popular amongst web developers because the API has a natural, language-oriented aspect. It’s almost neurologic – by looking at a certain block of jQuery code, you start to almost guess what the other functions could be named like.

Now, as soon as you have a good concept of the API using real-world language, easy to understand by simply looking at it, there needs to be a next step: Make the learning curve as small as possible. This can be done by providing a complete and solid documentation, demonstration of every feature, walkthrough tutorials and ways to communicate within the community (forums, mailing lists).

So, in other words, for a web programming language or toolkit/framework to be developer friendly, the following arguments (at the very least) need to apply:

  • Real-world language when naming API calls (do, write, make, etc)
  • A high learning curve, achieved by
    • Good documentation
    • Good demonstration
    • Good communities around the project (forums, mailing lists, etc)
    • A strict API design with no or little exceptions

Of course there’s more to it, but this should give you a good start (by the way, this works for most development, not only web development).

Tools

The second very important field where usability needs to be improved are the actual tools web developers use to create applications and websites. It’s no wonder Dreamweaver is ridiculously successful – it’s not necessarily something that outputs great results (although it can, if you’re disciplined!), but it’s simply so damn easy to use.

Web developers usually have to use tools for the following tasks, and the sub lists tell you how these need to beĀ  improved:

  • Writing the source code (IDE’s, Editors)
    • Better versioning integration
    • Helpers for refactoring
    • Integration with the browser engine
  • Creating and designing the frontend (WYSIWYG Editors)
    • Integration with the browser engine, instead of faulty preview modes (Dreamweaver CS4 has that, but they didn’t remove the preview mode yet)
    • Smart control panels that utilize a framework’s documentation to create fields / controls
    • Tight framework integration
    • Integration with actual design applications (i.e a bridge to Photoshop from Dreamweaver, allowing “live slices” to be be embedded into the Dreamweaver source, that update automatically as soon as I change the overall image in Photoshop)
  • Testing (End-platform, various browsers, Selenium [automated tests])
    • Semi-automated testing frameworks that run in a browser and serve a click-through for testers and mainly create experience surveys
    • Automated user tests, creating a ‘fake’ user that executes clicks and drags on actual websites and applications
  • Debugging (often integrated in IDE’s, our in the actual platform, i.e. Browsers)
    • One tool that debugs across various browsers, instead of great tools for each browser, i.e. Firebug, Dragonfly, the IE8 Debugger.

While there are some solutions that are clean, well designed and integrated for application development (see iPhone development), web developers still suffer. Especially testing and debugging is still a pain in the arse, and needs to be improved.

Conclusion

In the end, I think there is a lot that needs to be done to make the actual developers happy before those can make the end users happy . A developer in an inspiring environment can create things you wouldn’t even imagine.

On the jQuery UI side of things for instance, there’s still a lot that needs to be done, but what’s really great is that we realized that our development cycle sucked. We have started to make developer tasks as easy as possible – there’s a new jquery.simulate plugin that triggers actual clicks and drags to ease testing, there are new commit hooks that will clean trailing whitespaces and there will be a project tool in the future that aids in documentation, testing and API design. We were also proud to be the first framework to announce web widgets in Dreamweaver.

So if you’re involved into a product that helps developers, think about how usable it is (instead of all it’s cool features), and help me and my comrades to make developer lifes easier, so they can create the great products we all love.

Possible jQuery (UI) promotion tour in Japan

After the great success of my trip to Tokyo in May (thanks to my friend Yusuke!), I have been thinking a lot of how to better promote jQuery and jQuery UI over there. Usually, american products have a hard time in Japan because of the language barrier, and the easiest way to overcome this is to simply be in Japan!

So here’s my idea: To every japanese company interested, I will give free workshops about jQuery and jQuery UI to employees/staff. In exchange, they will cover a small part of my travel budget.

So,

  • If you live and work in Japan
  • And your company uses jQuery/jQuery UI or wants to use it
  • write me an email (paul.bakaus@gmail.com)

and we’ll discuss everything. I’m really excited about this idea, and it would be awesome if it works out. The same might happen in Brasil soon for another jQuery UI developer, which brang me the idea again.

Mata ne!

How library developers help defining standards

For the last couple of months, many people have been frightened that the Browser Wars are beginning to happen once again. It’s easy to come to such a conclusion if you see all these new standards in today’s browsers: Even only in CSS, Mozilla added a “-moz” scope for new CSS syntax, Webkit a “-webkit” one – and let’s not even talk about Internet Explorer.

We’re seeing a lot of move recently – Mozilla pushes their JavaScript API, Webkit adds CSS coolness, Opera comes up with Canvas 3D and Internet Explorer with awesome new events like recently featured hashchange. Now even Google comes up with their own browser and Gears is therefore becoming a own standard for that very own browser.

If you look at all that development however, it’s becoming very clear that it’s NOT the same than 10 years ago. I believe the overall idea behind it is different: Browser vendors are not actively trying to lure people to exclusively use their browser, but they’re trying to push the standards for the first time in 10 years – they want to push the web .

As a web developer, one might think it’s all a big mess now, and it does help nothing to their very own situation, because they cannot use the new standards of one browser in their new product – what about the other 75% of their target audience? And then, I’m not even sure if that feature survives in 2009!

Here is the point where I come in, as a JavaScript library developer. What we library developers can do is smoothen the path for these poor web devs. There are two ways of doing so:

  1. The Copy approach: Replicate an existing standard on other platform with the help of JavaScript
  2. The “Lowest common multiple” approach: Take a couple of different standards across browsers and create a subset that can be used across browsers

Let me show you one example for each approach to better show you pros and cons:

  1. The Copy approach: Google’s excanvas
    excanvas tries to bring the <canvas> element to Internet Explorer by using VML. While I think it’s a great project, it has some fundamental flaws: excanvas is not able to replicate the whole canvas API using VML. Although they’ve done a fair job of porting most of the features, some are missing simply because it’s not possible/too slow/too much work to port them.This makes developing for it fairly difficult, because you never now exactly what behaves how.
  2. The “Lowest common multiple” approach: Dojox GFX
    The Graphics engine of Dojo creates a own API and uses several different standards to render the exact same result. The advantage here is pretty clear: By defining what to support and what not in a limited subset, a web developer can be sure that whatever he uses here, even the most awesome, cutting-edge features, will work on every platform.

In my personal option, the second approach is the one that helps defining new standards. It’s the library developer in the end that reviews all standards and tries out what’s possible and what’s not, and therefore, the library developers opinion weights a lot. The library developers are the ones that have the power to bring new features to web devs as early as possible – not the browser vendors.

Cheers!
Paul

(What I talked about in this post is something i will feature again in my session for the Ajax Experience. If you have a change, I invite to check it out!)

3D CSS Transforms on the iPhone

So I wasn’t content with the things I’ve tried doing in Safari, and recently began digging through the documentation of the iPhone SDK and the actual CSS Transforms spec.

I was a bit skeptical when I first read about all the cool functions that work in Webkit iPhone, but nowhere else, because there was little documentation, and literally nothing done by other developers, no demos, no tests. I thought, surely, some students with too much free time must have jumped on that immediately?

Well, I decided to give it a go, and started Dashcode, created a new web application and hacked in some CSS Transforms into my elements. One very important discovery I’ve made is that only 2D CSS Transforms are directly visible on the WYSIWYG canvas in Dashcode. So when you think the actual 3D functions won’t work, run the iPhone simulator.

The iPhone simulator is actually capable of using the exact same API than the iPhone. This is awesome and a bit funny, since I always thought the 3D functions don’t work in the browser version of Safari yet, because they need to be bundled tightly to the hardware, but apparently, there must be a different reason.

The function that sounded the most awesome, I thought, was the -webkit-perspective function (“This matrix maps a viewing cube onto a pyramid whose base is infinitely far away from the viewer and whose peak represents the viewer’s position”, that just HAS to be awesome). The frustration came directly afterwards: The function did nothing.

At least, that is what I thought at first – the function does indeed nothing visually, if you don’t use any other transform functions. I believe this fact is nowhere written in the SDK docs, and it was hard to find out.

Here comes the cool stuff: The perspective function seems to define how the other primitive functions behave.

Let’s have a look at a practical example: Take a look at the following three functions:

  • rotateX – Rotates the element on the X axis.
  • rotateY – Rotates the element on the Y axis.
  • rotateZ – Rotates the element on the Z axis (By default, same as “rotate”)

Try these out – all three will give you flat, 2d animations, although they are, in fact, functions that use a 3D matrix. However, now change the -webkit-perspective property to 200, and try again. Now, you established virtual depth, and all three functions will give you incredible results.

To demonstrate it, here’s a demo that you have to either look at on your iPhone or in the iPhone Simulator:

As an extra flavor, this demo also uses the -webkit-backface-visibility property set to ‘hidden

‘, to hide the actual back side of the first element when the second element comes in (otherwise, you’d see the front flipped). Also, it’s lightning fast, even on the iPhone, since it uses Webkit’s native CSS Transitions, and triggers them via setting the webkitTransform css property.

Expect more to come soon!

Cheers,
Paul

CSS Transforms for Firefox

After my first teaser image, quite a few wondered why I’d bring out a version featuring CSS Transforms for Internet Explorer out instead. The reason why I now completely discontinued the CSS Transforms work for Firefox is that CSS Transforms are being shipped most likely along with the 3.1 release.

However, I think the two approaches were still interesting, so I’m discussing them with you:

The Canvas approach

This was my initial attempt to bring CSS Transforms to Firefox. Since there was no hack like using the Matrix Filter in IE, I had to do it the hard way. I knew that rendering web content to into a canvas was already supported by Firefox long ago but was then taken out due to security issues. So I had to take the long road and actually build my own limited rendering engine in Canvas (as some pointed out, of course not featuring things like inputs, buttons, everything natively styled by the OS).

Here’s how the logical implementation looked like:

  1. Find all instances of -webkit-transform
  2. For every found element:
  3. Create a new <canvas> element at the exact same position as the original, with the same constrains
  4. Rotate/modify/translate the whole canvas by the values found in the transform functions
  5. Literally draw borders, background and text (using FF3′s new text API for canvas) for the original item into the canvas and for all sub items
  6. Recompute the new constrains of the element and reset the constrains of the canvas

Although insanely difficult, it was working better than I initially thought, and I was able to create a DIV element with all kinds of sub nodes and rotate it with full speed in a nice animation.

The SVG approach

That’s when I found out about the foreignObject in SVG – since I never really played with SVG, it was completely new to me. The foreignObject basically is able to display namespaced XML, including HTML in an SVG canvas.

The fun thing here is that I immediately sensed that it was much more promising, because the CSS Transforms API is almost exactly copied from the SVG API, and if I could get the initial work done, I thought to myself, mapping it would be fairly easy.

Then I found about the limitations about SVG. For example, that it’s not possible to include inline SVG into an HTML page without serving the Content-Type as XHTML. Okay, this was a show blocker for my plugin, because I couldn’t possibly force people to use XHTML whenever they wanted to use CSS Transforms..

However, I did actually find a way to display inline SVG in HTML after many hours of research, and this is the implementation I came up with:

  1. Find all instances of -webkit-transform
  2. For each element,
  3. Serialize the whole node (outerHML) into a string (without positioning data in the style attribute)
  4. Wrap it with a prepared SVG XML Header
  5. Also insert the transform value as <g transform=’..’>
  6. Encode the whole string to base64
  7. Create a new embed element with the base64 String as data source, and render it to the page (with the position data from the original node on the actual <embed>)

If I would have continued with the development of the plugin, than definitely using the SVG approach. It’s pretty slow to do transformations on a foreignObject in Firefox 3, but you don’t loose the OS styles, and it’s so much easier since you don’t have to port over the CSS Transform API to something different.

See you soon with more exciting projects!

Bringing CSS Transforms to Internet Explorer

Extending the teaser

So I hope I got you a bit excited with my little teaser, and yes, the second tab was opened on purpose to give you a hint. Indeed, I was talking about CSS transforms, and yes, I was talking about somehow successfully porting them to Firefox.

I won’t go into details of my implemention of it yet, but I can assure you it isn’t using any additional plugins. Anyway, during my CSS transformation research for possible other browser implementations, I came up with something entirely different, and it was completely unexpected to me. As it turns out, Internet Explorer already supports CSS transformations in some way for years!

I was telling myself that surely, this wouldn’t actually work, since the Matrix Filter would allow you to actually rotate, scale and do whatever you want with elements, in IE, natively. And then, someone must have figured before me, years ago. But it turns out that the Matrix filter isn’t that popular at all (yes, these are filters that we hated so much back in time, and I feel totally stupid doing so now), so I decided to give it a go and played around with it.

Transformie!

What I came up with, is my new jQuery plugin (though fairly easy to convert to other libs) “Transformie“, a javascript plugin that comes in less than 5k that you embed into web pages and that maps the native IE Filter API to CSS transitions as proposed by Webkit.

Transformie supports the following functions from Webkit’s syntax (in degrees, radians or grads):

  • rotate
  • scale, scaleX, scaleY
  • skew, skewX, skewY
  • matrix (with the exception of the last two modifiers, tx and ty)

The reason the translate functions are not yet supported is the fact that IE’s Matrix function is not as flexible as Webkit’s, since you’re not able to specify tx and ty, the third columns’ first row value and second row value in the actual matrix (there is a way, but then the auto scaling doesn’t work anymore – does’t help much).

However, it’s fairly easy to also add the translate functions and the last two missing values of the matrix function by simply modifying the position top/left values. The only problem is that the actual behaviour then is a bit different than Webkit’s – Webkit’s translate doesn’t modify layout.

Also good to understand is the -webkit-transform-origin css function, that defaults to the center of the element in Webkit. However, in IE, and therefore also in my implemention (at this moment), the top left corner is the origin for calculations. Again, this should be easy to fix using position values.

Anyway, let’s get to the point. To show you how simple it really is to get started with Transformie, I simply included Transformie, and its dependancies Sylvester (great javascript utility, very useful for matrix multiplication!) and jQuery (was already included there, obviously) into my last blog post’s entry Coverflow, and from then it’s prety straight forward – reload Internet Explorer, and you should have CSS transforms!

One implementation detail that stands out is the usage of the terribly handy event “onpropertychange“, which almost behaves like DOMAttrChanged, but is much finer grained. It is capable of telling you whenever a DOM property changes on an element, and when you track the style attribute, it actually passes the actual style that changed along with the event. Neat, huh?

Documentation

Anyway, enough said, give it a try. It’s tested in Internet Explorer 6 and 7 and simply does nothing in other browsers. The following can be optionally configured directly after script inclusion:

  • Transformie.inlineCSS = jQuerySelector (default: “*”, defines if inline styles should be parsed for selected elements on page load [disable or narrow down for better performance])
  • Transformie.stylesheets = Boolean (default: true, defines if stylesheets are parsed on page load)
  • Transformie.trackChangesFor = jQuerySelector (default: “*”, defines for what elements changes should be tracked [disable or narrow down for better performance])

And when you’re done, simply use -webkit-transform or transform (thanks for the hint, John Resig!) in your Stylesheets or inline in the style tag.

Download

Here’s the download:

Transformie is, like jQuery, MIT/GPL double licensed.

Enjoy and leave me comments!

Firefox.

Soon.