@threestarsoftware/tssgrid 0.0.5 → 0.0.6
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/CHANGELOG.md +75 -0
- package/README.md +22 -22
- package/package.json +2 -1
- package/plugins/tss-autocomplete.js +0 -1
- package/plugins/tss-bar.js +0 -1
- package/plugins/tss-calc.js +0 -1
- package/plugins/tss-calendar.js +0 -1
- package/plugins/tss-datetime.js +0 -1
- package/plugins/tss-filter.js +0 -1
- package/plugins/tss-formula.js +0 -1
- package/plugins/tss-furigana.js +0 -1
- package/plugins/tss-heatmap.js +0 -1
- package/plugins/tss-merge.js +0 -1
- package/plugins/tss-messages.js +0 -1
- package/plugins/tss-running.js +0 -1
- package/plugins/tss-shared.js +0 -1
- package/plugins/tss-sparkline.js +0 -1
- package/plugins/tss-sum.js +0 -1
- package/plugins/tss-syncscroll.js +0 -1
- package/plugins/tss-time.js +0 -1
- package/plugins/tss-toggle.js +0 -1
- package/plugins/tss-totals.js +0 -1
- package/src/tssgrid.css +5 -0
- package/src/tssgrid.d.ts +6 -0
- package/src/tssgrid.js +101 -13
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# 変更履歴 (Changelog)
|
|
2
|
+
|
|
3
|
+
TssGrid の各リリースの変更点。日付は JST。形式は [Keep a Changelog](https://keepachangelog.com/ja/1.1.0/) 準拠(ゆるめ)。
|
|
4
|
+
数値は特記なき限り**自社調べ**(headless Chrome / Windows 11・環境差あり)。
|
|
5
|
+
|
|
6
|
+
## [0.0.6] - 2026-06-30
|
|
7
|
+
|
|
8
|
+
### 追加
|
|
9
|
+
- ドラッグ選択・フィルハンドルが**表示領域の外(上下左右)まで自動スクロールしながら伸びる**ように。ビューも一緒にスクロールし、速度は端からのはみ出し量に比例(少し超え=ゆっくり/大きく超え=速く)。仮想スクロール時・非仮想時の両方で動作。
|
|
10
|
+
- `rowHeaderLabel` オプション: 行ヘッダの表示を指定(`false`=数字なしの空ヘッダ/関数 `(r)=>文字列`=カスタム表示/未指定=従来の行番号)。空にしても溝は残り、クリックでの行選択は効く。
|
|
11
|
+
- `rowReorder: 'header'`: 行ヘッダーセル(左端の行番号の列)**全体**を行移動の掴み手に(クリック=行選択/ドラッグ=移動)。従来の `rowReorder: true` は ⠿ アイコンのみ掴める(不変)。
|
|
12
|
+
- `rowReorderMark` オプション: 行ヘッダーの ⠿ マークの位置を `'before'`(番号の前・既定)/ `'after'`(番号の後)/ `false`(出さない)から選べる。
|
|
13
|
+
|
|
14
|
+
### 修正
|
|
15
|
+
- 仮想スクロールでドラッグ選択/フィルが窓の端で止まっていた問題。
|
|
16
|
+
- フィルが端を1行超えただけで大量に伸びてしまう暴走を修正(伸ばす先を常にポインタ位置のセルに)。
|
|
17
|
+
- `examples/virtual.html`: 部署ドロップダウンの選択肢が出ない不具合(`options` 指定漏れ)を修正/表示中インジケータの更新でツールバーがずれる問題を修正/パネルを縦リサイズ可能に。
|
|
18
|
+
|
|
19
|
+
### ドキュメント
|
|
20
|
+
- 比較表(`examples/compare.html`): 仮想スクロールの行を「対応(`virtual:true`・opt-in)」に更新し、デモリンクに `virtual.html` を追加。
|
|
21
|
+
|
|
22
|
+
## [0.0.5] - 2026-06-25
|
|
23
|
+
|
|
24
|
+
### 追加
|
|
25
|
+
- **仮想スクロール `virtual: true`**(コア)— 大量行を「画面に見える窓ぶん+バッファだけ」描画。全件を一度に DOM 化しないので、初期描画が一瞬・スクロールも軽い。有効化はオプション一行。
|
|
26
|
+
- 自社調べ: 10万行で初回描画 ≈ 46ms(全件描画 ≈ 10.5秒に対して)。デモ: `examples/virtual.html`。
|
|
27
|
+
- 制約(v1): 行高一定/固定行列・折り返し・セル結合は非対応(指定時は自動無効化)。
|
|
28
|
+
- **`rowHeaderWidth` オプション**(コア)— 大量行で行番号の桁数が増える時に行ヘッダ幅を調整。
|
|
29
|
+
|
|
30
|
+
### ドキュメント
|
|
31
|
+
- README: 非破壊フィルタの説明を実測値に正確化(「絞り込み後が軽い」を自社調べ値で)+仮想スクロール節を追加。
|
|
32
|
+
- 比較表(`examples/compare.html`)に Tabulator を追加(公式デモ準拠)。
|
|
33
|
+
|
|
34
|
+
## [0.0.4] - 2026-06-24
|
|
35
|
+
|
|
36
|
+
### 追加
|
|
37
|
+
- 見積書デモ(`examples/quote.html`)— 印刷/日付ピッカー/列幅固定/Enter 横送り(`nextCell`)。
|
|
38
|
+
- `navSkipReadOnly` オプション(Tab/Enter 送りで readonly セルを飛ばす=伝票入力向け)。
|
|
39
|
+
- プラグイン `tss-datetime`(日付+時刻の同時ピッカー・曜日つき・別フィールド結合・時刻のみ対応)。
|
|
40
|
+
|
|
41
|
+
### 修正
|
|
42
|
+
- 編集中の `Ctrl+Z` で元の値に戻せない不具合(input 編集を Esc 同等でキャンセル)。
|
|
43
|
+
- グリッド外周の右・下が二重線になる不具合(最終行/列のセル罫線を枠線に一本化)。
|
|
44
|
+
- 全幅見出し帯の結合セルで列/行選択が他列へ広がる不具合(Excel 流にクランプ)。
|
|
45
|
+
- 結合解除で見出しラベルが消える不具合。
|
|
46
|
+
|
|
47
|
+
## [0.0.3] - 2026-06-23
|
|
48
|
+
|
|
49
|
+
### 追加
|
|
50
|
+
- プラグイン `tss-sum`(条件付き合計)+請求書デモで採用。
|
|
51
|
+
|
|
52
|
+
### 修正
|
|
53
|
+
- 請求書デモの合計欄を別グリッド化して金額列に完全整列/No. 列見出しが選択色になる不具合/印刷で選択枠を非表示。
|
|
54
|
+
|
|
55
|
+
## [0.0.2] - 2026-06-22
|
|
56
|
+
|
|
57
|
+
### 追加
|
|
58
|
+
- **npm パッケージ化**(`@threestarsoftware/tssgrid`)+公開 API の型定義 `tssgrid.d.ts`。
|
|
59
|
+
- 請求書(インボイス対応)デモ。
|
|
60
|
+
- サイト: `/docs` ドキュメント・`/api` リファレンス(`.d.ts` から自動生成)・会社名フッター。
|
|
61
|
+
|
|
62
|
+
### 修正
|
|
63
|
+
- 行/列ヘッダ選択中の右クリックで複数選択が解除される不具合。
|
|
64
|
+
|
|
65
|
+
## [0.0.1] - 2026-06-19
|
|
66
|
+
|
|
67
|
+
- 初回公開。コア(編集グリッド/日本語 IME 堅牢・全角半角・セル結合・固定行列・非破壊フィルタ・条件付き書式・コピー/貼付・Undo/Redo ほか)+同梱プラグイン+サンプル一式。
|
|
68
|
+
- 目玉デモ(方眼ガント/在庫管理)をサイトでライブ化。
|
|
69
|
+
|
|
70
|
+
[0.0.6]: https://github.com/threestarsoftware/TssGrid/releases/tag/v0.0.6
|
|
71
|
+
[0.0.5]: https://github.com/threestarsoftware/TssGrid/releases/tag/v0.0.5
|
|
72
|
+
[0.0.4]: https://github.com/threestarsoftware/TssGrid/releases/tag/v0.0.4
|
|
73
|
+
[0.0.3]: https://github.com/threestarsoftware/TssGrid/releases/tag/v0.0.3
|
|
74
|
+
[0.0.2]: https://github.com/threestarsoftware/TssGrid/releases/tag/v0.0.2
|
|
75
|
+
[0.0.1]: https://github.com/threestarsoftware/TssGrid/releases/tag/v0.0.1
|
package/README.md
CHANGED
|
@@ -269,7 +269,7 @@ new TssGrid(el, { virtual: { buffer: 10 }, data }); // 窓の上下バッフ
|
|
|
269
269
|
|
|
270
270
|
### 同梱プラグイン: ヘッダ オートフィルタ(filter UI)
|
|
271
271
|
|
|
272
|
-
`plugins/tss-filter.js`+`.css
|
|
272
|
+
`plugins/tss-filter.js`+`.css`= 各見出しの**ロート(漏斗)アイコン**をクリックで**値チェックリスト+検索**のポップアップ(Excel風。ソートの▲▼と区別できるアイコン)。複数列の条件は **AND**。中身は上の**コア `filter()` を呼ぶだけ**。動く例: [`examples/filter-ui.html`](https://tssgrid.threestarsoftware.co.jp/examples/filter-ui.html)。
|
|
273
273
|
|
|
274
274
|
```html
|
|
275
275
|
<link rel="stylesheet" href="plugins/tss-filter.css">
|
|
@@ -284,7 +284,7 @@ grid.getPlugin('filter').clearAll(); // 全条件クリア
|
|
|
284
284
|
|
|
285
285
|
### 同梱プラグイン: 共有マスタ(複数グリッドで1データ)
|
|
286
286
|
|
|
287
|
-
`plugins/tss-shared.js
|
|
287
|
+
`plugins/tss-shared.js`= **1つのマスタ(同じ行データ)を複数グリッドで共有**。左右を**別フィルタ/別ソート**で表示でき、**片方の編集がもう片方の同じ行へ即反映**(行参照を共有)。A系/B系を並べて突き合わせ編集する用途。動く例: [`examples/shared-master.html`](https://tssgrid.threestarsoftware.co.jp/examples/shared-master.html)。
|
|
288
288
|
|
|
289
289
|
```html
|
|
290
290
|
<script src="plugins/tss-shared.js"></script>
|
|
@@ -335,7 +335,7 @@ TssGrid.registerPlugin('autosave', autoSavePlugin); // 名前登録 → plugin
|
|
|
335
335
|
|
|
336
336
|
## カスタムエディタ
|
|
337
337
|
|
|
338
|
-
組込エディタ(text/dropdown/checkbox/date/time/number)以外に、**独自の編集UI**を列に差せます。`columns[c].editor`
|
|
338
|
+
組込エディタ(text/dropdown/checkbox/date/time/number)以外に、**独自の編集UI**を列に差せます。`columns[c].editor` に**薄いオブジェクト契約**を渡すだけ。
|
|
339
339
|
|
|
340
340
|
```js
|
|
341
341
|
const myEditor = {
|
|
@@ -362,7 +362,7 @@ new TssGrid(el, { columns: [{ editor: myEditor }] });
|
|
|
362
362
|
|
|
363
363
|
### 同梱プラグイン: 休日カレンダー対応の日付ピッカー
|
|
364
364
|
|
|
365
|
-
`plugins/tss-calendar.js
|
|
365
|
+
`plugins/tss-calendar.js`= ネイティブ `<input type=date>` では出来ない**会社の休日カレンダー(JSON)対応**の日付ピッカー。勤怠・シフト・予約などで効きます(動く例: [`examples/calendar.html`](https://tssgrid.threestarsoftware.co.jp/examples/calendar.html))。
|
|
366
366
|
|
|
367
367
|
```html
|
|
368
368
|
<link rel="stylesheet" href="plugins/tss-calendar.css">
|
|
@@ -383,7 +383,7 @@ new TssGrid(el, { columns: [{ type: 'date', editor: cal, format: 'yyyy/mm/dd' }]
|
|
|
383
383
|
|
|
384
384
|
### 同梱プラグイン: 時刻ピッカー(時/分プルダウン)
|
|
385
385
|
|
|
386
|
-
`plugins/tss-time.js
|
|
386
|
+
`plugins/tss-time.js`= 業務の時刻入力向けの**時/分プルダウン**ピッカー(クロックフェイスのようなリッチさは省き、任意時刻を素早く)。保存値は常に **24h `'HH:MM'`**(組込 `type:'time'` と互換)。動く例: [`examples/time.html`](https://tssgrid.threestarsoftware.co.jp/examples/time.html)。
|
|
387
387
|
|
|
388
388
|
```html
|
|
389
389
|
<link rel="stylesheet" href="plugins/tss-time.css">
|
|
@@ -398,7 +398,7 @@ new TssGrid(el, { columns: [{ type: 'time', editor: t }] });
|
|
|
398
398
|
|
|
399
399
|
### 同梱プラグイン: 派生列(formula / computed column)
|
|
400
400
|
|
|
401
|
-
`plugins/tss-formula.js
|
|
401
|
+
`plugins/tss-formula.js`=「その行の値だけから計算する列」を `columns[c].formula` 関数で書けるようにする。金額=数量×単価、税込=金額×1.1 のような**派生列**を宣言的に。動く例: [`examples/formula.html`](https://tssgrid.threestarsoftware.co.jp/examples/formula.html)。
|
|
402
402
|
|
|
403
403
|
```html
|
|
404
404
|
<script src="plugins/tss-formula.js"></script>
|
|
@@ -421,7 +421,7 @@ new TssGrid(el, {
|
|
|
421
421
|
|
|
422
422
|
### 同梱プラグイン: 列の集計(totals / 縦の SUM・平均…)
|
|
423
423
|
|
|
424
|
-
`plugins/tss-totals.js
|
|
424
|
+
`plugins/tss-totals.js`= 列方向の集計(`sum`/`avg`/`count`/`min`/`max`/独自関数)を担う。**計算だけで描画はしない**=結果を `onTotals` で受けて好きな場所へ(フッタ・ラベル・**別の TssGrid の合計表**でも)。`formula` と併用すると派生列の後に集計が連動。動く例: [`examples/formula.html`](https://tssgrid.threestarsoftware.co.jp/examples/formula.html)(明細=formula/合計=totals)。
|
|
425
425
|
|
|
426
426
|
```html
|
|
427
427
|
<script src="plugins/tss-totals.js"></script>
|
|
@@ -442,7 +442,7 @@ new TssGrid(el, {
|
|
|
442
442
|
|
|
443
443
|
### 同梱プラグイン: 条件付き合計(tss-sum / ラベル付き合計行・整列表示)
|
|
444
444
|
|
|
445
|
-
`plugins/tss-sum.js
|
|
445
|
+
`plugins/tss-sum.js`= **ラベル付きの"合計行"**(小計・消費税10%・消費税8%・合計 など)を、**条件(`when`)+対象(`of`)を宣言**で定義して作る。`tss-totals` が「列ごと1値」なのに対し、こちらは**同じ列を条件別に何本でも集計**でき(消費税10%と8%は両方 amount 由来=per-column では衝突する)、**ソースと同一列構成の readonly 集計グリッドを生成**するので**金額が縦にピッタリ揃う**(画面でも印刷でも)。請求書・見積などの合計欄に。動く例: [`examples/invoice.html`](https://tssgrid.threestarsoftware.co.jp/examples/invoice.html)(インボイス請求書の合計欄)。
|
|
446
446
|
|
|
447
447
|
```html
|
|
448
448
|
<script src="plugins/tss-merge.js"></script> <!-- ラベルの横結合に利用 -->
|
|
@@ -466,7 +466,7 @@ const sum = TssSum.attach(grid, document.getElementById('sumgrid'), {
|
|
|
466
466
|
|
|
467
467
|
### 同梱プラグイン: 残高/累計(running total・縦の連鎖)
|
|
468
468
|
|
|
469
|
-
`plugins/tss-running.js
|
|
469
|
+
`plugins/tss-running.js`=「**前の行の結果 + この行の増減**」で縦に積む列。`formula`(行内)でも `totals`(全体合計)でも出せない**縦方向の連鎖**を担う。出納帳/通帳の**残高**、在庫受払の**在庫数**、経費・ポイントの**累計**など。動く例: [`examples/running.html`](https://tssgrid.threestarsoftware.co.jp/examples/running.html)(現金出納帳=入金・出金→残高)。
|
|
470
470
|
|
|
471
471
|
```html
|
|
472
472
|
<script src="plugins/tss-running.js"></script>
|
|
@@ -485,11 +485,11 @@ new TssGrid(el, {
|
|
|
485
485
|
- `column`(残高列) / `initial`(前残) / `delta` か `step` / `skipEmpty`(全列空の行は連鎖を進めず空表示、既定true)。
|
|
486
486
|
- **行ドラッグ移動(rowReorder)併用時**は順序が変わるので `onAfterRowMove` で `handle.recompute()` を呼ぶ。
|
|
487
487
|
|
|
488
|
-
> 「**行=formula/列=totals/縦=running**」の3点が揃う。いずれも `setValueRaw`+`onAfterChange`
|
|
488
|
+
> 「**行=formula/列=totals/縦=running**」の3点が揃う。いずれも `setValueRaw`+`onAfterChange` ラップで動く**プラグイン**。
|
|
489
489
|
|
|
490
490
|
### 同梱プラグイン: 氏名→フリガナ 自動入力(furigana・辞書不要)
|
|
491
491
|
|
|
492
|
-
`plugins/tss-furigana.js
|
|
492
|
+
`plugins/tss-furigana.js`(**辞書不要**)= 漢字を入力(IME変換)すると**読みが別列に自動で入る**(スマホ連絡先の よみがな 自動入力と同じ)。辞書引きではなく、**IME変換の composition イベントから「変換前のかな」を拾う**方式。TssGrid は**アクティブセルに本物の `<input>` を重ねる**設計なので composition が確実に取れる=「**IMEに強い**」を機能で体現。動く例: [`examples/furigana.html`](https://tssgrid.threestarsoftware.co.jp/examples/furigana.html)。
|
|
493
493
|
|
|
494
494
|
```html
|
|
495
495
|
<script src="plugins/tss-furigana.js"></script>
|
|
@@ -506,7 +506,7 @@ new TssGrid(el, {
|
|
|
506
506
|
|
|
507
507
|
### 同梱プラグイン: セル内ミニ計算式(calc・=12*3)
|
|
508
508
|
|
|
509
|
-
`plugins/tss-calc.js
|
|
509
|
+
`plugins/tss-calc.js`(**eval/Function 不使用**)= セルに `=12*3+5` と打つと確定時に **41** に。四則 `+ - * /`・括弧・小数対応の**自前再帰下降パーサ**(CSP安全)。`columns[c].parse`(入力変換)seam に乗るだけ。動く例: [`examples/calc.html`](https://tssgrid.threestarsoftware.co.jp/examples/calc.html)。
|
|
510
510
|
|
|
511
511
|
```html
|
|
512
512
|
<script src="plugins/tss-calc.js"></script>
|
|
@@ -522,7 +522,7 @@ plugins: [ TssCalc.plugin({ columns: ['quantity', 'price'] }) ] // columns 省
|
|
|
522
522
|
|
|
523
523
|
### 同梱プラグイン: オートコンプリート(autocomplete エディタ)
|
|
524
524
|
|
|
525
|
-
`plugins/tss-autocomplete.js
|
|
525
|
+
`plugins/tss-autocomplete.js`= 自由入力+**候補の絞り込み**。固定 dropdown の上位版で「だいたい決まってるが新規もある」項目(取引先・商品名)向け。**IME変換中の Enter は奪わない**(変換確定が最優先)。動く例: [`examples/autocomplete.html`](https://tssgrid.threestarsoftware.co.jp/examples/autocomplete.html)。
|
|
526
526
|
|
|
527
527
|
```html
|
|
528
528
|
<link rel="stylesheet" href="plugins/tss-autocomplete.css">
|
|
@@ -540,7 +540,7 @@ columns: [
|
|
|
540
540
|
|
|
541
541
|
### 同梱プラグイン: セル内スパークライン(sparkline・ミニグラフ)
|
|
542
542
|
|
|
543
|
-
`plugins/tss-sparkline.js
|
|
543
|
+
`plugins/tss-sparkline.js`(**SVG自前描画**)= セルの数列を**ミニ折れ線/棒**で描く。`columns[c].html:true` + `format`(format が返す SVG がセルに入る)seam に乗るだけ。Chart.js 等は積まない。動く例: [`examples/sparkline.html`](https://tssgrid.threestarsoftware.co.jp/examples/sparkline.html)(月次売上→動向グラフ・編集でライブ更新)。
|
|
544
544
|
|
|
545
545
|
```html
|
|
546
546
|
<script src="plugins/tss-sparkline.js"></script>
|
|
@@ -554,11 +554,11 @@ columns: [
|
|
|
554
554
|
formula: (row) => ['m4','m5','m6','m7','m8','m9'].map(k=>row[k]).filter(v=>v!=='').join(',') }
|
|
555
555
|
```
|
|
556
556
|
- `type`('line'/'bar') / `width` / `height` / `color` / `strokeWidth` / `fill`(折れ線下の塗り) / `min`・`max`(既定は自動)。
|
|
557
|
-
- 数値しか SVG に入れない=安全。`formula`/`html-cells` と同じ仕組みで、**有料グリッドの "セル内グラフ"
|
|
557
|
+
- 数値しか SVG に入れない=安全。`formula`/`html-cells` と同じ仕組みで、**有料グリッドの "セル内グラフ" を無料で**。
|
|
558
558
|
|
|
559
559
|
### 同梱プラグイン: セル内 横棒グラフ(bar・データバー)
|
|
560
560
|
|
|
561
|
-
`plugins/tss-bar.js
|
|
561
|
+
`plugins/tss-bar.js`= セルの数値を**横棒**で描く(認知率・進捗%・スコア)。`html:true`+`format` seam。`type:'number'` 併用で**バーのまま編集**(値を打つと伸びる)。動く例: [`examples/bar.html`](https://tssgrid.threestarsoftware.co.jp/examples/bar.html)。
|
|
562
562
|
|
|
563
563
|
```html
|
|
564
564
|
<script src="plugins/tss-bar.js"></script>
|
|
@@ -573,7 +573,7 @@ columns: [
|
|
|
573
573
|
|
|
574
574
|
### 同梱プラグイン: ヒートマップ / 背景データバー(cellStyle)
|
|
575
575
|
|
|
576
|
-
`plugins/tss-heatmap.js
|
|
576
|
+
`plugins/tss-heatmap.js`= コアの `cellStyle` フックに乗せる**連続色(ヒートマップ)**と**背景データバー**。`tss-bar.js`(前景の棒+ラベル)と違い、**セル背景**を塗る=**数値はそのまま見せて編集できる**。動く例: [`examples/heatmap.html`](https://tssgrid.threestarsoftware.co.jp/examples/heatmap.html)。
|
|
577
577
|
|
|
578
578
|
```html
|
|
579
579
|
<script src="plugins/tss-heatmap.js"></script>
|
|
@@ -587,7 +587,7 @@ columns: [
|
|
|
587
587
|
- `TssHeatmap`: `min`/`max`(明示。セル単位呼び出しで列範囲を知らないため)/ `colors`(2色以上のストップ) or `low`/`high` / `text`(自動文字色, 既定on)。
|
|
588
588
|
- `TssDataBar`: `min`/`max` / `color` / `align`('left'/'right')。編集で即更新。
|
|
589
589
|
|
|
590
|
-
> 「セル内グラフ」3点: **前景の折れ線/棒=`html:true`+`format`(tss-sparkline / tss-bar)**、**背景の連続色/バー=`cellStyle`(tss-heatmap
|
|
590
|
+
> 「セル内グラフ」3点: **前景の折れ線/棒=`html:true`+`format`(tss-sparkline / tss-bar)**、**背景の連続色/バー=`cellStyle`(tss-heatmap)**。どれもノービルド。
|
|
591
591
|
|
|
592
592
|
### グラフ連携(Chart.js などと)— 編集でライブ更新
|
|
593
593
|
|
|
@@ -601,7 +601,7 @@ new TssGrid(el, { columns, data, onAfterChange: () => { chart.data = toChartData
|
|
|
601
601
|
|
|
602
602
|
### 同梱プラグイン: 2択トグル(toggle・有効|無効)
|
|
603
603
|
|
|
604
|
-
`plugins/tss-toggle.js`+`.css
|
|
604
|
+
`plugins/tss-toggle.js`+`.css`= ラジオの2択を**並んだセグメント(有効|無効)**で表示、クリックで切替。チェックボックスより**2ラベルが見える**。値は dropdown 同様 **value を保存**。動く例: [`examples/toggle.html`](https://tssgrid.threestarsoftware.co.jp/examples/toggle.html)。
|
|
605
605
|
|
|
606
606
|
```html
|
|
607
607
|
<link rel="stylesheet" href="plugins/tss-toggle.css">
|
|
@@ -618,7 +618,7 @@ plugins: [ TssToggle.plugin({ columns: {
|
|
|
618
618
|
|
|
619
619
|
### 同梱プラグイン: セル結合(merge・横/縦/矩形)
|
|
620
620
|
|
|
621
|
-
`plugins/tss-merge.js
|
|
621
|
+
`plugins/tss-merge.js`= データセルの**矩形結合**(`colspan`×`rowspan`)。左上の**アンカーが値・編集・選択の対象**で、覆われた従属セルは**描画スキップ+読み取り専用**(貼り付け・フィルは弾く)。動く例: [`examples/merge.html`](https://tssgrid.threestarsoftware.co.jp/examples/merge.html)。(見出しの結合は `nestedHeaders` を参照)
|
|
622
622
|
|
|
623
623
|
```html
|
|
624
624
|
<script src="plugins/tss-merge.js"></script>
|
|
@@ -644,7 +644,7 @@ plugins: [ TssMerge.plugin({ merges: [
|
|
|
644
644
|
|
|
645
645
|
### 同梱プラグイン: 同期スクロール(syncscroll・左右2表を並べて比較)
|
|
646
646
|
|
|
647
|
-
`plugins/tss-syncscroll.js
|
|
647
|
+
`plugins/tss-syncscroll.js`= 並べた複数グリッドのスクロールを連動(Excel「並べて比較+同時にスクロール」相当)。A系/B系で別々に絞り込んだ表を**突き合わせながら編集**する用途に。動く例: [`examples/sync-scroll.html`](https://tssgrid.threestarsoftware.co.jp/examples/sync-scroll.html)。
|
|
648
648
|
|
|
649
649
|
```html
|
|
650
650
|
<script src="plugins/tss-syncscroll.js"></script>
|
|
@@ -911,7 +911,7 @@ new TssGrid(el, {
|
|
|
911
911
|
|
|
912
912
|
### 入力の正規化 / 表示の整形(`parse` / `format`)
|
|
913
913
|
|
|
914
|
-
**保存値**(`getData()`
|
|
914
|
+
**保存値**(`getData()` が返す内部値)と、**入力**・**表示**を分離できます。外部ライブラリは同梱せず、必要なら列のフックに差し込む方針です。
|
|
915
915
|
|
|
916
916
|
| フック | 向き | 役割 |
|
|
917
917
|
|---|---|---|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threestarsoftware/tssgrid",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "軽量・ノービルド・日本語IME堅牢な編集グリッド(vanilla JS / 依存なし / MIT)。Excel ライクな入力画面を <script> タグ1本で。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ThreeStarSoftware (https://www.threestarsoftware.co.jp/)",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"src/tssgrid.d.ts",
|
|
53
53
|
"plugins/",
|
|
54
54
|
"README.md",
|
|
55
|
+
"CHANGELOG.md",
|
|
55
56
|
"LICENSE"
|
|
56
57
|
]
|
|
57
58
|
}
|
package/plugins/tss-bar.js
CHANGED
package/plugins/tss-calc.js
CHANGED
package/plugins/tss-calendar.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/*! TssCalendar — 日付ピッカー(TssGrid のカスタムエディタ / 単体ウィジェット両用)
|
|
2
|
-
* DEV: 無依存
|
|
3
2
|
* 休日カレンダーを JSON で渡せる(勤怠・シフト等向け)。CSS は tss-calendar.css をクラス/変数で自由に。
|
|
4
3
|
* 使い方(グリッド): columns: [{ type:'date', editor: TssCalendar({ holidays }) }]
|
|
5
4
|
* 使い方(単体) : TssCalendar({holidays}).openAt(anchorEl, isoValue, onPick)
|
package/plugins/tss-datetime.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/*! TssDatetime — 日付+時刻を同時に設定するピッカー(TssGrid カスタムエディタ / 単体ウィジェット両用)
|
|
2
|
-
* DEV: 無依存。カレンダー部は tss-calendar.css、時刻部は tss-time.css のクラスを再利用+薄い tss-datetime.css。
|
|
3
2
|
* 保存値は常に 'YYYY-MM-DDTHH:MM'(kintone DATETIME と相互変換しやすい正規形。表示は列 format で整形)。
|
|
4
3
|
* 使い方(グリッド): columns: [{ type:'text', editor: TssDatetime({ step:5 }), format: TssDatetime.format }]
|
|
5
4
|
* 使い方(単体) : TssDatetime({step:15}).openAt(anchorEl, 'YYYY-MM-DDTHH:MM', onPick)
|
package/plugins/tss-filter.js
CHANGED
package/plugins/tss-formula.js
CHANGED
package/plugins/tss-furigana.js
CHANGED
package/plugins/tss-heatmap.js
CHANGED
package/plugins/tss-merge.js
CHANGED
package/plugins/tss-messages.js
CHANGED
package/plugins/tss-running.js
CHANGED
package/plugins/tss-shared.js
CHANGED
package/plugins/tss-sparkline.js
CHANGED
package/plugins/tss-sum.js
CHANGED
package/plugins/tss-time.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/*! TssTime — 時刻ピッカー(TssGrid のカスタムエディタ / 単体ウィジェット両用)
|
|
2
|
-
* DEV: 無依存
|
|
3
2
|
* 時/分プルダウン方式(業務の任意時刻入力向き)。保存値は常に 24h 'HH:MM'(type:'time' と互換)。
|
|
4
3
|
* 使い方(グリッド): columns: [{ type:'time', editor: TssTime({ step:15 }) }]
|
|
5
4
|
* opts: step(分刻み,既定1) / hour12(AM/PM表示,既定false) / icon(既定 '🕐') / openOnClick(既定true) / className
|
package/plugins/tss-toggle.js
CHANGED
package/plugins/tss-totals.js
CHANGED
package/src/tssgrid.css
CHANGED
|
@@ -134,6 +134,11 @@
|
|
|
134
134
|
.tssgrid .tg-rowmove { cursor: grab; color: #b3b6c8; margin-right: 2px; font-size: 11px; line-height: 1; user-select: none; vertical-align: 1px; }
|
|
135
135
|
.tssgrid .tg-rowmove:hover { color: var(--tg-accent); }
|
|
136
136
|
.tssgrid .tg-rowmove:active { cursor: grabbing; }
|
|
137
|
+
.tssgrid .tg-rowmove.tg-mark-after { margin-right: 0; margin-left: 4px; } /* ⠿ を番号の後ろに置く時の間隔 */
|
|
138
|
+
.tssgrid .tg-rowmove.tg-mark-only { margin: 0; } /* 番号なし=⠿だけ=前後の区別をやめて中央に */
|
|
139
|
+
/* rowReorder:'header' = 行ヘッダーセル全体が移動ハンドル(クリック=選択/ドラッグ=移動) */
|
|
140
|
+
.tssgrid .tg-table th.rowhead.tg-rowmove-cell { cursor: grab; }
|
|
141
|
+
.tssgrid .tg-table th.rowhead.tg-rowmove-cell:active { cursor: grabbing; }
|
|
137
142
|
.tssgrid .tg-colgrip:hover { background: var(--tg-edit-accent); opacity: .5; }
|
|
138
143
|
.tssgrid .tg-rowgrip:hover { background: var(--tg-edit-accent); opacity: .5; }
|
|
139
144
|
/* リサイズのプレビュー線(ドラッグ中だけ表示、離して確定) */
|
package/src/tssgrid.d.ts
CHANGED
|
@@ -128,6 +128,12 @@ export interface TssGridOptions {
|
|
|
128
128
|
rowHeaders?: boolean;
|
|
129
129
|
/** 行番号列の幅(px)。既定 40。大量行で桁数が増える時に広げる。 */
|
|
130
130
|
rowHeaderWidth?: number;
|
|
131
|
+
/** 行ヘッダの表示内容。未指定=行番号(r+1) / false=数字なし(空) / (r)=>文字列=カスタム表示。 */
|
|
132
|
+
rowHeaderLabel?: false | ((r: number) => string | number);
|
|
133
|
+
/** 行のドラッグ並べ替え。true=行ヘッダーセルの ⠿ アイコンを掴んで移動 / 'header'=行ヘッダーセル全体が移動ハンドル(クリック=選択/ドラッグ=移動)。 */
|
|
134
|
+
rowReorder?: boolean | 'header';
|
|
135
|
+
/** 行ヘッダーの ⠿ マークの位置。'before'=番号の前(既定)/ 'after'=番号の後 / false=マークを出さない。 */
|
|
136
|
+
rowReorderMark?: 'before' | 'after' | false;
|
|
131
137
|
/** 仮想スクロール(固定行高ウィンドウイング)。大量行を可視窓だけ描画。true か { buffer:窓上下バッファ行数(既定6) }。
|
|
132
138
|
* 制約(v1): 行高一定/固定行列・折り返し・セル結合は非対応(指定時は自動無効化)。 */
|
|
133
139
|
virtual?: boolean | { buffer?: number };
|
package/src/tssgrid.js
CHANGED
|
@@ -146,6 +146,7 @@
|
|
|
146
146
|
|
|
147
147
|
this.active = { r: 0, c: 0 }; this.extent = { r: 0, c: 0 };
|
|
148
148
|
this.mode = 'nav'; this.dragging = false; this.filling = null;
|
|
149
|
+
this._asRAF = 0; this._dragDir = 0; this._fillRow = null; // ドラッグ/フィルの端自動スクロール状態
|
|
149
150
|
this.pendingCut = null;
|
|
150
151
|
this.headerDrag = null; this._colAnchor = 0; this._rowAnchor = 0; // 行/列ヘッダ選択
|
|
151
152
|
this._headerSel = null; // 'col'/'row'/'all'=列/行/全選択モード(結合に拡張せず実列/行にクランプ=Excel流)。null=通常セル選択
|
|
@@ -184,9 +185,12 @@
|
|
|
184
185
|
// 行/列ヘッダの表示(false で行番号列・ヘッダ行を隠す)
|
|
185
186
|
this.rowHeaders = opts.rowHeaders !== false;
|
|
186
187
|
this.rowHeaderW = (opts.rowHeaderWidth | 0) || 40; // 行番号列の幅(px)。大量行で桁数が増える時に広げる
|
|
188
|
+
this.rowHeaderLabel = opts.rowHeaderLabel; // 行ヘッダ表示: 未指定=行番号(r+1) / false=数字なし(空) / (r)=>文字列=カスタム
|
|
187
189
|
this.colHeaders = opts.colHeaders !== false;
|
|
188
190
|
// 行ヘッダの「つまみ」をドラッグして行を並べ替える(行番号列が必要)
|
|
189
191
|
this.rowReorder = !!opts.rowReorder;
|
|
192
|
+
this.rowReorderWhole = opts.rowReorder === 'header'; // 'header'=行ヘッダーセル全体が移動ハンドル(クリック=選択/ドラッグ=移動)/true=⠿アイコンのみ
|
|
193
|
+
this.rowReorderMark = opts.rowReorderMark === undefined ? 'before' : opts.rowReorderMark; // ⠿の位置: 'before'(番号の前/既定) | 'after'(番号の後) | false(出さない)
|
|
190
194
|
// 選択カーソル(緑の選択枠・範囲・セルハイライト・フィルハンドル)を表示するか。
|
|
191
195
|
// false で表示専用グリッド向けに非表示(内部の選択は保持=コピーは可)。
|
|
192
196
|
this.cursor = opts.cursor !== false;
|
|
@@ -522,6 +526,7 @@
|
|
|
522
526
|
if (this._destroyed) return;
|
|
523
527
|
this._destroyed = true;
|
|
524
528
|
if (this._vRAF) { try { cancelAnimationFrame(this._vRAF); } catch (_) {} this._vRAF = 0; } // 仮想スクロールの保留フレームを破棄
|
|
529
|
+
this._stopAutoScroll(); // ドラッグ自動スクロールの保留フレームを破棄
|
|
525
530
|
for (const p of this._plugins) { if (p.handle && typeof p.handle.destroy === 'function') { try { p.handle.destroy(); } catch (_) {} } }
|
|
526
531
|
this._plugins = [];
|
|
527
532
|
if (this._ro) { try { this._ro.disconnect(); } catch (_) {} this._ro = null; }
|
|
@@ -983,6 +988,13 @@
|
|
|
983
988
|
_colWidth(c) { return this.colW[c] != null ? this.colW[c] : this.defColW; }
|
|
984
989
|
_rowHeight(r) { return this.rowH[r] != null ? this.rowH[r] : this.defRowH; }
|
|
985
990
|
_rhW() { return this.rowHeaders ? this.rowHeaderW : 0; } // 行ヘッダ列の幅(非表示なら 0)
|
|
991
|
+
// 行ヘッダの表示内容: false=空(数字なし)/ 関数=カスタム(エスケープ)/ 既定=行番号(r+1)。
|
|
992
|
+
_rowHeadLabel(r) {
|
|
993
|
+
const L = this.rowHeaderLabel;
|
|
994
|
+
if (L === false) return '';
|
|
995
|
+
if (typeof L === 'function') { let v; try { v = L(r); } catch (_) {} return TssGrid.esc(v == null ? '' : v); }
|
|
996
|
+
return (r + 1);
|
|
997
|
+
}
|
|
986
998
|
// ---- 列の非表示 ----
|
|
987
999
|
_isHidden(c) { return this.hiddenCols.has(c); }
|
|
988
1000
|
_visCols() { const a = []; for (let c = 0; c < this.COLS; c++) if (!this.hiddenCols.has(c)) a.push(c); return a; }
|
|
@@ -1112,9 +1124,15 @@
|
|
|
1112
1124
|
_rowHTML(r) {
|
|
1113
1125
|
const rh = this.rowHeaders;
|
|
1114
1126
|
const rgrip = (rh && this.resizeRows) ? '<div class="tg-rowgrip"></div>' : '';
|
|
1115
|
-
const
|
|
1127
|
+
const canMove = rh && this.rowReorder && !this._hasVMerge();
|
|
1128
|
+
const lbl = this._rowHeadLabel(r);
|
|
1129
|
+
const after = this.rowReorderMark === 'after' && lbl !== ''; // 番号が無いなら「前/後」は無意味=中央に固定(マージンも消す)
|
|
1130
|
+
const markCls = 'tg-rowmove' + (lbl === '' ? ' tg-mark-only' : (after ? ' tg-mark-after' : ''));
|
|
1131
|
+
const mark = (canMove && this.rowReorderMark !== false) ? '<span class="' + markCls + '" title="ドラッグで行を移動">⠿</span>' : '';
|
|
1132
|
+
const inner = after ? (lbl + mark) : (mark + lbl); // ⠿ を番号の前/後に(rowReorderMark)。番号なしは前後どちらでも中央
|
|
1133
|
+
const rhCls = (canMove && this.rowReorderWhole) ? ' tg-rowmove-cell' : ''; // 'header'=行ヘッダーセル全体を掴み手に(grab カーソル)。番号/⠿の表示は独立
|
|
1116
1134
|
const rcls = (r < this.frozenRows) ? (' tg-frozen-row' + (r === this.frozenRows - 1 ? ' tg-frozen-row-edge' : '')) : ''; // 行固定
|
|
1117
|
-
let html = '<tr data-r="' + r + '" class="tg-row' + rcls + '" style="height:' + this._rowHeight(r) + 'px">' + (rh ? '<th class="rowhead" data-r="' + r + '">' +
|
|
1135
|
+
let html = '<tr data-r="' + r + '" class="tg-row' + rcls + '" style="height:' + this._rowHeight(r) + 'px">' + (rh ? '<th class="rowhead' + rhCls + '" data-r="' + r + '">' + inner + rgrip + '</th>' : '');
|
|
1118
1136
|
for (let c = 0; c < this.COLS; c++) {
|
|
1119
1137
|
if (this._merges && this._isCovered(r, c)) continue; // 結合に覆われた従属セルは td を出さない(アンカーが colspan で覆う)
|
|
1120
1138
|
const cs = this._merges ? this._colspanAt(r, c) : 1; // 結合アンカーは colspan で従属列ぶんを覆う
|
|
@@ -1698,7 +1716,10 @@
|
|
|
1698
1716
|
} else if (th.dataset.r != null) { // 行ヘッダ
|
|
1699
1717
|
const r = +th.dataset.r;
|
|
1700
1718
|
if (e.shiftKey) this._extendRow(r); else this.selectRow(r);
|
|
1701
|
-
this.editor.focus();
|
|
1719
|
+
this.editor.focus();
|
|
1720
|
+
// 'header'モード: 行ヘッダーセル全体が移動ハンドル=行を選択した上で移動を armする(クリック=選択のまま/ドラッグで移動)。縦結合/フィルタ中は不可。
|
|
1721
|
+
if (this.rowReorderWhole && !e.shiftKey && !this._hasVMerge() && !this._allRows) this._startRowMove(e);
|
|
1722
|
+
else this.headerDrag = 'row'; // 通常: ドラッグで複数行選択
|
|
1702
1723
|
} else { // 左上の角 → 全選択
|
|
1703
1724
|
this.selectAll(); this.editor.focus();
|
|
1704
1725
|
}
|
|
@@ -2197,6 +2218,66 @@
|
|
|
2197
2218
|
clearCopyMarquee() { this.copybox.style.display = 'none'; this.pendingCut = null; }
|
|
2198
2219
|
|
|
2199
2220
|
_tdAtPoint(e) { const el = document.elementFromPoint(e.clientX, e.clientY); return el && el.closest ? el.closest('td[data-r]') : null; }
|
|
2221
|
+
// ポインタ Y から絶対行を算出(td が無い窓外/スペーサ上でも使える=仮想スクロールのドラッグ用。一定行高モデル)。
|
|
2222
|
+
_rowFromPointerY(clientY) {
|
|
2223
|
+
const wr = this.wrap.getBoundingClientRect();
|
|
2224
|
+
const contentY = clientY - wr.top + this.wrap.scrollTop - (this.colHeaders ? (this._theadH || 0) : 0);
|
|
2225
|
+
return Math.max(0, Math.min(this.ROWS - 1, Math.floor(contentY / this.defRowH)));
|
|
2226
|
+
}
|
|
2227
|
+
// ポインタ X から列を算出(_colLefts 累積から。隠し列は飛ばす)。
|
|
2228
|
+
_colFromPointerX(clientX) {
|
|
2229
|
+
const wr = this.wrap.getBoundingClientRect(), x = clientX - wr.left + this.wrap.scrollLeft, L = this._colLefts;
|
|
2230
|
+
if (L) for (let c = this.COLS - 1; c >= 0; c--) if (!this._isHidden(c) && x >= L[c]) return c;
|
|
2231
|
+
return this.extent.c;
|
|
2232
|
+
}
|
|
2233
|
+
_stopAutoScroll() { if (this._asRAF) { try { cancelAnimationFrame(this._asRAF); } catch (_) {} this._asRAF = 0; } this._dragDir = 0; }
|
|
2234
|
+
_updateFillPreview(r, c, alt) {
|
|
2235
|
+
this._fillRow = r;
|
|
2236
|
+
const fr = this.fillRectFromPointer(r, c, this.filling.src, alt);
|
|
2237
|
+
if (fr) { this.placeRect(this.fillpreview, fr.r0, fr.c0, fr.r1, fr.c1); this.fillpreview.style.display = 'block'; }
|
|
2238
|
+
else this.fillpreview.style.display = 'none';
|
|
2239
|
+
}
|
|
2240
|
+
// ドラッグ/フィル中に上下端を越えたら自動スクロールしながら選択/プレビューを伸ばす。
|
|
2241
|
+
// 重要: 伸ばす先は「カウンタ加算」でなく常に【ポインタ位置の行】=端を1pxだけ超えたら1行しか伸びない(暴走しない)。
|
|
2242
|
+
// 自動スクロール速度は端からのはみ出し量に比例(少し超えた=ゆっくり / 大きく超えた=速く)。
|
|
2243
|
+
_edgeAutoScroll(e, mode) {
|
|
2244
|
+
this._dragY = e.clientY; this._dragX = e.clientX; this._dragAlt = !!e.altKey; this._dragMode = mode;
|
|
2245
|
+
const r = this._rowFromPointerY(e.clientY), c = this._colFromPointerX(e.clientX);
|
|
2246
|
+
if (mode === 'drag') this._extendTo(r, c); else this._updateFillPreview(r, c, this._dragAlt); // まずポインタ位置のセルへ
|
|
2247
|
+
const wr = this.wrap.getBoundingClientRect();
|
|
2248
|
+
const headB = wr.top + (this.colHeaders ? (this._theadH || 0) : 0); // 上端=ヘッダ下
|
|
2249
|
+
const leftB = wr.left + this._frozenPaneW(); // 左端=固定ペイン(行番号+固定列)の右
|
|
2250
|
+
const past = e.clientY > wr.bottom || e.clientY < headB || e.clientX > wr.right || e.clientX < leftB;
|
|
2251
|
+
if (past && !this._asRAF) this._asRAF = requestAnimationFrame(() => this._autoScrollTick());
|
|
2252
|
+
}
|
|
2253
|
+
_autoScrollTick() {
|
|
2254
|
+
this._asRAF = 0;
|
|
2255
|
+
if (!this.dragging && !this.filling) return;
|
|
2256
|
+
const wr = this.wrap.getBoundingClientRect();
|
|
2257
|
+
const headB = wr.top + (this.colHeaders ? (this._theadH || 0) : 0), leftB = wr.left + this._frozenPaneW();
|
|
2258
|
+
const amp = d => Math.min(24, 2 + d * 0.2); // px/フレーム=はみ出し量に比例(上限24・暴走しない)
|
|
2259
|
+
let v = 0, vh = 0;
|
|
2260
|
+
if (this._dragY > wr.bottom) v = amp(this._dragY - wr.bottom); else if (this._dragY < headB) v = -amp(headB - this._dragY);
|
|
2261
|
+
if (this._dragX > wr.right) vh = amp(this._dragX - wr.right); else if (this._dragX < leftB) vh = -amp(leftB - this._dragX);
|
|
2262
|
+
if (v !== 0) {
|
|
2263
|
+
const before = this.wrap.scrollTop;
|
|
2264
|
+
this.wrap.scrollTop = Math.max(0, before + v);
|
|
2265
|
+
if (this.wrap.scrollTop !== before && this.virtual) this._renderWindow(this._vWindow(), false); // 縦は仮想時のみ再窓(非仮想で呼ぶと tbody を壊す)
|
|
2266
|
+
}
|
|
2267
|
+
if (vh !== 0) this.wrap.scrollLeft = Math.max(0, this.wrap.scrollLeft + vh); // 横は全列描画なので scrollLeft だけ
|
|
2268
|
+
const r = this._rowFromPointerY(this._dragY), c = this._colFromPointerX(this._dragX); // 伸ばす先は常にポインタのセル
|
|
2269
|
+
if (this._dragMode === 'drag') this._extendTo(r, c); else this._updateFillPreview(r, c, this._dragAlt);
|
|
2270
|
+
const maxTop = this.wrap.scrollHeight - this.wrap.clientHeight, maxLeft = this.wrap.scrollWidth - this.wrap.clientWidth;
|
|
2271
|
+
const vStuck = (v > 0 && this.wrap.scrollTop >= maxTop) || (v < 0 && this.wrap.scrollTop <= 0);
|
|
2272
|
+
const hStuck = (vh > 0 && this.wrap.scrollLeft >= maxLeft) || (vh < 0 && this.wrap.scrollLeft <= 0);
|
|
2273
|
+
if ((v !== 0 && !vStuck) || (vh !== 0 && !hStuck)) this._asRAF = requestAnimationFrame(() => this._autoScrollTick());
|
|
2274
|
+
}
|
|
2275
|
+
// setExtent の自動可視化(_vEnsureVisible)を伴わない版=自動スクロールは _autoScrollTick が手動制御するため、二重スクロールを避ける。
|
|
2276
|
+
_extendTo(r, c) {
|
|
2277
|
+
const e = { r: this.clampR(r), c: this.clampC(c) };
|
|
2278
|
+
if (!this._beforeSel(this.active, e)) return;
|
|
2279
|
+
this.extent = e; this.updateSelectionUI(); this._fireSelection();
|
|
2280
|
+
}
|
|
2200
2281
|
|
|
2201
2282
|
// スクロール / リサイズでセル位置が動いた時、エディタと選択枠を貼り直す
|
|
2202
2283
|
_reflow() {
|
|
@@ -2248,7 +2329,7 @@
|
|
|
2248
2329
|
const cls = e.target.classList;
|
|
2249
2330
|
if (cls && cls.contains('tg-colgrip')) { this._startColResize(e); return; } // 列幅リサイズ
|
|
2250
2331
|
if (cls && cls.contains('tg-rowgrip')) { this._startRowResize(e); return; } // 行高リサイズ
|
|
2251
|
-
if (cls && cls.contains('tg-rowmove')) { this._startRowMove(e); return; } //
|
|
2332
|
+
if (cls && cls.contains('tg-rowmove') && !this.rowReorderWhole) { this._startRowMove(e); return; } // ⠿つまみドラッグ移動('header'モードはセル全体扱い=_onHeaderMouseDown 経由で選択も伴う)
|
|
2252
2333
|
const th = e.target.closest('th');
|
|
2253
2334
|
if (th) { this._onHeaderMouseDown(e, th); return; } // 行/列/全体 選択
|
|
2254
2335
|
const td = e.target.closest('td[data-r]'); if (!td) return;
|
|
@@ -2278,7 +2359,7 @@
|
|
|
2278
2359
|
const td = e.target.closest('td[data-r]'); if (!td) return;
|
|
2279
2360
|
this.setActive(+td.dataset.r, +td.dataset.c); this._beginEdit(this.active.r, this.active.c);
|
|
2280
2361
|
});
|
|
2281
|
-
this.fillhandle.addEventListener('mousedown', (e) => { e.preventDefault(); e.stopPropagation(); this.filling = { src: this.rectRange() }; });
|
|
2362
|
+
this.fillhandle.addEventListener('mousedown', (e) => { e.preventDefault(); e.stopPropagation(); this.filling = { src: this.rectRange() }; this._fillRow = null; });
|
|
2282
2363
|
// 右クリックメニュー(行/列の挿入・削除)
|
|
2283
2364
|
this.table.addEventListener('contextmenu', (e) => this._onContextMenu(e));
|
|
2284
2365
|
this.menuEl.addEventListener('mousedown', (e) => {
|
|
@@ -2346,12 +2427,15 @@
|
|
|
2346
2427
|
}
|
|
2347
2428
|
return;
|
|
2348
2429
|
}
|
|
2349
|
-
if (this.dragging) {
|
|
2430
|
+
if (this.dragging) {
|
|
2431
|
+
const td = this._tdAtPoint(e);
|
|
2432
|
+
if (td) { this._stopAutoScroll(); this.setExtent(+td.dataset.r, +td.dataset.c); }
|
|
2433
|
+
else this._edgeAutoScroll(e, 'drag'); // 窓外/端=自動スクロール+モデル幾何で伸ばす
|
|
2434
|
+
}
|
|
2350
2435
|
else if (this.filling) {
|
|
2351
|
-
const td = this._tdAtPoint(e);
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
else this.fillpreview.style.display = 'none';
|
|
2436
|
+
const td = this._tdAtPoint(e);
|
|
2437
|
+
if (td) { this._stopAutoScroll(); this._updateFillPreview(+td.dataset.r, +td.dataset.c, e.altKey); }
|
|
2438
|
+
else this._edgeAutoScroll(e, 'fill');
|
|
2355
2439
|
}
|
|
2356
2440
|
});
|
|
2357
2441
|
this._on(document, 'mouseup', (e) => {
|
|
@@ -2370,8 +2454,9 @@
|
|
|
2370
2454
|
return;
|
|
2371
2455
|
}
|
|
2372
2456
|
if (this.headerDrag) { this.headerDrag = null; return; }
|
|
2373
|
-
if (this.dragging) { this.dragging = false; return; }
|
|
2457
|
+
if (this.dragging) { this.dragging = false; this._stopAutoScroll(); return; }
|
|
2374
2458
|
if (this.filling) {
|
|
2459
|
+
this._stopAutoScroll();
|
|
2375
2460
|
// autoInsertRow: フィルハンドルをテーブル下端より下へドロップしたら、足りない行を追加(縦フィル時)
|
|
2376
2461
|
if (this.fillAutoInsertRow && this.fillDirection !== 'horizontal' && !this._tdAtPoint(e)) {
|
|
2377
2462
|
const tb = this.table.getBoundingClientRect();
|
|
@@ -2381,8 +2466,11 @@
|
|
|
2381
2466
|
this.buildTable();
|
|
2382
2467
|
}
|
|
2383
2468
|
}
|
|
2384
|
-
|
|
2385
|
-
const
|
|
2469
|
+
// 確定の対象セル: td があればそれ、無ければ(窓外)モデル幾何=直近のフィル行/ポインタ位置から。
|
|
2470
|
+
const td = this._tdAtPoint(e);
|
|
2471
|
+
const tr = td ? +td.dataset.r : (this._fillRow != null ? this._fillRow : this._rowFromPointerY(e.clientY));
|
|
2472
|
+
const tc = td ? +td.dataset.c : this._colFromPointerX(e.clientX);
|
|
2473
|
+
const fr = this.fillRectFromPointer(tr, tc, this.filling.src, e.altKey);
|
|
2386
2474
|
this.fillpreview.style.display = 'none';
|
|
2387
2475
|
const src = this.filling.src; this.filling = null;
|
|
2388
2476
|
if (fr) { this.doFill(src, fr, e.ctrlKey || e.metaKey); this.selectRect(fr.r0, fr.c0, fr.r1, fr.c1); }
|