From 42febf96d1fe0c4462fce040f9ac8745eeb80203 Mon Sep 17 00:00:00 2001 From: ralf Date: Mon, 8 Apr 2024 14:29:59 +0200 Subject: [PATCH] remove Et2SelectEmail replaced by Et2Email incl. using preprocessor to replace all usages --- api/etemplate.php | 3 + .../Et2Select/Select/Et2SelectEmail.ts | 396 ------------------ api/js/etemplate/et2_widget_taglist.ts | 6 +- 3 files changed, 6 insertions(+), 399 deletions(-) delete mode 100644 api/js/etemplate/Et2Select/Select/Et2SelectEmail.ts diff --git a/api/etemplate.php b/api/etemplate.php index b7e204c804..4afb641cb0 100644 --- a/api/etemplate.php +++ b/api/etemplate.php @@ -351,6 +351,9 @@ function send_template() return ''.$matches[5].''; }, $str); + // use et2-email instead of et2-select-email + $str = preg_replace('##s', '', $str); + // nextmatch headers $str = preg_replace_callback('#<(nextmatch-)([^ ]+)(header|filter) ([^>]+?)/>#s', static function (array $matches) { diff --git a/api/js/etemplate/Et2Select/Select/Et2SelectEmail.ts b/api/js/etemplate/Et2Select/Select/Et2SelectEmail.ts deleted file mode 100644 index 83b49094f9..0000000000 --- a/api/js/etemplate/Et2Select/Select/Et2SelectEmail.ts +++ /dev/null @@ -1,396 +0,0 @@ -/** - * EGroupware eTemplate2 - Email-selection WebComponent - * - * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License - * @package api - * @link https://www.egroupware.org - * @author Nathan Gray - */ - -import {Et2Select} from "../Et2Select"; -import {css, html, nothing, PropertyValues} from "lit"; -import {IsEmail} from "../../Validators/IsEmail"; -import interact from "@interactjs/interact"; -import {Validator} from "@lion/form-core"; -import {classMap} from "lit/directives/class-map.js"; -import {state} from "lit/decorators/state.js"; - -/** - * Select email address(es) - * - * Allows free entries of valid email addresses, but also searches contacts. - * - * You should set multiple="true" for most cases for better UI - * @see Et2SelectEmail - */ -export class Et2SelectEmail extends Et2Select -{ - static get styles() - { - return [ - ...super.styles, - css` - :host { - display: block; - flex: 1 1 auto; - min-width: 200px; - } - ::slotted(sl-icon[slot="suffix"]) { - display: none; - } - - /* Hide selected options from the dropdown */ - ::slotted([checked]) - { - display: none; - } - - /*** Drag & Drop ***/ - - .et2-select-draggable { - touch-action: none; - } - - :host(.et2_dropZone)::part(combobox) { - background-color: transparent; - } - ` - ]; - } - - static get properties() - { - return { - ...super.properties, - - /** - * Allow drag and drop tags between two or more Et2SelectEmail widgets - */ - allowDragAndDrop: {type: Boolean}, - - /** - * Allow placeholders like {{email}}, beside real email-addresses - */ - allowPlaceholder: {type: Boolean}, - - /** - * Include mailing lists: returns them with their integer list_id - */ - includeLists: {type: Boolean}, - - /** - * What to display for the selected email addresses - * - * {@link Et2EmailTag#emailDisplay} - */ - emailDisplay: {type: String}, //"full" | "email" | "name" | "domain"; - } - } - - /* Drag and drop has issues with positioning when we automatically open. Don't open if the user clicks on a tag. */ - @state() _cancelOpen = false; - - constructor(...args : any[]) - { - super(...args); - - // Additional option for select email, per ticket #79694 - this._close_on_select = this.egw().preference("select_multiple_close") != "open"; - - this.search = true; - this.searchUrl = "EGroupware\\Api\\Etemplate\\Widget\\Taglist::ajax_email"; - this.allowFreeEntries = true; - this.allowPlaceholder = false; - this.editModeEnabled = true; - this.allowDragAndDrop = false; - this.includeLists = false; - this.multiple = false; - this.fullEmail = false; - this.onlyEmail = false; - this.defaultValidators.push(new IsEmail(this.allowPlaceholder)); - - this.handleMouseDown = this.handleMouseDown.bind(this); - } - - - /** @param {import('@lion/core').PropertyValues } changedProperties */ - willUpdate(changedProperties : PropertyValues) - { - super.willUpdate(changedProperties); - - if(changedProperties.has('allowPlaceholder')) - { - this.defaultValidators = (>this.defaultValidators).filter(v => !(v instanceof IsEmail)); - this.defaultValidators.push(new IsEmail(this.allowPlaceholder)); - } - } - - firstUpdated() - { - this.select.addEventListener("mousedown", this.handleMouseDown); - } - - updated(changedProperties : Map) - { - super.updated(changedProperties); - - // Make tags draggable - this._cancelOpen = false; - if(!this.readonly && this.allowFreeEntries && this.allowDragAndDrop) - { - this._makeDraggable(); - } - } - - /** - * Make the tags draggable - * @protected - */ - protected _makeDraggable() - { - this.select.updateComplete.then(() => - { - let dragTranslate = {x: 0, y: 0}; - const tags = Array.from(this.select.shadowRoot.querySelectorAll(".select__tags et2-email-tag")); - let draggable = interact(".et2-select-draggable").draggable({ - startAxis: 'xy', - listeners: { - start: function(e) - { - this.hide(); - let dragPosition = {x: e.page.x, y: e.page.y}; - dragTranslate = {x: 0, y: 0}; - e.target.setAttribute('style', `width:${e.target.clientWidth}px !important`); - e.target.style.position = 'fixed'; - e.target.style.zIndex = 10; - e.target.style.transform = - `translate(${dragPosition.x}px, ${dragPosition.y}px)`; - }.bind(this), - move: function(e) - { - dragTranslate.x += e.delta.x; - dragTranslate.y += e.delta.y; - e.target.style.transform = - `translate(${dragTranslate.x}px, ${dragTranslate.y}px)`; - }, - end: function(e) - { - // Restore dragged tag to where it came from - e.target.removeAttribute("style"); - } - } - }); - // set parent_node with widget context in order to make it accessible after drop - draggable.parent_node = this; - }); - } - - protected _bindListeners() - { - super._bindListeners(); - if(!this.multiple) - { - return; - } - this.updateComplete.then(() => - { - interact(this).dropzone({ - accept: `.et2-select-draggable`, - ondrop: function(e) - { - // Restore dragged tag - e.relatedTarget.removeAttribute("style"); - - const source = e.relatedTarget.getRootNode().host // Containing sl-select - .getRootNode().host // Containing et2-select-email - // remove the dragged value from its origin source - source.value = source.value.filter(_item => {return e.relatedTarget.value !== _item;}) - - // Add in as free entry - e.target.createFreeEntry(e.relatedTarget.value); - e.target.classList.remove('et2_dropZone'); - }, - ondragenter: function(e) - { - this.hide(); - this.classList.add('et2_dropZone'); - }.bind(this), - ondragleave: function(e) - { - this.classList.remove('et2_dropZone'); - }.bind(this) - }); - }); - } - - protected handleMouseDown(e : MouseEvent) - { - if(this._cancelOpen) - { - e.stopImmediatePropagation(); - - // We need this hidden _now_ because of drag & drop, can't wait until update - this._activeControls.classList.remove("active"); - this.select.shadowRoot.querySelector("sl-popup").active = false; - } - } - /** - * Handle keypresses inside the search input - * Overridden from parent to also skip the hidden selected options, which other selects do not do - * - * @param {KeyboardEvent} event - * @protected - */ - protected _handleSearchKeyDown(event : KeyboardEvent) - { - // Pass off some keys to select - if(['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) - { - // Strip out hidden non-matching selected so key navigation works - this.menuItems = this.menuItems.filter(i => !i.checked); - } - return super._handleSearchKeyDown(event); - } - - /** - * Actually query the server. - * - * Overridden to change request to match server - * - * @param {string} search - * @param {object} options - * @returns {any} - * @protected - */ - protected remoteQuery(search : string, options : object) - { - return this.egw().request(this.searchUrl, [search, {includeLists: this.includeLists}]).then((results) => - { - // If results have a total included, pull it out. - // It will cause errors if left in the results - if(typeof results.total !== "undefined") - { - this._total_result_count += results.total; - delete results.total; - // Make it an array, since it was probably an object, and cleanSelectOptions() treats objects differently - results = Object.values(results); - } - else - { - this._total_result_count += results.length; - } - this._total_result_count -= this.processRemoteResults(results); - }); - } - - /** - * Use a custom tag for when multiple=true - * - * @returns {string} - */ - _tagTemplate(option, index) - { - const readonly = (this.readonly || option && typeof (option.disabled) != "undefined" && option.disabled); - const isEditable = this.editModeEnabled && !readonly; - - return html` - {this._cancelOpen = true;}} - .value=${option.value.replaceAll("___", " ")} - > - ${option.getTextLabel().trim()} - - `; - } - - /** - * Override icon for the select option to use lavatar, same as Et2SelectAccount - * - * @param option - * @protected - */ - protected _iconTemplate(option) - { - // lavatar uses a size property, not a CSS variable - let style = getComputedStyle(this); - - return html` - - `; - } - - /** - * Overwritten to NOT split RFC822 addresses containing a comma in quoted name part - * - * E.g. '"Becker, Ralf" ' - * - * @param val - */ - set_value(val : string | string[] | number | number[]) - { - if(typeof val === 'string' && val.indexOf(',') !== -1) - { - val = val.split(','); - for(let n=0; n < val.length-1; n++) - { - while (val[n].indexOf('@') === -1 && n < val.length-1) - { - val[n] += ',' + val[n+1]; - val.splice(n+1, 1); - } - } - } - super.set_value(val); - } - - - /** - * Sometimes users paste multiple comma separated values at once. Split them then handle normally. - * Overridden here to handle email addresses that may have commas using the regex from the validator. - * - * @param {ClipboardEvent} event - * @protected - */ - protected _handlePaste(event : ClipboardEvent) - { - event.preventDefault(); - - let paste = event.clipboardData.getData('text'); - if(!paste) - { - return; - } - const selection = window.getSelection(); - if(selection.rangeCount) - { - selection.deleteFromDocument(); - } - - let preg = this.allowPlaceholder ? IsEmail.EMAIL_PLACEHOLDER_PREG : IsEmail.EMAIL_PREG; - // Trim line start / end anchors off validation regex, make global - let regex = new RegExp(preg.toString().substring(2, preg.toString().length - 3), 'g'); - let values = paste.match(regex); - values.forEach(v => - { - this.createFreeEntry(v.trim()); - }); - this.dropdown.hide(); - } -} - -// @ts-ignore TypeScript is not recognizing that this widget is a LitElement -customElements.define("et2-select-email", Et2SelectEmail); \ No newline at end of file diff --git a/api/js/etemplate/et2_widget_taglist.ts b/api/js/etemplate/et2_widget_taglist.ts index 0f5511f93c..a72192e0d7 100644 --- a/api/js/etemplate/et2_widget_taglist.ts +++ b/api/js/etemplate/et2_widget_taglist.ts @@ -11,7 +11,7 @@ import type {Et2Select} from "./Et2Select/Et2Select"; import type {Et2SelectAccount} from "./Et2Select/Select/Et2SelectAccount"; -import type {Et2SelectEmail} from "./Et2Select/Select/Et2SelectEmail"; +import type {Et2Email} from "./Et2Email/Et2Email"; import type {Et2SelectCategory} from "./Et2Select/Select/Et2SelectCategory"; import type {Et2SelectThumbnail} from "./Et2Select/Select/Et2SelectThumbnail"; @@ -28,9 +28,9 @@ export type et2_taglist = Et2Select; export type et2_taglist_account = Et2SelectAccount; /** - * @deprecated use et2_SelectEmail + * @deprecated use ET2Email */ -export type et2_taglist_email = Et2SelectEmail; +export type et2_taglist_email = Et2Email; /** * @deprecated use Et2SelectCatgory