GithubHelp home page GithubHelp logo

Comments (8)

mgol avatar mgol commented on May 29, 2024

Oh, interesting. Perhaps we should update this list for 4.0 as this can be considered a breaking change.

Or we should get rid of this manual normalization, depending on users doing the right thing here. The biggest issue are possibly falsy checks on values since an empty string is also a valid value. This was also raised by @timmywil in a past issue where I proposed a similar simlification: #2946.

If we're worried about compat for such things, my guess would be we could limit this list to just a few entries like checked & selected. I feel keeping the list open-ended leads us to the same problems as the logic for auto-appending px - the list is never complete and modifying this is both a maintenance burden as well as a potential source of application breakage. (the px behavior was change to have a closed list in #4055)

Our list right now is:

  • checked
  • selected
  • async
  • autofocus
  • autoplay
  • controls
  • defer
  • disabled
  • hidden
  • ismap
  • loop
  • multiple
  • open
  • readonly
  • required
  • scoped

As Richard mentioned, hidden is no longer even correct here but removing it from the list is a compat break so it'd be good to fit it into 4.0.

If we want to keep the logic for at least some attributes, I could see us doing so just for checked & selected; maybe disabled. That said, I'd expect hidden to also be a commonly used one and a good case where our behavior causes issues for future standards changes. If another name from the list gets similar treatment in standards, we won't be able to adjust without another breaking change. It might be more future-proof to give up on this normalization in 4.0 in the end.

Thoughts, @timmywil @gibson042?

from jquery.

mgol avatar mgol commented on May 29, 2024

Tentatively adding it to 4.0.0 blockers so that we don't release before discussing this first.

from jquery.

mgol avatar mgol commented on May 29, 2024

I did a query on GitHub for calls like ".attr('disabled', false)" - and the same for other attributes - to see their popularity. This is not ideal - it only counts one type of quotes, it may not catch some formatting styles but it seems to correlate well with overall popularity. Here are the results with links:

Searches for all the other attributes generated less than 50 results.

I was surprised to see so few uses of the selected setter. Based on the above and on the fact that generalizing the false setter to mean attribute removal could break currently working code which depends on false being stringified to "false", I propose to:

  1. Remove the boolean attribute getter completely - always return the attribute value instead of its name
  2. Remove the boolean attribute setter for all attributes with two exceptions: disabled & checked
  3. For disabled & checked, limit the setter hook to remove for the false value but remove the value normalization - set the value the user provided instead of the attribute name.

Of course, that is a breaking change; the few most common breakages:

  1. The getter may return a different value than in 3.x. If the code compares it directly to the attribute name, it will break.
  2. Even if strict comparison is not used, code may check for the value truthiness. If the setter was used with an empty string, the getter would return a falsy value.

We can add Migrate warnings for both cases.

Thoughts?

from jquery.

gibson042 avatar gibson042 commented on May 29, 2024

Given that any change is breaking for some cases (albeit possibly only hypothetical) and that the current behavior is wrong and will become more wrong over time as HTML expand more currently-boolean attributes to include other values, I am of the opinion that we should remove special treatment for any boolean attribute, generalizing the .attr(name, false) setter to remove any attribute (which is both convenient behavior and important for existing code) and otherwise reflecting the DOM as-is. It would be unnecessarily confusing and inconsistent to privilege only disabled and checked.

from jquery.

mgol avatar mgol commented on May 29, 2024

@gibson042

I am of the opinion that we should remove special treatment for any boolean attribute, generalizing the .attr(name, false) setter to remove any attribute (which is both convenient behavior and important for existing code) and otherwise reflecting the DOM as-is.

I continue to be worried about the same as what I mentioned at one of our meetings - there are attributes with a valid "false" value and lots of code depends on false getting stringified to that value instead of causing the attribute to be deleted. This seems to especially apply to ARIA attributes, see e.g. the search for ".attr('aria-hidden', false)" or ".attr('aria-checked', false)". It's also not just ARIA - the HTML spec mentions a few others in its non-normative Attributes table: contenteditable, enctype, spellcheck, writingsuggestions. I suspect code setting data-* attributes may also depend on false stringification. What if more attributes start treating "false" as a valid value?

There's prior art for us special casing some inputs due to backwards compat even if we preferred to drop the code altogether; the logic when to auto-append px to numeric values in .css() is a good example:

var ralphaStart = /^[a-z]/,
// The regex visualized:
//
// /----------\
// | | /-------\
// | / Top \ | | |
// /--- Border ---+-| Right |-+---+- Width -+---\
// | | Bottom | |
// | \ Left / |
// | |
// | /----------\ |
// | /-------------\ | | |- END
// | | | | / Top \ | |
// | | / Margin \ | | | Right | | |
// |---------+-| |-+---+-| Bottom |-+----|
// | \ Padding / \ Left / |
// BEGIN -| |
// | /---------\ |
// | | | |
// | | / Min \ | / Width \ |
// \--------------+-| |-+---| |---/
// \ Max / \ Height /
rautoPx = /^(?:Border(?:Top|Right|Bottom|Left)?(?:Width|)|(?:Margin|Padding)?(?:Top|Right|Bottom|Left)?|(?:Min|Max)?(?:Width|Height))$/;
export function isAutoPx( prop ) {
// The first test is used to ensure that:
// 1. The prop starts with a lowercase letter (as we uppercase it for the second regex).
// 2. The prop is not empty.
return ralphaStart.test( prop ) &&
rautoPx.test( prop[ 0 ].toUpperCase() + prop.slice( 1 ) );
}

from jquery.

mgol avatar mgol commented on May 29, 2024

I thought about my original proposal and I think if we want to special-case, we should include more attributes, though, perhaps all with >50 search results above.

Our unit tests also tell a story - if we special cased not just false to mean attribute removal but also true for the value to replicate the attribute name, almost all our existing tests are passing.

Depending on how much we want to play safe, we could even keep a version of the getter that converts an empty string to the attribute name and returns the other values unchanged. That would make the HTML like <input checked> and the check if ( $( input ).attr( "checked" ) ) { /* ... */ } still work, avoiding the issue with an empty string being falsy. This pattern is, unfortunately, pretty popular; see the search for ".attr('checked')) {".

It would be hard to warn against this in Migrate as we can only patch the getter there, we cannot see it's being used as a truthy check.

from jquery.

mgol avatar mgol commented on May 29, 2024

I submitted #5451 implementing the conservative approach I mentioned above. We can make it less conservative be removing one or two parts from it. Let's discuss this today.

We can also go with Richard's solution of generalizing false - but we need to assess the breaking change from removing stringification to "false" for attributes where this is a valid value.

from jquery.

mgol avatar mgol commented on May 29, 2024

At the meeting, we decided to:

  1. Remove any special boolean attributes treatment
  2. Make the false value trigger attribute removal for all non-ARIA attributes, stringify it to "false" for ARIA attributes

PR #5452 implements this proposal.

from jquery.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.