Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions core-web/libs/edit-content/src/lib/utils/functions.util.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,13 +438,13 @@ describe('Utils Functions', () => {
]);
});

it('should handle mixed formats (pipes take precedence)', () => {
// When pipes are present, comma splitting should not occur
it('should parse comma-separated pipe-format items individually', () => {
// Each comma-separated item has its own pipe applied for label/value
expect(
getSingleSelectableFieldOptions('label1|value1,label2|value2', 'text')
).toEqual([
{ label: 'label1|value1', value: 'label1|value1' },
{ label: 'label2|value2', value: 'label2|value2' }
{ label: 'label1', value: 'value1' },
{ label: 'label2', value: 'value2' }
]);
});

Expand Down Expand Up @@ -507,6 +507,33 @@ describe('Utils Functions', () => {
]);
});
});

describe('Single-option pipe format (issue #36157)', () => {
it('should parse a single pipe-format option using label and value (AC8)', () => {
expect(getSingleSelectableFieldOptions('Yes|yes', 'text')).toEqual([
{ label: 'Yes', value: 'yes' }
]);
});

it('should use the whole string as label and value for a single option without pipe (AC9)', () => {
expect(getSingleSelectableFieldOptions('Yes', 'text')).toEqual([
{ label: 'Yes', value: 'Yes' }
]);
});

// AC10: Checkbox, Radio, Select and Multiselect all delegate to this util
// with a text dataType, so a single `Yes|yes` option must resolve identically.
it.each(['Checkbox', 'Radio', 'Select', 'Multiselect'])(
'should parse single-option pipe format for %s field',
(fieldType) => {
expect(getSingleSelectableFieldOptions('Yes|yes', 'text')).toEqual([
{ label: 'Yes', value: 'yes' }
]);
// fieldType is documented in the case name to clarify intent
expect(fieldType).toBeDefined();
}
);
});
});

describe('getFinalCastedValue', () => {
Expand Down
30 changes: 15 additions & 15 deletions core-web/libs/edit-content/src/lib/utils/functions.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ export const castSingleSelectableValue = (
* Note: If the input contains line breaks, it will be treated as a single option,
* preserving the line breaks as part of the option text.
*
* Pipe detection is applied per option, so a single option (`label|value`),
* multi-line options (`label|value` per line) and comma-separated options
* (`label|value,label|value`) are all parsed correctly. Options without a pipe
* use the whole string as both label and value.
*
* @param options - The string containing the options to parse
* @param dataType - The data type of the field
* @returns Array of parsed options with label and value
Expand All @@ -99,23 +104,18 @@ export const getSingleSelectableFieldOptions = (
if (!options?.trim()) return [];

const LINE_BREAKS_REGEX = /\r\n|\n|\r/;
const PIPE_REGEX = /\|/;
const hasLineBreaks = LINE_BREAKS_REGEX.test(options);
const hasPipes = PIPE_REGEX.test(options);

let items: string[] = [];
let isPipeFormat = false;

if (hasPipes && hasLineBreaks) {
// Multi-line pipe format (standard dotCMS format)
if (hasLineBreaks) {
// Multi-line format (standard dotCMS format)
items = options.split(LINE_BREAKS_REGEX).filter((line) => line.trim());
isPipeFormat = true;
} else if (hasPipes && !hasLineBreaks && options.trim().startsWith('|')) {
} else if (options.trim().startsWith('|')) {
// Special case: "|true" (checkbox without label)
items = [options.trim()];
isPipeFormat = true;
} else {
// Simple comma format or single-line with pipes treated as comma format
// Comma-separated format
items = options
.split(',')
.map((v) => v.trim())
Expand All @@ -132,16 +132,16 @@ export const getSingleSelectableFieldOptions = (
let label: string;
let value: string;

if (isPipeFormat) {
if (item.includes('|')) {
const parts = item.split('|');
// Si hay pipe, el label es la primera parte y el value es la segunda
// Si no hay segunda parte, el value es igual al label
// If a pipe is present, label is the first part and value the second;
// if there's no second part, value equals label
label = (parts[0] || '').trim();
value = parts[1]?.trim() || label;
} else {
// Si no hay pipe, tanto label como value son el mismo valor
label = item;
value = item;
// No pipe: label and value are the same
label = item.trim();
value = label;
}

if (!value) return null;
Expand Down
Loading