Tuesday, May 29, 2007

Draggable 2

I finally realize that the previous draggable version can be scary. The gadgets will jump out all of a sudden after ALL of them are loaded, which can be very slow depending on the external "application". In this peaceful version, the gadgets appear in the order they are found in the webpage.

To use, copy the code from the last post to one of the first html/javascript page elements in blogger. Enclose anything you want to drag with the <div> tag:

<div id="some_unique_name">
...
your gadget codes
...
</div>

<script> blogTools.init("some_unique_name"); </script>

and add the last <script> line to where you want to start rendering. It can be placed as the first line of the <div> tag. Or you can collect them all to put together in some place, to retain the dramatic effect.

I didn't write a lot of the codes. This version is rewritten to not interfere with anything else in your webpage. The only global parameters are BlogTools and blogTools. FF2 and IE7 compatible.

Draggable 2

<script>
var blogTools = new BlogTools();

function BlogTools(){
this.dragObject = null;
this.mouseOffset = null;
this.init=function(id){
var item=document.getElementById(id);
item.onmousemove = blogTools.mouseMove;
item.onmouseup = blogTools.mouseUp;
item.style.cursor = "move";
item.style.zIndex = "1000";
item.onmousedown = function(ev){
this.style.zIndex="2000";
blogTools.dragObject = this;
blogTools.mouseOffset = blogTools.getMouseOffset(this, ev);
return false;
}
item.ondblclick = function(ev){
blogTools.setCookie(this.id+'top' , "" );
blogTools.setCookie(this.id+'left' , "" );
this.style.display='none';
}
var top = this.getCookie(item.id + "top");
var left = this.getCookie(item.id + "left");
if( (top!="") && (left!="")){
item.style.position = "absolute";
item.style.left = left + "px";
item.style.top = top + "px";
}
}
this.getPosition=function(e){
var left = 0;
var top = 0;
while (e.offsetParent){
left += e.offsetLeft;
top += e.offsetTop;
e = e.offsetParent;
}
left += e.offsetLeft;
top += e.offsetTop;
return {x:left, y:top};
}
this.getMouseOffset=function(target, ev){
ev = ev || window.event;
var docPos = blogTools.getPosition(target);
var mousePos = blogTools.mouseCoords(ev);
return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}
this.mouseCoords=function(ev){
if(ev.pageX || ev.pageY){
return {x:ev.pageX, y:ev.pageY};
}
return {
x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
y:ev.clientY + document.body.scrollTop - document.body.clientTop
};
}
}
BlogTools.prototype.mouseMove=function(ev){
ev = ev || window.event;
var mousePos = blogTools.mouseCoords(ev);
if(blogTools.dragObject){
blogTools.dragObject.style.position = 'absolute';
blogTools.dragObject.style.top = mousePos.y - blogTools.mouseOffset.y + 'px';
blogTools.dragObject.style.left = mousePos.x - blogTools.mouseOffset.x + 'px';
return false;
}
}

BlogTools.prototype.mouseUp=function(ev){
if(blogTools.dragObject){
ev = ev || window.event;
var mousePos = blogTools.mouseCoords(ev);
blogTools.setCookie(blogTools.dragObject.id+'top' , mousePos.y - blogTools.mouseOffset.y, 365);
blogTools.setCookie(blogTools.dragObject.id+'left', mousePos.x - blogTools.mouseOffset.x, 365);
}
blogTools.dragObject.style.zIndex = "1000";
blogTools.dragObject = null;
}

BlogTools.prototype.getCookie=function(c_name)
{
if (document.cookie.length>0)
{
c_start=document.cookie.indexOf(c_name + "=")
if (c_start!=-1)
{
c_start=c_start + c_name.length+1
c_end=document.cookie.indexOf(";",c_start)
if (c_end==-1) c_end=document.cookie.length
return unescape(document.cookie.substring(c_start,c_end))
}
}
return ""
}

BlogTools.prototype.setCookie=function(c_name,value,expiredays)
{
var exdate=new Date()
exdate.setDate(exdate.getDate()+expiredays)
document.cookie=c_name+ "=" +escape(value)+
((expiredays==null) ? "" : ";expires="+exdate.toGMTString())
}
</script>

Friday, May 25, 2007

How to make blog gadgets position customizable

On the right hand side navigation bar, there is an example of a Google gadget for websites for missing persons. To move it to where you want it, move the mouse cursor over it near the edges. When you see the move cursor, you can drag the entire gadget to where you want it. To reset to the default position, double click when you see the move cursor to get rid of the gadget. The gadget will appear in the default position when the page reloads.

