🇮🇳India @kulpratap2002

Account created on 27 September 2024, 12 months ago
#

Recent comments

🇮🇳India kulpratap2002

Previously code uses:

$attribute_value = Html::cleanCssIdentifier($attribute_value);

This method is designed to sanitize CSS identifiers (e.g., class names, IDs).
It ensures they are valid by replacing leading numbers and stripping disallowed characters. However, this is too strict when applied to

HTML attribute values (such as `data)', because:

Valid `data-` attribute values may begin with digits (e.g., `550`).

Sanitization with cleanCssIdentifier() incorrectly rewrites these values (`550 → _550`).

$attribute_value = Html::escape($attribute_value);
    Context-appropriate sanitization:
  • `Html::escape()` encodes special HTML characters (`<`, `>`, `"`, `'`, `&`).
  • This prevents injection into the DOM or breaking out of the attribute context.
  • Preserves valid values:
  • Digits, letters, and safe symbols remain unchanged (`550` stays `550`).
  • Mitigates XSS:
  • Any attempt to inject markup like `">
    ...

    ` will be safely escaped:

  • `"><script>...</script>`
    Security Conclusion
  • `Html::cleanCssIdentifier()` is only necessary when generating CSS identifiers.
  • For attribute values in HTML, `Html::escape()` provides the correct level of protection against XSS.
  • Therefore, this change maintains security while restoring correct behavior for numeric and other valid attribute values.
🇮🇳India kulpratap2002

In the above image, we can see that in the Project Browser settings, the Recipes and Contrib Modules options are disabled, so the Recommended tab is not showing.

After enabling them, the Recommended tab becomes visible.

To fix this issue, we need to ensure that these options are automatically enabled during installation.

🇮🇳India kulpratap2002

Replaced Html::cleanCssIdentifier() with Html::escape() to prevent numeric data-* attribute values from being prefixed with underscores.

Please review.

🇮🇳India kulpratap2002

Are there any other configurations or settings that need to be set on the Drupal site? If I install the memcache_status module, there are no errors on the page.

🇮🇳India kulpratap2002
  • I have cleaned up the ImportConfigManipulator, and based on this, I also changed the ImportConfigManipulatorInterface
  • Methods can’t be made protected since they are defined in the interface. Implementations must keep them public; otherwise, it would break the contract and cause fatal errors.

Please review.

🇮🇳India kulpratap2002

I have solved the error and generated MR.

The reason $form_element = FormElementHelper::getElementByName([$key], $form); or $form_element = FormElementHelper::getElementByName(['submitted', $child_key], $form); does not work is because getElementByName() in Drupal core only accepts a string as its first argument, not an array.

Core internally compares this string against the element’s #parents array, joined with implode('][', …). Passing an array directly causes a PHP type error:
TypeError: Argument 1 ($name) must be of type string, array given

The correct approach is to convert any array of parent keys into a string before passing it, like this:

$form_element = FormElementHelper::getElementByName(implode('][', ['submitted', $child_key]), $form);
This ensures compatibility with both flat and nested form elements (Webforms, nodes, user profiles, etc.) without touching core.

Also, I have fixed this Issue 📌 webform file document field generates php TypeError caused by protected forms module Active .

Please review.

Thanks

🇮🇳India kulpratap2002

I fixed the warning by checking if the config value exists before using it. If nothing is saved yet, we just use an empty array as the default, so the form doesn’t try to read data from false.

🇮🇳India kulpratap2002

@berdir, I have removed it from the correct file.
Please review.

🇮🇳India kulpratap2002

I can't reproduce the issue with different file names; both use the same file path in my case, and no copy is created.

🇮🇳India kulpratap2002

This MR fixes the handling of the decline URL.
Right now, the block always assumes the value is an internal path, which breaks when you try to use a full external URL. The change makes it detect http:// or https:// and use the link as-is, while keeping the current behavior for internal paths.

Please review.

Thanks

🇮🇳India kulpratap2002

You have already done the changes, i have assigned this issue beacuse i didn't see any MR.

🇮🇳India kulpratap2002

Right now, when you add #attached['drupalSettings'] in a block’s build() method, those settings don’t always make it into the global drupalSettings unless the block also attaches a library. This feels like a change in behavior compared to earlier versions.

It would be more intuitive if settings from a block were always passed through, even without a library. That way we can attach simple data for frontend scripts without having to create a library just for it.

As a temporary workaround, you can either attach a library in the block or move the settings into hook_page_attachments().

🇮🇳India kulpratap2002

@jonedahn I didn't find this $view_config_updater = \Drupal::service(ViewsConfigUpdater::class); i think it is already updated.

🇮🇳India kulpratap2002

@sandeep_k you have not installed the "league/html-to-markdown": "^5.1" this is a package which is require to run this module.
You can see in the composer.json
After that reinstall the module.

🇮🇳India kulpratap2002

@omarlopesino I have created an action that downloads a ZIP file. For now, I have only created action for markdown.

For reference, I am attaching a video on how it works.

Please review.

Thanks

🇮🇳India kulpratap2002

Yes, I am on it and doing it the same way as you mentioned.
@omarlopesino We want both HTML and Markdown, or just Markdown, in the downloaded ZIP.

🇮🇳India kulpratap2002

I have fixed the pipeline issues.

Please review.

🇮🇳India kulpratap2002

After investigating, we found that the script expects a data-babel-source attribute on each

🇮🇳India kulpratap2002

Tested this patch and it works well.

  • The `layout_builder_preprocess_language_content_settings_table()` logic is migrated cleanly to a new class using the #[Hook] attribute.
  • layout_builder.module is now safely removable.

Marking this RTBC.

🇮🇳India kulpratap2002

I have applied the MR on a fresh Drupal 11.x site and confirmed the following through the UI:

  • Created a content type with a File field and tested upload and remove functionality. Everything worked as expected.
  • Repeated the test with an Image field — both upload and remove actions work correctly.
  • Verified behavior for single and multi-value fields.
  • Tested required field validation by removing the uploaded file — validation triggers as expected.
  • Confirmed no errors in the PHP logs or JavaScript console.
  • Verified that file_managed_file_submit() is now deprecated and the logic is moved to \Drupal\file\Element\ManagedFile::submit(), maintaining BC correctly.
  • Everything works as expected, and the code looks clean and standards-compliant.

Marking this issue RTBC.

Thanks!

🇮🇳India kulpratap2002
  1. Investigated and confirmed the issue originates from jQuery UI 1.10+ strict method behavior.
  2. Searched Webform module and custom code for any direct autocomplete('destroy') usage.
  3. Verified no explicit destroy calls exist — deduced issue happens during Drupal.detachBehaviors().
  4. Added data('ui-autocomplete') checks before calling .autocomplete('destroy') in patched logic but it also didn’t work.
  5. Explored related Webform behaviors (webformElementStates, webform.form.js, clientside_validation) for improper destroy usage.
  6. Validated that validate().destroy() was also unsafe and fixed it using a data('validator') check but it also didn’t work.
🇮🇳India kulpratap2002

@tim-diels I've updated the autofill behavior to include a more robust slugification process that properly removes consecutive hyphens and handles custom replacements.

Please review.
Thanks

🇮🇳India kulpratap2002

@harlor, I have done the changes as per your suggestions.
Please review.

🇮🇳India kulpratap2002

Since the MR was merged, please change the state of the issue.
Thanks.

🇮🇳India kulpratap2002

@lostcarpark Thanks, done the changes as per your suggestion.
Please review.

🇮🇳India kulpratap2002

@avpaderno If everything looks good now, can we move forward?

🇮🇳India kulpratap2002

I have updated the MR with the patch.

🇮🇳India kulpratap2002

@bigbabert Thank you for your suggestions,

But the ExtensionDiscovery service scans the entire filesystem and returns all available modules—whether enabled or disabled—including core, contributed, and custom modules. This makes it ideal for use cases requiring a comprehensive list of modules. In contrast, extension.list.module (or ModuleExtensionList) only lists currently installed and enabled modules, better suited for runtime logic such as plugin management or routing requiring active modules.

In my module, users can generate README files even for disabled modules, so we use ExtensionDiscovery to ensure those modules are included in the selection list. Additionally, we exclude modules located under core/modules to avoid cluttering the list with core system modules not relevant for README generation. Using ExtensionDiscovery allows us to provide a more complete and relevant module list for our use case, while extension.list.module would restrict us to only enabled modules and miss disabled but potentially important modules.

Also, the module is installing fine on my Drupal 11 fresh site. I have attached a video for reference.

Thank you.

🇮🇳India kulpratap2002

@bigbabert Thanks for the suggestion.

But I think it would become too complex if we had to read the main project composer.json file to determine the custom and the contrib folders.

So I updated the GenerateReadmeForm and ReadmeGeneratorCommandsto use a reliable method for collecting only top-level custom and contrib modules using ExtensionDiscovery.

src/Form/GenerateReadmeForm.php

public function getTopLevelCustomAndContribModules(): array {
    $modules = [];
    $discovery = new ExtensionDiscovery(DRUPAL_ROOT);
    $discovery->setProfileDirectories([]);
    $all_modules = $discovery->scan('module');

    foreach ($all_modules as $machine_name => $extension) {
      $module_path = $extension->getPath();

      if (str_starts_with($module_path, 'core/')) {
        continue;
      }
      $path_parts = explode('/', $module_path);
      $modules_index = array_search('modules', $path_parts);

      if ($modules_index !== FALSE) {
        $after_modules = array_slice($path_parts, $modules_index + 1);
        if (count($after_modules) !== 2) {
          continue;
        }
      }

      $info = $this->infoParser->parse($extension->getPathname());
      $modules[$machine_name] = $info['name'] ?? $machine_name;
    }

    asort($modules);
    return $modules;
  }

ReadmeGeneratorCommands

 public function generate(string $module): void {
    $discovery = new ExtensionDiscovery(DRUPAL_ROOT);
    $discovery->setProfileDirectories([]);
    $all_modules = $discovery->scan('module');

    if (!isset($all_modules[$module])) {
      $this->output()->writeln("Module '$module' not found in the filesystem.");
      return;
    }
    $extension = $all_modules[$module];
    $relative_path = $extension->getPath();

    if (str_starts_with($relative_path, 'core/')) {
      $this->output()->writeln("Core module '$module' is not supported.");
      return;
    }

    $module_path = DRUPAL_ROOT . '/' . $relative_path;
    $scanner = new CodebaseScanner($module_path);
    $moduleData = $scanner->scan();

    $config = $this->configFactory->get('ai_readme_generator.settings')->get();
    $apiKey = $config['api_key'] ?? NULL;
    $chatEndpoint = $config['chat_endpoint'] ?? NULL;
    $model = $config['model'] ?? NULL;

    if (empty($apiKey) || empty($chatEndpoint) || empty($model)) {
      $this->output()->writeln('<error>Please fill the AI configuration form first!</error>');
      return;
    }
    $ai = new AIResponse($config);
    $summary = $ai->summarizeArray($moduleData);

    $readme_path = $module_path . '/README.md';
    file_put_contents($readme_path, $summary);

    $this->output()->writeln("✅ README.md generated at: $readme_path");
  }

Please review the above code. If it's correct, I will update it in the module.

🇮🇳India kulpratap2002

@avpaderno Thank you for the review.
I've made the suggested changes.
Kindly have a look and let me know if anything else needs to be updated.
Thanks.

🇮🇳India kulpratap2002

@vishal.kadam Thank you for the review.
I've made the suggested changes.
Kindly have a look and let me know if anything else needs to be updated.
Thanks

🇮🇳India kulpratap2002

I have resolved the styling issue.
Please review.

Production build 0.71.5 2024