Archive for the ‘JavaScript’ Category

Facebook Style Image Cropping (Javascript Preview)

Tuesday, August 26th, 2008

While others are sun bathing somewhere on the shores of Black Sea I received another interesting task - to  implement cropping for user uploaded profile images. My first idea was to port MooCrop to Mootools 1.2 and apply couple of modifications, but the customer wanted the cropping to be exactly like in Facebook. For those who don’t know it is plain old boring mouse drag.

Instead of generating thumbnail and then cropping it (like in Facebook) I take the original (uploaded) image and resize it with CSS (yes I know it is not the right thing to do but for a quick preview IMO it is ok and we skip one resizing operation). Then I use the Drag Class to create a drag to scroll container (like in Adobe Acrobat) and finally with two hidden input fields I send the coordinates to the server side part which takes care of the resizing and cropping of the image.

Enough mumbojumbo - the cropping example and the pic

FaceBook cropping

Javascript Dynamic Paging (MooTools Pager)

Saturday, August 16th, 2008

Couple of days ago I had to create a content pager which can dynamically insert page numbers including previous and next buttons.

The reason why I had to use Javascript and not any server side solution is quite interesting - the paging method should not really divide the content into different web pages. This is needed because if the text we want to split contains any XHTML markup and we divide it into separate web pages the markup will be broken (invalid). Just imagine having opening <div> tag in the first page and closing in the second - not cool! Other break point is if we just split some tag in two.

Using my favourite Javascript Framework - Mootools and with couple of XHTML/CSS tricks I could get it working with the following code:

// This Javascript is written by Peter Velichkov (http://www.creonfx.com)
// and is distributed under the following license : http://creativecommons.org/licenses/by-sa/3.0/
// Use and modify all you want just keep this comment. Thanks
 
var pagerPageHeight = $('warper').getSize().y;
var contentArea = $('content');
var pagerCurPage = 1;
var pagerPagesCount = 1;
var pagerPages = $('pager');
 
var pagerInit = function(){
 
	var contentHeight = contentArea.getSize().y ;
	pagerPagesCount = (contentHeight / pagerPageHeight).toInt();
	if (contentHeight % pagerPageHeight != 0 ) pagerPagesCount++;
	if (pagerPagesCount === 1) return;
 
	var prev = new Element('a', {
			'class': 'cust-pager-prev',
			'html': '&amp;lt',
			'id': 'cust-pager-prev',
			'events': {
				'click': function(){
					pagerChangePage(pagerCurPage - 1);
				}
			}
		});
 
	var next = new Element('a', {
			'class': 'cust-pager-next',
			'html': '&amp;gt',
			'id': 'cust-pager-next',
			'events': {
				'click': function(){
					pagerChangePage(pagerCurPage + 1);
				}
			}
	});	
 
	prev.inject(pagerPages,'top');
	$('cust-pager-prev').setStyle('display','none');
 
	for (var i=1; i&lt;=pagerPagesCount; i++){
		var anchor = new Element('a', {
			'class': 'cust-pager-item',
			'id': 'cust-pager-item-'+ i,
			'html': i,
			'events': {
				'click': pagerChangePage.pass(i)
			}
		});
		anchor.inject(pagerPages);
	}
 
	next.inject(pagerPages,'bottom');
};
 
var pagerChangePage = function(page){
	$('cust-pager-item-' + pagerCurPage).set('class', 'cust-pager-item');
	$('cust-pager-item-' + page).set('class', 'cust-pager-item-sel');
 
	pagerCurPage = page;
 
	if (pagerCurPage === 1) {
		$('cust-pager-prev').setStyle('display', 'none');
	}else{
		$('cust-pager-prev').setStyle('display', 'inline');
	}
 
	if (pagerCurPage === pagerPagesCount) {
		$('cust-pager-next').setStyle('display', 'none');
	}else{
		$('cust-pager-next').setStyle('display', 'inline');
	}
 
	contentArea.setStyle('top', (-1) * pagerPageHeight * (page - 1));
};
 
