forked from extern/egroupware
Et2SelectEmail: Add button on hover to add a new contact with the email
(multiple)
This commit is contained in:
parent
9ca78de12f
commit
d11be10fa1
@ -24,6 +24,37 @@ export class Et2WidgetWithSelect extends Et2widgetWithSelectMixin(SlSelect)
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Select widget
|
||||
*
|
||||
* At its most basic, you can select one option from a list provided. The list can be passed from the server in
|
||||
* the sel_options array or options can be added as children in the template. Some extending classes provide specific
|
||||
* options, such as Et2SelectPercent or Et2SelectCountry. All provided options will be mixed together and used.
|
||||
*
|
||||
* To allow selecting more than one option, use the attribute multiple="true". This will take & return an array
|
||||
* as value instead of just a string.
|
||||
*
|
||||
* SearchMixin adds additional abilities to ALL select boxes
|
||||
* @see Et2WithSearchMixin
|
||||
*
|
||||
* Override for extending widgets:
|
||||
* # Custom display of selected value
|
||||
* When selecting a single value (!multiple) you can override doLabelChange() to customise the displayed label
|
||||
* @see Et2SelectCategory, which adds in the category icon
|
||||
*
|
||||
* # Custom option rows
|
||||
* Options can have 'class' and 'icon' properties that will be used for the option
|
||||
* The easiest way for further customisation to use CSS in an external file (like etemplate2.css) and ::part().
|
||||
* @see Et2SelectCountry which displays flags via CSS instead of using SelectOption.icon
|
||||
*
|
||||
* # Custom tags
|
||||
* When multiple is set, instead of a single value each selected value is shown in a tag. While it's possible to
|
||||
* use CSS to some degree, we can also use a custom tag class that extends Et2Tag.
|
||||
* 1. Create the extending class
|
||||
* 2. Make sure it's loaded (add to etemplate2.ts)
|
||||
* 3. In your extending Et2Select, override get tagTag() to return the custom tag name
|
||||
*
|
||||
*/
|
||||
// @ts-ignore SlSelect styles is a single CSSResult, not an array, so TS complains
|
||||
export class Et2Select extends Et2WithSearchMixin(Et2InvokerMixin(Et2WidgetWithSelect))
|
||||
{
|
||||
|
@ -141,6 +141,16 @@ export class Et2SelectEmail extends Et2Select
|
||||
super.processRemoteResults(results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a custom tag for when multiple=true
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
get tagTag() : string
|
||||
{
|
||||
return "et2-email-tag";
|
||||
}
|
||||
|
||||
/**
|
||||
* override tag creation in order to add DND functionality
|
||||
* @param item
|
||||
@ -149,7 +159,7 @@ export class Et2SelectEmail extends Et2Select
|
||||
protected _createTagNode(item)
|
||||
{
|
||||
let tag = super._createTagNode(item);
|
||||
if (!this.readonly && this.allowFreeEntries && this.allowDragAndDrop)
|
||||
if(!this.readonly && this.allowFreeEntries && this.allowDragAndDrop)
|
||||
{
|
||||
let dragTranslate = {x:0,y:0};
|
||||
tag.class = item.classList.value + " et2-select-draggable";
|
||||
|
168
api/js/etemplate/Et2Select/Tag/Et2EmailTag.ts
Normal file
168
api/js/etemplate/Et2Select/Tag/Et2EmailTag.ts
Normal file
@ -0,0 +1,168 @@
|
||||
/**
|
||||
* EGroupware eTemplate2 - Email Tag 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 {css} from "@lion/core";
|
||||
import shoelace from "../../Styles/shoelace";
|
||||
import {Et2Tag} from "./Et2Tag";
|
||||
import {cssImage} from "../../Et2Widget/Et2Widget";
|
||||
|
||||
/**
|
||||
* Display a single email address
|
||||
* On hover, queries the server to see if
|
||||
* Tag is usually used in a Et2EmailSelect with multiple=true, but there's no reason it can't go anywhere
|
||||
*/
|
||||
export class Et2EmailTag extends Et2Tag
|
||||
{
|
||||
private static email_cache : string[] = [];
|
||||
|
||||
static get styles()
|
||||
{
|
||||
return [
|
||||
super.styles,
|
||||
shoelace, css`
|
||||
.tag {
|
||||
position: relative;
|
||||
}
|
||||
.tag__prefix {
|
||||
display: none;
|
||||
|
||||
height: 16px;
|
||||
|
||||
background-color: white;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.contact_plus .tag__prefix {
|
||||
display: block;
|
||||
order: 2;
|
||||
}
|
||||
.tag__prefix.loading {
|
||||
width: 16px;
|
||||
background-image: ${cssImage("loading")};
|
||||
}
|
||||
|
||||
.tag__prefix.contact_plus_add {
|
||||
width: 16px;
|
||||
background-image: ${cssImage("add")};
|
||||
cursor: pointer;
|
||||
}
|
||||
`];
|
||||
}
|
||||
|
||||
static get properties()
|
||||
{
|
||||
return {
|
||||
...super.properties,
|
||||
/**
|
||||
* Check if the email is associated with an existing contact, and if it is not show a button to create
|
||||
* a new contact with this email address.
|
||||
*/
|
||||
contact_plus: {
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(...args : [])
|
||||
{
|
||||
super(...args);
|
||||
this.contact_plus = true;
|
||||
this.handleMouseEnter = this.handleMouseEnter.bind(this);
|
||||
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
connectedCallback()
|
||||
{
|
||||
super.connectedCallback();
|
||||
|
||||
if(this.contact_plus && this.egw().app('addressbook'))
|
||||
{
|
||||
this.addEventListener("mouseenter", this.handleMouseEnter);
|
||||
this.addEventListener("mouseleave", this.handleMouseLeave);
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback()
|
||||
{
|
||||
super.disconnectedCallback();
|
||||
this.removeEventListener("mouseenter", this.handleMouseEnter);
|
||||
this.removeEventListener("mouseleave", this.handleMouseLeave);
|
||||
}
|
||||
|
||||
public checkContact(email : string) : Promise<boolean | number>
|
||||
{
|
||||
if(typeof Et2EmailTag.email_cache[email] !== "undefined")
|
||||
{
|
||||
return Promise.resolve(Et2EmailTag.email_cache[email]);
|
||||
}
|
||||
return this.egw().jsonq('EGroupware\\Api\\Etemplate\\Widget\\Url::ajax_contact', [email]).then(
|
||||
(result) =>
|
||||
{
|
||||
Et2EmailTag.email_cache[email] = result;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
handleMouseEnter(e : MouseEvent)
|
||||
{
|
||||
this.shadowRoot.querySelector(".tag").classList.add("contact_plus");
|
||||
this._contactPlusNode.classList.add("loading");
|
||||
this._contactPlusNode.style.right = getComputedStyle(this).left;
|
||||
|
||||
this.checkContact(this.value).then((result) =>
|
||||
{
|
||||
this._contactPlusNode.classList.remove("loading");
|
||||
this.handleContactResponse(result);
|
||||
})
|
||||
}
|
||||
|
||||
handleMouseLeave(e : MouseEvent)
|
||||
{
|
||||
this.shadowRoot.querySelector(".tag").classList.remove("contact_plus");
|
||||
}
|
||||
|
||||
/**
|
||||
* We either have a contact ID, or false. If false, show the add button.
|
||||
* @param {boolean | number} data
|
||||
*/
|
||||
handleContactResponse(data : boolean | number)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this._contactPlusNode.classList.add("contact_plus_add");
|
||||
this._contactPlusNode.addEventListener("click", this.handleClick);
|
||||
}
|
||||
|
||||
handleClick(e : MouseEvent)
|
||||
{
|
||||
e.stopPropagation();
|
||||
|
||||
let extra = {
|
||||
'presets[email]': this.value
|
||||
};
|
||||
|
||||
this.egw().open('', 'addressbook', 'add', extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the node that is shown & clicked on to add email as contact
|
||||
*
|
||||
* @returns {Element}
|
||||
*/
|
||||
get _contactPlusNode() : HTMLElement
|
||||
{
|
||||
return this.shadowRoot.querySelector(".tag__prefix");
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("et2-email-tag", Et2EmailTag);
|
@ -58,6 +58,7 @@ import './Et2Select/Et2SelectReadonly';
|
||||
import './Et2Select/Et2SelectThumbnail'
|
||||
import './Et2Select/Tag/Et2Tag';
|
||||
import './Et2Select/Tag/Et2CategoryTag';
|
||||
import './Et2Select/Tag/Et2EmailTag';
|
||||
import './Et2Select/Tag/Et2ThumbnailTag';
|
||||
import './Et2Textarea/Et2Textarea';
|
||||
import './Et2Textbox/Et2Textbox';
|
||||
|
Loading…
Reference in New Issue
Block a user