Template:cssinfo

<%
/*
  Displays general information about a CSS property or descriptor

  $0 - property/descriptor name - defaults to the slug name
  $1 - @-rule - defaults to the @-rule within the URL
*/

var slug = env.slug;
var name = $0 || (slug ? slug.split("/").pop().toLowerCase() :
    "preview-wiki-content");
var atRule = $1;

var data = string.deserialize(template("CSSData"));
var formattedError = "<span style=\"color:red;\">$1$</span>";
var commonLocalStrings = string.deserialize(template("L10n:Common"));
var locale = env.locale;
var escapeQuotes = mdn.escapeQuotes;
var localize = mdn.getLocalString;
var localizeString = mdn.localString;
var replacePlaceholders = mdn.replacePlaceholders;
var localWiki = wiki;
var currentPage = page;

var cssLocalStrings = string.deserialize(template("L10n:CSS"));
var localStrings = string.deserialize(template("L10n:CSSData"));

/*
  Creates a link to another API, e.g. a CSS property or SVG element

  This function is used as a workaround for not being able to call other
  templates like 'cssxref' from within functions (see https://bugzil.la/939214)

  apiName - Name of the API to link to
  area - Area of the API (i.e. CSS, SVG, etc.)
  linkName - String to use as link label
*/
function createLink(apiName, area, linkName) {
    var formattedLinkName = linkName || apiName;
    var url = "/" + locale + "/docs/Web/" + (area || "CSS") + "/" + apiName;
    var thisPage = localWiki.getPage(url);

    if (currentPage.hasTag(thisPage, "CSS Function")) {
        formattedLinkName += "()";
    } else if (currentPage.hasTag(thisPage, "CSS Data Type") ||
        currentPage.hasTag(thisPage, "Element")) {
        formattedLinkName = "&lt;" + formattedLinkName + "&gt;";
    }

    var summary = (thisPage && thisPage.summary) ?
        escapeQuotes(thisPage.summary) :
        localize(commonLocalStrings, "summary");

    return "<a href=\"" + url + "\"" +
        (summary ? " title=\"" + summary + "\"" : "") + "><code>" +
        formattedLinkName + "</code></a>";
}


/*
  Parses all macros within a string

  string - String to parse
*/
function parseMacros(string) {
    if (string === undefined) {
        return undefined;
    }

    var apiName = "";
    var area = "";
    var parsedString = string;
    parsedString = parsedString.replace(/\{\{(.+?)(?:\((.+?)\))?\}\}/g,
        function (match, macroName, paramsString) {
            var params = paramsString ? paramsString.split(/, ?/) : [];
            params.forEach(function(param, index, params) {
              params[index] = params[index].toLowerCase().slice(1, -1);
            });
            var apiName = (params.length !== 0 ? params[0] : "");
            switch (macroName.toLowerCase()) {
                case "xref_csslength":
                    apiName = "length";
                    area = "CSS";
                    break;

                case "xref_cssangle":
                    apiName = "angle";
                    area = "CSS";
                    break;

                case "svgelement":
                    area = "SVG/Element";
                    break;

                default:
                    area = "CSS";
            }

            return createLink(apiName, area, params[1]);
        }
    );
    return parsedString;
}


/*
  Appends information about to which pseudo-elements a CSS property applies to
  the output to which normal elements it applies

  output - Current value output
  property - CSS info item name
  cssInfo - Structure containing information about a CSS property
*/
function addAdditionalAppliesToOutput(output, property, cssInfo) {
    if (property !== "appliesto" || !cssInfo.hasOwnProperty("alsoAppliesTo")) {
        return output;
    }

    var additionalApplies = "";
    // Remove '::placeholder' from array to avoid displaying it,
    // because it's not standardized yet
    var placeholderIndex = cssInfo.alsoAppliesTo.indexOf("::placeholder");
    if (placeholderIndex !== -1) {
      cssInfo.alsoAppliesTo.splice(placeholderIndex, 1);
    }

    // In case there are no items left, the output is returned unchanged
    if (cssInfo.alsoAppliesTo.length === 0) {
      return output;
    }

    cssInfo.alsoAppliesTo.forEach(function(element, index, elements) {
        additionalApplies += "{{cssxref(\"" + element + "\")}}";

        if (index < elements.length - 2) {
            additionalApplies += localize(localStrings, "listSeparator");
        } else if (index < elements.length - 1) {
            additionalApplies += localize(localStrings, "andInEnumeration");
        }
    });

    return replacePlaceholders(localize(localStrings, "applyingToMultiple"),
        [output, additionalApplies]);
}


