Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Sunday, January 22, 2012

A simple strategy for time localization

If you are building a webapp which is dependent on time (for example, a bidding or betting application) then you must have seen the requirement to show time on the webapp depending on the timezone of the logged in user. The other day i was going through various blogs and i saw a couple of posts by different blogs covering this approach and i was amazed to see that how complex route they took. So, i thought to write a post describing some really easy steps to achieve this.
There are multiple decisions/questions that you have to answer in order to achieve this goal.

1. In what timezone will you save the time in your db?
2. How would you get user's timezone?
3. When do you want to change the timezone according to user's timezone?

In this post i'll go through each of the above questions one by one.

In order to answer the first question, the best option is to go for GMT/UTC timezone. The reason is that it's extremely easy to convert time from GMT to GMT+8 or GMT0-5 etc. You can simply add/subtract the difference from the timestamp. But, you have to consider another thing here, if you are hosting your webapp on a shared server, then you need to consider the timestamp your shared hosting server is using. Because for any time critical webapp, you'll be frequently getting the current time and the server will be returning you the timestamp depending on the timezone it has set. Most of the shared hosting servers don't allow you to change the timezone. Now, you can also keep GMT/UTC timezone as the default timezone and you can change the timezone of the current time as well. Both are valid ways,  so it's up to you what to go for. Now, whenever user enters some datetime, you convert the datetime entered into the default timezone and save it in your db.

Now, the second question, i.e. how would you get user's timezone. Now there are a couple of ways to achieve this.

1. Ask the user for his timezone upon registration and use that
This is a fairly popular and accurate method of getting user's timestamp. The only problem in this approach is that it's not dynamic, i.e. if the user moves to a different timezone, he'll have to manually change his timezone on your webapp. If you don't mind putting your users through this step, then this method is recommended.

2. Get the timezone from the ip of the user
This is another method of getting the timezone of the logged in user. You can use ip of the user to track his geolocation and from that you can determine his timezone. Though, personally i don't think this is a good approach to go for. In my personal opinion it looks like an over kill unless you are already tracking and showing data on the basis of user's geolocation.

3. Get the timezone of the user through javascript.
I personally like this method because of its simplicity. You can easily get the timezone of the logged in user through following steps.
  • Get the timezone of the logged in user on your main page. For this i saw such complex approaches that i was amazed. Certainly some people love to bring gun to a knife fight :s .You can achieve this through one line of the following code
    • - (new Date.getTimezoneOffset()/60)
      • This method basically returns the difference between GMT and local time in minutes. So, if you are at GMT+2 then Date.getTimezoneOffset() will return -120 and if you are at GMT-2 then it will return 120. Therefore, simply put a - before it and divide the result by 60 and you'll get the time difference in hours. 
  • Make an ajax call and send this time difference on some server page and store it in session or cookie. A simple snippet of the code is
                         <?php 
             session_start();
             $_SESSION['userTimeZone'] = $_GET['utz'];
           ?>
Now, you have user's timezone saved in session. Whenever, you want to display a time, simply convert the stored time into user's timezone. Now, again there are multiple ways to achieve this. One very simple way is to save user's timezone in terms of seconds and simply add/subtract from the stored timestamp (if you used GMT as your default timezone). Or, you can use the following code to achieve this as well. (in order to use the following code you need to save user's timezone in proper format i.e. GMT+2)

public function convertTimeZone($date, $from_tz, $to_tz, $dateFormat) {
    $dateObj = new DateTime($date, new DateTimeZone($from_tz));
    $dateObj->setTimezone(new DateTimeZone($to_tz));
   
    return $dateObj->format($dateFormat);
}


And there you go, it's as simple as that.

Saturday, January 21, 2012

A simple jquery based ticker

This is a fairly simple and straight forward tutorial. The focus of this post is to share a simple method to create a ticker. There are many real life scenerios where you need tickers, e.g. on a news website to show the latest news. Now, keep in mind that this tutorial is not about real time event handling (though i am planning to write a tutorial on that as well). In this post, i'll simply cover a piece of code through which you can get all the data from server and then show it in the form of a automatic carousel (ticker). So, let's start with the code.

