John Cappiello - Dojo.common-0.4.1

Documentation | Source
dojo.provide("dojo.lfx.rounded");

dojo.require("dojo.lang.common");
dojo.require("dojo.html.common");
dojo.require("dojo.html.style");
dojo.require("dojo.html.display");
dojo.require("dojo.html.layout");

/*	Port of curvyCorners, by Cameron Cooke and Tim Hutchison.
 *	Original port done by Brian Lucas.
 *	Refactor and function by trt.
 */
dojo.lfx.rounded = function(/* object */settings /* ... */){
	//	summary
	//	Creates a set of rounded corners based on settings.
	var options={
		validTags:settings.validTags || ["div"],					//	tags we can apply this to
		autoPad:settings.autoPad!=null ? settings.autoPad : true,		//	automatically pad
		antiAlias:settings.antiAlias!=null ? settings.antiAlias : true,	//	anti-alias corners
		radii:{ 	//	corner radii
			tl:(settings.tl && settings.tl.radius!=null) ? settings.tl.radius:5, 
			tr:(settings.tr && settings.tr.radius!=null) ? settings.tr.radius:5, 
			bl:(settings.bl && settings.bl.radius!=null) ? settings.bl.radius:5, 
			br:(settings.br && settings.br.radius!=null) ? settings.br.radius:5 
		}
	};

	//	get the node list to operate on.
	var nodes;
	if(typeof(arguments[1]) == "string"){
		//	a CSS classname was passed, grab a node list.
		nodes=dojo.html.getElementsByClass(arguments[1]);
	} else if(dojo.lang.isArrayLike(arguments[1])){
		//	we assume that the second argument is an array of nodes to apply this to.
		nodes=arguments[1];
		for(var i=0; i<nodes.length; i++){ nodes[i]=dojo.byId(nodes[i]); }
	}
	if(nodes.length == 0) return;	//	don't bother.

	////////////////////////////////////////////////////////////////////
	for(var i=0; i<nodes.length; i++){
		dojo.lfx.rounded.applyCorners(options, nodes[i]);
	}
};

