Thursday, July 16, 2009

JavaScript & DHTML Tooltips

Sometimes with a lot of links on your webpage you need to display a small description about the link targets. HTML supports title attribute for links which is displayed as tooltip, but it is not customizable and most browsers takes a while to display it. I have created an easy to use DHTML tooltip script for HTML links which requires no extra coding at all. For displaying tooltip for a certain link you just need to include a tooltip attribute in that link, rest everything is handled by the JavaScript code. For Example:

<a href="" tooltip="Your tooltip text goes here">Your Link</a>

I have designed the tooltip script in such a manner that it automatically scans all the links with tooltip attribute when the page loads for the first time and assigns mouse events to all those links. The tooltip is always displayed at the bottom right corner of the link text/image. If there is not enough space to the right or bottom of the link, the tooltip is moved to left or top corner of the link text accordingly. This is how the tooltips are displayed on the page:

JavaScript DHTML Tooltips

Because it is an automated and generic script, all the tooltips on a page will be of same color, style and width. To change the width of your tooltips, you can modify the value of the variable TooltipWidth in the JavaScript code. You can place the JavaScript code into the head section of your page or a separate file. Here is the JavaScript code for the tooltips:

<script type="text/javascript">
var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    }
};

var TooltipWidth = 200; // set width for the tooltip
var Tooltip =
{
    init: function() {
        var links = document.getElementsByTagName("a"); // scan all the links
        for (var i = 0; i < links.length; i++) {
            var tooltip = links[i].getAttribute("tooltip"); // get tooltip attribute
            if (tooltip && tooltip.length > 0) // if tooltip attribute exists
            {     // assign events to links with tooltips
                document.links[i].onmouseover = function() { Tooltip.showTip(this); };
                document.links[i].onfocus = function() { Tooltip.showTip(this); };
                document.links[i].onmouseout = function() { Tooltip.hideTip(); };
                document.links[i].onblur = function() { Tooltip.hideTip(); };
            }
        }
    },
    showTip: function(mylink) { // show tooltip
        Tooltip.hideTip(); // hide existing tooltips
        // create tooltip div
        var tooltip_div = document.createElement("div");
        tooltip_div.id = "mytooltip";
        tooltip_div.className = "tooltip";
        tooltip_div.style.width = TooltipWidth + "px";
        document.body.appendChild(tooltip_div);
        tooltip_div.innerHTML = mylink.getAttribute("tooltip");
        tooltip_div.style.left = Tooltip.tipX(mylink.offsetLeft, mylink.offsetWidth, tooltip_div.offsetWidth) + "px";
        tooltip_div.style.top = Tooltip.tipY(mylink.offsetTop, mylink.offsetHeight, tooltip_div.offsetHeight) + "px";
    },
    hideTip: function() { // hide tooltip
        var tooltip_div = document.getElementById("mytooltip");
        if (tooltip_div) document.body.removeChild(tooltip_div);
    },
    tipX: function(offLeft, offWidth, TooltipWidth) { // X coordinate of tooltip
        return ((offLeft + offWidth + TooltipWidth) > PageWidth()) ? offLeft - TooltipWidth : offLeft + offWidth;
    },
    tipY: function(offTop, offHeight, TooltipHeight) { // Y coordinate of tooltip
        return ((offTop + offHeight + TooltipHeight) > PageHeight()) ? offTop - TooltipHeight : offTop + offHeight;
    }
};

function PageWidth() { // return Page Width
    return window.innerWidth ? window.innerWidth : document.documentElement ? document.documentElement.clientWidth : document.body ? document.body.clientWidth : 0;
}
function PageHeight() { // return Page Height
    return window.innerHeight ? window.innerHeight : document.documentElement ? document.documentElement.clientHeight : document.body ? document.body.clientHeight : 0;
}
// Instantiate Tooltip event on window load
EventUtil.addHandler(window, "load", Tooltip.init);
</script>

Here is the CSS code for the tooltip, you can modify this to suit the color and styling of your website:

<style type="text/css">
<!--
.tooltip {
      position: absolute;
      background-color: #FFFFD9;
      border: 1px solid #FC0;
      padding: 5px;
      font-family: Verdana, Geneva, sans-serif;
      font-size: x-small;
      color: #930;
      text-align: justify;
}
-->
</style>

For simplicity I have positioned the tooltips relative to the link location on the page. To display it at the exact mouse location you can pass the event variable to the Tooltip.showTip function and display the tooltip at event.clientX and event.clientY position.

Technorati Tags: ,

Wednesday, July 8, 2009

JavaScript Context Menu

Apart from regular event handlers like mouse and keyboard events, the DOM-compliant browsers also provides a contextmenu event to specifically indicate when context menu is about to be displayed. This allows you to cancel the default context menu and provide you own menu to the users. Your personal context menu will be very helpful to your visits for navigation on your website. Here is a sample of how the context menu would look like:
JavaScript Context MenuFor event handing I have used the code from my previous post on Cross-Browser Event Handler. Rest of the code for contextmenu event is pretty straight-forward and easy to modify. Two events are added to the page when it loads for the first time; first one to display the context menu and second one to close the context menu when the user clicks anywhere else on the window. Here is the complete JavaScript code for the context menu:

