Skip to content

Commit 491e0e3

Browse files
committed
MBS-12230: Allow pasting / parsing dates on date fields
As a first step, this supports only YMD dates. Further options can be added in subsequent commits. The regex is based on the one from the original paste-a-date script.
1 parent b62688c commit 491e0e3

File tree

6 files changed

+69
-7
lines changed

6 files changed

+69
-7
lines changed

root/components/PartialDateInput.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,18 @@ import * as React from 'react';
1212
import {isDateValid, isYearFourDigits}
1313
from '../static/scripts/edit/utility/dates';
1414
import {applyPendingErrors} from '../utility/subfieldErrors';
15+
import parseNaturalDate
16+
from '../static/scripts/common/utility/parseNaturalDate';
1517

1618
/* eslint-disable flowtype/sort-keys */
1719
export type ActionT =
1820
| {
1921
+type: 'set-date',
20-
+date: {+year?: string, +month?: string, +day?: string},
22+
+date: {
23+
+year?: string,
24+
+month?: string,
25+
+day?: string,
26+
},
2127
}
2228
| {+type: 'show-pending-errors'};
2329
/* eslint-enable flowtype/sort-keys */
@@ -101,6 +107,7 @@ const PartialDateInput = (props: Props): React.Element<'span'> => {
101107
const yearProps = {};
102108
const monthProps = {};
103109
const dayProps = {};
110+
const parserProps = {};
104111

105112
if (props.uncontrolled) {
106113
yearProps.defaultValue = field.field.year.value;
@@ -125,6 +132,7 @@ const PartialDateInput = (props: Props): React.Element<'span'> => {
125132
yearProps.onBlur = handleBlur;
126133
monthProps.onBlur = handleBlur;
127134
dayProps.onBlur = handleBlur;
135+
parserProps.onBlur = handleBlur;
128136

129137
yearProps.onChange = (event) => handleDateChange(
130138
event,
@@ -139,6 +147,14 @@ const PartialDateInput = (props: Props): React.Element<'span'> => {
139147
'day',
140148
);
141149

150+
parserProps.onChange = (event) => {
151+
const date = parseNaturalDate(event.currentTarget.value);
152+
props.dispatch({
153+
date: date,
154+
type: 'set-date',
155+
});
156+
};
157+
142158
yearProps.value = field.field.year.value ?? '';
143159
monthProps.value = field.field.month.value ?? '';
144160
dayProps.value = field.field.day.value ?? '';
@@ -181,6 +197,21 @@ const PartialDateInput = (props: Props): React.Element<'span'> => {
181197
type="text"
182198
{...dayProps}
183199
/>
200+
{props.uncontrolled ? null : (
201+
<>
202+
{' '}
203+
<input
204+
className="partial-date-parser"
205+
disabled={disabled}
206+
id={'id-' + field.html_name + '.partial-date-parser'}
207+
name={field.html_name + '.partial-date-parser'}
208+
placeholder={l('Enter date string to parse')}
209+
size={12}
210+
type="text"
211+
{...parserProps}
212+
/>
213+
</>
214+
)}
184215
</span>
185216
);
186217
};

root/static/scripts/common/utility/isDateEmpty.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ declare type PartialDateObservablesT = {
1313
+year: KnockoutObservable<string | null>,
1414
};
1515

16-
declare type PartialDateStringsT = {
17-
+day?: string,
18-
+month?: string,
19-
+year?: string,
20-
};
21-
2216
export function isDateObservableEmpty(
2317
date: PartialDateObservablesT,
2418
): boolean {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* @flow strict
3+
* Copyright (C) 2022 MetaBrainz Foundation
4+
*
5+
* This file is part of MusicBrainz, the open internet music database,
6+
* and is licensed under the GPL version 2, or (at your option) any
7+
* later version: http://www.gnu.org/licenses/gpl-2.0.txt
8+
*/
9+
10+
11+
const ymdRegex = /^\W*([0-9]{4})(?:\W+(0?[1-9]|1[0-2])(?:\W+(0?[1-9]|[12][0-9]|3[01]))?)?\W*$/;
12+
13+
export function parseNaturalDate(
14+
str: string,
15+
): PartialDateStringsT {
16+
const match = str.match(ymdRegex) || [];
17+
return {
18+
/* eslint-disable sort-keys */
19+
year: match[1] || '',
20+
month: match[2] || '',
21+
day: match[3] || '',
22+
/* eslint-enable sort-keys */
23+
};
24+
}
25+
26+
export default parseNaturalDate;

root/static/scripts/edit/components/DateRangeFieldset.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ const DateRangeFieldset = ({
186186
Partial dates such as YYYY-MM or just YYYY are OK,
187187
or you can omit the date entirely.`)}
188188
</p>
189+
<p>
190+
{l(`You can also enter a full date string into the parsing field
191+
rather than entering year, month and day separately.`)}
192+
</p>
189193
<FormRowPartialDate
190194
disabled={disabled}
191195
dispatch={beginDateDispatch}

root/static/styles/forms.less

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ div.half-width fieldset span.partial-date {
444444
&.partial-date-year { width: 4em; }
445445
&.partial-date-month { width: 2.5em; }
446446
&.partial-date-day { width: 2.5em; }
447+
&.partial-date-parser { width: 12em; }
447448
}
448449
}
449450

root/types/entity.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ declare type PartialDateT = {
9393
+year: number | null,
9494
};
9595

96+
declare type PartialDateStringsT = {
97+
+day?: string,
98+
+month?: string,
99+
+year?: string,
100+
};
101+
96102
declare type TypeRoleT<T> = {
97103
+typeID: number | null,
98104
+typeName?: string,

0 commit comments

Comments
 (0)