Issue #3499451: Restore toolbar chatbot state idempotently so a dialog re-attach cannot close it

Closes #3499451.

Refactored onto 1.x per the review on !1277 (which targeted 1.2.x). Same fork branch, retargeted to the default development branch; original approach by joshua1234511.

Problem

The toolbar chatbot closes itself and cannot be reopened without a page reload when a CKEditor or Media Library dialog is used while the chatbot is open.

Root cause

attach() restores a saved-open chatbot by calling the blind toggleChatbot(), which does classList.toggle('ai-chatbot-opened'). When a dialog re-attaches behaviors and the toolbar button is re-rendered, once() processes the new button and the blind toggle flips an already-open chatbot closed. The close persists to localStorage, so the next restore reopens then a later re-attach closes it again, and the user cannot recover without reloading.

Fix

Replace the restore and toggle with an idempotent setChatbotOpen(open) that sets the body class to match the requested state instead of flipping it. Restoring an already-open chatbot on re-attach is now a no-op. Single file: modules/ai_chatbot/js/toolbar-chatbot.js.

Testing steps

  1. Install and enable the toolbar chatbot; place the AI chatbot in the toolbar and open it (body gets ai-chatbot-opened).
  2. Edit a node with a CKEditor field, click Insert Media to open the Media Library dialog.
  3. Confirm the chatbot stays open while the dialog opens and closes (before this fix it closed and could not be reopened).
  4. Insert the media, confirm the chatbot is still open and usable.
  5. Toggle the chatbot closed and open again via the toolbar button and the close button; confirm both work.
  6. Reload the page with the chatbot open; confirm it restores open and can still be toggled.

Automated check

A DOM-stub harness that loads the real behavior and simulates the dialog re-attach (a fresh .button--ai-chatbot processed by once() a second time) confirms the difference: on the pre-fix code the body loses ai-chatbot-opened after the re-attach (reproduces the bug); with this fix it stays open.

Notes

1.2.x has diverged from 1.x (parallel branches), and the same bug is present there under the Drupal.ai.chatbotExpanded localStorage key. A separate backport can carry the same idempotent fix to 1.2.x if that branch is still maintained.

AI usage

AI assisted: root-cause analysis, the fix, and the verification harness were produced with AI assistance and reviewed before pushing.

Merge request reports

Loading