Ticket #3 (new enhancement)

Opened 3 years ago

Last modified 1 year ago

RoundedCorners Border and Background Fill Support

Reported by: dpitman@gmail.com Assigned to: somebody
Priority: lowest Milestone: MochiKit 1.5
Component: component1 Version:
Severity: normal Keywords: RoundedCorners Border
Cc:

Description

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";
            // assumes css compliant box model
            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>

Attachments

Visual.js (31.9 kB) - added by dpitman@gmail.com on 08/29/05 10:26:12.
Modified Visual.js

Change History

08/29/05 10:26:12 changed by dpitman@gmail.com

  • attachment Visual.js added.

Modified Visual.js

10/10/05 17:08:39 changed by mae

Bob what do you think of this code? I can work on integration if you need me to.

10/28/06 09:55:35 changed by bob@redivi.com

This looks ok, but I won't accept it unless it's turned into a patch against the curren t trunk.

11/18/06 16:10:23 changed by bob@redivi.com

  • priority changed from normal to lowest.

05/14/07 18:43:42 changed by rsayre@mozilla.com

  • milestone set to MochiKit 1.5.

not going to make 1.4