#! /bin/sh
+if [ $(id -u) = 0 ]; then
+ echo "+++ not working as root"
+else
flutter test --coverage
rm -Rf coverage/html/*
genhtml --show-details --output-directory=coverage/html coverage/lcov.info
+fi
return _instance;
}
- Settings.internal(this.widgetConfiguration, this.logger) {
- BaseConfiguration widgetConfiguration =
- BaseConfiguration(mapWidgetData, logger);
- }
+ Settings.internal(this.widgetConfiguration, this.logger);
/// Sets the locale code.
/// [locale] the info about localisation
import 'package:flutter/material.dart';
import 'package:flutter_bones/flutter_bones.dart';
-enum ButtonModelType {
- cancel,
- custom,
- search,
- store,
-}
-
typedef ButtonOnPressed = void Function(String name);
class ButtonModel extends WidgetModel {
List<String> options;
ButtonModelType buttonModelType;
- ButtonModel(SectionModel section, PageModel page, this.map, BaseLogger logger)
- : super(section, page, WidgetModelType.button, logger);
-
VoidCallback onPressed;
+
VoidCallback onLongPressed;
ValueChanged<bool> onHighlightChanged;
+ ButtonModel(SectionModel section, PageModel page, this.map, BaseLogger logger)
+ : super(section, page, WidgetModelType.button, logger);
+
+ /// Dumps a the instance into a [stringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer.write(
+ ' button $name: text: options: $text ${listToString(options)}\n');
+ return stringBuffer;
+ }
+
/// Returns the name including the names of the parent
@override
String fullName() => '${section.name}.$name';
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(map, 'buttonType name options text widgetType'.split(' '));
+ checkSuperfluousAttributes(
+ map, 'buttonType label name options text widgetType'.split(' '));
name = parseString('name', map, required: true);
text = parseString('text', map);
buttonModelType =
@override
String widgetName() => name;
}
+
+enum ButtonModelType {
+ cancel,
+ custom,
+ search,
+ store,
+}
final Map<String, dynamic> map;
- CheckboxModel(
- SectionModel section, PageModel page, this.map, BaseLogger logger)
+ CheckboxModel(SectionModel section, PageModel page, this.map,
+ BaseLogger logger)
: super(section, page, map, WidgetModelType.checkbox, logger);
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(map, 'name label options toolTip widgetType'.split(' '));
+ checkSuperfluousAttributes(
+ map, 'name label options toolTip widgetType'.split(' '));
super.parse();
options = parseOptions('options', map);
checkOptionsByRegExpr(options, regExprOptions);
}
+
+ /// Dumps the instance into a [StringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer.write(
+ ' checkbox $name: text: options: ${listToString(options)}\n');
+ return stringBuffer;
+ }
}
SectionModel section, PageModel page, this.map, BaseLogger logger)
: super(section, page, map, WidgetModelType.combobox, logger);
+ /// Dumps the instance into a [StringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer.write(
+ ' combobox $name: texts: ${listToString(texts)} options: ${options.join(' ')}\n');
+ return stringBuffer;
+ }
+
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(
+ checkSuperfluousAttributes(
map,
'name label dataType options texts toolTip widgetType values'
.split(' '));
super.parse();
texts = parseStringList('texts', map);
- values = dataType == DataType.string
- ? parseStringList('values', map)
- : parseValueList('values', map, dataType);
+ values = parseValueList('values', map, dataType);
options = parseOptions('options', map);
checkOptionsByRegExpr(options, regExprOptions);
}
SectionModel section, PageModel page, this.map, BaseLogger logger)
: super(section, page, WidgetModelType.emptyLine, logger);
+ /// Dumps the instance into a [StringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer.write(' emptyLine: options: ${options.join(' ')}\n');
+ return stringBuffer;
+ }
+
/// Returns the name including the names of the parent
@override
String fullName() => '${section.name}.${widgetName()}';
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(map, 'options widgetType'.split(' '));
+ checkSuperfluousAttributes(map, 'options widgetType'.split(' '));
options = parseOptions('options', map);
checkOptionsByRegExpr(options, regExprOptions);
}
import 'package:flutter/material.dart';
import 'package:flutter_bones/flutter_bones.dart';
-class FieldModel extends WidgetModel {
+abstract class FieldModel extends WidgetModel {
static final regExprOptions =
RegExp(r'^(undef|readonly|disabled|password|required)$');
String name;
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(
- map,
- 'fieldType dataType label maxSize name options rows toolTip '
- .split(' '));
name = parseString('name', map, required: true);
label = parseString('label', map, required: false);
toolTip = parseString('toolTip', map, required: false);
+
dataType = parseEnum<DataType>('dataType', map, DataType.values);
+ if (dataType == null) {
+ switch (widgetModelType) {
+ case WidgetModelType.checkbox:
+ dataType = DataType.bool;
+ break;
+ default:
+ dataType = DataType.string;
+ break;
+ }
+ }
}
@override
bool rc = false;
options.forEach((element) {
if (regExpr.firstMatch(element) == null) {
- logger.error('unbekannte Feldoption $element in ${fullName()}');
+ logger.error('wrong option $element in ${fullName()}');
rc = true;
}
});
/// Tests a [map] for superfluous [keys].
/// Keys of the [map] that are not listed in [keys] will be logged as errors.
/// Keys that do not have the type String are logged as errors.
- void checkSuperfluous(Map<String, dynamic> map, List<String> keys) {
+ void checkSuperfluousAttributes(Map<String, dynamic> map, List<String> keys) {
map.keys.forEach((element) {
- if (element.runtimeType != String) {
- logger.error(
- 'wrong attribute data type ${element.runtimeType} in ${fullName()}');
- } else if (!keys.contains(element)) {
- logger.error('unknown attribute "${element}" in ${fullName()}');
+ if (!keys.contains(element)) {
+ logger.error('unknown attribute "$element" in ${fullName()}');
}
});
}
/// Returns the name including the names of the parent
String fullName();
+ /// Converts a [list] of strings to a string.
+ String listToString(List<String> list) {
+ final rc = list == null ? 'null' : list.join(' ');
+ return rc;
+ }
+
/// Fetches an entry from a map addressed by a [key].
/// An error is logged if [required] is true and the map does not contain the key.
T parseEnum<T>(String key, Map<String, dynamic> map, List values,
T rc;
if (!map.containsKey(key)) {
if (required) {
- logger.error('missing $key in ${fullName()}');
+ logger.error('missing attribute "$key" in ${fullName()}');
}
} else {
final text = map[key] as String;
rc = StringUtils.stringToEnum<T>(text, values);
+ if (rc == null) {
+ logger.error(
+ 'unknown value $text of attribute "$key" in ${fullName()}. Allowed:' +
+ values.fold(
+ '',
+ (previousValue, element) => previousValue +=
+ ' ' + StringUtils.enumToString(element)));
+ }
}
return rc;
}
/// Fetches an entry from a map addressed by a [key].
/// An error is logged if [required] is true and the map does not contain the key.
- int parseInt(String key, Map<String, dynamic> map, {required: bool}) {
- int rc;
- if (!map.containsKey(key)) {
- if (required) {
- logger.error('missing $key in ${fullName()}');
- } else {
- if (map[key].runtimeType == int) {
- rc = map[key];
- } else if (map[key].runtimeType == String) {
- if (Validation.isInt(map[key])) {
- rc = StringUtils.asInt(map[key]);
- } else {
- logger
- .error('not an integer: ${map[key]} map[$key] in {fullName()}');
- }
- } else {
- logger.error('not an integer: ${map[key]} map[$key] in {fullName()}');
- }
- }
- }
- return rc;
+ int parseInt(String key, Map<String, dynamic> map, {bool required = false}) {
+ int rc;
+ if (!map.containsKey(key)) {
+ if (required) {
+ logger.error('missing $key in ${fullName()}');
+ } else {
+ final value = map[key];
+ if (value != null) {
+ if (value.runtimeType == int) {
+ rc = map[key];
+ } else if (value.runtimeType == String) {
+ if (Validation.isInt(value)) {
+ rc = StringUtils.asInt(value);
+ } else {
+ logger.error('not an integer: $value map[$key] in {fullName()}');
+ }
+ } else {
+ logger.error('not an integer: $value map[$key] in {fullName()}');
+ }
+ }
+ }
+ }
+ return rc;
}
/// Fetches an entry from a map addressed by a [key].
List<String> parseOptions(String key, Map<String, dynamic> map) {
List<String> rc = [];
if (map.containsKey(key)) {
- rc = map[key].split(';');
+ final value = map[key];
+ if (value.runtimeType == String && value.isNotEmpty) {
+ rc = value.split(';');
+ } else {
+ logger.error(
+ 'wrong datatype of options ${value.runtimeType} in ${fullName()}');
+ }
}
return rc;
}
if (dataType == null) {
dataType = DataType.string;
}
- final strings = parseStringList(key, map, required: required);
- final rc = strings.map((item) {
- var rc2;
- switch (dataType) {
- case DataType.int:
- rc2 = StringUtils.asInt(item);
- break;
- default:
- logger.error('unknown dataType in parseValueList()');
- rc2 = item;
- }
- return rc2;
- });
+ List<dynamic> rc;
+ if (ModelBase.isList(map[key])) {
+ rc = map[key];
+ } else {
+ final strings = parseStringList(key, map, required: required);
+ rc = strings.map((item) {
+ var rc2;
+ switch (dataType) {
+ case DataType.int:
+ rc2 = StringUtils.asInt(item);
+ break;
+ default:
+ logger.error('unknown dataType in parseValueList()');
+ rc2 = item;
+ }
+ return rc2;
+ });
+ }
return rc;
}
import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/cupertino.dart';
import 'package:flutter_bones/flutter_bones.dart';
import 'package:meta/meta.dart';
pageMap[page.name] = page;
}
+ /// Dumps the internal structure into a [stringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer.write('= module $name: options: ${options.join(' ')}\n');
+ for (var page in pages) {
+ page.dump(stringBuffer);
+ }
+ return stringBuffer;
+ }
+
/// Returns the name including the names of the parent
@override
String fullName() => name;
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(map, 'module options pages'.split(' '));
+ checkSuperfluousAttributes(map, 'module options pages'.split(' '));
name = parseString('module', map, required: true);
if (!map.containsKey('pages')) {
logger.error('Module $name: missing pages');
import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter_bones/flutter_bones.dart';
+typedef FilterWidget = bool Function(WidgetModel item);
+
/// Represents one screen of the application.
class PageModel extends ModelBase {
static final regExprOptions = RegExp(r'^(unknown)$');
PageModelType pageModelType;
final List<SectionModel> sections = [];
List<String> options;
+ @protected
+ final fields = <String, FieldModel>{};
+ @protected
+ final buttons = <String, ButtonModel>{};
+ final widgets = <WidgetModel>[];
PageModel(this.module, this.map, BaseLogger logger) : super(logger);
+ /// Adds a [button] to the [this.buttons].
+ /// If already defined and error is logged.
+ void addButton(ButtonModel button) {
+ final name = button.name;
+ if (buttons.containsKey(name)) {
+ logger.error('button ${button.fullName()} already defined: ' +
+ buttons[name].fullName());
+ } else {
+ buttons[name] = button;
+ }
+ }
+
+ /// Adds a [field] to the [this.fields].
+ /// If already defined and error is logged.
+ void addField(FieldModel field) {
+ final name = field.name;
+ if (fields.containsKey(name)) {
+ logger.error('field ${field.fullName()} already defined: ' +
+ fields[name].fullName());
+ } else {
+ fields[name] = field;
+ }
+ }
+
+ /// Dumps the internal structure into a [stringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer
+ .write('== page $name: $pageModelType options: ${options.join(' ')}\n');
+ for (var section in sections) {
+ section.dump(stringBuffer);
+ }
+ return stringBuffer;
+ }
+
/// Returns the name including the names of the parent
@override
String fullName() => '${module.name}.$name';
+ /// Returns a field by [name] or null on error.
+ ButtonModel getButton(String name, {bool required = true}) {
+ ButtonModel rc;
+ if (!buttons.containsKey(name)) {
+ if (required) {
+ logger.error('missing button $name in page ${fullName()}');
+ }
+ } else {
+ rc = buttons[name];
+ }
+ return rc;
+ }
+
+ /// Returns a field by [name] or null on error.
+ FieldModel getField(String name, {bool required = true}) {
+ FieldModel rc;
+ if (!fields.containsKey(name)) {
+ if (required) {
+ logger.error('missing field $name in page ${fullName()}');
+ }
+ } else {
+ rc = fields[name];
+ }
+ return rc;
+ }
+
+ /// Returns a list of widget models (in order as defined) matching the [filter].
+ /// If [filter] is none all widgets will be returned.
+ List<dynamic> getWidgets(FilterWidget filter) {
+ final rc = filter == null
+ ? widgets
+ : widgets.fold([], (prevValue, item) {
+ if (filter(item)) {
+ prevValue.add(item);
+ }
+ return prevValue;
+ });
+ return rc;
+ }
+
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(map, 'name options pageType sections'.split(' '));
+ checkSuperfluousAttributes(
+ map, 'name options pageType sections'.split(' '));
name = parseString('name', map, required: true);
- pageModelType =
- parseEnum<PageModelType>('pageType', map, PageModelType.values);
+ pageModelType = parseEnum<PageModelType>(
+ 'pageType', map, PageModelType.values,
+ required: true);
options = parseOptions('options', map);
if (!map.containsKey('sections')) {
logger.error('missing sections in ${fullName()}');
checkOptionsByRegExpr(options, regExprOptions);
}
- /// Returns a list of Pages constructed by the Json like [map].
- static void parseList(
- ModuleModel module, List<Map<String, dynamic>> map, BaseLogger logger) {
- for (var item in map) {
+ /// Returns a list of Pages constructed by the Json like [list].
+ static void parseList(ModuleModel module, List<dynamic> list,
+ BaseLogger logger) {
+ // Note: "List<Map<String, dynamic> list" does not work with json maps.
+ for (var item in list) {
if (!ModelBase.isMap(item)) {
module.logger.error(
- 'curious item in section list of ${module.fullName()}: ${StringUtils.limitString("$item", 80)}');
+ 'curious item in section list of ${module.fullName()}: ${StringUtils
+ .limitString("$item", 80)}');
} else {
final page = PageModel(module, item, logger);
page.parse();
BaseLogger logger)
: super(section, page, WidgetModelType.section, logger);
+ /// Dumps the internal structure into a [stringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer.write(
+ ' = section $name: $sectionModelType options: ${options.join(
+ ' ')} [\n');
+ for (var child in children) {
+ child.dump(stringBuffer);
+ }
+ stringBuffer.write(' ] # ${fullName()}\n');
+ return stringBuffer;
+ }
+
/// Returns the name including the names of the parent
@override
String fullName() =>
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(
+ checkSuperfluousAttributes(
map, 'children fields name options sectionType widgetType'.split(' '));
sectionModelType = parseEnum<SectionModelType>(
'sectionType', map, SectionModelType.values);
int no = 0;
for (var child in childrenList) {
no++;
- if (!ModelBase.isMap(childrenList)) {
+ if (!ModelBase.isMap(child)) {
logger
.error('child $no of "children" is not a map in ${fullName()}: '
- '${StringUtils.limitString(child.toString(), 80)}');
+ '${StringUtils.limitString(child.toString(), 80)}');
} else {
if (!child.containsKey('widgetType')) {
logger.error(
'child $no of "children" does not have "widgetType" in ${fullName()}: '
- '${StringUtils.limitString(child.toString(), 80)}');
+ '${StringUtils.limitString(child.toString(), 80)}');
} else {
final widgetType = StringUtils.stringToEnum<WidgetModelType>(
child['widgetType'].toString(), WidgetModelType.values);
break;
case WidgetModelType.combobox:
widget = ComboboxModel(this, page, child, logger);
+ page.addField(widget);
break;
case WidgetModelType.textField:
widget = TextFieldModel(this, page, child, logger);
}
if (widget != null) {
children.add(widget);
+ widget.parse();
+ page.widgets.add(widget);
+ switch (widget.widgetModelType) {
+ case WidgetModelType.button:
+ page.addButton(widget);
+ break;
+ case WidgetModelType.textField:
+ case WidgetModelType.combobox:
+ case WidgetModelType.checkbox:
+ page.addField(widget);
+ break;
+ default:
+ break;
+ }
}
}
}
}
}
- /// Returns a list of SectionModel constructed by the Json like [map].
+ /// Returns a list of SectionModel constructed by the Json like [list].
static void parseSections(PageModel page, SectionModel section,
- List<Map<String, dynamic>> map, BaseLogger logger) {
- final rc = <SectionModel>[];
+ List<dynamic> list, BaseLogger logger) {
int no = 0;
- for (var item in map) {
+ for (var item in list) {
no++;
if (!ModelBase.isMap(item)) {
page.logger.error(
- 'curious item in section list of ${page.fullName()}: ${StringUtils.limitString("$item", 80)}');
+ 'curious item in section list of ${page.fullName()}: ${StringUtils
+ .limitString("$item", 80)}');
} else {
final current = SectionModel(no, page, null, item, logger);
current.parse();
RegExp(r'^(readonly|disabled|password|required|unique)$');
int maxSize;
int rows;
+ var value;
FormFieldValidator<String> validator;
SectionModel section, PageModel page, this.map, BaseLogger logger)
: super(section, page, map, WidgetModelType.textField, logger);
+ /// Dumps the internal structure into a [stringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer
+ .write(' textField $name: options: ${listToString(options)}\n');
+ return stringBuffer;
+ }
+
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(
- map, 'dataType label maxSize name options rows toolTip'.split(' '));
+ checkSuperfluousAttributes(
+ map,
+ 'dataType label maxSize name options rows toolTip value widgetType'
+ .split(' '));
super.parse();
maxSize = parseInt('maxSize', map, required: false);
rows = parseInt('rows', map, required: false);
+ switch (dataType) {
+ case DataType.int:
+ case DataType.reference:
+ value = parseInt('value', map);
+ break;
+ default:
+ value = parseString('value', map);
+ break;
+ }
options = parseOptions('options', map);
checkOptionsByRegExpr(options, regExprOptions);
}
@override
String fullName() => '${section.name}.text$id';
+ /// Dumps the internal structure into a [stringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer
+ .write(' text $id text: $text: options: ${options.join(' ')}\n');
+ return stringBuffer;
+ }
+
/// Parses the map and stores the data in the instance.
void parse() {
- checkSuperfluous(map, 'options text widgetType'.split(' '));
+ checkSuperfluousAttributes(map, 'options text widgetType'.split(' '));
text = parseString('text', map, required: true);
options = parseOptions('options', map);
checkOptionsByRegExpr(options, regExprOptions);
this.id = ++lastId;
}
+ /// Dumps the internal structure into a [stringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer);
+
+ void parse();
+
String widgetName();
}
case WidgetModelType.textField:
rc.add(textField(child));
break;
+ case WidgetModelType.button:
+ rc.add(button(child));
+ break;
case WidgetModelType.emptyLine:
rc.add(emptyLine(child));
break;
break;
}
}
+ return rc;
}
}
-import 'package:dart_bones/dart_bones.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bones/flutter_bones.dart';
import 'package:test/test.dart';
'help': {'de': 'Hilfe'},
'wrong name %{0}': {'de': 'falscher name %{0}'}
};
- final logger = MemoryLogger(LEVEL_FINE);
setUpAll(() => Settings.setLocaleByNames(language: 'en'));
group('Settings', () {
test('basic', () {
Settings.setLocale(Locale('de', 'de'));
- final settings = Settings(logger);
expect(Settings.translate('abc', map), equals('abc'));
expect(Settings.translate('help', map), equals('help'));
expect(
+import 'dart:convert';
+
import 'package:dart_bones/dart_bones.dart';
import 'package:flutter_bones/flutter_bones.dart';
import 'package:test/test.dart';
final logger = MemoryLogger(LEVEL_FINE);
group('module', () {
test('module', () {
- final module = Demo1(logger);
+ logger.clear();
+ final module = Demo1(cloneOfMap(userModel), logger);
module.parse();
final errors = logger.errors;
expect(errors.length, equals(0));
final page = module.pageByName('create');
expect(page?.fullName(), equals('demo1.create'));
expect(module.fullName(), equals('demo1'));
+ final dump = module.dump(StringBuffer()).toString();
+ expect(dump, '''= module demo1: options:
+== page create: PageModelType.create options:
+ = section simpleForm1: SectionModelType.simpleForm options: [
+ textField user: options: required unique
+ button buttonStore: text: options: null
+ ] # create.simpleForm1
+''');
+ final userField = page.getField('user');
+ expect(userField, isNotNull);
+ expect(userField.widgetName(), 'user');
+ userField.value = 'Hi';
+ expect(userField.value, equals('Hi'));
+ expect(userField.fullName(), equals('create.user'));
+ expect(userField.page.fullName(), equals(page.fullName()));
+ expect(userField.section, isNotNull);
+ final button = page.getButton('buttonStore');
+ expect(button, isNotNull);
+ expect(button.section, equals(userField.section));
+ expect(button.fullName(), 'simpleForm1.buttonStore');
+ expect(button.widgetName(), 'buttonStore');
+ });
+ });
+ group('ModelBase', () {
+ test('errors', () {
+ logger.clear();
+ final map = cloneOfMap(userModel);
+ final field = <String, dynamic>{
+ 'widgetType': 'textField',
+ 'name': 'year',
+ 'label': 'Year',
+ 'options': 'required;blubb',
+ 'dataType': 'int'
+ };
+ map['pages'][0]['sections'][0]['children'][0] = field;
+ var module = Demo1(map, logger);
+ module.parse();
+ var errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(logger.contains('blub'), isTrue);
+ logger.clearErrors();
+ field['options'] = 3;
+ module = Demo1(map, logger);
+ module.parse();
+ errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(logger.contains('wrong datatype'), isTrue);
+ // ===
+ logger.clear();
+ field['newfeature'] = 3;
+ field['dataType'] = 'number';
+ field['options'] = '';
+ module = Demo1(map, logger);
+ module.parse();
+ errors = logger.errors;
+ expect(errors.length, equals(3));
+ expect(logger.contains('unknown attribute "newfeature"'), isTrue);
+ expect(
+ logger.contains(
+ 'unknown value number of attribute "dataType" in create.year'),
+ isTrue);
+ expect(logger.contains('wrong datatype of options String in create.year'),
+ isTrue);
+ // ===
+ logger.clear();
+ field.removeWhere(
+ (key, value) => key == 'newfeature' || key == 'dataType');
+ map['pages'][0].remove('pageType');
+ module = Demo1(map, logger);
+ module.parse();
+ map['pages'][0]['pageType'] = 'simpleForm';
+ errors = logger.errors;
+ expect(errors.length, equals(2));
+ expect(logger.contains('missing attribute \"pageType\" in demo1.create'),
+ isTrue);
+ });
+ });
+ group('CheckboxModel', () {
+ logger.clear();
+ test('errors', () {
+ final map = cloneOfMap(userModel);
+ final field = <String, dynamic>{
+ 'widgetType': 'checkbox',
+ 'name': 'hidden',
+ 'label': 'Hidden',
+ 'options': 'required',
+ };
+ map['pages'][0]['sections'][0]['children'][0] = field;
+ var module = Demo1(map, logger);
+ module.parse();
+ var errors = logger.errors;
+ expect(errors.length, equals(2));
+ final checkbox = module.pageByName('create').getField('hidden');
+ expect(checkbox, isNotNull);
+ expect(checkbox.dataType, DataType.bool);
+ final dump = module.dump(StringBuffer()).toString();
+ expect(dump, equals('''= module demo1: options:
+== page create: PageModelType.create options:
+ = section simpleForm1: SectionModelType.simpleForm options: [
+ checkbox hidden: text: options: required
+ button buttonStore: text: options: null
+ ] # create.simpleForm1
+'''));
+ });
+ });
+ group('ComboboxModel', () {
+ logger.clear();
+ test('basic', () {
+ final map = cloneOfMap(userModel);
+ final field = <String, dynamic>{
+ 'widgetType': 'combobox',
+ 'name': 'class',
+ 'label': 'Class',
+ 'options': 'undef',
+ 'texts': ';bad;OK;good',
+ 'values': [-1, 0, 1],
+ 'dataType': 'int',
+ };
+ map['pages'][0]['sections'][0]['children'][0] = field;
+ var module = Demo1(map, logger);
+ module.parse();
+ var errors = logger.errors;
+ expect(errors.length, equals(2));
+ final combobox = module.pageByName('create').getField('class');
+ expect(combobox, isNotNull);
+ expect(combobox.dataType, DataType.int);
+ final dump = module.dump(StringBuffer()).toString();
+ expect(dump, equals('''= module demo1: options:
+== page create: PageModelType.create options:
+ = section simpleForm1: SectionModelType.simpleForm options: [
+ combobox class: texts: bad OK good options: undef
+ button buttonStore: text: options: null
+ ] # create.simpleForm1
+'''));
+ });
+ });
+ group('Non field widgets', () {
+ logger.clear();
+ test('basic', () {
+ final map = cloneOfMap(userModel);
+ final list = [
+ {
+ 'widgetType': 'emptyLine',
+ },
+ {'widgetType': 'text', 'text': '*Hi world*', 'options': 'rich'},
+ ];
+ map['pages'][0]['sections'][0]['children'] = list;
+ var module = Demo1(map, logger);
+ module.parse();
+ var errors = logger.errors;
+ expect(errors.length, equals(3));
+ final dump = module.dump(StringBuffer()).toString();
+ expect(dump, equals('''= module demo1: options:
+== page create: PageModelType.create options:
+ = section simpleForm1: SectionModelType.simpleForm options: [
+ emptyLine: options:
+ text 24 text: *Hi world*: options: rich
+ ] # create.simpleForm1
+'''));
+ final page = module.pageByName('create');
+ final allWidgets = page.getWidgets(null);
+ expect(allWidgets.length, equals(2));
+ final names = allWidgets.fold('', (prevValue, element) {
+ return prevValue +=
+ ' ' + element.widgetName() + '/' + element.fullName();
+ });
+ expect(names.contains('null'), isFalse);
+ final nonFieldWidgets = page.getWidgets((item) => [
+ WidgetModelType.text,
+ WidgetModelType.emptyLine
+ ].contains(item.widgetModelType));
+ expect(nonFieldWidgets.length, equals(2));
});
});
}
-class Demo1 extends ModuleModel {
- static final model = <String, dynamic>{
- "module": "demo1",
- "pages": [
- {
- "name": "create",
- "pageType": "create",
- "sections": [
- {
- "sectionType": "simpleForm",
- "children": [
- {
- "widgetType": "textField",
- "name": "user",
- "label": "User",
- "options": "required;unique",
- },
- {
- "widgetType": "button",
- "name": "buttonStore",
- "label": "Save",
- },
- ]
- }
- ]
- },
- ],
- };
+final userModel = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ 'name': 'create',
+ 'pageType': 'create',
+ 'sections': [
+ {
+ 'sectionType': 'simpleForm',
+ 'children': [
+ {
+ 'widgetType': 'textField',
+ 'name': 'user',
+ 'label': 'User',
+ 'options': 'required;unique',
+ },
+ {
+ 'widgetType': 'button',
+ 'name': 'buttonStore',
+ 'label': 'Save',
+ },
+ ]
+ }
+ ]
+ },
+ ],
+};
- Demo1(BaseLogger logger) : super(model, logger);
+Map<String, dynamic> cloneOfMap(Map<String, dynamic> map) {
+ final rc = json.decode(json.encode(map));
+ return rc;
+}
+
+class Demo1 extends ModuleModel {
+ Demo1(Map<String, dynamic> map, BaseLogger logger) : super(map, logger);
/// Returns the name including the names of the parent
@override