Ver Fonte

Allow Action controller to trigger a redirect

- Migrate site switcher to use Stimulus approach via w-action
- Closes #10035
Aadi jindal há 2 anos atrás
pai
commit
ed58c692ca

+ 0 - 1
.eslintrc.js

@@ -151,7 +151,6 @@ module.exports = {
         'docs/_static/**',
         'wagtail/contrib/modeladmin/static_src/wagtailmodeladmin/js/prepopulate.js',
         'wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotions_formset.js',
-        'wagtail/contrib/settings/static_src/wagtailsettings/js/site-switcher.js',
         'wagtail/documents/static_src/wagtaildocs/js/add-multiple.js',
         'wagtail/embeds/static_src/wagtailembeds/js/embed-chooser-modal.js',
         'wagtail/images/static_src/wagtailimages/js/add-multiple.js',

+ 1 - 0
CHANGELOG.txt

@@ -115,6 +115,7 @@ Changelog
  * Maintenance: Migrate initDismissibles behaviour to a Stimulus controller `w-disimissible` (Loveth Omokaro)
  * Maintenance: Replace jQuery autosize v3 with Stimulus `w-autosize` controller using autosize npm package v6 (Suyash Srivastava)
  * Maintenance: Update `w-action` controller to support a click method (Suyash Srivastava)
+ * Maintenance: Migrate the site settings switcher select from jQuery to a refined version of the `w-action` controller usage (Aadi jindal, LB (Ben) Johnston)
 
 
 4.2.2 (03.04.2023)

+ 72 - 0
client/src/controllers/ActionController.test.js

@@ -3,9 +3,23 @@ import { ActionController } from './ActionController';
 
 describe('ActionController', () => {
   let app;
+  const oldWindowLocation = window.location;
+
+  beforeAll(() => {
+    delete window.location;
+
+    window.location = Object.defineProperties(
+      {},
+      {
+        ...Object.getOwnPropertyDescriptors(oldWindowLocation),
+        assign: { configurable: true, value: jest.fn() },
+      },
+    );
+  });
 
   afterEach(() => {
     app?.stop();
+    jest.clearAllMocks();
   });
 
   describe('post method', () => {
@@ -70,4 +84,62 @@ describe('ActionController', () => {
       expect(clickMock).toHaveBeenCalled();
     });
   });
+
+  describe('redirect method', () => {
+    beforeEach(() => {
+      document.body.innerHTML = `
+      <select name="url" data-controller="w-action" data-action="change->w-action#redirect">
+        <option value="http://localhost/place?option=1">1</option>
+        <option value="http://localhost/place?option=2" selected>2</option>
+      </select>
+      `;
+
+      app = Application.start();
+      app.register('w-action', ActionController);
+    });
+
+    it('should have a redirect method that falls back to any element value', () => {
+      const select = document.querySelector('select');
+
+      expect(window.location.href).toEqual('http://localhost/');
+      expect(window.location.assign).not.toHaveBeenCalled();
+
+      select.dispatchEvent(new CustomEvent('change'));
+
+      expect(window.location.assign).toHaveBeenCalledWith(
+        'http://localhost/place?option=2',
+      );
+    });
+
+    it('should allow redirection via the custom event detail', () => {
+      const select = document.querySelector('select');
+
+      expect(window.location.href).toEqual('http://localhost/');
+      expect(window.location.assign).not.toHaveBeenCalled();
+
+      select.dispatchEvent(
+        new CustomEvent('change', { detail: { url: '/its/in/the/detail/' } }),
+      );
+
+      expect(window.location.assign).toHaveBeenCalledWith(
+        '/its/in/the/detail/',
+      );
+    });
+
+    it('should allow redirection via the Stimulus param approach', () => {
+      const select = document.querySelector('select');
+
+      expect(window.location.href).toEqual('http://localhost/');
+      expect(window.location.assign).not.toHaveBeenCalled();
+
+      select.dataset.wActionUrlParam = '/check/out/the/param/';
+
+      select.dispatchEvent(
+        new CustomEvent('change', { detail: { url: '/its/in/the/detail/' } }),
+      );
+      expect(window.location.assign).toHaveBeenCalledWith(
+        '/check/out/the/param/',
+      );
+    });
+  });
 });

+ 21 - 0
client/src/controllers/ActionController.ts

@@ -25,6 +25,15 @@ import { WAGTAIL_CONFIG } from '../config/wagtailConfig';
  * >
  *  Enable
  * </button>
+ *
+ * @example - triggering a dynamic redirect
+ * // note: a link is preferred normally
+ * <form>
+ *   <select name="url" data-controller="w-action" data-action="change->w-action#redirect">
+ *     <option value="/path/to/1">1</option>
+ *     <option value="/path/to/2">2</option>
+ *   </select>
+ * </form>
  */
 export class ActionController extends Controller<
   HTMLButtonElement | HTMLInputElement
@@ -70,4 +79,16 @@ export class ActionController extends Controller<
     document.body.appendChild(formElement);
     formElement.submit();
   }
+
+  /**
+   * Trigger a redirect based on the custom event's detail, the Stimulus param
+   * or finally check the controlled element for a value to use.
+   */
+  redirect(
+    event: CustomEvent<{ url?: string }> & { params?: { url?: string } },
+  ) {
+    const url = event?.params?.url || event?.detail?.url || this.element.value;
+    if (!url) return;
+    window.location.assign(url);
+  }
 }

+ 0 - 5
client/webpack.config.js

@@ -186,11 +186,6 @@ module.exports = function exports(env, argv) {
             to: 'wagtail/users/static/',
             globOptions: { ignore: ['**/{app,scss}/**', '*.{css,txt}'] },
           },
-          {
-            from: 'wagtail/contrib/settings/static_src/',
-            to: 'wagtail/contrib/settings/static/',
-            globOptions: { ignore: ['**/{app,scss}/**', '*.{css,txt}'] },
-          },
           {
             from: 'wagtail/contrib/modeladmin/static_src/',
             to: 'wagtail/contrib/modeladmin/static/',

+ 1 - 0
docs/releases/5.0.md

@@ -162,6 +162,7 @@ Those improvements were implemented by Albina Starykova as part of an [Outreachy
  * Migrate initDismissibles behaviour to a Stimulus controller `w-disimissible` (Loveth Omokaro)
  * Replace jQuery autosize v3 with Stimulus `w-autosize` controller using autosize npm package v6 (Suyash Srivastava)
  * Update `w-action` controller to support a click method (Suyash Srivastava)
+ * Migrate the site settings switcher select from jQuery to a refined version of the `w-action` controller usage (Aadi jindal, LB (Ben) Johnston)
 
 
 ## Upgrade considerations

+ 9 - 10
wagtail/contrib/settings/forms.py

@@ -2,20 +2,19 @@ from django import forms
 from django.urls import reverse
 from django.utils.translation import gettext_lazy as _
 
-from wagtail.admin.staticfiles import versioned_static
 from wagtail.models import Site
 
 
 class SiteSwitchForm(forms.Form):
-    site = forms.ChoiceField(choices=[])
-
-    @property
-    def media(self):
-        return forms.Media(
-            js=[
-                versioned_static("wagtailsettings/js/site-switcher.js"),
-            ]
-        )
+    site = forms.ChoiceField(
+        choices=[],
+        widget=forms.Select(
+            attrs={
+                "data-controller": "w-action",
+                "data-action": "change->w-action#redirect",
+            }
+        ),
+    )
 
     def __init__(self, current_site, model, **kwargs):
         initial_data = {"site": self.get_change_url(current_site, model)}

+ 0 - 12
wagtail/contrib/settings/static_src/wagtailsettings/js/site-switcher.js

@@ -1,12 +0,0 @@
-$(function () {
-  var $switcher = $('form#settings-site-switch select');
-  if (!$switcher.length) return;
-
-  var initial = $switcher.val();
-  $switcher.on('change', function () {
-    var url = $switcher.val();
-    if (url !== initial) {
-      window.location = url;
-    }
-  });
-});