removeUnknownsAndDefaults.js 4.85 KB
'use strict';

exports.type = 'perItem';

exports.active = true;

exports.description = 'removes unknown elements content and attributes, removes attrs with default values';

exports.params = {
    unknownContent: true,
    unknownAttrs: true,
    defaultAttrs: true,
    uselessOverrides: true,
    keepDataAttrs: true,
    keepAriaAttrs: true,
    keepRoleAttr: false
};

var collections = require('./_collections'),
    elems = collections.elems,
    attrsGroups = collections.attrsGroups,
    elemsGroups = collections.elemsGroups,
    attrsGroupsDefaults = collections.attrsGroupsDefaults,
    attrsInheritable = collections.inheritableAttrs,
    applyGroups = collections.presentationNonInheritableGroupAttrs;

// collect and extend all references
for (var elem in elems) {
    elem = elems[elem];

    if (elem.attrsGroups) {
        elem.attrs = elem.attrs || [];

        elem.attrsGroups.forEach(function(attrsGroupName) {
            elem.attrs = elem.attrs.concat(attrsGroups[attrsGroupName]);

            var groupDefaults = attrsGroupsDefaults[attrsGroupName];

            if (groupDefaults) {
                elem.defaults = elem.defaults || {};

                for (var attrName in groupDefaults) {
                    elem.defaults[attrName] = groupDefaults[attrName];
                }
            }
        });

    }

    if (elem.contentGroups) {
        elem.content = elem.content || [];

        elem.contentGroups.forEach(function(contentGroupName) {
            elem.content = elem.content.concat(elemsGroups[contentGroupName]);
        });
    }
}

/**
 * Remove unknown elements content and attributes,
 * remove attributes with default values.
 *
 * @param {Object} item current iteration item
 * @param {Object} params plugin params
 * @return {Boolean} if false, item will be filtered out
 *
 * @author Kir Belevich
 */
exports.fn = function(item, params) {

    // elems w/o namespace prefix
    if (item.isElem() && !item.prefix) {

        var elem = item.elem;

        // remove unknown element's content
        if (
            params.unknownContent &&
            !item.isEmpty() &&
            elems[elem] && // make sure we know of this element before checking its children
            elem !== 'foreignObject' // Don't check foreignObject
        ) {
            item.content.forEach(function(content, i) {
                if (
                    content.isElem() &&
                    !content.prefix &&
                    (
                        (
                            elems[elem].content && // Do we have a record of its permitted content?
                            elems[elem].content.indexOf(content.elem) === -1
                        ) ||
                        (
                            !elems[elem].content && // we dont know about its permitted content
                            !elems[content.elem] // check that we know about the element at all
                        )
                    )
                ) {
                    item.content.splice(i, 1);
                }
            });
        }

        // remove element's unknown attrs and attrs with default values
        if (elems[elem] && elems[elem].attrs) {

            item.eachAttr(function(attr) {

                if (
                    attr.name !== 'xmlns' &&
                    (attr.prefix === 'xml' || !attr.prefix) &&
                    (!params.keepDataAttrs || attr.name.indexOf('data-') != 0) &&
                    (!params.keepAriaAttrs || attr.name.indexOf('aria-') != 0) &&
                    (!params.keepRoleAttr || attr.name != 'role')
                ) {
                    if (
                        // unknown attrs
                        (
                            params.unknownAttrs &&
                            elems[elem].attrs.indexOf(attr.name) === -1
                        ) ||
                        // attrs with default values
                        (
                            params.defaultAttrs &&
                            !item.hasAttr('id') &&
                            elems[elem].defaults &&
                            elems[elem].defaults[attr.name] === attr.value && (
                                attrsInheritable.indexOf(attr.name) < 0 ||
                                !item.parentNode.computedAttr(attr.name)
                            )
                        ) ||
                        // useless overrides
                        (
                            params.uselessOverrides &&
                            !item.hasAttr('id') &&
                            applyGroups.indexOf(attr.name) < 0 &&
                            attrsInheritable.indexOf(attr.name) > -1 &&
                            item.parentNode.computedAttr(attr.name, attr.value)
                        )
                    ) {
                        item.removeAttr(attr.name);
                    }
                }

            });

        }

    }

};