November 23, 2009

Rainbow Google and Annoying Google

I launched two more Google parodies: Rainbow Google and Annoying Google!

Rainbow Google is just a pretty demonstration of dynamic stylesheet modification. It was actually extremely hard to code — it took me about 8 hours of JavaScript hell. On another day, I’ll go over how I did it. This site adds a colorful spray of colors to the text on the page (see screenshot).

rainbowgoogle.com

RainbowGoogle.com

Annoying Google was about 10 minutes of work since it was just a super simple version of Rainbow Google’s code. :) Search queries and results are jumbled so that their letters are in random capitalized states… LiKe ThiS.

annoyinggoogle.com

AnnoyingGoogle.com

If you have suggestions or ideas, please let me know!

Filed under: Geeky Stuff, Javascript — Michi @ 10:03 pm

May 31, 2008

Getting Around Overwriting form.submit()

Since my dear reader Sameer requested it, I’m here making an update. I’ve got a cool JavaScript fix for everybody! I mentioned in a post a long time ago, but JavaScript has this semi-unexpected “feature” where you can accidentally overwrite the submit() function from a form. As in:

<form id=”myform”>
<input name=”submit” value=”submit me” type=”submit” />
</form>
<script>
document.getElementById(‘myform’).submit(); // THIS FAILS – Object not a method
</script>

Apparently, by creating a form element called “submit” you overwrite the native function that exists in every form element in JavaScript. Because it’s native, it also means you can’t just willy-nilly redefine it. And to make things worse, you cannot (at least not in a cross browser manner), successfully re-assign the submit() method because some browsers will disregard any attempt to reassign its value. As in:

<script>
document.getElementById(‘myform’).submit = ‘This gets ignored’;
</script>

Fortunately, there is a fix. This fix requires modifying the actual DOM. Because this tends to be inconsistent across browsers, I’m doing this fix in MooTools (which is my JS library of choice). However, the fix is fairly straight forward and can easily be done with (or without) any JS framework, as you will see. The steps are:

  1. REMOVE the form element in question. This is an absolute requirement to make the solution cross browser compatible. This can be skipped, but it will cause quirks. However, the good news is that we can assume that 99.99% of all form elements named “submit” are due to designers being ignorant — thus, such cases are exclusive to submit buttons. Luckily, these are almost NEVER needed in the server side code and really just act as wall flowers.
  2. Check if step #1 completed successfully
  3. If it did not, create a new Form element and copy its submit function over
  4. Submit

The code looks like this:

<script>
var formObject = document.getElementById(‘myform’);
// Removes the node
formObject.submit.remove();
// Functions don’t have tagName defined

if(‘undefined’ == (typeof formObject.submit.tagName)) {
    // create a form and assign its submit function
    formObject.submit = new Element(‘form’).submit;
}
formObject.submit()
</script>

Let me know if you encounter any problems.

Filed under: Javascript — Michi @ 1:54 am

November 9, 2007

Improving Your JavaScript Load Time

On our production website at work, I noticed that there was considerable lag time when loading the page due to a high number of JavaScript files. For those of you who don’t know, when a JavaScript file is loaded into a page, the rest of the page will hang until that file is completely downloaded. So unlike an image on a page, a slow JavaScript file can completely bog down your page. This is similar to an issue I noticed many months ago with FeedBurner. Each JavaScript file that is pulled requires the full overhead of firing up Apache and serving an HTTP request. This can be slower for you and painful for the web server if you have a high traffic website.

Additionally, once the JavaScript files load, if the code is full of asynchronous snippets (AJAX, event handlers, etc), the pieces can load in the wrong order! This has caused me headaches when unexplainable and random JavaScript errors began popping up (undefined variables and functions that are clearly defined in another file that should have loaded prior). This issue became increasingly common as the number of files being loaded increased. While I admit I don’t understand browser physiology enough to explain why this problem is more common with more files, I concluded there is some correlation that likely is attributed to the rendering order.

So after some thought, I came up with a solution. The goal was simple: decrease the number of web calls and try to make the JavaScript code render in 100% reliable and linear matter. Additionally, the hack would need to be easy to implement and take issues such as caching into account. The solution is a PHP file that looks like this:

/*
 * This file compiles a collection of JS files and then dumps them collectively
 * to the page, thereby reducing overall request overhead
 * Copyright 2007 Michi Kono (www.michikono.com)
 * Feel free to modify this however you want.
 */
