@hakumi-dev/hakumi-components 0.1.17-pre → 0.1.19-pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +218 -369
- package/app/javascript/hakumi_components/controllers/hakumi/admin_panel_controller.js +5 -7
- package/app/javascript/hakumi_components/controllers/hakumi/back_top_controller.js +1 -1
- package/app/javascript/hakumi_components/controllers/hakumi/button_controller.js +108 -2
- package/app/javascript/hakumi_components/controllers/hakumi/calendar_controller.js +183 -95
- package/app/javascript/hakumi_components/controllers/hakumi/color_picker_controller.js +23 -285
- package/app/javascript/hakumi_components/controllers/hakumi/date_picker_controller.js +274 -262
- package/app/javascript/hakumi_components/controllers/hakumi/float_button_group_controller.js +2 -2
- package/app/javascript/hakumi_components/controllers/hakumi/message_controller.js +4 -2
- package/app/javascript/hakumi_components/controllers/hakumi/modal_controller.js +119 -125
- package/app/javascript/hakumi_components/controllers/hakumi/table/editable.js +291 -0
- package/app/javascript/hakumi_components/controllers/hakumi/table_controller.js +166 -366
- package/app/javascript/hakumi_components/controllers/hakumi/tabs_controller.js +8 -2
- package/app/javascript/hakumi_components/controllers/hakumi/tag_controller.js +27 -25
- package/app/javascript/hakumi_components/controllers/hakumi/tag_group_controller.js +19 -18
- package/app/javascript/hakumi_components/controllers/hakumi/theme_controller.js +116 -117
- package/app/javascript/hakumi_components/controllers/hakumi/transfer_controller.js +17 -1
- package/app/javascript/hakumi_components/controllers/hakumi/tree_controller.js +363 -78
- package/app/javascript/hakumi_components/controllers/hakumi/typography_controller.js +3 -3
- package/app/javascript/hakumi_components/controllers/hakumi/upload_controller.js +320 -204
- package/app/javascript/hakumi_components/core/render_component.js +37 -11
- package/app/javascript/hakumi_components/utils/color_helper.js +262 -0
- package/app/javascript/stylesheets/_base.scss +9 -0
- package/app/javascript/stylesheets/_hakumi_components.scss +1 -0
- package/app/javascript/stylesheets/components/_breadcrumb.scss +2 -2
- package/app/javascript/stylesheets/components/_calendar.scss +13 -13
- package/app/javascript/stylesheets/components/_cascader.scss +5 -5
- package/app/javascript/stylesheets/components/_checkbox.scss +9 -11
- package/app/javascript/stylesheets/components/_color_picker.scss +11 -11
- package/app/javascript/stylesheets/components/_date_picker.scss +4 -4
- package/app/javascript/stylesheets/components/_descriptions.scss +2 -2
- package/app/javascript/stylesheets/components/_drawer.scss +3 -3
- package/app/javascript/stylesheets/components/_dropdown.scss +2 -2
- package/app/javascript/stylesheets/components/_flex.scss +1 -1
- package/app/javascript/stylesheets/components/_float_button.scss +5 -5
- package/app/javascript/stylesheets/components/_form_item.scss +92 -0
- package/app/javascript/stylesheets/components/_image.scss +15 -15
- package/app/javascript/stylesheets/components/_input.scss +23 -113
- package/app/javascript/stylesheets/components/_layout.scss +27 -26
- package/app/javascript/stylesheets/components/_menu.scss +15 -15
- package/app/javascript/stylesheets/components/_modal.scss +13 -13
- package/app/javascript/stylesheets/components/_notification.scss +3 -3
- package/app/javascript/stylesheets/components/_popover.scss +1 -1
- package/app/javascript/stylesheets/components/_segmented.scss +3 -3
- package/app/javascript/stylesheets/components/_select.scss +6 -6
- package/app/javascript/stylesheets/components/_slider.scss +1 -1
- package/app/javascript/stylesheets/components/_spin.scss +2 -2
- package/app/javascript/stylesheets/components/_steps.scss +10 -10
- package/app/javascript/stylesheets/components/_switch.scss +11 -10
- package/app/javascript/stylesheets/components/_table.scss +6 -6
- package/app/javascript/stylesheets/components/_tag.scss +2 -2
- package/app/javascript/stylesheets/components/_tooltip.scss +4 -4
- package/app/javascript/stylesheets/components/_tree_select.scss +3 -3
- package/app/javascript/stylesheets/components/_typography.scss +3 -3
- package/app/javascript/stylesheets/components/_upload.scss +4 -4
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import RegistryController from "../base/registry_controller.js"
|
|
2
2
|
import Sortable from "sortablejs"
|
|
3
|
+
import TableEditable from "./table/editable.js"
|
|
3
4
|
|
|
4
5
|
export default class extends RegistryController {
|
|
5
6
|
|
|
@@ -45,7 +46,7 @@ export default class extends RegistryController {
|
|
|
45
46
|
this._filters = new Map()
|
|
46
47
|
this._sorter = null
|
|
47
48
|
this._expandedRowKeys = new Set(this.#expandedRowKeysFromDom())
|
|
48
|
-
this.
|
|
49
|
+
this._editable = new TableEditable(this)
|
|
49
50
|
this._rowSortable = null
|
|
50
51
|
this._columnSortable = null
|
|
51
52
|
this._pagination = { current: 1, pageSize: this.pageSizeValue || 10, total: 0 }
|
|
@@ -98,16 +99,7 @@ export default class extends RegistryController {
|
|
|
98
99
|
|
|
99
100
|
disconnect() {
|
|
100
101
|
this.#teardownScrollSync()
|
|
101
|
-
|
|
102
|
-
// Clean up sortable instances
|
|
103
|
-
if (this._rowSortable) {
|
|
104
|
-
this._rowSortable.destroy()
|
|
105
|
-
this._rowSortable = null
|
|
106
|
-
}
|
|
107
|
-
if (this._columnSortable) {
|
|
108
|
-
this._columnSortable.destroy()
|
|
109
|
-
this._columnSortable = null
|
|
110
|
-
}
|
|
102
|
+
this.#teardownDragSorting()
|
|
111
103
|
|
|
112
104
|
super.disconnect()
|
|
113
105
|
}
|
|
@@ -325,15 +317,11 @@ export default class extends RegistryController {
|
|
|
325
317
|
}
|
|
326
318
|
|
|
327
319
|
registerShouldCellUpdate(name, fn) {
|
|
328
|
-
|
|
329
|
-
console.warn(`[Hakumi Table] registerShouldCellUpdate: "${name}" must be a function`)
|
|
330
|
-
return
|
|
331
|
-
}
|
|
332
|
-
this._shouldCellUpdateHooks.set(name, fn)
|
|
320
|
+
this._editable.registerShouldCellUpdate(name, fn)
|
|
333
321
|
}
|
|
334
322
|
|
|
335
323
|
unregisterShouldCellUpdate(name) {
|
|
336
|
-
this.
|
|
324
|
+
this._editable.unregisterShouldCellUpdate(name)
|
|
337
325
|
}
|
|
338
326
|
|
|
339
327
|
getRowOrder() {
|
|
@@ -350,44 +338,12 @@ export default class extends RegistryController {
|
|
|
350
338
|
|
|
351
339
|
async loadData(options = {}) {
|
|
352
340
|
if (!this.hasDataUrlValue) return null
|
|
353
|
-
|
|
354
|
-
const page = options.page ?? this._pagination.current
|
|
355
|
-
const pageSize = options.pageSize ?? this._pagination.pageSize
|
|
356
|
-
const sorter = options.sorter ?? this._sorter
|
|
357
|
-
|
|
358
|
-
const params = new URLSearchParams()
|
|
359
|
-
params.set("page", page)
|
|
360
|
-
params.set("per_page", pageSize)
|
|
361
|
-
if (sorter?.field) {
|
|
362
|
-
params.set("sort_field", sorter.field)
|
|
363
|
-
params.set("sort_order", sorter.order || "ascend")
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const fullUrl = `${this.dataUrlValue}?${params.toString()}`
|
|
367
|
-
|
|
341
|
+
|
|
368
342
|
this.element.classList.add("hakumi-table-loading")
|
|
369
|
-
|
|
343
|
+
|
|
370
344
|
try {
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
376
|
-
|
|
377
|
-
const json = await response.json()
|
|
378
|
-
|
|
379
|
-
this._pagination = {
|
|
380
|
-
current: json.pagination.current,
|
|
381
|
-
pageSize: json.pagination.pageSize,
|
|
382
|
-
total: json.pagination.total
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (json.sorter) {
|
|
386
|
-
this._sorter = json.sorter
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
this.#renderRows(json.data)
|
|
390
|
-
this.#updatePagination()
|
|
345
|
+
const json = await this.#fetchData(this.#buildDataUrl(options))
|
|
346
|
+
this.#applyDataResponse(json)
|
|
391
347
|
this.#dispatchLoadComplete(json)
|
|
392
348
|
return json
|
|
393
349
|
} catch (error) {
|
|
@@ -418,6 +374,52 @@ export default class extends RegistryController {
|
|
|
418
374
|
return this.loadData()
|
|
419
375
|
}
|
|
420
376
|
|
|
377
|
+
#buildDataUrl(options = {}) {
|
|
378
|
+
const { page, pageSize, sorter } = this.#dataRequestState(options)
|
|
379
|
+
const params = new URLSearchParams()
|
|
380
|
+
params.set("page", page)
|
|
381
|
+
params.set("per_page", pageSize)
|
|
382
|
+
if (sorter?.field) {
|
|
383
|
+
params.set("sort_field", sorter.field)
|
|
384
|
+
params.set("sort_order", sorter.order || "ascend")
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return `${this.dataUrlValue}?${params.toString()}`
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
#dataRequestState(options = {}) {
|
|
391
|
+
return {
|
|
392
|
+
page: options.page ?? this._pagination.current,
|
|
393
|
+
pageSize: options.pageSize ?? this._pagination.pageSize,
|
|
394
|
+
sorter: options.sorter ?? this._sorter
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
async #fetchData(url) {
|
|
399
|
+
const response = await fetch(url, {
|
|
400
|
+
headers: { "Accept": "application/json" }
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
404
|
+
|
|
405
|
+
return response.json()
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
#applyDataResponse(json) {
|
|
409
|
+
this._pagination = {
|
|
410
|
+
current: json.pagination.current,
|
|
411
|
+
pageSize: json.pagination.pageSize,
|
|
412
|
+
total: json.pagination.total
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (json.sorter) {
|
|
416
|
+
this._sorter = json.sorter
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
this.#renderRows(json.data)
|
|
420
|
+
this.#updatePagination()
|
|
421
|
+
}
|
|
422
|
+
|
|
421
423
|
#renderRows(data) {
|
|
422
424
|
const tbody = this.element.querySelector("tbody")
|
|
423
425
|
if (!tbody) return
|
|
@@ -469,29 +471,26 @@ export default class extends RegistryController {
|
|
|
469
471
|
if (!this.hasDataUrlValue) return
|
|
470
472
|
this.#syncPaginationFromComponent()
|
|
471
473
|
this.#bindPaginationEvents()
|
|
472
|
-
this.loadData()
|
|
474
|
+
this.loadData().catch(() => {})
|
|
473
475
|
}
|
|
474
476
|
|
|
475
477
|
#syncPaginationFromComponent() {
|
|
476
|
-
const paginationEl = this
|
|
478
|
+
const paginationEl = this.#paginationElement()
|
|
477
479
|
if (!paginationEl) return
|
|
478
480
|
|
|
479
|
-
const controller = this
|
|
481
|
+
const controller = this.#paginationController()
|
|
480
482
|
if (controller) {
|
|
481
483
|
this._pagination.pageSize = controller.pageSizeValue || this._pagination.pageSize
|
|
482
484
|
}
|
|
483
485
|
}
|
|
484
486
|
|
|
485
487
|
#getPaginationComponent() {
|
|
486
|
-
const paginationEl = this
|
|
488
|
+
const paginationEl = this.#paginationElement()
|
|
487
489
|
return paginationEl?.hakumiPagination || paginationEl?.hakumiComponent?.api
|
|
488
490
|
}
|
|
489
491
|
|
|
490
492
|
#updatePagination() {
|
|
491
|
-
const
|
|
492
|
-
if (!paginationEl) return
|
|
493
|
-
|
|
494
|
-
const controller = this.application.getControllerForElementAndIdentifier(paginationEl, "hakumi--pagination")
|
|
493
|
+
const controller = this.#paginationController()
|
|
495
494
|
if (!controller) return
|
|
496
495
|
|
|
497
496
|
const { current, pageSize, total } = this._pagination
|
|
@@ -503,260 +502,51 @@ export default class extends RegistryController {
|
|
|
503
502
|
}
|
|
504
503
|
|
|
505
504
|
#bindPaginationEvents() {
|
|
506
|
-
const container = this
|
|
505
|
+
const container = this.#paginationContainer()
|
|
507
506
|
if (!container || container._paginationBound) return
|
|
508
507
|
container._paginationBound = true
|
|
509
508
|
|
|
510
|
-
container.addEventListener("hakumi--pagination:change", (e) =>
|
|
511
|
-
e.stopPropagation()
|
|
512
|
-
const page = e.detail.current
|
|
513
|
-
if (page !== this._pagination.current) {
|
|
514
|
-
this._pagination.current = page
|
|
515
|
-
this.loadData()
|
|
516
|
-
}
|
|
517
|
-
})
|
|
509
|
+
container.addEventListener("hakumi--pagination:change", (e) => this.#handlePaginationChange(e))
|
|
518
510
|
|
|
519
|
-
container.addEventListener("hakumi--pagination:sizeChange", (e) =>
|
|
520
|
-
e.stopPropagation()
|
|
521
|
-
const size = e.detail.pageSize
|
|
522
|
-
if (size !== this._pagination.pageSize) {
|
|
523
|
-
this._pagination.pageSize = size
|
|
524
|
-
this._pagination.current = 1
|
|
525
|
-
this.loadData()
|
|
526
|
-
}
|
|
527
|
-
})
|
|
511
|
+
container.addEventListener("hakumi--pagination:sizeChange", (e) => this.#handlePaginationSizeChange(e))
|
|
528
512
|
}
|
|
529
513
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
if (cell.querySelector(".hakumi-table-cell-editor")) return
|
|
533
|
-
|
|
534
|
-
const tableConfig = this.editableConfigValue || {}
|
|
535
|
-
const mode = tableConfig.mode || "cell"
|
|
536
|
-
|
|
537
|
-
if (mode === "row") {
|
|
538
|
-
this.#editRow(cell)
|
|
539
|
-
} else {
|
|
540
|
-
this.#editSingleCell(cell)
|
|
541
|
-
}
|
|
514
|
+
#paginationContainer() {
|
|
515
|
+
return this.element.querySelector(".hakumi-table-pagination")
|
|
542
516
|
}
|
|
543
517
|
|
|
544
|
-
#
|
|
545
|
-
|
|
546
|
-
input.focus()
|
|
547
|
-
|
|
548
|
-
const rowElement = cell.closest("tr")
|
|
549
|
-
const rowKey = rowElement?.dataset.rowKey
|
|
550
|
-
const columnKey = config.key || cell.dataset.columnKey
|
|
551
|
-
const dataIndex = config.data_index
|
|
552
|
-
|
|
553
|
-
const save = () => {
|
|
554
|
-
if (!editor.isConnected) return
|
|
555
|
-
|
|
556
|
-
const newValue = input.value
|
|
557
|
-
const detail = { rowKey, columnKey, dataIndex, value: newValue, originalValue }
|
|
558
|
-
|
|
559
|
-
if (!this.#shouldUpdateCell(cell, detail)) {
|
|
560
|
-
if (originalContent) originalContent.style.display = ""
|
|
561
|
-
editor.remove()
|
|
562
|
-
return
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
if (originalContent) {
|
|
566
|
-
originalContent.textContent = newValue
|
|
567
|
-
originalContent.style.display = ""
|
|
568
|
-
}
|
|
569
|
-
cell.dataset.value = newValue
|
|
570
|
-
editor.remove()
|
|
571
|
-
|
|
572
|
-
this.#dispatchEdit(detail)
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
const cancel = () => {
|
|
576
|
-
if (!editor.isConnected) return
|
|
577
|
-
if (originalContent) originalContent.style.display = ""
|
|
578
|
-
editor.remove()
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
input.addEventListener("blur", save)
|
|
582
|
-
|
|
583
|
-
input.addEventListener("keydown", (e) => {
|
|
584
|
-
if (e.key === "Enter") {
|
|
585
|
-
e.preventDefault()
|
|
586
|
-
input.blur()
|
|
587
|
-
} else if (e.key === "Escape") {
|
|
588
|
-
e.preventDefault()
|
|
589
|
-
input.removeEventListener("blur", save)
|
|
590
|
-
cancel()
|
|
591
|
-
}
|
|
592
|
-
})
|
|
518
|
+
#paginationElement() {
|
|
519
|
+
return this.element.querySelector(".hakumi-table-pagination .hakumi-pagination")
|
|
593
520
|
}
|
|
594
521
|
|
|
595
|
-
#
|
|
596
|
-
const
|
|
597
|
-
if (!
|
|
598
|
-
|
|
599
|
-
row.classList.add("hakumi-table-row-editing")
|
|
600
|
-
const rowKey = row.dataset.rowKey
|
|
601
|
-
const editableCells = row.querySelectorAll("td[data-editable='true']")
|
|
602
|
-
const editors = []
|
|
603
|
-
|
|
604
|
-
editableCells.forEach((cell) => {
|
|
605
|
-
const { input, originalContent, originalValue, config } = this.#createCellEditor(cell)
|
|
606
|
-
input.dataset.columnKey = config.key || cell.dataset.columnKey
|
|
607
|
-
input.dataset.dataIndex = config.data_index
|
|
608
|
-
input.dataset.originalValue = originalValue
|
|
609
|
-
|
|
610
|
-
editors.push({ cell, input, originalContent, originalValue, config })
|
|
611
|
-
})
|
|
612
|
-
|
|
613
|
-
const clickedInput = clickedCell.querySelector(".hakumi-table-cell-input")
|
|
614
|
-
if (clickedInput) {
|
|
615
|
-
clickedInput.focus()
|
|
616
|
-
} else if (editors.length > 0) {
|
|
617
|
-
editors[0].input.focus()
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
const saveRow = () => {
|
|
621
|
-
const changes = []
|
|
622
|
-
let allValid = true
|
|
522
|
+
#paginationController() {
|
|
523
|
+
const paginationEl = this.#paginationElement()
|
|
524
|
+
if (!paginationEl) return null
|
|
623
525
|
|
|
624
|
-
|
|
625
|
-
const newValue = input.value
|
|
626
|
-
const columnKey = config.key || cell.dataset.columnKey
|
|
627
|
-
const dataIndex = config.data_index
|
|
628
|
-
const detail = { rowKey, columnKey, dataIndex, value: newValue, originalValue }
|
|
629
|
-
|
|
630
|
-
if (!this.#shouldUpdateCell(cell, detail)) {
|
|
631
|
-
allValid = false
|
|
632
|
-
return
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
changes.push({ cell, originalContent, newValue, detail })
|
|
636
|
-
})
|
|
637
|
-
|
|
638
|
-
if (!allValid) {
|
|
639
|
-
cancelRow()
|
|
640
|
-
return
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
changes.forEach(({ cell, originalContent, newValue }) => {
|
|
644
|
-
if (originalContent) {
|
|
645
|
-
originalContent.textContent = newValue
|
|
646
|
-
originalContent.style.display = ""
|
|
647
|
-
}
|
|
648
|
-
cell.dataset.value = newValue
|
|
649
|
-
cell.querySelector(".hakumi-table-cell-editor")?.remove()
|
|
650
|
-
})
|
|
651
|
-
|
|
652
|
-
row.classList.remove("hakumi-table-row-editing")
|
|
653
|
-
|
|
654
|
-
this.#dispatchRowEdit({
|
|
655
|
-
rowKey,
|
|
656
|
-
changes: changes.map(({ detail }) => detail)
|
|
657
|
-
})
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
const cancelRow = () => {
|
|
661
|
-
editors.forEach(({ cell, originalContent }) => {
|
|
662
|
-
if (originalContent) originalContent.style.display = ""
|
|
663
|
-
cell.querySelector(".hakumi-table-cell-editor")?.remove()
|
|
664
|
-
})
|
|
665
|
-
row.classList.remove("hakumi-table-row-editing")
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
editors.forEach(({ input }) => {
|
|
669
|
-
input.addEventListener("keydown", (e) => {
|
|
670
|
-
if (e.key === "Enter") {
|
|
671
|
-
e.preventDefault()
|
|
672
|
-
saveRow()
|
|
673
|
-
} else if (e.key === "Escape") {
|
|
674
|
-
e.preventDefault()
|
|
675
|
-
cancelRow()
|
|
676
|
-
}
|
|
677
|
-
})
|
|
678
|
-
})
|
|
679
|
-
|
|
680
|
-
this.dispatch("rowEditing", {
|
|
681
|
-
detail: { rowKey, save: saveRow, cancel: cancelRow }
|
|
682
|
-
})
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
#dispatchEdit(detail) {
|
|
686
|
-
this.dispatch("edit", { detail })
|
|
526
|
+
return this.application.getControllerForElementAndIdentifier(paginationEl, "hakumi--pagination")
|
|
687
527
|
}
|
|
688
528
|
|
|
689
|
-
#
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
this.
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
params
|
|
696
|
-
}
|
|
697
|
-
})
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
#changesToParams(changes) {
|
|
701
|
-
const params = {}
|
|
702
|
-
if (!changes || !Array.isArray(changes)) return params
|
|
703
|
-
|
|
704
|
-
changes.forEach(({ columnKey, dataIndex, value }) => {
|
|
705
|
-
const key = dataIndex || columnKey
|
|
706
|
-
if (key) {
|
|
707
|
-
params[key] = value
|
|
708
|
-
}
|
|
709
|
-
})
|
|
710
|
-
return params
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
#shouldUpdateCell(cell, detail) {
|
|
714
|
-
const hookName = cell?.dataset.shouldCellUpdate
|
|
715
|
-
if (!hookName) return true
|
|
716
|
-
|
|
717
|
-
const hook = this.#resolveHook(hookName)
|
|
718
|
-
if (typeof hook !== "function") {
|
|
719
|
-
console.warn(`[Hakumi Table] shouldCellUpdate hook "${hookName}" is not a function`)
|
|
720
|
-
return true
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
try {
|
|
724
|
-
const result = hook(detail)
|
|
725
|
-
if (result === false) return false
|
|
726
|
-
|
|
727
|
-
if (typeof result === "string") {
|
|
728
|
-
this.dispatch("cellUpdatePrevented", {
|
|
729
|
-
detail: {
|
|
730
|
-
...detail,
|
|
731
|
-
reason: result
|
|
732
|
-
}
|
|
733
|
-
})
|
|
734
|
-
return false
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
return true
|
|
738
|
-
} catch (error) {
|
|
739
|
-
console.error(`[Hakumi Table] shouldCellUpdate hook "${hookName}" failed`, error)
|
|
740
|
-
return true
|
|
529
|
+
#handlePaginationChange(event) {
|
|
530
|
+
event.stopPropagation()
|
|
531
|
+
const page = event.detail.current
|
|
532
|
+
if (page !== this._pagination.current) {
|
|
533
|
+
this._pagination.current = page
|
|
534
|
+
this.loadData()
|
|
741
535
|
}
|
|
742
536
|
}
|
|
743
537
|
|
|
744
|
-
#
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
if (typeof window === "undefined") return null
|
|
754
|
-
|
|
755
|
-
if (window.HakumiTableShouldCellUpdate && typeof window.HakumiTableShouldCellUpdate[name] === "function") {
|
|
756
|
-
return window.HakumiTableShouldCellUpdate[name]
|
|
538
|
+
#handlePaginationSizeChange(event) {
|
|
539
|
+
event.stopPropagation()
|
|
540
|
+
const size = event.detail.pageSize
|
|
541
|
+
if (size !== this._pagination.pageSize) {
|
|
542
|
+
this._pagination.pageSize = size
|
|
543
|
+
this._pagination.current = 1
|
|
544
|
+
this.loadData()
|
|
757
545
|
}
|
|
546
|
+
}
|
|
758
547
|
|
|
759
|
-
|
|
548
|
+
editCell(event) {
|
|
549
|
+
this._editable.editCell(event)
|
|
760
550
|
}
|
|
761
551
|
|
|
762
552
|
#exposeApi(api) {
|
|
@@ -780,8 +570,9 @@ export default class extends RegistryController {
|
|
|
780
570
|
})
|
|
781
571
|
|
|
782
572
|
|
|
783
|
-
|
|
784
|
-
|
|
573
|
+
const sorterKey = this._sorter?.field || this._sorter?.key
|
|
574
|
+
if (sorterKey && this._sorter.order) {
|
|
575
|
+
url.searchParams.set(this.sortFieldParamValue, sorterKey)
|
|
785
576
|
url.searchParams.set(this.sortOrderParamValue, this._sorter.order)
|
|
786
577
|
} else {
|
|
787
578
|
url.searchParams.delete(this.sortFieldParamValue)
|
|
@@ -808,27 +599,6 @@ export default class extends RegistryController {
|
|
|
808
599
|
}
|
|
809
600
|
}
|
|
810
601
|
|
|
811
|
-
#createCellEditor(cell) {
|
|
812
|
-
const config = this.#parseJson(cell.dataset.editableConfig, {})
|
|
813
|
-
const originalContent = cell.querySelector(".hakumi-table-cell-content")
|
|
814
|
-
const originalValue = cell.dataset.value ?? (originalContent?.textContent?.trim() || "")
|
|
815
|
-
|
|
816
|
-
const editor = document.createElement("div")
|
|
817
|
-
editor.className = "hakumi-table-cell-editor"
|
|
818
|
-
|
|
819
|
-
const input = document.createElement("input")
|
|
820
|
-
input.type = config.input_type || "text"
|
|
821
|
-
input.value = originalValue
|
|
822
|
-
input.className = "hakumi-table-cell-input"
|
|
823
|
-
|
|
824
|
-
editor.appendChild(input)
|
|
825
|
-
|
|
826
|
-
if (originalContent) originalContent.style.display = "none"
|
|
827
|
-
cell.appendChild(editor)
|
|
828
|
-
|
|
829
|
-
return { input, editor, originalContent, originalValue, config }
|
|
830
|
-
}
|
|
831
|
-
|
|
832
602
|
#syncSelection() {
|
|
833
603
|
const keys = this._selectedRowKeys
|
|
834
604
|
this.selectionCheckboxTargets.forEach((input) => {
|
|
@@ -853,7 +623,7 @@ export default class extends RegistryController {
|
|
|
853
623
|
}
|
|
854
624
|
|
|
855
625
|
#expandedRowKeysFromDom() {
|
|
856
|
-
const expandedRows = this.element.querySelectorAll("tr[data-row-type='expanded'].
|
|
626
|
+
const expandedRows = this.element.querySelectorAll("tr[data-row-type='expanded'].hakumi-table-row-expanded")
|
|
857
627
|
return Array.from(expandedRows).map((row) => String(row.dataset.rowKey))
|
|
858
628
|
}
|
|
859
629
|
|
|
@@ -967,13 +737,13 @@ export default class extends RegistryController {
|
|
|
967
737
|
if (!expandedRow || expandedRow.dataset.rowType !== "expanded") return
|
|
968
738
|
const expanded = this._expandedRowKeys.has(key)
|
|
969
739
|
|
|
970
|
-
expandedRow.hidden = !expanded
|
|
971
|
-
expandedRow.classList.toggle("
|
|
740
|
+
expandedRow.hidden = row.hidden || !expanded
|
|
741
|
+
expandedRow.classList.toggle("hakumi-table-row-expanded", expanded)
|
|
972
742
|
|
|
973
743
|
const button = row.querySelector("[data-hakumi--table-target='expandToggle']")
|
|
974
744
|
if (button) {
|
|
975
745
|
button.setAttribute("aria-expanded", expanded)
|
|
976
|
-
button.classList.toggle("
|
|
746
|
+
button.classList.toggle("hakumi-table-expand-button-expanded", expanded)
|
|
977
747
|
}
|
|
978
748
|
})
|
|
979
749
|
}
|
|
@@ -1007,19 +777,8 @@ export default class extends RegistryController {
|
|
|
1007
777
|
#syncScrollState() {
|
|
1008
778
|
if (!this.hasScrollContainerTarget) return
|
|
1009
779
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
const hasLeft = el.scrollLeft > 0
|
|
1013
|
-
const hasRight = el.scrollLeft < maxScrollLeft - 1
|
|
1014
|
-
|
|
1015
|
-
this.element.classList.toggle("hakumi-table-scroll-left", hasLeft)
|
|
1016
|
-
this.element.classList.toggle("hakumi-table-scroll-right", hasRight)
|
|
1017
|
-
|
|
1018
|
-
if (this.hasScrollBarTarget && !this._syncingFromBar) {
|
|
1019
|
-
this._syncingFromContainer = true
|
|
1020
|
-
this.scrollBarTarget.scrollLeft = el.scrollLeft
|
|
1021
|
-
this._syncingFromContainer = false
|
|
1022
|
-
}
|
|
780
|
+
this.#syncScrollEdgeClasses()
|
|
781
|
+
this.#syncMirrorScrollBarFromContainer()
|
|
1023
782
|
}
|
|
1024
783
|
|
|
1025
784
|
#syncFromScrollBar() {
|
|
@@ -1027,6 +786,7 @@ export default class extends RegistryController {
|
|
|
1027
786
|
|
|
1028
787
|
this._syncingFromBar = true
|
|
1029
788
|
this.scrollContainerTarget.scrollLeft = this.scrollBarTarget.scrollLeft
|
|
789
|
+
this.#syncScrollState()
|
|
1030
790
|
this._syncingFromBar = false
|
|
1031
791
|
}
|
|
1032
792
|
|
|
@@ -1037,6 +797,24 @@ export default class extends RegistryController {
|
|
|
1037
797
|
this.scrollBarThumbTarget.style.width = `${el.scrollWidth}px`
|
|
1038
798
|
}
|
|
1039
799
|
|
|
800
|
+
#syncScrollEdgeClasses() {
|
|
801
|
+
const el = this.scrollContainerTarget
|
|
802
|
+
const maxScrollLeft = el.scrollWidth - el.clientWidth
|
|
803
|
+
const hasLeft = el.scrollLeft > 0
|
|
804
|
+
const hasRight = el.scrollLeft < maxScrollLeft - 1
|
|
805
|
+
|
|
806
|
+
this.element.classList.toggle("hakumi-table-scroll-left", hasLeft)
|
|
807
|
+
this.element.classList.toggle("hakumi-table-scroll-right", hasRight)
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
#syncMirrorScrollBarFromContainer() {
|
|
811
|
+
if (!this.hasScrollBarTarget || this._syncingFromBar) return
|
|
812
|
+
|
|
813
|
+
this._syncingFromContainer = true
|
|
814
|
+
this.scrollBarTarget.scrollLeft = this.scrollContainerTarget.scrollLeft
|
|
815
|
+
this._syncingFromContainer = false
|
|
816
|
+
}
|
|
817
|
+
|
|
1040
818
|
#nextSortOrder(currentOrder) {
|
|
1041
819
|
if (!currentOrder) return this._sortDirections[0]
|
|
1042
820
|
const index = this._sortDirections.indexOf(currentOrder)
|
|
@@ -1077,62 +855,84 @@ export default class extends RegistryController {
|
|
|
1077
855
|
}
|
|
1078
856
|
}
|
|
1079
857
|
|
|
858
|
+
#teardownDragSorting() {
|
|
859
|
+
if (this._rowSortable) {
|
|
860
|
+
this._rowSortable.destroy()
|
|
861
|
+
this._rowSortable = null
|
|
862
|
+
}
|
|
863
|
+
if (this._columnSortable) {
|
|
864
|
+
this._columnSortable.destroy()
|
|
865
|
+
this._columnSortable = null
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
1080
869
|
#setupRowDrag() {
|
|
1081
870
|
const tbody = this.element.querySelector("tbody")
|
|
1082
871
|
if (!tbody) return
|
|
1083
872
|
|
|
873
|
+
this._rowSortable = Sortable.create(tbody, this.#rowDragOptions())
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
#rowDragOptions() {
|
|
1084
877
|
const options = {
|
|
1085
878
|
animation: 150,
|
|
1086
879
|
ghostClass: "hakumi-table-row-ghost",
|
|
1087
880
|
chosenClass: "hakumi-table-row-chosen",
|
|
1088
881
|
dragClass: "hakumi-table-row-drag",
|
|
1089
882
|
filter: ".hakumi-table-expanded-row",
|
|
1090
|
-
onEnd: (evt) =>
|
|
1091
|
-
if (evt.oldIndex === evt.newIndex) return
|
|
1092
|
-
|
|
1093
|
-
const row = evt.item
|
|
1094
|
-
const rowKey = row.dataset.rowKey
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
const expandedRow = row.nextElementSibling
|
|
1098
|
-
if (expandedRow?.dataset.rowType === "expanded") {
|
|
1099
|
-
row.parentNode.insertBefore(expandedRow, row.nextSibling)
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
this.#dispatchRowReorder(evt.oldIndex, evt.newIndex, rowKey)
|
|
1103
|
-
}
|
|
883
|
+
onEnd: (evt) => this.#handleRowDragEnd(evt)
|
|
1104
884
|
}
|
|
1105
885
|
|
|
1106
|
-
|
|
1107
886
|
if (this.rowDragHandleValue) {
|
|
1108
887
|
options.handle = ".hakumi-table-drag-handle"
|
|
1109
888
|
}
|
|
1110
889
|
|
|
1111
|
-
|
|
890
|
+
return options
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
#handleRowDragEnd(evt) {
|
|
894
|
+
if (evt.oldIndex === evt.newIndex) return
|
|
895
|
+
|
|
896
|
+
const row = evt.item
|
|
897
|
+
const rowKey = row.dataset.rowKey
|
|
898
|
+
|
|
899
|
+
this.#moveExpandedRowAfterDataRow(row)
|
|
900
|
+
this.#dispatchRowReorder(evt.oldIndex, evt.newIndex, rowKey)
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
#moveExpandedRowAfterDataRow(row) {
|
|
904
|
+
const expandedRow = row.nextElementSibling
|
|
905
|
+
if (expandedRow?.dataset.rowType === "expanded") {
|
|
906
|
+
row.parentNode.insertBefore(expandedRow, row.nextSibling)
|
|
907
|
+
}
|
|
1112
908
|
}
|
|
1113
909
|
|
|
1114
910
|
#setupColumnDrag() {
|
|
1115
911
|
const headerRow = this.element.querySelector(".hakumi-table-header-row")
|
|
1116
912
|
if (!headerRow) return
|
|
1117
913
|
|
|
1118
|
-
this._columnSortable = Sortable.create(headerRow,
|
|
914
|
+
this._columnSortable = Sortable.create(headerRow, this.#columnDragOptions())
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
#columnDragOptions() {
|
|
918
|
+
return {
|
|
1119
919
|
animation: 150,
|
|
1120
920
|
ghostClass: "hakumi-table-column-ghost",
|
|
1121
921
|
chosenClass: "hakumi-table-column-chosen",
|
|
1122
922
|
dragClass: "hakumi-table-column-drag",
|
|
1123
923
|
filter: ".hakumi-table-selection-column, .hakumi-table-expand-column",
|
|
1124
|
-
onEnd: (evt) =>
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
924
|
+
onEnd: (evt) => this.#handleColumnDragEnd(evt)
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
#handleColumnDragEnd(evt) {
|
|
929
|
+
if (evt.oldIndex === evt.newIndex) return
|
|
930
|
+
|
|
931
|
+
const th = evt.item
|
|
932
|
+
const columnKey = th.dataset.columnKey
|
|
933
|
+
|
|
934
|
+
this.#reorderBodyColumns(evt.oldIndex, evt.newIndex)
|
|
935
|
+
this.#dispatchColumnReorder(evt.oldIndex, evt.newIndex, columnKey)
|
|
1136
936
|
}
|
|
1137
937
|
|
|
1138
938
|
#reorderBodyColumns(oldIndex, newIndex) {
|