Collabora: Get insert placeholder dialog working again

This commit is contained in:
nathan 2022-10-05 10:50:54 -06:00
parent 59da89fe8b
commit 3ce5aebe12
5 changed files with 186 additions and 9 deletions

View File

@ -0,0 +1,160 @@
import {SlMenu, SlMenuItem} from "@shoelace-style/shoelace";
import {Et2widgetWithSelectMixin} from "./Et2WidgetWithSelectMixin";
import {RowLimitedMixin} from "../Layout/RowLimitedMixin";
import shoelace from "../Styles/shoelace";
import {css, html, TemplateResult} from "@lion/core";
import {SelectOption} from "./FindSelectOptions";
/**
* A selectbox that shows more than one row at a time
*
* Set rows attribute to adjust how many rows are visible at once
*
* Use Et2Selectbox in most cases, it's better.
*/
export class Et2Listbox extends RowLimitedMixin(Et2widgetWithSelectMixin(SlMenu))
{
static get styles()
{
return [
// Parent (SlMenu) returns a single cssResult, not an array
shoelace,
super.styles,
css`
:host {
display: block;
flex: 1 0 auto;
--icon-width: 20px;
}
::slotted(img), img {
vertical-align: middle;
}
.menu {
/* Get rid of padding before/after options */
padding: 0px;
/* No horizontal scrollbar, even if options are long */
overflow-x: clip;
}
/* Ellipsis when too small */
sl-menu-item.menu-item__label {
display: block;
text-overflow: ellipsis;
/* This is usually not used due to flex, but is the basis for ellipsis calculation */
width: 10ex;
}
:host([rows])::part(base) {
max-height: calc(var(--rows, 5) * 1.9rem);
overflow-y: auto;
}
`
];
}
static get properties()
{
return {
...super.properties,
/**
* Toggle between single and multiple selection
*/
multiple: {
type: Boolean,
reflect: true,
}
}
}
constructor(...args : any[])
{
super();
this.handleSelect = this.handleSelect.bind(this);
}
connectedCallback()
{
super.connectedCallback();
this.addEventListener("sl-select", this.handleSelect);
this.updateComplete.then(() =>
{
this.addEventListener("sl-change", this._triggerChange);
});
}
/**
* Handle an item was selected
*
* Toggle the checkmark and fire the changed event
*
* @param {MouseEvent} event
*/
handleSelect(event : CustomEvent)
{
let item = event.detail?.item;
if(!item)
{
return;
}
if(!this.multiple)
{
this.getAllItems().forEach((i) => i.checked = false);
item.checked = true;
}
else
{
item.checked = !item.checked;
}
this.dispatchEvent(new Event("change"));
}
get value()
{
let value = this.getAllItems()
.filter((item) => item.checked)
.map((item) => item.value);
return this.multiple ? value : value.pop();
}
set value(new_value : String[] | String)
{
const oldValue = this.value;
if(typeof new_value == "string")
{
new_value = [new_value]
}
this.getAllItems().forEach((item) => item.checked = false);
for(let i = 0; i < new_value.length; i++)
{
const value = new_value[i];
(<SlMenuItem>this.querySelector("[value='" + value + "']")).checked = true;
}
this.requestUpdate("value", oldValue);
}
_optionTemplate(option : SelectOption) : TemplateResult
{
let icon = option.icon ? html`
<et2-image slot="prefix" part="icon" style="width: var(--icon-width)"
src="${option.icon}"></et2-image>` : "";
// Tag used must match this.optionTag, but you can't use the variable directly.
// Pass option along so SearchMixin can grab it if needed
return html`
<sl-menu-item value="${option.value}"
title="${!option.title || this.noLang ? option.title : this.egw().lang(option.title)}"
class="${option.class}" .option=${option}>
${icon}
${this.noLang ? option.label : this.egw().lang(option.label)}
</sl-menu-item>`;
}
}
customElements.define("et2-listbox", Et2Listbox);

View File