header("content-type: application/x-javascript");
foreach(explode(",", $_GET["files"]) as $filename) {
   /*
    * prevent malicious attacks, only allow JS files
    */
   $filename = basename(trim($filename), ".js") . ".js";
   if($filename && file_exists($filename)) {
       $handle = fopen($filename, "r");
       fpassthru($handle);
       /*
        * in case there is no trailing ;
        */
       echo ";";
   }
}

Put this file in your JavaScript folder next to the rest of your JavaScript files. I called mine render.php.

Then, you put this in your HTML:

<script type="text/javascript" src="/javascript/render.php?files=firstfile.js, secondfile.js, thirdfile.js, etc.js"></script>

Ta-da! Faster JavaScript loading for everybody. :) Oh, and the issue of caching? Just put a timestamp on the end of the JavaScript URL string (like, "&<?php echo substr(time(), 0, -2) ?>" — cache changes every 100 seconds)

Other useful ideas: JS code could be compressed during this step, with comments and extra spaces being removed. Because code is being run through PHP, server side macros are now possible, rather than relying on cryptic JavaScript functions (such as for date management or database integration).

Filed under: Javascript, PHP — Michi @ 11:50 am

June 6, 2007

IE Redirect Bug with Dynamic Location Hash

I discovered the most obscure bug today in IE. For those of you paying attention, this bug is the reason I haven’t been updating — it ate up all my god-damned time. People who aren’t programmers can stop reading here.

What Happens