It is very simple to make anything draggable, including blogger widgets, and part of your blog, even YouTube embeds.

The simplest way is to enclose anything you want to be draggable by:

<div name="draggable">
... your super duper gadget/widget/embed/text here ...
</div>

The gadget can be dragged, but the position will be reset when the page resets. To remember the positions, you need an unique ID for each gadget:

<div name="draggable" id="missingchildren">
... your super duper gadget/widget/embed/text here ...
</div>

The gadgets will only move from the default position to the custom position after the whole page is loaded, so you can see the transitions. To make the transitions invisible, you need the display:none in the CSS style as follows.

<div name="draggable" id="missingchildren" style="display:none; border: solid thick #eeeeff;">

You do not need to see the move cursor to drag the gadgets. You can drag or double click as long as you are over the gadget. But since most gadgets has some functions associated with it, you may activate the gadget functions doing so. When you see the cross cursor near the edges, you can be sure that only the dragging functions are activated.

To make it easier to drag, you can add a thick border with or without color, so the move cursor appear in more areas. The example border is solid, thick with color code #eeeeff. You can find other borders here.

You don't need to wait for users to drag the gadgets to their desired positions. You can set the initial position to anywhere you want it. You need to add these into the style string:

position: absolute; left:10px; top:50px;

Your gadget will be initially at the top left corner of your browser.

Of course, you need code to make it all work. Copy the code between the script tags, including the tags, from the previous post, into any html/javascript page element in blogger. That's it. I put pure code or html as the first page elements as they need zero time to load. Anything containing external links and access I would put it near the last page elements, so you can start reading without waiting for everything to finish loading.

Draggable code

<script type="text/javascript">
window.onload = setPositionDrag;
document.onmousemove = mouseMove;
document.onmouseup = mouseUp;
var dragObject = null;
var mouseOffset = null;

function setPositionDrag(){
var lst = document.getElementsByTagName("div");
for(var i=0; i < lst.length; i++){
var item = lst[i];
if( item.getAttribute('name') == 'draggable' ){
item.style.cursor = "move";
item.style.display = "inline";
item.style.zIndex = "1000";
item.onmousedown = function(ev){
dragObject = this;
mouseOffset = getMouseOffset(this, ev);
return false;
}
item.ondblclick = function(ev){
if(this.id){
setCookie(this.id+'top' , "" );
setCookie(this.id+'left' , "" );
}
this.style.display='none';
}
if(item.id){
var top = getCookie(item.id + "top");
var left = getCookie(item.id + "left");
if( (top!="") && (left!="")){
item.style.position = "absolute";
item.style.left = left + "px";
item.style.top = top + "px";
}
}
}
}
}

function mouseCoords(ev){
if(ev.pageX || ev.pageY){
return {x:ev.pageX, y:ev.pageY};
}
return {
x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
y:ev.clientY + document.body.scrollTop - document.body.clientTop
};
}
function getMouseOffset(target, ev){
ev = ev || window.event;

var docPos = getPosition(target);
var mousePos = mouseCoords(ev);
return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}

function getPosition(e){
var left = 0;
var top = 0;

while (e.offsetParent){
left += e.offsetLeft;
top += e.offsetTop;
e = e.offsetParent;
}

left += e.offsetLeft;
top += e.offsetTop;

return {x:left, y:top};
}

function mouseMove(ev){
ev = ev || window.event;
var mousePos = mouseCoords(ev);

if(dragObject){
dragObject.style.position = 'absolute';
dragObject.style.top = mousePos.y - mouseOffset.y + 'px';
dragObject.style.left = mousePos.x - mouseOffset.x + 'px';

return false;
}
}
function mouseUp(ev){
if(dragObject){
ev = ev || window.event;
var mousePos = mouseCoords(ev);
setCookie(dragObject.id+'top' , mousePos.y - mouseOffset.y, 365);
setCookie(dragObject.id+'left', mousePos.x - mouseOffset.x, 365);
}
dragObject = null;
}

function getCookie(c_name)
{
if (document.cookie.length>0)
{
c_start=document.cookie.indexOf(c_name + "=")
if (c_start!=-1)
{
c_start=c_start + c_name.length+1
c_end=document.cookie.indexOf(";",c_start)
if (c_end==-1) c_end=document.cookie.length
return unescape(document.cookie.substring(c_start,c_end))
}
}
return ""
}

function setCookie(c_name,value,expiredays)
{
var exdate=new Date()
exdate.setDate(exdate.getDate()+expiredays)
document.cookie=c_name+ "=" +escape(value)+
((expiredays==null) ? "" : ";expires="+exdate.toGMTString())
}

</script>