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
|
// @ts-ignore SlSelect styles is a single CSSResult, not an array, so TS complains
|
||||||
export class Et2Select extends Et2WithSearchMixin(Et2InvokerMixin(Et2WidgetWithSelect))
|
export class Et2Select extends Et2WithSearchMixin(Et2InvokerMixin(Et2WidgetWithSelect))
|
||||||
{
|
{
|
||||||
|
@ -141,6 +141,16 @@ export class Et2SelectEmail extends Et2Select
|
|||||||
super.processRemoteResults(results);
|
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
|
* override tag creation in order to add DND functionality
|
||||||
* @param item
|
* @param item
|
||||||
@ -149,7 +159,7 @@ export class Et2SelectEmail extends Et2Select
|
|||||||
protected _createTagNode(item)
|
protected _createTagNode(item)
|
||||||
{
|
{
|
||||||
let tag = super._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};
|
let dragTranslate = {x:0,y:0};
|
||||||
tag.class = item.classList.value + " et2-select-draggable";
|
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/Et2SelectThumbnail'
|
||||||
import './Et2Select/Tag/Et2Tag';
|
import './Et2Select/Tag/Et2Tag';
|
||||||
import './Et2Select/Tag/Et2CategoryTag';
|
import './Et2Select/Tag/Et2CategoryTag';
|
||||||
|
import './Et2Select/Tag/Et2EmailTag';
|
||||||
import './Et2Select/Tag/Et2ThumbnailTag';
|
import './Et2Select/Tag/Et2ThumbnailTag';
|
||||||
import './Et2Textarea/Et2Textarea';
|
import './Et2Textarea/Et2Textarea';
|
||||||
import './Et2Textbox/Et2Textbox';
|
import './Et2Textbox/Et2Textbox';
|
||||||
|
Loading…
Reference in New Issue
Block a user