Adapt nextmatch to work with webcomponents + readonly datetime widget

This commit is contained in:
nathan 2021-12-14 16:55:02 -07:00
parent dc8b0a7080
commit 528134cfac
6 changed files with 557 additions and 331 deletions

View File

@ -0,0 +1,12 @@
import {css} from "@lion/core";
export const dateStyles = css`
:host {
display: inline-block;
white-space: nowrap;
min-width: 20ex;
}
.overdue {
color: red; // var(--whatever the theme color)
}
`;

View File

@ -13,6 +13,7 @@ import {css, html} from "@lion/core";
import {LionInputDatepicker} from "@lion/input-datepicker"; import {LionInputDatepicker} from "@lion/input-datepicker";
import {Unparseable} from "@lion/form-core"; import {Unparseable} from "@lion/form-core";
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {dateStyles} from "./DateStyles";
/** /**
@ -155,7 +156,7 @@ export function parseDateTime(dateTimeString)
{ {
if(!isNaN(dateTimeString) && parseInt(dateTimeString) == dateTimeString) if(!isNaN(dateTimeString) && parseInt(dateTimeString) == dateTimeString)
{ {
this.egw().debug("warn", "Invalid date/time string: " + dateTimeString); console.warn("Invalid date/time string: " + dateTimeString);
dateTimeString *= 1000; dateTimeString *= 1000;
} }
try try
@ -275,6 +276,7 @@ export class Et2Date extends Et2InputWidget(LionInputDatepicker)
{ {
return [ return [
...super.styles, ...super.styles,
dateStyles,
css` css`
:host([focused]) ::slotted(button), :host(:hover) ::slotted(button) { :host([focused]) ::slotted(button), :host(:hover) ::slotted(button) {
display: inline-block; display: inline-block;
@ -337,7 +339,7 @@ export class Et2Date extends Et2InputWidget(LionInputDatepicker)
{ {
return null; return null;
} }
// Empty field, return '' // Empty field, return ''
if(!this.modelValue) if(!this.modelValue)
{ {

View File

@ -0,0 +1,74 @@
import {css, html, LitElement} from "@lion/core";
import {formatDateTime, parseDateTime} from "./Et2Date";
import {et2_IDetachedDOM} from "../et2_core_interfaces";
import {Et2Widget} from "../Et2Widget/Et2Widget";
import {dateStyles} from "./DateStyles";
/**
* This is a stripped-down read-only widget used in nextmatch
*/
export class Et2DateTimeReadonly extends Et2Widget(LitElement) implements et2_IDetachedDOM
{
private value : any;
static get styles()
{
return [
...super.styles,
dateStyles
];
}
static get properties()
{
return {
...super.properties,
value: String,
}
}
set_value(value)
{
this.value = value;
}
render()
{
let parsed : Date | Boolean = this.value ? parseDateTime(this.value) : false
return html`
<time ${this.id ? html`id="${this._dom_id}"` : ''}
datetime="${parsed ? formatDateTime(<Date>parsed, {dateFormat: "Y-m-d", timeFormat: "H:i:s"}) : ""}">
${this.value ? formatDateTime(<Date>parsed) : ''}
</time>
`;
}
getDetachedAttributes(attrs)
{
attrs.push("id", "value", "class");
}
getDetachedNodes() : HTMLElement[]
{
return [<HTMLElement><unknown>this];
}
setDetachedAttributes(_nodes : HTMLElement[], _values : object, _data? : any) : void
{
// Do nothing, since we can't actually stop being a DOM node...
}
loadFromXML()
{
// nope
}
loadingFinished()
{
// already done, I'm a wc with no children
}
}
// @ts-ignore TypeScript is not recognizing that Et2Date is a LitElement
customElements.define("et2-datetime_ro", Et2DateTimeReadonly);

View File

