2009
09.24

Here is a small update to Karmic flow

- Fix auto slide timing not resetting when clicking on controllers
- Fix decesdants of controllers triggering the default behavior of controllers (i.e. popping up new windows)
- Now karmic_flow_slide_selected will trigger the correct slide and controller onDOMready
- Slides now uses id instead of name for standards compliance

This is a remake of my wildly popular plugin for jQuery, known as jFlow. It works with Karmagination 0.2 or jQuery 1.3.2.

Download or see a demo with Karmagination or see a demo with jQuery

Karmic Flow Demo

Basic usage

$('#container').karmicFlow();

Here are the configurable options:

duration: (int) the time in milliseconds it takes to move 1 slide
timer: (int) waiting time in milliseconds for each slide before it slides, used when slides are played
auto: (boolean) specify whether to automatically play the slides on load

The options below are not to be modified unless you know what you are doing. If you change the options below make sure you change the corresponding class name for the HTML.

container: (string) the class name for container of slider and slides
slider: (string) the class name for slider
slides: (string) the class name for slides
slide_selected: (string) the class name added to currect active slide
slide_overflow: (string) the class name that handles how to display overflow slide
controller: (string) the class name for controller that slides to a particular slides
controller_selected: (string) the class name added to the controller of the current active slide
next: (string) the class name that slides the slider to the next slide
prev: (string) the class name that slides the slider to the previous slide
play: (string) the class name that automatically slides slide in timed intervals
pause: (string) the class name that pauses the effects of play

The default values for the options:

duration: 300
timer: 2500
auto: false
container: ‘karmic_flow_container’
slider: ‘karmic_flow_slider’
slides: ‘karmic_flow_slides’
sliding: ‘karmic_flow_sliding’
slide_selected: ‘karmic_flow_slide_selected’
slide_overflow: ‘karmic_flow_slide_overflow’
controller: ‘karmic_flow_controller’
controller_selected: ‘karmic_flow_controller_selected’
next: ‘karmic_flow_next_controller’
prev: ‘karmic_flow_prev_controller’
play: ‘karmic_flow_play_controller’
pause: ‘karmic_flow_pause_controller’

Recommended HTML structure:

<a class="karmic_flow_prev_controller" href="#" target="container">Prev</a>
<a class="karmic_flow_next_controller" href="#" target="container">Next</a>
<a class="karmic_flow_play_controller" href="#" target="container">Play/Pause</a>
<br />
<br />
<br />
<a class="karmic_flow_controller" href="#slide1" target="container"><b>叶上水</b></a>
<a class="karmic_flow_controller" href="#slide2" target="container">沙与石</a>
<a class="karmic_flow_controller" href="#slide3" target="container">迷雾滩</a>
<a class="karmic_flow_controller" href="#slide4" target="container">豹爽</a>
 
<div id="container" class="karmic_flow_container">
    <ul class="karmic_flow_slider">
        <li class="karmic_flow_slides karmic_flow_slide_selected" id="slide1"><img src="i/p1.jpg" /></li>
        <li class="karmic_flow_slides" id="slide2"><img src="i/p2.jpg" /></li>
        <li class="karmic_flow_slides" id="slide3"><img src="i/p3.jpg" /></li>
        <li class="karmic_flow_slides" id="slide4"><img src="i/p4.jpg" /></li>
    </div>
</div>
2009
09.10

Note: I have released a new version of Karmic Flow here. Please click to get the latest Karmic Flow.

This is a remake of my wildly popular plugin for jQuery, known as jFlow. It works with Karmagination 0.2 or jQuery 1.3.2.

Download or see a demo with Karmagination or see a demo with jQuery

Karmic Flow Demo

Basic usage

$('#container').karmicFlow();

Here are the configurable options:

duration: (int) the time in milliseconds it takes to move 1 slide
timer: (int) waiting time in milliseconds for each slide before it slides, used when slides are played
auto: (boolean) specify whether to automatically play the slides on load

The options below are not to be modified unless you know what you are doing. If you change the options below make sure you change the corresponding class name for the HTML.