var initTicker = function(wrapperDiv, dataDiv, elementHeight, elementsToBeShown){
    $.get('getFeeds.php', function(data) {
        $('#'+dataDiv).html(data);
        var outerDiv = $('<div id="outerDiv"></div>').hide();       
        outerDiv.css({
                      'width': $("#activites").width(), 
                      'height': elementHeight*elementsToBeShown + 10,
                      'overflow': 'hidden'
                    });
        outerDiv.append($("#"+dataDiv));
        outerDiv.show();
        $("#"+wrapperDiv).append(outerDiv);         
        setInterval( function () { moveItUp(dataDiv, elementHeight) }, 7000); 
  });
}

In the above code, the data is basically provided from getFeeds.php.
wrapperDiv contains the id of the div which contains the div in which data is to be displayed. (A better approach is to create this wrapper div at run time and place the div in which data is to be shown inside the wrapper... for the sake of simplicity i am not including that code here)
dataDiv contains the id of the div in which data is to be shown
elementHeight height of one news element (again this can be determined through a simple javascript)
elementsToBeShown number of elements that you want to show on screen at a time.
 
a simple HTML snippet is


<div id="wrapper">
      <div id="activities">
      </div>
</div>

Now, before i move forward, let me just quickly explain what the above js code is doing. For explanation, i am gonna be using the divs shown in shown html snippet. A step by step explanation is:

1. Get the data from server and place the data in "activities"
2. Create a div at run time and set its width equal to the width of "activities" since we want the ticker to move vertically. Set the height of the div equal to the elementHeight*elementsToBeShown. Add some padding on the height side to get a smooth effect.. Set the overflow to hidden. Now, i'll get back to this point that why do we need the "overflow" property to be hidden.
3. Place the "activities" div inside "outerDiv"
4. Initiate the function which is supposed to apply the carousel/ticker style. Set the timer value according to your need. In the above code, the ticker will move the feeds every 7 seconds.

Now, let's quickly see what is moveItUp() is doing.

var moveItUp = function(dataDiv, elementHeight){
     var reduceMargin = '-='+elementHeight;
     $("#"+dataDiv).animate({'margin-top': reduceMargin}, 2000); 
}


Ok, this is only a two liner function. The above function is simply decreasing the "margin-top" property of "activities" div (which contains the data) by elementHeight. Now, why elementHeight and what purpose is served by decreasing "margin-top"?? The above function will successfully, move the data one element at a time. If you want to move 2 elements up, simply set reduceMargin to "-="+(2*elementHeight). Now, coming to the second part of question. If you remember, in the initialize code of "outerDiv", i mentioned to set "overflow" property to hidden. If you set "overflow" property to "hidden" of a div (or any element) then you'll see only the data which can fit in the mentioned height and width. So, for example, if a div's height and width are set to 500px, and you place data which requires 800px of height, then you'll only see 500px worth of data and rest will be clipped, there won't be any scrollbar as well. (for those who don't remember overflow property, a quick link http://www.w3schools.com/cssref/pr_pos_overflow.asp). So, in the initialization code, we set the height of the outerDiv to elementHeight*numberOfElements, and "activities" (dataDiv) contains all the data, but since "activities" is inside outerDiv, therefore, only that number of elements are shown on the screen that we passed to initTicker function, rest are clipped (not shown). Now, when we decrease the "margin-top" of "activities" div, it basically moves the data inside div vertically, but since, outerDiv can only contain "numberOfElements" elements on the screen at a time, the next elements in the "activities" div show up and the elements at top disappear. Using the jquery function "animate" we give the margin-top reduction step some nice animation and hence you get an effect of ticker/carousel. 

Tuesday, May 31, 2011

Disable all contents of the page using jQuery

Here is the code to disable all contents of the page. By "disable" i mean that everything on the page will neither be clickable nor any text will be selectable nor right click will work. Here is a simple solution to solve the problem using jQuery

var newDiv = $("<div></div>")
    $(newDiv).css({width: '100%',
                   height: $(document).height()+'px',
                   position: 'absolute',
                   top: '0px',
                   left: '0px',
                   backgroundColor: '#000000',
                   opacity:'0.5'});
    $("body").first().append(newDiv);
    $(document).bind("contextmenu",function(e){
            return false;
    });

}

You can also make a css class for the css attributes mentioned above, the only check is for the "height" , because setting height = 100% won't work. Since, if the page has a scroll bar, then setting height = 100% will only disable the part of the page which is currently in the context and if you scroll down, the rest of the page won't be disabled. If you simply set opacity to 0.0, this will show the page as a normal page but everything on it will be disabled

Sunday, November 21, 2010