pagerInit();

The example and the picture as usual.

Custom Pager

Dynamic Increase / Decrease Font Size Box with Javascript

Sunday, July 20th, 2008

Web Accessibility is important aspect of the modern websites and including functionality for increasing / decreasing the font-size of the body text is a good step for achieving it. With all recent A grade browsers this is kind of unneeded since they have build in zoom functionality (ctrl + / ctrl -) but still there are couple of advantages for using custom solution:

  1. Preventing broken design due to resizing displacements
  2. Easier for less experienced users who don’t know how to zoom from the browser
  3. Looks kind of cool :)

The script I’ve written has the following features:

  1. Stores settings (increase/decrease value) in cookie
  2. Uses style switching (overwriting) so there is no font resizing after page load
  3. Limits the resizing to three steps in each way

Here is the code and example. Note that I’m changing only the body font-size because all paragraphs are using relative units (em). If you prefer to use absolute units (px) you will need to declare all CSS selectors you are using.

dynamic font resizing

Of course there are couple of things which can be improved but I wanted a simple script working under all major browsers : IE 6+, FF, Opera, Safari.

Customizable Form Select / Dropdown Replacement with Mootools

Thursday, July 17th, 2008

After seeing couple of implementations of replacing the default form checkboxes and radio buttons I was on a search for cross-platform select dropdown which can be fully styled with CSS. Unfortunately there are not so many options and the best I could find is elSelect:


elSelect is a great tool that allows you to visually change look and feel of usual select, keeping its functionality.

However I believe there is plenty of space for improvements.

1. Porting to Mootools v1.2 -

You need to replace setHTML, setText and other deprecated stuff to the new syntax.

2. Instead of creating new input just move the original (otherwise all events connected with the DOM element are lost and it does not work with .NET forms) -

Replace:

this.hiddenInput = new Element('input').setProperties({
			type  : 'hidden',
			name  : this.source.getProperty('name')
		}).injectInside($(this.options.container))

with:

this.hiddenInput = this.source.injectAfter($(this.options.container));

3. Various optimizations + autocomplete functionality and keyboard shortcuts (Tab-ing through the form).

Also I’m checking the browser agent since under iPhone it is better not to replace the select and adding some code graceful degradation:

var addCustomSelect = function(wrapper){
	if(!Browser.Platform.ipod){
		try{
			var mySelect = new elSelect( {container : wrapper});
		}catch(e){}
	}
	if ($(wrapper).getElement('select')) $(wrapper).getElement('select').setStyle('display','inline'); // Select is still here - degrade gracefully
}
if($('cust-sel')) addCustomSelect('cust-sel'); // Call as soon as possible

Other good tip is to have the select (you are replacing) with style visibility:hidden so it does not flicker when loading.

You can download my modified version from here. It has 1 and 2 applied plus some other minor changes. Still it is a good idea to diff the original and my version since I have custom modification that you might not need.

Dojo vs JQuery vs MooTools vs Prototype Performance Comparison

Sunday, February 24th, 2008

As part of my Mootools lecture at Codecamp I showed a brief speed comparison between the most used Javascript Frameworks running in the major browsers. Now as the Mootools team has extended their performance test tool (slickspeed) it is time to revise my benchmarks and extend them over more browser/platforms.

Test results (Lower is better):

Speed Comparsion Graph

*For example FF (XP-NA) is Firefox 2.0.0.12 with no addons (extensions) enabled running under Windows XP

You can check the actual numbers (in ms) and the full browsers information in the table bellow:

  Dojo 1.0.2 JQuery 1.2.3 MooTools 1.2beta2 Prototype 1.6.0.2