container: (string) the class name for container of slider and slides
slider: (string) the class name for slider
slides: (string) the class name for slides
slide_selected: (string) the class name added to currect active slide
slide_overflow: (string) the class name that handles how to display overflow slide
controller: (string) the class name for controller that slides to a particular slides
controller_selected: (string) the class name added to the controller of the current active slide
next: (string) the class name that slides the slider to the next slide
prev: (string) the class name that slides the slider to the previous slide
play: (string) the class name that automatically slides slide in timed intervals
pause: (string) the class name that pauses the effects of play

The default values for the options:

duration: 300
timer: 2500
auto: false
container: ‘karmic_flow_container’
slider: ‘karmic_flow_slider’
slides: ‘karmic_flow_slides’
sliding: ‘karmic_flow_sliding’
slide_selected: ‘karmic_flow_slide_selected’
slide_overflow: ‘karmic_flow_slide_overflow’
controller: ‘karmic_flow_controller’
controller_selected: ‘karmic_flow_controller_selected’
next: ‘karmic_flow_next_controller’
prev: ‘karmic_flow_prev_controller’
play: ‘karmic_flow_play_controller’
pause: ‘karmic_flow_pause_controller’

Recommended HTML structure:

<a class="karmic_flow_prev_controller" href="#" target="container">Prev</a>
<a class="karmic_flow_next_controller" href="#" target="container">Next</a>
<a class="karmic_flow_play_controller karmic_flow_pause_controller" href="#" target="container">Play/Pause</a>
<br />
<br />
<br />
<a class="karmic_flow_controller karmic_flow_controller_selected" href="#slide1" target="container">Leaves</a>
<a class="karmic_flow_controller" href="#slide2" target="container">Sand</a>
 
<a class="karmic_flow_controller" href="#slide3" target="container">Beach</a>
<a class="karmic_flow_controller" href="#slide4" target="container">Cheetah</a>
 
<div id="container" class="karmic_flow_container">
    <ul class="karmic_flow_slider">
        <li class="karmic_flow_slides karmic_flow_slide_selected" name="slide1"><img src="i/p1.jpg" /></li>
        <li class="karmic_flow_slides" name="slide2"><img src="i/p2.jpg" /></li>
        <li class="karmic_flow_slides" name="slide3"><img src="i/p3.jpg" /></li>
        <li class="karmic_flow_slides" name="slide4"><img src="i/p4.jpg" /></li>
    </div>
</div>
2009
09.01

Below is the gzip algorithm in plain text, taken from http://www.gzip.org/. Why do we need to study it? Read below for the answer.

