fix: tooltip issue about customer follower
change: Grid.export optimized (compression with `deflate`) feature: ui-tab feature: Popup.closable
This commit is contained in:
@ -70,6 +70,10 @@ $buttonHeight: 28px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
>.ui-popup-header-title.no-move {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
>.ui-popup-header-icons {
|
||||
flex: 0 0 auto;
|
||||
padding: 10px 12px 6px 0;
|
||||
|
47
lib/ui/css/tab.scss
Normal file
47
lib/ui/css/tab.scss
Normal file
@ -0,0 +1,47 @@
|
||||
.ui-tab-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
--header-line-height: 24px;
|
||||
--header-padding: 6px 6px 0;
|
||||
--header-hover-color: #b9b9b9;
|
||||
--header-selected-color: rgb(173, 84, 12);
|
||||
|
||||
>.ui-tab-header {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
line-height: var(--header-line-height);
|
||||
padding: var(--header-padding);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
user-select: none;
|
||||
|
||||
>.ui-tab-title {
|
||||
border: 1px solid transparent;
|
||||
background-color: var(--bg-color);
|
||||
cursor: pointer;
|
||||
padding: 0 12px;
|
||||
|
||||
&:hover {
|
||||
color: var(--header-hover-color);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-color: var(--border-color);
|
||||
border-bottom-color: var(--bg-color);
|
||||
color: var(--header-selected-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.ui-tab-page {
|
||||
flex: 1 1 auto;
|
||||
padding: 6px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ import { GridColumn, GridInputColumn, GridTextColumn, GridDropdownColumn, GridCh
|
||||
* @version 1.0.2
|
||||
*/
|
||||
|
||||
const ScriptPath = (self.document == null ? self.location.href : self.document.currentScript.src).replace(/\?.+$/, '');
|
||||
|
||||
const ColumnChangedType = {
|
||||
Reorder: 'reorder',
|
||||
Resize: 'resize',
|
||||
@ -2092,7 +2094,7 @@ export class Grid {
|
||||
* }>
|
||||
* }
|
||||
* ```
|
||||
* @param {boolean} compressed - 是否压缩
|
||||
* @param {boolean} [compressed=true] - 是否采用 deflate 压缩
|
||||
* @returns {Promise<Uint8Array>} 返回 `Uint8Array` 数据对象
|
||||
* @since 1.0.2
|
||||
*/
|
||||
@ -2150,15 +2152,14 @@ export class Grid {
|
||||
sortKey: this.sortKey,
|
||||
sortArray: this.sortArray
|
||||
};
|
||||
const json = JSON.stringify(data);
|
||||
const uncompressed = json => new TextEncoder('utf-8').encode(json);
|
||||
if (compressed === false) {
|
||||
const encoder = new TextEncoder();
|
||||
const uncompressed = encoder.encode(JSON.stringify(data));
|
||||
return Promise.resolve(uncompressed);
|
||||
return Promise.resolve(uncompressed(json));
|
||||
}
|
||||
const js = new Blob(['function h(e,t,o){if(null==e)return"";let r;const l={},h={};let s="",n="",p="",a=2,f=3,c=2;const u=[];let i=0,d=0;for(let w=0;w<e.length;w+=1)if(s=e.charAt(w),Object.prototype.hasOwnProperty.call(l,s)||(l[s]=f++,h[s]=!0),n=p+s,Object.prototype.hasOwnProperty.call(l,n))p=n;else{if(Object.prototype.hasOwnProperty.call(h,p)){if(p.charCodeAt(0)<256){for(let e=0;e<c;e++)i<<=1,d==t-1?(d=0,u.push(o(i)),i=0):d++;r=p.charCodeAt(0);for(let e=0;e<8;e++)i=i<<1|1&r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r>>=1}else{r=1;for(let e=0;e<c;e++)i=i<<1|r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r=0;r=p.charCodeAt(0);for(let e=0;e<16;e++)i=i<<1|1&r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r>>=1}0==--a&&(a=Math.pow(2,c),c++),delete h[p]}else{r=l[p];for(let e=0;e<c;e++)i=i<<1|1&r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r>>=1}0==--a&&(a=Math.pow(2,c),c++),l[n]=f++,p=String(s)}if(""!==p){if(Object.prototype.hasOwnProperty.call(h,p)){if(p.charCodeAt(0)<256){for(let e=0;e<c;e++)i<<=1,d==t-1?(d=0,u.push(o(i)),i=0):d++;r=p.charCodeAt(0);for(let e=0;e<8;e++)i=i<<1|1&r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r>>=1}else{r=1;for(let e=0;e<c;e++)i=i<<1|r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r=0;r=p.charCodeAt(0);for(let e=0;e<16;e++)i=i<<1|1&r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r>>=1}0==--a&&(a=Math.pow(2,c),c++),delete h[p]}else{r=l[p];for(let e=0;e<c;e++)i=i<<1|1&r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r>>=1}0==--a&&(a=Math.pow(2,c),c++)}r=2;for(let e=0;e<c;e++)i=i<<1|1&r,d==t-1?(d=0,u.push(o(i)),i=0):d++,r>>=1;let w=!0;do{i<<=1,d==t-1?(u.push(o(i)),w=!1):d++}while(w);return u.join("")}function s(e){return null==e?"":h(e,16,e=>String.fromCharCode(e))}function i(e){const t=s(e),o=new Uint8Array(2*t.length);for(let e=0,r=t.length;e<r;e++){const r=t.charCodeAt(e);o[2*e]=r>>>8,o[2*e+1]=r%256}return o}self.addEventListener("message",function(e){this.self.postMessage(i(e.data))},!1);']);
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(resolve => {
|
||||
let working;
|
||||
const url = URL.createObjectURL(js);
|
||||
const url = URL.createObjectURL(new Blob([`let wasm,WASM_VECTOR_LEN=0,encoder=new TextEncoder("utf-8"),cachegetUint8Memory0=null;function getUint8Memory0(){return null!==cachegetUint8Memory0&&cachegetUint8Memory0.buffer===wasm.memory.buffer||(cachegetUint8Memory0=new Uint8Array(wasm.memory.buffer)),cachegetUint8Memory0}let cachegetInt32Memory0=null;function getInt32Memory0(){return null!==cachegetInt32Memory0&&cachegetInt32Memory0.buffer===wasm.memory.buffer||(cachegetInt32Memory0=new Int32Array(wasm.memory.buffer)),cachegetInt32Memory0}function passArray8ToWasm0(e,t){const n=t(1*e.length);return getUint8Memory0().set(e,n/1),WASM_VECTOR_LEN=e.length,n}function getArrayU8FromWasm0(e,t){return getUint8Memory0().subarray(e/1,e/1+t)}function deflate_encode_raw(e){var t=passArray8ToWasm0(e,wasm.__wbindgen_malloc),n=WASM_VECTOR_LEN;wasm.deflate_encode_raw(8,t,n);var r=getInt32Memory0()[2],a=getInt32Memory0()[3],s=getArrayU8FromWasm0(r,a).slice();return wasm.__wbindgen_free(r,1*a),s}self.addEventListener("message",e=>{const t=e.data.type;if("init"===t)if("function"==typeof WebAssembly.instantiateStreaming){const t={},n=fetch(e.data.module);WebAssembly.instantiateStreaming(n,t).then(({instance:e})=>{wasm=e.exports,self.postMessage({type:"init",result:0})}).catch(e=>n.then(t=>{"application/wasm"!==t.headers.get("Content-Type")?self.postMessage({type:"init",error:"\`WebAssembly.instantiateStreaming\` failed because your server does not serve wasm with \`application/wasm\` MIME type. Original error: "+e.message}):self.postMessage({type:"init",error:e.message})}))}else self.postMessage({type:"init",error:"no \`WebAssembly.instantiateStreaming\`"});else if("compress"===t)if(null==wasm)self.postMessage({error:"no \`wasm\` instance"});else{let t=deflate_encode_raw(encoder.encode(e.data.text));self.postMessage(t,[t.buffer])}});`]));
|
||||
const worker = new Worker(url);
|
||||
/**
|
||||
* @private
|
||||
@ -2171,26 +2172,37 @@ export class Grid {
|
||||
URL.revokeObjectURL(url);
|
||||
next(data);
|
||||
}
|
||||
// 超过 60 秒则拒绝
|
||||
// 超过 30 秒则返回无压缩数据
|
||||
const timer = setTimeout(() => {
|
||||
if (working) {
|
||||
terminate(reject, { message: 'timeout' });
|
||||
// terminate(reject, { message: 'timeout' });
|
||||
terminate(resolve, { data: uncompressed(json), error: 'timeout' });
|
||||
}
|
||||
}, 60000);
|
||||
}, 30000);
|
||||
worker.addEventListener('message', e => {
|
||||
if (working) {
|
||||
clearTimeout(timer);
|
||||
terminate(resolve, e.data);
|
||||
if (e.data.error != null) {
|
||||
// terminate(reject, { message: e.data.error });
|
||||
terminate(resolve, { data: uncompressed(json), error: e.data.error });
|
||||
} else {
|
||||
if (e.data.type === 'init') {
|
||||
worker.postMessage({ type: 'compress', text: json });
|
||||
} else {
|
||||
clearTimeout(timer);
|
||||
terminate(resolve, { type: 'compressed', data: e.data });
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
worker.addEventListener('error', e => {
|
||||
if (working) {
|
||||
clearTimeout(timer);
|
||||
terminate(reject, e);
|
||||
// terminate(reject, e);
|
||||
terminate(resolve, { data: uncompressed(json), error: e.message });
|
||||
}
|
||||
})
|
||||
working = true;
|
||||
worker.postMessage(JSON.stringify(data));
|
||||
worker.postMessage({ type: 'init', module: ScriptPath.replace(/ui\.min\.js$/, 'wasm_flate_bg.wasm') });
|
||||
});
|
||||
}
|
||||
|
||||
|
2
lib/ui/popup.d.ts
vendored
2
lib/ui/popup.d.ts
vendored
@ -13,6 +13,8 @@ interface PopupOptions {
|
||||
zIndex?: number;
|
||||
/** 是否在获取焦点时修改 z-index */
|
||||
changeZIndex?: boolean;
|
||||
/** 是否允许关闭 */
|
||||
closable?: boolean;
|
||||
/** 是否允许移动 */
|
||||
movable?: boolean;
|
||||
/** 是否允许修改大小 */
|
||||
|
@ -172,7 +172,11 @@ export class Popup {
|
||||
let title = option.title;
|
||||
if (!(title instanceof HTMLElement)) {
|
||||
title = createElement('div', t => {
|
||||
t.className = 'ui-popup-header-title';
|
||||
if (option.movable === false) {
|
||||
t.className = 'ui-popup-header-title no-move';
|
||||
} else {
|
||||
t.className = 'ui-popup-header-title';
|
||||
}
|
||||
t.innerText = title;
|
||||
});
|
||||
}
|
||||
@ -244,15 +248,17 @@ export class Popup {
|
||||
});
|
||||
icons.appendChild(collapse);
|
||||
}
|
||||
const cancel = createIcon('fa-regular', 'times');
|
||||
cancel.tabIndex = tabIndex + 3;
|
||||
cancel.addEventListener('keypress', e => {
|
||||
if (e.key === ' ' || e.key === 'Enter') {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
cancel.addEventListener('click', () => this.close());
|
||||
icons.appendChild(cancel);
|
||||
if (option.closable !== false) {
|
||||
const cancel = createIcon('fa-regular', 'times');
|
||||
cancel.tabIndex = tabIndex + 3;
|
||||
cancel.addEventListener('keypress', e => {
|
||||
if (e.key === ' ' || e.key === 'Enter') {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
cancel.addEventListener('click', () => this.close());
|
||||
icons.appendChild(cancel);
|
||||
}
|
||||
});
|
||||
header.appendChild(icons);
|
||||
}),
|
||||
|
43
lib/ui/tab.js
Normal file
43
lib/ui/tab.js
Normal file
@ -0,0 +1,43 @@
|
||||
import "./css/tab.scss";
|
||||
|
||||
/**
|
||||
* Tab 页创建参数类
|
||||
* @typedef TabOption
|
||||
* @property {HTMLElement} container - 父容器
|
||||
*/
|
||||
|
||||
import { createElement } from "../functions";
|
||||
|
||||
/**
|
||||
* 创建 Tab 页
|
||||
* @param {TabOption | HTMLElement} options - 创建选项
|
||||
*/
|
||||
export function createTab(options) {
|
||||
if (options instanceof HTMLElement) {
|
||||
options = { container: options };
|
||||
}
|
||||
let container;
|
||||
if (options?.container instanceof HTMLElement) {
|
||||
container = options.container;
|
||||
if (!container.classList.contains('ui-tab-container')) {
|
||||
container.classList.add('ui-tab-container');
|
||||
}
|
||||
} else {
|
||||
container = createElement('div', 'ui-tab-container');
|
||||
}
|
||||
container.replaceChildren(
|
||||
createElement('div', header => {
|
||||
header.className = 'ui-tab-header';
|
||||
header.addEventListener('click', e => {
|
||||
const title = e.target;
|
||||
if (title.classList.contains('ui-tab-title')) {
|
||||
// title
|
||||
header.querySelectorAll('.ui-tab-title').forEach(t => t === title ? t.classList.add('selected') : t.classList.remove('selected'));
|
||||
// pages
|
||||
const page = title.dataset.for;
|
||||
container.querySelectorAll('[data-page]').forEach(p => p.style.display = p.dataset.page === page ? 'block' : '');
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user