Mozilla Firefox 2.0.0.12 - no addons - winxp 128 266 115 259
Mozilla Firefox 2.0.0.12 - winxp 144 290 127 260
Mozilla Firefox 2.0.0.12 - linux 253 438 255 384
Opera 9.26 - winxp 32 136 148 194
Opera 9.26 - linux 110 188 238 364
Internet Explorer 7 - no addons - winxp 263 330 662 1563
Internet Explorer 7 - winxp 264 334 674 1583
Internet Explorer 6 387 600 945 2279
Internet Explorer 6 - linux (wine) 692 978 1310 2616
Safari 3.0.4 Beta 3 - winxp 36 76 84 116
Konqueror - linux 324 450 X X

Conclusions:

  • Safari under Windows XP is really blazing fast
  • Mootools and Prototype JS do not work under Konqueror (KDE’s default browser)
  • Dojo performs great. If we take only these test into consideration it safe to say it is the fastest Javascript Framework
  • Linux browsers are relatively slower against their Windows versions
  • Prototype is insanly slow under Internet Explorer

Disclaimer: This benchmark is somehow subjective because the test results depend on the current OS load and other factors. If you have any corrections or comments on this topic I will gladly review them and will revise the results if needed.

WAI / XHTML Valid Input Watermarks for Mootools

Thursday, November 15th, 2007

Just refactored the input watermarking script, of course it is still XHTML 1.0 transitional and WCAG priority 1,2 valid.

JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
// This Javascript is written by Peter Velichkov (http://www.creonfx.com)
// and is distributed under the following license : http://creativecommons.org/licenses/by-sa/3.0/
// Use and modify all you want just keep this comment. Thanks
 
var values = new Array();
var inputs = new Array();
 
function addWaterMark(el){
	try {
		values.push(el.value);
		el.addEvent('focus',function(){
			if (el.value === values[inputs.indexOf(el)]){el.value = ''};
		});
		el.addEvent('blur',function(){
			if(this.value === ''){el.value = values[inputs.indexOf(el)]};
		});
	} catch(e) {dbug.log('addWaterMark: ', e)}
};
window.addEvent('domready', function(){
	inputs = $$('input.watermark');
	inputs.each(addWaterMark);
});
//-->

Usage: Just put value on you inputs and use class=”watermark”

As usual example

Custom Dropdown (Styled Select)

Friday, November 2nd, 2007

Update: A far more better approach is to dynamically replace <select>’s in the HTML. Here is my post on the topic - Customizable Form Select / Dropdown Replacement with Mootools

Got tired of not able to style (colors, padding, background image, etc) dropdowns under various browsers (Internet Explorer and Safari are proven worst). Using my very favorite javascript framework mootools I created some simple dropdown simulating the select and option html tags usage.

Picture == thousand words
Custom Dropdown

and example of custom styled dropdown

Smooth Dynamic Rounded Corners

Tuesday, October 23rd, 2007

I have previously read about Javascript ways to make rounded corners but non of the suggested techniques produced antialiased (smooth) corners making me skeptic about the whole concept but curvyCorners proved me wrong - nice rounded corners with arbitrary radius, options for anti-aliasing and borders - Great work Cameron! I also tried the YUI compressor and was able to reduce the size significantly compared to the light version provided. If there is interest I can upload the compressed version.

As usual a demo is worth thousand words

Equal Height for Two / Three Columns DIV Layout

Wednesday, September 26th, 2007

Something that really stops tableless layouts is the lack of ability to make two or three columns the same height. There are a lot of tricks but the solution I prefer is with Javascript.

Description of the solution: I used the mootools framework since it provides lots of useful predefined methods, selectors etc.

Usage: Just include the latest mootools js file (don’t need ajax, json, fx and other) and the following js. Than add the class defined in the function (class=”equals” in the example) to the columns you want to be in equal height.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// This Javascript is written by Peter Velichkov (www.creonfx.com)// and is distributed under the following license : http://creativecommons.org/licenses/by-sa/3.0/
// Use and modify all you want just keep this comment. Thanks
 
