123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- 'use strict';
- const {
- querySelector,
- closestByName,
- detachNodeFromParent,
- } = require('../lib/xast.js');
- const { collectStylesheet, computeStyle } = require('../lib/style.js');
- const { parsePathData } = require('../lib/path.js');
- exports.name = 'removeHiddenElems';
- exports.type = 'visitor';
- exports.active = true;
- exports.description =
- 'removes hidden elements (zero sized, with absent attributes)';
- /**
- * Remove hidden elements with disabled rendering:
- * - display="none"
- * - opacity="0"
- * - circle with zero radius
- * - ellipse with zero x-axis or y-axis radius
- * - rectangle with zero width or height
- * - pattern with zero width or height
- * - image with zero width or height
- * - path with empty data
- * - polyline with empty points
- * - polygon with empty points
- *
- * @author Kir Belevich
- *
- * @type {import('../lib/types').Plugin<{
- * isHidden: boolean,
- * displayNone: boolean,
- * opacity0: boolean,
- * circleR0: boolean,
- * ellipseRX0: boolean,
- * ellipseRY0: boolean,
- * rectWidth0: boolean,
- * rectHeight0: boolean,
- * patternWidth0: boolean,
- * patternHeight0: boolean,
- * imageWidth0: boolean,
- * imageHeight0: boolean,
- * pathEmptyD: boolean,
- * polylineEmptyPoints: boolean,
- * polygonEmptyPoints: boolean,
- * }>}
- */
- exports.fn = (root, params) => {
- const {
- isHidden = true,
- displayNone = true,
- opacity0 = true,
- circleR0 = true,
- ellipseRX0 = true,
- ellipseRY0 = true,
- rectWidth0 = true,
- rectHeight0 = true,
- patternWidth0 = true,
- patternHeight0 = true,
- imageWidth0 = true,
- imageHeight0 = true,
- pathEmptyD = true,
- polylineEmptyPoints = true,
- polygonEmptyPoints = true,
- } = params;
- const stylesheet = collectStylesheet(root);
- return {
- element: {
- enter: (node, parentNode) => {
- // Removes hidden elements
- // https://www.w3schools.com/cssref/pr_class_visibility.asp
- const computedStyle = computeStyle(stylesheet, node);
- if (
- isHidden &&
- computedStyle.visibility &&
- computedStyle.visibility.type === 'static' &&
- computedStyle.visibility.value === 'hidden' &&
- // keep if any descendant enables visibility
- querySelector(node, '[visibility=visible]') == null
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // display="none"
- //
- // https://www.w3.org/TR/SVG11/painting.html#DisplayProperty
- // "A value of display: none indicates that the given element
- // and its children shall not be rendered directly"
- if (
- displayNone &&
- computedStyle.display &&
- computedStyle.display.type === 'static' &&
- computedStyle.display.value === 'none' &&
- // markers with display: none still rendered
- node.name !== 'marker'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // opacity="0"
- //
- // https://www.w3.org/TR/SVG11/masking.html#ObjectAndGroupOpacityProperties
- if (
- opacity0 &&
- computedStyle.opacity &&
- computedStyle.opacity.type === 'static' &&
- computedStyle.opacity.value === '0' &&
- // transparent element inside clipPath still affect clipped elements
- closestByName(node, 'clipPath') == null
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Circles with zero radius
- //
- // https://www.w3.org/TR/SVG11/shapes.html#CircleElementRAttribute
- // "A value of zero disables rendering of the element"
- //
- // <circle r="0">
- if (
- circleR0 &&
- node.name === 'circle' &&
- node.children.length === 0 &&
- node.attributes.r === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Ellipse with zero x-axis radius
- //
- // https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRXAttribute
- // "A value of zero disables rendering of the element"
- //
- // <ellipse rx="0">
- if (
- ellipseRX0 &&
- node.name === 'ellipse' &&
- node.children.length === 0 &&
- node.attributes.rx === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Ellipse with zero y-axis radius
- //
- // https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRYAttribute
- // "A value of zero disables rendering of the element"
- //
- // <ellipse ry="0">
- if (
- ellipseRY0 &&
- node.name === 'ellipse' &&
- node.children.length === 0 &&
- node.attributes.ry === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Rectangle with zero width
- //
- // https://www.w3.org/TR/SVG11/shapes.html#RectElementWidthAttribute
- // "A value of zero disables rendering of the element"
- //
- // <rect width="0">
- if (
- rectWidth0 &&
- node.name === 'rect' &&
- node.children.length === 0 &&
- node.attributes.width === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Rectangle with zero height
- //
- // https://www.w3.org/TR/SVG11/shapes.html#RectElementHeightAttribute
- // "A value of zero disables rendering of the element"
- //
- // <rect height="0">
- if (
- rectHeight0 &&
- rectWidth0 &&
- node.name === 'rect' &&
- node.children.length === 0 &&
- node.attributes.height === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Pattern with zero width
- //
- // https://www.w3.org/TR/SVG11/pservers.html#PatternElementWidthAttribute
- // "A value of zero disables rendering of the element (i.e., no paint is applied)"
- //
- // <pattern width="0">
- if (
- patternWidth0 &&
- node.name === 'pattern' &&
- node.attributes.width === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Pattern with zero height
- //
- // https://www.w3.org/TR/SVG11/pservers.html#PatternElementHeightAttribute
- // "A value of zero disables rendering of the element (i.e., no paint is applied)"
- //
- // <pattern height="0">
- if (
- patternHeight0 &&
- node.name === 'pattern' &&
- node.attributes.height === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Image with zero width
- //
- // https://www.w3.org/TR/SVG11/struct.html#ImageElementWidthAttribute
- // "A value of zero disables rendering of the element"
- //
- // <image width="0">
- if (
- imageWidth0 &&
- node.name === 'image' &&
- node.attributes.width === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Image with zero height
- //
- // https://www.w3.org/TR/SVG11/struct.html#ImageElementHeightAttribute
- // "A value of zero disables rendering of the element"
- //
- // <image height="0">
- if (
- imageHeight0 &&
- node.name === 'image' &&
- node.attributes.height === '0'
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Path with empty data
- //
- // https://www.w3.org/TR/SVG11/paths.html#DAttribute
- //
- // <path d=""/>
- if (pathEmptyD && node.name === 'path') {
- if (node.attributes.d == null) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- const pathData = parsePathData(node.attributes.d);
- if (pathData.length === 0) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // keep single point paths for markers
- if (
- pathData.length === 1 &&
- computedStyle['marker-start'] == null &&
- computedStyle['marker-end'] == null
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- return;
- }
- // Polyline with empty points
- //
- // https://www.w3.org/TR/SVG11/shapes.html#PolylineElementPointsAttribute
- //
- // <polyline points="">
- if (
- polylineEmptyPoints &&
- node.name === 'polyline' &&
- node.attributes.points == null
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- // Polygon with empty points
- //
- // https://www.w3.org/TR/SVG11/shapes.html#PolygonElementPointsAttribute
- //
- // <polygon points="">
- if (
- polygonEmptyPoints &&
- node.name === 'polygon' &&
- node.attributes.points == null
- ) {
- detachNodeFromParent(node, parentNode);
- return;
- }
- },
- },
- };
- };
|