mooCarousel... a mootools based generic js carousel script

A mootools based image carousel. This is very lightweight and extremely configurable pluggin. Supports both horizontal and vertical carousels with multiple options. You can change the background color of the carousel, the animation style, animation duration, arrow image themes etc.View at;

http://saadnawaz.github.com/mooCarousel/#demos

Tuesday, October 26, 2010

image height, width with Chrome

If one wants to get the height and width of an image, the simple syntax would be;

var img = document.getElementById("image");
alert("width = "+img.width);
alert("height = "+img.height);

now suppose, i am executing the above javascript code ondomready event. It will work perfectly fine with Opera, firefox and even with IE, however, this won't work under Chrome. The reason is simple, Chrome fires domready event before loading the images. So if you place some images in a html page and some text, you'll see that domready event is fired as soon as text is loaded. Now, since the images are not loaded yet, the above javascript code will return 0 in case of both height and width. The solution is simple, in order to make sure that the above code works under Chrome, execute the code on window.load. Hence, in mootools code, following won't work under chrome (it will display 0 for both height and width);

window.addEvent('domready', function(){
        alert("(in domready)width = "+$('image').getStyle('width') + " height = "+ $('image').getStyle('height'));
       //alert("(in domready)width = "+$('image').width + " height = "+ $('image').height);
    });

The following code will work under Chrome i.e. giving proper height and width of the element;

window.addEvent('load', function(){
        alert("(in load)width = "+$('image').getStyle('width') + " height = "+ $('image').getStyle('height'));
        //alert("(in load)width = "+$('image').width + " height = "+ $('image').height);
    });   

mooPager... a mootools based generic js pagination script

Almost on every web related project, there is a need for displaying data in pages. So, i thought of writing a simple yet generic pagination script which can apply pagination on any type of data including div, images etc.

checkout the demo at following url;

http://saadnawaz.github.com/mooPager/

The source can be downloaded from http://github.com/saadnawaz/mooPager/

Mootools using Events in Class

Following is a simple tutorial on how to use events in a mootools class. Mootools class provide a method to use events in your class. You can simply do that by using the "Implements: Events" in your class declaration. Hence, for new class it should be like following;

var myClass = new Class ({
              Implements: Events,
              initialize: function(elements){
                         //your code
              }
});

and if you want to add the support for events in an existing class, you can use the following syntax;

myClass.implement(Events);

Now, once we have added the support for the events in the class, it's time to see how to add and fire event from a class. Let's assume there is a div with id "el" and there are multiple divs inside this particular div. At the time being, we just want to hook an event on this div "el" and we want the function to fire when mouse is clicked inside the div.

var clicked = function(){
         alert("here");
}
var myClass = new Class ({
              Implements: Events,
              initialize: function(elements){
                         //your code
                         $('el').addEvent('click', this.click.bind(this));

              },
              click: function(){
                       this.fireEvent('click');
              }
});

window.addEvent('domready', function(){
    var obj = new myClass();
    obj.addEvent('click', clicked);
});

the function fireEvent fires all events of the specified type in the Class instance, in our case, it will fire all the events hooked on click. When you run the above code, you'll see that whenever you click inside the "el" div, the function is clicked is called.
Now, let's say we want to change this a bit. We want to get the id of the inner div on which the mouse is clicked. Now, remember we have event delegation, so we don't need to go through each and every element to hook that event. Consider the following code;


var clicked = function(myObj){
     alert("You clicked on div with id = "+myObj.id);
    }
    
    var myClass = new Class ({
          Implements: Events,
          initialize: function(elements){
                     //your code
                     $('el').addEvent('click:relay(div)', this.click.bind(this));
          },
    
          click: function(ev, divObj){
                   this.fireEvent('click', divObj);
          }

});

window.addEvent('domready', function(){
    var obj = new myClass();
    obj.addEvent('click', clicked);
});

Now, in above method, we have passed parameter divObj (the object of the div on which mouse is clicked) through fireEvent. if you want to pass more than one parameters to a function through fireEvent, you'll have to use array i.e. this.fireEvent('click', [arg1, arg2]);. When the above code is executed, it displays the id of the div on which mouse was clicked. See the above script in action on the following url;

 http://jsfiddle.net/vCYmk/1/

Thursday, October 21, 2010

Applying same style on multiple elements in mootool

