diff --git a/api/js/etemplate/Et2Taglist/Et2Taglist.ts b/api/js/etemplate/Et2Taglist/Et2Taglist.ts new file mode 100644 index 0000000000..92a82fb8d7 --- /dev/null +++ b/api/js/etemplate/Et2Taglist/Et2Taglist.ts @@ -0,0 +1,106 @@ +/** + * EGroupware eTemplate2 - Colorpicker widget (WebComponent) + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage api + * @link https://www.egroupware.org + * @author Hadi Nategh + */ + + + +import {css, html, LitElement} from "@lion/core"; +import { ScopedElementsMixin } from '@open-wc/scoped-elements'; +import {TaglistOption, TaglistOptionEmail} from "./TaglistOption"; +import {TaglistComboBox} from "./TaglistComboBox"; +import {Et2widgetWithSelectMixin} from "../Et2Select/Et2WidgetWithSelectMixin"; +import {TaglistSelection} from "./TaglistSelection"; + +/** + * Taglist base class implementation + */ +export class Et2Taglist extends Et2widgetWithSelectMixin(ScopedElementsMixin(LitElement)) +{ + static get styles() + { + return [ + ...super.styles, + css` + :host { + display: block; + } + ` + ]; + } + static get properties() + { + return { + ...super.properties, + multiple : {type : Boolean}, + + + } + } + + constructor() + { + super(); + + } + + // can be overriden for other taglist type implementations + static get taglistOptionImp () {return TaglistOption}; + static get taglistComboboxImp () {return TaglistComboBox}; + static get taglistSelectionImp () {return TaglistSelection}; + + static get scopedElements() { + return { + 'taglist-combobox': this.taglistComboboxImp, + 'taglist-option': this.taglistOptionImp, + 'taglist-selection': this.taglistSelectionImp + }; + } + + _setOptionTemplate() + { + return html` + ${this.get_select_options().map(entry => html` ${entry.label} `)} + `; + } + + render() + { + return html` + + + ${this._setOptionTemplate()} + + `; + } +} +customElements.define('et2-taglist', Et2Taglist); + + +/** + * Taglist-email implementation + */ +export class Et2TaglistEmail extends Et2Taglist +{ + static get taglistOptionImp () {return TaglistOptionEmail}; + + _setOptionTemplate() + { + //@todo: needs to be implemented + return super._setOptionTemplate(); + } + + get_select_options(): any + { + //@todo: needs to be implemented + return super.get_select_options(); + } +} +customElements.define('et2-taglist-email', Et2TaglistEmail); \ No newline at end of file diff --git a/api/js/etemplate/Et2Taglist/Et2TaglistEmail.ts b/api/js/etemplate/Et2Taglist/Et2TaglistEmail.ts new file mode 100644 index 0000000000..08f80f0f51 --- /dev/null +++ b/api/js/etemplate/Et2Taglist/Et2TaglistEmail.ts @@ -0,0 +1,19 @@ + +export class Et2TaglistEmail extends Et2Taglist +{ + static get taglist_option () {return TaglistOptionEmail}; + + _setOptionTemplate() + { + return html` + ${this.get_select_options().map(entry => html` ${entry.label} `)} + `; + } + + get_select_options(): any + { + //@todo: override it accordingly + return super.get_select_options(); + } +} +customElements.define('et2-taglist-email', Et2TaglistEmail); \ No newline at end of file diff --git a/api/js/etemplate/Et2Taglist/TaglistComboBox.ts b/api/js/etemplate/Et2Taglist/TaglistComboBox.ts new file mode 100644 index 0000000000..e553100cb3 --- /dev/null +++ b/api/js/etemplate/Et2Taglist/TaglistComboBox.ts @@ -0,0 +1,48 @@ + +/** + * EGroupware eTemplate2 - TaglistComboBox widget (WebComponent) + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage api + * @link https://www.egroupware.org + * @author Hadi Nategh + */ + + + +import { LionCombobox } from '@lion/combobox'; +import {css} from "@lion/core"; + + +export class TaglistComboBox extends LionCombobox { + static get properties() { + return { + ...super.properties, + + }; + } + static get styles() { + return [ + super.styles, + css` + ::slotted([slot='input']) { + min-height: 23px; + + } + :host { + border: 1px solid var(--taglist-combobox__container-boder-color); + border-radius: 3px; + } + `, + ]; + } + constructor() + { + super(); + } +} +customElements.define('taglist-combobox', TaglistComboBox); + + + diff --git a/api/js/etemplate/Et2Taglist/TaglistOption.ts b/api/js/etemplate/Et2Taglist/TaglistOption.ts new file mode 100644 index 0000000000..98e5d1e9d8 --- /dev/null +++ b/api/js/etemplate/Et2Taglist/TaglistOption.ts @@ -0,0 +1,54 @@ +/** + * EGroupware eTemplate2 - TaglistOption widget (WebComponent) + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage api + * @link https://www.egroupware.org + * @author Hadi Nategh + */ + +import { LionOption } from '@lion/listbox'; +import {css, html} from "@lion/core"; + + +export class TaglistOption extends LionOption { + + static get properties() { + return { + ...super.properties, + title: { + type: String, + }, + }; + } + constructor() { + super(); + this.title = ''; + + } + + static get styles() { + return [ + ...super.styles, + css` + :host([checked]) { + visibility: hidden; + } + `, + ]; + } + +} + +export class TaglistOptionEmail extends TaglistOption { + +} + +export class TaglistOptionState extends TaglistOption { + +} + +export class TaglistOptionCategory extends TaglistOption { + +} \ No newline at end of file diff --git a/api/js/etemplate/Et2Taglist/TaglistSelection.ts b/api/js/etemplate/Et2Taglist/TaglistSelection.ts new file mode 100644 index 0000000000..a578ad407e --- /dev/null +++ b/api/js/etemplate/Et2Taglist/TaglistSelection.ts @@ -0,0 +1,202 @@ +/** + * EGroupware eTemplate2 - TaglistSelection (WebComponent) + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage api + * @link https://www.egroupware.org + * @author Hadi Nategh + */ + + + +import {css, html, LitElement} from "@lion/core"; +import {TaglistComboBox} from "./TaglistComboBox"; +import {taglistStyles} from "./TaglistStyles"; + + +/** + * Implementation of selection tags + */ +export class TaglistSelection extends LitElement { + static get properties() { + return { + selectedTags: Array, + comboxElement: TaglistComboBox, + canBeClosed: Boolean, + canBeEdited: Boolean + } + }; + + static get styles() { + return [ + taglistStyles, + css` + :host { + display: flex; + } + + .taglist-selection__tags { + flex: none; + } + + .combobox__input { + display: block; + } + + .taglist-selection__tag { + margin: 0 5px 3px 0; + padding: 3px 20px 3px 5px; + border: 1px solid var(--taglist-selection__tag-boder-color); + border-radius: 3px; + background-color: var(--taglist-selection__tag-bg-color); + background-image: var(--taglist-selection__tag-bg-img); + background-clip: padding-box; + box-shadow: var(--taglist-selection__tag-box-shadow); + color: var(--taglist-selection__tag-color); + line-height: 13px; + font-size: 11px; + white-space: normal; + max-width: calc(100% - 30px); + display:flex; + } + .tag-label { + display:flex; + } + .tag-closeBtn{ + width: 10px; + height: 10px; + background-position: 0 -10px; + background-size: cover; + background-repeat: no-repeat; + display:flex; + background-image: var(--tag-closeBtn-img); + } + ` + ]; + } + + /** + * + */ + get _inputNode() { + return this._getComboBoxElement()._inputNode; + } + + + /** + * @return {TaglistComboBox} returns comboboxElement from TaglistComboBox + */ + _getComboBoxElement() + { + // @ts-ignore + return this.comboboxElement; + } + + /** + * @private + * @return returns checked formElements + */ + __getSelectedTags() { + return this._getComboBoxElement().formElements.filter((_tags) => { + return _tags.checked; + } + ); + } + + get multipleChoice() { + return this._getComboBoxElement()?.multipleChoice; + } + + + constructor() { + super(); + + this.selectedTags = []; + this.__handleCloseBtn = this.__handleCloseBtn.bind(this); + this.__handleEditBtn = this.__handleEditBtn.bind(this); + this.__inputOnKeyup = this.__inputOnKeyup.bind(this); + + } + + /** + * + * @param changedProperties + */ + firstUpdated(changedProperties) { + super.firstUpdated(changedProperties); + + if (this.multipleChoice) { + this._inputNode.addEventListener('keyup', this.__inputOnKeyup); + } + } + + /** + * + * @param changedProperties + */ + onComboboxElementUpdated(changedProperties) { + if (changedProperties.has('modelValue')) { + this.selectedTags = this.__getSelectedTags(); + } + } + + __handleEditBtn() + { + console.log('editBtn') + } + + __handleCloseBtn(_v) + { + console.log('closeBtn') + } + + /** + * + * @param option + */ + _selectedTagTemplate(option) { + return html` +
+ ${this._canBeEdited? html``:''} + ${option.value} + ${this._canBeClosed? html``:''} +
+ `; + } + + /** + * + */ + _selectedTagsTemplate() { + return html` +
+ ${this.selectedTags.map((option) => { + return this._selectedTagTemplate(option); + })} +
+ `; + } + + /** + * + */ + render() { + return html` ${this._selectedTagsTemplate()} `; + } + + /** + * @private + * @param ev + */ + __inputOnKeyup(ev) { + if (ev.key === 'Backspace') { + if (!this._inputNode.value) { + if (this.selectedTags.length) { + this.selectedTags[this.selectedTags.length - 1].checked = false; + } + } + } + } +} +customElements.define('taglist-selection', TaglistSelection); diff --git a/api/js/etemplate/Et2Taglist/TaglistStyles.ts b/api/js/etemplate/Et2Taglist/TaglistStyles.ts new file mode 100644 index 0000000000..d25a41ee71 --- /dev/null +++ b/api/js/etemplate/Et2Taglist/TaglistStyles.ts @@ -0,0 +1,20 @@ +/** + * styles constant + */ + +import {css} from "@lion/core"; + +export const taglistStyles = css` + :host { + /****** images ************/ + --tag-closeBtn-img : url(data:image/png;base64,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); + --taglist-selection__tag-bg-img : linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%); + + /****** colors ************/ + --taglist-combobox__container-boder-color : silver; + --taglist-selection__tag-boder-color : #aaa; + --taglist-selection__tag-bg-color : #e4e4e4; + --taglist-selection__tag-color : #333; + --taglist-selection__tag-box-shadow : 0 0 2px #fff inset, 0 1px 0 rgb(0 0 0 / 5%); + } +`; \ No newline at end of file diff --git a/api/js/etemplate/etemplate2.ts b/api/js/etemplate/etemplate2.ts index 70e495bd73..13fa14d783 100644 --- a/api/js/etemplate/etemplate2.ts +++ b/api/js/etemplate/etemplate2.ts @@ -43,6 +43,8 @@ import './Et2Textarea/Et2Textarea'; import './Et2Textbox/Et2Textbox'; import './Et2Textbox/Et2TextboxReadonly'; import './Et2Colorpicker/Et2Colorpicker'; +import './Et2Taglist/Et2Taglist'; + /* Include all widget classes here, we only care about them registering, not importing anything*/ import './et2_widget_vfs'; // Vfs must be first (before et2_widget_file) due to import cycle import './et2_widget_template';