/* * Calendar owner widget * * @license https://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package calendar * @subpackage etemplate * @link https://www.egroupware.org * @author Nathan Gray */ import {Et2Select} from "../../api/js/etemplate/Et2Select/Et2Select"; import {css, html, nothing} from "@lion/core"; import {IsEmail} from "../../api/js/etemplate/Validators/IsEmail"; import {cleanSelectOptions} from "../../api/js/etemplate/Et2Select/FindSelectOptions"; import {Et2StaticSelectMixin} from "../../api/js/etemplate/Et2Select/StaticOptions"; /** * Select widget customised for calendar owner, which can be a user * account or group, or an entry from almost any app, or an email address * */ export class CalendarOwner extends Et2StaticSelectMixin(Et2Select) { static get styles() { return [ ...super.styles, css` /* Larger maximum height before scroll*/ .select__tags { max-height: 10em; } ` ]; } constructor(...args : any[]) { super(...args); this.searchUrl = "calendar_owner_etemplate_widget::ajax_search"; this.multiple = true; // Take grants into account for search this.searchOptions['checkgrants'] = true; } connectedCallback() { super.connectedCallback(); // Start fetch of users const type = this.egw().preference('account_selection', 'common'); if(!type || type == "none" || type == "selectbox") { return; } let fetch = []; // for primary_group we only display owngroups == own memberships, not other groups if(type === 'primary_group') { fetch.push(this.egw().accounts('accounts').then(options => {this.static_options = this.static_options.concat(cleanSelectOptions(options))})); fetch.push(this.egw().accounts('owngroups').then(options => {this.static_options = this.static_options.concat(cleanSelectOptions(options))})); } else { fetch.push(this.egw().accounts('accounts').then(options => {this.static_options = this.static_options.concat(cleanSelectOptions(options))})); } this.fetchComplete = Promise.all(fetch) .then(() => this._renderOptions()); } /** * Override parent to handle our special additional data types (c#,r#,etc.) when they * are not available client side. * * @param {string|string[]} _value array of selected owners, which can be a number, * or a number prefixed with one character indicating the resource type. */ set_value(_value) { super.set_value(_value); // If parent didn't find a label, label will be the same as ID so we // can find them that way let missing_labels = []; this.updateComplete.then(() => { for(var i = 0; i < this.value.length; i++) { if(!this.menuItems.find(o => o.value == this.value[i])) { missing_labels.push(this.value[i]); } } if(Object.keys(missing_labels).length > 0) { // Proper label was not found by parent - ask directly this.egw().json('calendar_owner_etemplate_widget::ajax_owner', [missing_labels], function(data) { for(let owner in data) { if(!owner || typeof owner == "undefined") { continue; } // Put it in the list of options let index = this.select_options.findIndex(o => o.value == owner); let remote_index = this._selected_remote.findIndex(o => o.value == owner); if(remote_index !== -1) { this._selected_remote[remote_index] = data[owner]; } else if(index == -1) { this._selected_remote.push(data[owner]); } } this.requestUpdate("select_options"); this.updateComplete.then(() => {this.syncItemsFromValue();}); }, this, true, this).sendRequest(); } }); } /** * Check a value for missing options and remove them. * * Override to allow any value, since we won't have all options * * @param {string[]} value * @returns {string[]} */ filterOutMissingOptions(value : string[]) : string[] { return value; } /** * Override icon for the select option to use lavatar * * @param option * @protected */ protected _iconTemplate(option) { // Not a user / contact, no icon - use app image if(!option.fname && !option.lname && !option.icon && option.app) { return html` `; } // lavatar uses a size property, not a CSS variable let style = getComputedStyle(this); return html` `; } /** * Check if a free entry value is acceptable. * We only check the free entry, since value can be mixed. * * @param text * @returns {boolean} */ public validateFreeEntry(text) : boolean { let validators = [...this.validators, new IsEmail()]; let result = validators.filter(v => v.execute(text, v.param, {node: this}), ); return result.length == 0; } } if(!customElements.get("et2-calendar-owner")) { customElements.define("et2-calendar-owner", CalendarOwner); }