Update from 2022-March-04

See #170 for the proposed change in direction. The rest of this issue summary is for the prior direction, so might be outdated, but I'm leaving it in place for now pending discussion on the new proposal.

Before going any further, know this:

Much of the work on this task took place here: #2346973: Improve usability, accessibility, and scalability of long select lists. It eventually became apparent that this needed its own issue

  • Are you looking for the issue regarding a drop-in replacement for jQuery UI autocomplete, for stuff like entity reference fields? this is that issue
  • Are you looking for the issue regarding UX improvments to <select> elements, making it easier to deal with long lists of options? That is a different issue, and it is here: #2346973: Improve usability, accessibility, and scalability of long select lists

Problem/Motivation

We are in the process of deprecating jQuery UI in core. jQuery UI's autocomplete is among the components that would need to be removed/replaced.
As mentioned in the parent issue: #3067261: [Plan] Remove jQuery UI components used by Drupal core and replace with a set of supported solutions
The OpenJS Foundation lists jQuery UI as an Emeritus project in https://openjsf.org/projects/ which is described as:"Emeritus projects are those which the maintainers feel have reached or are nearing end-of-life"

jQuery UI, per an announcement in October 2021 jQuery UI's maintainers clarified it is not EOL, but "minimally maintained", and security and jQuery core compatibility will be supported. This was followed by a new 1.13 release that included security fixes. Although it's not clear how often or how comprehensive these maintenance releases will be, this reduces the urgency to remove jQuery UI from Drupal core altogether.

Proposed resolution

First, some context regarding the decisions made in this specific resolution

Because it was clear the new autocomplete would not be fully backwards compatible with jQuery Ui autocomplete, it was decided to introduce the new Autocomplete as an experimental module and leave jQuery UI autocomplete as the default until Drupal 10. This would provide sites with adequate time to make any changes required

The original plan for this was to replace jQuery UI with another library. Awesomplete was literally the only library without significant accessibility regressions compared to jQueryUI and one that could be added with the least disruption so that was the library we chose.

It was then observed that the amount of customization required for the Awesomplete implementation was significant enough that we were using very little of the library itself, and it may be simpler to make the solution entirely custom.

Then after that, it was observed that this new autocomplete may be a good candidate for being a standalone library that doesn't depend on Drupal, which would adhere to the policy here: #3176918: [policy, no patch] Publishing / Maintaining JS libraries produced by Drupal that do not have a dependency on Drupal

With that context out of the way, this is the current proposed solution

