/* * Egroupware etemplate2 JS Entry widget * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package etemplate * @subpackage api * @link https://www.egroupware.org * @author Nathan Gray */ /*egw:uses et2_core_valueWidget; */ import {et2_createWidget, et2_register_widget, WidgetConfig} from "./et2_core_widget"; import {et2_valueWidget} from "./et2_core_valueWidget"; import {ClassWithAttributes} from "./et2_core_inheritance"; import {et2_cloneObject, et2_no_init} from "./et2_core_common"; /** * A widget to display a value from an entry * * Since we have Etemplate\Widget\Transformer, this client side widget exists * mostly to resolve the problem where the ID for the entry widget is the same * as the widget where you actually set the value, which prevents transformer * from working. * * Server side will find the associated entry, and load it into ~ to * avoid overwriting the widget with id="entry_id". This widget will reverse * that, and the modifications from transformer will be applied. * * @augments et2_valueWidget */ export class et2_entry extends et2_valueWidget { static readonly _attributes : any = { field: { 'name': 'Fields', 'description': 'Which entry field to display, or "sum" to add up the alternate_fields', 'type': 'string' }, compare: { name: 'Compare', description: 'if given, the selected field is compared with its value and an X is printed on equality, nothing otherwise', default: et2_no_init, type: 'string' }, alternate_fields: { name: 'Alternate fields', description: 'colon (:) separated list of alternative fields. The first non-empty one is used if the selected field is empty, (-) used for subtraction', type: 'string', default: et2_no_init }, precision: { name: 'Decimals to be shown', description: 'Specifies the number of decimals for sum of alternates, the default is 2', type: 'string', default: '2' }, regex: { name: 'Regular expression pattern', description: 'Only used server-side in a preg_replace with regex_replace to modify the value', default: et2_no_init, type: 'string' }, regex_replace: { name: 'Regular expression replacement pattern', description: 'Only used server-side in a preg_replace with regex to modify the value', default: et2_no_init, type: 'string' }, value: { type: 'any' }, readonly: { default: true } }; public static readonly legacyOptions : string[] = ["field","compare","alternate_fields"]; public static readonly prefix = '~'; protected widget = null; constructor(_parent, _attrs? : WidgetConfig, _child? : object) { // Call the inherited constructor super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_entry._attributes, _child || {})); // Often the ID conflicts, so check prefix if(_attrs.id && _attrs.id.indexOf(et2_entry.prefix) < 0) { this.id = _attrs.id = et2_entry.prefix + _attrs.id; } let value = _attrs.value; // Add all attributes hidden in the content arrays to the attributes // parameter this.transformAttributes(_attrs); // Create a local copy of the options object this.options = et2_cloneObject(_attrs); // Save value from parsing, but only if set if(value) { this.options.value = value; } this.widget = null; this.setDOMNode(document.createElement('span')); } loadFromXML(_node) { // Load the nodes as usual super.loadFromXML(_node); // Do the magic this.loadField(); } /** * Initialize widget for entry field */ loadField() { // Create widget of correct type let attrs = { id: this.id + (this.options.field ? '[' +this.options.field+']' : ''), type: 'label', readonly: this.options.readonly }; let modifications = this.getArrayMgr("modifications"); if(modifications && this.options.field) { jQuery.extend(attrs, modifications.getEntry(attrs.id)); } // Supress labels on templates if(attrs.type == 'template' && this.options.label) { this.egw().debug('log', "Surpressed label on <" + this.getType() + ' label="' + this.options.label + '" id="' + this.id + '"...>'); this.options.label = ''; } let widget = et2_createWidget(attrs.type, attrs, this); // If value is not set, etemplate takes care of everything // If value was set, find the record explicitly. if(typeof this.options.value == 'string') { widget.value = this.getArrayMgr('content').getEntry(this.id + '[' + this.options.field + ']') || this.getRoot().getArrayMgr('content').getEntry(et2_entry.prefix + this.options.value + '[' + this.options.field + ']'); } else if (this.options.field && this.options.value && this.options.value[this.options.field]) { widget.value = this.options.value[this.options.field]; } if(this.options.compare) { widget.value = widget.options.value == this.options.compare ? 'X' : ''; } if(this.options.alternate_fields) { let sum : number | string = 0; let fields = this.options.alternate_fields.split(':'); for(let i = 0; i < fields.length; i++) { let negate = (fields[i][0] == "-"); let value = this.getArrayMgr('content').getEntry(fields[i].replace('-','')); sum += typeof value === 'undefined' ? 0 : (parseFloat(value) * (negate ? -1 : 1)); if(value && this.options.field !== 'sum') { widget.value = value; break; } } if(this.options.field == 'sum') { if(this.options.precision && !isNaN(sum)) { sum = parseFloat(sum).toFixed(this.options.precision); } // use decimal separator from user prefs const format = this.egw().preference('number_format'); const sep = format ? format[0] : '.'; if(typeof sum === 'string' && format && sep && sep !== '.') { sum = sum.replace('.', sep); } widget.value = sum; } } } } et2_register_widget(et2_entry, ["entry", 'contact-value', 'contact-account', 'contact-template', 'infolog-value','tracker-value','records-value']);