The browser is redirected when it shouldn’t be after modifying the URL hash (the stuff after #).

Scope

The bug exists on IE7, possibly 6 (why not, right?).

Steps to Reproduce

Assume you are on page A and want to redirect to page B.

  • Go to page A.
  • From page A, do a header redirect to page B in PHP/ASP/whatever. As in, header(‘location: $pageB’);
  • On page B, using JavaScript, modify the document.location.hash variable.

What Should Happen

The anchor text in the address bar should change. As in, http://www.michiknows.com/#someanchor changes to http://www.michiknows.com/#newanchor. This should happen without the page refreshing.

What Actually Happens

The browser refreshes. @#%!*(&$!

Solution / Fixes

On page A, rather than redirect using headers, use JavaScript:

<script>
// if page A was http://www.michiknows.com
document.location.href = 'http://www.michiknows.com/';
</script>
<a href="http://www.michiknows.com">go to page A</a>

For some dumb reason, this fixes the problem.

Damn you, Microsoft!

Filed under: Javascript — Michi @ 10:28 pm

May 11, 2007

The Truth Behind Giving IE7 Standards Compliance Updates

I just realized a funny irony about Microsoft competing with Google. See, Google has some really advanced JavaScript when it comes to its Adsense scripts (look to the left of or below this article). If you’ve never thought about this process, here’s your chance. The JavaScript that makes these ad unit boxes must:

  • Scan the page and send the contents to Google for analysis, get the response, and serve an ad accordingly (AJAX)
  • Build an entire block of HTML from scratch (DOM manipulation – very annoying)
  • Fire after the page loads, to ensure all of the content is in place (event handling)
  • Override any CSS or other page altering scripts to ensure people can’t be tricked into clicking (CSS hacking!)
  • Look and function exactly the same in all browsers

Well, the stuff I listed up there involves some of the most annoying aspects of programming in JavaScript (believe me). AJAX, Event handling, DOM manipulation, and CSS pretty much sum up the four pillars of “the most inconsistent things in JavaScript.” Thanks to IE, these tasks are a pain in the ass, when they really shouldn’t be.

Microsoft has to ensure their ads appear in all browsers, especially Firefox (#2 browser). You can’t sell your services to advertisers if it’s known that your ads break, and possibly misfire, when the wrong browser hits it. That means they’re forced to use a standards compliant implementation to do their ads.

This, of course, means they’re taking their own medicine and finding out what a horrible pain it is to support Firefox 1.5, Firefox 2.0, IE5, IE6, IE7, Opera, Safari, etc. It’s mostly a pain because of IE and its inconsistent and buggy support for the established JavaScript and CSS standards.

Maybe this is why they appear to be supporting some standards in IE7. Or, maybe they’re just building in the ones they use. Either way, this explains a lot. :P

Filed under: Geeky Stuff, Javascript — Michi @ 3:21 pm

May 10, 2007

Today, I Converted My JavaScript Allegiance to MooTools

As none of you probably realize (I mean, who even reads my JavaScript posts), I am an avid fan of JavaScript. I think it’s an awesome language that is very underestimated. Even Joel likes it. Anyway, one of the big problems with JavaScript is its inconsistencies between browsers. The first popular pioneer into cross browser scripting was Prototype, an open source library full of tons of useful functions and enhancements to the JavaScript language. It was quickly followed up by an extremely popular open source effects library called Scriptaculous. I was never a fan of Scriptaculous because of its bloat, but I have remained a steadfast supporter of Prototype.

That is, until yesterday.

Yesterday, I discovered MooTools, an amazing open source library that has all of Prototype and Scriptaculous’ functionality, and then some. After thoroughly examining its features, size, ease of use, and extensibility, I have concluded it is my new JavaScript library of choice. Some of the highlights include:

  • A relatively similar naming scheme as Prototype, making porting a simple process for most scripts.
  • Functionality that matches all of Prototype’s core methods, including AJAX functionality, DOM manipulation, and browser compatibility fixes.
  • Really easy animation effects that give you an amazing amount of control (see below).
  • Very active developers (they actually respond to questions within a day!)
  • The compressed download is only 40kb (which is the one you’d be using).

I highly encourage web developers to check it out. There was a recent article on Slashdot that discussed some of the big libraries out there, but it completely omitted MooTools. Well, I have been looking for a few months now for a library to use for our application at work. I examined Scriptaculous, Yahoo UI, Dojo, jQuery, Open Rico, Mochikit, and various other small ones I came across. I stumbled for hours just looking for JavaScript libraries. At one time or another, I wrote something relatively advanced with each of these frameworks in an attempt to see how well the advanced functionality was designed.

  • Scriptaculous suffers from insane bloat and heavy reliance on Prototype, a completely separate project — this problem was highlighted when a recent fix in Prototype broke Scriptaculous unless you switched to their unfinished beta release. This is unacceptable.
  • Yahoo UI tends to require more lines of code to do the same things in other libraries. It is trying to do “everything at once.” It is also very bloated because it fragments itself across many files.
  • Dojo is just huge (150kb, compressed). That’s a negative.
  • jQuery is too fragmented, which actually hurts it in my eyes (others see it as really “customizable”) – it has way too many plugins that you can’t depend on since the developers working on them aren’t affiliated to the jQuery project. If you do too much advanced stuff, it can end up like Yahoo UI, except the fragments you are relying on are made by 40 different people, none of whom have any reason to help you.
  • Open Rico is awesome for simplifying AJAX, but fails in the visual effects department due to over simplification of the process and requiring too many changes to the HTML (see their accordion example). It is, however, a great introduction for AJAX developers, in my opinion.
  • Mochikit had a (barely) tolerable size (113kb, compressed), but I despise their coding standards (just look at their code sample variable names!) and I wasn’t happy about the complicity in using their library. It is not very beginner friendly, in my opinion. This is a deal breaker since I can’t ensure future maintainers of my code will be JavaScript experts.

The decision was clear: MooTools owned the rest.

On ease of use, it was the top due to its consistent naming conventions and predictable function behavior. Their methods all support “chaining“, which allows you to compress several complex lines of code into one, easier to read one.

What impressed me most for its ease of use was its animation methods. Take this simple snippet:

new Fx.Style($('some-element'), 'margin-left', {
  duration: 400,
  wait: false)
}).start(0, 100);

What’s that do? It takes the element called “some-element” and slides it 100 pixels to the right by changing the margin-left CSS property from 0 to 100 over a 400ms span. This might seem complicated to complete JavaScript beginners, but believe me when I say JavaScript animation literally doesn’t get simpler than this. I have shown you an extremely simple example, but with only another line or two, you can do stuff like this. Here’s an example of making something transparent:

new Fx.Style('popup-message', 'opacity').start(1,0);

Change the “0″ to a “0.5″ and the popup message only goes half way invisible before stopping. They’ve done an exceptional job keeping it relatively simple while still giving you full control over the effects (you can apply transitional algorithms too).

On AJAX, I was also impressed because they managed to keep it very simple, yet give you control of the process. For example, check out this amazingly simple AJAX code:

<form id="myForm" action="submit.php">
<input value="bob@bob.com" name="email">
<input value="90210" name="zip">
</form>
<script>
$('myForm').send();
</script>

That sends an AJAX request to submit.php. Of course, you could customize this and add in callbacks and cool loading images, but just the fact that you can do the entire AJAX request in one line like that is impressive.

They also have a ton of demos (my favorite one). Again, if you are considering a library for AJAX and visual effects, MooTools is by far the best one I have encountered.

Note: If you are looking for a library for only AJAX and not visual effects, MooTools can be downloaded in pieces, so it can fit your needs there as well. It also means later, if you change your mind, you can always download the visual libraries and not have to worry about compatibility issues.

Filed under: Javascript — Michi @ 12:32 pm

April 18, 2007

Google Makes the Best Mashup Service Ever

Google just introduce a new RSS Feed JavaScript API. At first, I didn’t get why it was so useful, but after reading up on it, I realized its power.

First, it simplifies RSS parsing. This is awesome on its own level just because that can be a pain sometimes.

But the true power in this API is that it overcomes a critical problem in JavaScript in a safe and manageable way: you can read data from multiple domains. For those of you unaware, JavaScript has a limitation: you can only access one external domain in your script. When you try to get data from a second domain, JavaScript barfs up security warnings. This is there as a safety net so that developers don’t accidentally leave a security hole that lets some hacker throw in their JavaScript code that talks to the hacker’s server.

Google’s new API lets you side-step the entire issue by taking everything through Google. You can take a feed from Slashdot, Digg, and your favorite blog, all on one page, all at once, without having to use otherwise lame and unnecessary workarounds (using proxies or “middleman” scripts).

As I mentioned, the API makes parsing simple. Check out this example:

  1. var feed = new google.feeds.Feed('http://www.digg.com/rss/index.xml');
  2. feed.load(function(result) {
  3. if (!result.error) {
  4.     for (var i = 0; i < result.feed.entries.length; i++) {
  5.       var entry = result.feed.entries[i];
  6.       alert(entry.title);
  7.       alert(entry.content);
  8.     }
  9.   }
  10. });

At first glance, I know it looks like regular JavaScript. But if you look carefully, it is very intuitive.

  1. The first line grabs the RSS feed from Digg and creates a new feed object in feed
  2. The feed is loaded.
  3. If there is no error…
  4. Go through each item.
  5. Get the entry.
  6. Display the title of the entry.
  7. Display the content of the entry, etc.

While this isn’t going to be a huge step for the advanced developers out there, it will be significant for those of us who are too lazy to or didn’t know how to work around JavaScript’s domain security model. The added ease of parsing feeds will be huge for developers who aren’t familiar with parsing XML (note: it is a huge PitA).

Thanks, Google.

Filed under: Javascript — Michi @ 11:16 am

March 30, 2007

A Lesson on JavaScript Objects and Prototype’s bindAsEventListener Method

This post covers 3 topics about JavaScript:

  • How objects work in JavaScript and what makes them useful.
  • A concise explanation as to why the this variable is confusing at times.
  • A clear explanation of bindAsEventListener since the official one is confusing at best.

An Overview of JavaScript Objects

To dumb things down, in JavaScript, functions can be assigned to variables. Thus, you can do cool stuff like this:

var eat = function() {
    alert(‘munch, munch’);
};
// displays ‘munch, munch’
eat();

Objects are denoted by using curly brackets. Inside an object, you can put variables. The syntax is a little different, so pay attention. Thus:

var Michi = {
    favoriteFruit: ‘banana’,
    favoriteBread: ‘whole grain’
};
// displays ‘banana’
alert(Michi.favoriteFruit);

Note: I don’t like either of those that much.

The colon is sort of an equals sign. It essentially equates to “variable name: value”. Each assignment is separated by a comma and the “value” portion can be anything that you can assign to a regular variable. Since you can assign variables inside objects, that means you can put functions inside objects. Then you can call a function by putting a pair of parentheses () on the end of the variable. Again, pay attention to the syntax:

var Michi = {
    eatFruit: function() {
        return ‘Eating: banana’;
    }
}
// displays ‘Eating: banana’
alert(Michi.eatFruit());

In a truly object oriented example, calling eatFruit() should cause Michi to eat his favoriteFruit variable:

// does the same thing as the previous example
var Michi = {
    favoriteFruit: ‘banana’,
    eatFruit: function() {
        return ‘Eating: ‘ + this.favoriteFruit;
    }
}

This is where stuff gets sticky. Or maybe gooey. Nah, I won’t make a pun here. this refers to Michi. This is important because later we might copy Michi into another variable Tom. When that happens, this now refers to Tom’s favorite fruit, which might be an orange. this is a dynamic placeholder for whatever object that we are inside of.

How *this* Complicates Things

Let’s continue illustrating the problem by building another example:

function watch(personEating) {
    alert(personEating);
}
// displays “Eating: banana”
watch(Michi.eatFruit());

This will do exactly what you think it will do. It will cause Michi to eatFruit(). However, the next example is where things get very tricky:

function watch(personEating) {
    alert(personEating());
}
// the goal is to display “Eating: banana”
watch(Michi.eatFruit);

This will fail. Why? Notice the very subtle differences between the two examples. Look at section I highlighted. In the first example, the function is called and its result, the text “Eating: banana” is then sent to alert(). In the second example, the function Michi.eatFruit is passed in as a variable. It is then called as a function from inside watch(). Translated, that code renders like this:

function watch(personEating) {
    // this temp stuff isn’t necessary, but it should make
    // things easier to understand

    var tempFunction = function() {
        return ‘Eating: ‘ + this.favoriteFruit;
    }
    var tempText = tempFunction();
    alert(tempText);
}

As you can see, the problem is due to the this.favoriteFruit variable. this now refers to the function watch()’s parent (e.g., nothing at all), which doesn’t have a favoriteFruit variable. this no longer refers to Michi. This is a very common and very frustrating part about JavaScript. To get around this, the popular prototype library has a fix.

Prototype’s bindAsEventListener

The official documentation (as of this writing) for this method is dead wrong. Their example is wrong. Their explanation is fuzzy. Maybe somebody over there will read this and fix it up. Prototype’s example doesn’t even work! The corrected example is:

var obj = { name: ‘A nice demo’ ,
    handler: function (e) {
        var tag = Event.element(e).tagName.toLowerCase();
        var data = $A(arguments);
        data.shift();
        alert(this.name + ‘\nClick on a ‘ + tag + ‘\nOther args: ‘ + data.join(‘, ‘));
    }
};
Event.observe(window, ‘click’, obj.handler.bindAsEventListener(obj, 1, 2, 3));

So I will try to explain how to use it correctly. The syntax is simple:

parentObject.someFunction.bindAsEventListener(parentObject);

Thus, in my previous example that broke, you would rewrite it as follows:

function watch(personEating) {
    alert(personEating());
}
// was watch(Michi.eatFruit);
watch(Michi.eatFruit.bindAsEventListener(Michi));

When the code is executing, it knows that this refers to Michi, thanks to that argument being passed in. The argument represents what this refers to. So you would still call the method exactly as you normally would, but you tack bindAsEventListener on the end.

I hope this was educational. The fixed demo code will run for certain since I tested it; the rest: I am not as sure (95%).

REMEMBER: Word Press likes to convert my quotation marks into the slanted ones. So if you cut and paste my code, make sure you change those!

Filed under: Javascript — Michi @ 7:22 pm

February 23, 2007

FeedBurner Lagging My Site! Can’t Fix Until FeedBurner Gets Smart!

Well, today I noticed that each article takes about 10 seconds longer to load because of a little stat-tracking widget I installed from FeedBurner. If this happens a second time, or if this continues for longer than an hour, I’m removing it. I already track my stats through Analytics anyway.

Which, by the way, is an awesome way to track your stats. I’m only using FeedBurner’s because it’s convenient. But if it’s going to jack up my site, screw that!

In my opinion, a JavaScript tracker should be designed so that it doesn’t screw up load times! Why isn’t it load balanced? Why is FeedBurner.com loading just fine? Why can’t they give you an “advanced” piece of code to paste that uses conditional JavaScript loading. From the article:

You may sometimes find yourself with big JavaScript libraries to include in your documents. … add them dynamically via the DOM … This … would … load the file … when DOM is available in the browser, older browsers would not load the file.

In other words, load the JavaScript after the rest of the page has loaded rather than causing the entire site to lag! Like I said, this should be an “advanced” snippet people should be allowed to do.

Thus, the current snippet:

<script src=”http://feeds.FeedBurner.com/~s/MichiKnows?i=<?php the_permalink() ?>” type=”text/javascript” charset=”utf-8″></script>

Becomes:

<script type=”text/javascript” charset=”utf-8″>
window.onload=function(){
    if(!document.getElementById || !document.createElement){return;}
    var newjs=document.createElement(’script’);
    newjs.type=’text/javascript’;
    newjs.src=’http://feeds.feedburner.com/~s/MichiKnows?i=<?php the_permalink() ?>’;
    document.getElementsByTagName(‘head’)[0].appendChild(newjs);
}
</script>

Of course, this won’t work on FeedBurner for two reasons:

  1. If they are using onload functions, those won’t fire.
  2. FeedBurner uses document.write, which must be called before the document finishes rendering (during load). 

They use 100% inline Javascript!

Unfortunately, because they are written as in-line scripts which use document.write() statements, there is no easy way to defer their output after onload has fired or request them interactively in a way that won’t be likely to wipe out and completely rewrite the current document (unless you load them into individual <iframe> documents, which is the only guaranteed, though awkward, workaround I can think of at the moment).

So while my solution almost works, it doesn’t matter since they use a bad solution which breaks most workarounds!

When they fix their stupid script or if you know of a workaround, let me know!

Sheesh.

Filed under: Geeky Stuff, Javascript — Michi @ 2:13 pm

January 31, 2007

Google Loco – A Lesson on Event Handling

In the GoogleTV post, the video mentions (briefly) a Google service called Loco. I have decided, for fun, to make this service. Introducing Google Loco. I don’t make a dime from it and I redirect all search traffic to Google.com. Just a funny joke site to show your friends. ;)

