[JS] Make the date parser less strict
and display the expected date formt as a tooltip.
This commit is contained in:
parent
5653458b51
commit
2541d96bf5
@ -61,6 +61,7 @@ import {
|
|||||||
parseAppearanceStream,
|
parseAppearanceStream,
|
||||||
parseDefaultAppearance,
|
parseDefaultAppearance,
|
||||||
} from "./default_appearance.js";
|
} from "./default_appearance.js";
|
||||||
|
import { DateFormats, TimeFormats } from "../shared/scripting_utils.js";
|
||||||
import { Dict, isName, isRefsEqual, Name, Ref, RefSet } from "./primitives.js";
|
import { Dict, isName, isRefsEqual, Name, Ref, RefSet } from "./primitives.js";
|
||||||
import { Stream, StringStream } from "./stream.js";
|
import { Stream, StringStream } from "./stream.js";
|
||||||
import { BaseStream } from "./base_stream.js";
|
import { BaseStream } from "./base_stream.js";
|
||||||
@ -2780,6 +2781,25 @@ class TextWidgetAnnotation extends WidgetAnnotation {
|
|||||||
!this.hasFieldFlag(AnnotationFieldFlag.FILESELECT) &&
|
!this.hasFieldFlag(AnnotationFieldFlag.FILESELECT) &&
|
||||||
this.data.maxLen !== 0;
|
this.data.maxLen !== 0;
|
||||||
this.data.doNotScroll = this.hasFieldFlag(AnnotationFieldFlag.DONOTSCROLL);
|
this.data.doNotScroll = this.hasFieldFlag(AnnotationFieldFlag.DONOTSCROLL);
|
||||||
|
|
||||||
|
// Check if we have a date or time.
|
||||||
|
const {
|
||||||
|
data: { actions },
|
||||||
|
} = this;
|
||||||
|
for (const keystrokeAction of actions?.Keystroke || []) {
|
||||||
|
const m = keystrokeAction
|
||||||
|
.trim()
|
||||||
|
.match(/^AF(Date|Time)_Keystroke(?:Ex)?\(['"]?([^'"]+)['"]?\);$/);
|
||||||
|
if (m) {
|
||||||
|
let format = m[2];
|
||||||
|
const num = parseInt(format, 10);
|
||||||
|
if (!isNaN(num) && Math.floor(Math.log10(num)) + 1 === m[2].length) {
|
||||||
|
format = (m[1] === "Date" ? DateFormats : TimeFormats)[num] ?? format;
|
||||||
|
}
|
||||||
|
this.data[m[1] === "Date" ? "dateFormat" : "timeFormat"] = format;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasTextContent() {
|
get hasTextContent() {
|
||||||
|
|||||||
@ -1293,6 +1293,10 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
element.disabled = this.data.readOnly;
|
element.disabled = this.data.readOnly;
|
||||||
element.name = this.data.fieldName;
|
element.name = this.data.fieldName;
|
||||||
element.tabIndex = 0;
|
element.tabIndex = 0;
|
||||||
|
const format = this.data.dateFormat || this.data.timeFormat;
|
||||||
|
if (format) {
|
||||||
|
element.title = format;
|
||||||
|
}
|
||||||
|
|
||||||
this._setRequired(element, this.data.required);
|
this._setRequired(element, this.data.required);
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { DateFormats, TimeFormats } from "../shared/scripting_utils.js";
|
||||||
import { GlobalConstants } from "./constants.js";
|
import { GlobalConstants } from "./constants.js";
|
||||||
|
|
||||||
class AForm {
|
class AForm {
|
||||||
@ -21,23 +22,6 @@ class AForm {
|
|||||||
this._app = app;
|
this._app = app;
|
||||||
this._util = util;
|
this._util = util;
|
||||||
this._color = color;
|
this._color = color;
|
||||||
this._dateFormats = [
|
|
||||||
"m/d",
|
|
||||||
"m/d/yy",
|
|
||||||
"mm/dd/yy",
|
|
||||||
"mm/yy",
|
|
||||||
"d-mmm",
|
|
||||||
"d-mmm-yy",
|
|
||||||
"dd-mmm-yy",
|
|
||||||
"yy-mm-dd",
|
|
||||||
"mmm-yy",
|
|
||||||
"mmmm-yy",
|
|
||||||
"mmm d, yyyy",
|
|
||||||
"mmmm d, yyyy",
|
|
||||||
"m/d/yy h:MM tt",
|
|
||||||
"m/d/yy HH:MM",
|
|
||||||
];
|
|
||||||
this._timeFormats = ["HH:MM", "h:MM tt", "HH:MM:ss", "h:MM:ss tt"];
|
|
||||||
|
|
||||||
// The e-mail address regex below originates from:
|
// The e-mail address regex below originates from:
|
||||||
// https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
// https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
||||||
@ -52,17 +36,14 @@ class AForm {
|
|||||||
return event.target ? `[ ${event.target.name} ]` : "";
|
return event.target ? `[ ${event.target.name} ]` : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
_parseDate(cFormat, cDate, strict = false) {
|
_parseDate(cFormat, cDate) {
|
||||||
let date = null;
|
let date = null;
|
||||||
try {
|
try {
|
||||||
date = this._util._scand(cFormat, cDate, strict);
|
date = this._util._scand(cFormat, cDate, /* strict = */ false);
|
||||||
} catch {}
|
} catch {}
|
||||||
if (date) {
|
if (date) {
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
if (strict) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
date = Date.parse(cDate);
|
date = Date.parse(cDate);
|
||||||
return isNaN(date) ? null : new Date(date);
|
return isNaN(date) ? null : new Date(date);
|
||||||
@ -277,9 +258,7 @@ class AForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AFDate_Format(pdf) {
|
AFDate_Format(pdf) {
|
||||||
if (pdf >= 0 && pdf < this._dateFormats.length) {
|
this.AFDate_FormatEx(DateFormats[pdf] ?? pdf);
|
||||||
this.AFDate_FormatEx(this._dateFormats[pdf]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AFDate_KeystrokeEx(cFormat) {
|
AFDate_KeystrokeEx(cFormat) {
|
||||||
@ -293,7 +272,7 @@ class AForm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._parseDate(cFormat, value, /* strict = */ true) === null) {
|
if (this._parseDate(cFormat, value) === null) {
|
||||||
const invalid = GlobalConstants.IDS_INVALID_DATE;
|
const invalid = GlobalConstants.IDS_INVALID_DATE;
|
||||||
const invalid2 = GlobalConstants.IDS_INVALID_DATE2;
|
const invalid2 = GlobalConstants.IDS_INVALID_DATE2;
|
||||||
const err = `${invalid} ${this._mkTargetName(
|
const err = `${invalid} ${this._mkTargetName(
|
||||||
@ -305,8 +284,8 @@ class AForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AFDate_Keystroke(pdf) {
|
AFDate_Keystroke(pdf) {
|
||||||
if (pdf >= 0 && pdf < this._dateFormats.length) {
|
if (pdf >= 0 && pdf < DateFormats.length) {
|
||||||
this.AFDate_KeystrokeEx(this._dateFormats[pdf]);
|
this.AFDate_KeystrokeEx(DateFormats[pdf]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,9 +596,7 @@ class AForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AFTime_Format(pdf) {
|
AFTime_Format(pdf) {
|
||||||
if (pdf >= 0 && pdf < this._timeFormats.length) {
|
this.AFDate_FormatEx(TimeFormats[pdf] ?? pdf);
|
||||||
this.AFDate_FormatEx(this._timeFormats[pdf]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AFTime_KeystrokeEx(cFormat) {
|
AFTime_KeystrokeEx(cFormat) {
|
||||||
@ -627,8 +604,8 @@ class AForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AFTime_Keystroke(pdf) {
|
AFTime_Keystroke(pdf) {
|
||||||
if (pdf >= 0 && pdf < this._timeFormats.length) {
|
if (pdf >= 0 && pdf < TimeFormats.length) {
|
||||||
this.AFDate_KeystrokeEx(this._timeFormats[pdf]);
|
this.AFDate_KeystrokeEx(TimeFormats[pdf]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -227,7 +227,7 @@ class Util extends PDFObject {
|
|||||||
ddd: data => this._days[data.dayOfWeek].substring(0, 3),
|
ddd: data => this._days[data.dayOfWeek].substring(0, 3),
|
||||||
dd: data => data.day.toString().padStart(2, "0"),
|
dd: data => data.day.toString().padStart(2, "0"),
|
||||||
d: data => data.day.toString(),
|
d: data => data.day.toString(),
|
||||||
yyyy: data => data.year.toString(),
|
yyyy: data => data.year.toString().padStart(4, "0"),
|
||||||
yy: data => (data.year % 100).toString().padStart(2, "0"),
|
yy: data => (data.year % 100).toString().padStart(2, "0"),
|
||||||
HH: data => data.hours.toString().padStart(2, "0"),
|
HH: data => data.hours.toString().padStart(2, "0"),
|
||||||
H: data => data.hours.toString(),
|
H: data => data.hours.toString(),
|
||||||
|
|||||||
@ -105,4 +105,22 @@ class ColorConverters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ColorConverters };
|
const DateFormats = [
|
||||||
|
"m/d",
|
||||||
|
"m/d/yy",
|
||||||
|
"mm/dd/yy",
|
||||||
|
"mm/yy",
|
||||||
|
"d-mmm",
|
||||||
|
"d-mmm-yy",
|
||||||
|
"dd-mmm-yy",
|
||||||
|
"yy-mm-dd",
|
||||||
|
"mmm-yy",
|
||||||
|
"mmmm-yy",
|
||||||
|
"mmm d, yyyy",
|
||||||
|
"mmmm d, yyyy",
|
||||||
|
"m/d/yy h:MM tt",
|
||||||
|
"m/d/yy HH:MM",
|
||||||
|
];
|
||||||
|
const TimeFormats = ["HH:MM", "h:MM tt", "HH:MM:ss", "h:MM:ss tt"];
|
||||||
|
|
||||||
|
export { ColorConverters, DateFormats, TimeFormats };
|
||||||
|
|||||||
@ -1065,8 +1065,8 @@ describe("Scripting", function () {
|
|||||||
id: refId,
|
id: refId,
|
||||||
value: "",
|
value: "",
|
||||||
actions: {
|
actions: {
|
||||||
Format: [`AFDate_FormatEx("mmddyyyy");`],
|
Format: [`AFDate_FormatEx("mm.dd.yyyy");`],
|
||||||
Keystroke: [`AFDate_KeystrokeEx("mmddyyyy");`],
|
Keystroke: [`AFDate_KeystrokeEx("mm.dd.yyyy");`],
|
||||||
},
|
},
|
||||||
type: "text",
|
type: "text",
|
||||||
},
|
},
|
||||||
@ -1080,7 +1080,7 @@ describe("Scripting", function () {
|
|||||||
sandbox.createSandbox(data);
|
sandbox.createSandbox(data);
|
||||||
await sandbox.dispatchEventInSandbox({
|
await sandbox.dispatchEventInSandbox({
|
||||||
id: refId,
|
id: refId,
|
||||||
value: "12062023",
|
value: "12.06.2023",
|
||||||
name: "Keystroke",
|
name: "Keystroke",
|
||||||
willCommit: true,
|
willCommit: true,
|
||||||
});
|
});
|
||||||
@ -1088,14 +1088,14 @@ describe("Scripting", function () {
|
|||||||
expect(send_queue.get(refId)).toEqual({
|
expect(send_queue.get(refId)).toEqual({
|
||||||
id: refId,
|
id: refId,
|
||||||
siblings: null,
|
siblings: null,
|
||||||
value: "12062023",
|
value: "12.06.2023",
|
||||||
formattedValue: "12062023",
|
formattedValue: "12.06.2023",
|
||||||
});
|
});
|
||||||
send_queue.delete(refId);
|
send_queue.delete(refId);
|
||||||
|
|
||||||
await sandbox.dispatchEventInSandbox({
|
await sandbox.dispatchEventInSandbox({
|
||||||
id: refId,
|
id: refId,
|
||||||
value: "1206202",
|
value: "12.06.202",
|
||||||
name: "Keystroke",
|
name: "Keystroke",
|
||||||
willCommit: true,
|
willCommit: true,
|
||||||
});
|
});
|
||||||
@ -1103,16 +1103,15 @@ describe("Scripting", function () {
|
|||||||
expect(send_queue.get(refId)).toEqual({
|
expect(send_queue.get(refId)).toEqual({
|
||||||
id: refId,
|
id: refId,
|
||||||
siblings: null,
|
siblings: null,
|
||||||
value: "",
|
value: "12.06.202",
|
||||||
formattedValue: null,
|
formattedValue: "12.06.0202",
|
||||||
selRange: [0, 0],
|
|
||||||
});
|
});
|
||||||
send_queue.delete(refId);
|
send_queue.delete(refId);
|
||||||
|
|
||||||
sandbox.createSandbox(data);
|
sandbox.createSandbox(data);
|
||||||
await sandbox.dispatchEventInSandbox({
|
await sandbox.dispatchEventInSandbox({
|
||||||
id: refId,
|
id: refId,
|
||||||
value: "02062023",
|
value: "02.06.2023",
|
||||||
name: "Keystroke",
|
name: "Keystroke",
|
||||||
willCommit: true,
|
willCommit: true,
|
||||||
});
|
});
|
||||||
@ -1120,8 +1119,24 @@ describe("Scripting", function () {
|
|||||||
expect(send_queue.get(refId)).toEqual({
|
expect(send_queue.get(refId)).toEqual({
|
||||||
id: refId,
|
id: refId,
|
||||||
siblings: null,
|
siblings: null,
|
||||||
value: "02062023",
|
value: "02.06.2023",
|
||||||
formattedValue: "02062023",
|
formattedValue: "02.06.2023",
|
||||||
|
});
|
||||||
|
send_queue.delete(refId);
|
||||||
|
|
||||||
|
sandbox.createSandbox(data);
|
||||||
|
await sandbox.dispatchEventInSandbox({
|
||||||
|
id: refId,
|
||||||
|
value: "2.6.2023",
|
||||||
|
name: "Keystroke",
|
||||||
|
willCommit: true,
|
||||||
|
});
|
||||||
|
expect(send_queue.has(refId)).toEqual(true);
|
||||||
|
expect(send_queue.get(refId)).toEqual({
|
||||||
|
id: refId,
|
||||||
|
siblings: null,
|
||||||
|
value: "2.6.2023",
|
||||||
|
formattedValue: "02.06.2023",
|
||||||
});
|
});
|
||||||
send_queue.delete(refId);
|
send_queue.delete(refId);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user