| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 | "use strict";/** * Methods for getting and modifying attributes. * * @module cheerio/attributes */Object.defineProperty(exports, "__esModule", { value: true });exports.toggleClass = exports.removeClass = exports.addClass = exports.hasClass = exports.removeAttr = exports.val = exports.data = exports.prop = exports.attr = void 0;var static_1 = require("../static");var utils_1 = require("../utils");var hasOwn = Object.prototype.hasOwnProperty;var rspace = /\s+/;var dataAttrPrefix = 'data-';/* * Lookup table for coercing string data-* attributes to their corresponding * JavaScript primitives */var primitives = {    null: null,    true: true,    false: false,};// Attributes that are booleansvar rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i;// Matches strings that look like JSON objects or arraysvar rbrace = /^{[^]*}$|^\[[^]*]$/;function getAttr(elem, name, xmlMode) {    var _a;    if (!elem || !utils_1.isTag(elem))        return undefined;    (_a = elem.attribs) !== null && _a !== void 0 ? _a : (elem.attribs = {});    // Return the entire attribs object if no attribute specified    if (!name) {        return elem.attribs;    }    if (hasOwn.call(elem.attribs, name)) {        // Get the (decoded) attribute        return !xmlMode && rboolean.test(name) ? name : elem.attribs[name];    }    // Mimic the DOM and return text content as value for `option's`    if (elem.name === 'option' && name === 'value') {        return static_1.text(elem.children);    }    // Mimic DOM with default value for radios/checkboxes    if (elem.name === 'input' &&        (elem.attribs.type === 'radio' || elem.attribs.type === 'checkbox') &&        name === 'value') {        return 'on';    }    return undefined;}/** * Sets the value of an attribute. The attribute will be deleted if the value is `null`. * * @private * @param el - The element to set the attribute on. * @param name - The attribute's name. * @param value - The attribute's value. */function setAttr(el, name, value) {    if (value === null) {        removeAttribute(el, name);    }    else {        el.attribs[name] = "" + value;    }}function attr(name, value) {    // Set the value (with attr map support)    if (typeof name === 'object' || value !== undefined) {        if (typeof value === 'function') {            if (typeof name !== 'string') {                {                    throw new Error('Bad combination of arguments.');                }            }            return utils_1.domEach(this, function (el, i) {                if (utils_1.isTag(el))                    setAttr(el, name, value.call(el, i, el.attribs[name]));            });        }        return utils_1.domEach(this, function (el) {            if (!utils_1.isTag(el))                return;            if (typeof name === 'object') {                Object.keys(name).forEach(function (objName) {                    var objValue = name[objName];                    setAttr(el, objName, objValue);                });            }            else {                setAttr(el, name, value);            }        });    }    return arguments.length > 1        ? this        : getAttr(this[0], name, this.options.xmlMode);}exports.attr = attr;/** * Gets a node's prop. * * @private * @category Attributes * @param el - Elenent to get the prop of. * @param name - Name of the prop. * @returns The prop's value. */function getProp(el, name, xmlMode) {    if (!el || !utils_1.isTag(el))        return;    return name in el        ? // @ts-expect-error TS doesn't like us accessing the value directly here.            el[name]        : !xmlMode && rboolean.test(name)            ? getAttr(el, name, false) !== undefined            : getAttr(el, name, xmlMode);}/** * Sets the value of a prop. * * @private * @param el - The element to set the prop on. * @param name - The prop's name. * @param value - The prop's value. */function setProp(el, name, value, xmlMode) {    if (name in el) {        // @ts-expect-error Overriding value        el[name] = value;    }    else {        setAttr(el, name, !xmlMode && rboolean.test(name) ? (value ? '' : null) : "" + value);    }}function prop(name, value) {    var _this = this;    if (typeof name === 'string' && value === undefined) {        switch (name) {            case 'style': {                var property_1 = this.css();                var keys = Object.keys(property_1);                keys.forEach(function (p, i) {                    property_1[i] = p;                });                property_1.length = keys.length;                return property_1;            }            case 'tagName':            case 'nodeName': {                var el = this[0];                return utils_1.isTag(el) ? el.name.toUpperCase() : undefined;            }            case 'outerHTML':                return this.clone().wrap('<container />').parent().html();            case 'innerHTML':                return this.html();            default:                return getProp(this[0], name, this.options.xmlMode);        }    }    if (typeof name === 'object' || value !== undefined) {        if (typeof value === 'function') {            if (typeof name === 'object') {                throw new Error('Bad combination of arguments.');            }            return utils_1.domEach(this, function (el, i) {                if (utils_1.isTag(el))                    setProp(el, name, value.call(el, i, getProp(el, name, _this.options.xmlMode)), _this.options.xmlMode);            });        }        return utils_1.domEach(this, function (el) {            if (!utils_1.isTag(el))                return;            if (typeof name === 'object') {                Object.keys(name).forEach(function (key) {                    var val = name[key];                    setProp(el, key, val, _this.options.xmlMode);                });            }            else {                setProp(el, name, value, _this.options.xmlMode);            }        });    }    return undefined;}exports.prop = prop;/** * Sets the value of a data attribute. * * @private * @param el - The element to set the data attribute on. * @param name - The data attribute's name. * @param value - The data attribute's value. */function setData(el, name, value) {    var _a;    var elem = el;    (_a = elem.data) !== null && _a !== void 0 ? _a : (elem.data = {});    if (typeof name === 'object')        Object.assign(elem.data, name);    else if (typeof name === 'string' && value !== undefined) {        elem.data[name] = value;    }}/** * Read the specified attribute from the equivalent HTML5 `data-*` attribute, * and (if present) cache the value in the node's internal data store. If no * attribute name is specified, read *all* HTML5 `data-*` attributes in this manner. * * @private * @category Attributes * @param el - Elenent to get the data attribute of. * @param name - Name of the data attribute. * @returns The data attribute's value, or a map with all of the data attribute. */function readData(el, name) {    var domNames;    var jsNames;    var value;    if (name == null) {        domNames = Object.keys(el.attribs).filter(function (attrName) {            return attrName.startsWith(dataAttrPrefix);        });        jsNames = domNames.map(function (domName) {            return utils_1.camelCase(domName.slice(dataAttrPrefix.length));        });    }    else {        domNames = [dataAttrPrefix + utils_1.cssCase(name)];        jsNames = [name];    }    for (var idx = 0; idx < domNames.length; ++idx) {        var domName = domNames[idx];        var jsName = jsNames[idx];        if (hasOwn.call(el.attribs, domName) &&            !hasOwn.call(el.data, jsName)) {            value = el.attribs[domName];            if (hasOwn.call(primitives, value)) {                value = primitives[value];            }            else if (value === String(Number(value))) {                value = Number(value);            }            else if (rbrace.test(value)) {                try {                    value = JSON.parse(value);                }                catch (e) {                    /* Ignore */                }            }            el.data[jsName] = value;        }    }    return name == null ? el.data : value;}function data(name, value) {    var _a;    var elem = this[0];    if (!elem || !utils_1.isTag(elem))        return;    var dataEl = elem;    (_a = dataEl.data) !== null && _a !== void 0 ? _a : (dataEl.data = {});    // Return the entire data object if no data specified    if (!name) {        return readData(dataEl);    }    // Set the value (with attr map support)    if (typeof name === 'object' || value !== undefined) {        utils_1.domEach(this, function (el) {            if (utils_1.isTag(el))                if (typeof name === 'object')                    setData(el, name);                else                    setData(el, name, value);        });        return this;    }    if (hasOwn.call(dataEl.data, name)) {        return dataEl.data[name];    }    return readData(dataEl, name);}exports.data = data;function val(value) {    var querying = arguments.length === 0;    var element = this[0];    if (!element || !utils_1.isTag(element))        return querying ? undefined : this;    switch (element.name) {        case 'textarea':            return this.text(value);        case 'select': {            var option = this.find('option:selected');            if (!querying) {                if (this.attr('multiple') == null && typeof value === 'object') {                    return this;                }                this.find('option').removeAttr('selected');                var values = typeof value !== 'object' ? [value] : value;                for (var i = 0; i < values.length; i++) {                    this.find("option[value=\"" + values[i] + "\"]").attr('selected', '');                }                return this;            }            return this.attr('multiple')                ? option.toArray().map(function (el) { return static_1.text(el.children); })                : option.attr('value');        }        case 'input':        case 'option':            return querying                ? this.attr('value')                : this.attr('value', value);    }    return undefined;}exports.val = val;/** * Remove an attribute. * * @private * @param elem - Node to remove attribute from. * @param name - Name of the attribute to remove. */function removeAttribute(elem, name) {    if (!elem.attribs || !hasOwn.call(elem.attribs, name))        return;    delete elem.attribs[name];}/** * Splits a space-separated list of names to individual names. * * @category Attributes * @param names - Names to split. * @returns - Split names. */function splitNames(names) {    return names ? names.trim().split(rspace) : [];}/** * Method for removing attributes by `name`. * * @category Attributes * @example * * ```js * $('.pear').removeAttr('class').html(); * //=> <li>Pear</li> * * $('.apple').attr('id', 'favorite'); * $('.apple').removeAttr('id class').html(); * //=> <li>Apple</li> * ``` * * @param name - Name of the attribute. * @returns The instance itself. * @see {@link https://api.jquery.com/removeAttr/} */function removeAttr(name) {    var attrNames = splitNames(name);    var _loop_1 = function (i) {        utils_1.domEach(this_1, function (elem) {            if (utils_1.isTag(elem))                removeAttribute(elem, attrNames[i]);        });    };    var this_1 = this;    for (var i = 0; i < attrNames.length; i++) {        _loop_1(i);    }    return this;}exports.removeAttr = removeAttr;/** * Check to see if *any* of the matched elements have the given `className`. * * @category Attributes * @example * * ```js * $('.pear').hasClass('pear'); * //=> true * * $('apple').hasClass('fruit'); * //=> false * * $('li').hasClass('pear'); * //=> true * ``` * * @param className - Name of the class. * @returns Indicates if an element has the given `className`. * @see {@link https://api.jquery.com/hasClass/} */function hasClass(className) {    return this.toArray().some(function (elem) {        var clazz = utils_1.isTag(elem) && elem.attribs.class;        var idx = -1;        if (clazz && className.length) {            while ((idx = clazz.indexOf(className, idx + 1)) > -1) {                var end = idx + className.length;                if ((idx === 0 || rspace.test(clazz[idx - 1])) &&                    (end === clazz.length || rspace.test(clazz[end]))) {                    return true;                }            }        }        return false;    });}exports.hasClass = hasClass;/** * Adds class(es) to all of the matched elements. Also accepts a `function`. * * @category Attributes * @example * * ```js * $('.pear').addClass('fruit').html(); * //=> <li class="pear fruit">Pear</li> * * $('.apple').addClass('fruit red').html(); * //=> <li class="apple fruit red">Apple</li> * ``` * * @param value - Name of new class. * @returns The instance itself. * @see {@link https://api.jquery.com/addClass/} */function addClass(value) {    // Support functions    if (typeof value === 'function') {        return utils_1.domEach(this, function (el, i) {            if (utils_1.isTag(el)) {                var className = el.attribs.class || '';                addClass.call([el], value.call(el, i, className));            }        });    }    // Return if no value or not a string or function    if (!value || typeof value !== 'string')        return this;    var classNames = value.split(rspace);    var numElements = this.length;    for (var i = 0; i < numElements; i++) {        var el = this[i];        // If selected element isn't a tag, move on        if (!utils_1.isTag(el))            continue;        // If we don't already have classes — always set xmlMode to false here, as it doesn't matter for classes        var className = getAttr(el, 'class', false);        if (!className) {            setAttr(el, 'class', classNames.join(' ').trim());        }        else {            var setClass = " " + className + " ";            // Check if class already exists            for (var j = 0; j < classNames.length; j++) {                var appendClass = classNames[j] + " ";                if (!setClass.includes(" " + appendClass))                    setClass += appendClass;            }            setAttr(el, 'class', setClass.trim());        }    }    return this;}exports.addClass = addClass;/** * Removes one or more space-separated classes from the selected elements. If no * `className` is defined, all classes will be removed. Also accepts a `function`. * * @category Attributes * @example * * ```js * $('.pear').removeClass('pear').html(); * //=> <li class="">Pear</li> * * $('.apple').addClass('red').removeClass().html(); * //=> <li class="">Apple</li> * ``` * * @param name - Name of the class. If not specified, removes all elements. * @returns The instance itself. * @see {@link https://api.jquery.com/removeClass/} */function removeClass(name) {    // Handle if value is a function    if (typeof name === 'function') {        return utils_1.domEach(this, function (el, i) {            if (utils_1.isTag(el))                removeClass.call([el], name.call(el, i, el.attribs.class || ''));        });    }    var classes = splitNames(name);    var numClasses = classes.length;    var removeAll = arguments.length === 0;    return utils_1.domEach(this, function (el) {        if (!utils_1.isTag(el))            return;        if (removeAll) {            // Short circuit the remove all case as this is the nice one            el.attribs.class = '';        }        else {            var elClasses = splitNames(el.attribs.class);            var changed = false;            for (var j = 0; j < numClasses; j++) {                var index = elClasses.indexOf(classes[j]);                if (index >= 0) {                    elClasses.splice(index, 1);                    changed = true;                    /*                     * We have to do another pass to ensure that there are not duplicate                     * classes listed                     */                    j--;                }            }            if (changed) {                el.attribs.class = elClasses.join(' ');            }        }    });}exports.removeClass = removeClass;/** * Add or remove class(es) from the matched elements, depending on either the * class's presence or the value of the switch argument. Also accepts a `function`. * * @category Attributes * @example * * ```js * $('.apple.green').toggleClass('fruit green red').html(); * //=> <li class="apple fruit red">Apple</li> * * $('.apple.green').toggleClass('fruit green red', true).html(); * //=> <li class="apple green fruit red">Apple</li> * ``` * * @param value - Name of the class. Can also be a function. * @param stateVal - If specified the state of the class. * @returns The instance itself. * @see {@link https://api.jquery.com/toggleClass/} */function toggleClass(value, stateVal) {    // Support functions    if (typeof value === 'function') {        return utils_1.domEach(this, function (el, i) {            if (utils_1.isTag(el)) {                toggleClass.call([el], value.call(el, i, el.attribs.class || '', stateVal), stateVal);            }        });    }    // Return if no value or not a string or function    if (!value || typeof value !== 'string')        return this;    var classNames = value.split(rspace);    var numClasses = classNames.length;    var state = typeof stateVal === 'boolean' ? (stateVal ? 1 : -1) : 0;    var numElements = this.length;    for (var i = 0; i < numElements; i++) {        var el = this[i];        // If selected element isn't a tag, move on        if (!utils_1.isTag(el))            continue;        var elementClasses = splitNames(el.attribs.class);        // Check if class already exists        for (var j = 0; j < numClasses; j++) {            // Check if the class name is currently defined            var index = elementClasses.indexOf(classNames[j]);            // Add if stateValue === true or we are toggling and there is no value            if (state >= 0 && index < 0) {                elementClasses.push(classNames[j]);            }            else if (state <= 0 && index >= 0) {                // Otherwise remove but only if the item exists                elementClasses.splice(index, 1);            }        }        el.attribs.class = elementClasses.join(' ');    }    return this;}exports.toggleClass = toggleClass;
 |