diff --git a/api/js/etemplate/Et2Checkbox/Et2Checkbox.ts b/api/js/etemplate/Et2Checkbox/Et2Checkbox.ts index 5bb2c2be69..a93cc947fd 100644 --- a/api/js/etemplate/Et2Checkbox/Et2Checkbox.ts +++ b/api/js/etemplate/Et2Checkbox/Et2Checkbox.ts @@ -17,6 +17,11 @@ import shoelace from "../Styles/shoelace"; export class Et2Checkbox extends Et2InputWidget(SlCheckbox) { + /** + * Value to set checkbox in (third) indeterminate state + */ + static readonly INDETERMINATE = '***undefined***'; + static get styles() { return [ @@ -53,6 +58,9 @@ export class Et2Checkbox extends Et2InputWidget(SlCheckbox) constructor() { super(); + + this.selectedValue = 'true'; + this.unselectedValue = ''; } connectedCallback() @@ -81,40 +89,40 @@ export class Et2Checkbox extends Et2InputWidget(SlCheckbox) } } - get value() + get value() : string | boolean { - if(this.checked && this.selectedValue) - { - return this.selectedValue; - } - if(!this.checked && this.unselectedValue) - { - return this.unselectedValue; - } - return this.checked + ""; + return this.indeterminate ? undefined : + (this.checked ? this.selectedValue : this.unselectedValue); } set value(new_value : string | boolean) { this.requestUpdate("checked"); this.indeterminate = false; - if(typeof new_value === "boolean" || !this.selectedValue) + + if(typeof new_value === "boolean") { - this.checked = new_value; - return; + this.checked = new_value; } - if(this.selectedValue && new_value == this.selectedValue) + else if(new_value == this.selectedValue) { this.checked = true; } - else if(this.unselectedValue && new_value == this.unselectedValue) + else if(new_value == this.unselectedValue) { this.checked = false; } - else + // concept of an indeterminate value did not exist in eT2 and set value gets called with all kind of truthy of falsy values + // therefore we can NOT set everything not matching our (un)selectedValue to indeterminate! + // For now, we only do that for an explicit Et2Checkbox.INDETERMINATE value + else if (new_value === Et2Checkbox.INDETERMINATE) { this.indeterminate = true; } + else + { + this.checked = !!new_value; + } } private get _labelNode() diff --git a/api/js/etemplate/Et2Widget/Et2Widget.ts b/api/js/etemplate/Et2Widget/Et2Widget.ts index 4f0ad216f1..d1c5c624a5 100644 --- a/api/js/etemplate/Et2Widget/Et2Widget.ts +++ b/api/js/etemplate/Et2Widget/Et2Widget.ts @@ -799,7 +799,9 @@ const Et2WidgetMixin = (superClass : T) => iterateOver(_callback : Function, _context, _type) { - if(typeof _type == "undefined" || _type == et2_widget || et2_implements_registry[_type] && et2_implements_registry[_type](this)) + if (typeof _type === "undefined" || _type === et2_widget || _type === Et2Widget || + typeof _type === 'function' && this instanceof _type || + et2_implements_registry[_type] && et2_implements_registry[_type](this)) { _callback.call(_context, this); } diff --git a/api/js/etemplate/et2_core_inheritance.ts b/api/js/etemplate/et2_core_inheritance.ts index cf1a3c50ae..d0e785feeb 100644 --- a/api/js/etemplate/et2_core_inheritance.ts +++ b/api/js/etemplate/et2_core_inheritance.ts @@ -15,6 +15,7 @@ import {egw, IegwAppLocal} from "../jsapi/egw_global"; import {et2_checkType, et2_no_init, et2_validateAttrib} from "./et2_core_common"; import {et2_implements_registry} from "./et2_core_interfaces"; +import {Et2Widget} from "./Et2Widget/Et2Widget"; export class ClassWithInterfaces { @@ -49,6 +50,10 @@ export class ClassWithInterfaces { return this.implements(_class_or_interfacename); } + if (_class_or_interfacename === Et2Widget) + { + return true; + } return this instanceof _class_or_interfacename; } } @@ -273,5 +278,4 @@ export class ClassWithAttributes extends ClassWithInterfaces return attributes; } -} - +} \ No newline at end of file diff --git a/api/js/etemplate/et2_widget_checkbox.ts b/api/js/etemplate/et2_widget_checkbox.ts index 14f338e916..6388dd6f35 100644 --- a/api/js/etemplate/et2_widget_checkbox.ts +++ b/api/js/etemplate/et2_widget_checkbox.ts @@ -9,286 +9,9 @@ * @copyright Nathan Gray 2011 */ -/*egw:uses - /vendor/bower-asset/jquery/dist/jquery.js; - et2_core_inputWidget; - et2_core_valueWidget; -*/ - -import {et2_register_widget, WidgetConfig} from "./et2_core_widget"; -import {et2_inputWidget} from "./et2_core_inputWidget"; -import {ClassWithAttributes} from "./et2_core_inheritance"; -import {et2_IDetachedDOM} from "./et2_core_interfaces"; +import {Et2Checkbox} from "./Et2Checkbox/Et2Checkbox"; /** - * Class which implements the "checkbox" XET-Tag - * - * @augments et2_inputWidget + * @deprecated use Et2Checkbox */ -export class et2_checkbox extends et2_inputWidget -{ - static readonly _attributes : any = { - "selected_value": { - "name": "Set value", - "type": "string", - "default": "true", - "description": "Value when checked" - }, - "unselected_value": { - "name": "Unset value", - "type": "string", - "default": "", - "description": "Value when not checked" - }, - "ro_true": { - "name": "Read only selected", - "type": "string", - "default": "X ", - "description": "What should be displayed when readonly and selected" - }, - "ro_false": { - "name": "Read only unselected", - "type": "string", - "default": "", - "description": "What should be displayed when readonly and not selected" - }, - "value": { - // Stop framework from messing with value - "type": "any" - }, - "toggle_on": { - "name": "Toggle on caption", - "type": "string", - "default": "", - "description": "String caption to show for ON status", - "translate": true - }, - "toggle_off": { - "name": "Toggle off caption", - "type": "string", - "default": "", - "description": "String caption to show OFF status", - "translate": true - } - }; - - public static readonly legacyOptions : string[] = ["selected_value", "unselected_value", "ro_true", "ro_false"]; - input : JQuery = null; - toggle : JQuery = null; - value : string | boolean; - - /** - * Constructor - * - * @memberOf et2_checkbox - */ - constructor(_parent, _attrs? : WidgetConfig, _child? : object) - { - // Call the inherited constructor - super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_checkbox._attributes, _child || {})); - this.input = null; - this.createInputWidget(); - } - - createInputWidget() - { - this.input = jQuery(document.createElement("input")).attr("type", "checkbox"); - - this.input.addClass("et2_checkbox"); - - if (this.options.toggle_on || this.options.toggle_off) - { - let self = this; - // checkbox container - this.toggle = jQuery(document.createElement('span')) - .addClass('et2_checkbox_slideSwitch') - .append(this.input); - // update switch status on change - this.input.change(function(){ - self.getValue(); - return true; - }); - // switch container - let area = jQuery(document.createElement('span')).addClass('slideSwitch_container').appendTo(this.toggle); - // on span tag - let on = jQuery(document.createElement('span')).addClass('on').appendTo(area); - // off span tag - let off = jQuery(document.createElement('span')).addClass('off').appendTo(area); - on.text(this.options.toggle_on); - off.text(this.options.toggle_off); - - // handle a tag - jQuery(document.createElement('a')).appendTo(area); - this.setDOMNode(this.toggle[0]); - } - else - { - this.setDOMNode(this.input[0]); - } - } - - /** - * Override default to place checkbox before label, if there is no %s in the label - * - * @param {string} label - */ - set_label(label) { - if(label.length && label.indexOf('%s') < 0) - { - label = '%s'+label; - } - super.set_label(label); - jQuery(this.getSurroundings().getWidgetSurroundings()).addClass('et2_checkbox_label'); - } - - /** - * Override default to match against set/unset value - * - * @param {string|boolean} _value - */ - set_value(_value : string | boolean) - { - // in php, our database storage and et2_checkType(): "0" == false - if (_value === "0" && this.options.selected_value != "0") - { - _value = false; - } - if(_value != this.value) { - if(_value == this.options.selected_value || - _value && this.options.selected_value == this.attributes["selected_value"]["default"] && - _value != this.options.unselected_value) { - if (this.options.toggle_on || this.options.toggle_off) this.toggle.addClass('switchOn'); - this.input.prop("checked", true); - } else { - this.input.prop("checked", false); - if (this.options.toggle_on || this.options.toggle_off) this.toggle.removeClass('switchOn'); - } - } - } - - /** - * Disable checkbox on runtime - * - * @param {boolean} _ro - */ - set_readonly(_ro) - { - jQuery(this.getDOMNode()).attr('disabled', _ro); - this.input.prop('disabled', _ro); - } - - /** - * Override default to return unchecked value - */ - getValue() - { - if(this.input.prop("checked")) { - if (this.options.toggle_on || this.options.toggle_off) this.toggle.addClass('switchOn'); - return this.options.selected_value; - } else { - if (this.options.toggle_on || this.options.toggle_off) this.toggle.removeClass('switchOn'); - return this.options.unselected_value; - } - } - - set_disabled(_value) - { - let parentNode = jQuery(this.getDOMNode()).parent(); - if (parentNode[0] && parentNode[0].nodeName == "label" && parentNode.hasClass('.et2_checkbox_label')) - { - if (_value) - { - parentNode.hide(); - } - else - { - parentNode.show(); - } - } - super.set_disabled(_value); - } -} -et2_register_widget(et2_checkbox, ["checkbox"]); - -/** -* et2_checkbox_ro is the dummy readonly implementation of the checkbox -* @augments et2_checkbox -*/ -export class et2_checkbox_ro extends et2_checkbox implements et2_IDetachedDOM -{ - /** - * Ignore unset value - */ - static readonly _attributes : any = { - "unselected_value": { - "ignore": true - } - }; - - span : JQuery = null; - - /** - * Constructor - * - * @memberOf et2_checkbox_ro - */ - constructor(_parent, _attrs? : WidgetConfig, _child? : object) - { - // Call the inherited constructor - super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_checkbox_ro._attributes, _child || {})); - - this.value = ""; - this.span = jQuery(document.createElement("span")) - .addClass("et2_checkbox_ro"); - - this.setDOMNode(this.span[0]); - } - - /** - * note: checkbox is checked if even there is a value but not only if the _value is only "true" - * it's an exceptional validation for cases that we pass non boolean values as checkbox _value - * - * @param {string|boolean} _value - */ - set_value(_value) - { - if(_value == this.options.selected_value ||_value && this.options.selected_value == this.attributes["selected_value"]["default"] && - _value != this.options.unselected_value) { - this.span.text(this.options.ro_true); - this.value = _value; - } else { - this.span.text(this.options.ro_false); - } - } - - /** - * Code for implementing et2_IDetachedDOM - * - * @param {array} _attrs - */ - getDetachedAttributes(_attrs) - { - _attrs.push("value", "class"); - } - - getDetachedNodes() - { - return [this.span[0]]; - } - - setDetachedAttributes(_nodes, _values) - { - // Update the properties - if (typeof _values["value"] != "undefined") - { - this.span = jQuery(_nodes[0]); - this.set_value(_values["value"]); - } - - if (typeof _values["class"] != "undefined") - { - _nodes[0].setAttribute("class", _values["class"]); - } - } -} -et2_register_widget(et2_checkbox_ro, ["checkbox_ro"]); \ No newline at end of file +export class et2_checkbox extends Et2Checkbox {} \ No newline at end of file diff --git a/api/js/etemplate/et2_widget_toolbar.ts b/api/js/etemplate/et2_widget_toolbar.ts index c7ac21b111..5da455f398 100644 --- a/api/js/etemplate/et2_widget_toolbar.ts +++ b/api/js/etemplate/et2_widget_toolbar.ts @@ -15,10 +15,9 @@ */ import {et2_DOMWidget} from "./et2_core_DOMWidget"; -import {et2_createWidget, et2_register_widget, WidgetConfig} from "./et2_core_widget"; +import {et2_register_widget, WidgetConfig} from "./et2_core_widget"; import {ClassWithAttributes} from "./et2_core_inheritance"; import {egw_getObjectManager, egwActionObject, egwActionObjectManager} from '../egw_action/egw_action.js'; -import {et2_checkbox} from "./et2_widget_checkbox"; import {et2_IInput} from "./et2_core_interfaces"; import {egw} from "../jsapi/egw_global"; import {egwIsMobile} from "../egw_action/egw_action_common.js"; @@ -26,7 +25,6 @@ import {Et2Dialog} from "./Et2Dialog/Et2Dialog"; import {Et2DropdownButton} from "./Et2DropdownButton/Et2DropdownButton"; import {loadWebComponent} from "./Et2Widget/Et2Widget"; import interact from "@interactjs/interactjs"; -import Sortable from "sortablejs/modular/sortable.complete.esm.js"; import {Et2Button} from "./Et2Button/Et2Button"; import {Et2Checkbox} from "./Et2Checkbox/Et2Checkbox"; diff --git a/api/js/etemplate/etemplate2.ts b/api/js/etemplate/etemplate2.ts index 22eb5233d5..4eebbcec0b 100644 --- a/api/js/etemplate/etemplate2.ts +++ b/api/js/etemplate/etemplate2.ts @@ -110,7 +110,6 @@ import './et2_widget_textbox'; import './et2_widget_number'; import './et2_widget_url'; import './et2_widget_selectbox'; -import './et2_widget_checkbox'; import './et2_widget_radiobox'; import './et2_widget_date'; import './et2_widget_dialog'; diff --git a/api/js/etemplate/vfsSelectUI.ts b/api/js/etemplate/vfsSelectUI.ts index 64df53430a..30d9bf2d68 100644 --- a/api/js/etemplate/vfsSelectUI.ts +++ b/api/js/etemplate/vfsSelectUI.ts @@ -16,11 +16,10 @@ import {EgwApp} from "../jsapi/egw_app"; import {et2_vfs, et2_vfsPath, et2_vfsSelect} from "./et2_widget_vfs"; import {egw} from "../jsapi/egw_global"; import {et2_file} from "./et2_widget_file"; -import {Et2Textbox} from "./Et2Textbox/Et2Textbox"; import {Et2Button} from "./Et2Button/Et2Button"; import {Et2Select} from "./Et2Select/Et2Select"; -import {et2_checkbox} from "./et2_widget_checkbox"; import {Et2Dialog} from "./Et2Dialog/Et2Dialog"; +import {Et2Checkbox} from "./Et2Checkbox/Et2Checkbox"; /** @@ -266,11 +265,11 @@ export class vfsSelectUI extends EgwApp let file = widget.value.name; widget.getParent().iterateOver(function(widget) { - if(widget.options.selected_value == file) + if(widget.options.selectedValue === file) { - widget.set_value(widget.get_value() == file ? widget.options.unselected_value : file); + widget.set_value(widget.get_value() === file ? widget.options.unselectedValue : file); } - }, null, et2_checkbox); + }, null, Et2Checkbox); } // Stop event or it will toggle back off