fix(datatable): 修复 scope 从 @web 统一为 @apigo.cc,增强 editable 控制及编辑器交互(by AI)
Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
This commit is contained in:
parent
92b111c785
commit
d99b78fc6f
10
README.md
10
README.md
@ -1,6 +1,6 @@
|
|||||||
# @web/datatable AI 开发指南
|
# @apigo.cc/datatable AI 开发指南
|
||||||
|
|
||||||
`@web/datatable` 是一个高性能、无状态的 Web 数据表格组件,支持万级数据虚拟滚动、多维编辑及固定列。
|
`@apigo.cc/datatable` 是一个高性能、无状态的 Web 数据表格组件,支持万级数据虚拟滚动、多维编辑及固定列。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -11,9 +11,9 @@
|
|||||||
<script type="importmap">
|
<script type="importmap">
|
||||||
{
|
{
|
||||||
"imports": {
|
"imports": {
|
||||||
"@web/state": "path/to/state.mjs",
|
"@apigo.cc/state": "path/to/state.mjs",
|
||||||
"@web/base": "path/to/base.mjs",
|
"@apigo.cc/base": "path/to/base.mjs",
|
||||||
"@web/datatable": "path/to/datatable.mjs"
|
"@apigo.cc/datatable": "path/to/datatable.mjs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
20
dist/datatable.js
vendored
20
dist/datatable.js
vendored
@ -356,6 +356,7 @@
|
|||||||
globalThis.Component.register("DataTable", (container) => {
|
globalThis.Component.register("DataTable", (container) => {
|
||||||
if (!container.state) container.state = globalThis.NewState({});
|
if (!container.state) container.state = globalThis.NewState({});
|
||||||
const state = container.state;
|
const state = container.state;
|
||||||
|
container.editable = container.hasAttribute("editable");
|
||||||
Object.assign(state, {
|
Object.assign(state, {
|
||||||
list: [],
|
list: [],
|
||||||
fields: [],
|
fields: [],
|
||||||
@ -376,7 +377,8 @@
|
|||||||
_fieldsDirty: false,
|
_fieldsDirty: false,
|
||||||
_masterCellNodes: null,
|
_masterCellNodes: null,
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
isBulkEdit: null
|
isBulkEdit: null,
|
||||||
|
editable: container.editable
|
||||||
});
|
});
|
||||||
const perf = createPerfMonitor();
|
const perf = createPerfMonitor();
|
||||||
state.perf = perf.stats;
|
state.perf = perf.stats;
|
||||||
@ -404,6 +406,7 @@
|
|||||||
perf.onScroll();
|
perf.onScroll();
|
||||||
scroll.refresh();
|
scroll.refresh();
|
||||||
container.hideColumnMenu();
|
container.hideColumnMenu();
|
||||||
|
container.hideEditor(true);
|
||||||
const prev = container.querySelector(".dt-spacer-prev"), post = container.querySelector(".dt-spacer-post");
|
const prev = container.querySelector(".dt-spacer-prev"), post = container.querySelector(".dt-spacer-post");
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev.style.height = (state.prevHeight || 0) + "px";
|
prev.style.height = (state.prevHeight || 0) + "px";
|
||||||
@ -466,6 +469,11 @@
|
|||||||
container.showColumnMenu = (field, event) => {
|
container.showColumnMenu = (field, event) => {
|
||||||
var _a;
|
var _a;
|
||||||
const btn = event.currentTarget, menu = container.querySelector(".dt-column-menu");
|
const btn = event.currentTarget, menu = container.querySelector(".dt-column-menu");
|
||||||
|
if (menu.style.display === "block" && state.activeFieldId === field.id) {
|
||||||
|
container.hideColumnMenu();
|
||||||
|
container.applySortFilter();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const type = ((_a = field.settings) == null ? void 0 : _a.formType) || field.type || "text";
|
const type = ((_a = field.settings) == null ? void 0 : _a.formType) || field.type || "text";
|
||||||
state.activeModes = MODE_MAP[type] || (["boolean", "switch", "checkbox", "radio"].includes(type) ? [] : MODE_MAP.text);
|
state.activeModes = MODE_MAP[type] || (["boolean", "switch", "checkbox", "radio"].includes(type) ? [] : MODE_MAP.text);
|
||||||
if (!state.filterConfig[field.id]) state.filterConfig[field.id] = { mode: state.activeModes[0] || "contains", value: "", selectedValues: [] };
|
if (!state.filterConfig[field.id]) state.filterConfig[field.id] = { mode: state.activeModes[0] || "contains", value: "", selectedValues: [] };
|
||||||
@ -713,6 +721,7 @@
|
|||||||
};
|
};
|
||||||
container.onMainDblClick = (e) => {
|
container.onMainDblClick = (e) => {
|
||||||
var _a, _b, _c;
|
var _a, _b, _c;
|
||||||
|
if (!container.editable) return;
|
||||||
const cell = e.target.closest(".dt-cell"), row = cell == null ? void 0 : cell.closest(".dt-row");
|
const cell = e.target.closest(".dt-cell"), row = cell == null ? void 0 : cell.closest(".dt-row");
|
||||||
if (row && !row.classList.contains("dt-header-row")) {
|
if (row && !row.classList.contains("dt-header-row")) {
|
||||||
const item = (_a = row._ref) == null ? void 0 : _a.item, fIdx = cell.dataset.fidx ? parseInt(cell.dataset.fidx) : Array.from(row.querySelectorAll(".dt-cell")).indexOf(cell);
|
const item = (_a = row._ref) == null ? void 0 : _a.item, fIdx = cell.dataset.fidx ? parseInt(cell.dataset.fidx) : Array.from(row.querySelectorAll(".dt-cell")).indexOf(cell);
|
||||||
@ -930,7 +939,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="mt-2" style="max-height: 180px; overflow-y: auto;">
|
<div class="mt-2" style="max-height: 180px; overflow-y: auto;">
|
||||||
<div class="text-muted fw-bold mb-1" style="font-size: 9px; letter-spacing: 0.5px">TOP FREQUENT VALUES</div>
|
|
||||||
<template $each="this.state?._columnStats?.[this.state?.activeFieldId] || []">
|
<template $each="this.state?._columnStats?.[this.state?.activeFieldId] || []">
|
||||||
<label class="d-flex align-items-center mb-1 small cursor-pointer p-1 rounded-1 menu-item-row" onmouseover="this.style.background='var(--bs-light)'" onmouseout="this.style.background='transparent'">
|
<label class="d-flex align-items-center mb-1 small cursor-pointer p-1 rounded-1 menu-item-row" onmouseover="this.style.background='var(--bs-light)'" onmouseout="this.style.background='transparent'">
|
||||||
<input type="checkbox" class="form-check-input me-2" $checked="this.state?.filterConfig?.[this.state?.activeFieldId]?.selectedValues?.includes(String(item.val))" $onclick="this.toggleSelectedValue(String(item.val))">
|
<input type="checkbox" class="form-check-input me-2" $checked="this.state?.filterConfig?.[this.state?.activeFieldId]?.selectedValues?.includes(String(item.val))" $onclick="this.toggleSelectedValue(String(item.val))">
|
||||||
@ -944,7 +952,7 @@
|
|||||||
<span class="cursor-pointer text-primary small fw-bold" $onclick="this.clearColumnSettings()"><i class="bi bi-x-circle me-1"></i> Clear Filter</span>
|
<span class="cursor-pointer text-primary small fw-bold" $onclick="this.clearColumnSettings()"><i class="bi bi-x-circle me-1"></i> Clear Filter</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 pt-2 border-top d-flex gap-1 justify-content-between">
|
<div $if="this.state?.editable" class="mt-3 pt-2 border-top d-flex gap-1 justify-content-between">
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Edit Field" $onclick="this.editField()"><i class="bi bi-pencil"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Edit Field" $onclick="this.editField()"><i class="bi bi-pencil"></i></button>
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Add Field" $onclick="this.addField()"><i class="bi bi-plus-lg"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Add Field" $onclick="this.addField()"><i class="bi bi-plus-lg"></i></button>
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1 text-danger" title="Delete Field" $onclick="this.deleteField()"><i class="bi bi-trash"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1 text-danger" title="Delete Field" $onclick="this.deleteField()"><i class="bi bi-trash"></i></button>
|
||||||
@ -962,17 +970,17 @@
|
|||||||
|
|
||||||
<div class="dt-footer border-top bg-light d-flex align-items-center px-3 py-1 shadow-sm" style="height:40px; z-index: 10">
|
<div class="dt-footer border-top bg-light d-flex align-items-center px-3 py-1 shadow-sm" style="height:40px; z-index: 10">
|
||||||
<div class="d-flex align-items-center gap-3 flex-grow-1">
|
<div class="d-flex align-items-center gap-3 flex-grow-1">
|
||||||
<div class="d-flex align-items-center gap-1">
|
<div $if="this.state?.editable" class="d-flex align-items-center gap-1">
|
||||||
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.addRow()" title="Add Row"><i class="bi bi-plus-lg text-primary me-1"></i> Add</button>
|
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.addRow()" title="Add Row"><i class="bi bi-plus-lg text-primary me-1"></i> Add</button>
|
||||||
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.deleteSelectedRow()" $disabled="!this.state?.selectedRowCount" title="Delete Selected Rows"><i class="bi bi-trash text-danger me-1"></i> Delete</button>
|
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.deleteSelectedRow()" $disabled="!this.state?.selectedRowCount" title="Delete Selected Rows"><i class="bi bi-trash text-danger me-1"></i> Delete</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="vr h-50 my-auto text-muted opacity-25"></div>
|
<div $if="this.state?.editable" class="vr h-50 my-auto text-muted opacity-25"></div>
|
||||||
<div class="d-flex align-items-center gap-2 text-muted" style="font-size: 0.75rem">
|
<div class="d-flex align-items-center gap-2 text-muted" style="font-size: 0.75rem">
|
||||||
<i class="bi bi-check-all fs-6"></i>
|
<i class="bi bi-check-all fs-6"></i>
|
||||||
<span $text="(this.state?.selectedRowCount || 0) + ' selected / ' + (this.state?.list?.length || 0) + ' total'"></span>
|
<span $text="(this.state?.selectedRowCount || 0) + ' selected / ' + (this.state?.list?.length || 0) + ' total'"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div $if="this.state?.editable" class="d-flex align-items-center gap-2">
|
||||||
<button $if="this.state?.isDirty" class="btn btn-sm btn-primary border-0 px-3 shadow-sm d-flex align-items-center fw-bold" $onclick="this.saveChanges()"><i class="bi bi-cloud-upload me-1"></i> Save</button>
|
<button $if="this.state?.isDirty" class="btn btn-sm btn-primary border-0 px-3 shadow-sm d-flex align-items-center fw-bold" $onclick="this.saveChanges()"><i class="bi bi-cloud-upload me-1"></i> Save</button>
|
||||||
<button $if="!this.state?.isDirty" class="btn btn-sm btn-light border-0 px-3 text-muted disabled d-flex align-items-center" disabled><i class="bi bi-cloud-check me-1"></i> Saved</button>
|
<button $if="!this.state?.isDirty" class="btn btn-sm btn-light border-0 px-3 text-muted disabled d-flex align-items-center" disabled><i class="bi bi-cloud-check me-1"></i> Saved</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
2
dist/datatable.min.js
vendored
2
dist/datatable.min.js
vendored
File diff suppressed because one or more lines are too long
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@web/datatable",
|
"name": "@apigo.cc/datatable",
|
||||||
"version": "1.0.14",
|
"version": "1.0.14",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@web/datatable",
|
"name": "@apigo.cc/datatable",
|
||||||
"version": "1.0.14",
|
"version": "1.0.14",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.40.0",
|
"@playwright/test": "^1.40.0",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@web/datatable",
|
"name": "@apigo.cc/datatable",
|
||||||
"version": "1.0.14",
|
"version": "1.0.14",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/datatable.js",
|
"main": "dist/datatable.js",
|
||||||
@ -10,7 +10,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"test": "playwright test"
|
"test": "playwright test",
|
||||||
|
"pub": "node scripts/publish.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.40.0",
|
"@playwright/test": "^1.40.0",
|
||||||
|
|||||||
48
scripts/publish.js
Normal file
48
scripts/publish.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { execSync } from 'child_process';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 获取最新 tag
|
||||||
|
let tag;
|
||||||
|
try {
|
||||||
|
tag = execSync('git describe --tags --abbrev=0', { encoding: 'utf8' }).trim();
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error('Failed to find git tags. Please make sure the repository has tags (e.g., v1.0.0) before publishing.');
|
||||||
|
}
|
||||||
|
// 去掉 v 前缀
|
||||||
|
const version = tag.startsWith('v') ? tag.slice(1) : tag;
|
||||||
|
|
||||||
|
console.log(`Latest git tag: ${tag}, Version to publish: ${version}`);
|
||||||
|
|
||||||
|
// 2. 读取并更新 package.json
|
||||||
|
const pkgPath = path.join(__dirname, '../package.json');
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
||||||
|
|
||||||
|
// 保持原有名称(如果已经带有 @apigo.cc/ 前缀)或替换前缀
|
||||||
|
if (!pkg.name.startsWith('@apigo.cc/')) {
|
||||||
|
const baseName = pkg.name.includes('/') ? pkg.name.split('/')[1] : pkg.name;
|
||||||
|
pkg.name = `@apigo.cc/${baseName}`;
|
||||||
|
}
|
||||||
|
pkg.version = version;
|
||||||
|
|
||||||
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
||||||
|
console.log(`Updated package.json: name=${pkg.name}, version=${pkg.version}`);
|
||||||
|
|
||||||
|
// 3. 构建
|
||||||
|
console.log('Running build...');
|
||||||
|
execSync('npm run build', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||||
|
|
||||||
|
// 4. 发布
|
||||||
|
console.log('Publishing to npm...');
|
||||||
|
const args = process.argv.slice(2).join(' ');
|
||||||
|
execSync(`npm publish --access public ${args}`, { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||||
|
|
||||||
|
console.log('Publish successful!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Publish failed:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
@ -253,6 +253,7 @@ const createSelectionManager = (container, state) => {
|
|||||||
globalThis.Component.register('DataTable', container => {
|
globalThis.Component.register('DataTable', container => {
|
||||||
if (!container.state) container.state = globalThis.NewState({})
|
if (!container.state) container.state = globalThis.NewState({})
|
||||||
const state = container.state
|
const state = container.state
|
||||||
|
container.editable = container.hasAttribute('editable')
|
||||||
|
|
||||||
Object.assign(state, {
|
Object.assign(state, {
|
||||||
list: [], fields: [], _renderedList: [],
|
list: [], fields: [], _renderedList: [],
|
||||||
@ -263,7 +264,8 @@ globalThis.Component.register('DataTable', container => {
|
|||||||
filterConfig: {},
|
filterConfig: {},
|
||||||
activeFieldId: null, activeField: null, activeModes: [],
|
activeFieldId: null, activeField: null, activeModes: [],
|
||||||
_columnStats: {}, _internalUpdate: false, _appliedHash: '', _fieldsDirty: false, _masterCellNodes: null,
|
_columnStats: {}, _internalUpdate: false, _appliedHash: '', _fieldsDirty: false, _masterCellNodes: null,
|
||||||
isDirty: false, isBulkEdit: null
|
isDirty: false, isBulkEdit: null,
|
||||||
|
editable: container.editable
|
||||||
})
|
})
|
||||||
|
|
||||||
const perf = createPerfMonitor();
|
const perf = createPerfMonitor();
|
||||||
@ -292,6 +294,7 @@ globalThis.Component.register('DataTable', container => {
|
|||||||
container.onScroll = () => {
|
container.onScroll = () => {
|
||||||
perf.onScroll(); scroll.refresh();
|
perf.onScroll(); scroll.refresh();
|
||||||
container.hideColumnMenu();
|
container.hideColumnMenu();
|
||||||
|
container.hideEditor(true);
|
||||||
const prev = container.querySelector('.dt-spacer-prev'), post = container.querySelector('.dt-spacer-post');
|
const prev = container.querySelector('.dt-spacer-prev'), post = container.querySelector('.dt-spacer-post');
|
||||||
if (prev) { prev.style.height = (state.prevHeight || 0) + 'px'; prev.style.display = state.prevHeight > 0 ? 'block' : 'none'; }
|
if (prev) { prev.style.height = (state.prevHeight || 0) + 'px'; prev.style.display = state.prevHeight > 0 ? 'block' : 'none'; }
|
||||||
if (post) { post.style.height = (state.postHeight || 0) + 'px'; post.style.display = state.postHeight > 0 ? 'block' : 'none'; }
|
if (post) { post.style.height = (state.postHeight || 0) + 'px'; post.style.display = state.postHeight > 0 ? 'block' : 'none'; }
|
||||||
@ -342,6 +345,11 @@ globalThis.Component.register('DataTable', container => {
|
|||||||
|
|
||||||
container.showColumnMenu = (field, event) => {
|
container.showColumnMenu = (field, event) => {
|
||||||
const btn = event.currentTarget, menu = container.querySelector('.dt-column-menu');
|
const btn = event.currentTarget, menu = container.querySelector('.dt-column-menu');
|
||||||
|
if (menu.style.display === 'block' && state.activeFieldId === field.id) {
|
||||||
|
container.hideColumnMenu();
|
||||||
|
container.applySortFilter();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const type = field.settings?.formType || field.type || 'text';
|
const type = field.settings?.formType || field.type || 'text';
|
||||||
state.activeModes = MODE_MAP[type] || (['boolean', 'switch', 'checkbox', 'radio'].includes(type) ? [] : MODE_MAP.text);
|
state.activeModes = MODE_MAP[type] || (['boolean', 'switch', 'checkbox', 'radio'].includes(type) ? [] : MODE_MAP.text);
|
||||||
if (!state.filterConfig[field.id]) state.filterConfig[field.id] = { mode: state.activeModes[0] || 'contains', value: '', selectedValues: [] };
|
if (!state.filterConfig[field.id]) state.filterConfig[field.id] = { mode: state.activeModes[0] || 'contains', value: '', selectedValues: [] };
|
||||||
@ -520,6 +528,7 @@ globalThis.Component.register('DataTable', container => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
container.onMainDblClick = e => {
|
container.onMainDblClick = e => {
|
||||||
|
if (!container.editable) return;
|
||||||
const cell = e.target.closest('.dt-cell'), row = cell?.closest('.dt-row');
|
const cell = e.target.closest('.dt-cell'), row = cell?.closest('.dt-row');
|
||||||
if (row && !row.classList.contains('dt-header-row')) {
|
if (row && !row.classList.contains('dt-header-row')) {
|
||||||
const item = row._ref?.item, fIdx = cell.dataset.fidx ? parseInt(cell.dataset.fidx) : Array.from(row.querySelectorAll('.dt-cell')).indexOf(cell);
|
const item = row._ref?.item, fIdx = cell.dataset.fidx ? parseInt(cell.dataset.fidx) : Array.from(row.querySelectorAll('.dt-cell')).indexOf(cell);
|
||||||
@ -712,7 +721,6 @@ globalThis.Component.register('DataTable', container => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="mt-2" style="max-height: 180px; overflow-y: auto;">
|
<div class="mt-2" style="max-height: 180px; overflow-y: auto;">
|
||||||
<div class="text-muted fw-bold mb-1" style="font-size: 9px; letter-spacing: 0.5px">TOP FREQUENT VALUES</div>
|
|
||||||
<template $each="this.state?._columnStats?.[this.state?.activeFieldId] || []">
|
<template $each="this.state?._columnStats?.[this.state?.activeFieldId] || []">
|
||||||
<label class="d-flex align-items-center mb-1 small cursor-pointer p-1 rounded-1 menu-item-row" onmouseover="this.style.background='var(--bs-light)'" onmouseout="this.style.background='transparent'">
|
<label class="d-flex align-items-center mb-1 small cursor-pointer p-1 rounded-1 menu-item-row" onmouseover="this.style.background='var(--bs-light)'" onmouseout="this.style.background='transparent'">
|
||||||
<input type="checkbox" class="form-check-input me-2" $checked="this.state?.filterConfig?.[this.state?.activeFieldId]?.selectedValues?.includes(String(item.val))" $onclick="this.toggleSelectedValue(String(item.val))">
|
<input type="checkbox" class="form-check-input me-2" $checked="this.state?.filterConfig?.[this.state?.activeFieldId]?.selectedValues?.includes(String(item.val))" $onclick="this.toggleSelectedValue(String(item.val))">
|
||||||
@ -726,7 +734,7 @@ globalThis.Component.register('DataTable', container => {
|
|||||||
<span class="cursor-pointer text-primary small fw-bold" $onclick="this.clearColumnSettings()"><i class="bi bi-x-circle me-1"></i> Clear Filter</span>
|
<span class="cursor-pointer text-primary small fw-bold" $onclick="this.clearColumnSettings()"><i class="bi bi-x-circle me-1"></i> Clear Filter</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 pt-2 border-top d-flex gap-1 justify-content-between">
|
<div $if="this.state?.editable" class="mt-3 pt-2 border-top d-flex gap-1 justify-content-between">
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Edit Field" $onclick="this.editField()"><i class="bi bi-pencil"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Edit Field" $onclick="this.editField()"><i class="bi bi-pencil"></i></button>
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Add Field" $onclick="this.addField()"><i class="bi bi-plus-lg"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Add Field" $onclick="this.addField()"><i class="bi bi-plus-lg"></i></button>
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1 text-danger" title="Delete Field" $onclick="this.deleteField()"><i class="bi bi-trash"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1 text-danger" title="Delete Field" $onclick="this.deleteField()"><i class="bi bi-trash"></i></button>
|
||||||
@ -744,17 +752,17 @@ globalThis.Component.register('DataTable', container => {
|
|||||||
|
|
||||||
<div class="dt-footer border-top bg-light d-flex align-items-center px-3 py-1 shadow-sm" style="height:40px; z-index: 10">
|
<div class="dt-footer border-top bg-light d-flex align-items-center px-3 py-1 shadow-sm" style="height:40px; z-index: 10">
|
||||||
<div class="d-flex align-items-center gap-3 flex-grow-1">
|
<div class="d-flex align-items-center gap-3 flex-grow-1">
|
||||||
<div class="d-flex align-items-center gap-1">
|
<div $if="this.state?.editable" class="d-flex align-items-center gap-1">
|
||||||
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.addRow()" title="Add Row"><i class="bi bi-plus-lg text-primary me-1"></i> Add</button>
|
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.addRow()" title="Add Row"><i class="bi bi-plus-lg text-primary me-1"></i> Add</button>
|
||||||
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.deleteSelectedRow()" $disabled="!this.state?.selectedRowCount" title="Delete Selected Rows"><i class="bi bi-trash text-danger me-1"></i> Delete</button>
|
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.deleteSelectedRow()" $disabled="!this.state?.selectedRowCount" title="Delete Selected Rows"><i class="bi bi-trash text-danger me-1"></i> Delete</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="vr h-50 my-auto text-muted opacity-25"></div>
|
<div $if="this.state?.editable" class="vr h-50 my-auto text-muted opacity-25"></div>
|
||||||
<div class="d-flex align-items-center gap-2 text-muted" style="font-size: 0.75rem">
|
<div class="d-flex align-items-center gap-2 text-muted" style="font-size: 0.75rem">
|
||||||
<i class="bi bi-check-all fs-6"></i>
|
<i class="bi bi-check-all fs-6"></i>
|
||||||
<span $text="(this.state?.selectedRowCount || 0) + ' selected / ' + (this.state?.list?.length || 0) + ' total'"></span>
|
<span $text="(this.state?.selectedRowCount || 0) + ' selected / ' + (this.state?.list?.length || 0) + ' total'"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div $if="this.state?.editable" class="d-flex align-items-center gap-2">
|
||||||
<button $if="this.state?.isDirty" class="btn btn-sm btn-primary border-0 px-3 shadow-sm d-flex align-items-center fw-bold" $onclick="this.saveChanges()"><i class="bi bi-cloud-upload me-1"></i> Save</button>
|
<button $if="this.state?.isDirty" class="btn btn-sm btn-primary border-0 px-3 shadow-sm d-flex align-items-center fw-bold" $onclick="this.saveChanges()"><i class="bi bi-cloud-upload me-1"></i> Save</button>
|
||||||
<button $if="!this.state?.isDirty" class="btn btn-sm btn-light border-0 px-3 text-muted disabled d-flex align-items-center" disabled><i class="bi bi-cloud-check me-1"></i> Saved</button>
|
<button $if="!this.state?.isDirty" class="btn btn-sm btn-light border-0 px-3 text-muted disabled d-flex align-items-center" disabled><i class="bi bi-cloud-check me-1"></i> Saved</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>AutoForm Diagnostic</title>
|
<title>AutoForm Diagnostic</title>
|
||||||
<script src="lib/bootstrap.js"></script>
|
|
||||||
<script src="lib/state.js"></script>
|
<script src="lib/state.js"></script>
|
||||||
<script src="lib/base.js"></script>
|
<script src="lib/base.js"></script>
|
||||||
<script src="lib/datatable.js"></script>
|
<script src="lib/datatable.js"></script>
|
||||||
@ -46,6 +45,7 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="p-4">
|
<body class="p-4">
|
||||||
|
<script src="lib/bootstrap.js"></script>
|
||||||
<div style="width: 300px; border: 1px solid blue; min-height: 100px;">
|
<div style="width: 300px; border: 1px solid blue; min-height: 100px;">
|
||||||
<AutoForm id="diagForm" inline></AutoForm>
|
<AutoForm id="diagForm" inline></AutoForm>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,8 +5,6 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>DataTable Demo</title>
|
<title>DataTable Demo</title>
|
||||||
<!-- 0. Bootstrap -->
|
|
||||||
<script src="lib/bootstrap.js"></script>
|
|
||||||
<style>
|
<style>
|
||||||
body, html { height: 100%; margin: 0; padding: 0; overflow: hidden; }
|
body, html { height: 100%; margin: 0; padding: 0; overflow: hidden; }
|
||||||
.demo-container { height: 100vh; padding: 20px; display: flex; flex-direction: column; }
|
.demo-container { height: 100vh; padding: 20px; display: flex; flex-direction: column; }
|
||||||
@ -15,9 +13,11 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-light">
|
<body class="bg-light">
|
||||||
|
<!-- 0. Bootstrap -->
|
||||||
|
<script src="lib/bootstrap.js"></script>
|
||||||
<div class="demo-container">
|
<div class="demo-container">
|
||||||
<div class="table-wrapper">
|
<div class="table-wrapper">
|
||||||
<DataTable id="myTable"></DataTable>
|
<DataTable id="myTable" editable></DataTable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -127,14 +127,14 @@
|
|||||||
<option $each="item.options" as="opt" $value="opt.value !== undefined ? opt.value : opt" $text="opt.label || opt"></option>
|
<option $each="item.options" as="opt" $value="opt.value !== undefined ? opt.value : opt" $text="opt.label || opt"></option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div $if="['checkbox', 'radio'].includes(item.type)" class="d-flex align-items-center flex-wrap gap-3 h-100" style="padding-left: 0.75rem; padding-right: 0.75rem; min-height: calc(2.25rem + 2px);">
|
<div $if="['checkbox', 'radio'].includes(item.type)" class="d-flex align-items-center flex-wrap gap-3 h-100" style="padding: 0 0.75rem; min-height: calc(2.25rem + 2px);">
|
||||||
<label $each="item.options || [item.text||item.label||item.name]" as="opt" class="form-check mb-0 d-flex align-items-center" style="padding-left:0; cursor:pointer;">
|
<label $each="item.options || [item.text||item.label||item.name]" as="opt" class="form-check mb-0 d-flex align-items-center" style="padding-left:0; cursor:pointer;">
|
||||||
<input $name="item.name" class="form-check-input m-0 me-2" style="float:none;" $type="item.type" $.="item.setting || {}" $value="item.options ? (opt.value !== undefined ? opt.value : opt) : 'on'" $bind="this.data[item.name]">
|
<input $name="item.name" class="form-check-input m-0 me-2" style="float:none;" $type="item.type" $.="item.setting || {}" $value="item.options ? (opt.value !== undefined ? opt.value : opt) : 'on'" $bind="this.data[item.name]">
|
||||||
<span $if="!this.inline || (item.options && item.options.length > 0)" $text="opt.label || opt" class="form-check-label"></span>
|
<span $if="!this.inline || (item.options && item.options.length > 0)" $text="opt.label || opt" class="form-check-label"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div $if="item.type === 'switch'" class="form-check form-switch fs-5 d-flex align-items-center m-0" style="padding-left: 3.25rem; padding-right: 0.75rem; min-height: calc(2.25rem + 2px); display:flex !important;">
|
<div $if="item.type === 'switch'" class="form-check form-switch fs-5 d-flex align-items-center m-0" style="padding: 0 0.75rem; min-height: calc(2.25rem + 2px); display:flex !important;">
|
||||||
<input $name="item.name" class="form-check-input m-0" style="float:none; cursor:pointer" type="checkbox" $bind="this.data[item.name]">
|
<input $name="item.name" class="form-check-input m-0" style="float:none; cursor:pointer" type="checkbox" $bind="this.data[item.name]">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
13
test/lib/bootstrap.js
vendored
13
test/lib/bootstrap.js
vendored
@ -2120,7 +2120,9 @@ url("data:font/woff;base64,d09GRgABAAAAAsBAAAsAAAAHavgAAQAAAAAAAAAAAAAAAAAAAAAAA
|
|||||||
console.error("vite-plugin-css-injected-by-js", e);
|
console.error("vite-plugin-css-injected-by-js", e);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
var ApigoBootstrap = function(exports) {
|
(function(global, factory) {
|
||||||
|
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@apigo.cc/state")) : typeof define === "function" && define.amd ? define(["exports", "@apigo.cc/state"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ApigoBootstrap = global.ApigoBootstrap || {}));
|
||||||
|
})(this, function(exports2) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var top = "top";
|
var top = "top";
|
||||||
var bottom = "bottom";
|
var bottom = "bottom";
|
||||||
@ -7277,8 +7279,7 @@ var ApigoBootstrap = function(exports) {
|
|||||||
globalThis.bootstrap = bootstrap;
|
globalThis.bootstrap = bootstrap;
|
||||||
globalThis.Bootstrap = Bootstrap;
|
globalThis.Bootstrap = Bootstrap;
|
||||||
}
|
}
|
||||||
exports.Bootstrap = Bootstrap;
|
exports2.Bootstrap = Bootstrap;
|
||||||
exports.default = Bootstrap;
|
exports2.default = Bootstrap;
|
||||||
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
Object.defineProperties(exports2, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
||||||
return exports;
|
});
|
||||||
}({});
|
|
||||||
|
|||||||
@ -356,6 +356,7 @@
|
|||||||
globalThis.Component.register("DataTable", (container) => {
|
globalThis.Component.register("DataTable", (container) => {
|
||||||
if (!container.state) container.state = globalThis.NewState({});
|
if (!container.state) container.state = globalThis.NewState({});
|
||||||
const state = container.state;
|
const state = container.state;
|
||||||
|
container.editable = container.hasAttribute("editable");
|
||||||
Object.assign(state, {
|
Object.assign(state, {
|
||||||
list: [],
|
list: [],
|
||||||
fields: [],
|
fields: [],
|
||||||
@ -376,7 +377,8 @@
|
|||||||
_fieldsDirty: false,
|
_fieldsDirty: false,
|
||||||
_masterCellNodes: null,
|
_masterCellNodes: null,
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
isBulkEdit: null
|
isBulkEdit: null,
|
||||||
|
editable: container.editable
|
||||||
});
|
});
|
||||||
const perf = createPerfMonitor();
|
const perf = createPerfMonitor();
|
||||||
state.perf = perf.stats;
|
state.perf = perf.stats;
|
||||||
@ -404,6 +406,7 @@
|
|||||||
perf.onScroll();
|
perf.onScroll();
|
||||||
scroll.refresh();
|
scroll.refresh();
|
||||||
container.hideColumnMenu();
|
container.hideColumnMenu();
|
||||||
|
container.hideEditor(true);
|
||||||
const prev = container.querySelector(".dt-spacer-prev"), post = container.querySelector(".dt-spacer-post");
|
const prev = container.querySelector(".dt-spacer-prev"), post = container.querySelector(".dt-spacer-post");
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev.style.height = (state.prevHeight || 0) + "px";
|
prev.style.height = (state.prevHeight || 0) + "px";
|
||||||
@ -466,6 +469,11 @@
|
|||||||
container.showColumnMenu = (field, event) => {
|
container.showColumnMenu = (field, event) => {
|
||||||
var _a;
|
var _a;
|
||||||
const btn = event.currentTarget, menu = container.querySelector(".dt-column-menu");
|
const btn = event.currentTarget, menu = container.querySelector(".dt-column-menu");
|
||||||
|
if (menu.style.display === "block" && state.activeFieldId === field.id) {
|
||||||
|
container.hideColumnMenu();
|
||||||
|
container.applySortFilter();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const type = ((_a = field.settings) == null ? void 0 : _a.formType) || field.type || "text";
|
const type = ((_a = field.settings) == null ? void 0 : _a.formType) || field.type || "text";
|
||||||
state.activeModes = MODE_MAP[type] || (["boolean", "switch", "checkbox", "radio"].includes(type) ? [] : MODE_MAP.text);
|
state.activeModes = MODE_MAP[type] || (["boolean", "switch", "checkbox", "radio"].includes(type) ? [] : MODE_MAP.text);
|
||||||
if (!state.filterConfig[field.id]) state.filterConfig[field.id] = { mode: state.activeModes[0] || "contains", value: "", selectedValues: [] };
|
if (!state.filterConfig[field.id]) state.filterConfig[field.id] = { mode: state.activeModes[0] || "contains", value: "", selectedValues: [] };
|
||||||
@ -713,6 +721,7 @@
|
|||||||
};
|
};
|
||||||
container.onMainDblClick = (e) => {
|
container.onMainDblClick = (e) => {
|
||||||
var _a, _b, _c;
|
var _a, _b, _c;
|
||||||
|
if (!container.editable) return;
|
||||||
const cell = e.target.closest(".dt-cell"), row = cell == null ? void 0 : cell.closest(".dt-row");
|
const cell = e.target.closest(".dt-cell"), row = cell == null ? void 0 : cell.closest(".dt-row");
|
||||||
if (row && !row.classList.contains("dt-header-row")) {
|
if (row && !row.classList.contains("dt-header-row")) {
|
||||||
const item = (_a = row._ref) == null ? void 0 : _a.item, fIdx = cell.dataset.fidx ? parseInt(cell.dataset.fidx) : Array.from(row.querySelectorAll(".dt-cell")).indexOf(cell);
|
const item = (_a = row._ref) == null ? void 0 : _a.item, fIdx = cell.dataset.fidx ? parseInt(cell.dataset.fidx) : Array.from(row.querySelectorAll(".dt-cell")).indexOf(cell);
|
||||||
@ -930,7 +939,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="mt-2" style="max-height: 180px; overflow-y: auto;">
|
<div class="mt-2" style="max-height: 180px; overflow-y: auto;">
|
||||||
<div class="text-muted fw-bold mb-1" style="font-size: 9px; letter-spacing: 0.5px">TOP FREQUENT VALUES</div>
|
|
||||||
<template $each="this.state?._columnStats?.[this.state?.activeFieldId] || []">
|
<template $each="this.state?._columnStats?.[this.state?.activeFieldId] || []">
|
||||||
<label class="d-flex align-items-center mb-1 small cursor-pointer p-1 rounded-1 menu-item-row" onmouseover="this.style.background='var(--bs-light)'" onmouseout="this.style.background='transparent'">
|
<label class="d-flex align-items-center mb-1 small cursor-pointer p-1 rounded-1 menu-item-row" onmouseover="this.style.background='var(--bs-light)'" onmouseout="this.style.background='transparent'">
|
||||||
<input type="checkbox" class="form-check-input me-2" $checked="this.state?.filterConfig?.[this.state?.activeFieldId]?.selectedValues?.includes(String(item.val))" $onclick="this.toggleSelectedValue(String(item.val))">
|
<input type="checkbox" class="form-check-input me-2" $checked="this.state?.filterConfig?.[this.state?.activeFieldId]?.selectedValues?.includes(String(item.val))" $onclick="this.toggleSelectedValue(String(item.val))">
|
||||||
@ -944,7 +952,7 @@
|
|||||||
<span class="cursor-pointer text-primary small fw-bold" $onclick="this.clearColumnSettings()"><i class="bi bi-x-circle me-1"></i> Clear Filter</span>
|
<span class="cursor-pointer text-primary small fw-bold" $onclick="this.clearColumnSettings()"><i class="bi bi-x-circle me-1"></i> Clear Filter</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 pt-2 border-top d-flex gap-1 justify-content-between">
|
<div $if="this.state?.editable" class="mt-3 pt-2 border-top d-flex gap-1 justify-content-between">
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Edit Field" $onclick="this.editField()"><i class="bi bi-pencil"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Edit Field" $onclick="this.editField()"><i class="bi bi-pencil"></i></button>
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Add Field" $onclick="this.addField()"><i class="bi bi-plus-lg"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1" title="Add Field" $onclick="this.addField()"><i class="bi bi-plus-lg"></i></button>
|
||||||
<button class="btn btn-sm btn-light border-0 flex-grow-1 text-danger" title="Delete Field" $onclick="this.deleteField()"><i class="bi bi-trash"></i></button>
|
<button class="btn btn-sm btn-light border-0 flex-grow-1 text-danger" title="Delete Field" $onclick="this.deleteField()"><i class="bi bi-trash"></i></button>
|
||||||
@ -962,17 +970,17 @@
|
|||||||
|
|
||||||
<div class="dt-footer border-top bg-light d-flex align-items-center px-3 py-1 shadow-sm" style="height:40px; z-index: 10">
|
<div class="dt-footer border-top bg-light d-flex align-items-center px-3 py-1 shadow-sm" style="height:40px; z-index: 10">
|
||||||
<div class="d-flex align-items-center gap-3 flex-grow-1">
|
<div class="d-flex align-items-center gap-3 flex-grow-1">
|
||||||
<div class="d-flex align-items-center gap-1">
|
<div $if="this.state?.editable" class="d-flex align-items-center gap-1">
|
||||||
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.addRow()" title="Add Row"><i class="bi bi-plus-lg text-primary me-1"></i> Add</button>
|
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.addRow()" title="Add Row"><i class="bi bi-plus-lg text-primary me-1"></i> Add</button>
|
||||||
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.deleteSelectedRow()" $disabled="!this.state?.selectedRowCount" title="Delete Selected Rows"><i class="bi bi-trash text-danger me-1"></i> Delete</button>
|
<button class="btn btn-sm btn-light border-0 d-flex align-items-center px-2 py-1" $onclick="this.deleteSelectedRow()" $disabled="!this.state?.selectedRowCount" title="Delete Selected Rows"><i class="bi bi-trash text-danger me-1"></i> Delete</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="vr h-50 my-auto text-muted opacity-25"></div>
|
<div $if="this.state?.editable" class="vr h-50 my-auto text-muted opacity-25"></div>
|
||||||
<div class="d-flex align-items-center gap-2 text-muted" style="font-size: 0.75rem">
|
<div class="d-flex align-items-center gap-2 text-muted" style="font-size: 0.75rem">
|
||||||
<i class="bi bi-check-all fs-6"></i>
|
<i class="bi bi-check-all fs-6"></i>
|
||||||
<span $text="(this.state?.selectedRowCount || 0) + ' selected / ' + (this.state?.list?.length || 0) + ' total'"></span>
|
<span $text="(this.state?.selectedRowCount || 0) + ' selected / ' + (this.state?.list?.length || 0) + ' total'"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div $if="this.state?.editable" class="d-flex align-items-center gap-2">
|
||||||
<button $if="this.state?.isDirty" class="btn btn-sm btn-primary border-0 px-3 shadow-sm d-flex align-items-center fw-bold" $onclick="this.saveChanges()"><i class="bi bi-cloud-upload me-1"></i> Save</button>
|
<button $if="this.state?.isDirty" class="btn btn-sm btn-primary border-0 px-3 shadow-sm d-flex align-items-center fw-bold" $onclick="this.saveChanges()"><i class="bi bi-cloud-upload me-1"></i> Save</button>
|
||||||
<button $if="!this.state?.isDirty" class="btn btn-sm btn-light border-0 px-3 text-muted disabled d-flex align-items-center" disabled><i class="bi bi-cloud-check me-1"></i> Saved</button>
|
<button $if="!this.state?.isDirty" class="btn btn-sm btn-light border-0 px-3 text-muted disabled d-flex align-items-center" disabled><i class="bi bi-cloud-check me-1"></i> Saved</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
var _a, _b;
|
var _a, _b;
|
||||||
const Util = {
|
const Util = {
|
||||||
clone: globalThis.structuredClone ? (obj) => globalThis.structuredClone(obj) : (obj) => JSON.parse(JSON.stringify(obj)),
|
clone: (obj) => JSON.parse(JSON.stringify(obj)),
|
||||||
base64: (str) => btoa(String.fromCharCode(...new TextEncoder().encode(str))),
|
base64: (str) => btoa(String.fromCharCode(...new TextEncoder().encode(str))),
|
||||||
unbase64: (str) => new TextDecoder().decode(Uint8Array.from(atob(str), (c) => c.charCodeAt(0))),
|
unbase64: (str) => new TextDecoder().decode(Uint8Array.from(atob(str), (c) => c.charCodeAt(0))),
|
||||||
urlbase64: (str) => Util.base64(str).replace(/[+/=]/g, (m) => ({ "+": "-", "/": "", "=": "" })[m]),
|
urlbase64: (str) => Util.base64(str).replace(/[+/=]/g, (m) => ({ "+": "-", "/": "", "=": "" })[m]),
|
||||||
@ -385,6 +385,7 @@
|
|||||||
if (existingNodes) {
|
if (existingNodes) {
|
||||||
node._keyedNodes.delete(keyVal);
|
node._keyedNodes.delete(keyVal);
|
||||||
existingNodes.forEach((child) => {
|
existingNodes.forEach((child) => {
|
||||||
|
node.parentNode.insertBefore(child, node);
|
||||||
child._ref[indexName] = k;
|
child._ref[indexName] = k;
|
||||||
child._ref[asName] = item;
|
child._ref[asName] = item;
|
||||||
_scanTree(child);
|
_scanTree(child);
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script src="lib/bootstrap.js"></script>
|
|
||||||
<script src="lib/state.js"></script>
|
<script src="lib/state.js"></script>
|
||||||
<script src="lib/base.js"></script>
|
<script src="lib/base.js"></script>
|
||||||
<script src="lib/datatable.js"></script>
|
<script src="lib/datatable.js"></script>
|
||||||
@ -24,7 +23,7 @@
|
|||||||
|
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.setAttribute('style', 'height: 400px; width: 800px; border: 1px solid red');
|
div.setAttribute('style', 'height: 400px; width: 800px; border: 1px solid red');
|
||||||
div.innerHTML = '<DataTable id="dt" style="display: flex; flex-direction: column; height: 100%; min-height: 0; overflow: hidden"></DataTable>';
|
div.innerHTML = '<DataTable id="dt" editable style="display: flex; flex-direction: column; height: 100%; min-height: 0; overflow: hidden"></DataTable>';
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
|
|
||||||
// Wait for MutationObserver to pick up the new element
|
// Wait for MutationObserver to pick up the new element
|
||||||
@ -50,5 +49,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body>
|
||||||
|
<script src="lib/bootstrap.js"></script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import terser from '@rollup/plugin-terser';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@web/state': resolve(__dirname, '../state/src/index.js'),
|
'@apigo.cc/state': resolve(__dirname, '../state/src/index.js'),
|
||||||
'@web/base': resolve(__dirname, '../base/src/index.js'),
|
'@apigo.cc/base': resolve(__dirname, '../base/src/index.js'),
|
||||||
'@web/datatable': resolve(__dirname, 'src/index.js')
|
'@apigo.cc/datatable': resolve(__dirname, 'src/index.js')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
@ -22,7 +22,7 @@ export default defineConfig({
|
|||||||
formats: ['umd']
|
formats: ['umd']
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: ['@web/state', '@web/base'],
|
external: ['@apigo.cc/state', '@apigo.cc/base'],
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
format: 'umd',
|
format: 'umd',
|
||||||
@ -30,8 +30,8 @@ export default defineConfig({
|
|||||||
entryFileNames: 'datatable.js',
|
entryFileNames: 'datatable.js',
|
||||||
extend: true,
|
extend: true,
|
||||||
globals: {
|
globals: {
|
||||||
'@web/state': 'ApigoState',
|
'@apigo.cc/state': 'ApigoState',
|
||||||
'@web/base': 'ApigoBase'
|
'@apigo.cc/base': 'ApigoBase'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -40,8 +40,8 @@ export default defineConfig({
|
|||||||
entryFileNames: 'datatable.min.js',
|
entryFileNames: 'datatable.min.js',
|
||||||
extend: true,
|
extend: true,
|
||||||
globals: {
|
globals: {
|
||||||
'@web/state': 'ApigoState',
|
'@apigo.cc/state': 'ApigoState',
|
||||||
'@web/base': 'ApigoBase'
|
'@apigo.cc/base': 'ApigoBase'
|
||||||
},
|
},
|
||||||
plugins: [terser()]
|
plugins: [terser()]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user