/*
  Parses all macros within a string

  string - String to parse
*/
function getValueOutput(cssInfo, property, atRule) {
    if (property === "relatedAtRule") {
        var url = "/" + locale + "/docs/Web/CSS/" + atRule;
        var page = localWiki.getPage(url);
        var summary = (page && page.summary) ? escapeQuotes(page.summary) :
            localize(commonLocalStrings, "summary");

        return "<a href=\"/" + locale + "/docs/Web/CSS/" + atRule +
            "\" title=\"" + summary + "\"><code>" + atRule + "</code></a>";
    }

    var value = cssInfo[property];
    if (typeof value === "string") {
        var propMatches = value.match(/^'(.+?)'$/);
        if (propMatches) {
            return getValueOutput(data.properties[propMatches[1]], property);
        } else {
            if (property === "initial" && value[0] === "<") {
                return value;
            } else {
                var keywords = value.split(", ");
                var replacedKeywords = keywords.map(function(keyword) {
                    return localize(localStrings, keyword);
                });
        
                var output = addAdditionalAppliesToOutput(
                    replacedKeywords.join(", "), property, cssInfo);
                return parseMacros(output);
            }
        }
    } else if (Array.isArray(value)) {
        var output = localize(localStrings, "asLonghands") + "<br/>" +
        "<ul>";
        value.forEach(function(longhand) {
            output += "<li>{{cssxref(\"" + longhand + "\")}}: " +
                (data.properties.hasOwnProperty(longhand) ?
                    getValueOutput(data.properties[longhand], property) :
                    replacePlaceholders(formattedError,
                        [localize(cssLocalStrings, "missing")])) +
                "</li>";
        });
        output += "</ul>";

        return parseMacros(addAdditionalAppliesToOutput(output, property,
            cssInfo));
    } else if (typeof value === "object") {
        var note = value.note || "";
        var output = "";
        if (property === "animatable" && value.hasOwnProperty("as") &&
            value.as !== "yes") {
            var animatableValues = value.as.split(" ");
            var parsedAnimtableValues =
                animatableValues.map(function(animatableValue) {
                    var localizedString = localize(localStrings,
                        animatableValue);
                    if (animatableValue === "lpc") {
                        localizedString = replacePlaceholders(localizedString,
                            [localize(localStrings, "length")]);
                        note = localize(localStrings, "lpcNote") + note;
                    }
                    return localizedString;
                });

            output = replacePlaceholders(localize(localStrings, "yesAs"),
                [parsedAnimtableValues.join(localize(localStrings,
                    "listSeparator")), note]);
        } else {
            output = localizeString(value);
        }

        return parseMacros(addAdditionalAppliesToOutput(output, property,
            cssInfo)); 
    } else if (typeof value === "boolean") {
        return localize(localStrings, value ? "yes" : "no"); 
    } else if (typeof value === "undefined") {
        return replacePlaceholders(formattedError, [localize(cssLocalStrings,
            "missing")]);
    }

    return parseMacros(value);
}


var cssInfo = null;

if (!atRule) {
    var matches = null;
    if (slug) {
        matches = slug.match(/\/CSS\/(@.+?)(?=\/)/);
    }

    if (matches) {
        atRule = matches[1];
    }
}

if (name !== "preview-wiki-content") {
    if (atRule) {
        if (data.atRules[atRule] && data.atRules[atRule].descriptors) {
            cssInfo = data.atRules[atRule].descriptors[name];
        }
    } else if (data.properties[name]) {
        cssInfo = data.properties[name];
    }
}

var result = "";

if (name === "preview-wiki-content") {
    result = "<span style=\"color:red;\">CSS info in preview not " +
        "available</span>";
} else if (cssInfo) {
    result = "<table class=\"properties\">" +
        "<tbody>";
    var properties = [];
    if (atRule) {
        properties = properties.concat({
            name: "relatedAtRule",
            label: localize(localStrings, "relatedAtRule")
        });
    }

    properties = properties.concat({
        name: "initial",
        label: template("Xref_cssinitial")
    });

    if (!atRule) {
        properties = properties.concat({
            name: "appliesto",
            label: localize(localStrings, "appliesTo")
        });
    }

    if (cssInfo.hasOwnProperty("inherited")) {
        properties = properties.concat({
            name: "inherited",
            label: template("Xref_cssinherited")
        });
    }

    if (cssInfo.percentages !== "no") {
        properties = properties.concat({
            name: "percentages",
            label: localize(localStrings, "percentages")
        });
    }

    properties = properties.concat({
        name: "media",
        label: localize(localStrings, "media")
    },
    {
        name: "computed",
        label: template("Xref_csscomputed")
    });

    if (!atRule) {
        properties = properties.concat({
            name: "animatable",
            label: localize(localStrings, "animatable")
        });
    }

    properties = properties.concat({
        name: "order",
        label: localize(localStrings, "canonicalOrder")
    });

    if (cssInfo.stacking) {
        properties = properties.concat({
            name: "stacking",
            label: localize(localStrings, "createsStackingContext")
        });
    }

    properties.forEach(function(property) {
        result += "<tr>" +
            "<th scope=\"row\">" + property.label + "</th><td>" +
            getValueOutput(cssInfo, property.name, atRule) + "</td>";
    });
    result += "</tbody>" +
        "</table>";
} else {
    result = replacePlaceholders(formattedError,
        [localize(cssLocalStrings, "missing")]);
}
%><%- result %>
Search for pages that use Template:cssinfo to see example use cases and how many pages use this macro.

Document Tags and Contributors

 Contributors to this page: Sebastianz, teoli, fscholz
 Last updated by: Sebastianz,