diff options
| author | Tara Rostami <132676256+TaraRostami@users.noreply.github.com> | 2024-04-20 21:45:36 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-20 21:45:36 +0300 |
| commit | db24d216210e0038f92e634de1ab8a46fbce4632 (patch) | |
| tree | 3648326a1e359543febd865747822bc6f8f72781 /web/html | |
| parent | 3d5c06bf08f0ede7206e0ef39966d6be2106a225 (diff) | |
UI Improvements (#2228)
* UI Improvements
Better Table
Update QR Code Modal
Better Info Modal
Compression HTML files
Better Dropdown Menu
Better Calendar
and more ..
Remove files
Minor Fixes
Diffstat (limited to 'web/html')
25 files changed, 2543 insertions, 2392 deletions
diff --git a/web/html/common/head.html b/web/html/common/head.html index b2533098..6c195db5 100644 --- a/web/html/common/head.html +++ b/web/html/common/head.html @@ -1,32 +1,32 @@ {{define "head"}} <head> - <meta charset="UTF-8"> - <meta name="renderer" content="webkit"> - <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="stylesheet" href="{{ .base_path }}assets/ant-design-vue@1.7.8/antd.min.css"> - <link rel="stylesheet" href="{{ .base_path }}assets/element-ui@2.15.0/theme-chalk/display.css"> - <link rel="stylesheet" href="{{ .base_path }}assets/css/custom.css?{{ .cur_ver }}"> - <style> - [v-cloak] { - display: none; - } - /* vazirmatn-regular - arabic_latin_latin-ext */ - @font-face { - font-display: swap; - font-family: 'Vazirmatn'; - font-style: normal; - font-weight: 400; - src: url('{{ .base_path }}assets/Vazirmatn-UI-NL-Regular.woff2') format('woff2'); - unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC, U+0030-0039; - } - body { - font-family: -apple-system, BlinkMacSystemFont, 'Vazirmatn', 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', - 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', - 'Segoe UI Emoji', 'Segoe UI Symbol'; - } - </style> - <title>{{ .host }}-{{ i18n .title}}</title> + <meta charset="UTF-8"> + <meta name="renderer" content="webkit"> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" href="{{ .base_path }}assets/ant-design-vue@1.7.8/antd.min.css"> + <link rel="stylesheet" href="{{ .base_path }}assets/element-ui@2.15.0/theme-chalk/display.css"> + <link rel="stylesheet" href="{{ .base_path }}assets/css/custom.min.css?{{ .cur_ver }}"> + <style> + [v-cloak] { + display: none; + } + /* vazirmatn-regular - arabic_latin_latin-ext */ + @font-face { + font-display: swap; + font-family: 'Vazirmatn'; + font-style: normal; + font-weight: 400; + src: url('{{ .base_path }}assets/Vazirmatn-UI-NL-Regular.woff2') format('woff2'); + unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC, U+0030-0039; + } + body { + font-family: -apple-system, BlinkMacSystemFont, 'Vazirmatn', 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', + 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol'; + } + </style> + <title>{{ .host }}-{{ i18n .title}}</title> </head> <div id="message"></div> {{end}}
\ No newline at end of file diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html index 524335cf..fd5a17b7 100644 --- a/web/html/common/qrcode_modal.html +++ b/web/html/common/qrcode_modal.html @@ -1,110 +1,165 @@ {{define "qrcodeModal"}} <a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title" - :dialog-style="{ top: '20px' }" + :dialog-style="isMobileQr ? { top: '18px' } : {}" :closable="true" :class="themeSwitcher.currentTheme" - :footer="null" width="300px"> - <a-tag color="green" style="margin-bottom: 10px;display: block;text-align: center;"> - {{ i18n "pages.inbounds.clickOnQRcode" }} - </a-tag> - <template v-if="app.subSettings.enable && qrModal.subId"> - <a-divider>{{ i18n "pages.settings.subSettings"}}</a-divider> - <div class="qr-bg"><canvas @click="copyToClipboard('qrCode-sub',genSubLink(qrModal.client.subId))" id="qrCode-sub" class="qr-cv"></canvas></div> - <a-divider>{{ i18n "pages.settings.subSettings"}} Json</a-divider> - <div class="qr-bg"><canvas @click="copyToClipboard('qrCode-subJson',genSubJsonLink(qrModal.client.subId))" id="qrCode-subJson" class="qr-cv"></canvas></div> - </template> - <a-divider>{{ i18n "pages.inbounds.client" }}</a-divider> - <template v-for="(row, index) in qrModal.qrcodes"> - <a-tag color="green" style="margin: 10px 0; display: block; text-align: center;">[[ row.remark ]]</a-tag> - <div class="qr-bg"><canvas @click="copyToClipboard('qrCode-'+index, row.link)" :id="'qrCode-'+index" class="qr-cv"></canvas></div> - </template> + :footer="null" width="fit-content"> + <tr-qr-modal class="qr-modal"> + <template v-if="app.subSettings.enable && qrModal.subId"> + <tr-qr-box class="qr-box"> + <a-tag color="purple" class="qr-tag"><span>{{ i18n "pages.settings.subSettings"}}</span></a-tag> + <tr-qr-bg class="qr-bg-sub"> + <tr-qr-bg-inner class="qr-bg-sub-inner"> + <canvas @click="copyToClipboard('qrCode-sub',genSubLink(qrModal.client.subId))" id="qrCode-sub" class="qr-cv"></canvas> + </tr-qr-bg-inner> + </tr-qr-bg> + </tr-qr-box> + <tr-qr-box class="qr-box"> + <a-tag color="purple" class="qr-tag"><span>{{ i18n "pages.settings.subSettings"}} Json</span></a-tag> + <tr-qr-bg class="qr-bg-sub"> + <tr-qr-bg-inner class="qr-bg-sub-inner"> + <canvas @click="copyToClipboard('qrCode-subJson',genSubJsonLink(qrModal.client.subId))" id="qrCode-subJson" class="qr-cv"></canvas> + </tr-qr-bg-inner> + </tr-qr-bg> + </tr-qr-box> + </template> + <template v-for="(row, index) in qrModal.qrcodes"> + <tr-qr-box class="qr-box"> + <a-tag color="green" class="qr-tag"><span>[[ row.remark ]]</span></a-tag> + <tr-qr-bg class="qr-bg"> + <canvas @click="copyToClipboard('qrCode-'+index, row.link)" :id="'qrCode-'+index" class="qr-cv"></canvas> + </tr-qr-bg> + </tr-qr-box> + </template> + </tr-qr-modal> </a-modal> <script> + const isMobileQr = window.innerWidth <= 768; + const qrModal = { + title: '', + dbInbound: new DBInbound(), + client: null, + qrcodes: [], + clipboard: null, + visible: false, + subId: '', + show: function(title = '', dbInbound, client) { + this.title = title; + this.dbInbound = dbInbound; + this.inbound = dbInbound.toInbound(); + this.client = client; + this.subId = ''; + this.qrcodes = []; + if (this.inbound.protocol == Protocols.WIREGUARD) { + this.inbound.genInboundLinks(dbInbound.remark).split('\r\n').forEach((l, index) => { + this.qrcodes.push({ + remark: "Peer " + (index + 1), + link: l + }); + }); + } else { + this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, client).forEach(l => { + this.qrcodes.push({ + remark: l.remark, + link: l.link + }); + }); + } + this.visible = true; + }, + close: function() { + this.visible = false; + }, + }; + const qrModalApp = new Vue({ + delimiters: ['[[', ']]'], + el: '#qrcode-modal', + data: { + qrModal: qrModal, + }, + methods: { + copyToClipboard(elmentId, content) { + this.qrModal.clipboard = new ClipboardJS('#' + elmentId, { + text: () => content, + }); + this.qrModal.clipboard.on('success', () => { + app.$message.success('{{ i18n "copied" }}') + this.qrModal.clipboard.destroy(); + }); + }, + setQrCode(elmentId, content) { + new QRious({ + element: document.querySelector('#' + elmentId), + size: 400, + value: content, + background: 'white', + backgroundAlpha: 0, + foreground: 'black', + padding: 2, + level: 'L' + }); + }, + genSubLink(subID) { + return app.subSettings.subURI + subID; + }, + genSubJsonLink(subID) { + return app.subSettings.subJsonURI + subID; + }, + revertOverflow() { + const elements = document.querySelectorAll(".qr-tag"); + elements.forEach((element) => { + element.classList.remove("tr-marquee"); + element.children[0].style.animation = ''; + while (element.children.length > 1) { + element.removeChild(element.lastChild); + } + }); + } + }, + updated() { + if (this.qrModal.visible) { + fixOverflow(); + } else { + this.revertOverflow(); + } + if (qrModal.client && qrModal.client.subId) { + qrModal.subId = qrModal.client.subId; + this.setQrCode("qrCode-sub", this.genSubLink(qrModal.subId)); + this.setQrCode("qrCode-subJson", this.genSubJsonLink(qrModal.subId)); + } + qrModal.qrcodes.forEach((element, index) => { + this.setQrCode("qrCode-" + index, element.link); + }); + } + }); - const qrModal = { - title: '', - dbInbound: new DBInbound(), - client: null, - qrcodes: [], - clipboard: null, - visible: false, - subId: '', - show: function (title = '', dbInbound, client) { - this.title = title; - this.dbInbound = dbInbound; - this.inbound = dbInbound.toInbound(); - this.client = client; - this.subId = ''; - this.qrcodes = []; - if (this.inbound.protocol == Protocols.WIREGUARD){ - this.inbound.genInboundLinks(dbInbound.remark).split('\r\n').forEach((l,index) =>{ - this.qrcodes.push({ - remark: "Peer " + (index+1), - link: l - }); - }); - } else { - this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, client).forEach(l => { - this.qrcodes.push({ - remark: l.remark, - link: l.link - }); - }); - } - this.visible = true; - }, - close: function () { - this.visible = false; - }, - }; + function fixOverflow() { + const elements = document.querySelectorAll(".qr-tag"); + elements.forEach((element) => { + function isElementOverflowing(element) { + const overflowX = element.offsetWidth < element.scrollWidth, + overflowY = element.offsetHeight < element.scrollHeight; + return overflowX || overflowY; + } - const qrModalApp = new Vue({ - delimiters: ['[[', ']]'], - el: '#qrcode-modal', - data: { - qrModal: qrModal, - }, - methods: { - copyToClipboard(elmentId, content) { - this.qrModal.clipboard = new ClipboardJS('#' + elmentId, { - text: () => content, - }); - this.qrModal.clipboard.on('success', () => { - app.$message.success('{{ i18n "copied" }}') - this.qrModal.clipboard.destroy(); - }); - }, - setQrCode(elmentId, content) { - new QRious({ - element: document.querySelector('#' + elmentId), - size: 400, - value: content, - background: 'white', - backgroundAlpha: 0, - foreground: 'black', - padding: 2, - level: 'L' - }); - }, - genSubLink(subID) { - return app.subSettings.subURI+subID; - }, - genSubJsonLink(subID) { - return app.subSettings.subJsonURI+subID; - } - }, - updated() { - if (qrModal.client && qrModal.client.subId) { - qrModal.subId = qrModal.client.subId; - this.setQrCode("qrCode-sub", this.genSubLink(qrModal.subId)); - this.setQrCode("qrCode-subJson", this.genSubJsonLink(qrModal.subId)); - } - qrModal.qrcodes.forEach((element, index) => { - this.setQrCode("qrCode-" + index, element.link); - }); + function wrapContentsInMarquee(element) { + element.classList.add("tr-marquee"); + element.children[0].style.animation = `move-ltr ${ + (element.children[0].clientWidth / element.clientWidth) * 5 + }s ease-in-out infinite`; + const marqueeText = element.children[0]; + if (element.children.length < 2) { + for (let i = 0; i < 1; i++) { + const marqueeText = element.children[0].cloneNode(true); + element.children[0].after(marqueeText); + } } + } + if (isElementOverflowing(element)) { + wrapContentsInMarquee(element); + } }); - + } </script> {{end}} diff --git a/web/html/login.html b/web/html/login.html index dfb01cea..ae6bfde5 100644 --- a/web/html/login.html +++ b/web/html/login.html @@ -400,7 +400,7 @@ </g> </svg> </div> - <a-row type="flex" justify="center" align="middle" style="height: 100%; overflow: auto;"> + <a-row type="flex" justify="center" align="middle" style="height: 100%; overflow: auto; overflow-x: hidden;"> <a-col :xs="22" :sm="20" :md="14" :lg="10" :xl="8" :xxl="6" id="login" style="margin: 3rem 0;"> <a-row type="flex" justify="center"> <a-col style="width: 100%;"> @@ -461,7 +461,7 @@ </a-form-item> <a-form-item> <a-row justify="center" class="centered"> - <theme-switch></theme-switch> + <theme-switch-login></theme-switch-login> </a-row> </a-form-item> </a-form> @@ -476,83 +476,82 @@ {{template "component/themeSwitcher" .}} {{template "component/password" .}} <script> - class User { - constructor() { - this.username = ""; - this.password = ""; - } + class User { + constructor() { + this.username = ""; + this.password = ""; } - - const app = new Vue({ - delimiters: ['[[', ']]'], - el: '#app', - data: { - themeSwitcher, - loading: false, - user: new User(), - secretEnable: false, - lang: "" - }, - async created() { - this.lang = getLang(); - this.secretEnable = await this.getSecretStatus(); - }, - methods: { - async login() { - this.loading = true; - const msg = await HttpUtil.post('/login', this.user); - this.loading = false; - if (msg.success) { - location.href = basePath + 'panel/'; - } - }, - async getSecretStatus() { - this.loading = true; - const msg = await HttpUtil.post('/getSecretStatus'); - this.loading = false; - if (msg.success) { - this.secretEnable = msg.obj; - return msg.obj; - } - }, - }, - }); - document.addEventListener("DOMContentLoaded", function() { - var animationDelay = 2000; - initHeadline(); - - function initHeadline() { - animateHeadline(document.querySelectorAll('.headline')); + } + const app = new Vue({ + delimiters: ['[[', ']]'], + el: '#app', + data: { + themeSwitcher, + loading: false, + user: new User(), + secretEnable: false, + lang: "" + }, + async created() { + this.lang = getLang(); + this.secretEnable = await this.getSecretStatus(); + }, + methods: { + async login() { + this.loading = true; + const msg = await HttpUtil.post('/login', this.user); + this.loading = false; + if (msg.success) { + location.href = basePath + 'panel/'; } - - function animateHeadline(headlines) { - var duration = animationDelay; - headlines.forEach(function(headline) { - setTimeout(function() { - hideWord(headline.querySelector('.is-visible')); - }, duration); - }); + }, + async getSecretStatus() { + this.loading = true; + const msg = await HttpUtil.post('/getSecretStatus'); + this.loading = false; + if (msg.success) { + this.secretEnable = msg.obj; + return msg.obj; } + }, + }, + }); + document.addEventListener("DOMContentLoaded", function() { + var animationDelay = 2000; + initHeadline(); - function hideWord(word) { - var nextWord = takeNext(word); - switchWord(word, nextWord); - setTimeout(function() { - hideWord(nextWord); - }, animationDelay); - } + function initHeadline() { + animateHeadline(document.querySelectorAll('.headline')); + } - function takeNext(word) { - return (word.nextElementSibling) ? word.nextElementSibling : word.parentElement.firstElementChild; - } + function animateHeadline(headlines) { + var duration = animationDelay; + headlines.forEach(function(headline) { + setTimeout(function() { + hideWord(headline.querySelector('.is-visible')); + }, duration); + }); + } - function switchWord(oldWord, newWord) { - oldWord.classList.remove('is-visible'); - oldWord.classList.add('is-hidden'); - newWord.classList.remove('is-hidden'); - newWord.classList.add('is-visible'); - } - }); + function hideWord(word) { + var nextWord = takeNext(word); + switchWord(word, nextWord); + setTimeout(function() { + hideWord(nextWord); + }, animationDelay); + } + + function takeNext(word) { + return (word.nextElementSibling) ? word.nextElementSibling : word.parentElement.firstElementChild; + } + + function switchWord(oldWord, newWord) { + oldWord.classList.remove('is-visible'); + oldWord.classList.add('is-hidden'); + newWord.classList.remove('is-hidden'); + newWord.classList.add('is-visible'); + } + }); </script> </body> </html> diff --git a/web/html/xui/common_sider.html b/web/html/xui/common_sider.html index bc8f4608..df659489 100644 --- a/web/html/xui/common_sider.html +++ b/web/html/xui/common_sider.html @@ -1,61 +1,65 @@ {{define "menuItems"}} <a-menu-item key="{{ .base_path }}panel/"> - <a-icon type="dashboard"></a-icon> - <span><b>{{ i18n "menu.dashboard"}}</b></span> + <a-icon type="dashboard"></a-icon> + <span> + <b>{{ i18n "menu.dashboard"}}</b> + </span> </a-menu-item> <a-menu-item key="{{ .base_path }}panel/inbounds"> - <a-icon type="user"></a-icon> - <span><b>{{ i18n "menu.inbounds"}}</b></span> + <a-icon type="user"></a-icon> + <span> + <b>{{ i18n "menu.inbounds"}}</b> + </span> </a-menu-item> <a-menu-item key="{{ .base_path }}panel/settings"> - <a-icon type="setting"></a-icon> - <span><b>{{ i18n "menu.settings"}}</b></span> + <a-icon type="setting"></a-icon> + <span> + <b>{{ i18n "menu.settings"}}</b> + </span> </a-menu-item> <a-menu-item key="{{ .base_path }}panel/xray"> - <a-icon type="tool"></a-icon> - <span><b>{{ i18n "menu.xray"}}</b></span> + <a-icon type="tool"></a-icon> + <span> + <b>{{ i18n "menu.xray"}}</b> + </span> </a-menu-item> <a-menu-item key="{{ .base_path }}logout"> - <a-icon type="logout"></a-icon> - <span><b>{{ i18n "menu.logout"}}</b></span> + <a-icon type="logout"></a-icon> + <span> + <b>{{ i18n "menu.logout"}}</b> + </span> </a-menu-item> {{end}} {{define "commonSider"}} -<a-layout-sider :theme="themeSwitcher.currentTheme" id="sider" collapsible breakpoint="md" collapsed-width="0"> - <theme-switch></theme-switch> - <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="['{{ .request_uri }}']" - @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> - {{template "menuItems" .}} - </a-menu> +<a-layout-sider :theme="themeSwitcher.currentTheme" id="sider" collapsible breakpoint="md"> + <theme-switch></theme-switch> + <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="['{{ .request_uri }}']" @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> + {{template "menuItems" .}} + </a-menu> </a-layout-sider> -<a-drawer id="sider-drawer" placement="left" :closable="false" - @close="siderDrawer.close()" - :visible="siderDrawer.visible" - :wrap-class-name="themeSwitcher.currentTheme" - :wrap-style="{ padding: 0 }"> - <div class="drawer-handle" @click="siderDrawer.change()" slot="handle"> - <a-icon :type="siderDrawer.visible ? 'close' : 'menu-fold'"></a-icon> - </div> - <theme-switch></theme-switch> - <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="['{{ .request_uri }}']" - @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> - {{template "menuItems" .}} - </a-menu> +<a-drawer id="sider-drawer" placement="left" :closable="false" @close="siderDrawer.close()" :visible="siderDrawer.visible" :wrap-class-name="themeSwitcher.currentTheme" :wrap-style="{ padding: 0 }"> + <div class="drawer-handle" @click="siderDrawer.change()" slot="handle"> + <a-icon :type="siderDrawer.visible ? 'close' : 'menu-fold'"></a-icon> + </div> + <theme-switch></theme-switch> + <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="['{{ .request_uri }}']" @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> + {{template "menuItems" .}} + </a-menu> </a-drawer> <script> - const siderDrawer = { - visible: false, - show() { - this.visible = true; - }, - close() { - this.visible = false; - }, - change() { - this.visible = !this.visible; - }, - }; + const siderDrawer = { + visible: false, + show() { + this.visible = true; + }, + close() { + this.visible = false; + }, + change() { + this.visible = !this.visible; + }, + }; </script> {{end}} diff --git a/web/html/xui/component/sortableTable.html b/web/html/xui/component/sortableTable.html index 5eb2e1cc..f62eba44 100644 --- a/web/html/xui/component/sortableTable.html +++ b/web/html/xui/component/sortableTable.html @@ -1,236 +1,216 @@ {{define "component/sortableTableTrigger"}} - <a-icon type="drag" - class="sortable-icon" - style="cursor: move;" - @mouseup="mouseUpHandler" - @mousedown="mouseDownHandler" - @click="clickHandler" /> +<a-icon type="drag" + class="sortable-icon" + style="cursor: move;" + @mouseup="mouseUpHandler" + @mousedown="mouseDownHandler" + @click="clickHandler" /> {{end}} {{define "component/sortableTable"}} <script> - const DRAGGABLE_ROW_CLASS = 'draggable-row'; - - const findParentRowElement = (el) => { - if (!el || !el.tagName) { - return null; - } else if (el.classList.contains(DRAGGABLE_ROW_CLASS)) { - return el; - } else if (el.parentNode) { - return findParentRowElement(el.parentNode); - } else { - return null; - } + const DRAGGABLE_ROW_CLASS = 'draggable-row'; + const findParentRowElement = (el) => { + if (!el || !el.tagName) { + return null; + } else if (el.classList.contains(DRAGGABLE_ROW_CLASS)) { + return el; + } else if (el.parentNode) { + return findParentRowElement(el.parentNode); + } else { + return null; } - - Vue.component('a-table-sortable', { - data() { - return { - sortingElementIndex: null, - newElementIndex: null, - }; - }, - props: ['data-source', 'customRow'], - inheritAttrs: false, - provide() { - const sortable = {} - - Object.defineProperty(sortable, "setSortableIndex", { - enumerable: true, - get: () => this.setCurrentSortableIndex, - }); - - Object.defineProperty(sortable, "resetSortableIndex", { - enumerable: true, - get: () => this.resetSortableIndex, - }); - - return { - sortable, - } + } + Vue.component('a-table-sortable', { + data() { + return { + sortingElementIndex: null, + newElementIndex: null, + }; + }, + props: ['data-source', 'customRow'], + inheritAttrs: false, + provide() { + const sortable = {} + Object.defineProperty(sortable, "setSortableIndex", { + enumerable: true, + get: () => this.setCurrentSortableIndex, + }); + Object.defineProperty(sortable, "resetSortableIndex", { + enumerable: true, + get: () => this.resetSortableIndex, + }); + return { + sortable, + } + }, + render: function(createElement) { + return createElement('a-table', { + class: { + 'ant-table-is-sorting': this.isDragging(), }, - render: function (createElement) { - return createElement('a-table', { - class: { - 'ant-table-is-sorting': this.isDragging(), - }, - props: { - ...this.$attrs, - 'data-source': this.records, - customRow: (record, index) => this.customRowRender(record, index), - }, - on: this.$listeners, - nativeOn: { - drop: (e) => this.dropHandler(e), - }, - scopedSlots: this.$scopedSlots, - }, this.$slots.default, ) + props: { + ...this.$attrs, + 'data-source': this.records, + customRow: (record, index) => this.customRowRender(record, index), }, - created() { - this.$memoSort = {}; + on: this.$listeners, + nativeOn: { + drop: (e) => this.dropHandler(e), }, - methods: { - isDragging() { - const currentIndex = this.sortingElementIndex; - return currentIndex !== null && currentIndex !== undefined; - }, - resetSortableIndex(e, index) { - this.sortingElementIndex = null; - this.newElementIndex = null; - this.$memoSort = {}; - }, - setCurrentSortableIndex(e, index) { - this.sortingElementIndex = index; - }, - dragStartHandler(e, index) { - if (!this.isDragging()) { - e.preventDefault(); - return; - } - const hideDragImage = this.$el.cloneNode(true); - hideDragImage.id = "hideDragImage-hide"; - hideDragImage.style.opacity = 0; - e.dataTransfer.setDragImage(hideDragImage, 0, 0); - }, - dragStopHandler(e, index) { - const hideDragImage = document.getElementById('hideDragImage-hide'); - if (hideDragImage) hideDragImage.remove(); - this.resetSortableIndex(e, index); - }, - dragOverHandler(e, index) { - if (!this.isDragging()) { - return; - } - |
