WIP eTemplate2.0 DTD

This commit is contained in:
ralf 2024-04-19 12:23:10 +02:00
parent c04cf276b7
commit d1b3786b2a
6 changed files with 7404 additions and 1059 deletions

127
doc/etemplate2-rng.php Normal file → Executable file
View File

@ -1,3 +1,4 @@
#!/usr/bin/env php
<?php
/**
* eTemplate2 XML schema
@ -31,9 +32,10 @@ if (!file_exists(($file = __DIR__."/etemplate2/etemplate2.rng")))
die("Missing file '$file', you need to generate it from 'etemplate2.dtd' e.g. with PHPStorm!");
}
$grammar = new SimpleXMLElement(file_get_contents($file));
$widgets = getByName($grammar, 'Widgets');
$widgets_choice = getByName($grammar, 'Widgets')->choice;
/**
* Manually overwriting problems / errors in what we automatically generate
* Use class-name (e.g. Et2Button) so all descends inherit the fix, use-tag to fix only specific widget.
* @todo fix in TS sources
*/
$overwrites = [
@ -44,7 +46,9 @@ $overwrites = [
'id' => 'string', // commented out with some reasoning in Et2Widget
//'data' => null, // ToDo: not sure, but AFAIK this is no attribute, but somehow listed in each widget
'width' => 'string',
'height' => 'string',
'span' => 'string', // actually int|"all"
'slot' => 'string',
],
],
'Et2InputWidget' => [
@ -109,7 +113,34 @@ $overwrites = [
'et2-split' => [
'.children' => 'Widgets',
],
'et2-select-*' => 'et2-select', // seems like et2-select-* widgets are NOT parsed
'et2-url-email' => [
'.attrs' => [
'emailDisplay' => 'string', // can't see that anywhere in the code, but in addressbook.index.xet
],
],
'et2-nextmatch-header-custom' => [
'.attrs' => [
'emptyLabel' => 'string',
],
],
'Et2Button' => [
'.attrs' => [
'image' => 'string',
'noSubmit' => 'boolean',
],
],
'Et2Select' => [
'.attrs' => [
'rows' => 'int',
'tabindex' => 'int',
'allowFreeEntries' => 'boolean',
],
],
'et2-email' => [
'.attrs' => [
'onTagClick' => 'function',
],
],
];
/**
@ -118,13 +149,75 @@ $overwrites = [
// make overlay the only allowed start element
removeNode($grammar->start->choice);
$grammar->start->addChild('ref')->addAttribute('name', 'overlay');
// overlay can only container template, not all widgets
getByName($grammar, 'overlay')->element->zeroOrMore->ref->attributes()['name'] = 'template';
getByName($grammar, 'attlist.vfs-upload')->addChild('optional')
->addChild('attribute')->addAttribute('name', 'callback');
// add statustext to tab
getByName($grammar, 'attlist.tab')->addChild('optional')
->addChild('attribute')->addAttribute('name', 'statustext');
// fix legacy widgets: attribute-name => (array of) widgets
$missing_legacy_attributes = [
'callback' => 'vfs-upload',
'statustext' => 'tab',
'minWidth' => 'column',
'maxWidth' => 'column',
'id' => [
'.optional' => false,
'nextmatch-header', 'nextmatch-sortheader', 'nextmatch-customfields', 'nextmatch',
],
'template' => ['.optional' => false, 'nextmatch'],
'header_left' => 'nextmatch',
'header_row' => 'nextmatch',
'header_right' => 'nextmatch',
'disabled' => 'nextmatch',
'onselect' => 'nextmatch',
'span' => ['nextmatch', 'nextmatch-header', 'nextmatch-customfields', 'nextmatch-sortheader'],
'class' => ['nextmatch','nextmatch-header', 'nextmatch-customfields', 'nextmatch-sortheader'],
'label' => [
'.optional' => false,
'nextmatch-header', 'nextmatch-sortheader',
],
'sortmode' => [
'.values' => ['ASC', 'DESC'],
'.default' => 'ASC',
'nextmatch-sortheader',
],
];
foreach($missing_legacy_attributes as $attribute => $widgets)
{
foreach((array)$widgets as $key => $widget)
{
if (!is_int($key)) continue; // .(values|default)
// widget not found add it plus it's attribute-list
if (!getByName($grammar, $widget))
{
$widgets_choice->addChild('ref')->addAttribute('name', $widget);
($define = $grammar->addChild('define'))->addAttribute('name', $widget);
($element = $define->addChild('element'))->addAttribute('name', $widget);
$element->addChild('ref')->addAttribute('name', 'attlist.'.$widget);
$element->addChild('empty'); // no children allowed
$grammar->addChild('define')->addAttribute('name', 'attlist.'.$widget);
}
// add (optional) attribute
if (!is_array($widgets) || (!isset($widgets['.optional']) || $widgets['.optional'] === true))
{
$attr = getByName($grammar, 'attlist.'.$widget)->addChild('optional')
->addChild('attribute');
}
else
{
$attr = getByName($grammar, 'attlist.'.$widget)->addChild('attribute');
}
$attr->addAttribute('name', $attribute);
// add values and/or default
if (is_array($widgets) && isset($widgets['.values']))
{
$choice = $attr->addChild('choice');
foreach($widgets['.values'] as $value)
{
$choice->addChild('value', $value);
}
}
if (is_array($widgets) && isset($widgets['.default']))
{
$attr->addAttribute('a:defaultValue', $widgets['.default'], 'http://relaxng.org/ns/compatibility/annotations/1.0');
}
}
}
// build a hashed version of all classes, members and attributes to e.g. find ancestors
$classes = [];
@ -175,7 +268,7 @@ foreach($data['modules'] as $module)
$attrs = $element->addChild('ref');
$attrs->addAttribute('name', 'attlist.'.$export['name']);
// add to widgets
$widgets->choice->addChild('ref')->addAttribute('name', $export['name']);
$widgets_choice->addChild('ref')->addAttribute('name', $export['name']);
// add the element-attributes
$attrs = $grammar->addChild('define');
@ -193,10 +286,11 @@ foreach($data['modules'] as $module)
}
else
{
$list = $element->addChild('oneOrMore'); // zeroOrMore for e.g. empty boxes?
// add allowed children
foreach((array)$overwrites[$export['name']]['.children'] as $child)
{
$element->addChild('ref')->addAttribute('name', $child);
$list->addChild('ref')->addAttribute('name', $child);
}
}
@ -206,7 +300,7 @@ foreach($data['modules'] as $module)
}
$remove = [];
foreach($widgets->choice->children() as $widget)
foreach($widgets_choice->children() as $widget)
{
if (preg_match($overwrites['.remove'], $name=(string)$widget->attributes()['name']))
{
@ -261,8 +355,8 @@ echo preg_replace('#<choice>
*/
function removeWidget(string $name)
{
global $grammar, $widgets;
if (removeByName($widgets->choice, $name))
global $grammar, $widgets_choice;
if (removeByName($widgets_choice, $name))
{
removeByName($grammar, $name);
removeByName($grammar, 'attlist.'.$name);
@ -381,7 +475,10 @@ function attributes(array $class, ?SimpleXMLElement $attrs=null)
{
$default = substr($default, 1, -1);
}
$attribute->addAttribute('a:defaultValue', $default, 'http://relaxng.org/ns/compatibility/annotations/1.0');
if ($default !== 'undefined') // do NOT add undefined, it's the default anyway
{
$attribute->addAttribute('a:defaultValue', $default, 'http://relaxng.org/ns/compatibility/annotations/1.0');
}
}
switch ($attr['type']['text'] ?? 'any')
{

View File

@ -26,9 +26,9 @@ function replace(string, terms)
}
export default {
globs: ["api/js/etemplate/**/Et2*/*.ts"],
globs: ["api/js/etemplate/**/Et2*.ts","api/js/etemplate/Et2Nextmatch/**/*.ts"],
/** Globs to exclude */
exclude: [],//, 'et2_*.ts', '**/test/*', '**/*.styles.ts', '**/*.test.ts'],
exclude: ["api/js/etemplate/**/test/*"],//, 'et2_*.ts', '**/test/*', '**/*.styles.ts', '**/*.test.ts'],
dev: false,
litelement: true,
plugins: [

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@
-->
<!ENTITY % Widgets "template|grid|vbox|box|details|hbox|groupbox|caption|split|button|buttononly|colorpicker|description|label|entry|contact-value|contact-account|contact-template|infolog-value|tracker-value|records-value|textbox|hidden|searchbox|int|integer|float|passwd|url|url-email|url-phone|url-fax|menupopup|listbox|select|select-cat|select-percent|select-priority|select-country|select-state|select-year|select-month|select-day|select-dow|select-hour|select-number|select-app|select-lang|select-bool|select-timezone|select-bitwise|menulist|checkbox|radio|radiogroup|date|date-time|date-timeonly|date-duration|date-since|date-time_today|time_or_date|date-range|diff|dropdown_button|styles|link-to|link-apps|link-entry|link|link-string|link-list|link-add|select-account|taglist|taglist-account|taglist-email|taglist-cat|taglist-thumbnail|taglist-state|customfields|customfields-list|favorites|html|htmlarea|tabbox|button-timestamp|timestamper|toolbar|tree|tree-cat|historylog|hrule|image|appicon|avatar|lavatar|iframe|file|progress|portlet|ajax_select|vfs|vfs-name|vfs-path|vfs-mime|vfs-size|vfs-mode|vfs-uid|vfs-gid|vfs-upload|vfs-select|video|audio|barcode|itempicker|script|countdown">
<!ELEMENT overlay (%Widgets;)*>
<!ELEMENT overlay (template)*>
<!ELEMENT template (%Widgets;)*>
<!ATTLIST template
template CDATA #IMPLIED
@ -59,13 +59,14 @@ attributes CDATA #IMPLIED
class CDATA #IMPLIED
width CDATA #IMPLIED>
<!ELEMENT rows (row)*>
<!ELEMENT row (%Widgets;)>
<!ELEMENT row (%Widgets;)+>
<!ATTLIST row
class CDATA #IMPLIED
height CDATA #IMPLIED
valign CDATA #IMPLIED
disabled CDATA #IMPLIED
part CDATA #IMPLIED
id CDATA #IMPLIED
>
<!ATTLIST grid
border CDATA #IMPLIED
@ -2984,7 +2985,7 @@ customfields CDATA #IMPLIED
fields CDATA #IMPLIED
value CDATA #IMPLIED
type_filter CDATA #IMPLIED
private (true|false) "undefined"
private (true|false) #IMPLIED
sub_app CDATA #IMPLIED
onchange CDATA #IMPLIED
prefix CDATA "#"
@ -3017,7 +3018,7 @@ customfields CDATA #IMPLIED
fields CDATA #IMPLIED
value CDATA #IMPLIED
type_filter CDATA #IMPLIED
private (true|false) "undefined"
private (true|false) #IMPLIED
sub_app CDATA #IMPLIED
onchange CDATA #IMPLIED
prefix CDATA "#"
@ -3158,7 +3159,7 @@ add_tabs (true|false) "false"
tab_height CDATA #IMPLIED
align_tabs (v|h) "h"
>
<!ELEMENT tabs (tab)>
<!ELEMENT tabs (tab)*>
<!ELEMENT tab EMPTY>
<!ATTLIST tab
id CDATA #IMPLIED

View File

@ -147,7 +147,7 @@
<element name="overlay">
<ref name="attlist.overlay"/>
<zeroOrMore>
<ref name="Widgets"/>
<ref name="template"/>
</zeroOrMore>
</element>
</define>
@ -295,7 +295,9 @@
<define name="row">
<element name="row">
<ref name="attlist.row"/>
<ref name="Widgets"/>
<oneOrMore>
<ref name="Widgets"/>
</oneOrMore>
</element>
</define>
<define name="attlist.row" combine="interleave">
@ -314,6 +316,9 @@
<optional>
<attribute name="part"/>
</optional>
<optional>
<attribute name="id"/>
</optional>
</define>
<define name="attlist.grid" combine="interleave">
<optional>
@ -11611,7 +11616,7 @@
<attribute name="type_filter"/>
</optional>
<optional>
<attribute name="private" a:defaultValue="undefined">
<attribute name="private">
<choice>
<value>true</value>
<value>false</value>
@ -11729,7 +11734,7 @@
<attribute name="type_filter"/>
</optional>
<optional>
<attribute name="private" a:defaultValue="undefined">
<attribute name="private">
<choice>
<value>true</value>
<value>false</value>
@ -12254,7 +12259,9 @@
<define name="tabs">
<element name="tabs">
<ref name="attlist.tabs"/>
<ref name="tab"/>
<zeroOrMore>
<ref name="tab"/>
</zeroOrMore>
</element>
</define>
<define name="attlist.tabs" combine="interleave">