The deflation algorithm used by gzip (also zip and zlib) is a variation of
LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
the input data.  The second occurrence of a string is replaced by a
pointer to the previous string, in the form of a pair (distance,
length).  Distances are limited to 32K bytes, and lengths are limited
to 258 bytes. When a string does not occur anywhere in the previous
32K bytes, it is emitted as a sequence of literal bytes.  (In this
description, `string' must be taken as an arbitrary sequence of bytes,
and is not restricted to printable characters.)

Literals or match lengths are compressed with one Huffman tree, and
match distances are compressed with another tree. The trees are stored
in a compact form at the start of each block. The blocks can have any
size (except that the compressed data for one block must fit in
available memory). A block is terminated when deflate() determines that
it would be useful to start another block with fresh trees. (This is
somewhat similar to the behavior of LZW-based _compress_.)

Duplicated strings are found using a hash table. All input strings of
length 3 are inserted in the hash table. A hash index is computed for
the next 3 bytes. If the hash chain for this index is not empty, all
strings in the chain are compared with the current input string, and
the longest match is selected.

The hash chains are searched starting with the most recent strings, to
favor small distances and thus take advantage of the Huffman encoding.
The hash chains are singly linked. There are no deletions from the
hash chains, the algorithm simply discards matches that are too old.

To avoid a worst-case situation, very long hash chains are arbitrarily
truncated at a certain length, determined by a runtime option (level
parameter of deflateInit). So deflate() does not always find the longest
possible match but generally finds a match which is long enough.

deflate() also defers the selection of matches with a lazy evaluation
mechanism. After a match of length N has been found, deflate() searches for
a longer match at the next input byte. If a longer match is found, the
previous match is truncated to a length of one (thus producing a single
literal byte) and the process of lazy evaluation begins again. Otherwise,
the original match is kept, and the next match search is attempted only N
steps later.

The lazy match evaluation is also subject to a runtime parameter. If
the current match is long enough, deflate() reduces the search for a longer
match, thus speeding up the whole process. If compression ratio is more
important than speed, deflate() attempts a complete second search even if
the first match is already long enough.

The lazy match evaluation is not performed for the fastest compression
modes (level parameter 1 to 3). For these fast modes, new strings
are inserted in the hash table only when no match was found, or
when the match is not too long. This degrades the compression ratio
but saves time since there are both fewer insertions and fewer searches.

 

In our quest for the best possible JavaScript file size, we have always tried to optimize our code for minification. BUT, better minification does not equate to better gzip compression. Here’s what you need to avoid to get a better gzip compression, do not munge strings.

Recently there have been some libraries trying this strategy: using array notation instead of the dot notation for members of Objects. Here is a perfect illustration.

// uncompressed
var getElementById = 'getElementById';
document[getElementById].style.color = 'blue';
 
// minified
var a='getElementById';document[a].style.color = 'blue';

And you have read gzip’s algorithm, right? What does it do? Well, it maintains a lookup table for strings (note: everything is treated as strings in gzip’s point of view). By munging strings, you are actually emulating gzip in some ways. Here’s what the code above just did, added ‘a’ to the gzip lookup table, instead of just having getElementById there.

I have created a very simple case of string munging. Here’s the proof.

In the uncompressed file I have the following iterated till line 1000.

'u1'
'u2'
'u3'
'u4'
'u5'
'u6'
'u7'
'u8'
'u9'
'u10'

 
In the munged file, I have the following iterated till line 1001

var a = 'u1', b = 'u2', c = 'u3', d = 'u4', e = 'u5', f = 'u6', g = 'u7', h = 'u8', i = 'u9', j = 'u10'
a
b
c
d
e
f
g
h
i
j

 
The results are, taken from here :

  • uncompressed – 5,099 bytes
  • munged – 2,103 bytes
  • uncompressed gzipped – 93 bytes
  • munged gzipped – 120 bytes

My experiments conclude the following, string munging is perfectly fine if you are munging less than 3 different unique strings and it yields better result minification-wise. Otherwise, leave the strings as is, and save yourself some bytes (gzipped). Suprised? :)

2009
07.31

Note: Whether you agree or not to this article please retweet and spread the word so that we can promote a healthy discussion here.

Here is what I think happened in the last 10 plus years or so in the cross browser scripting world; pure incompetence -> global object detection (i.e. document.all) -> user agent sniffing -> feature detection (i.e. document.querySelectorAll) -> feature simulation -> browser detect + feature detection / feature simulation

Here’s some take on object detection vs user agent sniffing which I am not going to discussing in this article.

Browser detect, whether using user agent sniffing or global object detection, is notorious for being unreliable because are highly unpredictable or can be hijacked.

Feature detect lets you know whether the browser has the method but does not tell you if it works correctly.

Feature simulation, will not only detect if the browser supports a certain method but also tells you if it works correctly or not.

It is clear that, feature simulation is the only way to go in future. End of story. Not!

So, where does browser detect come into play?

In modern JavaScript, browser detect has lost its place in cross-browser scripting and there’s no doubt about that. BUT, browsers are built differently, from different people with different personalities and philosophies and with different tools. Although browsers try their best to adhere to all the standards, the standards does not specify how implement them i.e. which algorithm to use, how to allocate/deallocate etc.

There exists different codes that will achieve the same results. Let’s look at two pieces of code that delete all descendant nodes from an element.

<div id="test"><strong>A</strong><strong>A</strong><strong>A</strong></div>
// method one
var node = document.geElementById('test');
node.innerHTML = '';
 
// method two
var node = document.geElementById('test');
var fragment = document.createDocumentFragment();
var newEl = node.cloneNode(false);
fragment.appendChild(newEl);
node.parentNode.replaceChild(newEl, node);

The benchmark results are here. Both of the code snippets are cross-browser compatible. The Gecko engine runs faster using method two, other browser runs faster using method one. Here’s how I would use browser detect to do performance optimization.

var node = document.geElementById('test'), fragment, newEl;
 
if (isGecko) {
  fragment = document.createDocumentFragment();
  newEl = node.cloneNode(false);
  fragment.appendChild(newEl);
  node.parentNode.replaceChild(newEl, node);
}
else {
  node.innerHTML = '';
}

It does not matter whether isGecko returns a false positive or false negative, the code just works. Below is a generalization on how to use browser detect to optimize your code.

if (isSomeBrowser && isSomeBrowserFeatureSupported) {
 
}
else if (isSomeCrossBrowserFunctionSupported) {
 
}

To illustrate the performance improvements, here’s a benchmark using Karmagination vs other JS libraries.

2009
07.30

Before following this article, I suggest that you read Steven Levithan’s blog on this topic.

The most recent Firefox 3.5 release supports JavaScript 1.8.1. The language came with the trim, trimLeft, trimRight methods for string. Here’s how to use it.

if (String.prototype.trim)
  ' a '.trim();

The older faster and reliable way of doing it is simply do a string replace on both the left and right.

' a '.replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, '');

Here’s a sample code to benchmark how they fare against each other.

start = new Date().getTime();
for(var i =0; i < 200000; i++)
	' a '.trim();
end = new Date().getTime() - start;
 
document.write('trim method uses ' + end + ' ms<br />');
 
start = new Date().getTime();
for(var i =0; i < 200000; i++)
	' a '.replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, '');
end = new Date().getTime() - start;
 
document.write('replace method uses ' +end + ' ms<br />');
 
start = new Date().getTime();
for(var i =0; i < 200000; i++)
	' a '.trimLeft().trimRight();
end = new Date().getTime() - start;
 
document.write('trimLeft then trimRight method uses ' + end + ' ms<br />');

Running the benchmark resulted in:
.trim() 16ms
.replace() 303ms
.trimLeft().trimRight() 30ms

That’s a superb 20x improvement in this case, and I highly recommend its usage. The code below will take care of browsers that do not support trim.

var trim = function(str) {
  return str.trim ? str.trim() : str.replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, '');
}
2009
07.30

In real world applications, there are instances where the data structure of an object looks like an array.

var obj = {
 0: 'apple',
 1: 'orange',
 2: 'crab',
 length: 3
};
 
var ary = ['apple', 'orange', 'crab'];
 
alert(obj[0]); // apple
alert(ary[0]); // apple
 
alert(obj.length); // 3
alert(ary.length); // 3

They share some similarities, and, for debugging purposes (in Firebug), it’s sometimes beneficial display these special type of Objects as Arrays. Here’s how to do it.

// using the example above
var obj = {
  0: 'apple',
  1: 'orange',
  2: 'crab',
  length: 3,
  push: Array.prototype.push,
  slice: Array.prototype.slice,
  splice: Array.prototype.splice
};
 
if (this.console && console.log)
  console.log(obj); // ['apple', 'orange', 'crab'];

You can include other Array prototypes but push, slice and splice are the bare minimum to trick Firebug.

Note: The Objects are not converted to Arrays. I believe Firebug uses duck-typing to detect Arrays when displaying them on the console.

Updated: I guess my guess is correct, below is the proof.

// using the example above
var obj = {
  0: 'apple',
  1: 'orange',
  2: 'crab',
  length: 3,
  push: function(){},
  slice: function(){},
  splice: function(){}
};
 
if (this.console && console.log)
  console.log(obj); // ['apple', 'orange', 'crab'];

Update 2: Looking at the Firebug source that Tobie Langel provided in the comment below, we only need to include splice.

// using the example above
var obj = {
  0: 'apple',
  1: 'orange',
  2: 'crab',
  length: 3,
  splice: function(){}
};
 
if (this.console && console.log)
  console.log(obj); // ['apple', 'orange', 'crab'];
2009
07.29

What are literals? You use literals to represent values in JavaScript. These are fixed values, not variables, that you literally provide in your script. In this article, I am going to focus on Array and Object literals to show you the expressiveness and flexibility of JavaScript.

Object vs Array

There are a few differences between Object and Array.

  1. Their prototyped methods differs.
  2. Object does not have a built-in length, Array’s length is the number of items it has.
  3. Arrays auto increment their keys (in most cases), Object behaves like associative Arrays (meaning: you define the keys).
  4. New Objects use the {} literal and new Arrays use the [] literal.

There are a few similarities too.

  1. The typeof Array and Object is “object”. This causes headaches for many developers.
  2. You can store multiple values(data types) in Array and Object.

Object + Array vs {} + []

Similarities, read further below for proof.

  1. In their native forms. Array and Object instances share the same constructor as [] and {}.
  2. Literals are shorter representation for Array and Object instances. (Meaning: {} is equivalent to new Object() and [] is equivalent to new Array().

Differences.

  1. {} and []‘s constructor cannot be overwritten.
  2. Object and Array are constructors but {} and [] are instances.

Creating instances of Object and Array

The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.

var obj = new Object();
var arry = new Array();

You can use literals to create instances too.

var obj = {};
//verify obj
alert(obj instanceof Object); // alerts true, revisiting below
 
var ary = [];
//verify ary
alert(ary instanceof Array); // alerts true

Populating Object and Array

You can do it during initialization.

var obj = {
  name: "Tim Burtonic",
  age: 16
};
 
alert(obj.name); // Tim Burtonic
 
var ary = ['Sugar', 'Salt', 'Oil'];
alert(ary[0]); // Sugar
 
var ary2 = new Array('Sugar', 'Salt', 'Oil');
alert(ary[2]); // Salt

You can do it after initialization.

var obj = new Object();
obj.name = "Tim Burtonic";
obj.age = 16;
obj["sex"] = "male"; // equivalent to obj.sex = "male"
 
var ary = new Array();
ary.push('Sugar', 'Salt', 'Oil');
ary[3] = 'Pepper';

Detecting Object and Array

Let’s start with the intuitive typeof method.

var obj = {};
alert(typeof obj); // alerts object
 
var ary = [];
alert(typeof ary); // alerts object

The typeof method is not helpful in this situation. Why not instanceof or constructor?

var obj = {};
alert(obj instanceof Object); // true
alert(obj.constructor === Object); // true
 
var ary = [];
alert(ary instanceof Array); // true
alert(ary.constructor === Array); // true

Now this looks promising, but let us test further. Supposing you have an iframe checking whether it’s parent’s variable is an Array.

// in parent window
var a = [];
var b = {};
//inside the iframe
console.log(parent.window.a); // returns array
console.log(parent.window.b); // returns object
 
alert(parent.window.a instanceof Array); // false
alert(parent.window.b instanceof Object); // false
alert(parent.window.a.constructor === Array); // false
alert(parent.window.b.constructor === Object); // false

The array and object failed the instanceof test. Why? Each frame has it’s own copy of natives and globals, while the code and functionality is the same across frames (if not overloaded), the instances are not using the same copy of constructor function, that’s why the test failed.

Around 2008, Mark Miller came out with the a great idea by scrutinizing the EcmaScript specification. Let’s see what the Miller device looks like.

function isArray ( obj ) {
  return Object.prototype.toString.call(obj) === "[object Array]";
}
 
var a = [];
isArray(a); // returns true;

This niffy piece of code works across frames too! But this turns out to be only as reliable as Object itself being native. Detecting natives is not as trivial as it seems, according to Juriy Zaytsev. Let us make this fail badly.

// native prototype overloaded, some js libraries extends them
Object.prototype.toString= function(){
  return  '[object Array]';
}
 
function isArray ( obj ) {
  return Object.prototype.toString.call(obj) === '[object Array]';
}
 
var a = {};
alert(isArray(a)); // returns true, expecting false;

Reverting to native Object and Array

The code below overloads the Object’s native prototype.

// just overwriting the prototype
Object.prototype.toString= function(o){
  return o;
}
 
// using prototype
alert(Object.prototype.toString.call(this, 'good day')); // alerts good day
 
// using new instance
var o1 = new Object();
alert(o1.toString.call(this, 'good day')); // alerts good day
 
// using literal instance
var o2 = {};
alert(o2.toString.call(this, 'good day')); // alerts good day

This overloads the Object’s constructor and native prototype.

Object = function(){}
Object.prototype.toString= function(o){ return o; }
 
// what is Object now
alert(Object);
 
// directly using prototype call
alert(Object.prototype.toString.call('good day', 'good day')); // alerts good day
 
// using new Object
var o1 = new Object();
alert(o1.toString.call('good day', 'good day')); // alerts good day
 
// using literal
var o2 = {};
alert(o2.toString.call('good day', 'good day')); // alerts [object String]
 
// Object is being reverted to it's native form;
Object = {}.constructor;
 
var o3 = new Object();
alert(o3.toString.call('good day', 'good day')); // alerts [object String]

It seems that when a native constructor is overwritten, its literal will request a new copy of the native constructor and prototypes. Using this result, I will try to reset Object and Array to their native versions.

// overwriting the constructor and prototype
// overwritten prototype
Object.prototype.toString = function(){
  return '[I am overloaded toString]';
}
 
Array.prototype.sort = function(){
  return '[I am overloaded sort]';
}
 
alert(Object.prototype.toString.call([])); // alerts [I am overloaded toString]
alert(Array.prototype.sort(['c', 'b', 'a'])); // alerts [I am overloaded sort]
 
// function declaration instead of expression must be used because we want it to execute first globally
// do not put the constructor/named function inside any closure, it will mess with the execution order
function Object(){};
Object = {}.constructor;
 
function Array(){}; 
Array = [].constructor;
 
alert(Object.prototype.toString.call([])); // alerts [object Array]
alert(Array.prototype.sort.call(['c', 'b', 'a'])); // alerts a,b,c

Here you are! I, however, have tested this piece of code in limited platforms and do not have the resources to test them. I know at least they work for grade-A browsers as published by YUI.

2009
02.23

While the title mentions centered floats, the solution that I am about to present does not use floats at all but the end result is the same. Floats are notorious for their browser compatibilities and quirkiness. Through the years, there are only a few elegant solutions on float related problems. One notable solution is the use of hasLayout and the overflow property to clear floats which worked for all major browsers.

I have tried to tackle the centered floats problem a few times without much success, usually giving up and relying on methods that counter-position the container from it’s parent. It is not until I came across the Mozilla Webdev post on how to create a cross-browser inline block which reminded me of the reason why it’s so hard to create centered float is because we lacked the ability to define a cross-browser inline block. With that ability, we can just use text-align: center to do the job as what it would have done to images.

Now, let us jump directly into the CSS.

li {
	/* you can set a height or width if you need to */
 
	display: inline-block; /* for modern browsers */	
	display: -moz-inline-stack; /* for FF 2 */
	zoom: 1; /* for IE, triggers hasLayout */
	*display: inline; /* IE 7 and below */
 
	background:#CCC; /* not needed */
	margin: 5px; /* not needed */
}
 
ul {
	text-align:center; /* aligns all the children to center */
 
	background:#999; /* not needed */
	margin: 0; /* not needed */
	padding: 0; /* not needed */
}

Here is the html.

<ul>
    <li>aeroplane</li>
    <li>bird</li>
    <li>cat</li>
    <li>dog</li>
    <li>elephant</li>
    <li>fish</li>
</ul>

And the code in action.

aeroplanebirdcatdogelephantfish