mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 14:41:29 +01:00
Et2Email: Readonly & limited rows styling
This commit is contained in:
parent
57c76e9840
commit
a673a6ac5f
@ -27,7 +27,7 @@ export default css`
|
|||||||
border-radius: var(--sl-input-border-radius-medium);
|
border-radius: var(--sl-input-border-radius-medium);
|
||||||
font-size: var(--sl-input-font-size-medium);
|
font-size: var(--sl-input-font-size-medium);
|
||||||
min-height: var(--sl-input-height-medium);
|
min-height: var(--sl-input-height-medium);
|
||||||
max-height: calc(var(--height, 2.5) * var(--sl-input-height-medium));
|
max-height: calc(var(--height, 5) * var(--sl-input-height-medium));
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding-block: 0;
|
padding-block: 0;
|
||||||
padding-inline: var(--sl-input-spacing-medium);
|
padding-inline: var(--sl-input-spacing-medium);
|
||||||
@ -58,7 +58,8 @@ export default css`
|
|||||||
order: 1;
|
order: 1;
|
||||||
}
|
}
|
||||||
/* Tags */
|
/* Tags */
|
||||||
.email et2-email-tag {
|
|
||||||
|
et2-email-tag {
|
||||||
order: 2;
|
order: 2;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
margin: auto 0px;
|
margin: auto 0px;
|
||||||
@ -137,4 +138,70 @@ export default css`
|
|||||||
padding-inline: var(--sl-spacing-x-large);
|
padding-inline: var(--sl-spacing-x-large);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Readonly
|
||||||
|
*/
|
||||||
|
|
||||||
|
:host([readonly]) .email .email__combobox {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
max-height: calc(var(--height, 5) * (var(--sl-input-height-medium) * 0.8))
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([readonly])::part(expand-icon) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([readonly]) .email__search {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style for tag count if readonly and rows=1
|
||||||
|
*/
|
||||||
|
|
||||||
|
:host([readonly][rows="1"]) .email__combobox {
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: auto;
|
||||||
|
max-height: calc(var(--sl-input-height-medium) * 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag_limit {
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
box-shadow: rgb(0 0 0/50%) -1.5ex 0px 1ex -1ex, rgb(0 0 0 / 0%) 0px 0px 0px 0px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag_limit::part(base) {
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--sl-input-background-color);
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
font-weight: bold;
|
||||||
|
min-width: 3em;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show all rows on hover if readonly rows=1 */
|
||||||
|
|
||||||
|
:host([ readonly ][ rows ]) .hover__popup {
|
||||||
|
width: -webkit-fill-available;
|
||||||
|
width: -moz-fill-available;
|
||||||
|
width: fill-available;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([readonly][rows]) .hover__popup::part(popup) {
|
||||||
|
z-index: var(--sl-z-index-dropdown);
|
||||||
|
background-color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
/* Same as .email__combobox */
|
||||||
|
gap: 0.1rem 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End styles for [readonly][rows=1] */
|
||||||
`;
|
`;
|
@ -11,6 +11,7 @@ import {html, LitElement, nothing, PropertyValues, TemplateResult} from "lit";
|
|||||||
import {property} from "lit/decorators/property.js";
|
import {property} from "lit/decorators/property.js";
|
||||||
import {state} from "lit/decorators/state.js";
|
import {state} from "lit/decorators/state.js";
|
||||||
import {classMap} from "lit/directives/class-map.js";
|
import {classMap} from "lit/directives/class-map.js";
|
||||||
|
import {styleMap} from "lit/directives/style-map.js";
|
||||||
import {keyed} from "lit/directives/keyed.js";
|
import {keyed} from "lit/directives/keyed.js";
|
||||||
import {live} from "lit/directives/live.js";
|
import {live} from "lit/directives/live.js";
|
||||||
import {map} from "lit/directives/map.js";
|
import {map} from "lit/directives/map.js";
|
||||||
@ -63,7 +64,7 @@ import Sortable from "sortablejs/modular/sortable.complete.esm.js";
|
|||||||
* @csspart option - Each matching email address suggestion
|
* @csspart option - Each matching email address suggestion
|
||||||
* @csspart tag - The individual tags that represent each email address.
|
* @csspart tag - The individual tags that represent each email address.
|
||||||
*
|
*
|
||||||
* @cssproperty [--height=2.5] - The maximum height of the widget, to limit size when you have a lot of addresses.
|
* @cssproperty [--height=5] - The maximum height of the widget, to limit size when you have a lot of addresses. Set by rows property, when set.
|
||||||
*/
|
*/
|
||||||
export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinInterface
|
export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinInterface
|
||||||
{
|
{
|
||||||
@ -144,11 +145,21 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
*/
|
*/
|
||||||
@property({type: String}) searchUrl = "EGroupware\\Api\\Etemplate\\Widget\\Taglist::ajax_email";
|
@property({type: String}) searchUrl = "EGroupware\\Api\\Etemplate\\Widget\\Taglist::ajax_email";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limit the maximum height of the widget, for when you have a lot of addresses.
|
||||||
|
* Set it to 1 for special single-line styling, 0 to disable
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
@property({type: Number, reflect: true}) rows;
|
||||||
|
|
||||||
@state() searching = false;
|
@state() searching = false;
|
||||||
@state() hasFocus = false;
|
@state() hasFocus = false;
|
||||||
@state() currentOption : SlOption;
|
@state() currentOption : SlOption;
|
||||||
@state() currentTag : Et2EmailTag;
|
@state() currentTag : Et2EmailTag;
|
||||||
|
|
||||||
|
/** If the select is limited to 1 row, we show the number of tags not visible */
|
||||||
|
@state() _tagsHidden = 0;
|
||||||
|
|
||||||
|
|
||||||
get _popup() : SlPopup { return this.shadowRoot.querySelector("sl-popup");}
|
get _popup() : SlPopup { return this.shadowRoot.querySelector("sl-popup");}
|
||||||
|
|
||||||
@ -187,6 +198,9 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
protected _searchPromise : Promise<SelectOption[]> = Promise.resolve([]);
|
protected _searchPromise : Promise<SelectOption[]> = Promise.resolve([]);
|
||||||
protected _selectOptions : SelectOption[] = [];
|
protected _selectOptions : SelectOption[] = [];
|
||||||
|
|
||||||
|
// Overflow Observer for +# display
|
||||||
|
protected tagOverflowObserver : IntersectionObserver = null;
|
||||||
|
|
||||||
// Drag / drop / sort
|
// Drag / drop / sort
|
||||||
protected _sortable : Sortable;
|
protected _sortable : Sortable;
|
||||||
|
|
||||||
@ -208,8 +222,10 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
|
|
||||||
this.handleOpenChange = this.handleOpenChange.bind(this);
|
this.handleOpenChange = this.handleOpenChange.bind(this);
|
||||||
this.handleLostFocus = this.handleLostFocus.bind(this);
|
this.handleLostFocus = this.handleLostFocus.bind(this);
|
||||||
|
|
||||||
this.handleSortEnd = this.handleSortEnd.bind(this);
|
this.handleSortEnd = this.handleSortEnd.bind(this);
|
||||||
|
this.handleTagOverflow = this.handleTagOverflow.bind(this);
|
||||||
|
this.handleMouseEnter = this.handleMouseEnter.bind(this);
|
||||||
|
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback()
|
connectedCallback()
|
||||||
@ -271,6 +287,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
{
|
{
|
||||||
this.makeSortable();
|
this.makeSortable();
|
||||||
}
|
}
|
||||||
|
this.checkTagOverflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getEmailDisplayPreference()
|
private _getEmailDisplayPreference()
|
||||||
@ -374,6 +391,35 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected checkTagOverflow()
|
||||||
|
{
|
||||||
|
// Create / destroy intersection observer
|
||||||
|
if(this.readonly && this.rows == "1" && this.tagOverflowObserver == null)
|
||||||
|
{
|
||||||
|
this.tagOverflowObserver = new IntersectionObserver(this.handleTagOverflow, {
|
||||||
|
root: this.shadowRoot.querySelector(".email__combobox"),
|
||||||
|
threshold: 0.1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if((!this.readonly || this.rows !== 1) && this.tagOverflowObserver !== null)
|
||||||
|
{
|
||||||
|
this.tagOverflowObserver.disconnect();
|
||||||
|
this.tagOverflowObserver = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.tagOverflowObserver)
|
||||||
|
{
|
||||||
|
this.updateComplete.then(() =>
|
||||||
|
{
|
||||||
|
for(const tag of Array.from(this.shadowRoot.querySelectorAll(".email__combobox et2-email-tag")))
|
||||||
|
{
|
||||||
|
this.tagOverflowObserver.observe(tag);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an entry that is not in the suggestions and add it to the value
|
* Create an entry that is not in the suggestions and add it to the value
|
||||||
*
|
*
|
||||||
@ -667,6 +713,56 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for the intersection observer so we know when tags don't fit
|
||||||
|
*
|
||||||
|
* Here we set the flag to show how many more tags are hidden, but this only happens
|
||||||
|
* when there are more tags than space.
|
||||||
|
*
|
||||||
|
* @param entries
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected handleTagOverflow(entries : IntersectionObserverEntry[])
|
||||||
|
{
|
||||||
|
const oldCount = this._tagsHidden;
|
||||||
|
let visibleTagCount = this.value.length - this._tagsHidden;
|
||||||
|
let update = false;
|
||||||
|
// If we have all tags, start from 0, otherwise it's just a change
|
||||||
|
if(entries.length == this.value.length)
|
||||||
|
{
|
||||||
|
visibleTagCount = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
for(const tag of entries)
|
||||||
|
{
|
||||||
|
if(tag.isIntersecting)
|
||||||
|
{
|
||||||
|
visibleTagCount++;
|
||||||
|
}
|
||||||
|
else if(update && !tag.isIntersecting)
|
||||||
|
{
|
||||||
|
visibleTagCount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(visibleTagCount && visibleTagCount < this.value.length)
|
||||||
|
{
|
||||||
|
this._tagsHidden = this.value.length - visibleTagCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._tagsHidden = 0;
|
||||||
|
}
|
||||||
|
this.requestUpdate("_tagsHidden", oldCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sometimes users paste multiple comma separated values at once. Split them then handle normally.
|
* 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.
|
* Overridden here to handle email addresses that may have commas using the regex from the validator.
|
||||||
@ -895,6 +991,36 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If rows=1 and multiple=true, when they put the mouse over the widget show all tags
|
||||||
|
* @param {MouseEvent} e
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
protected handleMouseEnter(e : MouseEvent)
|
||||||
|
{
|
||||||
|
if(this.rows == "1" && this.value.length > 1)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
// Bind to turn this all off
|
||||||
|
this.addEventListener("mouseleave", this.handleMouseLeave);
|
||||||
|
|
||||||
|
this.classList.add("hover");
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we're showing all rows because of _handleMouseEnter, reset when mouse leaves
|
||||||
|
* @param {MouseEvent} e
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
protected handleMouseLeave(e : MouseEvent)
|
||||||
|
{
|
||||||
|
this.classList.remove("hover");
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keyboard events from the suggestion list
|
* Keyboard events from the suggestion list
|
||||||
*
|
*
|
||||||
@ -1013,6 +1139,31 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sub-template when [readonly][rows=1] to show all tags in current value in popup */
|
||||||
|
readonlyHoverTemplate()
|
||||||
|
{
|
||||||
|
if(!this.classList.contains("hover"))
|
||||||
|
{
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset distance to open _over_ the rest
|
||||||
|
let distance = (-1 * parseInt(getComputedStyle(this).height));
|
||||||
|
return html`
|
||||||
|
<sl-popup
|
||||||
|
active
|
||||||
|
anchor=${this}
|
||||||
|
auto-size="both"
|
||||||
|
class="hover__popup details hoist details__body"
|
||||||
|
distance=${distance}
|
||||||
|
placement="bottom"
|
||||||
|
sync="width"
|
||||||
|
>
|
||||||
|
${this.tagsTemplate()}
|
||||||
|
</sl-popup>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
tagsTemplate()
|
tagsTemplate()
|
||||||
{
|
{
|
||||||
return html`${keyed(this._valueUID, map(this.value, (value, index) => this.tagTemplate(value)))}`;
|
return html`${keyed(this._valueUID, map(this.value, (value, index) => this.tagTemplate(value)))}`;
|
||||||
@ -1045,6 +1196,21 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
</et2-email-tag>`;
|
</et2-email-tag>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected tagLimitTemplate() : TemplateResult | typeof nothing
|
||||||
|
{
|
||||||
|
if(this._tagsHidden == 0)
|
||||||
|
{
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<sl-tag
|
||||||
|
part="tag__limit"
|
||||||
|
class="tag_limit"
|
||||||
|
slot="expand-icon"
|
||||||
|
>+${this._tagsHidden}
|
||||||
|
</sl-tag>`;
|
||||||
|
}
|
||||||
|
|
||||||
inputTemplate()
|
inputTemplate()
|
||||||
{
|
{
|
||||||
return html`
|
return html`
|
||||||
@ -1110,6 +1276,13 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
|
const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
|
||||||
const isPlaceholderVisible = this.placeholder && this.value.length === 0 && !this.disabled && !this.readonly;
|
const isPlaceholderVisible = this.placeholder && this.value.length === 0 && !this.disabled && !this.readonly;
|
||||||
|
|
||||||
|
let styles = {};
|
||||||
|
|
||||||
|
if(this.rows !== 0)
|
||||||
|
{
|
||||||
|
styles["--height"] = this.rows;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Don't forget required & disabled
|
// TODO Don't forget required & disabled
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
@ -1121,7 +1294,9 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
'form-control--has-label': hasLabel,
|
'form-control--has-label': hasLabel,
|
||||||
'form-control--has-help-text': hasHelpText
|
'form-control--has-help-text': hasHelpText
|
||||||
})}
|
})}
|
||||||
|
style=${styleMap(styles)}
|
||||||
@click=${this.handleLabelClick}
|
@click=${this.handleLabelClick}
|
||||||
|
@mouseenter=${this.handleMouseEnter}
|
||||||
@mousedown=${() =>
|
@mousedown=${() =>
|
||||||
{
|
{
|
||||||
if(!this.hasFocus)
|
if(!this.hasFocus)
|
||||||
@ -1141,6 +1316,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
<slot name="label">${this.label}</slot>
|
<slot name="label">${this.label}</slot>
|
||||||
</label>
|
</label>
|
||||||
<div part="form-control-input" class="form-control-input">
|
<div part="form-control-input" class="form-control-input">
|
||||||
|
${this.readonlyHoverTemplate()}
|
||||||
<sl-popup
|
<sl-popup
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
email: true,
|
email: true,
|
||||||
@ -1171,6 +1347,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
<slot part="prefix" name="prefix" class="email__prefix"></slot>
|
<slot part="prefix" name="prefix" class="email__prefix"></slot>
|
||||||
${this.tagsTemplate()}
|
${this.tagsTemplate()}
|
||||||
${this.inputTemplate()}
|
${this.inputTemplate()}
|
||||||
|
${this.tagLimitTemplate()}
|
||||||
${this.searching ? html`
|
${this.searching ? html`
|
||||||
<sl-spinner class="email__loading"></sl-spinner>` : nothing}
|
<sl-spinner class="email__loading"></sl-spinner>` : nothing}
|
||||||
<slot part="suffix" name="suffix" class="email__suffix"></slot>
|
<slot part="suffix" name="suffix" class="email__suffix"></slot>
|
||||||
|
@ -90,7 +90,7 @@ export function inputBasicTests(before : Function, test_value : string, value_se
|
|||||||
// Shows as empty / no value
|
// Shows as empty / no value
|
||||||
let value = (<Element><unknown>element).querySelector(value_selector) || (<Element><unknown>element).shadowRoot.querySelector(value_selector);
|
let value = (<Element><unknown>element).querySelector(value_selector) || (<Element><unknown>element).shadowRoot.querySelector(value_selector);
|
||||||
assert.isDefined(value, "Bad value selector '" + value_selector + "'");
|
assert.isDefined(value, "Bad value selector '" + value_selector + "'");
|
||||||
debugger;
|
|
||||||
assert.equal(value.textContent.trim(), "", "Displaying something when there is no value");
|
assert.equal(value.textContent.trim(), "", "Displaying something when there is no value");
|
||||||
if(element.multiple)
|
if(element.multiple)
|
||||||
{
|
{
|
||||||
@ -104,7 +104,7 @@ export function inputBasicTests(before : Function, test_value : string, value_se
|
|||||||
it("value out matches value in", async() =>
|
it("value out matches value in", async() =>
|
||||||
{
|
{
|
||||||
element.set_value(test_value);
|
element.set_value(test_value);
|
||||||
debugger;
|
|
||||||
// wait for asychronous changes to the DOM
|
// wait for asychronous changes to the DOM
|
||||||
await elementUpdated(<Element><unknown>element);
|
await elementUpdated(<Element><unknown>element);
|
||||||
|
|
||||||
|
@ -30,28 +30,24 @@
|
|||||||
<et2-vbox class="addresses">
|
<et2-vbox class="addresses">
|
||||||
<et2-hbox>
|
<et2-hbox>
|
||||||
<et2-description value="From" class="firstColumnTitle"></et2-description>
|
<et2-description value="From" class="firstColumnTitle"></et2-description>
|
||||||
<et2-select-email id="additionalfromaddress" readonly="true"
|
<et2-email id="additionalfromaddress" readonly="true"
|
||||||
fullEmail="@emailTag=fullemail" onlyEmail="@emailTag=onlyemail" multiple="true"
|
onclick="app.mail.onclickCompose"></et2-email>
|
||||||
onclick="app.mail.onclickCompose"></et2-select-email>
|
|
||||||
<et2-date-time align="right" id="date" readonly="true"></et2-date-time>
|
<et2-date-time align="right" id="date" readonly="true"></et2-date-time>
|
||||||
</et2-hbox>
|
</et2-hbox>
|
||||||
<et2-hbox disabled="!@toaddress" width="100%">
|
<et2-hbox disabled="!@toaddress" width="100%">
|
||||||
<et2-description value="To" class="firstColumnTitle"></et2-description>
|
<et2-description value="To" class="firstColumnTitle"></et2-description>
|
||||||
<et2-select-email id="additionaltoaddress" readonly="true" multiple="true"
|
<et2-email id="additionaltoaddress" readonly="true" rows="1"
|
||||||
rows="1" fullEmail="@emailTag=fullemail" onlyEmail="@emailTag=onlyemail"
|
onTagClick="app.mail.onclickCompose"></et2-email>
|
||||||
onTagClick="app.mail.onclickCompose"></et2-select-email>
|
|
||||||
</et2-hbox>
|
</et2-hbox>
|
||||||
<et2-hbox disabled="!@ccaddress" width="100%">
|
<et2-hbox disabled="!@ccaddress" width="100%">
|
||||||
<et2-description value="Cc" class="firstColumnTitle"></et2-description>
|
<et2-description value="Cc" class="firstColumnTitle"></et2-description>
|
||||||
<et2-select-email id="ccaddress" readonly="true" multiple="true"
|
<et2-email id="ccaddress" readonly="true" rows="1"
|
||||||
rows="1" fullEmail="@emailTag=fullemail" onlyEmail="@emailTag=onlyemail"
|
onTagClick="app.mail.onclickCompose"></et2-email>
|
||||||
onTagClick="app.mail.onclickCompose"></et2-select-email>
|
|
||||||
</et2-hbox>
|
</et2-hbox>
|
||||||
<et2-hbox disabled="!@bccaddress" width="100%">
|
<et2-hbox disabled="!@bccaddress" width="100%">
|
||||||
<et2-description value="Bcc" class="firstColumnTitle"></et2-description>
|
<et2-description value="Bcc" class="firstColumnTitle"></et2-description>
|
||||||
<et2-select-email id="bccaddress" readonly="true" multiple="true"
|
<et2-email id="bccaddress" readonly="true" rows="1"
|
||||||
rows="1" fullEmail="@emailTag=fullemail" onlyEmail="@emailTag=onlyemail"
|
onTagClick="app.mail.onclickCompose"></et2-email>
|
||||||
onTagClick="app.mail.onclickCompose"></et2-select-email>
|
|
||||||
</et2-hbox>
|
</et2-hbox>
|
||||||
<et2-hbox width="100%" disabled="!@attachmentsBlock">
|
<et2-hbox width="100%" disabled="!@attachmentsBlock">
|
||||||
<et2-description value="Attachments" class="firstColumnTitle"></et2-description>
|
<et2-description value="Attachments" class="firstColumnTitle"></et2-description>
|
||||||
|
Loading…
Reference in New Issue
Block a user