@ -93,6 +93,12 @@ const Et2WidgetMixin = (superClass) =>
return { return {
...super.properties, ...super.properties,
/**
* Widget ID. Optional, and not always the same as the DOM ID if the widget is inside something
* else that also has an ID.
*/
id: {type: String, reflect: false},
/** /**
* CSS Class. This class is applied to the _outside_, on the web component itself. * CSS Class. This class is applied to the _outside_, on the web component itself.
* Due to how WebComponents work, this might not change anything inside the component. * Due to how WebComponents work, this might not change anything inside the component.
@ -606,6 +612,11 @@ const Et2WidgetMixin = (superClass) =>
} }
} }
transformAttributes(attrs)
{
transformAttributes(this, this.getArrayMgr("content"), attrs);
}
iterateOver(_callback : Function, _context, _type) iterateOver(_callback : Function, _context, _type)
{ {
if(typeof _type == "undefined" || et2_implements_registry[_type] && et2_implements_registry[_type](this)) if(typeof _type == "undefined" || et2_implements_registry[_type] && et2_implements_registry[_type](this))
@ -817,8 +828,12 @@ const Et2WidgetMixin = (superClass) =>
// Create the copy // Create the copy
var copy = <Et2WidgetClass>this.cloneNode(); var copy = <Et2WidgetClass>this.cloneNode();
let widget_class = window.customElements.get(this.nodeName); let widget_class = window.customElements.get(this.localName);
let properties = widget_class ? widget_class.properties() : {}; let properties = widget_class ? widget_class.properties : [];
for(let key in properties)
{
copy[key] = this[key];
}
if(_parent) if(_parent)
{ {
@ -1078,10 +1093,28 @@ export function loadWebComponent(_nodeName : string, _template_node, parent : Et
_template_node.getAttribute("id"), _template_node.getAttribute("readonly"), _template_node.getAttribute("id"), _template_node.getAttribute("readonly"),
typeof parent.readonly !== "undefined" ? parent.readonly : false) : false; typeof parent.readonly !== "undefined" ? parent.readonly : false) : false;
// Apply any set attributes - widget will do its own coercion let attrs = {};
_template_node.getAttributeNames().forEach(attribute => _template_node.getAttributeNames().forEach(attribute =>
{ {
let attrValue = _template_node.getAttribute(attribute); attrs[attribute] = _template_node.getAttribute(attribute);
});
widget.transformAttributes(attrs);
// Children need to be loaded
widget.loadFromXML(_template_node);
return widget;
}
function transformAttributes(widget, mgr : et2_arrayMgr, attributes)
{
const widget_class = window.customElements.get(widget.localName);
// Apply any set attributes - widget will do its own coercion
for(let attribute in attributes)
{
let attrValue = attributes[attribute];
// If there is not attribute set, ignore it. Widget sets its own default. // If there is not attribute set, ignore it. Widget sets its own default.
if(typeof attrValue === "undefined") if(typeof attrValue === "undefined")
@ -1095,7 +1128,7 @@ export function loadWebComponent(_nodeName : string, _template_node, parent : Et
case Boolean: case Boolean:
// If the attribute is marked as boolean, parse the // If the attribute is marked as boolean, parse the
// expression as bool expression. // expression as bool expression.
attrValue = mgr.parseBoolExpression(attrValue); attrValue = mgr ? mgr.parseBoolExpression(attrValue) : attrValue;
break; break;
case Function: case Function:
// We parse it into a function here so we can pass in the widget as context. // We parse it into a function here so we can pass in the widget as context.
@ -1106,8 +1139,8 @@ export function loadWebComponent(_nodeName : string, _template_node, parent : Et
} }
break; break;
default: default:
attrValue = mgr.expandName(attrValue); attrValue = mgr ? mgr.expandName(attrValue) : attrValue;
if(!_template_node.getAttribute("no_lang") && widget_class.translate[attribute]) if(!attributes.no_lang && widget_class.translate[attribute])
{ {
// allow attribute to contain multiple translated sub-strings eg: {Firstname}.{Lastname} // allow attribute to contain multiple translated sub-strings eg: {Firstname}.{Lastname}
if(attrValue.indexOf('{') !== -1) if(attrValue.indexOf('{') !== -1)
@ -1136,7 +1169,7 @@ export function loadWebComponent(_nodeName : string, _template_node, parent : Et
// Set as property, not attribute // Set as property, not attribute
widget[attribute] = attrValue; widget[attribute] = attrValue;
} }
}); }
if(widget_class.getPropertyOptions("value") && widget.set_value) if(widget_class.getPropertyOptions("value") && widget.set_value)
{ {
@ -1149,9 +1182,4 @@ export function loadWebComponent(_nodeName : string, _template_node, parent : Et
} }
} }
} }
// Children need to be loaded
widget.loadFromXML(_template_node);
return widget;
} }

View File

@ -23,6 +23,7 @@ import {et2_arrayMgrs_expand} from "./et2_core_arrayMgr";
import {et2_dataview_grid} from "./et2_dataview_view_grid"; import {et2_dataview_grid} from "./et2_dataview_view_grid";
import {egw} from "../jsapi/egw_global"; import {egw} from "../jsapi/egw_global";
import {et2_IDetachedDOM, et2_IDOMNode} from "./et2_core_interfaces"; import {et2_IDetachedDOM, et2_IDOMNode} from "./et2_core_interfaces";
import {Et2DateTimeReadonly} from "./Et2Date/Et2DateTimeReadonly";
/** /**
* The row provider contains prototypes (full clonable dom-trees) * The row provider contains prototypes (full clonable dom-trees)
@ -31,12 +32,13 @@ import {et2_IDetachedDOM, et2_IDOMNode} from "./et2_core_interfaces";
*/ */
export class et2_nextmatch_rowProvider export class et2_nextmatch_rowProvider
{ {
private _rowProvider: any; private _rowProvider : any;
private _subgridCallback: any; private _subgridCallback : any;
private _context: any; private _context : any;
private _rootWidget: any; private _rootWidget : any;
private _template: any; private _template : any;
private _dataRow: any; private _dataRow : any;
/** /**
* Creates the nextmatch row provider. * Creates the nextmatch row provider.
* *
@ -45,9 +47,9 @@ export class et2_nextmatch_rowProvider
* @param {object} _context * @param {object} _context
* @memberOf et2_nextmatch_rowProvider * @memberOf et2_nextmatch_rowProvider
*/ */
constructor( _rowProvider, _subgridCallback, _context) constructor(_rowProvider, _subgridCallback, _context)
{ {
// Copy the arguments // Copy the arguments
this._rowProvider = _rowProvider; this._rowProvider = _rowProvider;
@ -73,7 +75,7 @@ export class et2_nextmatch_rowProvider
* @param _rootWidget is the parent widget of the data rows (i.e. * @param _rootWidget is the parent widget of the data rows (i.e.
* the nextmatch) * the nextmatch)
*/ */
setDataRowTemplate( _widgets, _rowData, _rootWidget) setDataRowTemplate(_widgets, _rowData, _rootWidget)
{ {
// Copy the root widget // Copy the root widget
this._rootWidget = _rootWidget; this._rootWidget = _rootWidget;
@ -120,7 +122,7 @@ export class et2_nextmatch_rowProvider
this._template = rowTemplate; this._template = rowTemplate;
} }
getDataRow( _data : any, _row, _idx, _controller) getDataRow(_data : any, _row, _idx, _controller)
{ {
// Clone the row template // Clone the row template
@ -133,17 +135,24 @@ export class et2_nextmatch_rowProvider
// Insert the widgets into the row which do not provide the functions // Insert the widgets into the row which do not provide the functions
// to set the _data directly // to set the _data directly
var rowWidget : et2_nextmatch_rowTemplateWidget = null; var rowWidget : et2_nextmatch_rowTemplateWidget = null;
if (this._template.seperated.remaining.length > 0) if(this._template.seperated.remaining.length > 0)
{ {
// Transform the variable attributes // Transform the variable attributes
for (var i = 0; i < this._template.seperated.remaining.length; i++) for(var i = 0; i < this._template.seperated.remaining.length; i++)
{ {
var entry = this._template.seperated.remaining[i]; var entry = this._template.seperated.remaining[i];
for (var j = 0; j < entry.data.length; j++) for(var j = 0; j < entry.data.length; j++)
{ {
var set = entry.data[j]; var set = entry.data[j];
entry.widget.options[set.attribute] = mgrs["content"].expandName(set.expression); if(typeof entry.widget.options != "undefined")
{
entry.widget.options[set.attribute] = mgrs["content"].expandName(set.expression);
}
else if(entry.widget.getAttributeNames().indexOf(set.attribute) >= 0)
{
entry.widget.setAttribute(set.attribute, mgrs["content"].expandName(set.expression));
}
} }
} }
@ -156,47 +165,56 @@ export class et2_nextmatch_rowProvider
} }
// Update the content of all other widgets // Update the content of all other widgets
for (var i = 0; i < this._template.seperated.detachable.length; i++) for(var i = 0; i < this._template.seperated.detachable.length; i++)
{ {
var entry = this._template.seperated.detachable[i]; var entry = this._template.seperated.detachable[i];
let widget = entry.widget;
// Parse the attribute expressions // Parse the attribute expressions
var data : any = {}; var data : any = {};
for (var j = 0; j < entry.data.length; j++) for(var j = 0; j < entry.data.length; j++)
{ {
var set = entry.data[j]; var set = entry.data[j];
data[set.attribute] = mgrs["content"].expandName(set.expression); data[set.attribute] = mgrs["content"].expandName(set.expression);
} }
// WebComponent IS the node, and we've already cloned it
// Retrieve all DOM-Nodes if(typeof window.customElements.get(widget.localName) != "undefined")
var nodes = new Array(entry.nodeFuncs.length);
for (var j = 0; j < nodes.length; j++)
{ {
// Use the previously compiled node function to get the node // Use the clone, not the original
// from the entry widget = entry.nodeFuncs[0](row)
try }
else
{
// Retrieve all DOM-Nodes (legacy widgets)
var nodes = new Array(entry.nodeFuncs.length);
for(var j = 0; j < nodes.length; j++)
{ {
nodes[j] = entry.nodeFuncs[j](row); // Use the previously compiled node function to get the node
} // from the entry
catch (e) try
{ {
debugger; nodes[j] = entry.nodeFuncs[j](row);
continue; }
catch(e)
{
debugger;
continue;
}
} }
} }
// Set the array managers first // Set the array managers first
entry.widget._mgrs = mgrs; widget.setArrayMgrs(mgrs);
if (typeof data.id != "undefined") if(typeof data.id != "undefined")
{ {
entry.widget.id = data.id; widget.id = data.id;
} }
// Adjust data for that row // Adjust data for that row
entry.widget.transformAttributes?.call(entry.widget, data); widget.transformAttributes?.call(widget, data);
// Call the setDetachedAttributes function // Call the setDetachedAttributes function
entry.widget.setDetachedAttributes(nodes, data, _data); widget.setDetachedAttributes(nodes, data, _data);
} }
// Insert the row into the tr // Insert the row into the tr
@ -204,12 +222,13 @@ export class et2_nextmatch_rowProvider
tr.appendChild(row); tr.appendChild(row);
// Make the row expandable // Make the row expandable
if (typeof _data.content["is_parent"] !== "undefined" if(typeof _data.content["is_parent"] !== "undefined"
&& _data.content["is_parent"]) && _data.content["is_parent"])
{ {
_row.makeExpandable(true, function () { _row.makeExpandable(true, function()
{
return this._subgridCallback.call(this._context, return this._subgridCallback.call(this._context,
_row, _data, _controller); _row, _data, _controller);
}, this); }, this);
// Check for kept expansion, and set the row up to be re-expanded // Check for kept expansion, and set the row up to be re-expanded
@ -222,13 +241,14 @@ export class et2_nextmatch_rowProvider
var expansion_index = top_controller.kept_expansion.indexOf( var expansion_index = top_controller.kept_expansion.indexOf(
top_controller.dataStorePrefix + '::' + _data.content[this._context.settings.row_id] top_controller.dataStorePrefix + '::' + _data.content[this._context.settings.row_id]
); );
if(top_controller.kept_expansion && expansion_index >=0) if(top_controller.kept_expansion && expansion_index >= 0)
{ {
top_controller.kept_expansion.splice(expansion_index,1); top_controller.kept_expansion.splice(expansion_index, 1);
// Use a timeout since the DOM nodes might not be finished yet // Use a timeout since the DOM nodes might not be finished yet
window.setTimeout(function() { window.setTimeout(function()
{
_row.expansionButton.trigger('click'); _row.expansionButton.trigger('click');
},et2_dataview_grid.ET2_GRID_INVALIDATE_TIMEOUT); }, et2_dataview_grid.ET2_GRID_INVALIDATE_TIMEOUT);
} }
} }
@ -246,14 +266,14 @@ export class et2_nextmatch_rowProvider
* This allows the user to still have a drop target, or use actions that * This allows the user to still have a drop target, or use actions that
* do not require a row ID, such as 'Add new'. * do not require a row ID, such as 'Add new'.
*/ */
_createEmptyPrototype( ) _createEmptyPrototype()
{ {
var label = this._context && this._context.options && this._context.options.settings.placeholder; var label = this._context && this._context.options && this._context.options.settings.placeholder;
var placeholder = jQuery(document.createElement("td")) var placeholder = jQuery(document.createElement("td"))
.attr("colspan",this._rowProvider.getColumnCount()) .attr("colspan", this._rowProvider.getColumnCount())
.css("height","19px") .css("height", "19px")
.text(typeof label != "undefined" && label ? label : egw().lang("No matches found")); .text(typeof label != "undefined" && label ? label : egw().lang("No matches found"));
this._rowProvider._prototypes["empty"] = jQuery(document.createElement("tr")) this._rowProvider._prototypes["empty"] = jQuery(document.createElement("tr"))
.addClass("egwGridView_empty") .addClass("egwGridView_empty")
.append(placeholder); .append(placeholder);
@ -266,11 +286,11 @@ export class et2_nextmatch_rowProvider
* *
* @param {et2_widget} _widget * @param {et2_widget} _widget
*/ */
_getVariableAttributeSet( _widget) _getVariableAttributeSet(_widget)
{ {
let variableAttributes = []; let variableAttributes = [];
const process = function (_widget) const process = function(_widget)
{ {
// Create the attribtues // Create the attribtues
var hasAttr = false; var hasAttr = false;
@ -280,28 +300,15 @@ export class et2_nextmatch_rowProvider
}; };
// Get all attribute values // Get all attribute values
for (const key in _widget.attributes) let attrs = [];
if(_widget.getDetachedAttributes)
{
_widget.getDetachedAttributes(attrs);
}
for(let key of attrs)
{ {
if(typeof _widget.attributes[key] !== "object")
{
continue;
}
let attr_name = key; let attr_name = key;
let val; let val = _widget[key];
if(!_widget.attributes[key].ignore &&
typeof _widget.options != "undefined" &&
typeof _widget.options[key] != "undefined")
{
val = _widget.options[key];
}
// Handle web components
else if(_widget.attributes[key].value)
{
val = _widget.attributes[key].value;
attr_name = _widget.attributes[key].name;
}
// TODO: Improve detection
if(typeof val == "string" && val.indexOf("$") >= 0) if(typeof val == "string" && val.indexOf("$") >= 0)
{ {
hasAttr = true; hasAttr = true;
@ -312,6 +319,36 @@ export class et2_nextmatch_rowProvider
} }
} }
// Legacy
if(_widget.instanceOf(et2_widget))
{
for(const key in _widget.attributes)
{
if(typeof _widget.attributes[key] !== "object")
{
continue;
}
let attr_name = key;
let val;
if(!_widget.attributes[key].ignore &&
typeof _widget.options != "undefined" &&
typeof _widget.options[key] != "undefined")
{
val = _widget.options[key];
}
// TODO: Improve detection
if(typeof val == "string" && val.indexOf("$") >= 0)
{
hasAttr = true;
widgetData.data.push({
"attribute": attr_name,
"expression": val
});
}
}
}
// Add the entry if there is any data in it // Add the entry if there is any data in it
if(hasAttr) if(hasAttr)
{ {
@ -321,7 +358,7 @@ export class et2_nextmatch_rowProvider
// Check each column // Check each column
const columns = _widget._widgets; const columns = _widget._widgets;
for (var i = 0; i < columns.length; i++) for(var i = 0; i < columns.length; i++)
{ {
// If column is hidden, don't process it // If column is hidden, don't process it
if(typeof columns[i] === 'undefined' || this._context && this._context.columns && this._context.columns[i] && !this._context.columns[i].visible) if(typeof columns[i] === 'undefined' || this._context && this._context.columns && this._context.columns[i] && !this._context.columns[i].visible)
@ -334,7 +371,7 @@ export class et2_nextmatch_rowProvider
return variableAttributes; return variableAttributes;
} }
_seperateWidgets( _varAttrs) _seperateWidgets(_varAttrs)
{ {
// The detachable array contains all widgets which implement the // The detachable array contains all widgets which implement the
// et2_IDetachedDOM interface for all needed attributes // et2_IDetachedDOM interface for all needed attributes
@ -345,19 +382,20 @@ export class et2_nextmatch_rowProvider
var remaining = []; var remaining = [];
// Iterate over the widgets // Iterate over the widgets
for (var i = 0; i < _varAttrs.length; i++) for(var i = 0; i < _varAttrs.length; i++)
{ {
var widget = _varAttrs[i].widget; var widget = _varAttrs[i].widget;
// Check whether the widget parents are not allready in the "remaining" // Check whether the widget parents are not allready in the "remaining"
// slot - if this is the case do not include the widget at all. // slot - if this is the case do not include the widget at all.
var insertWidget = true; var insertWidget = true;
var checkWidget = function (_widget) { var checkWidget = function(_widget)
if (_widget.parent != null) {
if(_widget.parent != null)
{ {
for (var i = 0; i < remaining.length; i++) for(var i = 0; i < remaining.length; i++)
{ {
if (remaining[i].widget == _widget.parent) if(remaining[i].widget == _widget.parent)
{ {
insertWidget = false; insertWidget = false;
return; return;
@ -370,29 +408,32 @@ export class et2_nextmatch_rowProvider
checkWidget(widget); checkWidget(widget);
// Handle the next widget if this one should not be included. // Handle the next widget if this one should not be included.
if (!insertWidget) if(!insertWidget)
{ {
continue; continue;
} }
// Check whether the widget implements the et2_IDetachedDOM interface // Check whether the widget implements the et2_IDetachedDOM interface
var isDetachable = false; var isDetachable = false;
if (widget.implements(et2_IDetachedDOM)) if(widget.implements && widget.implements(et2_IDetachedDOM))
{ {
// Get all attributes the widgets supports to be set in the // Get all attributes the widgets supports to be set in the
// "detached" mode // "detached" mode
var supportedAttrs = []; var supportedAttrs = [];
widget.getDetachedAttributes(supportedAttrs); if(widget.getDetachedAttributes)
{
widget.getDetachedAttributes(supportedAttrs);
}
supportedAttrs.push("id"); supportedAttrs.push("id");
isDetachable = true; isDetachable = true;
for (var j = 0; j < _varAttrs[i].data.length/* && isDetachable*/; j++) for(var j = 0; j < _varAttrs[i].data.length/* && isDetachable*/; j++)
{ {
var data = _varAttrs[i].data[j]; var data = _varAttrs[i].data[j];
var supportsAttr = supportedAttrs.indexOf(data.attribute) != -1; var supportsAttr = supportedAttrs.indexOf(data.attribute) != -1;
if (!supportsAttr) if(!supportsAttr)
{ {
egw.debug("warn", "et2_IDetachedDOM widget " + egw.debug("warn", "et2_IDetachedDOM widget " +
widget._type + " does not support " + data.attribute); widget._type + " does not support " + data.attribute);
@ -403,7 +444,7 @@ export class et2_nextmatch_rowProvider
} }
// Insert the widget into the correct slot // Insert the widget into the correct slot
if (isDetachable) if(isDetachable)
{ {
detachable.push(_varAttrs[i]); detachable.push(_varAttrs[i]);
} }
@ -424,28 +465,28 @@ export class et2_nextmatch_rowProvider
* *
* @param {object} _rowTemplate * @param {object} _rowTemplate
*/ */
_stripTemplateRow( _rowTemplate) _stripTemplateRow(_rowTemplate)
{ {
_rowTemplate.placeholders = []; _rowTemplate.placeholders = [];
for (var i = 0; i < _rowTemplate.seperated.remaining.length; i++) for(var i = 0; i < _rowTemplate.seperated.remaining.length; i++)
{ {
var entry = _rowTemplate.seperated.remaining[i]; var entry = _rowTemplate.seperated.remaining[i];
// Issue a warning - widgets which do not implement et2_IDOMNode // Issue a warning - widgets which do not implement et2_IDOMNode
// are very slow // are very slow
egw.debug("warn", "Non-clonable widget '"+ entry.widget._type + "' in dataview row - this " + egw.debug("warn", "Non-clonable widget '" + entry.widget._type + "' in dataview row - this " +
"might be slow", entry); "might be slow", entry);
// Set the placeholder for the entry to null // Set the placeholder for the entry to null
entry.placeholder = null; entry.placeholder = null;
// Get the outer DOM-Node of the widget // Get the outer DOM-Node of the widget
if (entry.widget.implements(et2_IDOMNode)) if(entry.widget.implements(et2_IDOMNode))
{ {
var node = entry.widget.getDOMNode(entry.widget); var node = entry.widget.getDOMNode(entry.widget);
if (node && node.parentNode) if(node && node.parentNode)
{ {
// Get the parent node and replace the node with a placeholder // Get the parent node and replace the node with a placeholder
entry.placeholder = document.createElement("span"); entry.placeholder = document.createElement("span");
@ -460,15 +501,15 @@ export class et2_nextmatch_rowProvider
} }
} }
_nodeIndex( _node) _nodeIndex(_node)
{ {
if(_node.parentNode == null) if(_node.parentNode == null)
{ {
return 0; return 0;
} }
for (var i = 0; i < _node.parentNode.childNodes.length; i++) for(var i = 0; i < _node.parentNode.childNodes.length; i++)
{ {
if (_node.parentNode.childNodes[i] == _node) if(_node.parentNode.childNodes[i] == _node)
{ {
return i; return i;
} }
@ -483,20 +524,20 @@ export class et2_nextmatch_rowProvider
* @param {DOMElement} _root * @param {DOMElement} _root
* @param {DOMElement} _target * @param {DOMElement} _target
*/ */
_compileDOMAccessFunc( _root, _target) _compileDOMAccessFunc(_root, _target)
{ {
function recordPath(_root, _target, _path) function recordPath(_root, _target, _path)
{ {
if (typeof _path == "undefined") if(typeof _path == "undefined")
{ {
_path = []; _path = [];
} }
if (_root != _target && _target) if(_root != _target && _target)
{ {
// Get the index of _target in its parent node // Get the index of _target in its parent node
var idx = this._nodeIndex(_target); var idx = this._nodeIndex(_target);
if (idx >= 0) if(idx >= 0)
{ {
// Add the access selector // Add the access selector
_path.unshift("childNodes[" + idx + "]"); _path.unshift("childNodes[" + idx + "]");
@ -522,18 +563,18 @@ export class et2_nextmatch_rowProvider
* *
* @param {object} _rowTemplate * @param {object} _rowTemplate
*/ */
_buildNodeAccessFuncs( _rowTemplate) _buildNodeAccessFuncs(_rowTemplate)
{ {
for (var i = 0; i < _rowTemplate.seperated.detachable.length; i++) for(var i = 0; i < _rowTemplate.seperated.detachable.length; i++)
{ {
var entry = _rowTemplate.seperated.detachable[i]; var entry = _rowTemplate.seperated.detachable[i];
// Get all needed nodes from the widget // Get all needed nodes from the widget
var nodes = entry.widget.getDetachedNodes(); var nodes = window.customElements.get(entry.widget.localName) ? [entry.widget] : entry.widget.getDetachedNodes();
var nodeFuncs = entry.nodeFuncs = new Array(nodes.length); var nodeFuncs = entry.nodeFuncs = new Array(nodes.length);
// Record the path to each DOM-Node // Record the path to each DOM-Node
for (var j = 0; j < nodes.length; j++) for(var j = 0; j < nodes.length; j++)
{ {
nodeFuncs[j] = this._compileDOMAccessFunc(_rowTemplate.row, nodeFuncs[j] = this._compileDOMAccessFunc(_rowTemplate.row,
nodes[j]); nodes[j]);
@ -548,11 +589,11 @@ export class et2_nextmatch_rowProvider
* *
* We can NOT use something like /(^| |,|cat_)([0-9]+)( |,|$)/g as it wont find all cats in "123,456,789 "! * We can NOT use something like /(^| |,|cat_)([0-9]+)( |,|$)/g as it wont find all cats in "123,456,789 "!
*/ */
cat_regexp: RegExp = /(^| |,|cat_)([0-9]+)/g; cat_regexp : RegExp = /(^| |,|cat_)([0-9]+)/g;
/** /**
* Regular expression used to filter out non-nummerical chars from above matches * Regular expression used to filter out non-nummerical chars from above matches
*/ */
cat_cleanup: RegExp = /[^0-9]/g; cat_cleanup : RegExp = /[^0-9]/g;
/** /**
* Applies additional row data (like the class) to the tr * Applies additional row data (like the class) to the tr
@ -561,10 +602,10 @@ export class et2_nextmatch_rowProvider
* @param {DOMElement} _tr * @param {DOMElement} _tr
* @param {object} _mgrs * @param {object} _mgrs
*/ */
_setRowData( _data, _tr, _mgrs) _setRowData(_data, _tr, _mgrs)
{ {
// TODO: Implement other fields than "class" // TODO: Implement other fields than "class"
if (_data["class"]) if(_data["class"])
{ {
var classes = _mgrs["content"].expandName(_data["class"]); var classes = _mgrs["content"].expandName(_data["class"]);
@ -575,7 +616,10 @@ export class et2_nextmatch_rowProvider
{ {
// Accept either cat, cat_id or category as ID, and look there for category settings // Accept either cat, cat_id or category as ID, and look there for category settings
var category_location = _data["class"].match(/(cat(_id|egory)?)/); var category_location = _data["class"].match(/(cat(_id|egory)?)/);
if(category_location) category_location = category_location[0]; if(category_location)
{
category_location = category_location[0];
}
cats = classes.match(this.cat_regexp) || []; cats = classes.match(this.cat_regexp) || [];
classes = classes.replace(this.cat_regexp, ''); classes = classes.replace(this.cat_regexp, '');
@ -585,9 +629,9 @@ export class et2_nextmatch_rowProvider
{ {
// Need cat_, classes can't start with a number // Need cat_, classes can't start with a number
var cat_id = cats[i].replace(this.cat_cleanup, ''); var cat_id = cats[i].replace(this.cat_cleanup, '');
var cat_class = 'cat_'+cat_id; var cat_class = 'cat_' + cat_id;
classes += ' '+cat_class; classes += ' ' + cat_class;
} }
classes += " row_category"; classes += " row_category";
} }
@ -607,8 +651,9 @@ export class et2_nextmatch_rowProvider
*/ */
export class et2_nextmatch_rowWidget extends et2_widget implements et2_IDOMNode export class et2_nextmatch_rowWidget extends et2_widget implements et2_IDOMNode
{ {
private _widgets: any[]; private _widgets : any[];
private _row: any; private _row : any;
/** /**
* Constructor * Constructor
* *
@ -616,7 +661,7 @@ export class et2_nextmatch_rowWidget extends et2_widget implements et2_IDOMNode
* @param _row * @param _row
* @memberOf et2_nextmatch_rowWidget * @memberOf et2_nextmatch_rowWidget
*/ */
constructor( _mgrs, _row) constructor(_mgrs, _row)
{ {
// Call the parent constructor with some dummy attributes // Call the parent constructor with some dummy attributes
super(null, {"id": "", "type": "rowWidget"}); super(null, {"id": "", "type": "rowWidget"});
@ -635,15 +680,18 @@ export class et2_nextmatch_rowWidget extends et2_widget implements et2_IDOMNode
* *
* @param {array} _widgets * @param {array} _widgets
*/ */
createWidgets( _widgets) createWidgets(_widgets)
{ {
// Clone the given the widgets with this element as parent // Clone the given the widgets with this element as parent
this._widgets = []; this._widgets = [];
let row_id = 0; let row_id = 0;
for (var i = 0; i < _widgets.length; i++) for(var i = 0; i < _widgets.length; i++)
{ {
// Disabled columns might be missing widget - skip it // Disabled columns might be missing widget - skip it
if(!_widgets[i]) continue; if(!_widgets[i])
{
continue;
}
this._widgets[i] = _widgets[i].clone(this); this._widgets[i] = _widgets[i].clone(this);
this._widgets[i].loadingFinished(); this._widgets[i].loadingFinished();
@ -662,13 +710,16 @@ export class et2_nextmatch_rowWidget extends et2_widget implements et2_IDOMNode
* @param {et2_widget} _sender * @param {et2_widget} _sender
* @return {DOMElement} * @return {DOMElement}
*/ */
getDOMNode( _sender) getDOMNode(_sender)
{ {
var row_id = 0; var row_id = 0;
for (var i = 0; i < this._widgets.length; i++) for(var i = 0; i < this._widgets.length; i++)
{ {
// Disabled columns might be missing widget - skip it // Disabled columns might be missing widget - skip it
if(!this._widgets[i]) continue; if(!this._widgets[i])
{
continue;
}
if(this._widgets[i] == _sender && this._row.childNodes[row_id]) if(this._widgets[i] == _sender && this._row.childNodes[row_id])
{ {
return this._row.childNodes[row_id].childNodes[0]; // Return the i-th td tag return this._row.childNodes[row_id].childNodes[0]; // Return the i-th td tag
@ -686,9 +737,10 @@ export class et2_nextmatch_rowWidget extends et2_widget implements et2_IDOMNode
*/ */
export class et2_nextmatch_rowTemplateWidget extends et2_widget implements et2_IDOMNode export class et2_nextmatch_rowTemplateWidget extends et2_widget implements et2_IDOMNode
{ {
private _root: any; private _root : any;
private _row: any; private _row : any;
private _widgets: any[]; private _widgets : any[];
/** /**
* Constructor * Constructor
* *
@ -696,7 +748,7 @@ export class et2_nextmatch_rowTemplateWidget extends et2_widget implements et2_I
* @param _row * @param _row
* @memberOf et2_nextmatch_rowTemplateWidget * @memberOf et2_nextmatch_rowTemplateWidget
*/ */
constructor( _root, _row) constructor(_root, _row)
{ {
// Call the parent constructor with some dummy attributes // Call the parent constructor with some dummy attributes
super(null, {"id": "", "type": "rowTemplateWidget"}); super(null, {"id": "", "type": "rowTemplateWidget"});
@ -712,14 +764,14 @@ export class et2_nextmatch_rowTemplateWidget extends et2_widget implements et2_I
this._widgets = []; this._widgets = [];
} }
createWidgets( _mgrs, _widgets : {widget : et2_widget,func(_row: any): any; }[]) createWidgets(_mgrs, _widgets : { widget : et2_widget, func(_row : any) : any; }[])
{ {
// Set the array managers - don't use setArrayMgrs here as this creates // Set the array managers - don't use setArrayMgrs here as this creates
// an unnecessary copy of the object // an unnecessary copy of the object
this._mgrs = _mgrs; this._mgrs = _mgrs;
this._widgets = new Array(_widgets.length); this._widgets = new Array(_widgets.length);
for (var i = 0; i < _widgets.length; i++) for(var i = 0; i < _widgets.length; i++)
{ {
this._row.childNodes[0].childNodes[0]; this._row.childNodes[0].childNodes[0];
@ -737,12 +789,12 @@ export class et2_nextmatch_rowTemplateWidget extends et2_widget implements et2_I
* @param {et2_widget} _sender * @param {et2_widget} _sender
* @return {DOMElement} * @return {DOMElement}
*/ */
getDOMNode( _sender: et2_widget): HTMLElement getDOMNode(_sender : et2_widget) : HTMLElement
{ {
for (var i = 0; i < this._widgets.length; i++) for(var i = 0; i < this._widgets.length; i++)
{ {
if (this._widgets[i].widget == _sender) if(this._widgets[i].widget == _sender)
{ {
return this._widgets[i].node; return this._widgets[i].node;
} }

File diff suppressed because it is too large Load Diff