function equalHeight(cl){
	var className = '.' + cl;
	var maxHeight = 0;
	$$(className).each(function(el) {
	if (el.offsetHeight & gt; maxHeight) {
		maxHeight = el.offsetHeight;
	}
	});
 
	if ($$('.dummyExtender') != '') {
	$$('.dummyExtender').each(function(el) {
		el.setStyle('height', maxHeight - el.getParent().offsetHeight + el.offsetHeight);
	});
	} else {
	$$(className).each(function(el) {
		var curExtender = new Element('div', {
		'class': 'dummyExtender'
		});
		curExtender.injectInside(el);
		curExtender.setStyle('height', maxHeight - el.offsetHeight);
	});
	}
}
 
window.addEvent('load',function() {
    equalHeight('equals');
});

Example: Equal Height DIV Columns

Update: Also since Internet Explorer 6 adds silly spacing in DIVs add the following lines to your css:

.dummyExtender{
font-size:0;
line-height:0;
padding:0;
margin:0;
}

WAI / XHTML Valid Input Fields Watermark

Wednesday, August 29th, 2007

Have you ever wondered how people put text in their input fields and when you click on it, it disappears. This process is called input watermarking.

Bellow is the JavaScript I’m using on my sites. It is XHTML 1.0 transitional and WCAG priority 1,2 valid.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
< script type = "text/javascript" > 
 
<!--
// This Javascript is written by Peter Velichkov (www.creonfx.com)
// and is distributed under the following license : http://creativecommons.org/licenses/by-sa/3.0/
// Use and modify all you want just keep this comment. Thanks
// Defining array that holds the IDs or Names of the inputs and the default text to display
// If you are using Names remeber that I am taking only the first one.
// The format is : 'ID1','VALUE1','ID2','VALUE2'....var inputs = new Array('firstname','firstvalue','secondid','secondvalue','thirdid','thirdvalue')
// Defining "indexOf" function for Internet Explorer
// It returns the index of the first occurance of an item in the array
 
if (!Array.indexOf) {
    Array.prototype.indexOf = function(obj, start) {
        for (var i = (start || 0); i < this.length; i++) {
            if (this[i] == obj) {
                return i;
            }
        }
    }
}
 
// Defining addEvent function since Internet Explorer does not support the official way of adding events
 
function addEvent(obj, type, fn) {
    if (obj.addEventListener)
    obj.addEventListener(type, fn, false);
    else if (obj.attachEvent)
    {
        obj["e" + type + fn] = fn;
        obj[type + fn] = function() {
            obj["e" + type + fn](window.event);
        }
        obj.attachEvent("on" + type, obj[type + fn]);
    }
}
 
function inputWatermark() {
    if (inputs.length < 2 || inputs.length % 2 != 0) {
        alert('Wrong usage - please read the source comments!');
    }
    for (i = 0; i < inputs.length; i++) {
        if (i % 2 == 0 && (document.getElementById(inputs[i]) || document.getElementsByName(inputs[i])[0])) {
            var cur = (document.getElementById(inputs[i])) ? (document.getElementById(inputs[i])) : (document.getElementsByName(inputs[i])[0]);
            cur.value = inputs[i + 1];
            addEvent(cur, "focus", onFocusHandler);
            addEvent(cur, "blur", onBlurHandler);
        }
    }
}
 
function onFocusHandler() {
    var inpname = this.id ? this.id: this.name;
    if (this.value == '' || this.value == inputs[inputs.indexOf(inpname) + 1]) {
        this.value = '';
    }
}
 
function onBlurHandler() {
    var inpname = this.id ? this.id: this.name;
    if (this.value == '') {
        this.value = inputs[inputs.indexOf(inpname) + 1];
    }
}
 
addEvent(window, "load", inputWatermark);
 
//-->
< /script>

Usage: Just fill the array with the IDs and the values. Instead of IDs you can use names

Input Watermark Example page