e-virt-table
Version:
A powerful data table based on canvas. You can use it as data grid、Microsoft Excel or Google sheets. It supports virtual scroll、cell edit etc.
347 lines • 12 kB
JavaScript
import { expandSvg, svgLoading } from './Icons';
export class FinderBar {
constructor(ctx) {
Object.defineProperty(this, "ctx", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "container", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "input", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "prevBtn", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "nextBtn", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "closeBtn", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "countEl", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "loadingEl", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "isVisible", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "searchResults", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "currentIndex", {
enumerable: true,
configurable: true,
writable: true,
value: -1
});
Object.defineProperty(this, "searchData", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "isComposing", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
this.ctx = ctx;
this.container = this.createContainer();
this.ctx.containerElement.appendChild(this.container);
this.bindEvents();
this.ctx.on('keydown', (e) => {
if (!this.ctx.config.ENABLE_FINDER) {
return;
}
if (this.ctx.editing) {
return;
}
if ((e.ctrlKey || e.metaKey) && e.code === 'KeyF') {
e.preventDefault();
this.show();
return;
}
if (this.ctx.finding) {
if (e.code === 'Escape') {
e.preventDefault();
this.hide();
return;
}
if (e.code === 'ArrowUp' || (e.shiftKey && e.code === 'Enter')) {
e.preventDefault();
this.navigatePrevious();
return;
}
if (e.code === 'ArrowDown' || e.code === 'Enter') {
e.preventDefault();
this.navigateNext();
return;
}
}
});
this.ctx.on('setSelector', () => {
this.hide();
});
this.ctx.on('outsideMousedown', () => {
this.hide();
});
}
async initSearchData() {
this.showLoading();
this.searchData = [];
setTimeout(() => {
const { allCellHeaders } = this.ctx.header;
for (let i = 0; i < allCellHeaders.length; i++) {
const header = allCellHeaders[i];
if (header && ['string', 'number'].includes(typeof header.text)) {
this.searchData.push({
rowIndex: 0,
colIndex: header.colIndex,
text: `${header.text}`,
type: 'header',
colKey: header.key,
});
}
}
const { maxColIndex, maxRowIndex } = this.ctx;
for (let i = 0; i < maxRowIndex; i++) {
for (let j = 0; j < maxColIndex; j++) {
const cell = this.ctx.database.getVirtualBodyCell(i, j, false);
const text = cell?.getText();
if (['string', 'number'].includes(typeof text)) {
this.searchData.push({
rowIndex: i,
colIndex: j,
text: `${text}`,
type: 'body',
});
}
}
}
this.hideLoading();
}, 0);
}
createContainer() {
const container = document.createElement('div');
container.className = 'e-virt-table-finder-bar';
// 创建输入框容器
const inputWrapper = document.createElement('div');
inputWrapper.className = 'e-virt-table-finder-bar-input-wrapper';
// 创建输入框
this.input = document.createElement('input');
this.input.type = 'text';
this.input.className = 'e-virt-table-finder-bar-input';
this.input.placeholder = '';
inputWrapper.appendChild(this.input);
// 创建 loading 指示器(放在输入框容器内)
this.loadingEl = document.createElement('div');
this.loadingEl.className = 'e-virt-table-finder-bar-loading';
const loadingSvg = svgLoading;
this.loadingEl.innerHTML = loadingSvg;
inputWrapper.appendChild(this.loadingEl);
// 创建计数文本
this.countEl = document.createElement('span');
this.countEl.className = 'e-virt-table-finder-bar-count';
// 创建导航按钮容器
const navContainer = document.createElement('div');
navContainer.className = 'e-virt-table-finder-bar-nav';
// 创建上一个按钮(向上箭头)
this.prevBtn = document.createElement('button');
this.prevBtn.className = 'e-virt-table-finder-bar-nav-btn prev-btn';
this.prevBtn.innerHTML = expandSvg;
// 创建下一个按钮(向下箭头)
this.nextBtn = document.createElement('button');
this.nextBtn.className = 'e-virt-table-finder-bar-nav-btn next-btn';
this.nextBtn.innerHTML = expandSvg;
navContainer.appendChild(this.prevBtn);
navContainer.appendChild(this.nextBtn);
// 创建关闭按钮
this.closeBtn = document.createElement('button');
this.closeBtn.className = 'e-virt-table-finder-bar-nav-btn close-btn';
this.closeBtn.innerHTML = '×';
container.appendChild(inputWrapper);
container.appendChild(this.countEl);
container.appendChild(navContainer);
container.appendChild(this.closeBtn);
return container;
}
bindEvents() {
// 输入框输入事件
this.input.addEventListener('input', () => {
if (!this.isComposing)
this.performSearch();
});
this.input.addEventListener('compositionstart', () => {
this.isComposing = true;
});
this.input.addEventListener('compositionend', () => {
this.isComposing = false;
this.performSearch();
});
// 导航按钮事件
this.prevBtn.addEventListener('click', () => {
this.navigatePrevious();
});
this.nextBtn.addEventListener('click', () => {
this.navigateNext();
});
// 关闭按钮事件
this.closeBtn.addEventListener('click', () => {
this.hide();
});
}
performSearch() {
const searchText = this.input.value.trim();
this.searchResults = [];
this.currentIndex = -1;
if (!searchText) {
this.cearFinderBar();
this.updateCount();
return;
}
this.showLoading();
setTimeout(() => {
// 支持大小写搜索
this.searchResults = this.searchData.filter((item) => item.text.toLowerCase().includes(searchText.toLowerCase()));
// 如果找到结果,定位到第一个
if (this.searchResults.length > 0) {
this.currentIndex = 0;
this.scrollToCurrentResult();
}
else {
// 清空
this.cearFinderBar();
}
this.updateCount();
this.hideLoading();
}, 0);
}
scrollToCurrentResult() {
if (this.currentIndex < 0 || this.currentIndex >= this.searchResults.length) {
return;
}
const result = this.searchResults[this.currentIndex];
this.ctx.finderBar = result;
const { rowIndex, colIndex } = result;
this.ctx.emit('scrollToIndex', rowIndex, colIndex);
}
navigateNext() {
if (this.searchResults.length === 0)
return;
this.currentIndex = (this.currentIndex + 1) % this.searchResults.length;
this.scrollToCurrentResult();
this.updateCount();
}
navigatePrevious() {
if (this.searchResults.length === 0)
return;
this.currentIndex = this.currentIndex <= 0 ? this.searchResults.length - 1 : this.currentIndex - 1;
this.scrollToCurrentResult();
this.updateCount();
}
updateCount() {
if (this.searchResults.length === 0) {
if (this.input.value.trim()) {
this.countEl.textContent = '0/0';
this.countEl.classList.add('no-results');
}
else {
this.countEl.textContent = '';
this.countEl.classList.remove('no-results');
}
}
else {
const current = this.currentIndex + 1;
const total = this.searchResults.length;
this.countEl.textContent = `${current}/${total}`;
this.countEl.classList.remove('no-results');
}
}
show() {
if (this.isVisible)
return;
this.isVisible = true;
this.ctx.finding = true;
this.container.classList.add('show');
this.input.focus();
this.initSearchData();
}
showLoading() {
this.loadingEl.classList.add('show');
this.loadingEl.parentElement?.classList.add('loading');
this.input.readOnly = true;
}
hideLoading() {
this.loadingEl.classList.remove('show');
this.loadingEl.parentElement?.classList.remove('loading');
this.input.readOnly = false;
}
cearFinderBar() {
this.ctx.finderBar = {
rowIndex: -1,
colIndex: -1,
text: '',
type: 'header',
};
this.ctx.emit('draw');
}
hide() {
if (!this.isVisible)
return;
this.isVisible = false;
this.container.classList.remove('show');
this.ctx.finding = false;
this.input.value = '';
this.searchResults = [];
this.searchData = [];
this.currentIndex = -1;
this.hideLoading();
this.ctx.finderBar = {
rowIndex: -1,
colIndex: -1,
text: '',
type: 'header',
};
this.updateCount();
this.ctx.emit('draw');
}
destroy() {
this.hide();
this.container.remove();
}
}
//# sourceMappingURL=FinderBar.js.map