I have been lately trying to see how to apply same style on multiple elements using mootools. Now, mootools does provide a method for that known as Fx.Elements. Now, if you want to apply only 1 style, use tween on Fx.Elements and if you want to change multiple styles, then use morph. The issue is if you visit the official documentation here you will see that it requires you to know the total number of elements and you have to mention the index number as well. However, what if you want to apply same effect on all the elements and you don't know how many elements there are. The method to do that is fairly simple. Use the following code;

$$('.simpleBox').morph({
height: 50,
opacity: 0.3
});



where simpleBox is the name of the class which is applied on all the elements on which you wanna apply the style/effect. See the following url to see it in action;

http://www.jsfiddle.net/xwUFN/2/

Friday, October 15, 2010

Event Delegation with Mootools

Ever stuck in a situation where you have hundreds of elements and you want to execute same function for each one of them on some event? One possible solution to that approach is simply going through each and every element and hooking the event. However, that is low in performance and doesn't look that elegant. Consider a simple scenerio, there are a lot of images on your page and you want to apply a simple effect that when the mouse is moved on any image, the opacity of the image should be set to 1 and when the mouse is taken out, the opacity is set to 0.4. Let's say that the image is contained in a div with the id "parentDiv". Consider the following code to achieve in a traditional way;

var increaseOpac = function(image){
     image.set({'opacity': 1});
};

var decreaseOpac = function(image){
     image.set({'opacity': 0.4});
};

$$('#parentDiv > img').each(function(img, index){
   img.addEvent('mouseover', increaseOpac.bind(this, img));
   img.addEvent('mouseout', decreaseOpac.bind(this, img));
} );

The above code will work like a charm, however, it's not a good way to do it. This method makes the browser keep track of a lot of work. And if you want to add/remove elements dynamically, then you'll have to hook event on the newly created element as well. Hence, we should go for Event delegation. With event delegation you simply need to add the event on the parent element and it'll delegate it down to it's children. Now, even if you add new element dynamically, since it'll be under the same parent, the event will be automatically apply on it as well. Let's try to achieve the same thing with event delegation;


var increaseOpac = function(event, image){
     image.set({'opacity': 1});
};

var decreaseOpac = function(event, image){
     image.set({'opacity': 0.4});
};

window.addEvent('domready', function(){
    $('parentDiv').addEvent('mouseover:relay(img)', increaseOpac);
    $('parentDiv').addEvent('mouseout:relay(img)', decreaseOpac);
}); 

Now, with event delegation, when the mouse will be moved on any image inside the parentDiv, the event will be fired, however, it will be relayed to the matching selector, which in our case is "img". Another interesting thing is that we don't need to bind any value, the object of the image on which the mouse is moved is sent to the event handler automatically.

For event delegation in mootools, you'll need to download "mootools more" along with mootools core.

Thursday, October 14, 2010

Mootools Function.Bind

There are alot of cases when you need to pass some value to the function you have hooked on an event. For example, consider there is an image. you want to hook an event on the image that when the mouse is moved on the image, a value is passed to the function by which the opacity of the image should be increased. Consider the following code for this;

var opacVal = 0.9;
$('someImage').addEvent('mousemove', 
                        function(element, opacVal){
                            element.set({'opacity': opacVal});
                        }.bind( this, [$('someImage'), opacVal])
                       );

However, there is a problem with above approach. Since, we have forcefully bound the parameters of the function, therefore, the event object is not passed to the function. If you want to pass the event object aswell, then use the bindWithEvent function of mootools. Consider the following code;


var opacVal = 0.9;
$('someImage').addEvent('mousemove', 
                       function(element, opacVal){
                          element.set({'opacity': opacVal});
                          event.stop();
                       }.bindWithEvent( this, [$('someImage'), opacVal])
                       );

Tuesday, October 12, 2010

Change url dynamically through javascript

If you want to change the value of some attribute in the url dynamically through javascript without reloading the page, keep in mind that you can't change the complete url. However, there is one way around. You can change the anchor part of the url dynamically through javascript.

The window.location.hash property sets or returns the value from the anchor part of the url. Hence, if you want to change the value of the anchor, simply use the following syntax;

window.location.hash = "something";

One of the reasons for placing some value in the anchor part of the url dynamically is to make the url shareable. For example, consider you are making a slide show of images. The images are shown on the page without reloading the page and the id of the image being displayed is placed in the anchor part of the url, so that the user may bookmark/share the url and when the url is opened the slide show starts from the image whose id is placed in the url.