<script type="text/javascript">
var EventUtil = {
      addHandler: function(element, type, handler){
            if (element.addEventListener){
                  element.addEventListener(type, handler, false);
            } else if (element.attachEvent){
                  element.attachEvent("on" + type, handler);
            } else {
                  element["on" + type] = handler;
            }
      },
      removeHandler: function(element, type, handler){
            if (element.removeEventListener){
                  element.removeEventListener(type, handler, false);
            } else if (element.detachEvent){
                  element.detachEvent("on" + type, handler);
            } else {
                  element["on" + type] = null;
            }
      },
      getEvent: function(event){
            return event ? event : window.event;
      },    
      getTarget: function(event){
            return event.target || event.srcElement;
      },
      preventDefault: function(event){
            if (event.preventDefault){
                  event.preventDefault();
            } else {
            event.returnValue = false;
            }
      },
      stopPropagation: function(event){
            if (event.stopPropagation){
                  event.stopPropagation();
            } else {
                  event.cancelBubble = true;
            }
      }
};

// Add contextmenu event to document on page load
EventUtil.addHandler(window, "load", function(event){
      // Add contextmenu event to document
      EventUtil.addHandler(document, "contextmenu", function(event){
            EventUtil.preventDefault(event); // Prevent default context menu
            var menu = document.getElementById("ContextMenu");
            menu.style.left = event.clientX + "px"; //Context Menu X location
            menu.style.top = event.clientY + "px"; //Context Menu Y location
            menu.style.visibility = "visible";  //Make Context Menu visible
      });
      // Add click event to document for closing contextmenu
      EventUtil.addHandler(document, "click", function(event){
            // Hide Context Menu
            document.getElementById("ContextMenu").style.visibility = "hidden";
      });
});
</script>

Here is the CSS Code for the Context Menu. You can modify the Menu CSS to match the color and styling of your website:

<style type="text/css">
<!--
#ContextMenu {
      position: absolute;
      visibility: hidden;
      margin: 0px;
      padding: 0px;
      border: 3px outset #E4E4E4;
}
#ContextMenu li{
      list-style-image: none;
      list-style-type: none;
}
#ContextMenu li a{
      font-family: Verdana, Geneva, sans-serif;
      font-size: small;
      color: #333;
      padding-top: 2px;
      padding-right: 20px;
      padding-bottom: 2px;
      padding-left: 20px;
      display: block;
      text-decoration: none;
      cursor: default;
}
#ContextMenu li a:hover{
      background-color: #E4E4E4;
}
#ContextMenu li.divider{
      border: 1px solid #DDD;
      margin: 2px;
}
-->
</style>

Put the JavaScript and CSS code inside the head section of your HTML page.

The HTML code for the context menu is simply an unordered list (ul) of links. To insert divider between the menu items you can simply use a list item (li) with divider class as shown below. I have created links for some of the basic functionalities on a webpage context menu like back, forward and refresh. For adding new items to the menu simply add a link inside a new list item. The HTML code for your context menu can be placed anywhere inside the HTML page body:

<ul id="ContextMenu">
      <li><a href="javascript:history.go(-1)">Back</a></li>
      <li><a href="javascript:history.go(1)">Forward</a></li>
      <li><a href="javascript:location.reload(true)">Refresh</a></li>
      <li class="divider"></li>
      <li><a href="">My Homepage</a></li>
      <li><a href="">My Blog</a></li>
      <li><a href="">My Link 1</a></li>
      <li><a href="">My Link 2</a></li>
      <li class="divider"></li>
      <li><a href="mailto:youremail@mail.com">Email me</a></li>
</ul>

Note: This DOM event may not be supported by all the browsers.

Technorati Tags:

Tuesday, July 7, 2009

Cross-Browser Event Handler

Events are certain actions performed either by the user or by the browser itself such as mouse clicks, page load etc. A function that is called in response to an event is called an event handler (or an event listener).

DOM Level 2 Events defines two methods to deal with the assignment and removal of event handlers: addEventListener() and removeEventListener(). These methods exist on all DOM nodes and accept three arguments: the event name to handle, the event handler function, and a Boolean value indicating whether to call the event handler during the capture phase (true) or during the bubble phase (false).

IE implements methods similar to the DOM called attachEvent() and detachEvent(). These methods accept the same two arguments: the event handler name and the event handler function. Since IE only supports event bubbling, event handlers added using attachEvent() are attached on the bubbling phase.

To implement event handing in a cross-browser way we need to implement a separate library to implement both types of event handlers appropriately. Here is the JavaScript code to implement a cross-browser event handler:

<script type="text/javascript">
var EventUtil = {
      addHandler: function(element, type, handler){
            if (element.addEventListener){
                  element.addEventListener(type, handler, false);
            } else if (element.attachEvent){
                  element.attachEvent("on" + type, handler);
            } else {
                  element["on" + type] = handler;
            }
      },
     
      removeHandler: function(element, type, handler){
            if (element.removeEventListener){
                  element.removeEventListener(type, handler, false);
            } else if (element.detachEvent){
                  element.detachEvent("on" + type, handler);
            } else {
                  element["on" + type] = null;
            }
      },
     
      getEvent: function(event){
            return event ? event : window.event;
      },
     
      getTarget: function(event){
            return event.target || event.srcElement;
      },
     
      preventDefault: function(event){
            if (event.preventDefault){
                  event.preventDefault();
            } else {
            event.returnValue = false;
            }
      },
     
      stopPropagation: function(event){
            if (event.stopPropagation){
                  event.stopPropagation();
            } else {
                  event.cancelBubble = true;
            }
      }
};
</script>

Examples:

To add events to HTML elements you can use this as follows:
var btn = document.getElementById(“myButton”);
var handler = function(){ alert(“Clicked”); };
EventUtil.addHandler(btn, “click”, handler);

This will display an alert every time myButton is clicked.

getEvent() returns a reference to the event object:
btn.onclick = function(event){
event = EventUtil.getEvent(event);
};

getTarget() which returns the target of the event:
btn.onclick = function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
};

preventDefault() stops the default behavior of an event:
var link = document.getElementById(“myLink”);
link.onclick = function(event){
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
};

Technorati Tags: