mirror of
https://github.com/wagtail/wagtail.git
synced 2024-11-29 01:22:07 +01:00
Slug Controller - enhance default compare function
- Allow compareAs behaviour to be overridden via the event detail OR a param - Enhance types to be more strict, refine JSDoc to be clearer about the default behaviour - Add unit tests for default compare function and make logic a bit easier to read in regards to how the slugify/urilify methods are conditionally called - Relates to #10532
This commit is contained in:
parent
ccec24b888
commit
015c4339d7
@ -81,7 +81,7 @@ describe('compare behaviour', () => {
|
||||
const slugInput = document.querySelector('#id_slug');
|
||||
|
||||
slugInput.dataset.action = [
|
||||
'blur->w-slug#slugify',
|
||||
'blur->w-slug#urlify',
|
||||
'custom:event->w-slug#compare',
|
||||
].join(' ');
|
||||
});
|
||||
@ -113,6 +113,76 @@ describe('compare behaviour', () => {
|
||||
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should prevent default using the slugify (default) behaviour as the compare function when urlify values is not equal', () => {
|
||||
const slug = document.querySelector('#id_slug');
|
||||
|
||||
const title = 'Тестовий заголовок';
|
||||
|
||||
slug.setAttribute('value', title);
|
||||
|
||||
// apply the urlify method to the content to ensure the value before check is urlify
|
||||
slug.dispatchEvent(new Event('blur'));
|
||||
|
||||
expect(slug.value).toEqual('testovij-zagolovok');
|
||||
|
||||
const event = new CustomEvent('custom:event', { detail: { value: title } });
|
||||
|
||||
event.preventDefault = jest.fn();
|
||||
|
||||
slug.dispatchEvent(event);
|
||||
|
||||
// slugify used for the compareAs value by default, so 'compare' fails
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not prevent default using the slugify (default) behaviour as the compare function when urlify value is equal', () => {
|
||||
const slug = document.querySelector('#id_slug');
|
||||
|
||||
const title = 'the-french-dispatch-a-love-letter-to-journalists';
|
||||
|
||||
slug.setAttribute('value', title);
|
||||
|
||||
// apply the urlify method to the content to ensure the value before check is urlify
|
||||
slug.dispatchEvent(new Event('blur'));
|
||||
|
||||
expect(slug.value).toEqual(
|
||||
'the-french-dispatch-a-love-letter-to-journalists',
|
||||
);
|
||||
|
||||
const event = new CustomEvent('custom:event', { detail: { value: title } });
|
||||
|
||||
event.preventDefault = jest.fn();
|
||||
|
||||
slug.dispatchEvent(event);
|
||||
|
||||
// slugify used for the compareAs value by default, so 'compare' passes with the initial urlify value on blur
|
||||
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not prevent default using the urlify behaviour as the compare function when urlify value matches', () => {
|
||||
const title = 'Тестовий заголовок';
|
||||
|
||||
const slug = document.querySelector('#id_slug');
|
||||
|
||||
slug.setAttribute('data-w-slug-compare-as-param', 'urlify');
|
||||
slug.setAttribute('value', title);
|
||||
|
||||
// apply the urlify method to the content to ensure the value before check is urlify
|
||||
slug.dispatchEvent(new Event('blur'));
|
||||
|
||||
expect(slug.value).toEqual('testovij-zagolovok');
|
||||
|
||||
const event = new CustomEvent('custom:event', {
|
||||
detail: { compareAs: 'urlify', value: title },
|
||||
});
|
||||
|
||||
event.preventDefault = jest.fn();
|
||||
|
||||
slug.dispatchEvent(event);
|
||||
|
||||
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should prevent default if the values are not the same', () => {
|
||||
document.querySelector('#id_slug').setAttribute('value', 'title-alpha');
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Controller } from '@hotwired/stimulus';
|
||||
import { cleanForSlug } from '../utils/text';
|
||||
|
||||
type SlugMethods = 'slugify' | 'urlify';
|
||||
|
||||
/**
|
||||
* Adds ability to slugify the value of an input element.
|
||||
*
|
||||
@ -15,24 +17,30 @@ export class SlugController extends Controller<HTMLInputElement> {
|
||||
declare allowUnicodeValue: boolean;
|
||||
|
||||
/**
|
||||
* Allow for a comparison value to be provided, if does not compare to the
|
||||
* current value (once transformed), then the event's default will
|
||||
* be prevented.
|
||||
* Allow for a comparison value to be provided so that a dispatched event can be
|
||||
* prevented. This provides a way for other events to interact with this controller
|
||||
* to block further updates if a value is not in sync.
|
||||
* By default it will compare to the slugify method, this can be overridden by providing
|
||||
* either a Stimulus param value on the element or the event's detail.
|
||||
*/
|
||||
compare(
|
||||
event: CustomEvent<{ value: string }> & { params?: { compareAs?: string } },
|
||||
event: CustomEvent<{ compareAs?: SlugMethods; value: string }> & {
|
||||
params?: { compareAs?: SlugMethods };
|
||||
},
|
||||
) {
|
||||
// do not attempt to compare if the current field is empty
|
||||
if (!this.element.value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const {
|
||||
detail: { value = '' } = {},
|
||||
params: { compareAs = 'slugify' } = {},
|
||||
} = event;
|
||||
const compareAs =
|
||||
event.detail?.compareAs || event.params?.compareAs || 'slugify';
|
||||
|
||||
const compareValue = this[compareAs](
|
||||
{ detail: { value: event.detail?.value || '' } },
|
||||
true,
|
||||
);
|
||||
|
||||
const compareValue = this[compareAs]({ detail: { value } }, true);
|
||||
const currentValue = this.element.value;
|
||||
|
||||
const valuesAreSame = compareValue.trim() === currentValue.trim();
|
||||
@ -50,7 +58,10 @@ export class SlugController extends Controller<HTMLInputElement> {
|
||||
* If a custom event with detail.value is provided, that value will be used
|
||||
* instead of the field's value.
|
||||
*/
|
||||
slugify(event: CustomEvent<{ value: string }>, ignoreUpdate = false) {
|
||||
slugify(
|
||||
event: CustomEvent<{ value: string }> | { detail: { value: string } },
|
||||
ignoreUpdate = false,
|
||||
) {
|
||||
const unicodeSlugsEnabled = this.allowUnicodeValue;
|
||||
const { value = this.element.value } = event?.detail || {};
|
||||
const newValue = cleanForSlug(value.trim(), false, { unicodeSlugsEnabled });
|
||||
@ -68,7 +79,10 @@ export class SlugController extends Controller<HTMLInputElement> {
|
||||
* If a custom event with detail.value is provided, that value will be used
|
||||
* instead of the field's value.
|
||||
*/
|
||||
urlify(event: CustomEvent<{ value: string }>, ignoreUpdate = false) {
|
||||
urlify(
|
||||
event: CustomEvent<{ value: string }> | { detail: { value: string } },
|
||||
ignoreUpdate = false,
|
||||
) {
|
||||
const unicodeSlugsEnabled = this.allowUnicodeValue;
|
||||
const { value = this.element.value } = event?.detail || {};
|
||||
const newValue = cleanForSlug(value.trim(), true, { unicodeSlugsEnabled });
|
||||
|
Loading…
Reference in New Issue
Block a user