//	can call this directly if one wants.
dojo.lfx.rounded.applyCorners = function(/* object */options, /* HTMLElement */node){
	//	summary
	//	Rounds corners based on options to passed node.
	var top = null;
	var bottom = null;
	var contentNode = null;
	var fns=dojo.lfx.rounded._fns;

	//	node details
	var width = node.offsetWidth;
	var height = node.offsetHeight;
	var borderWidth = parseInt(dojo.html.getComputedStyle(node, "border-top-width"));
	var borderColor = dojo.html.getComputedStyle(node, "border-top-color");
	var color = dojo.html.getComputedStyle(node, "background-color");
	var bgImage = dojo.html.getComputedStyle(node, "background-image");
	var position = dojo.html.getComputedStyle(node, "position");
	var padding = parseInt(dojo.html.getComputedStyle(node, "padding-top"));

	//	formatting details
	//	TODO: use Dojo equivilents for these if exists.
	var format={
		height : height,
		width : width,
		borderWidth : borderWidth,
		color : fns.getRGB(color),
		padding : padding,
		borderColor : fns.getRGB(borderColor),
		borderString : borderWidth + "px" + " solid " + fns.getRGB(borderColor),
		bgImage : ((bgImage != "none")? bgImage : ""),
		content : node.innerHTML
	};

	if(!dojo.html.isPositionAbsolute(node)){ node.style.position="relative"; }
	node.style.padding="0px";
	if(dojo.render.html.ie && width=="auto" && height=="auto"){ node.style.width="100%"; }
	if(options.autoPad && format.padding>0){
		node.innerHTML="";
	}

	var topHeight=Math.max(options.radii.tl, options.radii.tr);
	var bottomHeight=Math.max(options.radii.bl, options.radii.br);

	//	build the containers.
	if(options.radii.tl || options.radii.tr){
		top = document.createElement("div");
		top.style.width="100%";
		top.style.fontSize="1px";
		top.style.overflow="hidden";
		top.style.position="absolute";
		top.style.paddingLeft=format.borderWidth+"px";
		top.style.paddingRight=format.borderWidth+"px";
		top.style.height=topHeight+"px";
		top.style.top=(0-topHeight)+"px";
		top.style.left=(0-format.borderWidth)+"px";
		node.appendChild(top);
	}
	if(options.radii.bl || options.radii.br){	//	bottom
		bottom = document.createElement("div");
		bottom.style.width="100%";
		bottom.style.fontSize="1px";
		bottom.style.overflow="hidden";
		bottom.style.position="absolute";
		bottom.style.paddingLeft=format.borderWidth+"px";
		bottom.style.paddingRight=format.borderWidth+"px";
		bottom.style.height=bottomHeight+"px";
		bottom.style.bottom=(0-bottomHeight)+"px";
		bottom.style.left=(0-format.borderWidth)+"px";
		node.appendChild(bottom);
	}

	//	turn off the borders
	if(top){ node.style.borderTopWidth = "0px"; }
	if(bottom){ node.style.borderBottomWidth = "0px"; }

	//	do the corners
	var corners = ["tr", "tl", "br", "bl"];
	for(var i=0; i<corners.length; i++){
		var cc=corners[i];
		if(options.radii[cc]==0){
			//	fill up the space with a div.
			if((cc.charAt(0)=="t"&&top) || (cc.charAt(0)=="b"&&bottom)){
				var corner=document.createElement("div");
				corner.style.position="relative";
				corner.style.fontSize="1px;";
				corner.style.overflow="hidden";
				if(format.bgImage==""){
					corner.style.backgroundColor=format.color;
				} else {
					corner.style.backgroundImage=format.bgImage;
				}
				switch(cc){
					case "tl":{
						corner.style.height=topHeight-format.borderWidth+"px";
						corner.style.marginRight=options.radii[cc]-(format.borderWidth*2)+"px";
						corner.style.borderLeft=format.borderString;
						corner.style.borderTop=format.borderString;
						corner.style.left=-format.borderWidth+"px";
						break;
					}
					case "tr":{
						corner.style.height=topHeight-format.borderWidth+"px";
						corner.style.marginLeft=options.radii[cc]-(format.borderWidth*2)+"px";
						corner.style.borderRight=format.borderString;
						corner.style.borderTop=format.borderString;
						corner.style.backgroundPosition="-"+(topHeight-format.borderWidth)+"px 0px";
						corner.style.left=format.borderWidth+"px";
						break;
					}
					case "bl":{
						corner.style.height=bottomHeight-format.borderWidth+"px";
						corner.style.marginRight=options.radii[cc]-(format.borderWidth*2)+"px";
						corner.style.borderLeft=format.borderString;
						corner.style.borderBottom=format.borderString;
						corner.style.left=format.borderWidth+"px";
						corner.style.backgroundPosition="-"+format.borderWidth+"px -"+(format.height+(bottomHeight+format.borderWidth))+"px";
						break;
					}
					case "br":{
						corner.style.height=bottomHeight-format.borderWidth+"px";
						corner.style.marginLeft=options.radii[cc]-(format.borderWidth*2)+"px";
						corner.style.borderRight=format.borderString;
						corner.style.borderBottom=format.borderString;
						corner.style.left=format.borderWidth+"px";
						corner.style.backgroundPosition="-"+(bottomHeight+format.borderWidth)+"px -"+(format.height+(bottomHeight+format.borderWidth))+"px";
						break;
					}
				}
			}
		} else {
			//	NB: this version will not do the caching they built into the
			//		current version of curvyCorners.
			var corner=document.createElement("div");
			corner.style.height=options.radii[cc]+"px";
			corner.style.width=options.radii[cc]+"px";
			corner.style.position="absolute";
			corner.style.fontSize="1px";
			corner.style.overflow="hidden";

			var borderRadius=Math.floor(options.radii[cc] - format.borderWidth);
			for(var x=0, j=options.radii[cc]; x<j; x++){
				//	figure out y coords
				var y1=Math.floor(Math.sqrt(Math.pow(borderRadius,2)-Math.pow((x+1),2)))-1;
				if((x+1) >= borderRadius){ var y1=-1; }
				var y2=Math.ceil(Math.sqrt(Math.pow(borderRadius,2)-Math.pow(x,2)));
				if(x >= borderRadius){ y2=-1; }
				var y3=Math.floor(Math.sqrt(Math.pow(j,2)-Math.pow((x+1),2)))-1;
				if((x+1) >= j){ y3=-1; }
				var y4=Math.ceil(Math.sqrt(Math.pow(j, 2)-Math.pow(x, 2)));
				if(x >= j){ y4=-1; }

				//	start drawing
				if(y1 > -1){
					fns.draw(x, 0, format.color, 100, (y1+1), corner, -1, j, topHeight, format);
				}

				// cycle the y-axis
				for(var y=(y1+1); y<y2; y++){
					if(options.antiAlias){
						if(format.bgImage != ""){
							var fract=fns.fraction(x, y, borderRadius)*100;
							if(fract < 30){
								fns.draw(x, y, format.borderColor, 100, 1, corner, 0, options.radii[cc], topHeight, format);
							} else {
								fns.draw(x, y, format.borderColor, 100, 1, corner, -1, options.radii[cc], topHeight, format);
							}
						} else {
							var clr=fns.blend(format.color, format.borderColor, fns.fraction(x, y, borderRadius));
							fns.draw(x, y, clr, 100, 1, corner, 0, options.radii[cc], topHeight, format);
						}
					}
				}

				//	bar for the border
				if(options.antiAlias){
					if(y3 >= y2){
						if(y2 == -1){ y2 = 0; }
						fns.draw(x, y2, format.borderColor, 100, (y3-y2+1), corner, 0, 0, topHeight, format)
					} else {
						if(y3 >= y1){
							fns.draw(x, (y1+1), format.borderColor, 100, (y3-y1), corner, 0, 0, topHeight, format);
						}
					}
					for(var y=(y3+1); y<y4; y++){
						fns.draw(x, y, format.borderColor, (fns.fraction(x, y, j)*100), 1, corner, (format.borderWidth>0 ? 0:-1), options.radii[cc], topHeight, format);
					}
				} else {
					y3=y1;
				}
			}

			//	reposition pixels if not the bottom right.
			if(cc != "br"){
				for(var t=0, k=corner.childNodes.length; t<k; t++){
					var bar=corner.childNodes[t];
					var barTop = parseInt(dojo.html.getComputedStyle(bar, "top"));
					var barLeft = parseInt(dojo.html.getComputedStyle(bar, "left"));
					var barHeight = parseInt(dojo.html.getComputedStyle(bar, "height"));

					//	reposition.
					if(cc.charAt(1)=="l"){ 
						bar.style.left = (options.radii[cc]-barLeft-1)+"px"; 
					}
					if(cc=="tr"){
						bar.style.top = (options.radii[cc]-barHeight-barTop)+"px";
						bar.style.backgroundPosition="-"+Math.abs((format.width-options.radii[cc]+format.borderWidth)+barLeft)
							+"px -"+Math.abs(options.radii[cc]-barHeight-barTop-format.borderWidth)+"px";
					} else if (cc=="tl"){
						bar.style.top = (options.radii[cc]-barHeight-barTop)+"px";
						bar.style.backgroundPosition="-"+Math.abs((options.radii[cc]-barLeft-1)-format.borderWidth)
							+"px -"+Math.abs(options.radii[cc]-barHeight-barTop-format.borderWidth)+"px";
					} else {
						bar.style.backgroundPosition="-"+Math.abs((options.radii[cc]+barLeft)+format.borderWidth)
							+"px -"+Math.abs((format.height+options.radii[cc]+barTop)-format.borderWidth)+"px";
					}
				}
			}
		}

		if(corner){
			//	position the container.
			var psn=[];
			if(cc.charAt(0)=="t"){ psn.push("top"); }
			else { psn.push("bottom"); }
			if(cc.charAt(1)=="l"){ psn.push("left"); }
			else { psn.push("right"); }
			
			if(corner.style.position=="absolute"){
				for(var z=0; z<psn.length; z++){ corner.style[psn[z]]="0px"; }
			}
			
			if(psn[0]=="top"){ 
				if(top){ top.appendChild(corner); }
			} else {
				if(bottom){ bottom.appendChild(corner); }
			}
		}
	}

	//	draw fillers.
	var diff={ 
		t: Math.abs(options.radii.tl - options.radii.tr),
		b: Math.abs(options.radii.bl - options.radii.br)
	};
	for(var z in diff){
		var smaller=(options.radii[z+"l"]<options.radii[z+"r"] ? z+"l":z+"r");
		var filler=document.createElement("div");
		filler.style.height=diff[z]+"px";
		filler.style.width=options.radii[smaller]+"px";
		filler.style.position="absolute";
		filler.style.fontSize="1px";
		filler.style.overflow="hidden";
		filler.style.backgroundColor=format.color;
		switch(smaller){
			case "tl":{
				filler.style.bottom="0px";
				filler.style.left="0px";
				filler.style.borderLeft=format.borderString;
				top.appendChild(filler);
				break;
			}
			case "tr":{
				filler.style.bottom="0px";
				filler.style.right="0px";
				filler.style.borderRight=format.borderString;
				top.appendChild(filler);
				break;
			}
			case "bl":{
				filler.style.top="0px";
				filler.style.left="0px";
				filler.style.borderLeft=format.borderString;
				bottom.appendChild(filler);
				break;
			}
			case "br":{
				filler.style.top="0px";
				filler.style.right="0px";
				filler.style.borderRight=format.borderString;
				bottom.appendChild(filler);
				break;
			}
		}

		var fillBar=document.createElement("div");
		fillBar.style.position="relative";
		fillBar.style.fontSize="1px";
		fillBar.style.overflow="hidden";
		fillBar.style.backgroundColor=format.color;
		fillBar.style.backgroundImage=format.bgImage;
		if(z=="t"){
			if(top){
				if(options.radii.tl && options.radii.tr){
					fillBar.style.height=(topHeight-format.borderWidth) + "px";
					fillBar.style.marginLeft=(options.radii.tl-format.borderWidth)+"px";
					fillBar.style.marginRight=(options.radii.tr-format.borderWidth)+"px";
					fillBar.style.borderTop=format.borderString;
					if(format.bgImage!=""){
						fillBar.style.backgroundPosition="-"+(topHeight+format.borderWidth)+"px 0px";
					}
				}
				top.appendChild(fillBar);
			}
		} else {
			if(bottom){
				if(options.radii.bl && options.radii.br){
					fillBar.style.height=(bottomHeight-format.borderWidth) + "px";
					fillBar.style.marginLeft=(options.radii.bl-format.borderWidth)+"px";
					fillBar.style.marginRight=(options.radii.br-format.borderWidth)+"px";
					fillBar.style.borderBottom=format.borderString;
					if(format.bgImage!=""){
						fillBar.style.backgroundPosition="-"+(bottomHeight+format.borderWidth)+"px -"
							+ (format.height + (topHeight+format.borderWidth))+"px";
					}
				}
				bottom.appendChild(fillBar);
			}
		}
	}

	//	finally, set up the padding.
	if(options.autoPad && format.padding>0){
		var content=document.createElement("div");
		content.style.position="relative";
		content.innerHTML=format.content;
		content.className="autoPadDiv";
		if(topHeight < format.padding){
			content.style.paddingTop = Math.abs(topHeight-format.padding)+"px";
		}
		if(bottomHeight < format.padding){
			content.style.paddingBottom = Math.abs(bottomHeight-format.padding)+"px";
		}
		content.style.paddingLeft=format.padding+"px";
		content.style.paddingRight=format.padding+"px";
		node.appendChild(content);
	}
};

