From 7937a5b33ad51581b84897faaa597b4609fe12ca Mon Sep 17 00:00:00 2001 From: Alexey Koshelev Date: Tue, 25 Feb 2025 16:36:12 +0300 Subject: [PATCH] Add ui component ListView --- .../content/ai/components/ListView/script.js | 175 ++++++++++++++++++ .../content/ai/components/ListView/style.css | 85 +++++++++ 2 files changed, 260 insertions(+) create mode 100644 sdkjs-plugins/content/ai/components/ListView/script.js create mode 100644 sdkjs-plugins/content/ai/components/ListView/style.css diff --git a/sdkjs-plugins/content/ai/components/ListView/script.js b/sdkjs-plugins/content/ai/components/ListView/script.js new file mode 100644 index 00000000..c4951c24 --- /dev/null +++ b/sdkjs-plugins/content/ai/components/ListView/script.js @@ -0,0 +1,175 @@ +function ListView($el, options) { + this._init = function() { + var defaults = { + emptyText: '', + renderItem: function(item, index) { + var itemEl = document.createElement('div'); + itemEl.classList.add('item'); + itemEl.innerText = item.label; + return itemEl; + } + }; + this.options = Object.assign({}, defaults, options); + + $el.classList.add('list-view'); + this.$el = $el; + this.list = []; + this.selectedItem = null; + this.events = { + set: [], + add: [], + edit: [], + delete: [], + select: [], + deselect: [], + }; + + this._render(); + }; + + this._render = function() { + var me = this; + this.$el.innerHTML = ''; + if(this.list.length > 0) { + this.list.forEach(function(item, index) { + let itemEl = me.options.renderItem(item, index); + itemEl.addEventListener('click', function() { + me.setSelected(index); + }); + me.$el.appendChild(itemEl); + }); + } else if(this.options.emptyText) { + let emptyEl = document.createElement('div'); + emptyEl.innerText = this.options.emptyText; + emptyEl.classList.add('empty-text'); + this.$el.appendChild(emptyEl); + } + }; + + this._trigger = function(event, data) { + if(this.events[event]) { + this.events[event].forEach(function(callback) { + callback(data); + }); + } + }; + + this.getList = function() { + return this.list; + }; + + this.set = function(list) { + this.list = list; + this._render(); + if(list.length > 0) { + this.setSelected(0); + } else { + this.deselect(); + } + scrollbarList.update(); + scrollbarList.update(); + + this._trigger('set', list); + }; + + this.add = function(item) { + this.list.push(item); + this._render(); + this.setSelected(this.list.length - 1); + this.$el.scrollTop = this.$el.scrollHeight; + scrollbarList.update(); + scrollbarList.update(); + + this._trigger('add', item); + }; + + this.edit = function(item) { + var findedItem = this.list.filter(function(el) { + return el.id == item.id; + })[0]; + + if(!findedItem) return; + + for (var key in item) { + if (findedItem[key]) { + findedItem[key] = item[key]; + } + } + this._render(); + + this._trigger('edit', findedItem, item); + }; + + this.delete = function(item) { + var indexDeletedItem = this.list.indexOf(item); + if(indexDeletedItem != -1) { + this.list = this.list.filter(function(el) { + return el != item; + }); + this._render(); + + if(this.list.length == 0) { + this.deselect(); + } else if(indexDeletedItem < this.list.length) { + this.setSelected(indexDeletedItem); + } else { + this.setSelected(this.list.length - 1); + } + + this._trigger('delete', item); + } + }; + + this.deleteByIndex = function(index) { + if(!this.list[index]) return; + + this.delete(this.list[index]); + }; + + this.setSelected = function(index) { + if(this.list.length == 0) return; + + if(index == -1) { + index = this.list.length - 1; + } + if(!this.list[index]) return; + + this.deselect(); + this.selectedItem = this.list[index]; + this.$el.children[index].classList.add('selected'); + + this._trigger('select', this.selectedItem); + }; + + this.getSelected = function() { + return this.selectedItem; + }; + + this.deselect = function() { + var previouslySelectedItem = this.selectedItem; + this.selectedItem = null; + + var itemsEl = this.$el.getElementsByClassName('item'); + for (var i = 0; i < itemsEl.length; i++) { + itemsEl[i].classList.remove('selected'); + } + + if (previouslySelectedItem) { + this._trigger('deselect', previouslySelectedItem); + } + }; + + this.setEmptyText = function(text) { + this.options.emptyText = text; + this._render(); + }; + + this.on = function(event, callback) { + if(this.events[event]) { + this.events[event].push(callback); + } + }; + + + this._init(); +} diff --git a/sdkjs-plugins/content/ai/components/ListView/style.css b/sdkjs-plugins/content/ai/components/ListView/style.css new file mode 100644 index 00000000..85816076 --- /dev/null +++ b/sdkjs-plugins/content/ai/components/ListView/style.css @@ -0,0 +1,85 @@ +.list-view { + flex: 1; + border: 1px solid; + position: relative; +} +.list-view .item { + padding: 6px; + cursor: pointer; + border-bottom: 1px solid; +} + +.list-view .empty-text { + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +/* Themes style for Models List */ +body.theme-classic-light .list-view { + border-color: #cfcfcf; +} +body.theme-light .list-view, +body.theme-gray .list-view { + border-color: #c0c0c0; +} +body.theme-dark .list-view { + border-color: #666; +} +body.theme-contrast-dark .list-view { + border-color: #696969; +} + +/* Themes style for Item Models List */ +body.theme-classic-light .list-view .item { + border-color: #cfcfcf; +} +body.theme-classic-light .list-view .item:hover { + background-color: #d8dadc; + color: #444; +} +body.theme-classic-light .list-view .item.selected { + background-color: #7d858c; + color: #fff; +} + +body.theme-light .list-view .item, +body.theme-gray .list-view .item { + border-color: #c0c0c0; +} +body.theme-light .list-view .item:hover, +body.theme-gray .list-view .item:hover { + background-color: #e0e0e0; + color: rgba(0, 0, 0, 0.8); +} +body.theme-light .list-view .item.selected, +body.theme-gray .list-view .item.selected { + background-color: #cbcbcb; + color: rgba(0, 0, 0, 0.8); +} + +body.theme-dark .list-view .item { + border-color: #666; +} +body.theme-dark .list-view .item:hover { + background-color: #555; + color: rgba(255, 255, 255, 0.8); +} +body.theme-dark .list-view .item.selected { + background-color: #707070; + color: rgba(255, 255, 255, 0.8); +} + +body.theme-contrast-dark .list-view .item { + border-color: #696969; +} +body.theme-contrast-dark .list-view .item:hover { + background-color: #424242; + color: #e8e8e8; +} +body.theme-contrast-dark .list-view .item.selected { + background-color: #666666; + color: #e8e8e8; +} \ No newline at end of file