final regExprDateSortable = RegExp(r'(\d{4})[-.](\d\d?)[.-](\d\d?)');
final regExprDateStandard = RegExp(r'(\d\d?)[-.](\d\d?)[.-](\d{4})');
final regExprDateTimeSortable =
+ // ........1.....1....2.....2....3.....3.4..5.....5.6.....67.8.....87.4
RegExp(r'(\d{4})[-.](\d\d?)[.-](\d\d?)?(\D(\d\d?):(\d\d?)(:(\d\d?))?)?');
final regExprDateTimeStandard =
// ......1.....1....2.....2....3.....34..5.....5.6.....67.8.....87.4
final standardDateTimeFormatSeconds = DateFormat('dd.MM.yyyy HH:mm:ss');
-// ..................................1.....1....2.....2....3....3.4.5.....5.6.....67.....7.4
+const weekDaysLongEnglish = [
+ '<undef>',
+ 'Monday',
+ 'Tuesday',
+ 'Wednesday',
+ 'Thursday',
+ 'Friday',
+ 'Saturday',
+ 'Sunday'
+];
+const weekDaysShortEnglish = [
+ '<undef>',
+ 'Mo',
+ 'Tue',
+ 'Wed',
+ 'Thu',
+ 'Fri',
+ 'Sat',
+ 'Sun'
+];
+const weekDaysLongGerman = [
+ '<undef>',
+ 'Montag',
+ 'Dienstag',
+ 'Mittwoch',
+ 'Donnerstag',
+ 'Freitag',
+ 'Samstag',
+ 'Sonntag'
+];
+const weekDaysShortGerman = [
+ '<undef>',
+ 'Mo',
+ 'Di',
+ 'Mi',
+ 'Do',
+ 'Fr',
+ 'Sa',
+ 'So'
+];
+
/// Handles the [input] as a pattern in a filter list:
///
/// Appends '*' if input does not end with a '*'.
import 'package:dart_bones/dart_bones.dart';
+import 'defines.dart';
+import 'helper.dart';
import 'i18n.dart';
final i18n = I18N();
-final _regExprEMailChar = RegExp(r'[\/ "!$%&()?;:,*<>|^°{}\[\]\\=]');
+final _regExpEMailChar = RegExp(r'[\/ "!$%&()?;:,*<>|^°{}\[\]\\=]');
-final _regExprEMailFormat = RegExp(r'^[^@]+@[^@]+\.[a-zA-Z]+$');
+final _regExpEMailFormat = RegExp(r'^[^@]+@[^@]+\.[a-zA-Z]+$');
-final _regExprTime = RegExp(r'^(\d{1,2})(:(\d{1,2}))?$');
+final _regExpDate = RegExp(r'^(\d{1,4})[.-](\d{1,2})[.-](\d{1,4})?$');
+final _regExpTime = RegExp(r'^(\d{1,2})(:(\d{1,2}))?$');
-final _regExprNat = RegExp(r'^\d+$');
+final _regExpNat = RegExp(r'^\d+$');
+
+/// Tests whether the [input] is a date, e.g. "1.02.2021".
+///
+/// [input]: string to test
+///
+/// [mayBeEmpty]: true: input may be null or empty
+/// false: if input is empty an error is returned
+String? isDate(String? input,
+ {bool mayBeEmpty = false, bool placeholderAllowed = true}) {
+ String? rc;
+ RegExpMatch? match;
+ if (input == null || input.isEmpty) {
+ if (!mayBeEmpty) {
+ rc = i18n.tr('Nothing is not a date');
+ }
+ } else if (!placeholderAllowed || input != '*') {
+ if ((match = _regExpDate.firstMatch(input)) == null) {
+ rc = i18n.trArgs(
+ 'Not a Date: {0} Examples: 1.2.2021 2021-01-22', '!global', [input]);
+ } else {
+ int first = int.parse(match!.group(1)!);
+ int second = int.parse(match.group(2)!);
+ int third = int.parse(match.group(3)!);
+ if (second < 1 || second > 12) {
+ rc = i18n.trArgs('Wrong month in: {0}: 1..12', '!global', [input]);
+ } else {
+ int year = first;
+ int month = second;
+ int day = third;
+ if (third > 1900 && first < 32) {
+ year = third;
+ day = first;
+ }
+ if (year < 1900 || year > 2100) {
+ rc =
+ i18n.trArgs('Wrong year in: {0}: 1900..2100', '!global', [input]);
+ } else if (month > 12) {
+ rc = i18n.trArgs('Wrong month in: {0}: 1..12', '!global', [input]);
+ } else if (day > 31) {
+ rc = i18n.trArgs('Wrong day in: {0}: 1..31', '!global', [input]);
+ } else {
+ final date2 = fromString(input, dataType: DataType.date);
+ if (int.parse(asString(date2, dateOnly: true).substring(0, 2)) !=
+ day) {
+ rc =
+ i18n.trArgs('Day too large for month: {0}', '!global', [input]);
+ }
+ }
+ }
+ }
+ }
+ return rc;
+}
/// Tests whether [input] is an correct email address.
///
if (input == null) {
rc = i18n.tr('null is not an email');
} else {
- RegExpMatch? match = _regExprEMailChar.firstMatch(input);
+ RegExpMatch? match = _regExpEMailChar.firstMatch(input);
if (countChar(input, '@') > 1) {
rc = i18n.tr('too many "@" in email address: ') + input;
} else if (match != null) {
rc = i18n.trArgs('Illegal character "{0}" in email address', '!global',
[match.group(0)!]);
- } else if (_regExprEMailFormat.firstMatch(input) == null) {
+ } else if (_regExpEMailFormat.firstMatch(input) == null) {
rc = i18n.tr('Not an email address: ') + input;
}
}
if (input == null) {
rc = i18n.tr('null is not a not negative integer');
} else {
- RegExpMatch? match = _regExprNat.firstMatch(input);
+ RegExpMatch? match = _regExpNat.firstMatch(input);
if (match == null) {
rc = i18n.trArgs(
'Not negative integer expected, not: {0}', '!global', [input]);
rc = i18n.tr('Nothing is not a time');
}
} else {
- if ((match = _regExprTime.firstMatch(input)) == null) {
+ if ((match = _regExpTime.firstMatch(input)) == null) {
rc = i18n
.trArgs('Not a time: {0} Examples: 10 or 9:44 ', '!global', [input]);
} else if (int.parse(match!.group(1)!) >= 24) {
-import 'package:exhibition/base/defines.dart';
import 'package:flutter/material.dart';
import 'package:synchronized/synchronized.dart';
+import '../../base/defines.dart';
import '../../base/helper.dart';
import '../../base/i18n.dart';
import '../../persistence/persistence.dart';
final i18n = I18N();
+/// This function can modify a column of a record.
+/// [column] is the name of the column.
+/// [index] is the index of the column in the record: 0..N-1.
+/// [value] is the current value of the column.
+/// [record] is the whole record.
+typedef DbColumnChanger = dynamic Function(
+ String column, int index, dynamic value, JsonMap? record);
+
/// Links some instances belonging to a module page (given as
/// member "statefulWidget").
///
{required int primaryKey,
required String what,
required Map<String, dynamic> parameters,
- required Function() onDone}) {
+ required Function() onDone,
+ DbColumnChanger? dbColumnChanger}) {
JsonMap? rc;
String name = 'record';
if (!pageStates.dbDataState.hasEntry(name)) {
rc = dbData.singleRecord!;
}
}
+ if (dbColumnChanger != null && rc != null) {
+ int ix = -1;
+ for (var column in rc.keys) {
+ rc[column] = dbColumnChanger(column, ++ix, rc[column], rc);
+ }
+ }
return rc;
}
required String columnList,
required Function() onDone, //@ToDo: remove
required String routeEdit,
- required BuildContext context}) {
+ required BuildContext context,
+ DbColumnChanger? dbColumnChanger}) {
List<DataRow>? rc;
if (dbData.recordList != null) {
rc = <DataRow>[];
for (var record in dbData.recordList!) {
final cells = <DataCell>[];
+ int ix = -1;
for (var column in columnList.split(';')) {
final primaryKey = moduleMetaData.primaryOf()?.columnName;
String value;
} else {
value = dbValueToString(record[column], property.dataType);
}
- cells.add(DataCell(Text(value), onTap: () {
+ if (dbColumnChanger != null) {
+ value = dbColumnChanger(column, ++ix, value, record);
+ }
+ cells.add(DataCell(Text(value == 'null' ? '' : value), onTap: () {
globalData.navigate(context, routeEdit + ';${record[primaryKey]}');
}));
}
--- /dev/null
+---
+# Customized SQL statements of the module "Users":
+
+module: Users
+list:
+ type: list
+ parameters: [":text",":role"]
+ order: "user_id"
+ sql: |
+ SELECT
+ t0.*,t1.role_name AS role
+ FROM users t0
+ JOIN roles t1 ON t1.role_id=t0.user_role
+ WHERE
+ (:text='' OR user_name like :text
+ OR user_displayname like :text OR user_email like :text
+ OR role_name like :text)
+ AND (:role=0 OR :role=user_role)
+insert:
+ type: insert
+ parameters: [":name",":displayName",":email",":role",":createdBy"]
+ sql: |
+ INSERT INTO users(user_name,user_displayname,user_email,user_role,
+ user_status,user_createdby,user_createdat)
+ VALUES(:name,:displayName,:email,:role,1,:createdBy,NOW());
expect(notEmpty(''), isNotNull);
expect(notEmpty(null), isNotNull);
});
+ test('isDate', () {
+ expect(isDate('1.2.2021'), isNull);
+ expect(isDate('01.02.2021'), isNull);
+ expect(isDate('2001.02.28'), isNull);
+ expect(isDate('2001.2.8'), isNull);
+ expect(isDate('1-2-2021'), isNull);
+ expect(isDate('01-02-2021'), isNull);
+ expect(isDate('2001-02-28'), isNull);
+ expect(isDate('2001-2-8'), isNull);
+ expect(isDate('02.2.8'), matches('1900..2100'));
+ expect(isDate('2002.13.8'), matches(RegExp(r'.*1[.][.]12')));
+ expect(isDate('2002.1.32'), isNotNull);
+ });
}