Google Loco has some pretty nifty JavaScript that I’d like to share. The main interest is in the script that:

  • In Firefox: flips around the text you type in
  • In all browsers: randomizes the colors

I will cover the text flipping in another post. This one will focus on event handling.

Event Handling Mini-Lesson

What the heck is event handling anyway? Well, that’s the “onclick” or “onmouseover” stuff you have probably encountered. It’s a term for telling the computer to handle and event when something happens. Thus,

onclick=”SOMETHING”

Is read as “do SOMETHING when a CLICK event happens”. Event handling is an advanced topic in JavaScript. So how do we do it in Google Loco?

First of all, I added an event handler that fires when the page loads.  You see, in the old days, people used stuff like this:

<body onload=”initializeOnLoad()”>

But we’re in 2007 now. Things are done differently. The above command now can be redone using event handlers in the following syntax (see the actual site for the advanced, error proof syntax):

window.addEventListener(‘load’, initializeOnLoad, false) // syntax different for IE, see .js file

I know the second one looks more confusing, but it’s better. Why? Because you aren’t mixing business logic with your presentation layer (JavaScript separate from HTML). Secondly, this line can be put anywhere on the page, making it more portable since it can reside inside a JS file.

You’ll notice in the event handler example, initializeOnLoad doesn’t have parentheses after it. This is because, in short, JavaScript treats functions like variables.

When the parentheses are removed it’s like saying “don’t execute me, I’m just the messenger.” My, that was a very clever pun…

Or in other words,  initializeOnLoad() executes whatever is inside that function. InitializeOnLoad (no parentheses) refers to the contents, but doesn’t actually execute anything. This allows you to copy it around, modify it, reassign it, or whatever else you might do with a regular variable. In our case, we assigned it to the event handler for when the page loads.

The page itself uses a “loco” variable. You’ll notice there’s stuff like:

addEvent(document.getElementById(‘typed-box’), ‘keydown’, loco.locoEffects);

This, for example, would grab the element “typed-box”, and cause loco.locoEffect to fire whenever a key is pressed on it. If I had used “window” instead of “document.getElementById(‘typed-box’)”, the event would fire when a key is hit anywhere on the page.

Anyway, that loco.locoEffects thing… That’s a class. Well, a faked class. It’s really a variable called loco with another variable called locoEffects inside it. This inner variable just so happens to be a function.  Why did I do this? Oh, just to keep the global namespace uncluttered (as in, so I don’t have to worry about overwriting a native JavaScript function).

Filed under: Javascript, News — Michi @ 2:54 am
Next Page »