@ -173,6 +173,15 @@ export class et2_placeholder_select extends et2_inputWidget
this._do_insert_callback(submit_value); this._do_insert_callback(submit_value);
return true; return true;
} }
else if(submit_button_id == 'cancel')
{
return true;
}
else
{
// Keep dialog open
return false;
}
}.bind(this); }.bind(this);
this.dialog = new Et2Dialog(this.egw()); this.dialog = new Et2Dialog(this.egw());
@ -448,12 +457,12 @@ export class et2_placeholder_snippet_select extends et2_placeholder_select
app.onchange = (node, widget) => app.onchange = (node, widget) =>
{ {
entry.set_value({app: widget.get_value()}); entry.set_value({app: widget.get_value()});
placeholder_list.set_select_options(this._get_placeholders(app.get_value(), "addresses")); placeholder_list.set_select_options(this._get_placeholders(app.value, "addresses"));
} }
placeholder_list.onchange = this._on_placeholder_select.bind(this); placeholder_list.onchange = this._on_placeholder_select.bind(this);
entry.onchange = this._on_placeholder_select.bind(this); entry.onchange = this._on_placeholder_select.bind(this);
app.set_value(app.get_value()); app.set_value(app.value);
this._on_placeholder_select(); this._on_placeholder_select();
} }
@ -463,16 +472,22 @@ export class et2_placeholder_snippet_select extends et2_placeholder_select
*/ */
_on_placeholder_select() _on_placeholder_select()
{ {
let app = <Et2Select><unknown>this.dialog.template.widgetContainer.getDOMWidgetById("app");
let entry = <Et2LinkEntry><unknown>this.dialog.template.widgetContainer.getDOMWidgetById("entry"); let entry = <Et2LinkEntry><unknown>this.dialog.template.widgetContainer.getDOMWidgetById("entry");
let placeholder_list = <Et2Select><unknown>this.dialog.template.widgetContainer.getDOMWidgetById("placeholder_list"); let placeholder_list = <Et2Select><unknown>this.dialog.template.widgetContainer.getDOMWidgetById("placeholder_list");
let preview_content = <Et2Description><unknown>this.dialog.template.widgetContainer.getDOMWidgetById("preview_content"); let preview_content = <Et2Description><unknown>this.dialog.template.widgetContainer.getDOMWidgetById("preview_content");
let placeholder = "";
if(app && app.value)
{
placeholder = Object.keys(et2_placeholder_snippet_select.placeholders[<string>app.value]["addresses"])[<string>placeholder_list.value];
}
if(placeholder_list.value && entry.get_value()) if(placeholder && entry.get_value())
{ {
// Show the selected placeholder replaced with value from the selected entry // Show the selected placeholder replaced with value from the selected entry
this.egw().json( this.egw().json(
'EGroupware\\Api\\Etemplate\\Widget\\Placeholder::ajax_fill_placeholders', 'EGroupware\\Api\\Etemplate\\Widget\\Placeholder::ajax_fill_placeholders',
[placeholder_list.value, {app: "addressbook", id: entry.get_value()}], [placeholder, {app: "addressbook", id: entry.get_value()}],
function(_content) function(_content)
{ {
if(!_content) if(!_content)
@ -525,11 +540,11 @@ export class et2_placeholder_snippet_select extends et2_placeholder_select
_get_placeholders(appname : string, group : string) _get_placeholders(appname : string, group : string)
{ {
let options = []; let options = [];
Object.keys(et2_placeholder_snippet_select.placeholders[appname][group]).map((key) => Object.keys(et2_placeholder_snippet_select.placeholders[appname][group]).map((key, index) =>
{ {
options.push( options.push(
{ {
value: key, value: index,
label: this.egw().lang(et2_placeholder_snippet_select.placeholders[appname][group][key]) label: this.egw().lang(et2_placeholder_snippet_select.placeholders[appname][group][key])
}); });
}); });

View File

@ -66,6 +66,7 @@ import './Et2Nextmatch/Headers/AccountFilterHeader';
import './Et2Nextmatch/Headers/CustomFilterHeader'; import './Et2Nextmatch/Headers/CustomFilterHeader';
import './Et2Nextmatch/Headers/EntryHeader'; import './Et2Nextmatch/Headers/EntryHeader';
import './Et2Nextmatch/Headers/FilterHeader'; import './Et2Nextmatch/Headers/FilterHeader';
import './Et2Select/Et2Listbox';
import './Et2Select/Et2Select'; import './Et2Select/Et2Select';
import './Et2Select/Et2SelectAccount'; import './Et2Select/Et2SelectAccount';
import './Et2Select/Et2SelectCategory'; import './Et2Select/Et2SelectCategory';

View File

@ -10,12 +10,12 @@
<select id="group"/> <select id="group"/>
</vbox> </vbox>
<select id="placeholder_list" rows="10"/> <et2-listbox id="placeholder_list" rows="10"/>
</hbox> </hbox>
<hbox class="preview"> <hbox class="preview">
<description id="preview_placeholder"/> <description id="preview_placeholder"/>
<button background_image="true" id="insert_placeholder" label="Insert" statustext="Insert placeholder" <button background_image="true" id="insert_placeholder" label="Insert" statustext="Insert placeholder"
image="export"></button> align="right" image="export"></button>
</hbox> </hbox>
<hrule/> <hrule/>
<link-entry id="entry" label="Preview with entry"/> <link-entry id="entry" label="Preview with entry"/>
@ -23,6 +23,7 @@
<description id="preview_content"/> <description id="preview_content"/>
<buttononly background_image="true" id="insert_content" label="Insert" <buttononly background_image="true" id="insert_content" label="Insert"
statustext="Insert merged content" statustext="Insert merged content"
align="right"
image="export"></buttononly> image="export"></buttononly>
</hbox> </hbox>
</vbox> </vbox>

View File

@ -6,7 +6,7 @@
<vbox id="outer_box"> <vbox id="outer_box">
<vbox id="selects"> <vbox id="selects">
<select id="app"/> <select id="app"/>
<select id="placeholder_list"/> <et2-listbox id="placeholder_list" rows="10"/>
</vbox> </vbox>
<hrule/> <hrule/>
<link-entry id="entry" label="Select entry" only_app="addressbook"/> <link-entry id="entry" label="Select entry" only_app="addressbook"/>