This adds two features to rounded corners-
Borders (and specifying a color for the border)
Also allowing RoundedCorners? to fill in the background color. I've found this is very useful for things like lists, which tend to be blocked out rather tightly, leading to holes in the background color.
Most of the modifications are in _setOption, _borderColor, _renderBorder, and _roundCornersImpl. However, there are several more modifications, but mainly for passing the necessary variable along to the right function.
I've also included a small snippet to add to the current example.
Documentation is very limited-
The map passed in to roundClass now has three additonal bindings (all of which default to the appropriate false, etc, if not specified).
fillBG- If set to "true", will fill in the background using the value of the "color" mapping.
border- If set to "true", will create borders.
borderColor- Takes a Color (MochiKit.Visual) which will then be used as the border color. If no border color is specified, defaults to the "color" mapping color.
In MochiKit.Visual.RoundCorners?.prototype (below), the majority of the new code is merely exposing the functionality already in place to be controlled via the mapping.
Modified Code
MochiKit.Visual._RoundCorners = function (e, options) {
var e = MochiKit.DOM.getElement(e);
this._setOptions(options);
var color = this.options.color;
var m = MochiKit.Visual;
if (this.options.color == "fromElement") {
color = m.Color.fromBackground(e);
} else if (!(color instanceof m.Color)) {
color = m.Color.fromString(color);
}
this.isTransparent = (color.asRGB().a <= 0);
var bgColor = this.options.bgColor;
if (this.options.bgColor == "fromParent") {
bgColor = m.Color.fromBackground(e.offsetParent);
} else if (!(bgColor instanceof m.Color)) {
bgColor = m.Color.fromString(bgColor);
}
var borderColor = this.options.borderColor;
if (this.options.borderColor == "fromBackground") {
borderColor = bgColor;
} else if (! (borderColor instanceof m.Color)) {
borderColor = m.Color.fromString(borderColor);
}
this._roundCornersImpl(e, color, bgColor, borderColor);
};
MochiKit.Visual._RoundCorners.prototype = {
"_roundCornersImpl": function (e, color, bgColor, borderColor) {
if (this.options.border) {
this._renderBorder(e, color, borderColor);
}
if (this._isTopRounded()) {
this._roundTopCorners(e, color, bgColor, borderColor);
}
if (this._isBottomRounded()) {
this._roundBottomCorners(e, color, bgColor, borderColor);
}
},
"_renderBorder": function (el, color, borderColor) {
var borderValue = "1px solid " + this._borderColor(borderColor);
var borderL = "border-left: " + borderValue;
var borderR = "border-right: " + borderValue;
var backgroundColor = "";
if(this.options.fillBG){
backgroundColor = "background-color: " + color;
}
var style = "style='" + borderL + ";" + borderR + ";" + backgroundColor + "'";
el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>";
},
"_roundTopCorners": function (el, color, bgColor, borderColor) {
var corner = this._createCorner(bgColor);
for (var i = 0; i < this.options.numSlices; i++) {
corner.appendChild(
this._createCornerSlice(color, bgColor, borderColor, i, "top")
);
}
el.style.paddingTop = 0;
el.insertBefore(corner, el.firstChild);
},
"_roundBottomCorners": function (el, color, bgColor, borderColor) {
var corner = this._createCorner(bgColor);
for (var i = (this.options.numSlices - 1); i >= 0; i--) {
corner.appendChild(
this._createCornerSlice(color, bgColor, borderColor, i, "bottom")
);
}
el.style.paddingBottom = 0;
el.appendChild(corner);
},
"_createCorner": function (bgColor) {
var corner = document.createElement("div");
corner.style.backgroundColor = bgColor.toString();
return corner;
},
"_createCornerSlice": function (color, bgColor, borderColor, n, position) {
var slice = document.createElement("span");
var inStyle = slice.style;
inStyle.backgroundColor = color.toString();
inStyle.display = "block";
inStyle.height = "1px";
inStyle.overflow = "hidden";
inStyle.fontSize = "1px";
var borderColor = this._borderColor(color, borderColor);
if (this.options.border && n == 0) {
inStyle.borderTopStyle = "solid";
inStyle.borderTopWidth = "1px";
inStyle.borderLeftWidth = "0px";
inStyle.borderRightWidth = "0px";
inStyle.borderBottomWidth = "0px";
inStyle.height = "0px";
inStyle.borderColor = borderColor.toString();
} else if (borderColor) {
inStyle.borderColor = borderColor.toString();
inStyle.borderStyle = "solid";
inStyle.borderWidth = "0px 1px";
}
if (!this.options.compact && (n == (this.options.numSlices - 1))) {
inStyle.height = "2px";
}
this._setMargin(slice, n, position);
this._setBorder(slice, n, position);
return slice;
},
"_setOptions": function (options) {
this.options = {
corners : "all",
color : "fromElement",
bgColor : "fromParent",
fillBG : false,
blend : true,
border : false,
borderColor : "fromBackground",
compact : false
};
MochiKit.Base.update(this.options, options);
this.options.numSlices = (this.options.compact ? 2 : 4);
},
"_whichSideTop": function () {
var corners = this.options.corners;
if (this._hasString(corners, "all", "top")) {
return "";
}
var has_tl = (corners.indexOf("tl") != -1);
var has_tr = (corners.indexOf("tr") != -1);
if (has_tl && has_tr) {
return "";
}
if (has_tl) {
return "left";
}
if (has_tr) {
return "right";
}
return "";
},
"_whichSideBottom": function () {
var corners = this.options.corners;
if (this._hasString(corners, "all", "bottom")) {
return "";
}
var has_bl = (corners.indexOf('bl') != -1);
var has_br = (corners.indexOf('br') != -1);
if (has_bl && has_br) {
return "";
}
if (has_bl) {
return "left";
}
if (has_br) {
return "right";
}
return "";
},
"_borderColor": function (color, bgColor) {
if (color == "transparent") {
return bgColor;
} else if (this.options.border) {
return this.options.borderColor;
} else if (this.options.blend) {
return bgColor.blendedColor(color);
}
return "";
},
"_setMargin": function (el, n, corners) {
var marginSize = this._marginSize(n) + "px";
var whichSide = (
corners == "top" ? this._whichSideTop() : this._whichSideBottom()
);
var style = el.style;
if (whichSide == "left") {
style.marginLeft = marginSize;
style.marginRight = "0px";
} else if (whichSide == "right") {
style.marginRight = marginSize;
style.marginLeft = "0px";
} else {
style.marginLeft = marginSize;
style.marginRight = marginSize;
}
},
"_setBorder": function (el, n, corners) {
var borderSize = this._borderSize(n) + "px";
var whichSide = (
corners == "top" ? this._whichSideTop() : this._whichSideBottom()
);
var style = el.style;
if (whichSide == "left") {
style.borderLeftWidth = borderSize;
style.borderRightWidth = "0px";
} else if (whichSide == "right") {
style.borderRightWidth = borderSize;
style.borderLeftWidth = "0px";
} else {
style.borderLeftWidth = borderSize;
style.borderRightWidth = borderSize;
}
},
"_marginSize": function (n) {
if (this.isTransparent) {
return 0;
}
var o = this.options;
if (o.compact && o.blend) {
var smBlendedMarginSizes = [1, 0];
return smBlendedMarginSizes[n];
} else if (o.compact) {
var compactMarginSizes = [2, 1];
return compactMarginSizes[n];
} else if (o.blend) {
var blendedMarginSizes = [3, 2, 1, 0];
return blendedMarginSizes[n];
} else {
var marginSizes = [5, 3, 2, 1];
return marginSizes[n];
}
},
"_borderSize": function (n) {
var o = this.options;
var borderSizes;
if (o.compact && (o.blend || this.isTransparent)) {
return 1;
} else if (o.compact) {
borderSizes = [1, 0];
} else if (o.blend) {
borderSizes = [2, 1, 1, 1];
} else if (o.border) {
borderSizes = [0, 2, 0, 0];
} else if (this.isTransparent) {
borderSizes = [5, 3, 2, 1];
} else {
return 0;
}
return borderSizes[n];
},
"_hasString": function (str) {
for (var i = 1; i< arguments.length; i++) {
if (str.indexOf(arguments[i]) != -1) {
return true;
}
}
return false;
},
"_isTopRounded": function () {
return this._hasString(this.options.corners,
"all", "top", "tl", "tr"
);
},
"_isBottomRounded": function () {
return this._hasString(this.options.corners,
"all", "bottom", "bl", "br"
);
},
"_hasSingleTextChild": function (el) {
return (el.childNodes.length == 1 && el.childNodes[0].nodeType == 3);
}
};
Example
rounded_corners.js
roundClass(null,"roundBorder", {color:"#ccf", fillBG:true, blend:true, border:true, borderColor:Color.fromString("#000")});
index.html
<p class="roundBorder">
MochiKit can also add a border.
<br/>
<br/>and fill background colors on its own- useful for rendering quirks in browsers
</p>