var count=0;

//	helper methods.
dojo.lfx.rounded._fns={
	blend:function(clr1, clr2, frac){
		var c1={
			r:parseInt(clr1.substr(1,2),16),
			g:parseInt(clr1.substr(3,2),16),
			b:parseInt(clr1.substr(5,2),16)
		};
		var c2={
			r:parseInt(clr2.substr(1,2),16),
			g:parseInt(clr2.substr(3,2),16),
			b:parseInt(clr2.substr(5,2),16)
		};
		if(frac>1||frac<0){ frac=1; }
		var ret=[
			Math.min(Math.max(Math.round((c1.r*frac)+(c2.r*(1-frac))),0),255),
			Math.min(Math.max(Math.round((c1.g*frac)+(c2.g*(1-frac))),0),255),
			Math.min(Math.max(Math.round((c1.b*frac)+(c2.b*(1-frac))),0),255)
		];
		for(var i=0; i<ret.length; i++){
			var n=ret[i].toString(16);
			if(n.length<2){ n="0"+n; }
			ret[i]=n;
		}
		return "#"+ret.join("");
	},
	fraction:function(x, y, r){
		var frac=0;
		var xval=[];
		var yval=[];
		var point=0;
		var whatsides="";

		var intersect=Math.sqrt((Math.pow(r,2)-Math.pow(x,2)));
		if(intersect >=y && intersect < (y+1)){
			whatsides="Left";
			xval[point]=0;
			yval[point++]=intersect-y;
		}

		intersect=Math.sqrt((Math.pow(r,2)-Math.pow(y+1,2)));
		if(intersect >=x && intersect < (x+1)){
			whatsides += "Top";
			xval[point]=intersect-x;
			yval[point++]=1;
		}
		
		intersect=Math.sqrt((Math.pow(r,2)-Math.pow(x+1,2)));
		if(intersect >= y && intersect < (y+1)){
			whatsides += "Right";
			xval[point]=1;
			yval[point++] = intersect-y;
		}

		intersect=Math.sqrt((Math.pow(r,2)-Math.pow(y,2)));
		if(intersect >=x && intersect < (x+1)){
			whatsides += "Bottom";
			xval[point]=intersect-x;
			yval[point]=1;
		}

		switch(whatsides){
			case "LeftRight":
				return Math.min(yval[0],yval[1]) + ((Math.max(yval[0],yval[1])-Math.min(yval[0],yval[1]))/2);
			case "TopRight":
				return 1-(((1-xval[0])*(1-yval[1]))/2);
			case "TopBottom":
				return Math.min(xval[0],xval[1]) + ((Math.max(xval[0],xval[1])-Math.min(xval[0],xval[1]))/2);
			case "LeftBottom":
				return (yval[0]*xval[1])/2;
			default: return 1;
		}
	},
	draw:function(x, y, color, opac, height, corner, image, radius, top, format){
		var px=document.createElement("div");
		px.style.height=height+"px"
		px.style.width="1px";
		px.style.position="absolute";
		px.style.fontSize="1px";
		px.style.overflow="hidden";
		if(image==-1 && format.bgImage!=""){
			px.style.backgroundImage=format.bgImage;
			px.style.backgroundPosition="-"+(format.width-(radius-x)+format.borderWidth)
				+"px -"+((format.height+top+y)-format.borderWidth)+"px";
		} else { 
			px.style.backgroundColor=color; 
		}
		if(opac!=100){ dojo.html.setOpacity(px, (opac/100)); }
		px.style.top=y+"px";
		px.style.left=x+"px";
		corner.appendChild(px);
	},
	getRGB:function(clr){
		var ret="#ffffff";
		if(clr!="" && clr!="transparent"){
			if(clr.substr(0,3)=="rgb"){
				var t=clr.substring(4, clr.indexOf(")"));
				t=t.split(",");
				for(var i=0; i<t.length; i++){
					var n=parseInt(t[i]).toString(16);
					if(n.length<2){ n = "0"+n; }
					t[i]=n;
				}
				ret = "#"+t.join("");
			}
			else if(clr.length==4){
				ret = "#"+clr.substring(1,2)+clr.substring(1,2)
					+ clr.substring(2,3)+clr.substring(2,3)
					+ clr.substring(3,4)+clr.substring(3,4);
			}
			else {
				ret = clr;
			}
		}
		return ret;
	}
};