How it will work in Drupal:
  • Create a new A11y_autocomplete standalone npm package that can work independent of Core.
  • A11y_autocomplete will be added to /vendor. It will effectively replace the jQuery UI autocomplete library . There will be a backwards-compatible shim that translates jQuery UI autocomplete usages to work with A11y_autocomplete on any input initialized by Drupal.Autocomplete.initialize. Drupal behaviors will continue to initialize autocomplete on any input with the .form-autocomplete class. This class is automatically added to any render array with autocomplete enabled.
  • When shim features are used, deprecation warnings will be triggered so sites are aware that the A11y_Autocomplete equivalents must be used by Drupal 10.
  • Stable and Stable 9 provide JS that refactors the autocomplete markup to match that provided by jQuery UI Autocomplete.
  • Accessibility implementation will use Accessible Autocomplete from GOV.UK as reference, as it was informed by extensive testing and research. (the accessible autocomplete library was not an option as something Drupal could use as the feature set did not cover what core would need from an autocomplete.

Steps taken prior to the proposed resolution

Several other options were evaluated. Note that all links to evaluations go a separate issue: #2346973: Improve usability, accessibility, and scalability of long select lists, the issue that this originated from.

Other than Awesomplete, nontrivial accessibility problems were identified in each candidate. These problems were discovered from general accessibility testing. In each case, enough issues were found that it wasn't worth devoting additional time to strictly checking against W3 specs.

Remaining tasks

  • In case where BC support is not provided in shim, such as extending widgets, throw error to crash JS
  • If feasible, remove markup BC from the main shim and move to Stable/Stable9.
  • All autocomplete-related files in /misc moved to their own directory
  • We need to support BC on the Drupal.autocomplete API as well, which includes config properties beyond those provided by jQuery UI. Here's a snippet from autocomplete.es6.js (the jQuery UI using version), with the already shimmed items removed.
    autocomplete = {
        cache: {},
        // Exposes options to allow overriding by contrib.
        splitValues: autocompleteSplitValues,
        extractLastTerm,
        options: {
          renderItem,  // Needs work... The functionality is already shimmed, but uses an underscore-prefixed property name
          // Custom options, used by Drupal.autocomplete.
          firstCharacterBlacklist: '', // Might already be fully shimmed?
          // Custom options, indicate IME usage status. This is likely unnecessary....
          isComposing: false,
        },
        ajax: {
          dataType: 'json',
          jsonp: false,
        },
      };
    

  • There needs to be a way to configure an input to use the original not-shimmed jQuery UI autocomplete either via https://www.drupal.org/project/jquery_ui_autocomplete/ or the deprecated version in core. (maybe another option on the render array?). Note that there will be challenges having shimmed and regular jQueryUI Autocomplete coexisting on the same page because the shim overrides $.ui.autocomplete(). Is it necessary to allow this coexisting, or is it adequate to say "you're stuck with old autocomplete everywhere until you can get by with the shim BC layer"
  • The unshimmed Autocomplete inputs need CSS styling (in earlier iterations, we we using jQuery UI classes for styling, but with that no longer the case, this autocomplete is now unstyled)
  • Change records for any added polyfills
  • Test coverage to ensure shim & non-shimmed can coexist
  • Functional Javascript test integration test coverage
  • Shim test coverage
  • Accessibility review
  • Change Record, including explanation of shim, and the extent to which BC is supported (such as extending widgets with the full jQueryUI API... that's not supported)
  • check if comma separated lists work in multilingual settings, particularly where the English comma, ',' is not used. See #177.
  • JS FM Signoff
  • Product Manager review
  • Release manager signoff (regarding the deprecations)
  • Accessibility Signoff
  • FEFM signoff
  • A11y_Autocomplete added to core in separate issue so it's not part of this MR (potentially including PHP notices)
  • Find some additional means of communicating this change + new npm package beyond just a boring change notice as this could benefit the community.
  • A review that targets the Nightwatch tests and associated test modules - these are unlikely to change much so a comment signing off on those could remove them from the overall review-burden for other reviewers
  • Deprecation warnings exist when overriding any default properties of the deprecated Drupal.autocomplete API (note the lowercase "a" in "autocomplete". These specific warnings do not yet have test coverage. Determine if test coverage is necessary and if so add the tests.

User interface changes

Yes.

API changes

The entire Drupal.autocomplete API is deprecated.
There is a new Drupal.Autocomplete api with different properties. Details are in the change record

Release Notes Snippet

jQuery UI autocomplete has been deprecated and removed, replaced by Drupal's Accessible Autocomplete library. A backwards compatible shim has been added to provide an API surface that is fully compatible with the jQuery UI Autocomplete API, and largely compatible (but not 100%) with the jQuery UI's widget API, which autocomplete (and all other jQuery widgets) extend. When the shim is used by calling $('#an-input').autocomplete(/* anything */), a deprecation warning will be triggered. This shim will be removed in Drupal 10.0.
In themes that have Stable or Stable 9 as base themes, the Autocomplete widget markup is unchanged. Autocomplete markup will be different in themes not extending Stable/Stable 9. will and markup that is unchanged from jQuery UI Autocomplete.

CommentFileSizeAuthor
#176 3076171-nr-bot.txt150 bytesneeds-review-queue-bot
#160 IME.mov1.5 MBbnjmnm
#108 interdiff_105-108.txt33.44 KBbnjmnm
#108 3076171-108.patch300.74 KBbnjmnm
#105 3076171-105.patch301.89 KBbnjmnm
#104 autocompletePortedTests.patch87.02 KBbnjmnm
#104 3076171-104-NEW-LIBRARY.patch154.21 KBbnjmnm
#96 3076171-96-REROLL.patch146.09 KBbnjmnm
#91 3076171-91.patch146.1 KBbnjmnm
#91 interdiff_90-91.txt28 KBbnjmnm
#90 interdiff_85_90.txt2.34 KBanmolgoyal74
#90 3076171-90.patch143.09 KBanmolgoyal74
#89 interdiff_85_89.txt2.72 KBanmolgoyal74
#89 3076171-89.patch142.64 KBanmolgoyal74
#85 3076171-85.patch143.05 KBbnjmnm
#85 interdiff_83-85.txt546 bytesbnjmnm
#83 interdiff_81-83.txt10.82 KBbnjmnm
#83 3076171-83.patch143.03 KBbnjmnm
#81 3076171-81.patch142.06 KBbnjmnm
#81 interdiff_78-81.txt2.32 KBbnjmnm
#78 interdiff_77-78.txt85.73 KBbnjmnm
#78 3076171-78.patch142.06 KBbnjmnm
#77 interdiff_72-77.txt106.61 KBbnjmnm
#77 3076171-77.patch87.94 KBbnjmnm
#72 3076171-72-REROLL.patch46.49 KBbnjmnm
#70 3076171-70-REROLL.patch46.6 KBbnjmnm
#68 interdiff_66_67.txt721 byteskapilv
#68 3076171-67.patch12.7 KBkapilv
#66 interdiff_59_66.txt38.8 KBkapilv
#66 3076171-66.patch12.25 KBkapilv
#59 3076171-59_ALL-CUSTOM.patch47.15 KBbnjmnm
#55 gin_drupal_custom_select.png150.08 KBsaschaeggi
#53 auto-compele.png55.84 KBdroplet
#43 3076171-43.patch68.44 KBbnjmnm
#43 interdiff_40-43.txt950 bytesbnjmnm
#40 3076171-40.patch68.44 KBbnjmnm
#40 interdiff_37-40.txt2.11 KBbnjmnm
#37 3076171-37.patch66.79 KBbnjmnm
#37 interdiff_35-37.txt10.88 KBbnjmnm
#35 interdiff_28-34.txt21.74 KBbnjmnm
#35 3076171-34.patch66.31 KBbnjmnm
#28 interdiff_26-28.txt420 byteszrpnr
#28 3076171-28.patch61.6 KBzrpnr
#26 interdiff_24-26.txt5.25 KBzrpnr
#26 3076171-26.patch61.13 KBzrpnr
#24 interdiff_22-24.txt146.54 KBzrpnr
#24 interdiff_18-24.txt132.36 KBzrpnr
#24 3076171-24.patch60.21 KBzrpnr
#22 3076171-22.patch100.15 KBbnjmnm
#22 interdiff_18-22.txt18.36 KBbnjmnm
#18 3076171-18.patch86.42 KBbnjmnm
#18 interdiff_10-18.txt6.43 KBbnjmnm
#10 autocomplete-multiple.png48.79 KBzrpnr
#10 autocomplete-filter.png31.8 KBzrpnr
#10 interdiff-5-10.txt9.46 KBzrpnr
#10 3076171-10.patch85.01 KBzrpnr
#5 3076171-5.patch85.76 KBbnjmnm

Issue fork drupal-3076171

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

bnjmnm created an issue. See original summary.

bnjmnm’s picture

Priority: Major » Critical
wim leers’s picture

Title: [policy, no patch] replace jQueryUI autocomplete with awesomplete » [policy, no patch] replace jQuery UI autocomplete with awesomplete
Issue summary: View changes

Thanks for splitting this off and making each issue title & issue summary so clear, @bnjmnm! 🙏👏Looking forward to patches to review 🤓

I just fixed a few typos!

lauriii’s picture

Title: [policy, no patch] replace jQuery UI autocomplete with awesomplete » Replace jQuery UI autocomplete with awesomplete
bnjmnm’s picture

Status: Active » Needs review
StatusFileSize
new85.76 KB

This is a patch-in-progress, but definitely far enough along to get review/feedback from maintainers and other folks. The library is implemented and the expanded test coverage has started but will be expanded further.

This includes a patch from #3027240: Undefined index: #parents FormState.php which was necessary for \Drupal\Tests\comment\Functional\CommentAnonymousTest::testAnonymous to pass. There had been difficulty getting test coverage for that issue so hopefully this will help that happen as well.

wim leers’s picture

Note: I manually tested using the field_tags field at /node/add/article.

I suspect what's really needed here is to try to break this in as many ways as possible. I did some of that, and found a few problems. You as the person who worked on the code probably have a more informed hunch of where the risks are, i.e. how it could break. It'd be great if you could document your own attempts of breaking it in a comment — or better yet, share those in the form of tests. Then none of us would have to repeat that manually!

Overall, it already seems to be working very well! 👏

  1. +++ b/core/core.libraries.yml
    @@ -104,16 +104,24 @@ drupal.announce:
    +  version: VERSION
    

    🐛 This needs the included asset library's version, not VERSION which means "core's version".

    It also needs the license key, just like all other 3rd party asset libraries.

  2. +++ b/core/core.libraries.yml
    @@ -104,16 +104,24 @@ drupal.announce:
    +    - core/drupal.announce
    

    🥳 Oh! Exciting! I'll be testing this specifically then.

  3. +++ b/core/core.libraries.yml
    @@ -471,20 +479,6 @@ jquery.ui.accordion:
    -jquery.ui.autocomplete:
    

    👎 We can't delete it, we can only deprecate it.

  4. +++ b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php
    @@ -142,6 +142,21 @@ public static function processEntityAutocomplete(array &$element, FormStateInter
    +    // Create attribute that will be used for client side enforcement of field
    

    🤓 Nit: s/client side/client-side/

  5. +++ b/core/misc/autocomplete.es6.js
    @@ -55,150 +55,89 @@
    +   * Detemines if a suggestion should be an available option.
    

    🤓 Nit: s/Detemines/Determines/

  6. +++ b/core/misc/autocomplete.es6.js
    @@ -55,150 +55,89 @@
    +    const cardinality = inputElement
    +      .closest('[data-autocomplete-cardinality]')
    +      .getAttribute('data-autocomplete-cardinality');
    

    🤔 Needs to handle the case of no cardinality metadata being present. Or fail explicitly.

  7. +++ b/core/misc/autocomplete.es6.js
    @@ -55,150 +55,89 @@
    +      'data-autocomplete-first-character-blacklist',
    

    👎 Let's use different terminology — see #2993575: [meta] Remove usage of "blacklist", "whitelist", use better terms instead.

  8. +++ b/core/misc/autocomplete.es6.js
    @@ -55,150 +55,89 @@
    +    // Do not show items already added to field.
    +    if (currentValues.indexOf(suggestionValue) !== -1) {
    +      return false;
         }
    
    @@ -213,40 +152,113 @@
    +        // Screenreader announces the number of results found, and if it is
    +        // the first set of results for a field, additional instructions on
    +        // navigating the results are provided.
    ...
    +            'There is one result available.',
    +            'There are @count results available.',
    

    🐛 These operate independently of each other, but the announcing of the number of read results needs to be aware of omitted suggestions.

    Otherwise this results in incorrect announcements.

    For example: terms "bar" and "baz" exist, "bar" is already entered, type "b" to search. You see 1 suggestion ("baz") but the screen reader announces there are two results.

  9. +++ b/core/misc/autocomplete.es6.js
    @@ -213,40 +152,113 @@
    +        // The first time autocomplete results appear on a field, the
    +        // screenreader provides detailed instructions on how to navigate the
    +        // options. After the first time, this variable is set to true so the
    +        // screenreader does not provide lengthy instructions each time.
    +        let autocompleteInstructionsRead = false;
    

    👍 This is a nice touch! This will need to be verified by an accessibility maintainer in the end, but I can confirm it works as advertised :)

  10. +++ b/core/misc/autocomplete.es6.js
    @@ -213,40 +152,113 @@
    +        // Add class previously added by jQueryUI for backwards compatibility.
    +        autocompleteElement.classList.add('awesomplete-input');
    

    🤔 It seems unlikely that jQuery UI was adding the class awesomeplete-input? Did you mean to add ui-autocomplete here? That would also allow some test changes to be reverted. Although I'm not sure that's really worth it.

  11. 🐛 When typing a single character, that yields autocomplete suggestions. Good. But when you delete that single character, the autocomplete suggestions remain visible. That seems like a bug in our implementation, because https://leaverou.github.io/awesomplete/'s demo doesn't do this. Note this only happens for any entry that isn't the first — it does not happen when choosing a first entry!
    The current jQuery UI-based solution also does not do this.
  12. 👍 I explicitly tested with accented characters and emoji in an attempt to break it 😏, this worked fine.
catch’s picture

Issue tags: +Drupal 9
xjm’s picture

We need a dependency evaluation for Awesomplete here. Thanks!

xjm’s picture

Issue summary: View changes
zrpnr’s picture

StatusFileSize
new85.01 KB
new9.46 KB
new31.8 KB
new48.79 KB

This is looking really good @bnjmnm! I think awesomeplete is an excellent choice, and I'm a big fan of Lea Verou too.

I've tried to address @Wim Leers feedback:

  1. Changed version to 1.1.5 and added the license info
  2. I did some testing with Mac OS voiceover on
  3. Restored the jquery.ui.autocomplete asset lib, added deprecation message.
  4. Added hyphen
  5. Fixed spelling
  6. I think this is covered in
                +++ b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php
                @@ -142,6 +142,21 @@ public static function processEntityAutocomplete(array &$element, FormStateInter
                +    // Create attribute that will be used for client side enforcement of field
                +    // cardinality.
                +    $name = explode('[', $element['#name'])[0];
                +    if (!empty($complete_form[$name]['widget']['#theme']) && $complete_form[$name]['widget']['#theme'] === 'field_multiple_value_form') {
                +      $cardinality = 1;
                +    }
                +    elseif (!empty($complete_form[$name]['widget']['#cardinality'])) {
                +      $cardinality = $complete_form[$name]['widget']['#cardinality'];
                +    }
                +    else {
                +      $cardinality = -1;
                +    }
                +
                +    $complete_form[$name]['#attributes']['data-autocomplete-cardinality'] = $cardinality;
                +
            

    However I also added an additional expression to set cardinality to -1 if the wrapper element with that attribute is not found.

  7. Changed to "denylist" per the variable names in the latest patch in #2993575: [meta] Remove usage of "blacklist", "whitelist", use better terms instead
  8. This was a really good catch, at first I was only looking at the markup that awesomeplete generates and it seemed accurate. This bug is with the value that gets sent to "announce".
    jQuery UI autocomplete doesn't filter the lists as well as awesomeplete, either- after selecting an item it was still available in the list.
    selected item filter

    Changed the value passed here to be the same count awesomeplete has after evaluating the cached autocomplete list.

  9. I like this too, there also seems to be something in "announce" preventing some other repetitions but I didn't dig into it.
  10. Changed this back to ui-autocomplete-input, but I left awesomeplete in JSWebAssert and EntityReferenceAutocompleteWidgetTest since that is the class that gets added to the wrapper div.
  11. This does seem a little buggy, I may be misunderstanding but it seems to work the same as http://leaverou.github.io/awesomplete/#multiple-values
    multiple item list
    select one word, type a character then hit backspace and the full list appears.

#9 I'll open an issue to start the dependency evaluation, and post the reply here.

lauriii’s picture

I'm concerned that changing this library in a minor release will be disruptive because this completely replaces the suggestions markup, meaning that any CSS targeting the old autocomplete suggestions wouldn't work anymore. How do we make sure that themes have enough time to prepare for this update? It almost seems like there we should try to find a way for themes to decide which markup they support, and we would deprecate the jQuery UI autocomplete option to be removed in Drupal 9.

I'm also concerned about the potential disruption caused by adding the new <div class="awesomplete"> element. This change could break selectors, for example .form-type-entity-autocomplete > input would be affected.

It seems like the default design is also different, meaning that anyone relying on the default designs would also see changes in the UI after this change. I suggest that we try to customize the design to be similar to jQuery UI to minimize potential disruption.

We should try to move as much of the markup as possible to theme functions to make it easier for themes to customize the design of the autocomplete suggestions.

catch’s picture

I'm concerned that changing this library in a minor release will be disruptive because this completely replaces the suggestions markup, meaning that any CSS targeting the old autocomplete suggestions wouldn't work anymore. How do we make sure that themes have enough time to prepare for this update?

Can we ship both implementations, and then make it a site-level configuration option for which one gets used in 8.8 and 8.9 (defaulting to jQuery UI)? Then complete replacement in Drupal 9?

ghost of drupal past’s picture

Maybe we could ship awesomplete as a module replacing the core/drupal.autocomplete library via the library alter hook?

I reviewed the patch from this angle. Besides adding the library, two PHP files are changed here. The change to FormState just avoids an error, we could ship it without a problem. And adding a new data-autocomplete-cardinality attribute to EntityAutocomplete looks like a minor and non-breaking markup change. So both of those could stay and be present even if awesomplete is not enabled. This would also put minimal burden on the awesome people working on the patch here since the necessary plus code is just an info and a very small module file (famous last words, I know) and would avoid a configuration form and all that.

catch’s picture

Using a module means we'll eventually need to deprecate/uninstal/remove the module when we do the change 100% in core, but we're doing that for other modules (like migrate multilingual) already so seems viable to me.

aaronmchale’s picture

Using a module means we'll eventually need to deprecate/uninstal/remove the module when we do the change 100% in core, but we're doing that for other modules (like migrate multilingual) already so seems viable to me.

Another example of that is the Field Layout (experimental) module #3007167: [policy] Deprecate field_layout module and move it to contrib, so if this was done as a module it could also be marked as experimental, which might be appropriate given this will require a lot of manual experimenting by many users to find all of the edge-case issues and incompatibilities.

aaronmchale’s picture

Issue tags: +Needs usability review

Tagging for future UX call.

bnjmnm’s picture

Based on the discussion about the (quite reasonable) interest in having the experience/markup changed as little as possible, there are two aspects of this new implementation that are technically different, but arguably improvements. I'd like feedback on whether these improvements should be removed to match the experience or if they're acceptable changes since they're pretty good ones.

  • With jQueryUI autocomplete, with fields using the "tag" widget: Even if maximum cardinality was reached, the autocomplete would continue providing suggestsions, and they could be added to the field -- but only the first {{cardinality}} would actually be saved. With the Awesomplete implementation, suggestions are not provided once the field has reached max cardinality.
  • With jQueryUI autocomplete, it's possible to add the same reference multiple times in the same field, but only one instance is actually saved with the entity. In the Awesomplete implementation, suggestions will not include items that are already entered in the field.

If there's a need to keep things very consistent, suggestion-warts and all, these can be split into their own issues.

bnjmnm’s picture

StatusFileSize
new6.43 KB
new86.42 KB

This patch adds the test \Drupal\FunctionalJavascriptTests\EntityReference\EntityReferenceAutocompleteWidgetTest::testMarkup

The test checks for the structure and classnames for jQueryUI autocomplete, so this test is going to fail with the current Awesomplete implementation. Once the Awesomplete implementation is updated to pass this test, we'll have confirmed that no pre-existing css will be broken as a result of this update.

Status: Needs review » Needs work

The last submitted patch, 18: 3076171-18.patch, failed testing. View results

zrpnr’s picture

I think this is a smart way to be more careful about BC @bnjmnm. There are a lot of places where jQuery UI classnames exist in core, such as in stable and seven. If we can get this patch landed we should add follow-up issues for eventually removing/changing the jQuery UI css.

If we put awesomplete in an optional module, what would the process be for updating all the places where the old classnames are used, and what would be the motivation for ever changing them in themes like Claro?

Besides classnames, the biggest difference in markup is that the jQuery UI suggestion list is appended to the body (then positioned with javascript), compared to the awesomplete markup which keeps the list as a direct sibling to the input.

In #18 testMarkup enforces the jQuery UI approach.

+++ b/core/tests/Drupal/FunctionalJavascriptTests/EntityReference/EntityReferenceAutocompleteWidgetTest.php
@@ -106,4 +116,112 @@ public function testEntityReferenceAutocompleteWidget() {
+    $suggestion_list = $page->find('css', 'body > .ui-autocomplete');

Why is it important to show that the suggestion list is a direct descendent of the body? I don't think that's necessarily a better way and I didn't find any examples of css which depended on this placement. If that body > is removed then it would be simpler to make this test pass without altering how awesomplete works.

lauriii’s picture

If we put awesomplete in an optional module, what would the process be for updating all the places where the old classnames are used, and what would be the motivation for ever changing them in themes like Claro?

If awesomplete is shipped in an optional module, themes could support both, jQuery UI and awesomplete simultaneously. We should make core themes support both as part of the initial patch.

Why is it important to show that the suggestion list is a direct descendent of the body? I don't think that's necessarily a better way and I didn't find any examples of css which depended on this placement.

I don't think there's any reason for us to try to make awesomplete work that way. I think it was just an implementation detail in jQuery UI. I think we could change this selector to allow placing the suggestions list anywhere in the markup.

bnjmnm’s picture

StatusFileSize
new18.36 KB
new100.15 KB

Similar to #18, these tests will fail until the Awesomplete implementation is modified to better match the one from jQueryUI.

In this patch, the tests have been expanded to check for all jQueryUI Autocomplete events, which include verifying the variables are structured the same. This also adds more tests related to how items with spaces and commas are handled.

catch’s picture

I'm not sure about trying to make awesomplete fully backwards compatible with jQuery UI. If we ever want to remove the bc layer we'll be faced with the same problem again.

If we go for the optional module approach, this isn't necessary - themes can just target both sets of markup until they/Drupal completely drops jQuery UI support.

zrpnr’s picture

Status: Needs work » Needs review
StatusFileSize
new60.21 KB
new132.36 KB
new146.54 KB

This patch moves all the awesomplete code into an experimental core module and restores the changes to core.libraries.yml and misc/autocomplete.
I left @bnjmnm's changes to EntityAutocomplete and FormState, as well as some of the new tests, but I removed the markup test and the tests and new module from #22 which was added for BC.

The "loading" class is now being toggled, and I fixed a small issue with how list items were assigned an #id.

The module overrides the core library and replaces the dependency with awesomplete. I used the minified js and the "base" css so that it was easier to override with Drupal styles, I copied a few lines from Seven to give the dropdown list a default look, as well as some padding that the jQuery UI Autocomplete gets from "menu".

I looked into overriding the markup but it gets generated by awesomplete directly and is very minimal, there's an open feature request for custom templates

Status: Needs review » Needs work

The last submitted patch, 24: 3076171-24.patch, failed testing. View results

zrpnr’s picture

Status: Needs work » Needs review
StatusFileSize
new61.13 KB
new5.25 KB

The previous patch failed because the InstallUninstallTest was looking for a specific string pointing to online documentation, I created a doc page and updated the help text and link.
https://www.drupal.org/docs/8/core/modules/experimental-awesomplete-auto...
This test didn't always finish on my local, it takes around 15-20 min to run for me. I experimented with local changes to the test to only install this new module and it seemed to be fixed but I'm not 100% confident this will pass now.

The remaining warnings were from the deprecation message, in https://www.drupal.org/project/drupal/issues/3067251#comment-13264865
I suppressed that deprecation warning in \Drupal\Tests\Listeners\DeprecationListenerTrait::getSkippedDeprecations()
That seemed like a valid approach here, too, since having this deprecation warning for core/jquery.ui.autocomplete appear to developers is one of the goals of this issue.

There are some other minor changes and nit fixes in this patch to comply with the linter and hopefully avoid more warnings from testbot.

Status: Needs review » Needs work

The last submitted patch, 26: 3076171-26.patch, failed testing. View results

zrpnr’s picture

Status: Needs work » Needs review
StatusFileSize
new61.6 KB
new420 bytes

Added drupal/awesomplete_autocomplete to composer.json under "replace"

lauriii’s picture

Status: Needs review » Needs work
  1. +++ b/core/misc/autocomplete.es6.js
    @@ -257,32 +272,26 @@
       autocomplete = {
    ...
    -      source: sourceData,
    -      focus: focusHandler,
    -      search: searchHandler,
    -      select: selectHandler,
    ...
    -      minLength: 1,
    ...
    +      minChars: 1,
    

    Could we try to keep changes to this minimal since this is the API surface to the autocomplete? For example, changing minLength to minChars seems unnecessary.

    Also, removing source, focus, search and select seems potentially disruptive. How are we expecting people to extend this in future?

    If we can't replace these with anything, we should try to document how to achieve that (if it's even possible). And we should rename this to something else than autocomplete so that modules and themes can support both autocomplete libraries at the same time without having knowledge about this module.

  2. +++ b/core/tests/Drupal/FunctionalJavascriptTests/EntityReference/EntityReferenceAutocompleteWidgetTest.php
    @@ -17,11 +19,19 @@ class EntityReferenceAutocompleteWidgetTest extends WebDriverTestBase {
    +  public static $modules = ['node', 'taxonomy'];
    

    Should we add test coverage for awesomplete as well?

  3. +++ b/core/modules/awesomplete_autocomplete/awesomplete_autocomplete.info.yml
    @@ -0,0 +1,5 @@
    +description: 'Provides a replacement for jQuery UI Autocomplete which will be deprecated in Drupal 9.0.'
    

    This seems a bit unclear. Is jQuery UI Autocomplete deprecated in Drupal 9.0 or is this module deprecated in Drupal 9.0?

  4. +++ b/core/modules/awesomplete_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,317 @@
    +  const extractTermID = term =>
    

    Autocomplete could be used for other types of entities than terms. Maybe extractEntityId would be a better name?

xjm’s picture

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

xjm’s picture

Title: Replace jQuery UI autocomplete with awesomplete » Provide an experimental module to replace jQuery UI autocomplete with awesomplete
Issue summary: View changes
Issue tags: -JavaScript +JavaScript

@catch and I discussed that since the experimental module we'd be adding here is equal parts improved product feature and security hardening, unlike most experimental modules, this could be added as a beta module in 8.9.x/9.0.x as well as 8.8.x or 9.1.x.

xjm’s picture

Issue tags: +Needs release note
bnjmnm’s picture

Assigned: Unassigned » bnjmnm

Assigning to myself to work on #29. Items 2-4 are taken care of and I'm looking into preserving the autocomplete api based on the feedback in item 1.

bnjmnm’s picture

Assigned: bnjmnm » Unassigned
Status: Needs work » Needs review
StatusFileSize
new66.31 KB
new21.74 KB

This addresses the feedback in #29 including adding tests and further abstracting the JS so it can be more easily extended. It's not really possible to extend it in the same way, as the jQueryUI functions send different arguments and have a very different this in function scope. What's been provided here should be as extensible as jQueryUI autocomplete, but accomplished in a different manner.

Some other nits and corrections were addressed as well, which can be seen in the interdiff.

zrpnr’s picture

The patch in #35 looks good! It mostly addresses the feedback in #29 and reorganizes some of the js in a more sensible way.

#29.1 Since minChars is a property awesomplete is expecting in the options- we'd have to add a map function to rename the keys before the options are passed in.

It's not really possible to extend it in the same way, as the jQueryUI functions send different arguments

There isn't a 1:1 match for every option or method from jQuery UI autocomplete to awesomplete.

I do like this improvement to the options- separating out that object. It would be better if modules or themes could override these options, but I'm don't think adding the awesompleteOptions object to the Drupal global means it can be overriden here. Even if that global is changed by another module or theme it would already have been passed into the Awesomplete instance.
If we want this to be override-able it would need to be moved to a separate js file that can be replaced with libraries_override for example.

#29.2 The test coverage looks perfect, just extending the existing test but with this module installed. Clever! I ran it locally and it excecuted the 2 tests. I also paused to verify in the testing browser that the awesomplete markup was present.
From the comments in the test file:

If awesomplete_autocomplete is moved to core, this test can be removed as EntityReferenceAutocompleteWidgetTest will then be testing with Awesomplete

That seems ideal, it should function exactly the same as the old autocomplete so re-using the existing test makes sense.

#29.3 Adding the standard deprecation message to the description is an improvement.
#29.4 There were a few other places "term" is still being used, in comments and extractLastTerm

    +++ b/core/modules/awesomplete_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,336 @@
    +   * Helper splitting terms from the autocomplete value.
    ...
    +    // We will match the value against comma-separated terms.
    ...
    +   * @function Drupal.autocomplete.extractLastTerm
    ...
    +   * @param {string} terms
    ...
    +  const extractLastTerm = terms => autocomplete.splitValues(terms).pop();
    ...
    +    return Awesomplete.FILTER_CONTAINS(suggestion, extractLastTerm(input));
    ...
    +      extractLastTerm(input),
    ...
    +    const term = autocomplete.extractLastTerm(input.value);
    ...
    +    if (term && term.length > 0) {
    +      if (autocomplete.cache[inputId].hasOwnProperty(term)) {
    +        awesomplete.list = autocomplete.cache[inputId][term];
    ...
    +        xhr.open('GET', `${apiUrl}?q=${term}`);
    ...
    +            autocomplete.cache[inputId][term] = results;
    ...
    +    extractLastTerm,
    

nit: There are also a couple comments where function names don't match.

    +++ b/core/modules/awesomplete_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,336 @@
    +   * @function Drupal.autocomplete.splitValues
    ...
    +  const autocompleteSplitValues = value => {
    ...
    +   * @function Drupal.autocomplete.extractLastTerm
    ...
    +  const extractLastTerm = terms => autocomplete.splitValues(terms).pop();
    +++ b/core/.eslintrc.json
    @@ -19,7 +19,8 @@
    +    "Awesomplete": true

Good catch adding this to the eslint file!

bnjmnm’s picture

StatusFileSize
new10.88 KB
new66.79 KB

Addressed the feedback in #36. Moving the awesomplete options to drupalSettings makes it possible to override in another file, which I confirmed with manual testing. For example, adding drupalSettings.awesompleteOptions.minChars = 2; outside of a behavior (but after drupalSettings.awesompleteOptions is initialized) will successfully change the minChars option that Awesomplete initializes with.

zrpnr’s picture

Thanks for fixing those naming issues, and the approach of moving those options into drupalSettings is smart.
This all still looks good, and there weren't any functional changes in this last patch.

catch’s picture

There seems to be a regression here.

With a term reference field, the current behavour is that if you manually type the full term into the autocomplete (for example in the middle of the list, or before autocomplete has a chance to, um, complete), then we'll query the database for the term to look it up when you submit the form. With awesomplete, it just says it's unable to find a matching entity.

This is related to #2881892: UX: Hide entity ID in autocomplete widget - I was testing the patch to see if it helps with that, but it appears to be even more dependent on the ID being in the textfield values.

bnjmnm’s picture

StatusFileSize
new2.11 KB
new68.44 KB

I expanded the test coverage to include (what I think is) the use case in #39, and the tests pass on jQueryUI and Awesomplete. The test adds the title of an entity to reference to the field without interacting with autocomplete to add the id parentheses to it, saves the node, then verifies that it is referencing the existing entity.

It's possible I'm overlooking something in the test scenario and will update as needed if that turns out to be the case.

Status: Needs review » Needs work

The last submitted patch, 40: 3076171-40.patch, failed testing. View results

bnjmnm’s picture

Despite passing locally it looks like the test I added fails for both Awesomplete and jQueryUI. Updated test on the way...

bnjmnm’s picture

Status: Needs work » Needs review
StatusFileSize
new950 bytes
new68.44 KB

The test fails in #40 were due to relative paths in href attributes being different in drupalci runs.

This tests the scenario in #39 with both jQueryUI autocomplete and Awesomplete.

zrpnr’s picture

With awesomplete, it just says it's unable to find a matching entity

@catch can you elaborate on this?

Awesomplete displays the label in the list like "News" but puts the value with the id into the input like "News (3)". If you type in the label only without letting Awesomplete fill in the value, saving still seems to find the referenced entity.

I'm sure I'm missing something, but I'm not seeing a regression in behavior.

The new tests @bnjmnm added pass for me locally and just went green from the testbot, looks good unless that test isn't proving the right thing!

catch’s picture

If you type in the label only without letting Awesomplete fill in the value, saving still seems to find the referenced entity.

This is what I was testing but it wasn't on a clean 8.x install, so it might be my local rather than the code - good to have the extra test coverage though regardless! If I get a chance to retest I'll do so though.

xjm’s picture

@zrpnr has also posted #3089455: [META] Awesomplete roadmap so that we can split out anything that's not alpha-blocking into that meta issue. I've posed some questions there about how we should handle the path to stability, mostly not directly related to this patch.

catch’s picture

Version: 8.9.x-dev » 9.1.x-dev

This could be added to 9.1 now that it's open, too late for 8.9/9.0 but main thing is being able to deprecate remaining jQuery UI libraries for Drupal 10.

nod_’s picture

Status: Needs review » Needs work

It looks good :) need a reroll and a few things:

  1. +++ b/core/core.libraries.yml
    @@ -496,6 +496,7 @@ jquery.ui.autocomplete:
    +  deprecated: The "%library_id%" asset library is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. See https://www.drupal.org/project/drupal/issues/3076171
    
    +++ b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php
    @@ -147,6 +147,7 @@ public static function getSkippedDeprecations() {
    +      'The "core/jquery.ui.autocomplete" asset library is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. See https://www.drupal.org/project/drupal/issues/3076171',
    

    Need to be updated, it's not removed from D9

  2. +++ b/core/modules/awesomplete_autocomplete/awesomplete_autocomplete.info.yml
    @@ -0,0 +1,5 @@
    +core: 8.x
    

    need to use core_version_requirement

  3. +++ b/core/modules/awesomplete_autocomplete/awesomplete_autocomplete.libraries.yml
    @@ -0,0 +1,23 @@
    +  version: 1.1.5
    

    Still up to date :)

  4. +++ b/core/modules/awesomplete_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,342 @@
    +        const xhr = new XMLHttpRequest();
    +        xhr.open('GET', `${apiUrl}?q=${searchTerm}`);
    +        xhr.onload = () => {
    

    I like the effort but we should stick with jquery for that. Having a dependency on jQuery is not making me happy but we have to keep things consistent. If you want to change how we do something, it needs to be discussed and the plan for how everything in core will be impacted need to be detailed before we make a move.

    Chances are another element on the page needs jQuery since we still rely on it a lot.

  5. +++ b/core/modules/awesomplete_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,342 @@
    +    attach(context) {
    +      const autoCompleteInputs = context.querySelectorAll(
    +        'input.form-autocomplete',
    +      );
    ...
    +      Array.prototype.forEach.call(autoCompleteInputs, autocompleteElement => {
    

    Need to use .once()

  6. +++ b/core/modules/awesomplete_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,342 @@
    +    detach(context) {
    +      const autoCompleteInputs = context.querySelectorAll(
    +        'input.form-autocomplete',
    +      );
    +      Array.prototype.forEach.call(autoCompleteInputs, autocompleteElement => {
    +        autocompleteElement.removeEventListener('input');
    +      });
    +    },
    

    Need to make sure the detach trigger is "unload", otherwise it will wreak havoc when ajax requests are made elsewhere on the page.

  7. +++ b/core/modules/awesomplete_autocomplete/js/autocomplete.js
    @@ -0,0 +1,190 @@
    diff --git a/core/modules/awesomplete_autocomplete/js/awesomplete.min.js b/core/modules/awesomplete_autocomplete/js/awesomplete.min.js
    

    Can we put that in /assets with the rest of the third party code?

  8. Doesn't work on claro, probably because of the override.
rajandro’s picture

Assigned: Unassigned » rajandro

Working on it.

droplet’s picture

This change addressed about nothing of the current autocomplete issues. So, here is not asking for crazy NEW features. Even the `LeaVerou/awesomplete` is worse than the current autocomplete on my quick test.

Therefore, this awesomplete is: INPUT + DROPDOWN LIST

awesomplete is very lite:
https://github.com/LeaVerou/awesomplete/blob/gh-pages/awesomplete.js

above patch is about rewritten or provding the core part of the `LeaVerou/awesomplete`:

autocomplete = {
cache: {},
splitValues: autocompleteSplitValues,
extractLastEntityReference,
inputListener: autocompleteInputListener,
firstCharacterDenylist: ',',
};

now, you can jump out of the box and doing your own version with:
#1899236: Add new Splitbutton render element to eventually replace Dropbutton

You only need to adopt the INPUT to trigger a dropdown list I think.

Then you have the same experience on dropdown things in Drupal. :) Nope?

rajandro’s picture

Assigned: rajandro » Unassigned

Unassigned this issue as of now if someone wants to pick this up. Otherwise, I will recheck after someday.

bnjmnm’s picture

In #50 there are some points that are probably worth investigating. @droplet, could you confirm my understanding of this is correct?

This is what I took away from the comment
It may not be neccessary to add Awesomplete at all because:

  • Awesomplete does not offer any new features or fixes, it is just a replacement for the end-of-life jQueryUI autocomplete.
  • The implementation of Awesomplete in Drupal core is customized to the point that very little of the library is actually used. It is very close to being a Drupal-core custom solution already.

A custom solution could be preferable because:

I think that is worth discussing further, and let me know if I missed anything!

droplet’s picture

StatusFileSize
new55.84 KB

@bnjmnm,

Correct! Awesomplete is also a dropdown list builder like the Splitbutton does. Ajax and other parts are fed from customized coding. Awesomplete has no keyboard shortcuts, and you need to keep it the same experience for Drupal globally.

Awesomplete has very similar problems with the Core one:

RED: no deduplicated
GREY: the problem of change / start from the middle.

(sidenote: I think I've provided patches somewhere in Core threads to address these autocomplete issues)

+ Patch coding, Only 2 extra major features required to turn Splitbutton into Autocompelete:
- INPUT handler
- item selection handler (IMO, Splitbutton required this feature alone also)

bnjmnm’s picture

I'm glad you thought of this @droplet. In my next patch for #1899236: Add new Splitbutton render element to eventually replace Dropbutton I'll refactor to make it easier for an element to extend splitbutton and add an input handler. Good timing as I can include this in splitbutton now without having to worry about BC breaks!

saschaeggi’s picture

StatusFileSize
new150.08 KB

I'm currently working on writing a custom implementation (library) on my own for Gin. Maybe this can be used/modified & optimized for a more global use.

It's basically using the default dropdown for all AT/Keyboard users (+ native select implementations on mobile like the revolver on iOS) but provides pointer users a custom solution which also works with keyboard search, filter etc.

Quick WIP Demo: https://twitter.com/saschaeggi/status/1291351015279796225?s=20

droplet’s picture

@saschaeggi

😍😍

that's same to my suggestion on above few comments I believed.

more:
https://www.drupal.org/project/drupal/issues/1899236#comment-13701448

So if Drupal implemented my idea, you will get the same thing with shared codebase

It's good to see you're the Lead of the Drupal Design. Probably, you & your team can figure out more sharable component and codebase :)

bnjmnm’s picture

I had a chance to look over the Gin select. Some of the things I ran into:

  • I couldn't open it via keyboard navigation unless a screenreader is enabled
  • If the element is focused and clicked, the native select options appear instead of the styled ones.
  • If opened at the bottom of the page, the option position does not adjust to be visible in the viewport. This can be fine for something like an autocomplete or dropbutton, but with a select there's an expectations the options will appear in the viewport.
  • This implementation hides the native
    and elements, and copies the content of those elements to very nicely styled divs. This approach has provided all sorts of great contrib features, but it's extremely unlikely such an approach would make it through the core gates.
saschaeggi’s picture

@bnjmnm quick note on the Gin select state: It's a early draft for sure.

I couldn't open it via keyboard navigation unless a screenreader is enabled
should be possible to open via keyboard (native select)

If the element is focused and clicked, the native select options appear instead of the styled ones.
based idea on this principle here https://css-tricks.com/striking-a-balance-between-native-and-custom-sele...

If opened at the bottom of the page, the option position does not adjust to be visible in the viewport. This can be fine for something like an autocomplete or dropbutton, but with a select there's an expectations the options will appear in the viewport.
This is just not yet implemented

Maybe this helps, Cheers :)

bnjmnm’s picture

Status: Needs work » Needs review
StatusFileSize
new47.15 KB

This is an alternative implementation that doesn't use a library. This is for evaluation and does not presume that there has been any decision to move away from the awesomplete approach. It is more that I find an issue is more likely to progress if the discussion is responding to something that exists. Some of my reasoning to try this:

  • #50 pointed out that so much of Awesomplete is overridden, it is close to being a custom implementation already. The patch is 20k smaller, the custom JS only ~100 lines longer (including comments), and it seems more maintainable as all functionality is contained within a single class in one file.
  • I compared the accessibility of the Awesomplete implementation to that provided by Accessible Autocomplete - demo here https://alphagov.github.io/accessible-autocomplete/examples/. Accessible Autocomplete had been ruled out for reasons unrelated to accessibility, so it seemed beneficial to still use it as a reference, particularly considering the manual testing documented here https://accessibility.blog.gov.uk/2018/05/15/what-we-learned-from-gettin... (I am emotionally prepared to be informed by our accessibility maintainers as to why this isn't good to reference 😊. The keyboard navigation and aria implementation in this patch should now match Accessible Autocomplete
  • I needed to add a jQuery dependency for once() and event management. Everything else is still vanilla (if this is the approach we go with, NodeList.forEach and Element.closest() polyfills should get added)

In the prior comments, I can see there's a pretty strong interest in shareable component/codebase, particularly splitbutton. I'm not entirely sure how to go about this as splitbutton is working with items that are part of a render element, and the Autocomplete is generating those lists dynamically with Javascript. The keyboard navigation implementations are different enough that I'm not sure if there's any reuse opportunities that would be more beneficial than they are confusing, but I'm quite happy to be persuaded with some implementable examples.

andrewmacpherson’s picture

What does "gin select" refer to?

I recall being fairly impressed with Awesomeplete when I tried it a while ago. Since then I've found some situations where it mis-reports it's value. That's a hard blocker.

bnjmnm’s picture

What does "gin select" refer to?

The answer to this requires context that I now realize is absent from this issue, so here's that context:

The "Gin select" is what @saschaeggi mentioned in #55. It is a select (not autocomplete) element that he is working on adding to a future version of the Gin admin theme. I had an opportunity to evaluate this in the Gin theme and there's nothing there that would expedite the replacement of the end-of-life jQueryUI autocomplete library, nor is there anything in there that would have to be done within this issue to make it into core.

bnjmnm’s picture

Issue tags: -Needs usability review

@lauriii, @benjifisher and @ckrina and I discussed this at #3175207: Drupal Usability Meeting 2020-10-13. The agreement was any implementation is fine, provided it does not alter the current UX. There were some UX changes the Awesomplete solution, but this is not a concern with custom solution in #59.

Some possible future UX enhancements to autocomplete were discussed, and comps of these can be found here https://www.figma.com/file/OqWgzAluHtsOd5uwm1lubFeH/Drupal-Design-system.... While these enhancements are not at all in scope for this issue, we should ensure the custom autocomplete solution is structured in a way that these kind of enhancements are feasible - be it from core or contrib.

Removing the "Needs usability review" on the assumption that we will proceed with the custom solution that doesn't alter the UX. If that changes, we'll need to re-add the tag.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

lauriii’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll
kapilv’s picture

Assigned: Unassigned » kapilv
kapilv’s picture

Assigned: kapilv » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new12.25 KB
new38.8 KB

Hear a reroll patch.

Status: Needs review » Needs work

The last submitted patch, 66: 3076171-66.patch, failed testing. View results

kapilv’s picture

Status: Needs work » Needs review
StatusFileSize
new12.7 KB
new721 bytes
lauriii’s picture

Status: Needs review » Needs work

Seems like something is missing from the patch given that it went from ~47kb to ~12kb.

bnjmnm’s picture

Status: Needs work » Needs review
StatusFileSize
new46.6 KB

Status: Needs review » Needs work

The last submitted patch, 70: 3076171-70-REROLL.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

bnjmnm’s picture

Status: Needs work » Needs review
StatusFileSize
new46.49 KB

Status: Needs review » Needs work

The last submitted patch, 72: 3076171-72-REROLL.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

nod_’s picture

Had a look, don't know how to fix the composer issue.

  1. +++ b/core/composer.json
    @@ -54,6 +54,7 @@
    +        "drupal/d9_autocomplete": "self.version",
    

    not a fan of the name. maybe we can make a vanilla js module and put all the overrides in there (autocomplete, ajax, tabledrag, etc.)?

  2. +++ b/core/modules/d9_autocomplete/d9_autocomplete.info.yml
    @@ -0,0 +1,4 @@
    +description: 'Provides a replacement for jQuery UI Autocomplete. jQuery UI Autocomplete is deprecated in Drupal 8.8.0 and will be removed in Drupal 9.0.'
    

    versions should be deprecated in D9.2, removed in D10 no?

  3. +++ b/core/modules/d9_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,492 @@
    +  Drupal.Autocomplete = class {
    

    Lacks significant docs :) and candidate for "extraction", might want to declare it outside the Drupal namespace already.

  4. +++ b/core/modules/d9_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,492 @@
    +      $(this.input).on('input', () => this.inputListener());
    +      $(this.input).on('blur', (e) => this.blurHandler(e));
    +      $(this.input).on('keydown', (e) => this.inputKeyDown(e));
    +      $(this.ul).on('mousedown', (e) => e.preventDefault());
    +      $(this.ul).on('click', (e) => this.itemClick(e));
    +      $(this.ul).on('keydown', (e) => this.listKeyDown(e));
    +      $(this.ul).on('blur', (e) => this.blurHandler(e));
    

    we could use the object version to avoid having several $(this.input) and $(this.ul) calls.

  5. +++ b/core/modules/d9_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,492 @@
    +      const separator =
    +        numItems < cardinality || parseInt(cardinality, 10) === 0 ? ',' : '';
    +      const before = this.input.value.match(/^.+,\s*|/)[0];
    +      this.input.value = `${before}${item}${separator}`;
    

    Should probably be configurable, or do we expect people to override the whole function?

  6. +++ b/core/modules/d9_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,492 @@
    +          const xhr = new XMLHttpRequest();
    

    we should get the fetch polyfill in core sonner or later. As an external lib I'd go with using fetch only.

  7. +++ b/core/modules/d9_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,492 @@
    +      // Wrapped in an `<a>` for backwards compatibility.
    

    we're going back to where with that? if it's for under IE11 I'd get rid of it.

  8. +++ b/core/modules/d9_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,492 @@
    +    announceSuggestionCount(count) {
    

    as an external lib I'd see an event being triggered for this.

  9. +++ b/core/modules/d9_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,492 @@
    +        ? this.input.getAttribute('data-autocomplete-first-character-denylist')
    

    maybe we can put the setting as a json string in a generic data-autocomplete attribute? like we did for #states

In any case it seems to be working just fine :)

lauriii’s picture

  1. Removing needs release notes and needs release manager review since I think there are couple of steps we probably want to take before working on those. Leaving needs accessibility review and needs issue summary update there since they seem still relevant.
  2. We should probably expand our test coverage to explicitly test some of the features provided for improved accessibility. This would both act as documentation on the expected behavior, and ensure that it remains consistent as time passes.
  3. Should users be able to navigate back to the input from the autocomplete list using arrows? This seems to be how Accessible Autocomplete and jQuery UI Autocomplete work.
  4. +++ b/core/core.libraries.yml
    @@ -465,6 +465,7 @@ jquery.ui.autocomplete:
    +  deprecated: The "%library_id%" asset library is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. See https://www.drupal.org/project/drupal/issues/3076171
    

    This should point at a change record.

  5. +++ b/core/modules/d9_autocomplete/js/autocomplete.es6.js
    @@ -0,0 +1,492 @@
    +      const wrapper = this.input.closest('[data-autocomplete-cardinality]');
    

    I don't think this is going to work with IE 11. We should support IE 11 until #3155358: [policy, no patch] Drop IE11 support from Drupal 10.0.x has been resolved.

  6. Even though we probably want to set some restrictions on how much of the markup and the attributes can be overridden, we probably should add some theme functions / API for adding additional classes and wrappers.
bnjmnm’s picture

Title: Provide an experimental module to replace jQuery UI autocomplete with awesomplete » Provide an experimental module to replace jQuery UI autocomplete
Assigned: Unassigned » bnjmnm
Issue summary: View changes
Issue tags: -Needs issue summary update

There's probably little risk of someone else jumping in here, but assigning to myself as making this "detachable" requires a few days of work so it's probably good to make it clear that it is being worked on.

I also updated the issue summary to reflect the new approach.

bnjmnm’s picture

Status: Needs work » Needs review
Issue tags: +Needs tests
StatusFileSize
new87.94 KB
new106.61 KB

This is a huge change as it makes the autocomplete class extraction-friendly. This includes changes that should address most of #75 and #76, with some exceptions.

#74

not a fan of the name. maybe we can make a vanilla js module and put all the overrides in there (autocomplete, ajax, tabledrag, etc.)?

I renamed the class, but the module name is not yet changed as I it will need to be discussed a bit, particularly since I didn't have any great ideas. As far as an all-overrides module, I opened an issue to discuss that possibility and alternatives: #3179174: [policy, no patch] Updating core JavaScript APIs gracefully.

#74.3

Lacks significant docs :)

Yep, was waiting on those until there was definite support for the non-library approach. The class meets drupal standards, but probably needs more before it gets extracted. Will need to double-check on the need for other docs in the next patch where I add tests.

#75.2

We should probably expand our test coverage to explicitly test some of the features provided for improved accessibility. This would both act as documentation on the expected behavior, and ensure that it remains consistent as time passes

Will get added soon. Tagging with "needs tests" for visibiility. There is now considerable functionality that is better tested without a Drupal install, and would best be implemented via the guidelines being discussed in #3176918: [policy, no patch] Publishing / Maintaining JS libraries produced by Drupal that do not have a dependency on Drupal.

bnjmnm’s picture

Assigned: bnjmnm » Unassigned
Issue tags: -Needs tests
StatusFileSize
new142.06 KB
new85.73 KB

This adds a bunch of test coverage, as well as several necessary changes that surfaced by these tests.

For this to be available as a standalone library, additional non-Drupal test coverage would also be neccessary, but the tests that have been added attempt to cover all ways Drupal would use this library, as well as many additional potential use cases. My goal is for the test coverage to be thorough enough for this to get committed to core. The additional coverage can happen if/when it is "detached", which doesn't necessarily have to happen here.

This patch also has several enhancements to how messages are relayed to assistive tech. Through manual testing, I discovered that some calls to Drupal.announce() were colliding with default screenreader output and information would be lost. I took inspiration from https://alphagov.github.io/accessible-autocomplete/ and added some delays so the calls to announce() would not occur until after default screenreader content was complete.

And now a PSA
IT IS MY HOPE THAT THE LARGE SIZE OF THIS PATCH DOES NOT SCARE OFF REVIEWERS
In fact, the size of the patch makes having multiple reviewers all the more important. Reviews targeting only specific bits of the patch are welcome, just make it clear what was/wasn't reviewed.

bnjmnm’s picture

Status: Needs review » Needs work

The last submitted patch, 78: 3076171-78.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

bnjmnm’s picture

Status: Needs work » Needs review
StatusFileSize
new2.32 KB
new142.06 KB

Had to update the skippeddeprecations string to address the fails in #78

lauriii’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/d9_autocomplete/d9_autocomplete.libraries.yml
    @@ -0,0 +1,36 @@
    +  drupalSettings:
    +    autocompleteOptions:
    +      inputClass: ui-autocomplete-input
    +      ulClass:  ui-menu ui-widget ui-widget-content ui-autocomplete ui-front
    +      loadingClass: ui-autocomplete-loading
    +      itemClass: ui-menu-item
    

    As part of #3067523: Add Drupal JavaScript theme functions for password confirm widget I think we set precedent that we prefer not to use drupalSettings for this type of UI settings.

  2. +++ b/core/modules/d9_autocomplete/d9_autocomplete.libraries.yml
    @@ -0,0 +1,36 @@
    +      liveRegion: false
    

    Seems like we already force this to be false so we could probably remove this from here.

  3. +++ b/core/modules/d9_autocomplete/js/drupalautocomplete.es6.js
    @@ -0,0 +1,866 @@
    +  constructor(input, options = {}) {
    

    It would be helpful to have docs for the constructor parameters.

  4. +++ b/core/modules/d9_autocomplete/js/drupalautocomplete.es6.js
    @@ -0,0 +1,866 @@
    +        'When autocomplete results are available use up and down arrows to review and enter to select.  Touch device users, explore by touch or with swipe gestures.',
    

    Two spaces after the first sentence.

  5. +++ b/core/modules/d9_autocomplete/js/drupalautocomplete.es6.js
    @@ -0,0 +1,866 @@
    +    // This f
    

    This comment seems incomplete 😇

  6. +++ b/core/modules/d9_autocomplete/js/drupalautocomplete.es6.js
    @@ -0,0 +1,866 @@
    +    this.preventCloseOnBlur = true;
    ...
    +      this.preventCloseOnBlur = true;
    ...
    +    this.preventCloseOnBlur = true;
    ...
    +      this.preventCloseOnBlur = true;
    

    Why are we setting this twice 🤔

  7. +++ b/core/modules/d9_autocomplete/js/drupalautocomplete.es6.js
    @@ -0,0 +1,866 @@
    +    if (previousItem) {
    ...
    +    } else {
    +      this.input.focus();
    +      this.close();
    +    }
    

    Why are we closing the tray when the input is being focused again? Current behavior is that the tray remains open even when the input gets focused using keyboard arrow navigation.

  8. +++ b/core/modules/d9_autocomplete/js/drupalautocomplete.es6.js
    @@ -0,0 +1,866 @@
    +   * Announces to assistive tech when an item is highlighted
    

    Nit: missing a full stop 🧐

bnjmnm’s picture

Status: Needs work » Needs review
StatusFileSize
new143.03 KB
new10.82 KB

Addresses everything in #82

and I'll repeat my PSA from #81
IT IS MY HOPE THAT THE LARGE SIZE OF THIS PATCH DOES NOT SCARE OFF REVIEWERS
In fact, the size of the patch makes having multiple reviewers all the more important. Reviews targeting only specific bits of the patch are welcome, just make it clear what was/wasn't reviewed
😎

Status: Needs review » Needs work

The last submitted patch, 83: 3076171-83.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

bnjmnm’s picture

Status: Needs work » Needs review
StatusFileSize
new546 bytes
new143.05 KB

Test failure in #84 was due to the module info yml not having a version.

zrpnr’s picture

Not a complete review, starting with checking that the points in #82 were addressed in #85:

  1. The entire drupalSettings block was removed
  2. liveRegion removed
  3. docblock added to constructor
  4. extra space removed
  5. incomplete comment removed
  6. extra preventCloseOnBlur removed
  7. close() removed
  8. full stop added
bserem’s picture

I tested patch #85 in a fresh installation and I faced no issues. None at all I must say.

I have a UX suggestion though: It would be great to automatically add a comma (,) once the user selects a term when using "autocomple tags-style" widget, so that he/she can proceed typing the next term without the need to add the comma.
Just a suggestion, nothing more. This was never the case with previous versions of Drupal anyway.

The patch works and works as expected for the frontend user/editor. As far as I am concerned that part is RTBC by me.

Other things to consider:
There is a composer.lock change in the patch file, I can't understand why.
There are references to IE10-11. I suppose that's needed if we wanna added the new functionality in Drupal 9?
The module name "Drupal 9 Autocomplete", "d9_autocomplete" ties this to Drupal 9, which is not the case. Maybe "drupal_autocomplete" would make more sense in the long run?

lauriii’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll
anmolgoyal74’s picture

Status: Needs work » Needs review
StatusFileSize
new142.64 KB
new2.72 KB

Re-rolled.

anmolgoyal74’s picture

StatusFileSize
new143.09 KB
new2.34 KB

Updated composer.lock file.
Mistakenly reverted the changes.

bnjmnm’s picture

Issue tags: -Needs reroll
StatusFileSize
new28 KB
new146.1 KB

Addresses the custom commands failed, and renames the module (maybe it should just be autocomplete? Added the "Drupal" to make it easier to distinguish from jQuery UI autocomplete)

bnjmnm’s picture

Issue summary: View changes

Updated the issue summary with specifics regarding proposed approach to deprecating jQuery UI, and when/how the experimental module introduced here would be promoted to stable.

bnjmnm’s picture

Issue summary: View changes

Fixed IS formatting problems

lauriii’s picture

Tagging for release manager review since I think we are finally ready for that 🙂Thank you for updating the IS @bnjmnm!

xjm’s picture

bnjmnm’s picture

StatusFileSize
new146.09 KB
bnjmnm’s picture

It's been suggested that the new autocomplete be added directly to core instead of as an experimental module. This is because such a change is feasible now that the Autocomplete replacement is no longer a library, but a part of core that we have more control over. @lauriii and I discussed what a fully BC-supporting + deprecation-packed shim would require:

Markup

  • Backwards compatible markup will be added in core, but override options will be deprecated
  • Port jQuery UI “markup structure” test to run with drupal.autocomplete

jQuery Events

  • change
  • close (can be mapped to existing autocomplete-close event)
  • create (can be mapped to existing autocomplete-created event)
  • focus
  • open (can be mapped to existing autocomplete-created event)
  • response
  • search
  • select (can be mapped to existing autocomplete-selection-added event, but this event needs to be refactored so it can be cancelled before the selection occurs.)

jQuery Methods

Most of these are straightforward unless stated otherwise.

drupal.autocomplete settings

jQuery UI options

  • appendTo (will becomplex to shim)
  • autoFocus
  • classes (the need to shim this means jQuery UI markup will need to be generated by core autocomplete)
  • delay
  • disabled
  • minLength (can be mapped to existing minChars property)
  • position (will likely require something that converts jQuery UI position values into PopperJS config)
  • source (will be complex to shim)

Extension Points

While this would clearly require additional work, it adheres to the accepted upgrade path and removes the need to enable an experimental module that many may be unmotivated to enable.

bnjmnm’s picture

Pros/Cons of implementation options

Module Pros:

  • Sites can easily choose when to adopt the new autocomplete

Module Cons:

  • A risk of few sites enabling the module. Low adoption prior to the removal of jQuery UI autocomplete in Drupal 10 introduces a risk of bugs and other problems surfacing with no fallback available.
  • 9.x supporting contrib would need to support two Autocomplete APIs, and there may not be awareness there’s a second API to support.

Separate libraries pros:

  • Theoretically possible for core to fully switch to the new autocomplete while contrib continues to use the deprecated jQueryUI autocomplete. (There’s a pretty big “con” to this, see below)

Separate libraries cons:

  • Potentially lower rate of adoption than module
  • Providing a library with a "just be sure to not run both libraries at the same time" expectation seems prohibitively unreasonable.
  • The ability to have both libraries load simultaneously is possible with changes to Form API that are complex to categorize this as "con". Autocomplete functionality is initialized based on the presence of #autocomplete_route_name in ANY element extending FormElement, if this property is present, then several other #autocomplete_ prefixed elements may inform the final config. To avoid library collisions, it would require something like new autocomplete-specific render array properties that designate the library used, or new widgets that override \Drupal\Core\Render\Element\FormElement::processAutocomplete . There are several ways to go about this, but all seem like ones that would results in nontrivial Form API Changes.

Shim pros:

  • This approach has worked for jQuery Cookie and (most likely) tabbingmanager.
  • Eliminates the complexity of supporting two libraries simultaneously
  • The API would remain the same, so the functionality for contrib/custom would be unchanged other than some new deprecation notices.

Shim cons:

  • Significant effort to shim all of jQuery UI autocomplete features + provide test coverage. Potentially 1-2 weeks dev time. Note that 10% of these (potentially unpopular) features may consume ~80% of development time.
jonathanshaw’s picture

A risk of few sites enabling the module

That is mitigated if you enable it by default in the standard or minimal profiles, so new installs get it. And high-volume adoption would likely raise awareness in 9.x supporting contrib.

droplet’s picture

What is Module & Lib way?(I think I got it now after reading the below 2 comments) For me, I suggested making it a standard lib and add a module layer. (Both)

About the BC things, I suggested not to do it in the new module (or provide very limited support only, mainly handle the Events). And move current code into a contri-module as BC for old sites if needed.

There's a very long time ago, I suggested Drupal define its own API (Interface) for some (controversial) JS components. Then, we can plugin our own libs and interact with other libs more easily. I can predict still a lot of sites will drop the new lib and add Chosen-alike in the future. (The Core Needs are very different from the real-world)

catch’s picture

Except for the development time, the shim sounds like the best option here - we'll know everyone is using the same thing, so it's a lot more predictable.

A risk of few sites enabling the module

That is mitigated if you enable it by default in the standard or minimal profiles, so new installs get it. And high-volume adoption would likely raise awareness in 9.x supporting contrib.

This is tempting, but has the potential to break contrib modules and themes that aren't updated yet (possibly in a non-obvious way for people installing core for the first time).

xjm’s picture

As far as I'm concerned, the experimental module approach is off the table at this point. We originally went that direction over a year ago when we thought we'd be adopting an autocomplete library that had new features and such. Awesomplete turned out not to be more of a BC solution rather than anything adding new features, so from that point on the module approach wasn't really on the table from a product perspective. For something to be exposed to the site builder as a module, it should include features or enhancements valuable to the site owner that don't exist with it disabled.

So, let's go ahead with the shim approach. As much as possible, we should keep the use of jQuery limited to the shim, and make the shim self-contained so that it can be cleanly deprecated for a clean removal in Drupal 10. We'll want to thoroughly document the primary API, the shim API, and the upgrade path as we go through it.

Thanks everyone!

xjm’s picture

Title: Provide an experimental module to replace jQuery UI autocomplete » Provide a new library to replace jQuery UI autocomplete

Retitling to reflect the current scope. Thanks!

bnjmnm’s picture

StatusFileSize
new154.21 KB
new87.02 KB

Two patches here

  • autocompletePortedTests takes all but 3 of jQuery UI's autocomplete tests and ports them to nightwatch. These tests will be used to confirm the soon-to-be-added shim provides the same functionality as jQuery UI
  • 3076171-104-NEW-LIBRARY moves the experimental module functionality to a new library, used by core/drupal.autocomplete. Some of the assets are not in their final location, and several things will need renaming. Although there are still many outstanding tasks, there are enough changes here to warrant posting a patch to show the progress.

These two patches will ultimately combine into one, but it's necessary to have a passing patch with just the ported jQuery UI autocomplete tests to confirm they pass with jQuery UI autocomplete's code, and they will all need to pass with the shimmed code.

bnjmnm’s picture

StatusFileSize
new301.89 KB

This adds a (gigantic) BC shim for jQuery UI autocomplete. All the tests ported from jQuery UI work with the shim+Drupal Autocomplete. Given the flexible usages of jQuery UI Autocomplete, There are likely additional considerations not covered by the ported-over tests. Those will be easier to identify once I've had a bit of time away from this (the shim took quite a while...)

Note that this patch has small changes to Claro's autocomplete.js so tests that were helpful to this overall process would pass and. To make those changes unnecessary, the shim will need to adjust the markup around the input (the markup for the list is already fully shimmed).

Two definite next steps are:

  1. Have the shim markup manipulation extend to the input element.
  2. Refactor and comment to make this easier on reviewers - it's going to be rough enough in a best case scenario
bnjmnm’s picture

bnjmnm’s picture

A few things I noticed in #105 that need addressing:

  1. +++ b/core/misc/jqueryui.autocomplete.shim.es6.js
    @@ -0,0 +1,417 @@
    +  function returnFalse() {
    +    return false;
    +  }
    

    This should get a doc to indicate that it's a seemingly pointless function used by the copy of jQuery on() just below this. Ideally creating a copy of this function would not be necessary at all.

  2. +++ b/core/misc/jqueryui.autocomplete.shim.es6.js
    @@ -0,0 +1,417 @@
    +  $.fn.extend({
    ...
    +    on(types, selector, data, fn) {
    +      // Translate the jQuery UI events to Drupal Autocomplete.
    +      const eventsToAddListenersTo = {};
    +      const autocompleteEvents = {
    +        autocompletechange: 'autocomplete-change',
    

    This is something that will need to be changed. This is not functionality specific to autocomplete, so it shouldn't be in an autocomplete specific shim. There will almost certainly be future, non-autocomplete, needs to override this such as adding deprecation notices and shimming dialog. There's an issue that will likely require a centralized override for jQuery events: #3176441: JavaScript event handling without a full jQuery dependency.

    I'm also not sure if this accounts for one()

  3. +++ b/core/misc/jqueryui.autocomplete.shim.es6.js
    @@ -0,0 +1,417 @@
    +          case 'instance':
    +            return {
    +              document: $(document),
    +              element: $(instance.input),
    +              menu: {
    +                element: $(instance.ul),
    +              },
    +              liveRegion: $(instance.liveRegion),
    +              bindings: null,
    +              classesElementLookup: null,
    +              eventNamespace: null,
    +              focusable: null,
    +              hoverable: null,
    +              isMultiLine: null,
    +              isNewMenu: null,
    +              options: null,
    +              source: null,
    +              uuid: null,
    +              valueMethod: null,
    +              window,
    +            };
    

    Most (probably all) the nulled values here need to be populated.

bnjmnm’s picture

StatusFileSize
new300.74 KB
new33.44 KB

Takes care of:
#105.1
#105.2 (partially)
#107.1
#107.2

#107.3 was expanded on a bit, but I'll need to dig further into jQuery UI to see how to get all those properties (or determine it's reasonable to not include them)

nod_’s picture

Status: Needs review » Needs work

There are shims a little all over the place, in autocomplete-init as well as jqueryui.autocomplete.shim.es6.js can we put all in one place?

I would reduce the API we support from jQueryUI do we need all those options this in the ally_autocomplete script?

  1. +++ b/core/.eslintrc.json
    @@ -20,7 +20,8 @@
    +    "DrupalAutocomplete": true
    
    +++ b/core/misc/a11y_autocomplete/autocomplete.es6.js
    @@ -0,0 +1,1032 @@
    +    this.count = document.querySelectorAll(
    +      '[data-drupal-autocomplete-input]',
    +    ).length;
    

    So this is a roundabout way to have a counter and have a unique number for this specific instance. Not a fan of indirectly making a counter like that.

  2. +++ b/core/misc/a11y_autocomplete/autocomplete.es6.js
    @@ -0,0 +1,1032 @@
    +        'When autocomplete results are available use up and down arrows to review and enter to select. Touch device users, explore by touch or with swipe gestures.',
    

    Need to have that translatable somehow

  3. +++ b/core/misc/a11y_autocomplete/autocomplete.es6.js
    @@ -0,0 +1,1032 @@
    +    // If jQuery is available, use it to add events listeners. Otherwise use
    +    // vanilla JavaScript.
    

    We should go with native only. the point is to remove jquery dependency at some point so why not start now if that works?

  4. +++ b/core/misc/a11y_autocomplete/autocomplete.es6.js
    @@ -0,0 +1,1032 @@
    +  implementWrapper() {
    

    It's hard to follow that the HTML will look like, might want to have comments explaining the whole structure. And while we don't have to use Drupal.theme having a "theme" function here might be a good thing, makes it easier to override too

  5. +++ b/core/misc/a11y_autocomplete/autocomplete.es6.js
    @@ -0,0 +1,1032 @@
    +    // Delay the announcement by 500 milliseconds. This prevents unnecessary
    +    // calls when a user is navigating quickly.
    

    Is that actually helping? a user navigates quickly but doesn't know if hitting keyup/down does anything like this no?

  6. +++ b/core/misc/a11y_autocomplete/autocomplete.es6.js
    @@ -0,0 +1,1032 @@
    +      this.cache[inputId] = {};
    

    how is it invalidated?

  7. +++ b/core/misc/a11y_autocomplete/autocomplete.es6.js
    @@ -0,0 +1,1032 @@
    +window.DrupalAutocomplete = DrupalAutocomplete;
    

    not a11y_autocomplete?

  8. +++ b/core/misc/autocomplete-init.es6.js
    @@ -0,0 +1,341 @@
    +      const pluralMessage =
    +        maxItems <= this.totalSuggestions
    +          ? 'There are at least @count results available. Type additional characters to refine your search.'
    +          : 'There are @count results available.';
    +      return Drupal.formatPlural(
    +        count,
    +        'There is one result available.',
    +        pluralMessage,
    +      );
    

    This is not translatable,
    Need to have on call to formatPlural and a different one to Drupal.t() with the @count parameter

Would welcome a merge request to simplify review.

nod_’s picture

+++ b/core/misc/autocomplete-init.es6.js
@@ -0,0 +1,341 @@
+    detach(context) {
+      context.querySelectorAll('input.form-autocomplete').forEach((input) => {
+        const id = input.getAttribute('id');
+        Drupal.Autocomplete.instances[id].destroy();
+      });
+    },

Need to check the trigger parameter and check that it's "unload", otherwise this will destroy autocomplete on ajax requests (trigger = "serialize"), like adding a paragraph or adding a media.

nod_’s picture

proposed resolution is not up to date

nod_’s picture

Following a meeting with bnjmnm, lauriii, gabor, and myself, todo:

  • Need to have a way to use autocomplete with and without the shim at the same time
  • Define/document the Drupal API supported by a11y_autocomplete, create the @drupal/a11y_autocomplete package in the project: https://www.drupal.org/project/a11y_autocomplete
bnjmnm’s picture

bnjmnm’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs issue summary update

Updated issue summary, and

I also moved the A11y_autocomplete code to /vendor, although it's not yet available as a standalone library - something that will happen in #3204530: Create autocomplete JS library (but I need some assistance with).
It is being moved to /vendor now to make it clear that it doesn't need to be part of the reviews in this issue. There's PLENTY of other code that needs review here, so getting that moved may make reviewing slightly less ominous.

bnjmnm’s picture

artusamak’s picture

Just sharing this link that crossed my Twitter feed that may be helpful: https://adamsilver.io/blog/building-an-accessible-autocomplete-control/

Thanks for your work.

zrpnr’s picture

This wasn't working in IE11 so I added the polyfills as dependencies to the a11y_autocomplete library

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

bnjmnm’s picture

Version: 9.3.x-dev » 9.2.x-dev

Switching branch to 9.2

andypost’s picture

zrpnr’s picture

Still digging into this MR, but wanted to mention something that stood out to me:
in the removed autocomplete.js there was a property: firstCharacterBlacklist
which is set by data-autocomplete-first-character-blacklist

In the new version, that property is changed to firstCharacterDenylist and set by data-autocomplete-first-character-denylist

in core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php should the old data attribute be changed to the new one?
blacklist --> denylist

Or should the shim convert the old property name to the new one?

bnjmnm’s picture

The last few commits added BC support for jQuery UI Autocomplete extension points. There are two additional things that need to be done with this

  • Add the ability to customize extension points via calls to $.widget()
  • Add ports of any jQuery UI qunit test that included extension points. These were among the few not included in the intial ports

These additional tasks do not need to block review. It will not fundamentally alter what is already there, there will likely be a few dozen additional lines added to the several thousand that are already there, and they can be reviewed at a later stage.

bnjmnm’s picture

Issue summary: View changes

IS update

bnjmnm’s picture

Most recently I added support for the _render extension points and ported a test.

There's currently a test failure in a test that checks for a deprecation triggered in template_preprocess_input. If I run the test with xdebug, the line triggering the deprecation is reached. That test fails whether or not the deprecation is in the skipped deprecation list.

bnjmnm’s picture

I was taking a look through config uses, and I'm concerned about uses such as this one from the https://www.drupal.org/project/erd project: https://git.drupalcode.org/project/erd/-/blob/8.x-1.x/js/main.js#L52-56

  /**
   * Defines a custom autocomplete to select entity bundles and types.
   */
  $.widget('custom.erdautocomplete', $.ui.autocomplete, {
    _create: function () {
      this._super();
      this.widget().menu('option', 'items', '> :not(.erd-autocomplete-category)');
    },

The current MR has already extended jQuery UI's $.widget to allow _render extension points via the shim. The example above hints at just how much more needs to be addressed to truly support a shimmed autocomplete + using $.widget to customize it. In just the one contrib use above, it shows the need to support overriding _create</code, the <code>this expects to have the functionality provided by code>_super() and widget() (which definitely needs a menu property, but undoubtedly requires more). Just supporting the above contrib use case will likely require significant additional complexity and filesize. It doesn't seem feasible to approach it like that. These are some of the options that come to mind:

  • For modules customizing autocomplete in ways that too complex to be supported by the shim, Provide a contrib module that depends on https://www.drupal.org/project/jquery_ui_autocomplete and overrides the drupal.autocomplete library to use jQuery UI autocomplete instead.
  • Look into implementing the shim via $.widget(). The this would at least be available, but it would still need all sorts of overriding
  • Make the shim be the default, but leave jQuery UI autocomplete in for the rest of 9.x and make it reasonably easy to switch to it if necessary. Warnings could be triggered if there are attempts to use the shim in ways that are unsupported, and they could provide steps on how to use jQuery UI autocomplete instead. Other jQuery UI libraries were deprecated in 8 before being completely removed in 9.
  • Add several hundred lines (at least) of code to the existing shim to support all the ways $widget facilitates extension, and mentally prepare to do the same complex steps for dialog.
kim.pepper’s picture

Issue tags: +#pnx-sprint
rikki_iki’s picture

Make the shim be the default, but leave jQuery UI autocomplete in for the rest of 9.x and make it reasonably easy to switch to it if necessary. Warnings could be triggered if there are attempts to use the shim in ways that are unsupported, and they could provide steps on how to use jQuery UI autocomplete instead. Other jQuery UI libraries were deprecated in 8 before being completely removed in 9.

Seems reasonable to me. I certainly don't think supporting all the possible uses of $widget is viable, and adding a contrib module to revert to jQuery IU seems like it would limit contribs adoption of this replacement.

Fantastic work here btw!! It's really exciting :)

bnjmnm’s picture

Version: 9.2.x-dev » 9.3.x-dev
nod_’s picture

added #3217881: Reduce public API surface to the patch, and updated the core implementation accordingly, seems to be working as expected.

nod_’s picture

pushed a pretty significant update, tried to decouple things as much as possible between the vanilla script and the jquery shim, cleaned up the library definition too.

once this is more or less good I think we need to split this issue up:

  1. Add autocomplete and polyfill libs (no integration yet)
  2. Add the shim library and and tests
  3. Finally make the actual change to the drupal.autocomplete library declaration and relevant tests, deprecation notices, etc.

We're missing styling for the vanilla autocomplete I think, right now the dropdown is transparent :p

nod_’s picture

Much better, nightwatch test works now. jquery ui test stuff failed because I changed the library definition back to what it was.

nod_’s picture

we might need to split this issue a bit once it's closer to green.

  1. add the autocomplete lib
  2. add the new autocomplete init
  3. Add the shim layer & tests
  4. Replace all uses of jquery-era autocomplete and trigger deprecations

what do you think?

bnjmnm’s picture

The deprecation test was removed as the deprecation itself needs to be skipped as the shim must run to provide markup BC. f19d733b and its results triggering the deprecation 145 times is confirmation the deprecation works. I'm not sure how long those test results are available, but there's a bunch of

Remaining self deprecation notices (5)

  5x: The jQuery UI markup structure is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Use the API provided by core/a11y_autocomplete instead. See https://www.drupal.org/node/3083715

Re #133
Having a separate issue for adding the Autocomplete lib sounds good.

I'm not sure if the init can be added without the shim because the non-shimmed autocomplete has different markup, which would be a BC issue. We could potentially do something like Tour/Joyride/Shepherd where the BC markup support is provided via Stable/Stable9. This could potentially be good as it separates concerns, but there's also the risk of introducing even more complexity as many of the shim's overrides handle API and markup in the same place. The markup BC is also a barrier to making it possible to replace jQuery-era autocomplete so maybe it is necessary to move the markup portion to Stable despite what it may introduce to the scope of this already large issue.

bnjmnm’s picture

Issue summary: View changes
bnjmnm’s picture

Issue summary: View changes
tim.plunkett’s picture

Status: Needs review » Needs work
Issue tags: -Drupal 9 +Needs change record updates

We need to specifically document what areas of the API get BC and which do not, this should be done in the draft change record.

bnjmnm’s picture

Issue summary: View changes

Updated IS to cross out completed remaining tasks.

bnjmnm’s picture

Here's a video of the autocomplete appearance in all core themes https://youtu.be/YpO-_MRT5uo

This will appear slightly different from the jQuery UI version due to the way focus is managed. In jQuery UI autocomplete, only the autocomplete input is focusable. When navigating through the result list, a highlighted item doesn't receive focus... focus always remains on the input.

Using https://github.com/alphagov/accessible-autocomplete as inspiration, keyboard navigation of list items results in them being focused, and (unlike jQuery autocomplete )focus styles are different from hover styles. Hover and focus are two separate things, after all, and that difference should be conveyed visually.

bnjmnm’s picture

Accessibility Review Material

Screenreader / AT Walkthroughs

With the new core autocomplete: https://youtu.be/3zTjNJd4Uqs

The same walkthrough was also performed with the UKGov Accessible Autocomplete. This is the library Drupal core would have likely used were it not missing some features required by any autocomplete replacing jQuery UI's: https://youtu.be/7sh9xLfbyLg and it's design was informed by user testing. The goal was for Drupal's autocomplete to at least be as accessible as this

Both walkthroughs test the following screenreader/browser comos (in the same order):

  • Safari + Voiceover (OSX)
  • Chrome + Voiceover (OSX)
  • Chrome + Jaws (Windows)
  • Edge + Narrator (Windows)
  • Edge + NVDA (Windows)

The Core autocomplete walkthrough ends with an example of using OSX voice control to operate the autocomplete.

Hover/Focus

Originally posted in #139, this video demonstrates the hover & focus states of the new autocomplete in core, with all core themes. Note that this begins with an example using the Stable theme that knowingly does not highlight the entire width of the list item on hover. This is intentional as it fully replicates the markup/ui provided by jQuery UI autocomplete in order to fulfill the BC promise https://youtu.be/YpO-_MRT5uo

The other examples will appear slightly different from the jQuery UI version due to the way focus is managed. In jQuery UI autocomplete, only the autocomplete input is focusable. When navigating through the result list, a highlighted item doesn't receive focus... focus always remains on the input. With this new autocomplete, hover and focus are now visually distinct from one another.

Shared this with the #accessiblity channel in Drupal Slack shortly before 5pm on Mon, Oct 18.

andrewmacpherson’s picture

I'd like to try this out myself. Say, using a taxonomy reference with a large vocabulary. I can only see LinkWidget in the diff, but the video seems to show an entity reference. What's involved in getting this running? Say with a term reference field and a large vocabulary.

I found the video in #139 hard to follow.

Re. #140:

Firefox is notably absent from the demos.

The demos sounded remarkably verbose to me, with much redundant information. I think some of the custom announcements may not be necessary. It's worth doing a detailed comparison.

It also sounds like you've tried to emulate VoiceOver's optional training hints. I fear those may annoy a lot of users; VoiceOver's training hints can be turned off, and other screen readers don't have anything so verbose.

The Core autocomplete walkthrough ends with an example of using OSX voice control to operate the autocomplete.

This was very brief.

The choice was made using the show-numbers tool. Is it possible to make a choice without resorting to that?

Has this been tested with any other speech control apart from Apple's?

andrewmacpherson’s picture

There are lots of mentions of "the shim", but the issue summary doesn't explain it well. Is that explained in another issue?

Awesomplete was literally the only library without significant accessibility regressions compared to jQueryUI and one that could be added with the least disruption so that was the library we chose.

It was then observed that the amount of customization required for the Awesomplete implementation was significant enough that we were using very little of the library itself, and it may be simpler to make the solution entirely custom.

My recollection is different. The main problem with Awesomeplete was that in some situations it would misreport the control's value to assistive tech, which was a critical blocker.

lauriii’s picture

Discussed with @catch, @nod_ and @bnjmnm the approach for the BC layer on this issue. The overall approach seemed like it was going to the right direction. However, there were few changes that we thought would be useful to make:

  1. Remove data-drupal-10-autocomplete since it isn't needed anymore now that markup BC layer has been moved to Stable
  2. Ensure that the shim only triggers deprecation warnings when the shim is not used meaning that the initialization of the shim shouldn't trigger deprecation warnings.
  3. Make the shim more specifically target the drupal.autocomplete use case to avoid breaking use cases where jQuery UI autocomplete is initialized directly.
nod_’s picture

Thanks for the thorough review and background info on the implementation Ben.

@andrew thanks for taking the time to take a look. I'm working on the new standalone Autocomplete implementation so I'm following this very closely. I'm having a hard time understanding the specific actions you're asking for though.

  • Do you mean Firefox testing is required to pass the accessibility core gate or is it something you would have liked to have?
  • Putting my core committer hat on, I'd like to have a list of required/supported software/hardware setup that explain what we need to test for to pass the accessibility core gate. This should be it's own spin off issue though.
  • from what Ben said the verbosity is to mimic the implementation which went through extensive user testing. If it is too verbose, what do you think should be the exact level of verbosity? Right now m happy to tweak the implementation but at my level it's not actionable feedback on this topic and I'm not sure of what the detailed comparison would entail
  • the numbers tool I don't know what it's referring to so I'll defer to Ben on that. I'm not sure of what you are asking though, is this a core gate requirements?
  • for speech control I wasn't aware we were even testing for that in core so guidance on the specific list of software to test for would be welcome

It seems the level of accessibility review differs depending on the issue, the core gate doc are pretty vague too so it might be worth revising them to add some more details.

bnjmnm’s picture

Issue summary: View changes

nod_’s picture

The last test failure from the dontbreakstuff branch happens when the form-autocomplete class is added. even before the shim is changed to make use of the class to know if it needs to call the old autocomplete or our version. Not sure what's happening.

The commit in question: https://git.drupalcode.org/project/drupal/-/merge_requests/1356/diffs?co.... the previous commit passed the tests.

bnjmnm’s picture

Re #147

8a12c198 - Revert "Update shim trigger with class instead of attribute" + 8a12c198 - Revert "Update shim trigger with class instead of attribute"

Triggering the shim with the class present instead of an attribute had been passing all tests - this is the most recent commit where all tests were passing + included this change. https://git.drupalcode.org/project/drupal/-/merge_requests/413/diffs?com...

The corresponding test run is https://www.drupal.org/pift-ci-job/2214154

The commit that reverts that removes a few pieces of functionality that we discussed along with @lauriii,

  • It removes the ability to use a non-overridden jQuery autocomplete. That needs be provided in some capacity for modules that want to use a contrib jQuery autocomplete that isn't shimmed.
  • To remove the data attribute requirement for making the shim available - it's simply available for the rest of 9.x and only triggers deprecations when used (as opposed to loaded). There were several benefits to this if I recall - one I remember offhand is it would eliminate some procedural awkwardness of having to deprecate an attribute that only existed due to other code being deprecated.
nod_’s picture

yeah not planning on removing this feature. Just trying to see if there are other problems.

bnjmnm’s picture

#149

yeah not planning on removing this feature. Just trying to see if there are other problems.

Ah that makes sense. Carry on!

nod_’s picture

now the question is how much of EntityReferenceAutocompleteWidgetTest::testAutocompleteOptions do we want to keep knowing the lib is pretty well tested already. We should have some but maybe not as much if some of them can be included upstream (like for the ignored char search trigger thing?

nod_’s picture

Status: Needs work » Needs review

Removed some test cases for options that are not supported by the library anymore (sort/displaylabel) should be green, we can see what else we want to test for in the core patch vs. the library itself.

nod_’s picture

All right finally back to green, thanks for your patience.

Added a few things to make integration easier with things like link it, fixed a few edge cases (avoid double initialization of Autocomplete, introduced a few helpers to make the shim code less verbose/brittle.

On the test coverage there are 2 night watch tests that don't test what they are supposed to otherwise they are good.

As far as feature go I'd like to add back the classes options because the shim and modules like link it rely heavily on it.

andypost’s picture

Version: 9.3.x-dev » 9.4.x-dev

Now it's 10.0/9.4 material, patches are hidden because work happens in merge requests

nod_’s picture

Umm so there is some issue with the latest merge from 9.3.x haven't had time to track it down and I'm off tomorrow. Will pick it up on Friday if nobody beats me to it.

nod_’s picture

I think we might need to add some more features to the BC layer, namely supporting wiget's _search and _response as boostrap theme is using them: https://git.drupalcode.org/project/bootstrap/-/blob/8.x-4.x/js/misc/auto... and with 65k+

nod_’s picture

With latest patch + the merge request to add the _search and _response overrides bootstap theme works as expected.

bnjmnm’s picture

Issue summary: View changes
bnjmnm’s picture

So there are a bunch of new failing nightwatch tests! Here's why:
We established that it needs to be possible to use non-shimmed jQuery autocomplete, since that could be added via contrib and there may be uses that are simply unshimmable. The presence of the autocomplete shim can't prevent direct jQuery autocomplete use from working (despite the fact that it overrides $.ui.autocomplete)

So I added tests that run the nightwatch tests in three additional scenarios
- jqueryUIAutocompleteShimTestBypassA11yAutocomplete runs the suite of tests on a page where the jquery-overriding shim is loaded, but no input uses the shim, just a direct invocation of jQuery UI autocomplete.
- jqueryUIAutocompleteTestDirectWhileShimmedPresent runs the suite of tests on a page where both shimmed and direct-jQuery-autocomplete inputs exist. The tests are performed on the input invoking jQuery UI autocomplete directly.
- jqueryUIAutocompleteTestShimmedWhileDirectPresent runs the suite of tests on a page where both shimmed and direct-jQuery-autocomplete inputs exist. The tests are performed on the shimmed input.

These new tests have several failures. Most (perhaps all?) of them are due to jquery.event.overrides.js and jqueryui.widget.overrides.js unconditionally overriding jQuery UI autocomplete functionality - it assumes the use is shimmed. This breaks direct (non-shimmed) usage of jQuery Ui autocomplete. It's not immediately clear how to address the widget overrides since there's no element involved.

bnjmnm’s picture

StatusFileSize
new1.5 MB

Attaching a video to demonstrate that typing with an IME does not trigger an autocomplete search until composition is complete, so it's not necessary to port the Drupal.autocomplete.isComposing property & the related handlers.

bnjmnm’s picture

As of the most current commit, Nightwatch tests are still not passing on drupalci, nor do they pass when I run yarn test:nightwatch locally. However, they all pass when run individually. I suspect this is a side effect of tests extending jqueryUIAutocompleteShimTest via Object.assign(). The solution may be obvious once I spend a little bit of time away from this evil MR.

nod_’s picture

I think the last commit did it \o/

bnjmnm’s picture

Issue summary: View changes

Update IS

bnjmnm’s picture

Issue summary: View changes
bnjmnm’s picture

THE CURRENT STATE OF THESE EFFORTS

Activity on this issue may be less frequent. There is less urgency to get this completed for several reasons:

  • There is confirmation that jQuery UI is not EOL. This October 2021 announcement clarified it is "minimally maintained"; security + jQuery core compatibility will be supported. Shortly after, there was a 1.13 release
  • The extensive work done so far surfaced a wide range of edge cases that were addressed, but suggest there may be even more that haven't been identified. There are risks in introducing such elaborate changes to Drupal core.
  • Multiple contributors to this issue (including myself) have become fluent enough with the internals of jQuery UI that we're quite capable of fixing issues upstream. Fixing issues upstream means Drupal sites can continue using the existing autocomplete API without having to make potentially complex changes in order to work with Drupal 10.

It is worth mentioning that issue is quite far along. The issue summary has been updated to accurately reflect the remaining tasks. Aside from adding tests for Drupal.autocomplete deprecations and minor cleanups the MR is potentially complete and awaiting reviews/signoffs.

bnjmnm’s picture

I commented out event delegation tests - they are passing locally but not on Drupal CI. Fixing or removing them will be necessary.

Despite this (and there needing to be deprecation tests), this issue can be considered ready for review, signoff, etc. If there is momentum behind that it can justify the effort needed to complete those final tasks. Moving this issue forward is predicated on someone having the willpower to go through this enormous MR, so it would be good to confirm such individuals exist before moving forward with final touches.

NIKS_Artreaktor’s picture

I propose autocomplete library, free from Jquery.
1) Good with accessibility
2) light
3) working with most type of data - static file, axios, jquery ajax, Promises fetching data.
4) A lot of hooks and options. could be rewrited.

https://tomik23.github.io/autocomplete/#started
https://github.com/tomik23/autocomplete

effulgentsia’s picture

I'm starting to review this MR. One thing I'm tripped up on at the moment is that the MR has lines like the following...

'Drupal.autocomplete.ajax is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Override the source method of A11y_Autocomplete instead. See https://www.drupal.org/node/3083715',

'Drupal.autocomplete.cache is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. It is now handled automatically and should not be manually configured. See https://www.drupal.org/node/3083715',

'Drupal.autocomplete.splitValues is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Override the splitValues method of A11y_Autocomplete instead. See https://www.drupal.org/node/3083715',

But I don't see details or examples about these in https://www.drupal.org/node/3083715.

bnjmnm’s picture

Re #168 The Drupal.autocomplete deprecations are some of the most recent changes. The need to deprecate properties of the existing autocomplete API was discovered very late in the process. I believe the change record was not updated since those changes were made. If this is adding difficulty to the (very appreciated) review, I'm happy to get the CR current.

effulgentsia’s picture

jQuery UI, per an announcement in October 2021 jQuery UI's maintainers clarified it is not EOL

Based on this, I spoke with @bnjmnm, @nod_, and @lauriii about how they feel about the current state of the a11y_autocomplete library and this MR. The following comment is based on that discussion....

Problem

The people who worked on this issue are concerned that as things currently stand, that the a11y_autocomplete library will be harder to maintain for Drupal 10's lifetime than jQuery UI autocomplete, primarily because it's a new library that hasn't been battle-tested in production yet. For example, @nod_ recently discovered a memory leak with it.

That's not even counting the remaining work needed to get this MR reviewed/completed, or the extra maintenance cost of the backwards compatibility shim that's in this MR that would need to be maintained for Drupal 9's lifetime.

However, while that might be the short-term situation, in the long run we do not have confidence that jQuery and jQuery UI will be maintained in a way that supports Drupal core's needs, so we would still like to replace jQuery UI autocomplete eventually, possibly as soon as for Drupal 11.

Background

The approach taken up until now in this issue was based on a prior condition that jQuery UI was an abandoned project. The need was therefore to replace the jQuery UI autocomplete library with something else as quickly as possible (in Drupal 9, in order to remove jQuery UI from Drupal 10), even if the replacement came with its own challenges (as any replacement would). However, since then, jQuery UI became un-abandoned, so we now have the luxury of time in which to optimize how we want to roll out the replacement.

In working on this issue, the team discovered that Drupal's autocomplete has a large JavaScript API surface, because it exposes all of jQuery UI autocomplete's API surface and then some. Contrib projects, including some popular ones, like Bootstrap, use various parts of this API.

The PHP API is minimal:

  • Set #autocomplete_route_name (and optionally, #autocomplete_route_parameters) on a form element.

Doing that causes FormElement::processAutocomplete() to add the 'form-autocomplete' CSS class to the element, which causes the Drupal.behaviors.autocomplete JavaScript behavior to attach the jQuery UI autocomplete widget to the element. From the perspective of the PHP API, we could easily replace the jQuery UI widget with a different JavaScript library just by changing the logic of Drupal.behaviors.autocomplete.attach().

However, the JavaScript API is where things get tricky:

  • For an element that Drupal.behaviors.autocomplete.attach() has already attached an autocomplete widget to (e.g., because it's a Drupal form element that had its #autocomplete_route_name set), JS code can call $(element).autocomplete(optionName, value) in order to change any of jQuery UI autocomplete's 26 options, methods, events, or extension points as well as additional ones from the base widget. Some of these options are coupled to jQuery; for example, they receive jQuery objects or jQuery event objects.
  • For an element that doesn't already have an autocomplete widget attached (e.g., because it does not correspond to a Drupal form element that had #autocomplete_route_name set), JS code can call $(element).autocomplete({option1: value1, option2: value2, ...}) in order to attach an autocomplete widget with those options.
  • To affect all autocomplete elements, JS code can extend the jQuery UI autocomplete widget factory by calling $.widget('ui.autocomplete', $.ui.autocomplete, {_option1: value1, _option2: value2, ...}).
  • In addition to all of the above that's exposed by jQuery UI, Drupal also exposes a Drupal.autocomplete object that JS code can read or modify to alter the autocomplete behavior of all autocomplete elements.

The current merge request implements a shim that attempts to provide BC for all of the above APIs. While working on that MR, the team also discovered that Drupal has some JavaScript tests that rely on certain low-level behaviors of jQuery UI autocomplete (e.g., being able to access the list with either the up arrow key or the down arrow key) that differ from a11y_autocomplete (e.g., being able to access the list only with the down arrow key), so the shim also includes code that adds in the behaviors needed to make those tests pass. If committed to core, all of this shim code would add additional fragility and maintenance burden for the duration that it would need to be maintained.

Proposed resolution

If jQuery UI hadn't become maintained again, the best course of action might have been to commit the above MR to 9.4 and 10.0, remove the shim in 10.0, submit PRs to popular contrib projects to change their code from relying on the jQuery UI autocomplete APIs (which on 9.4 would start emitting deprecation notices and on 10.0 would break) to instead use the a11y_autocomplete API, and then deal with whatever bug reports come in if and when production sites run into bugs or unexpected behavior with a11y_autocomplete.

However, with jQuery UI being maintained again, I think we can make the replacement smoother on everyone by doing the following:

  1. Don't change anything in Drupal 9 core.
  2. Release an a11y_autocomplete integration module as a contrib module. This could be a module that alters the drupal.autocomplete library to remove the jQuery UI dependency/assets and replaces autocomplete.js with a JS file that instead attaches a11y_autocomplete instances to .form-autocomplete elements. This would break any module/theme that relies on the jQuery UI autocomplete API or behaviors, but we could release the module as alpha and include warnings on the project page to let people know to not use it if they are using a site that has any modules or themes that rely on the jQuery UI implementation. However, for sites that don't have any such modules or themes, we can start collecting real-world bug reports for a11y_autocomplete.
  3. For Drupal 10.1, create a small surface Drupal JavaScript API for autocomplete. For example, there's no reason why Bootstrap's autocomplete integration needs to depend on either jQuery UI or on a11y_autocomplete; we can instead create an implementation-agnostic API. In Drupal core, we can integrate this new API with the jQuery UI implementation. In the a11y_autocomplete integration module, we can integrate it with that implementation.
  4. Submit PRs to popular contrib projects to change to this new API.
  5. Once enough have committed these PRs, release a stable version of the a11y_autocomplete integration module, without the warnings about its incompatibilities with popular projects. This allows more sites to use this module, and as they do so, we gain more confidence in it.
  6. Deprecate the jQuery UI autocomplete APIs (create a shim that intercepts them and emits a deprecation notice, instructing people to use the small surface Drupal API instead).
  7. For Drupal 11.0, replace the jQuery UI autocomplete implementation with the a11y_autocomplete implementation.
effulgentsia’s picture

Issue summary: View changes

Adding a note to the IS about the proposed change in direction in #170.

xjm’s picture

The new proposal is definitely in line with what @catch was suggesting, and I think it makes sense too. Given there's a sufficient quorum of framework, frontend framework, and release managers in favor of something like #170, I'm explicitly moving this to #3265680: Deprecate dependencies, libraries, modules, and themes that will be removed from Drupal 11 core.

The parent is postponed for now, but will be active as soon as we branch 10.1.x. This issue does not need to be postponed, but we've agreed it will no longer block 10.0.0-beta1.

catch’s picture

Version: 9.4.x-dev » 10.0.x-dev

Moving to 10.x

lauriii’s picture

Discussed this issue with @xjm because there were some concerns in regards to the fact that jQuery UI autocomplete library has been deprecated in core, and removed from Drupal 10. As a result of the conversation, she asked me to document the status quo on the issue.

We have deprecated the core/jquery.ui.autocomplete library definition and removed it from Drupal 10. jQuery UI autocomplete is loaded internally as part of the core/drupal.autocomplete library. This doesn't have an impact on the autocomplete PHP API. Also, jQuery UI customizations on Drupal Autocomplete are possible but only by explicitly extending the drupal.autocomplete library.

What is not possible and what we have wanted to deprecate is the option to initialize jQuery UI autocomplete directly without also either depending on drupal.autocomplete or jquery_ui_autocomplete contrib module.

There are some use cases in the grey area. For example, widget factory is a jQuery + jQuery UI functionality and allows overriding the core implementation. I guess technically folks overriding jQuery UI autocomplete with widget factory should depend on jQuery UI even if they are only overriding Drupal autocomplete functionality. However, this continues to work by extending core/drupal.autocomplete. This use case seems very much of an edge case and should not have too much weight on our decision.

mgifford’s picture

Issue tags: +wcag135

Associating with WCAG 1.3.5.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new150 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

quietone’s picture

Issue summary: View changes
Issue tags: +Bug Smash Initiative

In a bugsmash group triage meeting, the two issues #582534: Free tagging vocabularies: Treatment of comma in Chinese and Unicode and #77045: Comma separated lists should obey regional settings were discussed. In that discussion catch noted that the replacement for JQuery UI autocomplete should be checked to see if it has the same problem.

I have added an item for that to the remaining tasks.

catch’s picture

chi’s picture

a11y_autocomplete

What's the point of naming libraries this way? Does it imply that libraries without a11y prefix have zero accessibility? I think all Drupal modules and libraries eventually should become accessible. We don't need to prefix them all with a11y. Another concern here is that users might think that accessibility is the only notable feature of this library.

Version: 10.0.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

xjm’s picture

Amending attribution.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.